基于flex的词法分析器的设计和实现
- 格式:docx
- 大小:567.42 KB
- 文档页数:15
《编译原理》课程实验报告题目利用lex生成c语言的词法分析程序专业班级学号姓名一. 实验题目利用lex生成c语言的词法分析程序二. 实验日期三. 实验环境(操作系统,开发语言)操作系统是Windows开发语言是C语言四. 实验内容(实验要求)利用flex,仿教材p227的pascal语言的词法分析程序,经过适当修改后,遵照教材p48-图4.1和p50-表4.1编写自己的类别码。
要求:1.生成的词法分析程序要求能够对给定的任意c程序进行词法分析,并生成文档输出。
2.词法分析程序能够识别关键字、运算符、分界符、标识符、常量(至少是整形常量,可以自己扩充识别其它常量)等,并能处理注释、部分复合运算符(如>=等)。
3.交 .l 文件,c源文件、输出分析结果文件及实验报告。
五. 实验步骤(1)遵照教材p48-图4.1和p50-表4.1,自己编写自己的类别编码。
(2)仿教材p227,pascal语言的词法分析程序,经过适当的修改后输入记事本中,保存格式为.l文件。
(3)在DOS环境下,利用flex运行.l文件,生成lex.yy.c文件。
(4)用c-free打开lex.yy.c文件,检查是否有错误并运行,生成lex.yy.exe 文件。
(5)可利用此程序运行任意的c程序进行词法分析。
六. 实验体会(包括收获、心得体会、存在的问题及解决问题的方法、建议等)1.此次实验让我进一步熟悉了词法分析程序lex的运用,熟悉了模式的运用方法及其格式的运用。
2.要使词法分析程序能够识别c程序中任意的关键字、运算符、分界符、标识符、常量,必须对这五类单词符号非常熟悉,因此还需要加强巩固c语言这方面的知识。
3.由于对pascal语言的陌生,在将代码修改为c语言的过程中,更多的只是跟着老师说的改,至于为什么这么改并不是很清楚,这其中一个原因是对各种模式的运用和理解的欠缺。
因此需要不断进行总结。
七. 实验结果(关键源代码)单词符号输出形式(表格)如下:。
编译原理-实验⼆-FLEX词法分析器FLEX词法分析器⼀、Lex和Yacc介绍Lex 是⼀种⽣成扫描器的⼯具。
扫描器是⼀种识别⽂本中的词汇模式的程序。
⼀种匹配的常规表达式可能会包含相关的动作。
这⼀动作可能还包括返回⼀个标记。
当 Lex 接收到⽂件或⽂本形式的输⼊时,它试图将⽂本与常规表达式进⾏匹配。
它⼀次读⼊⼀个输⼊字符,直到找到⼀个匹配的模式。
如果能够找到⼀个匹配的模式,Lex 就执⾏相关的动作(可能包括返回⼀个标记)。
另⼀⽅⾯,如果没有可以匹配的常规表达式,将会停⽌进⼀步的处理,Lex 将显⽰⼀个错误消息。
Yacc代表 Yet Another Compiler Compiler 。
Yacc 的 GNU 版叫做 Bison。
它是⼀种⼯具,将任何⼀种编程语⾔的所有语法翻译成针对此种语⾔的 Yacc 语法解析器。
(下载下载flex和bison。
⽹址分别是/packages/flex.htm和/packages/bison.htm。
)⼆、配置环境(win7)①下载flex和bison并安装到D:\GnuWin32(尽量是根⽬录)②由于我们使⽤的flex和bison都是GNU的⼯具,所以为了⽅便,采⽤的C/C++编译器也采⽤GNU的编译器GCC,当然我们需要的也是Windows版本的GCC了。
所以提前准备好VC 6.0③检验是否可以进⾏lex⽂件编译1.新建⽂本⽂件,更改名称为lex.l,敲⼊下⾯代码%{int yywrap(void);%}%%%%int yywrap(void){return 1;}2.新建⽂本⽂件,更改名称为yacc.y,敲⼊下⾯代码%{void yyerror(const char *s);%}%%program:;%%void yyerror(const char *s){}int main(){yyparse();}我们暂且不讨论上⾯代码的意思。
打开控制台,进⼊到刚才所建⽴⽂件(lex.l,yacc.y)所在的⽂件夹。
flex编译原理教程Flex编译原理教程一、引言Flex(Fast Lexical Analyzer Generator)是一个快速的词法分析器生成工具,它能够将输入的正则表达式规则转化为有效的C代码,用于实现词法分析的过程。
本文将介绍Flex编译原理的基本概念和实现过程。
二、什么是词法分析词法分析是编译过程中的第一个阶段,它负责将源程序中的字符序列划分为有意义的词素(Token)序列。
词素是语言中的基本单位,例如关键字、标识符、常数、运算符等。
词法分析器的任务就是根据预先定义的词法规则,将输入的字符序列转化为词素序列。
三、Flex编译原理概述Flex的工作原理是基于有限状态自动机(Finite State Automaton)的。
它将词法规则表示成一系列正则表达式,并将其转化为NFA (Nondeterministic Finite Automaton)和DFA(Deterministic Finite Automaton)。
Flex会将这些自动机转化为C代码,从而实现词法分析器。
四、Flex编译原理详解1. 定义词法规则在Flex中,词法规则是用正则表达式表示的。
每个规则由两部分组成:模式(pattern)和动作(action)。
模式用于匹配输入字符序列,动作则指定匹配成功后的处理逻辑。
2. 构建NFA根据词法规则,Flex会构建一组NFA片段,每个片段对应一个词法规则。
NFA片段由一组状态和转移函数组成。
状态表示在词法分析过程中的不同状态,转移函数表示状态之间的转换关系。
3. 合并NFA将所有NFA片段合并成一个大的NFA。
合并的过程中,Flex会将各个片段的接受状态通过ε转移链接在一起,形成新的接受状态。
4. 子集构造法通过子集构造法将NFA转化为DFA。
子集构造法的基本思想是根据当前状态和输入字符,确定下一个状态。
通过不断迭代,直到构造出完整的DFA。
5. DFA最小化对生成的DFA进行最小化处理,去除一些不可达状态和等价状态,减少状态的数量。
实验四借助Flex/Bison进行语法分析一.说明:利用附录提供的C语言文法的相关参考资料,利用Yacc/Bison编写一个C语言分析器。
二.具体内容:利用语法分析器生成工具Bison编写一个语法分析程序,与词法分析器结合,能够根据语言的上下文无关文法,识别输入的单词序列是否文法的句子。
三.实验要求:实验资料如下:3.1 阅读Flex源文件input.lex、Bison源文件cgrammar-new.y。
3.2 实现C 语言的语法分析功能,最后上机调试。
3.3 生成语法分析程序2_2.exe,以给定的测试文件作为输入,输出运行结果到输出文件中。
四.实验过程:(1)执行以下命令,生成lex.yy.c、cgrammar-new.tab.h、cgrammar-new.tab.c。
(2)cgrammar-new.y有移近规约冲突。
执行命令bison -d cgrammar-new.y 后,Bison提示移近规约冲突“cgrammar-new.y: conflicts: 1 shift/reduce”。
以Bison的"-v"选项生成状态机描述文件cgrammar-new.output,即执行bison -d cgrammar-new.y。
cgrammar-new.output文件内容如下:修改以下两处:2.1 在yacc的头部加入%nonassoc LOWER_THAN_ELSE%nonassoc ELSE2.2 在355行加入%prec LOWER_THAN_ELSE(3)编译使用cl.exe或gcc编译器,编译lex.yy.c cgrammar-new.tab.c main.c parser.c。
使用cl.exe编译后,得到以下错误提示:修改lex.yy.c,使其能顺利编译。
3.1 将lex.yy.c中的#ifdef __cplusplusstatic int yyinput()#elsestatic int input()#endif改为static int yyinput()2.2 将lex.yy.c中的#ifdef __cplusplusreturn yyinput();#elsereturn input();#endif改为return yyinput();(3)生成可执行文件2_2.exe,并分析源文件test.c。
基于LEX的C语言词法分析器下面是一个基于LEX的C语言词法分析器的示例代码:```c#include <stdio.h>%}letter [a-zA-Z]digit [0-9]id {letter}({letter},{digit})*number {digit}+(\.{digit}+)?([eE][+-]?{digit}+)?%%{number} { printf("Number: %s\n", yytext); }{if} { printf("If: %s\n", yytext); }{else} { printf("Else: %s\n", yytext); }{while} { printf("While: %s\n", yytext); }{for} { printf("For: %s\n", yytext); }{id} { printf("Identifier: %s\n", yytext); }[ \t\n]+ // ignore white space. { printf("Unrecognized character: %c\n", yytext[0]); }%%int maiyylex(;return 0;```在上述代码中,首先是一些初始化的定义,定义了一些正则表达式模式,例如`letter`表示字母,`digit`表示数字,`id`表示标识符,`number`表示数字。
然后是各个模式的匹配规则和对应的处理逻辑。
其中,`{number}`表示如果匹配到了数字模式,就打印出该数字;`{if}`、`{else}`、`{while}`、`{for}`和`{id}`分别表示匹配到了if、else、while、for关键字和标识符,就打印出对应的信息;`[ \t\n]+`表示忽略空格和换行符;`.`表示匹配到了其他未定义的字符,就打印出异常信息。
词法分析器生成工具flex1.FLEX简介单词的描述称为模式(Lexical Pattern),模式一般用正规表达式进行精确描述。
FLEX通过读取一个有规定格式的文本文件,输出一个如下所示的C语言源程序。
+------------+ +------------+ +----------------+| 输入文件*.l |------>|flex工具 |------>|输出文件lex.yy.c |+------------+ +------------+ +----------------+FLEX的输入文件称为LEX源文件,它内含正规表达式和对相应模式处理的C语言代码。
LEX 源文件的扩展名习惯上用.l表示。
FLEX通过对源文件的扫描自动生成相应的词法分析函数int yylex(),并将之输出到名规定为lex.yy.c的文件中。
实用时,可将其改名为lexyy.c。
该文件即为LEX的输出文件或输出的词法分析器。
也可将int yylex()加入自已的工程文件中使用。
2. LEX源文件的格式LEX对源文件的格式要求非常严格,比如若将要求顶行书写的语句变成非顶行书写就会产生致命错误。
而LEX本身的查错能力很弱,所以书写时一定要注意。
下面以统计单词出现的次数的源程序count.l做说明,count.l的内容如下:%{#include "stdio.h"#include "stdlib.h"int num_num=0,num_id=0;%}INTEGER [-+]?[1-9][0-9]*ID [a-zA-Z][a-zA-Z_0-9]*SPACE [ /n/t]%%{INTEGER} { num_num++;printf("(num=%d)/n",atoi(yytext));/*打印数字值*//*数字数加一*/}{ID} { num_id++;printf("(id=%s)/n",yytext);}{SPACE} |. {/*什么也不做,滤掉白字符和其它字符*/}%%int main(){yylex();printf("num=%d,id=%d/n",num_num,num_id);return 0;}int yywrap()//此函数必须由用户提供{return 1;}定义部份由C语言代码、模式的宏定义、条件模式的开始条件说明三部份组成。
课程设计1 基于Flex的词法分析器设计及实现1.1 需求分析1.1.1 问题定义1、通过对 flex 基本知识的阅读,了解其工作原理和过程以及其匹配模式和规则,掌握简单的 lex 语法和规则;2、在上述基础上能够自主编写出简单且可以运行的词法分析器,实现简单的词法分析功能;3、通过实验,设计编制调试一个具体的词法分析程序,加深对词法分析原理的理解,并掌握在对程序设计语言源程序进行扫描过程中将其分解为各类单词的词法分析方法。
1.1.2 功能描述本次编制调试的词法分析器基本可以实现如下简单功能:1、可以匹配识别关键字:else if switch for int float return void while (所有的关键字都是保留字,并且必须是小写);2、可以匹配识别专用符号: + - * / < <= > >= == != = ; ,( ) [ ] { } /* */;3、标识符(ID)和数字(NU )通过下列正则表达式定义: ID = letter letter* NUM = digit digit* letter = a|..|z|A|..|Z digit = 0|..|9;4、可以匹配识别空格(空格由空白、换行符和制表符组成,空格通常被忽略,除了它必须分开 ID、NUM 关键字);5、可以识别简单的注释(/* 注释内容*/);1.1.3 开发环境及工具介绍1、Window环境下载Visual Studio之后,利用其命令提示窗口进行操作。
下载并安装Flex。
2、vs2010的编译器cl.exe。
3、flex:词法分析器Flex是用来生成程序的工具,他们所生成的程序能够处理结构化输入,最初的Flex是用来生成编译器的,但是后来他们被证明在其他领域也非常有效。
Flex是一个SourceForge项目。
其依赖于GNU m4宏处理器。
Linux和BSD都应该有m4,对于Windos用户来说,Flex被包含在Cygein Linux模拟环境中。
(一)实验题目:flex生成词法分析器(二)实验目的:掌握词法分析程序生成器flex的用法(三)实验内容:例程一:Count.l:%{int num_lines = 0;num_chars = 0;%}%%\n ++num_lines; ++num_chars;. ++num_chars;%%main( argc, argv )int argc;char **argv;{++argv, --argc; /* skip over program name */if ( argc > 0 )yyin = fopen( argv[0], "r" );elseyyin = stdin;yylex();printf( "# of lines = %d, # of chars = %d\n",num_lines, num_chars ); }int yywrap(){return 1;}分析文件:abc.txt:运行结果:例程二:Sample1.l:/* scanner for a toy Pascal-like language */%{/* need this for the call to atof() below */#include <math.h>%}DIGIT [0-9]ID [a-z][a-z0-9]*%%{DIGIT}+ { printf( "An integer:%s(%d)\n",yytext, atoi( yytext ) ); } {DIGIT}+"."{DIGIT}* { printf( "A float: %s (%g)\n", yytext,atof( yytext ) ); }if|then|begin|end|procedure|function { printf( "A keyword: %s\n", yytext ); }{ID} printf( "An identifier: %s\n", yytext ); "+"|"-"|"*"|"/" printf( "An operator: %s\n", yytext );"{"[^}\n]*"}" /* eat up one-line comments */[ \t\n]+ /* eat up whitespace */. printf( "Unrecognized character: %s\n", yytext );%%main( argc, argv )int argc;char **argv;{++argv, --argc; /* skip over program name */ if ( argc > 0 )yyin = fopen( argv[0], "r" );elseyyin = stdin;yylex(); /*调用词法分析器*/}int yywrap(){return 1;}运行结果:。
词法分析器的设计与实现
1.定义词法规则:根据编程语言的语法规范,定义不同的词法规则,
如关键字、标识符、操作符、常量等。
每个词法规则由一个正则表达式或
有限自动机来描述。
2.构建有限自动机:根据词法规则,构建一个有限自动机(DFA)来
识别词法单元。
有限自动机是一种形式化模型,用于在输入字符序列上进
行状态转换。
3.实现状态转换函数:根据有限自动机的定义,实现状态转换函数。
状态转换函数接受一个输入字符,并返回当前状态和输出的词法单元。
4.实现输入缓冲区:为了方便词法分析器的实现,通常需要实现一个
输入缓冲区,用于存储源代码,并提供一些读取字符的函数。
5. 实现词法分析器:将前面实现的状态转换函数和输入缓冲区结合
起来,实现一个完整的词法分析器。
词法分析器可以使用迭代器模式,每
次调用next(函数来获取下一个词法单元。
6.处理错误情况:在词法分析过程中,可能会遇到一些错误情况,如
未定义的词法单元、不符合语法规范的词法单元等。
词法分析器需要能够
检测并处理这些错误情况。
7.构建测试用例:为了验证词法分析器的正确性,需要构建测试用例,包括各种不同的源代码片段,并验证分析结果是否符合预期。
8.进行性能优化:词法分析是编译器中的一个耗时操作,因此可以进
行一些性能优化,如使用缓存机制、减少状态转换次数等。
以上是词法分析器的设计与实现的一般步骤,具体实现过程可能因编程语言和编译器的不同而有所差异。
JFlex 的词法分析说明使用JFlex这个项目中使用JFlex 的目的是为我们的计算器创建一个词法分析器。
这个词法分析器,或者叫扫描器,将为我们计算器检查输入,而且确认所有的字符归类是有效的。
用于JFlex 的词法分析说明文件可以分成三个部分。
每个部分由%%分开。
用户代码段%%参数设置和声明段%%词法规则段用户代码段这个段中的所有内容将被拷贝到生成的词法类的类声明之前。
在这个段中,常见的是package 和import 语句。
我们的词法说明在这个段中引入(import)了两个类,sym 和java_cup.runtime.*,如下所示:import java_cup.runtime.*;import sym;在我们的例子中,sym 类(与处理器一起)由CUP产生。
参数设置和声明段这个段含有参数,词法状态,和宏定义。
设置参数将包含额外的代码,它们将被包括在产生的扫描器类。
参必须另开新行,以%开头。
可以包含的参数很多。
在随JFlex 来的手册中可以得到一个可以包含的参数列表。
在我们的词法说明中用到的参数如下:%class Lexer%line%column%cup第一个参数,class Lexer,告诉JFlex 把生成的类命名为Lexer并把代码写到名为Lexer.java的文件。
参数Line打开行计数,使你可以用变量yyline存取输入的当前行号。
参数column有类似的作用,除了它是通过变量yycolumn存取当前列号。
最后一个参数,cup,把JFlex设置成一个特殊模式,使它与CUP产生的处理器兼容,我们使用的就是。
然后,你可以声明扫描器用到的成员变量和函数。
可以加入的代码是Java 代码,并放在%{和}%之间。
它们将被拷贝到生成的词法类源代码中。
在我们的词法说明中,声明了两个成员函数。
这些函数创建java_cup.runtime.Symbol对象。
第一个仅仅记录当前记号的位置信息。
第二个还包含了记号的值。
词法分析程序自动工具使用说明2012词法分析程序自动工具使用说明1.建立工作文件夹如D:\LEX2.将词法分析工具flex.exe 拷入到该文件夹3.建立LEX源文件如:用文本编辑器建立lextemp.txt源文件%{#include#define BEGIN 101#define END 202%}digit [0-9]alpha [a-z]alnum [a-z0-9]%%begin {out(BEGIN,"begin");}end {out(END,"end");}"*" {out(303,"*");}"+" {out(404,"+");}{alpha}{alnum}* {out(505,yytext);}"=" {out(606,"=");}%%out(int c,char *val){printf("word:%d, %s\n",c,val);}4.建立简单语言的源程序文件如:用文本编辑器建立data.txt文件beginabcd=100efg=200gh123=300abcd=abcd*efgh+gh123end5.在DOS运行flex 生成目标文件lex.yy.c flex lex源文件名如:d:\lex\flex lextemp.txt6.进入VC,对lex.yy.c进行修改(1)增加或修改main()函数增加打开程序文件的语句int main(void){int c;if ((yyin=fopen("data.txt","r"))==NULL){printf("can’t open the file\n");exit(0);}yylex();return 0;}(2)增加函数int yywrap(){return 0;}(3)尾部上这二行屏蔽// #if YY_MAIN// #Endif7.运行得到结果识别出的单词将在屏幕输出,通过修改out 函数可改为输出到一文件中。
词法分析器的实现与设计
1. 确定待分析的源代码的字符集和词法规则:首先,确定源代码所
使用的字符集,例如ASCII或Unicode。
然后,根据编程语言的语法规则,确定各种词法单元(如关键字、标识符、操作符、常量等)的识别规则。
2.设计识别词法单元的算法:根据词法规则,设计算法来识别每个词
法单元。
通常,这涉及到使用正则表达式或有限自动机(DFA)来进行模
式匹配。
3. 实现词法分析器:使用选定的编程语言实现词法分析器。
词法分
析器可以使用手写的代码实现,也可以使用工具(如Lex、Flex等)来自
动生成。
4.构建词法分析器的输入和输出接口:词法分析器通常需要从输入流
中读取源代码,并将识别出的词法单元输出到输出流中。
因此,需要设计
适当的输入和输出接口。
5.测试和调试词法分析器:编写测试用例,用不同类型的代码对词法
分析器进行测试,以确保它能正确地识别各种词法单元。
在测试过程中,
需要检查词法分析器的输出是否符合预期的结果。
6.集成到编译器中:将词法分析器集成到编译器的其他部分中,例如
语法分析器、语义分析器等。
这需要定义合适的接口,并确保各个部分之
间的协调工作。
总结起来,词法分析器的设计和实现包括选择字符集和词法规则、设
计识别算法、实现词法分析器、构建输入和输出接口、测试和调试以及集
成到编译器中。
这些步骤需要综合考虑编程语言的特点、词法规则的复杂
性和性能需求等因素。
linux flex 用法Flex在Linux下通常用于生成词法分析器。
以下是Flex的基本用法:1. 安装Flex:在终端中运行以下命令:```sudo apt-get install flex```2. 编写Flex文件(.l文件):Flex文件由一系列规则组成,每个规则指定了如何匹配输入并执行相应的操作。
以下是Flex文件的示例:```%{// 包含头文件或定义全局变量等#include <stdio.h>%}%%// 正则表达式和对应的动作"hello" { printf("Hello, World!\n"); }[0-9]+ { printf("Number: %s\n", yytext); }[A-Za-z]+ { printf("ID: %s\n", yytext); }. { printf("Unknown: %c\n", yytext[0]); }%%// 可选的C代码部分int main() {yylex(); // 调用词法分析器return 0;}```3. 生成词法分析器:在终端中运行以下命令:```flex <flex_file_name>.l```这将生成一个名为`lex.yy.c`的C文件。
4. 编译词法分析器:在终端中运行以下命令:```gcc lex.yy.c -o lexer```这将生成一个可执行文件`lexer`。
5. 运行词法分析器:在终端中运行以下命令:```./lexer```输入一些文本,词法分析器将根据规则进行匹配,并执行相应的操作。
注意:以上示例中的规则和动作只是示范,您可以根据自己的需求进行修改和扩展。
还可以通过`man flex`命令查看更多Flex的用法和选项。
院系:计算机学院实验课程:编译原理实验项目:C++源代码单词扫描程序(词法分析)指导老师:陈寅开课时间:2014~2015年度第1学期专业:数据库班级:2班学生:雷楚楚学号:20122100158C++源代码单词扫描程序(词法分析)一、实验目的设计并实现一个词法分析器,深刻理解编译原理中词法分析器的原理。
二、实验内容1、C++源代码扫描程序识别C++记号。
C++语言包含了几种类型的记号:标识符,关键字,数(包括整数、浮点数),字符串,注释,特殊符号(分解符)和运算符号等。
2、打开一个C++源文件,打印出所有以上的记号。
3、选作部分:为了提高C++源程序的可读性,C++程序在书写过程中加入了空行、空格、缩进、注释等。
假设你想牺牲可读性,以节省磁盘空间,那么你可以存贮一个删除了所有不必要空格和注释的C++源程序的压缩文本。
因此,程序中还看可以有这样的压缩功能。
4、进一步实现减少源文件大小的压缩功能。
5、完善软件文档。
二、实验过程1、对C++文法中的各类单词分类(1)保留字:asm、do、if、return、typedef、auto、double、inline、short、typeid、bool、try、include、long、sizeof、union、case、enum、mutable、static、unsigned、long、sizeof、union、case、enum、mutable、static、unsigned、catch、explicit、namespace、using、char、export、int、signed、break、else、new、struct、virtual、class、extern、operator、switch、void、const、false、private、template、volatile、float、protected、this、continue、for、public、throw、while、default、friend、register、true、delete、goto、try、include、std、iomanip、setw、setprecision、endl、setiosflags、ios (2)数字:包括整数和浮点数(3)标识符:由字母打头的字母和数字的字符串,可包含下划线(4)运算符:"&="、"^="、"、="、"<<="、">>="、"*="、"/="、"%="、"+="、"-="、"="、"?:"、"、、"、"&&"、"、"、"^"、"&"、"=="、"!="、">"、">="、"<"、"<="、"<<"、">>"、"+"、"-"、"*"、"/"、"%"、".*"、"->*"、"&"、"+"、"-"、"++"、"--"、"->"、"::"(5)界符:"{"、"}"、"("、")"、"#"、","、":"、";"、"."、"\""(6)注释:包括//和/**/两种类型的注释(7)字符串:包含在“”里面的内容2、将各类单词对应到Flex中:(1)保留字:asm|do|if|return|typedef|auto|double|inline|short|typeid|bool|try|include|long|sizeof|union|case|enum|mutable|static|unsigned|long|sizeof|union|case|enum|mutable|static|unsigned|catch|explicit|namespace|using|char|export|int|signed|break|else|new|struct|virtual|class|extern|operator|switch|void|const|false|private|template|volatile|float|protected|this|continue|for|public|throw|while|default|friend|register|true|delete|goto|try|include|std|iomanip|setw|setprecision|endl|setiosflags|ios(2)数字:包括整数和浮点数(正负)[+-]?([0-9]*|0|([0-9]*\.[0-9]*))(3)标识符:由字母打头的字母和数字的字符串,包含下划线[A-Za-z]([A-Za-z]|[0-9]|_)*(4)运算符:"&="|"^="|"|="|"<<="|">>="|"*="|"/="|"%="|"+="|"-="|"="|"?:"|"||"|"&&"|"|"|"^"|"&"|"=="|"!="|">"|">="|"<"|"<="|"<<"|">>"|"+"|"-"|"*"|"/"|"%"|".*"|"->*"|"&"|"+"|"-"|"++"|"--"|"->"|"::"(5)界符:"{"|"}"|"("|")"|"#"|","|":"|";"|"."|"\""(6)注释:包括//和/**/两种类型的注释\/\*(\s|.)*?\*\/(/**/)\/\/[^\n]*(//)(7)字符串:包含在“”里面的内容'[^'\n]*'|\"[^\"]*\"(8)除其他情况之外判断为出错3、跳过空行和空格[\t]+{}/*空格*/ \n|.{}/*空行*/4、为lex制定一些规则5、写子程序让用户输入要进行词法扫描的文件,当lex读完输入文件之后就会调用函数yywrap。
实验项目二语法和语义分析器一、实验类型本实验为验证性实验。
二、实验目的1.掌握 Yacc 的基本用法,并能够根据语言给出语法规则的定义,最后生成语言的解析器;2.使用Yacc实现一个高级计算器程序。
三、准备工作和预备知识在进一步阐述以前,让我们复习一下什么是语法。
在上一节中,我们看到Lex 从输入序列中识别标记。
如果你在查看标记序列,你可能想在这一序列出现时执行某一动作。
这种情况下有效序列的规范称为语法。
Yacc 语法文件包括这一语法规范。
它还包含了序列匹配时你想要做的事。
为了更加说清这一概念,让我们以英语为例。
这一套标记可能是:名词, 动词, 形容词等等。
为了使用这些标记造一个语法正确的句子,你的结构必须符合一定的规则。
一个简单的句子可能是名词+动词或者名词+动词+名词。
(如I care. See spot run.)所以在我们这里,标记本身来自语言(Lex),并且标记序列允许用Yacc 来指定这些标记(标记序列也叫语法)。
用Yacc 来创建一个编译器包括四个步骤:1. 通过在语法文件上运行Yacc 生成一个解析器。
2. 说明语法:o编写一个 .y 的语法文件(同时说明C 在这里要进行的动作)。
o编写一个词法分析器来处理输入并将标记传递给解析器。
这可以使用Lex 来完成。
o编写一个函数,通过调用yyparse() 来开始解析。
o编写错误处理例程(如yyerror())。
3. 编译Yacc 生成的代码以及其他相关的源文件。
4. 将目标文件链接到适当的可执行解析器库。
终端和非终端符号终端符号 : 代表一类在语法结构上等效的标记。
终端符号有三种类型:命名标记: 这些由%token标识符来定义。
按照惯例,它们都是大写。
字符标记 : 字符常量的写法与C 相同。
例如, -- 就是一个字符标记。
字符串标记 : 写法与C 的字符串常量相同。
例如,"<<" 就是一个字符串标记。
lexer 返回命名标记。
《C-语⾔的词法分析器(基于Lex)》课程设计报告《编译原理与实践》课程报告课题名称: C-语⾔的词法分析器实现(基于Lex)课题负责⼈名(学号):李恒(0643111198)同组成员名单(⾓⾊):⽆指导教师:于中华评阅成绩:评阅意见:提交报告时间:2007 年12 ⽉31⽇1. ⽬的与意义词法分析是编译原理中⼀个重要的部分。
它可将源程序读作字符⽂件并将其分为若⼲个记号,每⼀个记号都是表⽰源程序中信息单元的字符序列。
词法分析器是翻译步骤的第⼀步,它对于编译器接下来要进⾏的⼯作起着开头的作⽤,因此要想实现对C-语⾔的编译器,词法分析器必不可少。
2. 基于Parser Generator的词法分析器构造⽅法利⽤Parser Generator构造词法分析器规则,⽣成对应的c语⾔及其头⽂件。
然后进⾏编译。
3. C-语⾔词法分析的设计重要数据类型:关键字枚举:typedef enum{ENDFILE, ERROR,/* reserved words */ELSE, IF, INT, RETURN, VOID, WHILE,/* multicharacter tokens */ID, NUM,/* special symbols */PLUS, MINUS, TIMES, OVER, LT, LE, GT, GE, EQU, NEQU,ASSIGN, SEMI, COMMA, LPAREN, RPAREN, LBRKT, RBRKT, LBRC, RBRC, LCOM, RCOM}TokenType;关键字声明:digit [0-9]number {digit}+letter [a-zA-Z]identifier {letter}+newline \nwhitespace [ \t]+c-语⾔的词法规则:"else" {return ELSE;} "if" {return IF;}"int" {return INT;} "return" {return RETURN;} "void" {return VOID;} "while" {return WHILE;} "+" {return PLUS;} "-" {return MINUS;} "*" {return TIMES;} "/" {return OVER;} "<" {return LT;}"<=" {return LE;} ">" {return GT;}">=" {return GE;}"==" {return EQU;}"!=" {return NEQU;} "=" {return ASSIGN;} ";" {return SEMI;} "," {return COMMA;} "(" {return LPAREN;} ")" {return RPAREN;} "[" {return LBRKT;} "]" {return RBRKT;} "{" {return LBRC;} "}" {return RBRC;} {number} {return NUM;} {identifier} {return ID;} {newline} {lineNo++} {whitespace} {/* skip */} "/*" { char c;do{ c = input();if (c == EOF ) break;if (c == '\n' ) lineNo++;} while ( c != '/*');}{return ERROR;}重要处理程序设计:⽂件util.c执⾏输出结果的打印:void printToken(TokenType token, const char* tokenString) { switch (token){case ELSE:case IF:case INT:case RETURN:case VOID:case WHILE:fprintf(listing, "reserved word: %s\n", tokenString);break;case PLUS:fprintf(listing, "+\n");break;case MINUS:fprintf(listing, "-\n");break;case TIMES:fprintf(listing, "*\n");break;case OVER:fprintf(listing, "/\n");break;case LT:fprintf(listing, "<\n");break;case LE:fprintf(listing, "<=\n");break;fprintf(listing, ">\n"); break;case GE:fprintf(listing, ">=\n"); break;case EQU:fprintf(listing, "==\n"); break;case NEQU:fprintf(listing, "!=\n"); break;case ASSIGN: fprintf(listing, "=\n"); break;case SEMI:fprintf(listing, ";\n"); break;case COMMA: fprintf(listing, ",\n"); break;case LPAREN: fprintf(listing, "(\n"); break;case RPAREN: fprintf(listing, ")\n"); break;case LBRKT: fprintf(listing, "[\n"); break;case RBRKT: fprintf(listing, "]\n"); break;case LBRC:fprintf(listing, "{\n");case RBRC:fprintf(listing, "}\n");break;case LCOM:fprintf(listing, "/*\n");break;case RCOM:fprintf(listing, "*/\n");break;case ENDFILE:fprintf(listing,"EOF\n");break;case NUM:fprintf(listing, "NUM,val=%s\n",tokenString); break;case ID:fprintf(listing, "ID, name=%s\n",tokenString); break;case ERROR:fprintf(listing, "ERROR: %s\n",tokenString); break;default:break;}}函数getToken获取下⼀个token:TokenType getToken(void){ static int firstTime = TRUE; TokenType currentToken;if (firstTime){ firstTime = FALSE;lineNo++;yyin = source;yyout = listing;}currentToken = yylex();strncpy(tokenString,yytext,MAXTOKENLEN);if (TraceScan) {fprintf(listing, "\t%d: ", lineNo);printToken(currentToken,tokenString);}return currentToken;}4. 运⾏结果及分析输⼊⽂件如果所⽰:输出结果如图:对于输⼊的每⼀⾏进⾏词法分析,表⽰出保留字,标识符,以及终结符。
实验项目一词法分析器一、实验类型本实验为验证性实验。
二、实验目的1.通过本实验加深对词法分析程序的功能及实现方法的理解;2.使用flex实现词法分析程序。
三、准备工作和预备知识Lex(Lexical Analyzar 词法分析生成器)是Unix下十分重要的词法分析工具。
经常用于语言分析,公式编译等广泛领域。
1.Lex(Lexical Analyzar) 初步示例先看简单的例子:一个简单的Lex文件 exfirst.l 内容:%{#include "stdio.h"%}%%[\n] ;[0-9]+ printf("Int : %s\n",yytext);[0-9]*\.[0-9]+ printf("Float : %s\n",yytext);[a-zA-Z][a-zA-Z0-9]* printf("Var : %s\n",yytext);[\+\-\*\/\%] printf("Op : %s\n",yytext);“.” printf("Unknown : %c\n",yytext[0]);%%在命令行下执行命令flex解析,会自动生成lex.yy.c文件:[root@localhost liweitest]flex exfirst.l进行编译生成parser可执行程序:[root@localhost liweitest]cc -o parser lex.yy.c –ll或者[root@localhost liweitest]gcc lex.yy.c –ll -o parser[注意:如果不加-ll链结选项,cc编译时会出现以下错误,后面会进一步说明。
] /tmp/cciACkbX.o(.text+0x37b): In function `yylex':: undefined reference to `yywrap'/tmp/cciACkbX.o(.text+0xabd): In function `input':: undefined reference to `yywrap'创建待解析的文件 file.txt:titlei=1+3.9;a3=909/6bcd=4%9-333通过已生成的可执行程序,进行文件解析。
课程设计1 基于Flex的词法分析器设计及实现1.1 需求分析1.1.1 问题定义1、通过对 flex 基本知识的阅读,了解其工作原理和过程以及其匹配模式和规则,掌握简单的 lex 语法和规则;2、在上述基础上能够自主编写出简单且可以运行的词法分析器,实现简单的词法分析功能;3、通过实验,设计编制调试一个具体的词法分析程序,加深对词法分析原理的理解,并掌握在对程序设计语言源程序进行扫描过程中将其分解为各类单词的词法分析方法。
1.1.2 功能描述本次编制调试的词法分析器基本可以实现如下简单功能:1、可以匹配识别关键字:else if switch for int float return void while (所有的关键字都是保留字,并且必须是小写);2、可以匹配识别专用符号: + - * / < <= > >= == != = ; ,( ) [ ] { } /* */;3、标识符(ID)和数字(NU )通过下列正则表达式定义: ID = letter letter* NUM = digit digit* letter = a|..|z|A|..|Z digit = 0|..|9;4、可以匹配识别空格(空格由空白、换行符和制表符组成,空格通常被忽略,除了它必须分开 ID、NUM 关键字);5、可以识别简单的注释(/* 注释内容*/);1.1.3 开发环境及工具介绍1、Window环境下载Visual Studio之后,利用其命令提示窗口进行操作。
下载并安装Flex。
2、vs2010的编译器cl.exe。
3、flex:词法分析器Flex是用来生成程序的工具,他们所生成的程序能够处理结构化输入,最初的Flex是用来生成编译器的,但是后来他们被证明在其他领域也非常有效。
Flex是一个SourceForge项目。
其依赖于GNU m4宏处理器。
Linux和BSD都应该有m4,对于Windos用户来说,Flex被包含在Cygein Linux模拟环境中。
什么是FLEX?它是一个自动化工具,可以按照定义好的规则自动生成一个C 函数yylex(),也成为扫描器(Scanner)。
这个C函数把文本串作为输入,按照定义好的规则分析文本串中的字符,找到符合规则的一些字符序列后,就执行在规则中定义好的动作(Action)。
例如在规则中可以这样定义:如果遇到一个换行字符\n,那么就把行计数器的值加一。
Flex文件就是一个文本文件,内容包括定义好的一系列词法规则。
1.2 系统概要设计1.2.1 系统体系结构Flex源文件(.l)flex词法分析器的C语言源文件(.h)编译此法分析器的课执行程序图1-1 体系结构图开始初始化读入需要分析的语句还有单词未分析?读一个字符是字母?是数字?其他单词分析程序输出单词二元式常数分析程序关键字或标识符分析程序结束是否否是是否图1-2 词法分析流程图1.2.2 系统模块划分Lex 工具是一种词法分析程序生成器,它可以根据词法规则说明书的要求来生成单词识别程序,由该程序识别出输入文本中的各个单词。
一般可以分为<定义部分><规则部分>< 用户子程序部分>。
其中规则部分是必须的,定义和用户子程序部分是任选的。
(1)定义部分:定义部分起始于 %{ 符号,终止于 %} 符号,其间可以是包括 include 语句、声明语句在内的 C 语句。
这部分跟普通 C 程序开头没什么区别。
(2)规则部分:规则部分起始于"%%"符号,终止于"%%"符号,其间则是词法规则。
词法规则由模式和动作两部分组成。
模式部分可以由任意的正则表达式组成,动作部分是由 C 语言语句组成,这些语句用来对所匹配的模式进行相应处理。
需要注意的是,lex 将识别出来的单词存放在 yytext[]字符数据中,因此该数组的内容就代表了所识别出来的单词的内容。
类似 yytext 这些预定义的变量函数会随着后面内容展开一一介绍。
动作部分如果有多行执行语句,也可以用{}括起来。
(3)用户子程序部分:最后一个%%后面的内容是用户子程序部分,可以包含用 C 语言编写的子程序,而这些子程序可以用在前面的动作中,这样就可以达到简化编程的目的。
这里需要注意的是,当编译时不带-ll 选项时,是必须加入 main 函数和 yywrap(yywrap 将下后面说明)。
Lex 其实就是词法分析器,通过配置文件*.l,依据正则表达式逐字符去顺序解析文件,并动态更新内存的数据解析状态。
Lex 善长于模式匹配。
词法分析的基本任务是从字符串表示的源程序中识别出具有独立意义的单词符号,其基本思想是根据扫描到单词符号的第一个字符的种类,拼出相应的单词符号。
词法分析阶段是编译过程的第一个阶段,是编译的基础。
这个阶段的任务是从左到右一个字符一个字符地读入源程序,即对构成源程序的字符流进行扫描然后根据构词规则识别单词(也称单词符号或符号)。
词法分析的核心任务是扫描、识别单词且对识别出的单词给出定性、定长的处理;实现词法分析程序的常用途径:自动生成, 手工生成。
1.3 详细设计与实现1.3.1 Lex代码的设计与实现lex 源代码编写通过对 flex 的语法学习,掌握了编写的基本原则和步骤,因为实验要求编写一个简单地词法分析器,根据实验所要求实现检查分析的功能,实验代码较为简单,以下是自己编写的实验代码:letter [a-zA-Z\_] 定义字母letterdight [0-9] 定义数字dightID {letter}({letter})* 定义单词ID由若干个字母组成NUM {dight}({dight})* 定义数字串NUM由若干个数字组成B {letter}({dight}|{letter})* 定义标识符B 由数字戒字母组成%{int nchar, nword, nline; nchar 字符数nword单词数nline 行数int line=1; line 为当前行数初始化为1%}%%"else"|"if"|"else if"|"switch"|"for"|"int"|"float"|"return"|"void"|"while"{nword++;nchar+=yyleng;printf("第%d 行:\t",line);printf("关键字:%s\n",yytext);}若匹配上else int float 等上述的关键字:单词数+1;字符数增加相应的个数;输出“第line 行yytext \n”;{B} {nword++;nchar+=yyleng;printf("第%d 行:\t",line);printf("标识符:%s\n",yytext);} {B} {nword++;nchar+=yyleng;printf("第%d 行:\t",line);printf("标识符:%s\n",yytext);}若匹配上B 标识符:单词数+1;字符数增加相应的个数;输出“第line 行标识符:yytext \n”;{NUM} {nword++;nchar+=yyleng;printf("第%d 行:\t",line);printf("数字:%s\n",yytext);}若匹配上NUM数字:单词数+1;字符数增加相应的个数;输出“第line 行数字:yytext \n”;\+|\-|\*|\/|\<|\>|\=|\;|\,|\(|\)|\[|\]|\{|\} {nchar+=yyleng;printf("第%d行:\t",line);printf("与%s\n",yytext);}若匹配上+ - * / 等与:字符数增加相应的个数;输出“第line 行与yytext \n”;\<\=|\>\=|\=\=|\!\=|\/\*|\*\/ {nword++;nchar+=yyleng;printf("第%d行:\t",line);printf("与%s\n",yytext);}若匹配上< = > 等与:字符数增加相应的个数;输出“第line 行与yytext \n”;[ \t]+ {nchar++;}若匹配上制表符:字符数+1;无输出;\n { nline++;line++;nchar++; }若匹配上回车\n:字符数+1;行数+1;当前行数line+1;无输出;[^ \t\n]+ { nword++;nchar+=yyleng;printf("第%d 行:\t",line);printf("其他符号:%s\n",yytext);}若匹配上其他符号:字符数增加相应的个数;输出“第line 行其他符号:yytext \n”;%%void main(){yylex(); 调用yylex 函数printf("字符数:%d\t 单词数:%d\t 行数:%d\n", nchar, nword,nline);} 最后输出字符数、单词数、行数int yywrap(){return 1;}最后将这些代码按照flex 语法进行整合得到完整flex 源码,得到源程序lex1.l;1.3.2 定义部分的设计与实现定义部份由C语言代码、模式的宏定义、条件模式的开始条件说明三部份组成。
其中,C代码部份由顶行的%{和}%引入,LEX扫描源文件时将%{和}%之间的部分原封不动的拷贝到输出文件lex.yy.c中。
上面的定义部分没有条件模式的开始条件说明部分,只有C语言代码、模式的宏定义。
模式宏定义是一个正则表达式的定义,如上面所示的INTEGER [-+]?[1-9][0-9]*。
正则表达式的匹配如下:1.3.3 规则部分的设计与实现规则部份是LEX源文件的核心部份,它包括一组模式和在生成分析器识别相应模式后对相应模式进行处理的C语言动作(Action)。
格式如下同定义部分一样,C语言代码必须出现在第一个模式之前,包括在%{和}%之中,且%{必须顶行书写。
%{和}%之间的代码部份可用来定义yylex()用到的局部变量。
模式必须顶行书写。