词法分析器
词法分析器原理
词法分析器原理词法分析器(Lexical Analyzer)是编译器中的重要组成部分,用于将输入的源代码分解为一个个词法单元(Token),为语法分析器(Syntax Analyzer)提供分析的基础。
本文将介绍词法分析器的原理和工作流程。
一、概述词法分析器通过扫描源代码字符流,并识别出其中的合法词法单元。
它将源代码转化为一个个标识符、关键字、常数、运算符等基本构件,以供后续阶段进行进一步的处理和分析。
二、工作原理1. 自动机词法分析器通常使用有限自动机(Finite Automaton)来实现。
有限自动机由一系列状态组成,每个状态所接受的输入决定了自动机的状态转移。
利用状态转移规则,自动机可以根据输入字符逐步分析源代码并产生相应的词法单元。
2. 正则表达式为了方便描述词法分析器对输入的词法单元进行匹配,可以使用正则表达式。
正则表达式是一种描述字符模式的工具,它可以定义一类字符串的集合。
词法分析器将正则表达式与状态机相结合,通过模式匹配的方式识别输入字符流中的词法单元。
3. 词法规则词法分析器通过预先定义的词法规则来描述源代码中的不同词法单元。
例如,某个编程语言的词法规则可能包含关键字、标识符、数字、字符串等。
词法规则的定义中常常使用正则表达式来指定某个词法单元的模式。
4. 符号表为了方便后续的语义处理和编译过程,词法分析器通常会维护一个符号表(Symbol Table)。
符号表记录了源代码中出现的标识符、常量等信息,以供后续的语法分析和语义分析使用。
三、工作流程词法分析器的工作流程可以分为以下几个步骤:1. 读取源代码字符流,并初始化状态机。
2. 通过状态转移规则,逐个输入字符进行状态转移,直到达到某个终止状态。
3. 判断当前状态是否为某个词法单元的终止状态,如果是,产生相应的词法单元,并将其记录在符号表中。
4. 继续读取源代码字符流,重复以上过程,直到扫描完整个源代码。
五、总结词法分析器作为编译器的重要组成部分,负责将源代码分解为一个个词法单元,并提供给语法分析器进行进一步的处理。
编译原理课程设计—词法分析器
编译原理课程设计(一)——词法分析器1、题目编写程序实现一个简易的词法分析器。
2、实验目的对一段程序代码进行词法分析,将程序段中的关键字、标识符、常数、运算符、界符按照一定的种别编码分析出来。
3、环境及工具操作系统:windows XP ;使用工具:Microsoft Visual C++ 6.0; 编程语言:C 语言;4、分析程序输入:从文件中读入程序段;程序输出:由单词种别和单词符号的属性值组成的二元式;单词种别通常使用整数编码,编码方式可以有多种,在设计词法分析器之前应确定一种程序处理起来较方便的编码方式。
当一个种别中含有多个单词符号时,在分析出其属于哪个种别的时候应同时给出其单词符号属性,本程序为方便起见,采用单词符号本身来作为其属性,以标识同种别种的不同单词符号。
标识符及关键字的识别:字母开头的字母和数字组成的串是多数编程语言的标识符,所以我们的简易词法分析器中,将标识符定义为这种字母数字串。
当第一个字母为字母且紧接着的字符为数字或字母时,应将其串接在一起为一个单词,直到紧跟着的不在是字母数字时。
由于关键字通常为一个单词,则这样得到的串可能是标识符也可能是关键字,又因为一种语言的关键字通常是有限个,则我们可以构造一个存放所有关键字的表,查询关键字表,可以判断得到的串是否为关键字。
界符和运算符的识别:它们多为当个字符,建立两个分别存放界符合运算符的表,读取字符后,进行查表便可以得出它们的类型。
为方便词法分析器的设计,可以使用状态转换图,根据一种特定的编程语言先设计出其状态转换图才能更好将其用代码实现。
典型状态转换图结构如下:(a)有不含回路含分支的状态节点:对应if …else if …else …语句;(b)有含回路的状态节点:对应while …if …语句。
(b )5、状态转换图6、程序框架描述程序中编写了以下函数,各个函数实现的作用如下:1. GetChar():将下一输入的字符读入到全局变量ch中,搜素指示器前移一个字符的位置。
词法分析器功能
➢词法记号及属性➢词法记号的描述与识别➢有限自动机➢DFA构建➢DFA化简➢词法模式的识别过程➢子集构造法词法分析器语法分析器语义分析器源程序中间代码生成器代码优化器代码生成器出错管理器符号表管理器源代码词法分析器记号(token)流词法分析器语法分析器符号表记号取下一个记号源程序本章内容➢词法分析器:把构成源程序的字符流翻译成记号流,还完成和用户接口的一些任务。
➢介绍正规式、状态转换图和有限自动机概念。
➢Lex 与词法分析器的自动生成。
词法记号词法模式词法单元词法记号的属性词法错误➢看一个中文的句子你们是优秀的大工学子代词动词形容词名词(短语)通过分词操作,把句子以单词或者词组为单位进行划分,得到一个句型。
L1:x =ID COLON ID ASSGNy2+12;ID PLUS INT SEMI-COL 编译的词法分析做的工作类似于分词,把原始的字符串流形式的程序文本转换为词法记号流的形式。
例子中哪些是词法单元?➢词法单元又称单词,是编程语言中合法的字符串➢词法记号满足某种规则的词法单元,采用同一种记法。
➢满足一个给定规则的词法单元,被记为一个词法记号。
模式词法单元词法记号➢C语言的标识符?➢x2, 12, _12, _abc哪些是合法的C标识符?C语言标识符的规则(模式):首字符必须是_或者字母,由_、字母或数字组成的字符串词法记号词法单元例举模式的非形式描述STRUCT struct struct FOR for for RELOP <,<=,=,IDsum,_12,_x NUM 3.1,10,2.8e12LITERAL “seg.error”➢常见记号及模式的例子:简单的一对一模式相对复杂一点的模式引号“和”之间的任意字符串,但引号本身除外_或字母开头的由_、字母和数字组成的串<或<=或=或…任何数值常数词法记号词法单元例举模式的非形式描述relation < , < = , = , …< 或<= 或= 或…idsum, count, D5 由字母开头的字母数字串名词大连软件大黑山表示名称的词连词和与或和与或….词法记号词法单元例举模式的非形式化描述词法记号词法单元例举模式的非形式描述中国人胡锦涛毛泽东具有中国国籍的人美国人奥巴马克林顿具有美国国籍的人存在的意义?词法分析器语法分析器符号表记号取下一个记号源程序➢如果简单地把词法记号流传给语法分析器,会产生什么后果?-语义被完全摒弃,只剩下一个语法结构。
词法分析器
词法分析器词法分析器是一种重要的编译器技术,用于将输入的源代码按照词法规则进行分割、识别和标记。
它是编译过程中的第一个阶段,也是编译器的基础组成部分之一。
在本文中,我将详细介绍词法分析器的基本原理、应用场景和实现方法。
首先,让我们来了解一下词法分析器的基本原理。
词法分析器主要通过扫描源代码中的字符流,按照一定的词法规则将其分割成一个个的词法单元(token)。
词法单元是语言中的最小语法单位,可以是关键字、标识符、运算符、常量等。
词法分析器通常使用有限状态自动机(DFA)来实现,通过状态转换和模式匹配的方式来识别每个词法单元的类型和属性。
词法分析器在编译器中的作用非常重要。
它能够为后续的语法分析器提供正确的输入,为编译器的错误检查和优化提供基础。
通过词法分析器,我们可以将源代码转换为一系列的词法单元序列,为语法分析器和语义分析器提供正确的输入。
同时,词法分析器还可以检测源代码中的词法错误,并通过错误处理机制进行相应的处理和提示。
词法分析器的应用场景非常广泛。
除了编译器中的使用外,它还可以应用于其他领域,如代码编辑器、语法高亮、代码自动补全等。
在代码编辑器中,词法分析器可以实时地对用户输入的源代码进行分析和高亮显示,提供友好的编辑环境。
在代码自动补全场景中,词法分析器可以根据当前的上下文信息,自动提示用户可能的词法单元选项,提高编码效率和准确性。
实现一个词法分析器的方法有很多种,常用的包括手写词法分析器和使用词法分析器生成器。
手写词法分析器是通过编写代码的方式来实现,根据词法规则和状态转换表逐个字符地进行识别和匹配。
这种方式的优点是灵活性高,可以随时根据需求进行修改和调整。
然而,手写词法分析器的实现相对复杂,对开发者的要求较高。
而使用词法分析器生成器,如Lex和Flex,可以根据给定的词法规则自动生成词法分析器的代码。
这种方式的优点是简化代码编写过程,提高开发效率。
综上所述,词法分析器作为编译器中的重要组成部分,具有非常重要的作用。
词法分析器实验报告
词法分析器实验报告词法分析器实验报告一、引言词法分析器是编译器中的重要组成部分,它负责将源代码分解成一个个的词法单元,为之后的语法分析提供基础。
本实验旨在设计和实现一个简单的词法分析器,以深入理解其工作原理和实现过程。
二、实验目标本实验的目标是设计和实现一个能够对C语言代码进行词法分析的程序。
该程序能够将源代码分解成关键字、标识符、常量、运算符等各种词法单元,并输出其对应的词法类别。
三、实验方法1. 设计词法规则:根据C语言的词法规则,设计相应的正则表达式来描述各种词法单元的模式。
2. 实现词法分析器:利用编程语言(如Python)实现词法分析器,将源代码作为输入,根据词法规则将其分解成各种词法单元,并输出其类别。
3. 测试和调试:编写测试用例,对词法分析器进行测试和调试,确保其能够正确地识别和输出各种词法单元。
四、实验过程1. 设计词法规则:根据C语言的词法规则,我们需要设计正则表达式来描述各种词法单元的模式。
例如,关键字可以使用'|'操作符将所有关键字列举出来,标识符可以使用[a-zA-Z_][a-zA-Z0-9_]*的模式来匹配,常量可以使用[0-9]+的模式来匹配等等。
2. 实现词法分析器:我们选择使用Python来实现词法分析器。
首先,我们需要读取源代码文件,并将其按行分解。
然后,针对每一行的代码,我们使用正则表达式进行匹配,以识别各种词法单元。
最后,我们将识别出的词法单元输出到一个结果文件中。
3. 测试和调试:我们编写了一系列的测试用例,包括各种不同的C语言代码片段,以测试词法分析器的正确性和鲁棒性。
通过逐个测试用例的运行结果,我们可以发现和解决词法分析器中的问题,并进行相应的调试。
五、实验结果经过多次测试和调试,我们的词法分析器能够正确地将C语言代码分解成各种词法单元,并输出其对应的类别。
例如,对于输入的代码片段:```cint main() {int a = 10;printf("Hello, world!\n");return 0;}```我们的词法分析器将输出以下结果:```关键字:int标识符:main运算符:(运算符:)运算符:{关键字:int标识符:a运算符:=常量:10运算符:;标识符:printf运算符:(常量:"Hello, world!\n"运算符:)运算符:;关键字:return常量:0运算符:;```可以看到,词法分析器能够正确地将代码分解成各种词法单元,并输出其对应的类别。
实验一、词法分析器(含源代码)
词法分析器实验报告一、实验目的及要求本次实验通过用C语言设计、编制、调试一个词法分析子程序,识别单词,实现一个C语言词法分析器,经过此过程可以加深对编译器解析单词流的过程的了解。
运行环境:硬件:windows xp软件:visual c++6.0二、实验步骤1.查询资料,了解词法分析器的工作过程与原理。
2.分析题目,整理出基本设计思路。
3.实践编码,将设计思想转换用c语言编码实现,编译运行。
4.测试功能,多次设置包含不同字符,关键字的待解析文件,仔细察看运行结果,检测该分析器的分析结果是否正确。
通过最终的测试发现问题,逐渐完善代码中设置的分析对象与关键字表,拓宽分析范围提高分析能力。
三、实验内容本实验中将c语言单词符号分成了四类:关键字key(特别的将main说明为主函数)、普通标示符、常数和界符。
将关键字初始化在一个字符型指针数组*key[]中,将界符分别由程序中的case列出。
在词法分析过程中,关键字表和case列出的界符的内容是固定不变的(由程序中的初始化确定),因此,从源文件字符串中识别出现的关键字,界符只能从其中选取。
标识符、常数是在分析过程中不断形成的。
对于一个具体源程序而言,在扫描字符串时识别出一个单词,若这个单词的类型是关键字、普通标示符、常数或界符中之一,那么就将此单词以文字说明的形式输出.每次调用词法分析程序,它均能自动继续扫描下去,形成下一个单词,直到整个源程序全部扫描完毕,从而形成相应的单词串。
输出形式例如:void $关键字流程图、程序流程图:程序:#include<string.h>#include<stdio.h>#include<stdlib.h>#include<ctype.h>//定义关键字char*Key[10]={"main","void","int","char","printf","scanf","else","if","return"}; char Word[20],ch; // 存储识别出的单词流int IsAlpha(char c) { //判断是否为字母if(((c<='z')&&(c>='a'))||((c<='Z')&&(c>='A'))) return 1;else return 0;}int IsNum(char c){ //判断是否为数字if(c>='0'&&c<='9') return 1;else return 0;}int IsKey(char *Word){ //识别关键字函数int m,i;for(i=0;i<9;i++){if((m=strcmp(Word,Key[i]))==0){if(i==0)return 2;return 1;}}return 0;}void scanner(FILE *fp){ //扫描函数char Word[20]={'\0'};char ch;int i,c;ch=fgetc(fp); //获取字符,指针fp并自动指向下一个字符if(IsAlpha(ch)){ //判断该字符是否是字母Word[0]=ch;ch=fgetc(fp);i=1;while(IsNum(ch)||IsAlpha(ch)){ //判断该字符是否是字母或数字Word[i]=ch;i++;ch=fgetc(fp);}Word[i]='\0'; //'\0' 代表字符结束(空格)fseek(fp,-1,1); //回退一个字符c=IsKey(Word); //判断是否是关键字if(c==0) printf("%s\t$普通标识符\n\n",Word);//不是关键字else if(c==2) printf("%s\t$主函数\n\n",Word);else printf("%s\t$关键字\n\n",Word); //输出关键字 }else //开始判断的字符不是字母if(IsNum(ch)){ //判断是否是数字Word[0]=ch;ch=fgetc(fp);i=1;while(IsNum(ch)){Word[i]=ch;i++;ch=fgetc(fp);}Word[i]='\0';fseek(fp,-1,1); //回退printf("%s\t$无符号实数\n\n",Word);}else //开始判断的字符不是字母也不是数字{Word[0]=ch;switch(ch){case'[':case']':case'(':case')':case'{':case'}':case',':case'"':case';':printf("%s\t$界符\n\n",Word); break;case'+':ch=fgetc(fp);Word[1]=ch;if(ch=='='){printf("%s\t$运算符\n\n",Word);//运算符“+=”}else if(ch=='+'){printf("%s\t$运算符\n\n",Word); //判断结果为“++”}else {fseek(fp,-1,1);printf("%s\t$运算符\n\n",Word); //判断结果为“+”}break;case'-':ch=fgetc(fp);Word[1]=ch;if(ch=='='){printf("%s\t$运算符\n\n",Word); }else if(ch=='-'){printf("%s\t$运算符\n\n",Word); //判断结果为“--”}else {fseek(fp,-1,1);printf("%s\t$运算符\n\n",Word); //判断结果为“-”}break;case'*':case'/':case'!':case'=':ch=fgetc(fp);if(ch=='='){printf("%s\t$运算符\n\n",Word);}else {fseek(fp,-1,1);printf("%s\t$运算符\n\n",Word);}break;case'<':ch=fgetc(fp);Word[1]=ch;if(ch=='='){printf("%s\t$运算符\n\n",Word); //判断结果为运算符“<=”}else if(ch=='<'){printf("%s\t$运算符\n\n",Word); //判断结果为“<<”}else {fseek(fp,-1,1);printf("%s\t$运算符\n\n",Word); //判断结果为“<”}break;case'>':ch=fgetc(fp);Word[1]=ch;if(ch=='=') printf("%s\t$运算符\n\n",Word);else {fseek(fp,-1,1);printf("%s\t$运算符\n\n",Word);}break;case'%':ch=fgetc(fp);Word[1]=ch;if(ch=='='){printf("%s\t$运算符\n\n",Word);}if(IsAlpha(ch)) printf("%s\t$类型标识符\n\n",Word);else {fseek(fp,-1,1);printf("%s\t$取余运算符\n\n",Word);}break;default:printf("无法识别字符!\n\n"); break;}}}main(){char in_fn[30]; //文件路径FILE *fp;printf("\n请输入源文件名(包括路径和后缀名):");while(1){gets(in_fn);//scanf("%s",in_fn);if((fp=fopen(in_fn,"r"))!=NULL) break; //读取文件内容,并返回文件指针,该指针指向文件的第一个字符else printf("文件路径错误!请重新输入:");}printf("\n******************* 词法分析结果如下 *******************\n");do{ch=fgetc(fp);if(ch=='#') break; //文件以#结尾,作为扫描结束条件else if(ch==' '||ch=='\t'||ch=='\n'){} //忽略空格,空白,和换行else{fseek(fp,-1,1); //回退一个字节开始识别单词流scanner(fp);}}while(ch!='#');return(0);}4.实验结果解析源文件:void main(){int a=3;a+=b;printf("%d",a);return;}#解析结果:5.实验总结分析通过本次实验,让再次浏览了有关c语言的一些基本知识,特别是对文件,字符串进行基本操作的方法。
词法分析器的实验报告
词法分析器的实验报告词法分析器的实验报告引言:词法分析器是编译原理中的重要组成部分,它负责将源代码中的字符序列转换为有意义的词法单元,为后续的语法分析提供基础。
本实验旨在设计和实现一个简单的词法分析器,并对其进行测试和评估。
实验设计:1. 词法规则设计:在开始实验之前,我们首先需要设计词法规则,即定义源代码中的合法词法单元。
例如,对于一门类C的语言,我们可以定义关键字(如if、while、int等)、标识符、运算符(如+、-、*等)、分隔符(如()、{}等)等。
2. 有限自动机(DFA)的设计:基于词法规则,我们可以设计一个有限自动机,用于识别和分析源代码中的词法单元。
有限自动机是一个状态转换图,其中每个状态代表一种词法单元,而边表示输入字符的转换关系。
3. 实现代码:根据有限自动机的设计,我们可以使用编程语言(如Python、C++等)实现词法分析器的代码。
代码的主要功能包括读取源代码文件、逐个字符进行词法分析、识别和输出词法单元。
实验过程:1. 词法规则设计:我们以一门简单的算术表达式语言为例,设计了以下词法规则:- 数字:由0-9组成的整数或浮点数。
- 运算符:包括+、-、*、/等。
- 分隔符:包括括号()和逗号,。
- 标识符:以字母开头,由字母和数字组成的字符串。
2. 有限自动机(DFA)的设计:我们基于词法规则,设计了一个简单的有限自动机。
该自动机包含以下状态:- 初始状态:用于读取和识别源代码中的字符。
- 数字状态:用于识别和输出数字。
- 运算符状态:用于识别和输出运算符。
- 分隔符状态:用于识别和输出分隔符。
- 标识符状态:用于识别和输出标识符。
3. 实现代码:我们使用Python编程语言实现了词法分析器的代码。
代码主要包括以下功能:- 读取源代码文件。
- 逐个字符进行词法分析,根据有限自动机的设计进行状态转换。
- 识别和输出词法单元。
实验结果:我们对几个测试样例进行了词法分析,并对结果进行了评估。
词法分析器
词法分析器词法分析器又称扫描器。
词法分析是指将我们编写的文本代码流解析为一个一个的记号,分析得到的记号以供后续语法分析使用。
词法分析器的工作是低级别的分析:将字符或者字符序列转化成记号.。
在谈论词法分析时,使用术语“词法记号”(简称记号)、“模式”和“词法单元”表示特定的含义。
在分析时,一是把词法分析器当成语法分析的一部分,另一种是把词法分析器当成编译程序的独立部分。
在前一种情况下,词法分析器不断地被语法分析器调用,每调用一次词法分析器将从源程序的字符序列拼出一个单词,并将其Token值返回给语法分析器。
后一种情况则不同,词法分析器不是被语法分析器不断地调用,而是一次扫描全部单词完成编译器的独立一遍任务。
词法分析器主要特点是不依靠语法,而只依靠词法,即处理一个单词时不依赖于外部单词的信息,因此词法分析器一般都很简单。
当然,对某些语言在作词法分析时,在有些情况下不得不往前查看多个字符,有时还要做一些特殊处理,还有一些在词法分析中处理不了的,要留到语法分析中进行处理。
本算法主要利用状态转换图生成一个词法分析器,对输入的程序进行词法分析,并将分析得到的单词造表。
其中关键字表和界限符表的大小是由高级语言的子集决定的,可以用数组装载;而标识符表和常数表的大小取决于输入的待分析程序中的变量、过程名、常数的个数,所以要用动态数组(即vector)来装载。
当然为了方便,我们也把它定义成数组处理。
语法分析时,调用词法分析器,根据已知文法利用递归向下分析,检查语法错误。
源代码如下// LexicalAnalyzer.cpp : 定义控制台应用程序的入口点。
#include"stdafx.h"#include"iostream"#include"fstream"#include"string"#include"vector"using namespace std;struct Node{string state;string word;};class LA{private:vector<Node> list;string keyword[32];public:void BinarySearch(void);bool BinaryFind(string str);bool BinaryFindchar(char ch);char get_word(ifstream &infile,char str);char get_constant(ifstream &infile,char str);char get_operatorcharacter(ifstream &infile,char str);char get_list(ifstream &infile,char str);void printall();};void LA::BinarySearch(void){ifstream infile("keyword.txt",ios::in);if(! infile){cerr<<"open error!"<<endl;exit(1);}for(int i=0;i<32;i++){infile>>keyword[i];}infile.close();}bool LA::BinaryFind(string str){int low=0,high=31;while(low<=high){int mid=(low+high)/2;if(pare(keyword[mid])==0)return true;elseif(pare(keyword[mid])>0)low=mid+1;else high=mid-1;}return false;}bool LA::BinaryFindchar(char ch){intlc[20]={33,37,38,40,41,42,43,45,46,47,58,60,61,62,63,91,93,94,124,126};int low=0,high=19;while(low<=high){int mid=(low+high)/2;if(lc[mid]==ch)return true;elseif(ch>lc[mid])low=mid+1;else high=mid-1;}return false;}char LA::get_word(ifstream &infile,char str){BinarySearch();string ss;list.resize(list.size()+1);list[list.size()-1].word="";list[list.size()-1].word+=ss.assign(1,str);infile.get(str);while(str==95 || (str>=48 && str<=57)||(str >= 65 && str <= 90) || (str >=97 && str<= 122)){list[list.size()-1].word+=ss.assign(1,str);infile.get(str);}if (BinaryFind(list[list.size()-1].word))list[list.size()-1].state="保留字";elselist[list.size()-1].state="标示符";return str;}void LA::printall(){int i=0;ofstream outfile("result.txt",ios::out);if(! outfile.is_open()){cerr<<"open error!"<<endl;exit(1);}while (i < list.size()){outfile<<list[i].state<<": "<<list[i].word<<endl;i++;}outfile.flush();outfile.close();}char LA::get_constant(ifstream &infile,char str){string ss;list.resize(list.size()+1);list[list.size()-1].word="";list[list.size()-1].word+=ss.assign(1,str);if (str>=48 && str<=57){infile.get(str);while(str==46 || (str>=48 && str<=57)){list[list.size()-1].word+=ss.assign(1,str);infile.get(str);}}elseif (str==34){infile.get(str);while (str != 34){list[list.size()-1].word+=ss.assign(1,str);infile.get(str);}list[list.size()-1].word+=ss.assign(1,str);infile.get(str);}else{infile.get(str);while (str != 39){list[list.size()-1].word+=ss.assign(1,str);infile.get(str);}list[list.size()-1].word+=ss.assign(1,str);infile.get(str);}list[list.size()-1].state="常量";return str;}char LA::get_operatorcharacter(ifstream &infile,char str) {string ss;list.resize(list.size()+1);list[list.size()-1].word="";list[list.size()-1].word+=ss.assign(1,str);list[list.size()-1].state="运算符";char temp=str;infile.get(str);if(temp=='/'){if(str=='/'){while(str !='\n'){list[list.size()-1].word+=ss.assign(1,str);infile. get(str);}list[list.size()-1].word+=ss.assign(1,str);infile.get(str);list[list.size()-1].state="注释段";}if(str =='*'){char ch;list[list.size()-1].word+=ss.assign(1,str);infile.get(str);list[list.size()-1].word+=ss.assign(1,str);while((ch=infile.get())!='/' || str!='*'){str=ch;list[list.size()-1].word+=ss.assign(1,str);}list[list.size()-1].word+=ss.assign(1,ch);infile.get(str);list[list.size()-1].state="注释段";}}if (temp==45 && str==62){list[list.size()-1].word+=ss.assign(1,str);infile.get(str);list[list.size()-1].state="运算符";}if((temp==38 || temp==43 || temp==45 || temp==60 || temp==61 || temp==62 || temp==124)&&(temp==str || str==61)){list[list.size()-1].word+=ss.assign(1,str);char temp1=str;infile.get(str);if (temp==temp1 && str==61){list[list.size()-1].word+=ss.assign(1,str);infile.get(str);}list[list.size()-1].state="运算符";}if((temp==33 || temp==37 || temp==42 || temp==47 || temp==94) && str==61) {list[list.size()-1].word+=ss.assign(1,str);infile.get(str);list[list.size()-1].state="运算符";}if (temp==58 && str==58){list[list.size()-1].word+=ss.assign(1,str);infile.get(str);list[list.size()-1].state="运算符";}return str;}char LA::get_list(ifstream &infile,char str){string ss;list.resize(list.size()+1);list[list.size()-1].word="";list[list.size()-1].word+=ss.assign(1,str);infile.get(str);list[list.size()-1].state="界限符";return str;}int main(){LA la;char filename[30];char str;cout<<"请输入原文件名:";cin>>filename;ifstream infile(filename,ios::in);if(! infile.is_open()){cerr<<"open error!"<<endl;exit(1);}infile.get(str);while (! infile.eof()){if(str==95 || (str >= 65 && str <= 90) || (str >=97 && str<= 122)) str=la.get_word(infile,str);elseif((str>=48 && str<=57)||str==34 || str==39)str=la.get_constant(infile,str);elseswitch (str){case 35: {str=la.get_list(infile,str); break;}case 36: {str=la.get_list(infile,str); break;}case 44: {str=la.get_list(infile,str); break;}case 59: {str=la.get_list(infile,str); break;}case 64: {str=la.get_list(infile,str); break;}case 92: {str=la.get_list(infile,str); break;}case 96: {str=la.get_list(infile,str); break;}case 123: {str=la.get_list(infile,str); break;}case 125: {str=la.get_list(infile,str); break;}default: {if(la.BinaryFindchar(str))str=la.get_operatorcharacter(infile,str);elseinfile.get(str);break;}}}infile.close();la.printall();cout<<endl<<"词法分析结束,结果保存在当前目录的result.txt文件里!"<<endl;return 0;}。
词法分析器的设计与实现
词法分析器的设计与实现
1.定义词法规则:根据编程语言的语法规范,定义不同的词法规则,
如关键字、标识符、操作符、常量等。
每个词法规则由一个正则表达式或
有限自动机来描述。
2.构建有限自动机:根据词法规则,构建一个有限自动机(DFA)来
识别词法单元。
有限自动机是一种形式化模型,用于在输入字符序列上进
行状态转换。
3.实现状态转换函数:根据有限自动机的定义,实现状态转换函数。
状态转换函数接受一个输入字符,并返回当前状态和输出的词法单元。
4.实现输入缓冲区:为了方便词法分析器的实现,通常需要实现一个
输入缓冲区,用于存储源代码,并提供一些读取字符的函数。
5. 实现词法分析器:将前面实现的状态转换函数和输入缓冲区结合
起来,实现一个完整的词法分析器。
词法分析器可以使用迭代器模式,每
次调用next(函数来获取下一个词法单元。
6.处理错误情况:在词法分析过程中,可能会遇到一些错误情况,如
未定义的词法单元、不符合语法规范的词法单元等。
词法分析器需要能够
检测并处理这些错误情况。
7.构建测试用例:为了验证词法分析器的正确性,需要构建测试用例,包括各种不同的源代码片段,并验证分析结果是否符合预期。
8.进行性能优化:词法分析是编译器中的一个耗时操作,因此可以进
行一些性能优化,如使用缓存机制、减少状态转换次数等。
以上是词法分析器的设计与实现的一般步骤,具体实现过程可能因编程语言和编译器的不同而有所差异。
词法分析器文档
}
else if(chf==',')
{printf("48,%c\n",chf);
fprintf(fpout,"%d\t%s\n",48,",");
}
else if(chf==':')
{printf("49,%c\n",chf);
fprintf(fpout,"%d\t%s\n",49,":");
}
}
}
scan(FILE *fp)
{ char chf;
while((chf=fgetc(fp))!=EOF&&chf!='#') /*文件未结束就执行循环判断输入的字符串*/
{
if(isalpha(chf)) /*标示符和关键字的判断*/
{ int p=0;
char str1[20];
do
{str1[p++]=chf;
}
else if(chf=='=')
{chf=getc(fp);
if(chf=='=')
{printf("56,%c\n",chf);
fprintf(fpout,"%d\t%s\n",56,"==");
}
else{printf("47,%c\n",chf);
fprintf(fpout,"%d\t%s\n",47,"=");
}
str2[--j]='\0';
fseek(fp,-2L,1);
词法分析器实验报告
词法分析器实验报告一、实验目的本实验旨在通过构建一个简单的词法分析器来加深对编译原理中词法分析的理解,并掌握基本的词法分析算法和程序设计技巧。
二、实验环境操作系统:Windows 10编程语言:C/C++开发环境:Visual Studio 2019三、实验内容1. 设计并实现一个词法分析器,要求具备以下功能:(1)能够识别并区分关键字、标识符、字符常量、字符串常量、整型常量和浮点型常量等基本单词;(2)能够跳过注释、空格、制表符和换行符等无用字符;(3)能够给出错误提示并指明错误所在位置。
2. 对设计的词法分析器进行测试,并记录测试结果,分析测试结果的正确性和效率。
四、实验方法1. 分析待处理的源程序,并确定需要识别的词法单元;2. 设计状态转换图或状态转换表,并将其转化为程序代码;3. 开发测试程序,对所设计的词法分析器进行测试。
五、实验结果1. 实现的词法分析器程序可以正确识别出源程序中的各个单词,并能够跳过无用字符;2. 在测试过程中发现了一些错误,比如未能正确识别一些特殊情况下的单词,或者给出了错误的错误提示等。
经过修改后,程序可以正确识别这些情况,并给出正确的错误提示信息;3. 程序的效率较高,能够在短时间内对源程序进行词法分析。
六、实验体会通过本次实验,我对编译原理中词法分析的概念、算法和程序设计技巧有了更加深入的了解和掌握。
在实践中,我遇到了许多问题,比如如何设计状态转换图,如何正确识别一些特殊的单词等。
这些问题一一解决后,我对词法分析有了更加深刻的理解。
通过本次实验,我还深刻体会到了编译器设计过程中的思维方式和技术要求。
编译器是计算机科学中的一项重要技术,对于提高程序运行效率、保证程序安全性、增强程序可读性和扩展程序功能等都有重要作用。
因此,编译原理作为计算机科学的重要组成部分,对于我以后的学习和研究具有重要意义。
编译原理名词解释
编译原理名词解释1. 词法分析器(Lexer):也称为扫描器(Scanner),用于将源代码分割成一个个单词(Token)。
2. 语法分析器(Parser):将词法分析器生成的单词序列转换成语法树(Parse Tree)或抽象语法树(Abstract Syntax Tree)。
3. 语法树(Parse Tree):表示源代码的语法结构的树状结构,它由语法分析器根据语法规则生成。
4. 抽象语法树(Abstract Syntax Tree):比语法树更加简化和抽象的树状结构,用于表示源代码的语义结构。
5. 语义分析器(Semantic Analyzer):对抽象语法树进行语义检查,并生成中间代码或目标代码。
6. 中间代码(Intermediate code):一种介于源代码和目标代码之间的中间表示形式,可以被不同的优化器和代码生成器使用。
7. 目标代码生成器(Code Generator):将中间代码转换成特定目标平台的机器代码。
8. 优化器(Optimizer):用于对中间代码进行优化,以提高代码的执行效率和资源利用率。
9. 符号表(Symbol Table):用于存储程序中的标识符(变量、函数等)的信息,包括名称、类型等。
10. 语言文法(Grammar):定义了一种语言的语法规则,常用的形式包括上下文无关文法和正则文法。
11. 上下文无关文法(Context-free Grammar):一种形式化的语法表示方法,由产生式和非终结符组成,描述一种语言的句子结构。
12. 语言解释器(Interpreter):将源代码逐行解释执行的程序,不需要生成目标代码。
13. 回溯法(Backtracking):一种递归式的算法,用于在语法分析过程中根据产生式进行选择。
14. 正则表达式(Regular Expression):用于描述一类字符串的表达式,可以用于词法分析中的模式匹配。
15. 自顶向下分析(Top-down Parsing):从文法的起始符号开始,按照语法规则逐步构建语法树的过程。
编译原理词法分析器实验报告
编译原理词法分析器实验报告1. 引言编译原理是计算机科学中的重要概念,它涉及将高级语言程序转换为计算机可执行的低级指令。
词法分析是编译过程中的第一个阶段,它负责将源代码分解为词法单元,为后续的语法分析做准备。
本实验旨在设计和实现一个基本的词法分析器,以了解词法分析的原理和实际应用。
2. 实验目标本实验的主要目标是实现一个基本的词法分析器,能够识别并提取源代码中的各种词法单元。
具体而言,我们将设计一个针对某种编程语言的词法分析器,能够识别关键字、标识符、算术运算符、括号、常量等。
3. 实验环境为了完成本实验,我们需要使用以下工具和环境:•一种编程语言,例如Python、Java或C++•一个文本编辑器,例如Visual Studio Code或Sublime Text•一个命令行终端4. 实验步骤4.1 定义词法规则首先,我们需要定义词法分析器的词法规则。
这些规则描述了编程语言中各种词法单元的模式。
例如,关键字可以被定义为由特定字符组成的字符串,标识符可以被定义为以字母开头并由字母和数字组成的字符串。
4.2 实现词法分析器接下来,我们将根据定义的词法规则,使用编程语言实现一个词法分析器。
在实现过程中,我们可以使用正则表达式来匹配和提取各种词法单元。
4.3 编写测试用例完成词法分析器的实现后,我们需要编写一些测试用例来验证其正确性。
测试用例应该包含各种可能的输入情况,以确保词法分析器能够正确地识别和提取词法单元。
4.4 运行测试用例最后,我们将使用编写的测试用例来运行词法分析器,并检查输出是否符合预期。
如果测试通过,说明词法分析器能够正常工作;否则,我们需要检查代码并进行调试。
5. 实验结果经过实验,我们成功地设计并实现了一个基本的词法分析器。
该词法分析器能够按照预定义的词法规则,正确地识别和提取源代码中的各种词法单元。
在运行测试用例时,词法分析器能够产生符合预期的输出,表明其具有良好的准确性和可靠性。
编译原理实验-词法分析器
编译原理实验-词法分析器⼀、实验⽬的设计、编制、调试⼀个词法分析程序,对单词进⾏识别和编码,加深对词法分析原理的理解。
⼆、实验内容1.选定语⾔,编辑任意的源程序保存在⽂件中;2.对⽂件中的代码预处理,删除制表符、回车符、换⾏符、注释、多余的空格并将预处理后的代码保存在⽂件中;3.扫描处理后的源程序,分离各个单词符号,显⽰分离的单词类型。
三、实验思路对于实验内容1,选择编写c语⾔的源程序存放在code.txt中,设计⼀个c语⾔的词法分析器,主要包含三部分,⼀部分是预处理函数,第⼆部分是扫描判断单词类型的函数,第三部分是主函数,调⽤其它函数;对于实验内容2,主要实现在预处理函数processor()中,使⽤⽂档操作函数打开源程序⽂件(code.txt),去除两种类型(“//”,“/*…*/”)的注释、多余的空格合并为⼀个、换⾏符、回车符等,然后将处理后的保存在另⼀个新的⽂件(afterdel.txt)中,最后关闭⽂档。
对于实验内容3,打开处理后的⽂件,然后调⽤扫描函数,从⽂件⾥读取⼀个单词调⽤判断单词类型的函数与之前建⽴的符号表进⾏对⽐判断,最后格式化输出。
四、编码设计代码参考了两篇博主的,做了部分改动,添加了预处理函数等1 #include<iostream>2 #include<fstream>3 #include<cstdio>4 #include<cstring>5 #include<string>6 #include<cstdlib>78using namespace std;910int aa;// fseek的时候⽤来接着的11string word="";12string reserved_word[20];//保留13char buffer;//每次读进来的⼀个字符14int num=0;//每个单词中当前字符的位置15int line=1; //⾏数16int row=1; //列数,就是每⾏的第⼏个17bool flag; //⽂件是否结束了18int flag2;//单词的类型192021//预处理函数22int processor(){//预处理函数23 FILE *p;24int falg = 0,len,i=0,j=0;25char str[1000],str1[1000],c;26if((p=fopen("code.txt","rt"))==NULL){27 printf("⽆法打开要编译的源程序");28return0;29 }30else{31//fgets(str,1000,p);32while((c=getc(p))!=EOF){33 str[i++] = c;34 }35 fclose(p);36 str[i] = '\0';37for(i=0;i<strlen(str);i++){38if(str[i]=='/'&&str[i+1]=='/'){39while(str[i++]!='\n'){}40 }//单⾏注释41else if(str[i]=='/'&&str[i+1]=='*'){42while(!(str[i]=='*'&&str[i+1]=='/')){i++;}43 i+=2;44 }//多⾏注释45else if(str[i]==''&&str[i+1]==''){46while(str[i]==''){i++;}47 i--;48if(str1[j-1]!='')49 str1[j++]='';50 }//多个空格,去除空格51else if(str[i]=='\n') {52if(str1[j-1]!='')53 str1[j++]='';54 }//换⾏处理,55else if(str[i]==9){56while(str[i]==9){57 i++;58 }59if(str1[j-1]!='')60 str1[j++]='';61 i--;62 }//tab键处理63else str1[j++] = str[i];//其他字符处理64 }65 str1[j] = '\0';66if((p = fopen("afterdel.txt","w"))==NULL){ 67 printf("can not find it!");68return0;69 }70else{71if(fputs(str1,p)!=0){72 printf("预处理失败!");73 }74else printf("预处理成功!");75 }76 fclose(p);77 }78return0;79 }8081//设置保留字82void set_reserve()83 {84 reserved_word[1]="return";85 reserved_word[2]="def";86 reserved_word[3]="if";87 reserved_word[4]="else";88 reserved_word[5]="while";89 reserved_word[6]="return";90 reserved_word[7]="char";91 reserved_word[8]="for";92 reserved_word[9]="and";93 reserved_word[10]="or";94 reserved_word[11]="int";95 reserved_word[12]="bool";96 }9798//看这个字是不是字母99bool judge_word(char x)100 {101if(x>='a' && x<='z' || x>='A' && x<='Z' ){ 102return true;103 }104else return false;105 }106107//看这个字是不是数字108bool judge_number(char x)109 {110if(x>='0' && x<='9'){111return true;112 }113else return false;114 }115116//看这个字符是不是界符117bool judge_jiefu(char x)118 {119if(x=='('||x==')'||x==','||x==';'||x=='{'||x=='}'){ 120return true;121 }122else return false;123 }124125126//加减乘127bool judge_yunsuanfu1(char x)128 {129if(x=='+'||x=='-'||x=='*')130 {131return true;132 }133else return false;134 }135136//等于赋值,⼤于⼩于⼤于等于,⼩于等于,⼤于⼩于137bool judge_yunsuannfu2(char x)138 {139if(x=='='|| x=='>'||x=='<'||x=='&'||x=='||'){140return true;141 }142else return false;143 }144145146//这个最⼤的函数的总体作⽤是从⽂件⾥读⼀个单词147int scan(FILE *fp)148 {149 buffer=fgetc(fp);//读取⼀个字符150if(feof(fp)){//检测结束符151 flag=0;return0;152 }153else if(buffer=='')154 {155 row++;156return0;157 }158else if(buffer=='\n')159 {160 row=1;161return0;162 }163//如果是字母开头或'_' 看关键字还是普通单词164else if(judge_word(buffer) || buffer=='_')165 {166 word+=buffer;167 row++;168while((buffer=fgetc(fp)) && (judge_word(buffer) || judge_number(buffer) || buffer=='_'))169 {170 word+=buffer;171 row++;172 }173if(feof(fp)){174 flag=0;175return1;176 }177for(int i=1;i<=12;i++){178if(word==reserved_word[i]){179 aa=fseek(fp,-1,SEEK_CUR);//如果执⾏成功,stream将指向以fromwhere为基准,偏移offset(指针偏移量)个字节的位置,函数返回0。
词法分析器(含完整源码)
词法分析实验报告一、实验目的与要求:1、了解字符串编码组成的词的内涵,感觉一下字符串编码的方法和解读2、了解和掌握自动机理论和正规式理论在词法分析程序和控制理论中的应用二、实验内容:构造一个自己设计的小语言的词法分析器:1、这个小语言能说明一些简单的变量识别诸如begin,end,if,while等保留字;识别非保留字的一般标识符(有下划线、字符、数字,且第一个字符不能是数字)。
识别数字序列(整数和小数);识别:=,<=,>=之类的特殊符号以及;,(,)等界符。
2、相关过程(函数):Scanner()词法扫描程序,提取标识符并填入display表中3、这个小语言有顺序结构的语句4、这个小语言能表达分支结构的语句5、这个小语言能够输出结果总之这个小语言词法分析器能提供以上所说明到的语法描述的功能……三、实验步骤:1、测试评价(1)、测试1:能说明一些简单的变量,如关键字、一般标识符、界符等;(2)、测试2:能输出结果:单词符号(内码形式)、各种信息表(如符号表、常量表等);(3)、测试程序:var x,y,z;beginx:=2;y:=3;if (x+5>=y*y) thenbeginz:=y*y-x;z:=z+x*x;endelsez:=x+y;prn z;end.(4)、结果:①、从键盘读入;部分结果如下:(类型:该标识符所属的类型,如关键字,变量等;下标:该标识符所对应表(如变量标识符表,常量标识符表等)中其相应的位置,下同)②、从文件读入,输出到文件;部分结果如下:其他测试及结果如下:③、出错处理;注:若有错误,则只指出错误,不输出各个表;(5)、评价:这个小语言程序基本上能完成词法分析阶段的工作,识别诸如begin,if等保留字;识别非保留字的一般标识符(有下划线、字符、数字,且第一个字符不能是数字)。
识别数字序列(整数和小数);识别:=,<=,>=之类的特殊符号以及;,(,)等界符。
高级语言的解释过程
高级语言的解释过程
高级语言的解释过程
一、解释过程
1. 词法分析
词法分析是编译过程的第一步,也称为词法分析器或词法分析器,词法分析的任务是将输入的字符流拆分成有意义的词,即转换字符流为单词流。
因此,词法分析器的工作如同一台阅读机,负责从源程序文本中取出若干个符号,它们是组成程序语句的基本的单元素,如标识符、关键字、常量、符号等。
2. 语法分析
语法分析是编译过程的第二步,也叫语法分析器或语法分析器,其任务是检查单词流和程序语法之间的关系,检测出尽可能多的错误,并根据语法规则,合成程序的语法结构,即树状结构。
通过它可以构造一个抽象语法树,抽象语法树中的每一个节点都包括运算符号以及操作数。
3. 语义分析
语义分析是编译过程的第三步,也叫语义分析器或语义分析器,它的目的是将抽象语法树转换为中间代码,检查程序的语法正确性以及语义正确性。
主要包括类型检查、名字解析、定义检查等。
4. 代码生成
代码生成是编译过程的最后一步,也称为代码生成器或代码生成器,它的主要任务是将中间代码转换为目标机可以执行的代码,如机
器指令代码等。
代码生成的过程包括决定操作数位置、决定操作数寻址方式以及决定操作码等。
二、解释器
解释器是一种快速的、动态的解释程序,它不将程序的源代码编译为机器可识别的代码,而是直接将源代码转换为机器可执行的机器码。
它可以在程序运行的过程中动态的解释代码,并能够及时的检测出程序中的错误,这使得解释器更加易用,也更加适用于动态运行的程序。
解释器的工作过程是:首先将源程序转换为单词流,接着将单词流转换为抽象语法树;最后将抽象语法树转换为机器可以执行的代码,再将机器可以执行的代码提交给机器执行。
实验二词法分析器
实验二:词法分析器一、实验目的:1.强化对系统软件综合工程实现能力的训练;2.加强对词法分析原理、方法和基本实现技术的理解;二、实验内容:语言的词法用C语言或者其他的高级语言作为宿主语言完成实验一设计的C分析器的设计和实现。
三、实验要求:语言词法分析器的源程序并调试通过;1. 编写C2. 通过测试程序的验收;3.实验报告按照提供的模板填写:(1)功能描述:该程序具有什么功能?(2)程序结构描述:函数调用格式、参数含义、返回值描述、函数功能;另外可以附加函数之间的调用关系图、程序总体执行流程图。
(3)实验总结:你在编程过程中花时多少?多少时间在纸上设计?多少时间上机输入和调试?多少时间在思考问题?遇到了哪些难题?你是怎么克服的?你对你的程序的评价?你的收获有哪些?四、评判标准:1. 输出正确的实验结果;2. 代码清晰,格式良好;3. 提交报告,报告阐述清楚。
五、程序工作说明:语言程序段。
程序的输入文件是任何一个目录下的文件格式的C程序的输出文件是程序自己生成的,并以文件格式输出,该输出将作为下个实验语法分析的输入文件。
这里建议使用*.xml文件输出。
词法分析结果输出成xml文件格式为<root><Token lineno=xx type=’…’string=’…’ ></Token><Token lineno=xx type=’…’string=’…’></Token>…</root>程序输入/输出示例:如源程序为如下:void f1(int a,int b) {a = 1;b = 2;}void main(){int a;int b;f1(a,b);}则要求得到如下输出文件:<?xml version="1.0"?><root><token line="1" type="VOID" string="void" /> <token line="1" type="ID" string="f1" /><token line="1" type="LPAREN" string="(" /><token line="1" type="INT" string="int" /><token line="1" type="ID" string="a" /><token line="1" type="COMMA" string="," /><token line="1" type="INT" string="int" /><token line="1" type="ID" string="b" /><token line="1" type="RPAREN" string=")" /><token line="1" type="LBRACE" string="{" /><token line="2" type="ID" string="a" /><token line="2" type="ASSIGN" string="=" /><token line="2" type="NUMBER" string="1" /><token line="2" type="SEMI" string=";" /><token line="3" type="ID" string="b" /><token line="3" type="ASSIGN" string="=" /><token line="3" type="NUMBER" string="2" /><token line="3" type="SEMI" string=";" /><token line="4" type="RBRACE" string="}" /><token line="5" type="VOID" string="void" /> <token line="5" type="ID" string="main" /><token line="5" type="LPAREN" string="(" /><token line="5" type="RPAREN" string=")" /><token line="6" type="LBRACE" string="{" /><token line="7" type="INT" string="int" /><token line="7" type="ID" string="a" /><token line="7" type="SEMI" string=";" /><token line="8" type="INT" string="int" /><token line="8" type="ID" string="b" /><token line="8" type="SEMI" string=";" /><token line="9" type="ID" string="f1" /><token line="9" type="LPAREN" string="(" /><token line="9" type="ID" string="a" /><token line="9" type="COMMA" string="," /><token line="9" type="ID" string="b" /><token line="9" type="RPAREN" string=")" /><token line="9" type="SEMI" string=";" /><token line="10" type="RBRACE" string="}" /></root>六、相关知识:词法分析器任务:输入源程序;扫描、分解字符串,识别出一个个单词(定义符、标识符、运算符、界符、常数)。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
实验二词法分析器一、实验要求为给定编程语言设计词法分析器二、实验材料1、单词结构∙注释:以“//”开头到该行尾部为注释∙关键字(共6个):int real if then else while∙标识符:以字母开头,后跟字母或数字的符号串,最长为64个字符。
(注意:关键字不是标识符)∙操作符(共11个):+ - / * = == < <= > >= !=∙分隔符(共5个):( ) { } ;∙数字(用正规式描述):digit ← 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9整数← digit+ (最大整数为231)exponent ← E ( + | - | ε ) digit+ (最大指数为128)fraction ← . digit+实数← digit+ exponent | digit+ fraction ( exponent | ε )2、词法分析器要求将词法分析部分设计为一个子程序(以备随后的语法分析器调用)。
输入:input.txt,其内容为指定编程语言的一段程序代码。
输出:output.txt,其内容为四元组形式(单词类型,单词本身,行号,列号),output文件中的每一行对应一个单词的信息。
四元组形式中,第一项为单词类型,第二项为单词本身,第三项为单词所在的行号,第四项为单词所在的列号。
注意:词法分析器需要滤掉注释,即在词法分析过程中遇到注释则跳过,继续分析随后的单词信息,词法分析器的输出信息中不含注释。
三、实验提示1、对于设计词法分析器来说,首先应明确词法分析器是做什么的,然后进行分析和设计,最后编程实现并测试。
即先分析问题,再想解决问题的办法,然后再着手解决问题。
2、编程实现词法分析器后,是否进行了测试?特别是,你设计的词法分析器能否滤掉注释?能否识别小数?3、在进行词法分析时,会遇到什么样的错误?词法分析器能否识别这些错误?当遇到这些错误后,词法分析器如何继续进行分析?四、实验提交资料1、词法分析器设计思路.doc,其内容包含各类单词的DFA描述、词法分析器的处理流程等;2、词法分析器源程序;3、测试输入文件input.txt及词法分析输出文件output.txt。
这三类资料打包,文件名命名为“学号姓名实验二”,上交至邮箱:tlf1220@。
DO IT YOURSELF – CHEATING WILL BE PUNISHED词法分析程序参考文档一、实验目的设计、编制并调试一个词法分析程序,加深对词法分析原理的理解。
二、实验要求2.1 待分析的简单的词法(1)关键字:begin if then while do end所有的关键字都是小写。
(2)运算符和界符:= + - * / < <= <> > >= = ; ( ) #(3)其他单词是标识符(ID)和整型常数(SUM),通过以下正规式定义:ID = letter (letter | digit)*NUM = digit digit*(4)空格有空白、制表符和换行符组成。
空格一般用来分隔ID、SUM、运算符、界符和关键字,词法分析阶段通常被忽略。
2.2 各种单词符号对应的种别码:输入:所给文法的源程序字符串。
输出:二元组(syn,token或sum)构成的序列。
其中:syn为单词种别码;token为存放的单词自身字符串;sum为整型常数。
例如:对源程序begin x:=9: if x>9 then x:=2*x+1/3; end #的源文件,经过词法分析后输出如下序列:(1,begin)(10,x)(18,:=)(11,9)(26,;)(2,if)……标识符(需进一步判断是否为关键字)数字+=+-=-词法分析状态转换图(终结状态右上角*表示多读一个符号)三、词法分析程序的算法思想:算法的基本任务是从字符串表示的源程序中识别出具有独立意义的单词符号,其基本思想是根据扫描到单词符号的第一个字符的种类,拼出相应的单词符号。
3.1 主程序示意图:主程序示意图如图3-1所示。
其中初始包括以下两个方面: ⑴ 关键字表的初值。
关键字作为特殊标识符处理,把它们预先安排在一张表格中(称为关键字表),当扫描程序识别出标识符时,查关键字表。
如能查到匹配的单词,则该单词为关键字,否则为一般标识符。
关键字表为一个字符串数组,其描述如下:Char *rwtab[6] = {“begin ”, “if ”, “then ”, “while ”, “do ”, “end ”};否(2)程序中需要用到的主要变量为syn,token和sum3.2 扫描子程序的算法思想:首先设置3个变量:①token用来存放构成单词符号的字符串;②sum用来存放整型单词;③syn用来存放单词符号的种别码。
扫描子程序主要部分流程如图3-2所示。
图 3-2四、词法分析程序的C++语言程序源代码:#include"stdafx.h"#include"conio.h" //包含getch函数的头文件#include"stdlib.h" //包含exit函数的头文件#include <stdio.h>#include <string.h>char prog[80],token[8],ch;int syn,p,m,n,sum;char *rwtab[6]={"begin","if","then","while","do","end"};scaner();main(){p=0;printf("\n please input a string(end with '#'):/n");do{scanf("%c",&ch);prog[p++]=ch;}while(ch!='#');p=0;do{scaner();switch(syn){case 11:printf("( %-10d%5d )\n",sum,syn);break;case -1:printf("you have input a wrong string\n");getch();exit(0);default: printf("( %-10s%5d )\n",token,syn);break;}}while(syn!=0);getch();}scaner(){ sum=0;for(m=0;m<8;m++)token[m++]=NULL;ch=prog[p++];m=0;while((ch==' ')||(ch=='\n'))ch=prog[p++];if(((ch<='z')&&(ch>='a'))||((ch<='Z')&&(ch>='A'))){ while(((ch<='z')&&(ch>='a'))||((ch<='Z')&&(ch>='A'))||((ch>='0')&&(ch<='9'))) {token[m++]=ch;ch=prog[p++];}p--;syn=10;for(n=0;n<6;n++)if(strcmp(token,rwtab[n])==0){ syn=n+1;break;}}else if((ch>='0')&&(ch<='9')){ while((ch>='0')&&(ch<='9')){ sum=sum*10+ch-'0';ch=prog[p++];}p--;syn=11;}{ case '<':token[m++]=ch; ch=prog[p++];if(ch=='='){ syn=22;token[m++]=ch; }else{ syn=20;p--;}break;case '>':token[m++]=ch; ch=prog[p++];if(ch=='='){ syn=24;token[m++]=ch;}else{ syn=23;p--;}break;case '+': token[m++]=ch; ch=prog[p++];if(ch=='+'){ syn=17;token[m++]=ch;}else{ syn=13;p--;}break;case '-':token[m++]=ch; ch=prog[p++];if(ch=='-'){ syn=29;token[m++]=ch;}else{ syn=14;p--;}break;case '!':ch=prog[p++];if(ch=='='){ syn=21;token[m++]=ch;}else{ syn=31;p--;}break;case '=':token[m++]=ch; ch=prog[p++];{ syn=25;token[m++]=ch;}else{ syn=18;p--;}break;case '*': syn=15;token[m++]=ch;break;case '/': syn=16;token[m++]=ch;break;case '(': syn=27;token[m++]=ch;break;case ')': syn=28;token[m++]=ch;break;case '{': syn=5;token[m++]=ch;break;case '}': syn=6;token[m++]=ch;break;case ';': syn=26;token[m++]=ch;break;case '\"': syn=30;token[m++]=ch;break;case '#': syn=0;token[m++]=ch;break;case ':':syn=17;token[m++]=ch;break;default: syn=-1;break;}token[m++]='\0';}五、结果分析:输入begin x:=9: if x>9 then x:=2*x+1/3; end # 后经词法分析输出如下序列:(begin 1)(x 10)(:17)(= 18)(9 11)(;26)(if 2)……如图5-1所示:图5-1六、总结:词法分析的基本任务是从字符串表示的源程序中识别出具有独立意义的单词符号,其基本思想是根据扫描到单词符号的第一个字符的种类,拼出相应的单词符号。