编译原理 实验2 词法分析器
编译原理-实验二-FLEX词法分析器

编译原理-实验⼆-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)所在的⽂件夹。
编译原理词法分析实验报告

编译原理词法分析实验报告实验名称:词法分析器的设计与实现一、实验目的:1.熟悉编译原理中词法分析的基本概念和原理;2.掌握正则表达式的使用方法;3.实现一个简单的词法分析器。
二、实验内容:1.设计一个简单的编程语言,包含如下几种类型的词法单元:关键字、标识符、常量、运算符和界符。
2.使用正则表达式定义每种词法单元的模式。
3.设计一个词法分析器,将源代码中的每个词法单元识别出来并输出。
三、实验步骤:1. 确定编程语言的词法单元类型和正则表达式模式,定义相应的单词类型(如 TokenType)和模式(如 regex)。
2. 实现一个词法分析器的类 Lexer,包含以下方法:(1)一个构造方法,用于初始化词法分析器的输入源代码。
(2) 一个getNextToken方法,用于获取源代码中的下一个词法单元。
3. 在getNextToken方法中,使用正则表达式逐个识别源代码中的词法单元,并返回相应的Token对象。
4. 设计一个Token类,包含以下属性:词法单元类型、词法单元的值和位置信息等。
5.在主程序中使用词法分析器,将源代码中的每个词法单元识别出来并输出。
四、实验结果:1.设计一个简单的编程语言,包含如下词法单元类型(示例):(1) 关键字:if、else、while、for等;(2)标识符:变量名等;(3)常量:整数、浮点数、字符串等;(4)运算符:+、-、*、/、=等;(5)界符:(、)、{、}、;等。
2. 实现一个词法分析器,识别出源代码中的每个词法单元,并输出相应的Token对象。
五、实验总结:通过本次实验,我熟悉了编译原理中词法分析的基本概念和原理,并掌握了正则表达式的使用方法。
我成功完成了一个简单的词法分析器的设计与实现,实现了源代码中每个词法单元的识别与输出。
这次实验对我深化了对编译原理中词法分析的理解,并提高了我的编程能力。
编译原理实验报告

编译原理实验报告一、实验概述本次实验旨在设计并实现一个简单的词法分析器,即实现编译器的第一个阶段,词法分析。
词法分析器将一段源程序代码作为输入,将其划分为一个个的词法单元,并将其作为输出。
二、实验过程1.设计词法规则根据编程语言的规范和所需实现的功能,设计词法规则,以明确规定如何将源程序代码分解为一系列的词法单元。
2.实现词法分析器采用合适的编程语言,根据所设计的词法规则,实现词法分析器。
词法分析器的主要任务是读入源程序代码,并将其根据词法规则进行分解,生成对应的词法单元。
3.测试词法分析器设计测试用例,用于检验词法分析器的正确性和性能。
测试用例应包含各种情况下的源程序代码。
4.分析和修正错误根据测试过程中发现的问题,分析产生错误的原因,并进行修正。
重复测试和修正的过程,直到词法分析器能够正确处理所有测试用例。
三、实验结果我们设计了一个简单的词法分析器,并进行了测试。
测试用例涵盖了各种情况下的源程序代码,包括正确的代码和错误的代码。
经过测试,词法分析器能够正确处理所有的测试用例。
词法分析器将源程序代码分解为一系列的词法单元,每个词法单元包含了单词的种类和对应的值。
通过对词法单元的分析,可以进一步进行语法分析和语义分析,从而完成编译过程。
四、实验总结通过本次实验,我深入了解了编译原理的词法分析阶段。
词法分析是编译器的第一个重要阶段,它将源程序代码分解为一个个的词法单元,为后续的语法分析和语义分析提供基础。
在实现词法分析器的过程中,我学会了如何根据词法规则设计词法分析器的算法,并使用编程语言实现词法分析器。
通过测试和修正,我掌握了调试和错误修复的技巧。
本次实验的经验对我今后的编程工作有很大帮助。
编译原理是计算机科学与技术专业的核心课程之一,通过实践能够更好地理解和掌握其中的概念和技术。
我相信通过进一步的学习和实践,我能够在编译原理领域取得更大的成果。
编译原理 词法分析器

