Flex

本文详细介绍了Flex的结构,包括定义段、规则段和用户代码段,并讲解了编译操作、匹配原则、正则表达式匹配以及如何处理回溯。此外,文章还探讨了Flex编译选项、IO文件操作以及遇到的问题和解决方案,例如解决-yylax函数的编译问题和处理最长匹配与最先匹配原则。
摘要由CSDN通过智能技术生成

FLEX 结构

定义段 (definitions) %% 规则段 (rules) %% 用户代码段 (user code)

  • rules 由正则表达式动作(Action)组成
  • 注释 /*…*/
  • 规则段中,正则表达式必须顶行,否则直接复制到.c文件中
/*定义段*/
%{
  #include<iostream>
  #include<string>
  extern "C" {
    int yywrap();
  } 
  std::string str;
  std::string num;
%}
/*规则段*/
%%
[a-zA-Z]+ { str += yytext; return 1; } 
[0-9]+ { num += yytext;  return 1; }
\n   { return 0; }
%%
/*用户代码段*/
int yywrap() { return 1; }
int main() {
  while( yylex() );
  std::cout<<"Number: " << num <<std::endl;
  std::cout<<"String: " << str <<std::endl;
  return 0;
}

编译操作

  • 控制台操作
    • flex fb1-1.l
    • g++ lex.yy.c
    • a (运行exe)
  • 编译像yywrap这样flex的函数需要用C的方式编译,如果不用C++也就是用gcc编译,就不需要extern “C”
  • yywrap必须定义,也可以使用%option noyywrap或g++ -lfl 来避免用户来定义它。

但我直接使用g++ lex.yy.c -lfl 时出现找不到-lfl的错误,解决方案 g++ lex.yy.c -lfl -Llib/ -L后面接静态链接库 libfl.a 所在的路径
还有一种解决方案:https://blog.csdn.net/linuxheik/article/details/79557023,但比较麻烦,他用到使VS来链接 libfl.a 而不是gcc或g++

  • char *yytext 表示匹配到的内容,由flex定义

匹配原则

  • 最长匹配原则
  • 最先匹配原则

回溯

需要回溯的情况:

  • 模式中一个是另一个的前缀或子串
  • “trailing context”和^r会导致回溯

正则匹配

表达式匹配例子
r1r2连接
r1|r2
(r)不改变r表示,主要是用于确定运算优先关系
r*零个或多个实例
r+一个或多个实例
r?零个或多个实例
[a-c]等价于a|b|c,或 [abc]
.除了换行符以外的任意字符
^一行的开始
$行的结尾
[^abc]除了abc以外的任何字符
r{m,n}重复出现次数m-n
r1/r2后面有r2时的r1abc/123
\c运算类字符的字面值\*,\$,\|
<S>rr, but in start condition S
<<EOF>>the end-of-file

lex函数

yylex

int yylex();

yylex() 对输入流(默认stdin)进行分析,当匹配到一个正则表达式,有两种情况

  1. 诸如 [0-9]+ { num += yytext; return 1; } 动作有返回, yylex()立即返回,在下次调用时从此处继续读取
  2. 诸如[ \t\] {} 动作无返回, yylex 继续往后分析

常用函数与变量说明

  • 可以在词法分析器的开头设定 %oiption noyywrap来要求它不使用yywrap
变量说明
yy_c_buf_p缓冲区指针,相当于读头
static yyconst int yy_ec[256]状态转移矩阵
extern FILE *yyin;yylex()所扫描的文件
extern FILE *yyout;yylex()所输出的文件
extern int yyleng;yylex()当前所识别词形的长度
extern char *yytext;yylex()当前所识别的词形
#define ECHO (void) fwrite( yytext, yyleng, 1, yyout )打印当前识别的词形到yyout
#define REJECT reject_used_but_not_detected识别下一个最佳词形
yymore()模式对应的action完成之后yytext不清空
yyless(n)当前模式匹配后,缓冲区指针回到当前词形的第n+1个字符
input()从缓冲区读入一个字符,并将指针后移一位
unput©回退字符c到输入流,即追加c到缓冲区当前扫描字符之前
BEGIN(s)
int yywrap();当yylex遇到EOF时调用此函数,此函数返回1,yylex()扫描结束,否则继续扫描

常用的c语言函数

名称功能声明
atoi字符串转换为10进制数int atoi(const char *str)
strtol字符串转换成任意进制数字(2~36)long int strtol(const char *str, char **endptr, int base)

flex编译选项

选项说明
-b输出回溯到lex.backup文件中
-C对输出状态转移矩阵进行不同程度的压缩,强弱次序为:-Cem(缺省),-C,-C{f, F}e, -C{f, F}, -C{f, F}a
-f状态转移矩阵不压缩
-d每个模式匹配后输出调试信息
-vverbose mode, 输出生成的扫描程序DFA等状态信息
-Ttrace mode, 跟踪扫描程序的生成的每个过程

IO文件操作

例:

extern FILE* yyin;
...
int main(int argc, char **argv)
{
	if(argc>1){
		if(!(yyin = fopen(argv[1], "r"))){
			perror(argv[1]);
			return 1;
		}
	}
	...
	return 0;
}

踩过的坑

  1. error: expected identifier or ‘(’ before string constant
  • 原因 #include<string.h>, 具体我也不知到为什么
  • 解决方案:a.改成cstring, 所以要用g++编译,不能用gcc
    b. 在定义段声明 int strlen(char*);
  1. 注意优先级
    如bar* === ba(r*)

  2. %{一定要顶行书写

  3. 要匹配空格,需要出现在“ ”或 [ ]中

  4. 规则段也要顶行书写。

  5. {}要平衡,如果少了一个,flex将把后面的代码全部当作action

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值