LEX & FLEX 实现C语言词法分析器

最近在学习《编译原理》,学完词法分析之后,做了一个C语言的词法分析器。

词法分析简述:

词法分析是编译过程的第一步,主要实现高级语言程序中词法规范的检查。词法分析程序的主要任务是按语言的词法规则从源程序中逐个识别单词,把字符串形式的源程序转行成单词串的形式,并把每个单词转换成他们的内部表示,即所谓的“TOKEN”,并对词法进行检查。

词法分析模型:

 

                                   图一:词法分析模型图

对于一个完整的词法分析模块,主要包含三个部分:输入,处理,输出。

输入:高级语言源程序。

输出:TOKEN ListTOKEN为单词的一种内部表示,一般由两部分组成:单词类别和语义信息。但此类别用来区分不同的单词种类,通常可以使用整数进行编码,语义信息也取决于今后处理的方便(一般为单词内容)。

                                                   图二:TOLEN结构

词法分析器:对于某一具体语言(本文采用C语言为例)的所有类词汇,使用正则表达式描述其组成,然后将每条正则表达式转换成有限自动机进而确定化和化简,再把所有的状态机合并成一个总的状态机,然后根据该状态机构造词法分析程序。                                                                              图二:TOKEN结构图

为了实现方便,采用词法分析器自动生成器FLEX

FLEX工作原理介绍:

FLEX的功能是根据FLEX源文件构造一个词法分析器,由FLEX生成的词法分析器由两部分组成,一个状态转换矩阵和一个控制执行程序。

它的工作过程是:

1,扫描每一条正则式规则Ri,为之构造一个非确定的有限自动机NFA Mi

2,将各条正则式对应的NFA Mi合并成一个新的NFA M.

3,将NFA M等价变换成DFA D,并生成该DFA的状态转换矩阵和控制执行程序。

 

                                               图三:FLEX工作模型图

FLEX源文件:

格式:.l

内容:定义部分和辅助函数部分可选,识别规则部分必须。

定义部分

%%

识别规则部分

%%

辅助函数部分

定义部分:对规则部分要引用的文件和变量进行说明,通常包含头文件,常量定义,全局变量定义以及宏定义等。

识别规则部分:有一组识别规则组成,书写格式如下:

R1 A1

R2 A2