一、实验目的和要求:设计并实现一个PL/0语言(或其它语言,如C语言)的词法分析程序,加深对词法分析原理的理解。
二、实验原理:词法分析是从左向右扫描每行源程序的符号,拼成单词,换成统一的机内表示形式——TOKEN字,送给语法分析程序。
TOKEN字是一个二元式:(单词种别码,自身值)。
PL/0语言单词的种别码参见教材(或自行设定),单词自身值按如下规则给出:1 标识符的自身值是它在符号表的入口地址。
2常数的自身值是常数本身(或它的二进制数值)。
3关键字和界限符的自身值为本身。
三、实验步骤与要求1、设计的词法分析器符合软件工程的要求。
2、编制程序,此程序应具有如下功能:1)输入:字符串(待进行词法分析的源程序),输出:由(种别码,自身值)所组成的二元组序列。
2)功能:a.滤空格b.识别保留字c.识别标识符d.拼数e.拼复合单词: 例如:>=、 <=、 :=3)检查如下错误:a.程序语言的字符集以外的非法字符b.单词拼错,如9A88,而对于将begin拼写成begon的错误,只须把begon当成标识符即可3、请指导教师检查程序和运行结果,评定成绩。
4、撰写并上交实验报告。
四、试验设计和算法分析:实验原理:程序流程:置初值→调用扫描子程序→输出串结束→输出单词二元组→是→否→结束词法分析主程序示意图待分析的简单语言的词法(1) 关键字:begin if then while do end所有关键字都是小写。
(2)运算符和界符::= + - * / < > <= <> >= ; ( ) #(3):其他单词是标识符(ID)和整型常数(NUM),通过以下正规式定义:ID=letter(letter | digit)*NUM=digit digit*(4)空格由空白、制表符和换行符组成。
空格一般用来分隔ID、NUM、运算符、界符和关键字,词法分析阶段通常被忽略。
、设计的词法分析器符合软件工程的要求。
编译原理词法分析器

