flex自动实现词法分析器
FLEX 与 BISON 的使用
FLEX介绍
Flex是一个生成词法分析器的工具,它可以利用正则表达式来生成匹配相应字符串的C语言代码,其语法格式基本同Lex相同。
单词的描述称为模式(Lexical Pattern),模式一般用正规表达式进行精确描述。FLEX通过读取一个有规定格式的文本文件,输出一个C语言源程序。
FLEX的输入文件称为LEX源文件,它内含正规表达式和对相应模式处理的C语言代码。LEX源文件的扩展名习惯上用.l表示。FLEX通过对源文件的扫描自动生成相应的词法分析函数int yylex(),并将之输出到名规定为lex.yy.c的文件中。实用时,可将其改名为lexyy.c。- - - 百度百科
fex的输入是文件或输入设备,这些输入中的信息以正则表达式和C代码的形式组成,这些形式被称为规则(rule);
当可执行文件被执行时,其分析输入中可能存在的符合规则的内容,当找到任何一个正则表达式相匹配内容时,相应的C代码将被执行。
fex的输入文件由3段组成,用一行中只有%%来分隔;
定义: definition
%%
规则: rules
%%
用户代码:code
定义部分
其中定义有变量声明,正则表达式声明;
%{
int a;
int b;
%}
- 正则表达式声明方式:
表达式名称 表达式
在使用时需要将表达式名称用{}
括起来;
- 规则部分
一个规则一行
正则表达式{动作函数}
动作函数可以调用在用户代码中定义的
下面有小例子
下载安装
下载地址:https://sourceforge.net/projects/winflexbison/
下载好后,解压到任意目录下都可以的。解压后:
操作例子
1、在减压的目录下创建一个以.l
结尾的文件我这里创建的是lex.l
,使用记事本打开文件(当然也可以使用别的了),编辑。在这里,就使用简单例子简洁说明一下:
%{
#include<stdio.h>
#include<stdlib.h>
int line=1;
%}
DIGIT [0-9]
OINTEGER [1-9]{DIGIT}*
%%
\n {++line;}
{DIGIT} {printf("line%d:(integer, %s)\n",line,yytext);}
{OINTEGER} {printf("line%d:(integer, %s)\n",line,yytext);}
. {}
[ \t]+ {}
%%
int main(){
yyin=fopen("F:/data.txt","r");
yylex();
return 0;
}
int yywrap(){
return 1;
}
2、在绝对路径下创建data文件,这里是F盘下(fopen("F:/data.txt","r")
),编辑文件:
13 14 520
3、在项目目录下,DOS 命令提示符下(cmd)。执行win_flex ‐‐nounistd lex.l
(lex.l为你的项目名),执行成功会生成一个lex.yy.c文件。
对C程序进行编译运行:
词法分析器
首先写正则表达式
例如:
单位整数:DIGIT [0-9]
整数:OINTEGER [1-9]{DIGIT}*
因此,需要根据各词的特征将正则表达式写出来。
lex.l
%{
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int line=1;
%}
LETTER [a-zA-Z]
ID ({LETTER}|_)({LETTER}|_|{DIGIT})*
OPT ("+"|"-"|"*"|"/"|"+="|"-="|"*="|"/="|">="|"<="|"=="|">"|"<"|"="|"++"|"--")
BRACKET ("("|")"|"["|"]"|"{"|"}"|";"|","|"\'"|"\""|"#")
DIGIT [0-9]
OINTEGER [1-9]{DIGIT}*
INTEGER ("+"|"-")?{OINTEGER}
DECIMAL {INTEGER}(.{OINTEGER})
FLOAT ([0-9])*+[.]([0-9])*+[Ee]([+-]?[0-9]([0-9])*|[0])
ERROEFLOAT ([0-9])*+[.](0-9)*+("E"|"e")
TYPE void|int|double|char
KEYWORD if|else|do|while|for|scanf|printf|sqrt|abs|main|return|float
TYPEIDENTIFY %d|%c|%s|%f|&{ID}
SGPS \/\/.*
DBPS \/\*(.|\n)*\*\/
%%
\n {++line;}
{TYPE} {printf("line%d:(type, %s)\n",line,yytext);}
{KEYWORD} {printf("line%d:(keyword, %s)\n",line,yytext);}
{DIGIT} {printf("line%d:(integer, %s)\n",line,yytext);}
{OINTEGER} {printf("line%d:(integer, %s)\n",line,yytext);}
{ID} {printf("line%d:(identify, %s)\n",line,yytext);}
{BRACKET} {printf("line%d:(bracket, %s)\n",line,yytext);}
{OPT} {printf("line%d:(OPT, %s)\n",line,yytext);}
{INTEGER} {printf("line%d:(integer, %s)\n",line,yytext);}
{DECIMAL} {printf("line%d:(decimal, %s)\n",line,yytext);}
{FLOAT} {printf("line%d:(float, %s)\n",line,yytext);}
{TYPEIDENTIFY} {printf("line%d:(typeidentify, %s)\n",line,yytext);}
{ERROEFLOAT} {printf("ERROEFLOAT\n");}
({SGPS}|{DBPS}) {}
. {}
[ \t]+ {}
%%
int main(){
yyin=fopen("F:/data.txt","r");
yylex();
return 0;
}
int yywrap(){
return 1;
}
- 第一个测试样例:
data.txt
int main(){
int a = 10;
double b = -20.9;
if(a<=b)
a+=b;
return a;
}
- 第二个测试样例:
data.txt
int main(){
int a = 10;
double b = -20.9;
float c=1.2E-3;
if(a<=b)
a+=b;
return a;
}
- 第三个测试样例:
data.txt
int main(){
int a = 10;
double b = -20.9;
float c=1.2E3;
printf("%d",&a);
return a;
}
特别提醒:
如果需要处理错误情况(如:浮点数错误,符号错误),依然是写出错误情况的正则表达式,进行匹配。需要像报错那样,只输出错误情况,而且在错误之前的语句也不输出,需要把输出存储起来,然后判断是否有错误,有错,则输出错误,否则按照正常输出。
参考文献
编译原理(龙书)