1.词法分析自动生成器概述
词法分析自动生成器基于正则表达式和有穷自动机理论。正则表达式是一个用数学表达式来描述一个单词集合的构成模式,而有穷自动机从识别的观点来看一个集合中的符号串是否被有穷自动机所识别。
2. Lex
2.1 Lex概述
Lex是一个基于正则表达式的描述来构造词法分析器的工具。它的输入是用Lex语言编写的源程序。在Lex中,要将基于正则表达式的模式说明与词法分析器要完成的动作组织在一起。输出则是词法分析器的C语言程序。
下图所示就是Lex的用法:
2.2 Lex源文件格式
使用Lex产生词法分析器的关键就是设计Lex源程序。Lex源程序包括三个部分:声明、翻译规则和辅助程序,这三个部分用%%分开,如下面所示:
声明 %% 翻译规则 %% 辅助程序
2.3 正则表达式
格式 含义 a 字符a "a" 即使a是一个元符,它仍是字符a \a 当a时应该元字符时,为字符a a* a的零次或多次重复 a+ a的一次或多次重复 a? 一个可选的a a|b a或b (a) a本身 [abc] 字符a、b或c中的任意一个 [a-d] 字符a、b、c或d中的任意一个 [^ab] 除了a或b之外的任何一个字符 . 除了新行之外的任何一个字符 {xxx} 名字xxx表示的正则表达式 <EOF> 匹配的文件结束标记 2.4 Lex的翻译规则
规则如下:
p1 {动作1} p2 {动作2} p3 {动作3} ... ...
3.Lex案例
3.1 统计文本文件中的字符数和行数
Lex源码如下:
%{ /*该Lex程序的功能是统计文本文件中的字符数和行数,并输出结果*/ #include <stdio.h> int num_chars = 0, num_lines = 0; /*全局变量定义,初值为0*/ %} %% /*从此后是第二部分*/ \n { ++num_chars; ++num_lines; } /*\n匹配一行*/ . { ++num_chars; } /*.匹配任一符号,注意从第一列开始写*/ %% /*从此后是第三部分*/ int main( ) { yylex(); printf("This file has %5d chars, %5d lines", num_chars,num_lines); return 0; } int yywrap()/*文件结束处理函数,yylex在读到文件结束标记EOF时,要调用该函数,用户必须提供该函数,否则在编译时会出错*/ { return 1; }
3.2 输出标识符和整数
%{ #include <stdio.h> #include <stdlib.h> %} DIGIT [0-9]+ ID [a-zA-Z][a-zA-Z0-9]* %% {DIGIT} {printf("整数:%s(%d)\n",yytext,atoi(yytext));} {ID} {printf("标识符:%s\n",yytext);} %% void main(){ yyin=fopen("C:/test.txt",r); yylex(); } int yywrap(){return 1;}
3.3 将关键字小写,去掉注释
%{ #include <stdio.h> %} ID [a-zA-Z][a-zA-Z0-9]* id auto|double|int|struct|break|else|long|switch|case| enum|register|typedef|char|extern|return|union|const| float|short|unsigned|continue|for|signed|void|default| goto|sizeof|volatile|do|if|while|static %% {id} { int i; printf("关键字小写为:"); for(i=0;i<yyleng;i++) { if(yytext[i]>='A'&&yytext[i]<='Z') printf("%c",yytext[i]+'a'-'A'); else printf("%c",yytext[i]); } printf("\n"); } {ID} {printf("标识符:%s\n",yytext);} "/*"([^\*|(\*)*[^\*/])*(\*)*"*/" ""; %% main() { yylex(); } int yywrap(void) { return 1; }