一、实验目的了解词法分析程序的两种设计方法:1.根据状态转换图直接编程的方式;2.利用DFA 编写通用的词法分析程序。
二、实验内容及要求1.根据状态转换图直接编程编写一个词法分析程序,它从左到右逐个字符的对源程序进行扫描,产生一个个的单词的二元式,形成二元式(记号)流文件输出。
在此,词法分析程序作为单独的一遍,如下图所示。
具体任务有:(1)组织源程序的输入(2)拼出单词并查找其类别编号,形成二元式输出,得到单词流文件(3)删除注释、空格和无用符号(4)发现并定位词法错误,需要输出错误的位置在源程序中的第几行。
将错误信息输出到屏幕上。
(5)对于普通标识符和常量,分别建立标识符表和常量表(使用线性表存储),当遇到一个标识符或常量时,查找标识符表或常量表,若存在,则返回位置,否则返回0并且填写符号表或常量表。
标识符表结构:变量名,类型(整型、实型、字符型),分配的数据区地址注:词法分析阶段只填写变量名,其它部分在语法分析、语义分析、代码生成等阶段逐步填入。
常量表结构:常量名,常量值2.编写DFA模拟程序算法如下:DFA(S=S0,MOVE[][],F[],ALPHABET[])/*S为状态,初值为DFA的初态,MOVE[][]为状态转换矩阵,F[] 为终态集,ALPHABET[] 为字母表,其中的字母顺序与MOVE[][] 中列标题的字母顺序一致。
*/{Char Wordbuffer[10]=“”//单词缓冲区置空Nextchar=getchar();//读i=0;while(nextchar!=NULL)//NULL代表此类单词{ if (nextcha r!∈ALPHABET[]){ERROR(“非法字符”),return(“非法字符”);}S=MOVE[S][nextchar] //下一状态if(S=NULL)return(“不接受”);//下一状态为空,不能识别,单词错误wordbuffer[i]=nextchar ;//保存单词符号i++;nextchar=getchar();}Wordbuffer[i]=‘\0’;If(S∈F)return(wordbuffer);//接受Else return(“不接受”);}该算法要求:实现DFA算法,给定一个DFA(初态、状态转换矩阵、终态集、字母表),调用DFA(),识别给定源程序中的单词,查看结果是否正确。
编译原理报告—词法分析器

词法分析器的作用词法分析是编译的第一阶段。
词法分析器的主要任务是读入源程序的输入字符,将它们组成词素,生成并输出一个词法单元序列,这个词法单元序列被输出到语法分析器进行语法分析。
另外,由于词法分析器在编译器中负责读取源程序,因此除了识别词素之外,它还会完成一些其他任务,比如过滤掉源程序中的注释和空白,将编译器生成的错误消息与源程序的位置关联起来等。
总而言之,词法分析器的作用如下:1.读入源程序的输入字符,将它们组成词素,生成并输出一个词法单元序列;2.过滤掉源程序中的注释和空白;3.将编译器生成的错误消息与源程序的位置关联起来;4.其它。
词法分析过程首先,对某个正则语言L,构造能够描述其的正则表达式r;然后,需要将r 转换成一个有穷自动机。
这里有三种方法,一是直接转换成NFA,而是直接转换成DFA,三是先转换成NFA,再把NFA 转换成DFA;最后,如果将r 转换成了一个DFA,需要将此DFA 的状态数最小化。
正则表达式正则表达式可以用来描述词素的模式,一个正则表达式可以由较小的正则表达式递归的构建。
对于符号集合∑={a,b},有:-正则表达式a 表示语言{a};-正则表达式a|b 表示语言{a,b};-正则表达式(a|b)(a|b)表示语言{aa,ab,ba,bb};-正则表达式a*表示语言{ε,a,aa,aaa,…};-正则表达式(a|b)*表示语言{ε,a,b,aa,ab,ba,bb,aaa,…};-正则表达式a|a*b 表示语言{a,b,ab,aab,aaab,…}。
上面通过基本的并、连接和闭包运算递归定义了正则表达式有穷自动机一个有穷自动机可以把一个描述词素的模式变成一个词法分析器,从本质上来讲,有穷自动机是与状态转换图相类似的图,它有以下特点:有穷自动机是一个识别器,它只能对每个输入符号串简单的输出“yes”或“no”,表示是否能够识别此符号串;有穷自动机和状态转换图类似,它具有有限个数的结点,每个结点表示一个状态,并且这些状态中有一个初始状态和若干个终止状态。
编译原理实验报告——词法分析器(内含源代码)

编译原理实验(一)——词法分析器一.实验描述运行环境:vc++2008对某特定语言A ,构造其词法规则。
该语言的单词符号包括:12状态转换图3程序流程:词法分析作成一个子程序,由另一个主程序调用,每次调用返回一个单词对应的二元组,输出标识符表、常数表由主程序来完成。
二.实验目的通过动手实践,使学生对构造编译系统的基本理论、编译程序的基本结构有更为深入的理解和掌握;使学生掌握编译程序设计的基本方法和步骤;能够设计实现编译系统的重要环节。
同时增强编写和调试程序的能力。
三.实验任务编制程序实现要求的功能,并能完成对测试样例程序的分析。
四.实验原理char set[1000],str[500],strtaken[20];//set[]存储代码,strtaken[]存储当前字符char sign[50][10],constant[50][10];//存储标识符和常量定义了一个Analyzer类class Analyzer{public:Analyzer(); //构造函数 ~Analyzer(); //析构函数int IsLetter(char ch); //判断是否是字母,是则返回 1,否则返回 0。
int IsDigit(char ch); //判断是否为数字,是则返回 1,否则返回 0。
void GetChar(char *ch); //将下一个输入字符读到ch中。
void GetBC(char *ch); //检查ch中的字符是否为空白,若是,则调用GetChar直至ch进入一个非空白字符。
void Concat(char *strTaken, char *ch); //将ch中的字符连接到strToken之后。
int Reserve(char *strTaken); //对strTaken中的字符串查找保留字表,若是一个保留字返回它的数码,否则返回0。
void Retract(char *ch) ; //将搜索指针器回调一个字符位置,将ch置为空白字符。
编译原理词法分析实验

编译原理词法分析实验一、实验目的本实验旨在通过编写一个简单的词法分析器,了解编译原理中词法分析的基本原理和实现方法。
二、实验材料1. 计算机编程环境2. 编程语言三、实验步骤1. 了解词法分析的概念和作用。
词法分析是编译器中的第一个阶段,它的主要任务是将源代码中的字符序列转化为有意义的标识符,如关键字、操作符、常量和标识符等。
2. 设计词法分析器的流程和算法。
词法分析器的主要原理是通过有限状态自动机来识别和提取标识符。
在设计过程中,需考虑各种可能出现的字符序列,并定义相应的状态转移规则。
3. 根据设计的流程和算法,使用编程语言编写词法分析器的代码。
4. 编译并运行词法分析器程序,输入待分析的源代码文件,观察程序的输出结果。
5. 分析输出结果,检查程序是否正确地提取了源代码中的标识符。
四、实验结果经过词法分析器的处理,源代码将被成功地转化为有意义的标识符。
结果可以通过以下几个方面来验证:1. 关键字和操作符是否被正确识别和提取。
2. 常量和标识符是否被正确识别和提取。
3. 检查程序的错误处理能力,如能否发现非法字符或非法标识符。
4. 输出结果是否符合预期,可与自己编写的语法规则进行对比。
5. 对于特殊情况,如转义字符等是否正确处理。
五、实验总结通过本次实验,我深入了解了编译原理中词法分析的重要性和基本原理。
编写词法分析器的过程中,我学会了使用有限状态自动机来识别和提取标识符,并通过实践巩固了相关知识。
此外,我还对源代码的结构有了更深入的了解,并且掌握了如何运用编程语言来实现词法分析器。
通过本次实验,我不仅提升了自己的编程技术,也对编译原理有了更深入的认识和理解。
六、实验心得通过实验,我深刻体会到了词法分析在编译过程中的重要性。
合理设计和实现词法分析器,可以大大提高编译器的效率和准确性。
同时,通过编写词法分析器的代码,我不仅锻炼了自己的编程能力,还提升了对编译原理的理解和掌握。
这次实验让我更加深入地了解了编译原理中的词法分析,也为我今后在编程领域的发展打下了坚实的基础。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
编译原理实验2 词法分析器一、实验目的1. 通过设计编制调试一个具体的词法分析程序,加深对词法分析原理的理解。
2. 掌握在对程序设计语言源程序进行扫描过程中将其分解为各类单词的词法分析方法。
3. 编制一个读单词的程序,从输入的源程序中,识别出各个具有独立意义的单词,即基本保留字、标识符、常数、运算符和分隔符五大类。
并依次输出各个单词的内部编码及单词符号自身值。
(遇到错误时可显示“Error”,然后跳过错误部分继续显示)二、词法分析的基础知识1. 词法分析器的功能和输出格式词法分析器的功能是输入源程序,输出单词符号。
词法分析器的单词符号常常表示成以下的二元式(单词种别码,单词符号的属性值)。
在本实验中,采用的是一类符号一种别码的方式。
标识符的BNF表示:<标识符>-> <字母><字母数字串>)<字母数字串>-><字母><字母数字串>|<数字><字母数字串>|ε无符号整数的BNF表示:<无符号整数>-> <数字><数字串><数字串>-> <数字><数字串> |ε运算符的BNF表示:<加法运算符>-> +<减法运算符>-> -<大于关系运算符>-> ><大于等于关系运算符>-> >=2. 超前搜索;词法分析时,常常会用到超前搜索方法。
如当前待分析字符串为“a > i”,当前字符为“>”,此时,分析器到底是将其分析为大于关系运算符还是大于等于关系运算符呢显然,只有知道下一个字符是什么才能下结论。
于是分析器读入下一个字符“+”,这时可知应将“>”解释为大于运算符。
但此时,超前读了一个字符“i”,所以要回退一个字符,词法分析器才能正常运行。
在分析标识符,无符号整数等时也有类似情况。
三、程序要求1. 程序输入示例:如源程序为C语言,输入如下一段:main(){int a, b;a = 10;b = a+20;};2. 程序输出示例:(2,“main”)(5,“(”)(5,“)”)(5,“{”)(1,“int”)(2,“a”)(5,“,”)(2,“b”)(5,“;”)~(2,“a”)(4,“=”)(3,“10”)(5,“;”)(2,“b”)(4,“=”)(2,“a”)(4,“+”)(3,“20”)(5,“;”)$(5,“}“)3. 具体要求如下:(1)识别保留字:if、int、for、while、do、return、break、continue等。
(2)运算符包括:+、-、*、/、=、>、<、>=、<=、!=(3)分隔符包括:,、;、{、}、(、)(4)常数为无符号整形数;(5)其它的都识别为标识符;4. 程序思路:(1)定义部分:定义常量、变量、数据结构。
(2)初始化:从文件将源程序全部输入到字符缓冲区中。
…(3)取单词前:去掉多余空白。
(4)取单词:读出单词的每一个字符,组成单词,分析类型,其中,关键是如何判断取单词结束,取到的单词是什么类型的单词。
(5)显示结果。
四、实验结果#include <>#include ""#include <>#define N 100 //定义要分析的标识符或常数的最大个数#define M 20 //标识符的长度;char *sourceFile="D:\\"; // 定义进行词法分析的源文件char *key[8]={"if","else","for","while","do","return","break","continue"}; // 关键字char *border[6]={",",";","{","}","(",")"}; // 界符定义char *arithmetic[4]={"+","-","*","/"}; // 算术运算符定义char *relation[6]={"<","<=","=",">",">=","<>"}; // 关系运算符定义char *consts[N]; // 常数定义char *label[N]; // 标识符int constnum=0,labelnum=0; // constnum-常数个数;labelnum-标识符个数// 判断一个字符是不是字母;int Isletter(char ch){if(ch>='a' && ch<='z'||ch>='A' && ch<='Z')return 1;return 0;}// 判断一个字符是不是数字int IsDigit(char ch){(if(ch>='0' && ch<='9')return 1;return 0;}// 判断单词符号类型int search(char searchchar[],int wordtype){int i=0;switch (wordtype)—{case 1:for (i=0;i<=7;i++){if(strcmp(key[i],searchchar)==0) // 返回具体的关键字return(i+1);}case 2:{for (i=0;i<=5;i++)¥if(strcmp(border[i],searchchar)==0) // 返回具体的界符return(i+1);return(0);}case 3:{for(i=0;i<=3;i++)if(strcmp(arithmetic[i],searchchar)==0) // 返回具体的算术运算符return(i+1);return(0);[}case 4:{for(i=0;i<=5;i++)if(strcmp(relation[i],searchchar)==0) // 返回具体的关系运算符return(i+1);return(0);}case 5:{、for(i=0;i<constnum;i++)if(strcmp(consts[i],searchchar)==0) // 返回具体的整型常数return(i+1);consts[i]=(char *)malloc(sizeof(searchchar));strcpy(consts[i],searchchar);constnum++;return(i);}case 6:{:for(i=0;i<labelnum;i++)if(label[i]!=NULL)if(strcmp(label[i],searchchar)==0) // 返回标识符return(i+1);label[i-1]=(char *)malloc(sizeof(searchchar));strcpy(label[i-1],searchchar);labelnum++;return(i);}}(return -1;}// 常数处理char digitprocess(char buffer,FILE* fp){int i=-1;char digittp[M];int dtype;…while ((IsDigit(buffer))){digittp[++i]=buffer;buffer=fgetc(fp);}digittp[i+1]='\0';dtype=search(digittp,5); // 输出整型常数printf("%s (5,%d)\n",digittp,dtype-1);return(buffer);》}// 标识符或关键字char alphaprocess(char buffer,FILE* fp){int atype;int i=-1;char alphatp[M];while ((Isletter(buffer))||(IsDigit(buffer)))'{alphatp[++i]=buffer;buffer=fgetc(fp);}alphatp[i+1]='\0';if (atype=search(alphatp,1)) // 输出关键字printf("%s (1,%d)\n",alphatp,atype-1);else{atype=search(alphatp,6); // 输出标识符~printf("%s (6,%d)\n",alphatp,atype-1);}return(buffer);}// 其它处理(运算符,界符等)char otherprocess(char buffer,FILE* fp){int i=-1;^char othertp[M];int otype,otypetp;othertp[0]=buffer;othertp[1]='\0';if(otype=search(othertp,3)){printf("%s (3,%d)\n",othertp,otype-1);buffer=fgetc(fp);goto out;`}if(otype=search(othertp,4)){buffer=fgetc(fp);othertp[1]=buffer;othertp[2]='\0';if(otypetp=search(othertp,4)){printf("%s (4,%d)\n",othertp,otypetp-1);goto out;-}elseothertp[1]='\0';printf("%s (4,%d)\n",othertp,otype-1);goto out;}if(buffer==':'){buffer=fgetc(fp);if (buffer=='=')&printf(":= (2,2)\n");buffer=fgetc(fp);goto out;}else{if(otype=search(othertp,2)){printf("%s (2,%d)\n",othertp,otype-1);buffer=fgetc(fp);《goto out;}}if((buffer!='\n')&&(buffer!=' '))printf("%c error,not a word\n",buffer);buffer=fgetc(fp);out: return(buffer);}int main(int argc, char* argv[])}{int i;FILE *fp; // 文件指针,指向要分析的源程序char cbuffer; // 保存最新读入的字符for (i=0; i<=N; i++){label[i]=NULL; // 初始化标识符consts[i]=NULL; // 初始化常数}if((fp=fopen(sourceFile,"rb"))==NULL) // 判断源文件是否存在printf("文件%s不存在",sourceFile);else{cbuffer = fgetc(fp); // 读入字符while (cbuffer!=EOF) // 如果文件没有结束,就一直循环{if (Isletter(cbuffer)) // 若为字母cbuffer=alphaprocess(cbuffer,fp);else if (IsDigit(cbuffer)) // 若为数字cbuffer=digitprocess(cbuffer,fp);elsecbuffer=otherprocess(cbuffer,fp);}printf("over\n");getchar();}return 0;}*。