通过使用flex/lex来编写一个简单词法分析器,以便加深对词法分析的理解
词法分析是从左往右分逐个字符地对源程序进行扫描,然后按照源程的构词规则规识别出一个个单词符号,把作为字符串的源程序等价地转化为单词符号中间程序。-----《编译与反编译技术》
词法分析程序输出的单词通常用二元式(单词种别,单词符合的属性值表示),但这里的输出形式为<所属类别,单词,种别码>
(1)关键字:while,for,if,else,case,int,char,void,return,main
(2)运算符:*,+, -,=,<,>,<=,>=,==,/
(3)界限符:( ) [ ] { } , : ;
(4)标识符(ID):仅由字母,数字组成的字符串
(5)常量:自然数
(6)种别码:在代码中可见
delim [ \t] // \->>转义,eg:\t->>制表符,\n->>换行符
digit [0-9]
letter [A-Za-z]
Identifier {letter}({letter}|{digit})*
number {digit}{digit}*|0
whitespace {delim}+ //排除\t干扰
定义部分
%%
识别规则部分
%%
辅助函数部分
定义部分
%%
该部分可以分为变量及引用文件声明和正则表达式声明,变量及引用文件声明可包含头文件、常数定义、全局变量定义、外部变量定义以及正规式定义,同时需要用“%{”和“%}”括起来,例如
%{
//0-10为关键字种别码
#include<stdio.h>
#define While 1
#define For 2
int word_sum=0; //字符总数
int line=1;
%}
digit [0-9]
letter [A-Za-z]
Identifier {letter}({letter}|{digit})*
number {digit}{digit}*|0
%%
遵循正则式-动作规则,正则式是被识别的单元,动作是词法分析器识别到相应正则式后要执行的操作,该操作可在识别规则部分直接定义,也可在辅助函数部分定义,然后进行引用,例如
直接定义:
{identifier} fprintf(yyout,"\nline%d: < 关键字 , %s , %d >", line, yytext,Identifier );
引用辅助函数:
定义部分
%%
//识别规则部分
{Identifier} {identifier(id);}
%%
//辅助函数部分
void identifier(int type)
{
word_sum++;
fprintf(yyout,"\nline%d: < 标识符 , %s , %d >", line, yytext,type );
}
在这里用C语言来写识别规则部分所要用到的函数,如上面例子
这里还有一些flex/lex自带函数,这里就不列举了
flex exp.l //默认生成lex.yy.c文件,flex -o xx.c exp.l 指定生成文件xx.c
gcc lex.yy.c //默认生成a.out gcc -o xx.out lex.yy.c 指定生成文件xxx.out
./a.out input.txt ouput.txt //这里设计的是文件的输入输出,但也可改成,键盘的输入,屏幕的输出
int main()
{
int a=10;
if(a>5)
{
a+=10;
return a;
}
else return a+1;
}
%{
//0-10为关键字种别码
#include
#define While 1
#define For 2
#define If 3
#define Else 4
#define Switch 5
#define Case 6
#define Int 7
#define Char 8
#define Void 9
#define Return 10
//11-20为运算符种别码
#define star 11 // *
#define plus 12 // +
#define minus 13 // -
#define assign 14 // =
#define relop_lt 15 // <
#define relop_gt 16 // >
#define relop_le 17 // <=
#define relop_ge 18 // >=
#define relop_eq 19 // ==
#define div 20 // /
//21-27界限符种别码
#define LP 21 // (
#define RP 22 // )
#define LBS 23 // {
#define RBS 24 // }
#define comma 25 // ,
#define SEM 26 // ;
#define colon 27 // :
#define id 28 // 标识符
#define num 29 // 常量
#define Main 30
// 全局常量定义
int word_sum=0; //字符总数
int line=1;
%}
delim [ \t] // \->>转义,eg:\t->>制表符,\n->>换行符
digit [0-9]
letter [A-Za-z]
Identifier {letter}({letter}|{digit})*
number {digit}{digit}*|0
whitespace {delim}+
%%
\n {++line;}
while {KEYword(While);}
for {KEYword(For);}
if {KEYword(If);}
else {KEYword(Else);}
case {KEYword(Case);}
int {KEYword(Int);}
char {KEYword(Char);}
void {KEYword(Void);}
return {KEYword(Return);}
main {KEYword(Main);}
"*" {Operator(star);}
"+" {Operator(plus);}
"-" {Operator(minus);}
"=" {Operator(assign);}
"<" {Operator(relop_lt);}
">" {Operator(relop_gt);}
"<=" {Operator(relop_le);}
">=" {Operator(relop_ge);}
"==" {Operator(relop_eq);}
"/" {Operator(div);}
"(" {Border(LP);}
")" {Border(RP);}
"{" {Border(LBS);}
"}" {Border(RBS);}
"," {Border(comma);}
";" {Border(SEM);}
":" {Border(colon);}
{Identifier} {identifier(id);}
{number} {Constant(num);}
[ \t] {}
%%
void KEYword(int type)
{
word_sum++;
fprintf(yyout,"\nline%d: < 关键字 , %s , %d >", line, yytext,type );
}
void Operator(int type)
{
word_sum++;
fprintf(yyout,"\nline%d: < 运算符 , %s , %d >", line, yytext,type );
}
void Border(int type)
{
word_sum++;
fprintf(yyout,"\nline%d: < 界限符 , %s , %d >", line, yytext,type );
}
void identifier(int type)
{
word_sum++;
fprintf(yyout,"\nline%d: < 标识符 , %s , %d >", line, yytext,type );
}
void Constant(int type)
{
word_sum++;
fprintf(yyout,"\nline%d: < 常量 , %s , %d >", line, yytext,type );
}
int main(int argc, char **argv)
{
if (argc>1)
{
FILE *file;
file=fopen(argv[1],"r");
if(file)
yyin=file;
}
if (argc>2)
{
FILE *file;
file=fopen(argv[2],"w");
if(file)
{
yyout=file;
//freopen(argv[2],"w",stdout);
}
}
fprintf(yyout,"\n-----------------------------------------------------------\n");
fprintf(yyout,"\n 词法分析结果 \n");
fprintf(yyout,"\n-----------------------------------------------------------\n");
fprintf(yyout,"行号 所属类别 单词 种别码");
yylex();
fprintf(yyout,"\n-----------------------------------------------------------");
fprintf(yyout,"\n字符总数:%d ",word_sum);
fprintf(yyout,"\n行数:%d ",line);
yywrap();
}
int yywrap()
{
return 1;
}