```

Rn An

其中Ri是单词的正则表示,Ai表示当时别出该串时所要执行的动作。

辅助函数部分:这部分包含了识别规则动作代码段中所调用的各局部函数,这些函数由用户编写,由FLEX直接复制输出到lex.yy.c中。

FLEX生成的词法分析器,作为语法分析的子程序,每调用一次返回一个TOKEN.

以下是C语言的单词正则表达式描述:

 

表一:语言单词正则表示

(auto)

(break)

(case)

(char)

(const)

(continue)

(default)

(do)

(double)

(else)

(enum)

(extern)

(float)

(for)

(goto)

(if)

(inline)

(int)

(long)

(register)

(return)

(short)

(signed)

(sizeof)

(static)

(struct)

(switch)

(typedef)

(union)

(unsigned)

([a-z]|[A-Z]|_)([a-z]|[A-Z]|[0-9]|_)*

(void)

(while)

(volatile)

(\()

(\))

(\])

(\-\>)

(\.)

(\[)

(!)

(\-)

(\-\-)

(\+\+)

(~)

(\+)

(%)

(\/)

(&)

(\*)

(\<=)

(\<)

(\>\>)

(\>)

(\<\<)

(\|)

(\^)

(!=)

(==)

(\>=)

(&&)

(\|\|)

(\?:)

(=)

(\+=)

(\-=)

(\*=)

(\/=)

(%=)

(\>\>=)

(\<\<=)

(&=)

(\|=)

(,)

(\^=)

(\\a)

(\\b)

(\\f)

(\\n)

(\\r)

(\\t)

(\\v)

(;)

(:)

(\+|\-)?([1-9][0-9]*|0)(\.[0-9]+)

(\+|\-)?([1-9][0-9]*|0)

(")([\s\S]*)(")

(')([a-z]|[A-Z])(')

(\/\/)

(\/\*)([\s\S]*)(\*\/)

 

 

 

 


下载,安装Flex(因为Lex是Unix系统下的),软件资源链接http://download.csdn.net/detail/u014594922/9499863

下载之后安装,安装完之后配置环境变量,右键点击“计算机”,“属性”、“高级系统设置”、“环境变量”,在下面系统变量里面找到PATH,修改,在后面加上:;E:\FlexInstall\GnuWin32\bin flex的安装路径,注意最前面的";"

配置完之后:

使用上图的C语言单词正则描述构建Flex源文件C.l

%%
(auto)
(break)
(case)
(char)
(const)
(continue)
(default)
(do)
(double)
(else)
(enum)
(extern)
(float)
(for)
(goto)
(if)
(inline)
(int)
(long)
(register)
(return)
(short)
(signed)
(sizeof)
(static)
(struct)
(switch)
(typedef)
(union)
(unsigned)
(void)
(volatile)
(while)
([a-z]|[A-Z]|_)([a-z]|[A-Z]|[0-9]|_)*

(\()

(\))

(\[)

(\])
(\-\>)
(\.)
(!)
(~)
(\+\+)
(\-\-)
(\-)
(\*)
(&)
(\/)
(%)
(\+)
(\<\<)
(\>\>)
(\<)
(\<=)
(\>)
(\>=)
(==)
(!=)
(\^)
(\|)
(&&)
(\|\|)
(\?:)
(=)
(\+=)
(\-=)
(\*=)
(\/=)
(%=)
(\>\>=)
(\<\<=)
(&=)
(\^=)
(\|=)
(,)
(\\a)
(\\b)
(\\f)
(\\n)
(\\r)
(\\t)
(\\v)
(;)
(:)
(\+|\-)?([1-9][0-9]*|0)
(\+|\-)?([1-9][0-9]*|0)(\.[0-9]+)
(')([a-z]|[A-Z])(')
(")([\s\S]*)(")
(\/\/)
(\/\*)([\s\S]*)(\*\/)

文件目录在:E:\课件\编译原理\词法分析\C语言词法分析


接下来使用Flex生成词法分析状态转换矩阵和处理程序

进入Dos执行相应命令:


源目录下生成了词法分析器程序:lex.yy.c


这里是单独使用Flex,实际上是和Bison词法分析器自动生成器一起连用的。


相关推荐
实验二 词法分析器 一、实验目的 掌握词法分析器的构造原理,掌握手工编程或LEX编程方法之一。 二、实验内容 编写一个LEX源程序,使之生成一个词法分析器,能够输入的源程序转换为单词序列输出。 三、实验环境 Flex+VC6.0 四、实验注意 1.Id正则表达式:{letter}({letter}|{digit})* 2.Num正则表达式:{digit}+(\.{digit}+)?(E[+-]?{digit}+)? 3.注释:(\/\*(.)*\*\/) 4.关键字再加上其他字符就又能编程id,所以在词法分析时,id的判断应该放在关键字前面,这样才不会误判 5.由于本程序知识简单的打印数字,因此没有考虑数字的转换 6.&quot;&gt;=&quot;比&quot;&gt;&quot;多一个字符,它应该放在前面判断,其他类似的也应该如此安排 五、实验代码 ******************************************************************************* 实验文件:lex.l、lex.yy.c 实验结果:lex.exe 运行方式:打开lex.exe,弹出input.txt,在其中输入所要测试的程序,保存并关闭,即可在output.txt中看到所得结果 ******************************************************************************* %{ void Install(char *type); %} %option noyywrap delim [ \t] newline [\n] digit [0-9] num {digit}+(\.{digit}+)?(E[+-]?{digit}+)? letter [A-Za-z] id {letter}({letter}|{digit})* key (&quot;if&quot;|&quot;while&quot;|&quot;do&quot;|&quot;break&quot;|&quot;true&quot;) basic (&quot;int&quot;|&quot;float&quot;|&quot;bool&quot;|&quot;char&quot;) op (&quot;&gt;=&quot;|&quot;&lt;=&quot;|&quot;==&quot;|&quot;&gt;&quot;|&quot;&lt;&quot;|&quot;=&quot;|&quot;!=&quot;|&quot;+&quot;|&quot;-&quot;|&quot;*&quot;|&quot;/&quot;) comment (\/\*(.)*\*\/) %% delim {;} newline {printf(&quot;\n&quot;);} {num} {Install(&quot;Num&quot;);} {key} {Install(&quot;Key&quot;);} {basic} {Install(&quot;Basic&quot;);} {op} {Install(&quot;Op&quot;);} &quot;;&quot; {Install(&quot;Comma&quot;);} {id} {Install(&quot;ID&quot;);} {comment} {Install(&quot;Comment&quot;);} &quot;(&quot; | &quot;[&quot; | &quot;{&quot; {Install(&quot;lbracket&quot;);} &quot;)&quot; | &quot;]&quot; | &quot;}&quot; {Install(&quot;rbracket&quot;);} %% void Install(char *s) { fprintf(yyout, &quot;%s:%s &quot;, s, yytext); } int main() { printf(&quot;please input the test program in input.txt\n&quot;); system(&quot;input.txt&quot;); yyin = fopen(&quot;input.txt&quot;, &quot;r&quot;); yyout = fopen(&quot;output.txt&quot;, &quot;w&quot; ); yylex(); fclose(yyout); fclose(yyin); printf(&quot;analysis result in output.txt\n&quot;); system(&quot;output.txt&quot;); return 0; } 六、实验小结 本次的实验由于使用了flex,所以代码较短,麻烦的事flex的正则式表达,由于该使用规则只有简单介绍,而网上找的教程难免有比重就轻之嫌,所以得到上述表达式着实费力,且有的没有成功,例如bracket的(\ ((.)*\ ))或者(&quot;(&quot;(.)*&quot;)&quot;)使用时都没有成功,所以便单独写出,有点不伦不类。至于其他的,都较为简单,完。
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页