Removed_实验一:词法分析器编制实验37
词法分析实验
![词法分析实验](https://img.taocdn.com/s3/m/7919d129192e45361066f54f.png)
实验一:词法分析一、实验目的通过设计编制调试一个具体的词法分析程序,加深对词法分析原理的理解。
并掌握在对程序设计语言源程序进行扫描过程中将其分解为各类单词的词法分析方法。
编制一个读单词过程,从输入的源程序中,识别出各个具有独立意义的单词,即基本保留字、标识符、常数、运算符、分隔符五大类。
并依次输出各个单词的内部编码及单词符号自身值。
二、实验预习提示1、词法分析器的功能和输出格式词法分析器的功能是输入源程序,输出单词符号。
词法分析器的单词符号常常表示成以下的二元式(单词种别码,单词符号的属性值)。
本实验中,采用的是一类符号一种别码的方式。
2、单词的BNF表示<标识符>----> <字母><字母数字串><无符号整数>----> <数字><数字串><加法运算符>----> +<减法运算符>----> -等等3、模块结构(见课本P95-96)(可根据自己的理解适当修改)三、实验过程和指导:(一)准备:1.阅读课本有关章节,明确语言的语法,写出基本保留字、标识符、常数、运算符、分隔符和程序例。
2.初步编制好程序。
3.准备好多组测试数据。
(二)上机:(三)程序要求:1.要求用C++Builder或者Dephi或者VB或者VC或者JAVA等可视化编程工具编写;要求有界面(即一般windows下应用程序界面)。
2.输入为某语言源代码。
程序输入/输出示例:如源程序为C语言。
输入如下一段:main(){int a,b;a=10;b=a+20;}要求输出如下(也可以以文件形式输出)。
(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,”)“)注:为右大括号要求(可根据实际情况加以扩充和修改):识别保留字:if、int、for、while、do、return、break、continue等等;单词种别码为1。
词法分析器实验报告
![词法分析器实验报告](https://img.taocdn.com/s3/m/7c8d96c170fe910ef12d2af90242a8956aecaa78.png)
词法分析器实验报告引言:词法分析器(Lexical Analyzer)是编译器的重要组成部分,其主要任务是将源代码转化为一个个独立的词法单元,为语法分析器提供输入。
在本次实验中,我们设计并实现了一个简单的词法分析器,通过对其功能和性能的测试,评估其在不同场景下的表现。
实验目的:1. 确定词法分析器的输入和输出要求;2. 通过构建适当的正则表达式规则,匹配不同类型的词法单元;3. 实现一个高效的词法分析器,确保在处理大型源代码时性能不受影响;4. 对词法分析器的功能和性能进行测试和评估。
实验过程:1. 设计词法分析器的接口:1.1 确定输入:源代码字符串。
1.2 确定输出:词法单元流,每个词法单元包含类型和对应的字符串值。
2. 构建正则表达式规则:2.1 识别关键字:根据编程语言的关键字列表构建正则表达式规则,将关键字与标识符区分开。
2.2 识别标识符:一般由字母、下划线和数字组成,且以字母或下划线开头。
2.3 识别数字:整数和浮点数可以使用不同的规则来识别。
2.4 识别字符串:使用引号(单引号或双引号)包裹的字符序列。
2.5 识别特殊符号:各类操作符、括号、分号等特殊符号需要单独进行规则设计。
3. 实现词法分析器:3.1 读取源代码字符串:逐个字符读取源代码字符串,并根据正则表达式规则进行匹配。
3.2 保存词法单元:将匹配到的词法单元保存到一个词法单元流中。
3.3 返回词法单元流:将词法单元流返回给调用者。
4. 功能测试:4.1 编写测试用例:针对不同类型的词法单元编写测试用例,包括关键字、标识符、数字、字符串和特殊符号。
4.2 执行测试用例:将测试用例作为输入传递给词法分析器,并检查输出是否和预期一致。
4.3 处理错误情况:测试词法分析器对于错误输入的处理情况,如非法字符等。
5. 性能测试:5.1 构建大型源代码文件:生成包含大量代码行数的源代码文件。
5.2 执行词法分析:使用大型源代码文件作为输入,测试词法分析器的性能。
词法分析器实验报告
![词法分析器实验报告](https://img.taocdn.com/s3/m/a458259003d276a20029bd64783e0912a2167c2d.png)
词法分析器实验报告⼀、实验⽬的通过设计⼀个词法分析程序,对词法进⾏分析,加强对词法的理解,掌握对程序设计语⾔的分解和理解。
⼆、实验内容和要求在原程序中输⼊源代码对字符串表⽰的源程序从左到右进⾏扫描和分解根据词法规则识别出⼀个⼀个具有独⽴意义的单词符号以供语法分析之⽤发现词法错误,则返回出错信息在源程序中,⾃动识别单词,把单词分为五种,并输出对应的单词种别码。
1. 识别关键字:main if int for while do return break continue,该类的单词码为1.2. 识别标识符:表⽰各种名字,如变量名、数组名、函数名等,如char ch, int syn, token,sum,该类的单词码为2.3. 运算符:+、-、*、/、=、>、<、>=、<=、!=4. 分隔符:,、;、{、}、(、)5. 常数,例:123各种单词符号对应的种别码。
输出形式:⼆元式– (单词种别,单词⾃⾝的值)单词种别,表明单词的种类,语法分析需要的重要信息– 整数码关键字、运算符、界符:⼀符⼀码标识符:10, 常数:11单词⾃⾝的值– 标识符token、常数sum– 关键字、运算符、界符token三、实验⽅法、步骤及结果测试1.源程序#include <stdio.h>#include <string.h>char string[80],simbol[8],ch;int wordID,index,m,n,sum;char *rwtab[6]={"begin","if","then","while","do","end"};void scaner(void);main(){int index=0;printf("请输⼊代码,并以串#号键结束:\n");do{scanf("%c",&ch);string[index++]=ch;}while(ch!='#');index=0;do{scaner();switch(wordID)case11:printf("( %-10d%5d )\n",sum,wordID);break;case -1:printf("错误\n");return0;break;default:printf("( %-10s%5d )\n",simbol,wordID);break;}}while(wordID!=0);return0;}void scaner(void){sum=0;for(m=0;m<8;m++)simbol[m++]= NULL;ch=string[index++];m=0;while((ch=='')||(ch=='\n'))ch=string[index++];if(((ch<='z')&&(ch>='a'))||((ch<='Z')&&(ch>='A')))//判断输⼊的字符是否为英⽂字母 {while(((ch<='z')&&(ch>='a'))||((ch<='Z')&&(ch>='A'))||((ch>='0')&&(ch<='9'))){simbol[m++]=ch;ch=string[index++];}index--;wordID=10;for(n=0;n<6;n++)if(strcmp(simbol,rwtab[n])==0){wordID=n+1;break;}}else if((ch>='0')&&(ch<='9'))//判断输⼊的字符是否为数字{while((ch>='0')&&(ch<='9')){sum=sum*10+ch-'0';ch=string[index++];}index--;wordID=11;}else{switch(ch)//通过循环判断输⼊的字符是否为运算符{case'<':simbol[m++]=ch;ch=string[index++];if(ch=='='){wordID=22;simbol[m++]=ch;}else{wordID=20;index--;}break;case'>':simbol[m++]=ch;ch=string[index++];if(ch=='='){wordID=24;simbol[m++]=ch;else{wordID=23;index--;}break;case'+':simbol[m++]=ch;ch=string[index++];if(ch=='+'){wordID=17;simbol[m++]=ch;}else{wordID=13;index--;}break;case'-':simbol[m++]=ch;ch=string[index++];if(ch=='-'){wordID=29;simbol[m++]=ch;}else{wordID=14;index--;}break;case'!':ch=string[index++];if(ch=='='){wordID=21;simbol[m++]=ch;}else{wordID=31;index--;}break;case'=':simbol[m++]=ch;ch=string[index++];if(ch=='='){wordID=25;simbol[m++]=ch;}else{wordID=18;index--;}break;case'*':wordID=15;simbol[m++]=ch;break;case'/':wordID=16;simbol[m++]=ch;break;case'('://判断输⼊的字符是否为分隔符 wordID=27;simbol[m++]=ch;break;case')':wordID=28;simbol[m++]=ch;break;case'{':wordID=5;simbol[m++]=ch;break;case'}':wordID=6;simbol[m++]=ch;break;case';':wordID=26;simbol[m++]=ch;break;case'\"':wordID=30;simbol[m++]=ch;break;case'#':wordID=0;simbol[m++]=ch;break;case':':wordID=17;simbol[m++]=ch;break;default:wordID=-1;break;}}simbol[m++]='\0'; }四.运⾏结果及分析。
实验一:词法分析研究器编制实验
![实验一:词法分析研究器编制实验](https://img.taocdn.com/s3/m/5b050e6169dc5022abea00d5.png)
实验一:词法分析器编制实验一教学重点与实现地关键技术1.1词法分析概述人们理解一篇文章(或解析一个程序)起码是在单词级别上来思考地.同样,编译程序也是在单词地级别上来分析和翻译源程序地.词法分析地任务是:从左至右逐个字符地对源程序进行扫描,产生一个个地单词符号(tok en),把作为字符串地源程序改造成单词符号串地中间程序.因此,词法分析是编译地基础.执行词法分析地程序称为词法分析器.构造词法分析器地方法分为手工编制和自动生成(如用著名地词法分析器地自动生成工具Lex自动为某种语言地编译构造词法分析器)两种,本实验要求学生利用所学习掌握地知识手工编制一个小型地词法分析器.1.2词法分析器地设计要求1.2.1词法分析器地功能和输出形式词法分析器地功能是输入源程序,输出单词符号.单词符号是一个程序语言地基本语法符号.程序语言地单词符号一般可分为下列五种.(1)关键字是由程序语言定义地具有固定意义地标志符.有时称这些标志符为保留字或基本字.例如,Pascal中地begin,end,if,while都是保留字.这些字通常不用作一般标志符.(2)标识符用来表示各种名字,如变量名、数组名、过程名等等.(3)常数常数地类型一般有整型、实型、布尔型、文字型等等.例如,100,3.14159,TRUE,‘Sample’.(4)运算符如+、-、*、/等等(5)界符如逗号、分号、括号、/*,*/等等.一个程序语言地关键字、运算符和界符都是确定地,一般只有几十个或上百个.而对于标识符或常数地使用通常都不加什么限制.词法分析器所输出地单词符号常常表示成如下地二元式:(单词种别,单词符号地属性值)单词种别通常用整数编码.一个语言地单词符号如何分种,分成几种,怎么编码,是一个技术性地问题.它主要取决于处理上地方便.标识符一般统归为一种.常数则宜按类型(整、实、布尔等)分种.关键字可将其全体视为一种,也可以一字一种.采用一字一种地分法实际处理起来较为方便.运算符可采用一符一种地分法,但也可以把具有一定共性地运算符视为一种.至于界符一般用一符一种地分法.如果一个种别只含一个单词符号,那么,对于这个单词符号,种别编码就完全代表它自身了.若一个种别含有多个单词符号,那么,对于它地每个单词符号,除了给出种别编码之外,还应给出有关单词符号地属性信息.单词符号地属性是指单词符号地特性或特征.属性值则是反映特性或特征地值.例如,对于某个标识符,常将存放它地有关信息地符号表项地指针作为其属性值;对于某个常数,则将存放它地常数表项地指针作为其属性值.在这里,我们给出一种编码方法(以FORTRAN语言为例):单词符号编码举例单词种别内部助记符符号编码值DIM IF DO 123$DIM$IF$DO标 准STOPEND 标 识 符456 内 部符 号 串$STOP$END$IDN整数7 $INT 二 进 制=+ * **, (89 10 11 1213$ASG$PLUS $STAR $POWER $COMMA$SLP) 14 $SRP1.2.2 词法分析器作为一个独立子程序为何将词法分析作为一个独立阶段呢?是否还应该将它安排为独立地一遍 呢?把词法分析安排为一个独立阶段地好处是 ,它可使整个编译程序地结构更简 洁、清晰和条理化.词法分析比语法分析要简单得多,可用更有效地特殊方法和工具 进行处理.但是,这并不意味着我们也必须把词法分析作为独立地一遍 .当然,也可以把词 法分析安排成独立地一遍 .让它把整个源程序翻译成一连串地单词符号存放于文 件中.待语法分析器进入工作是在对从文件输进地这些单词符号进行分析 .这种做 法意味着必须在文件中保存整个源程序地内码形式 ,这似乎是没有必要地 .我们可 以把词法分析器安排成一个子程序 ,每当语法分析器需要一个单词符号时就调用 这个子程序.每一次调用,词法分析器就从输入串中识别出一个单词符号 ,把它交给 语法分析器.这样,把词法分析器安排成一个子程序就比较自然.1.3 词法分析器地实现技术在以下地讨论中 ,我们将按照词法分析地任务和作为一个独立子程序地要求来考虑词法分 析器地设计.1.3.1 输入、预处理词法分析器工作地第一步是输入源程序文本 .输入串一般是放在一个缓冲区中 ,这个缓冲区 称输入缓冲区.词法分析地工作可以直接在这个缓冲区中进行 .但在很多情况下,把输入串预处理 一下,对单词符号地识别工作将是比较方便地.对于许多程序语言来说,空白符、跳格符、回车符和换行符等编辑性字符除了出现在文字常 数中之外,在别处地任何出现都没有意义.对于它们,预处理时可以将其剔掉.我们可以设想构造一个预处理子程序来完成预处理功能 .每当词法分析器调用它时 ,它就处 理出一串确定长度地输入字符 ,并将其装进词法分析器所指定地缓冲区中(称为扫描缓冲区) . 这样,分析器就可以在此缓冲区中直接进行单词符号地识别,而不必照管其它繁琐事务.分析器对扫描缓冲区进行扫描时一般用两个指示器 ,一个指向当前正在识别地单词地开始 位置(指向新单词地首字符),另一个用于向前搜索以寻找单词地终点.不论扫描缓冲区设地多大都不能保证单词符号不会被他地边界所打断 .因此,扫描缓冲区最 好使用一个如下所示地一分为二地区域 ,即著名地双缓冲区设计 .具体地操作步骤如下图所示:每次移动向前指针都需要做两次测试.forward:=forward+1;if forward 在缓冲区第一部分末尾 the n 重装缓冲区第二部分else if forward 在缓冲区第二部分末尾 th e n begin重装缓冲区第一部分;将 forward 移到缓冲区第一部分开始 endforward:=forward+1; If forward !=e o f th e nIf forward 在缓冲区第一部分末尾 th e n 重装 缓冲区第二部分else if forward 在第二部分末尾 then begin 重装缓冲区第一部分;将 forward 移到缓冲区第一部分开始endelse 终止词法分析 /*eof 在表示输入结束*/1.3.2 单词符号地识别:状态转换图使用状态转换图是设计词法分析器地一种好途径.转换图是一张有限方向图(有向图)在状 态转换图中,结点代表状态,用圆圈表示.状态之间用箭弧连接.箭弧上地标记(字符)代表在射出 结点(即箭弧始结点)状态下可能出现地输入字符或字符类.举例:对于正规式 IDN →letter(letter|digit)*描述地标识符,其状态图如下所示:letter ,digitletterε(其它)(IDN ,入口)digitdigit其它:+ε (其它)(ASG ,_)(NUM ,值)=(ADD ,_)+ADD→+1.3.3 利用状态转换图识别单词(Token )地步骤 1. 从初态出发2. 读入一字符3. 按当前字符转入下一状态4. 重复 2,3 直到无法继续转移ASG→:=(INC ,_)INC→++注:在遇到读入地字符是T oken地分割符时,若当前状态是终止状态,说明读入地字符组成一单词;否则,说明输入不符合词法规则.1.3.4算法描述★子程序scan()⏹输入:字符流⏹输出:⏹Symbol(Code):单词种别⏹Attr(value):属性(全局变量)★数据结构与子例程⏹数据结构⏹ch当前输入字符⏹tok en输入缓冲区(字符数组)⏹symbol单词种别(子程序地返回值)⏹attr属性(全局变量)⏹子例程⏹Lookup(token):将tok en存入符号表,返回入口指针⏹isKeyword(token):判别tok en是关键字?返回关键字种别或-1⏹getchar():从输入缓冲区中读入一个字符放入ch⏹isdigit()isalpha()★该例地实现算法1.getchar()2.WHILE ch是空格//跳过空格2.1DO getchar();3.CASE ch OF4.isdigit(ch):4.1ch→token;getchar();4.2WHILE isdigit(ch)DOch→token;getchar();4.3输入指针回退一个字符;4.4将tok en中地字符串变成数值→attr4.5返回NUM5.isalpha(ch):5.1ch→token;getchar();5.2WHILE isalpha(ch)OR isdigit(ch)DO ch→token;getchar();5.3输入指针回退一个字符;5.4key=isKeyword(token);5.5IF key≥0THEN返回key5.6Lookup(token)→attr;5.7返回IDN6':':getchar();6.1IF ch等于'='THEN返回ASG6.2出错处理7'+':返回ADD8'-':返回SUB9'*':返回MUL10'/':返回DIV11'=':返回EQ12'>':返回GT13'<':返回LT. ,, . .14 '(' : 返回 LP 15 ')' : 返回 RP 16 ';' : 返回 SEMI 17 其它 : 出错处理 18 END OF CASE 1.4 实现地关键技术提示除了前述地双缓冲区设计、识别单词地状态转换图等,符号表地组织与实现也是不容忽视地 一项关键技术.但由于学生初次接触编译系统地设计,往往忽略符号表地设计,即使想到了也无从 下手.有地学生甚至认为标识符表既是符号表地全部——编译地运行环境只需要(也只能有)一 张标识符表.这种理解上地偏差正是由于对符号表地作用(特别是对标识符表地特定用途)理解 不够,而多数教科书在这个问题上往往只是给出一些宏观上地引导所至 .下面将分别对符号表地 作用与具体实现进行阐述.1.4.1 符号表地作用为了检查语义地正确性和生成代码 ,编译程序需要知道用户源程序中所使用地各种标识符 地属性,这些属性信息常常由编译程序集中起来并存放于一张标识符表或符号表中符号表用于存放程序中出现地有关各种名字地属性信息 ,以反应名字地语义特征 ,编译地各 阶段均涉及符号表地操作.符号表地作用主要有以下几个方面:1) 收集符号地各种属性.如名字、类型、定义地层次等.2) 作为语义地合法性检查地依据.如引用时类型是否一致、层次是否得当等.作为目标代码生成阶段地址分配地依据.如根据符号表中该变量地特性可为其在适当地 存储区域分配大小合适地存储空间.1.4.2 符号表地建立符号表一般在编译程序地开始阶段(词法分析或语法分析阶段)就建立了其内容地填写一 般在词法分析、语法分析、语义分析阶段陆续填入而它地使用与管理则贯穿于整个编译程序工 作地各个阶段.1.4.3 符号表地内容符号表地每一项(也称入口)由若干域构成,存放一个符号地所有属性信息. 程序设计语言中地符号一般分为两大部分:固定部分和非固定部分 (1)固定部分符号表固定部分包括符号地名字域和种属域. (2)非固定部分符号表地非固定部分包括符号地各种信息域.不同种属地符号有不同地信息域 ,如简单变量有类型、地址、存储类别、作用域等信息域 , 数组名可有类型、内情向量地址等信息域,过程名、函数名可有参数个数、参数表地址、入口地 址等信息域.1.4.4 符号表地组织符号表地组织直接关系到语义功能地实现和语义处理地时空效率 ★符号表地总体组织所谓符号表地总体组织就是构造多少张符号表 ,以及哪些符号放在同一张表中 ,一般可选以 下三种方式之一:1)将属性完全相同地符号(即同一种属地符号)组织在一起构成一张符号表 ,从而编译程 序将使用多张符号表.优点是每张符号表地属性个数和结构完全相同,每个表项等长、表项中每个 栏目均有效,对其中地每个符号地管理方便一致.缺点是编译程序要同时管理多个符号表 ,管理工 作量和复杂度较大.2)所有符号都组织在一张符号表中.优点是管理集中,缺点是符号表地结构及相应地表处理较为复杂.3)前两种方式地折中,即按符号所具有地属性地相似程度分类组织成若干张表,其优缺点自然也是前两种方式地折中.以上是关于符号表地一般描述 .由于符号表是指存放与管理源程序中出现地各种名字地相 关信息地表地总称,对于多趟扫描地编译系统,在具体实现时应包含名字表和标识表(如 N.Wirth, ,在其为著名地 Tiny Pascal 构造地范例编译程序就是这样设计地) 名字表,顾名思义,只是用来存 放源程序中出现地不同地各种名字(即标识符)地拼法(字符串)而标识符表则是在语义分析 阶段随着分析地进程为每个过程体中说明地标识符动态地建立起来 ,并为语义分析与中间代码 生成服务地;显然,同名地出现在不同过程体中地标识符(由于其作用域不同)将分别出现在与 该过程体相关地标识符表中 ,这一点与名字表中地情形是不同地 .这也是由于名字表与标识符表 中存入地信息是在编译地不同阶段获取地 .事实上,在词法分析阶段,并不会涉及到标识符地作用 域分析与类型检查等工作 ,而只需收集源程序中出现地名字信息以及这些名字是否为关键字即 可.因此只需要查填名字表 .所以,名字表地实现较为简单 ,可用一字符串型地一维数组来实现 .不 同地名字在表(数组)中有不同地下标,我们就以名字在表中地下标代表不同地标识符.当词法分析器析出一个名字时 ,还不能肯定其就是一个用户定义地标识符 ,因为它还可能是 语言本身地保留字又称关键字 ,而关键字是不能被用作标识符地 .为了在析出一个名字时能高效 地判断其是否为关键字,在词法分析阶段要建立一张保留字(关键字)表.可设置一个结构型数组 ResWords,其第一个域 sp 按保留字地长度从短到长地顺序存放保留字地拼法(spelling),第二个域 sy 存放相应地内部符号 .数组 frw 是为了加速比较而引入地 ,它地第 i 个元素是在保留字表 ResWords 中长度为 i 地第一个保留字地下标.下图以 Pascal 语言地一个子集地保留字集合来说明设计思想.Res W ordsspsy1‘IF’…..ifsy…..12’ 3’ 4 5 6 7 891011frw11 6 13 16 2022232425256121314 1516 17181920 21 222324 ‘V AR’…..‘MOD’‘TYPE’‘THEN’ ‘ELSE’ ‘CONST’ ‘BEGIN’‘WHILE’‘ARRAY’‘DOWNTO’ ‘RECORD’ ‘PROGRAM’ ‘FUNCTION’‘PROCEDURE’varsy…..mod syT ypesythensy eslesy constsy beginsy whilesyarraysydowntosy recordsy programsy funcsyprocsy25.二词法分析器地具体要求 2.1 实验目地基本掌握计算机语言地词法分析器地开发方法. 2.2 实验内容编制一个能够分析三种整数、标识符、主要运算符和主要关键字地词法分析器 2.3 实验要求1 根据以下地正规式,编制正规文法,画出状态图 标识符 <字母>(<字母>|<数字字符>)* 十进制整数 0 | (1|2|3|4|5|6|7|8|9)(0|1|2|3|4|5|6|7|8|9)* 八进制整数 0(1|2|3|4|5|6|7)(0|1|2|3|4|5|6|7)* 十六进制整数 0x(0|1|2|3|4|5|6|7|8|9|a|b|c|d|e|f)(0|1|2|3|4|5|6|7|8|9|a|b|c|d|e|f)* 运算符和分隔符 + - * / > < = ( ) ; 关键字 if th e n else while do2 根据状态图,设计词法分析函数 int scan( ),完成以下功能:1) 从键盘读入数据,分析出一个单词. 2) 返回单词种别(用整数表示),3) 返回单词属性(不同地属性可以放在不同地全局变量中). 3 编写测试程序,反复调用函数 scan( ),输出单词种别和属性.2.4 实验环境★PC 微机★DOS 操作系统或 Windows 操作系统★T urbo C 程序集成环境或 Visual C++ 程序集成环境 2.5 实验步骤1 根据状态图,设计词法分析算法2 采用 C 语言,设计函数 scan( ),实现该算法3 编制测试程序(主函数 main ).4 调试程序:输入一组单词,检查输出结果. 2.6 基本测试数据输入数据例: 0 92+data> 0x3f 00 while 正确结果:这些单词地单词种别及其属性INT10 0 INT10 92 + _ IDN d ata > _ INT16 63 INT8 0 WHILE _2.7实验报告要求实验报告应包括以下几个部分:1词法地正规式描述2变换后地正规文法3状态图4词法分析器地数据结构与算法2.8思考题1词法分析能否采用空格来区分单词?2程序设计中哪些环节影响词法分析地效率?如何提高效率?版权申明本文部分内容,包括文字、图片、以及设计等在网上搜集整理.版权为个人所有This article includes some parts,including text,pictures, and design.Copyright is personal ownership.用户可将本文地内容或服务用于个人学习、研究或欣赏,以及其他非商业性或非盈利性用途,但同时应遵守著作权法及其他相关法律地规定,不得侵犯本网站及相关权利人地合法权利.除此以外,将本文任何内容或服务用于其他用途时,须征得本人及相关权利人地书面许可,并支付报酬.Users may use the contents or services of this article for personal study,research or appreciation,and othernon-commercial or non-profit purposes,but at the same time, they shall abide by the provisions of copyright law and other relevant laws,and shall not infringe upon the legitimate rights of this website and its relevant obligees.In addition, when any content or service of this article is used for otherpurposes,written permission and remuneration shall be obtained from the person concerned and the relevant obligee.转载或引用本文内容必须是以新闻性或资料性公共免费信息为使用目地地合理、善意引用,不得对本文内容原意进行曲解、修改,并自负版权等法律责任.Reproduction or quotation of the content of this article must be reasonable and good-faith citation for the use of news or informative public free information.It shall not misinterpret or modify the original intention of the content of this article,and shall bear legal liability such as copyright.。
词法分析器的实验报告
![词法分析器的实验报告](https://img.taocdn.com/s3/m/08b5cf804128915f804d2b160b4e767f5acf8083.png)
词法分析器的实验报告词法分析器的实验报告引言:词法分析器是编译原理中的重要组成部分,它负责将源代码中的字符序列转换为有意义的词法单元,为后续的语法分析提供基础。
本实验旨在设计和实现一个简单的词法分析器,并对其进行测试和评估。
实验设计:1. 词法规则设计:在开始实验之前,我们首先需要设计词法规则,即定义源代码中的合法词法单元。
例如,对于一门类C的语言,我们可以定义关键字(如if、while、int等)、标识符、运算符(如+、-、*等)、分隔符(如()、{}等)等。
2. 有限自动机(DFA)的设计:基于词法规则,我们可以设计一个有限自动机,用于识别和分析源代码中的词法单元。
有限自动机是一个状态转换图,其中每个状态代表一种词法单元,而边表示输入字符的转换关系。
3. 实现代码:根据有限自动机的设计,我们可以使用编程语言(如Python、C++等)实现词法分析器的代码。
代码的主要功能包括读取源代码文件、逐个字符进行词法分析、识别和输出词法单元。
实验过程:1. 词法规则设计:我们以一门简单的算术表达式语言为例,设计了以下词法规则:- 数字:由0-9组成的整数或浮点数。
- 运算符:包括+、-、*、/等。
- 分隔符:包括括号()和逗号,。
- 标识符:以字母开头,由字母和数字组成的字符串。
2. 有限自动机(DFA)的设计:我们基于词法规则,设计了一个简单的有限自动机。
该自动机包含以下状态:- 初始状态:用于读取和识别源代码中的字符。
- 数字状态:用于识别和输出数字。
- 运算符状态:用于识别和输出运算符。
- 分隔符状态:用于识别和输出分隔符。
- 标识符状态:用于识别和输出标识符。
3. 实现代码:我们使用Python编程语言实现了词法分析器的代码。
代码主要包括以下功能:- 读取源代码文件。
- 逐个字符进行词法分析,根据有限自动机的设计进行状态转换。
- 识别和输出词法单元。
实验结果:我们对几个测试样例进行了词法分析,并对结果进行了评估。
编译原理实验报告——词法分析器(内含源代码)
![编译原理实验报告——词法分析器(内含源代码)](https://img.taocdn.com/s3/m/17b46fdac1c708a1284a44da.png)
编译原理实验(一)——词法分析器一.实验描述运行环境: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置为空白字符。
实验一、词法分析器(含源代码)
![实验一、词法分析器(含源代码)](https://img.taocdn.com/s3/m/7161ce24dd88d0d232d46a3e.png)
词法分析器实验报告一、实验目的及要求本次实验通过用C语言设计、编制、调试一个词法分析子程序,识别单词,实现一个C语言词法分析器,经过此过程可以加深对编译器解析单词流的过程的了解。
运行环境:硬件:win dows xp软件:visual C++6.0二、实验步骤1.查询资料,了解词法分析器的工作过程与原理。
2.分析题目,整理出基本设计思路。
3.实践编码,将设计思想转换用c语言编码实现,编译运行。
4.测试功能,多次设置包含不同字符,关键字的待解析文件,仔细察看运行结果,检测该分析器的分析结果是否正确。
通过最终的测试发现问题,逐渐完善代码中设置的分析对象与关键字表,拓宽分析范围提咼分析能力。
三、实验内容本实验中将c语言单词符号分成了四类:关键字key (特别的将main说明为主函数)、普通标示符、常数和界符。
将关键字初始化在一个字符型指针数组*key[]中,将界符分别由程序中的case列出。
在词法分析过程中,关键字表和case列出的界符的内容是固定不变的(由程序中的初始化确定),因此,从源文件字符串中识别出现的关键字,界符只能从其中选取。
标识符、常数是在分析过程中不断形成的。
对于一个具体源程序而言,在扫描字符串时识别出一个单词,若这个单词的类型是关键字、普通标示符、常数或界符中之一,那么就将此单词以文字说明的形式输出.每次调用词法分析程序,它均能自动继续扫描下去,形成下一个单词,直到整个源程序全部扫描完毕,从而形成相应的单词串。
输出形式例如:void $ 关键字流程图、程序流程图:开始\ .丿输入源文件路径+■路径是否效是回退初始化文件指针.识别指针内容文件结束?否跳过该字符指向下一字符指向下一字符是字母惑数字nn将字符加入字符数组Word[]是是是数字吗丫否输出word为常数将字符加入字符数组Word[]将字符加入字符数组Word[]输出word为界符输出Word内容为不可识别指向下一字符4程序:#in clude<stri ng.h>#in clude<stdio.h>#in clude<stdlib.h>#in clude<ctype.h>// 定义关键字char*Key[10]={"mai n","void","i nt","char","pri ntf',"sca nf',"else","if","return"}; char Word[20],ch; // 存储识别出的单词流int lsAlpha(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 scann er(FILE *fp){ //char Word[20]={'\0'};char ch;int i,c;ch=fgetc(fp); // if(IsAlpha(ch)){ //Word[0]=ch; ch=fgetc(fp);扫描函数获取字符,指针fp并自动指向下一个字符判断该字符是否是字母i=1;while(lsNum(ch)||lsAlpha(ch)){ // 判断该字符是否是字母或数字Word[i]=ch; i++; ch=fgetc(fp); }Word[i]='\0: 〃'\0'fseek(fp,-1,1); c=lsKey(Word); if(c==0) prin tf("%s\t$ elseif(c==2) prin tf("%s\t$ else prin tf("%s\t$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';':pri ntf("%s\t$ 界符 \n\n". Word); break;case'+':ch=fgetc(fp);Word[1]=ch; if(ch=='='){代表字符结束(空格) //回退一个字符 //判断是否是关键字 普通标识符\n\n",Word);//不是关键字主函数 \n\n",Word); 关键字\n\n",Word); //输出关键字 } else//开始判断的字符不是字母if(IsNum(ch)){//判断是否是数字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 {prin tf("%s\t$ } elseif(ch=='+'){ prin tf("%s\t$ } else { fseek(fp,-1,1); prin tf("%s\t$ } break;case'-':ch=fgetc(fp);Word[1]=ch; if(ch=='='){ prin tf("%s\t$ else if(ch=='-'){ prin tf("%s\t$ } else { fseek(fp,-1,1); prin tf("%s\t$ } break;运算符\n\n",Word);〃运算符 \n\n",Word); //运算符 \n\n",Word); //运算符 \n\n",Word);运算符 \n\n",Word); //运算符“ +=”判断结果为“ ++”判断结果为“ +”}判断结果为“--”判断结果为“-”<=”fseek(fp,-1,1); printf("%s\t$运算符 \n\n",Word); // 判断结果为“ <”} break;case'>':ch=fgetc(fp);Word[1]=ch;if(ch=='=') pri ntf("%s\t$ else {fseek(fp,-1,1); printf("%s\t$ 运算符 \n\n",Word);} break;case'%':ch=fgetc(fp);Word[1]=ch; if(ch=='='){printf("%s\t$ if(lsAlpha(ch)) prin tf("%s\t$ else {fseek(fp,-1,1); printf("%s\t$ 取余运算符 \n\n",Word); } break;default:pri ntf(" }mai n() {// char in_fn[30]; FILE *fp; prin tf("\n while(1){gets(in_fn); //scan f("%s",in_fn); if((fp=fope n(in_fn,"r"))!=NULL) break; // 指针指向文件的第一个字符 else prin tf(" 文件路径错误 } printf("\n*******************do{ ch=fgetc(fp);if(ch=='#') break; // else if(ch==' '||ch=='\t'||ch=='\n'){} // else{请输入源文件名 (包括路径和后缀名)!请重新输入:"); 词法分析结果如下 文件路径读取文件内容,并返回文件指针,该 *******************\n")・ 文件以#结尾,作为扫描结束条件 忽略空格,空白,和换行运算符 \n\n",Word);运算符 \n\n",Word);}类型标识符\n\n",Word);无法识别字符!\n\n"); break;fseek(fp,-1,1); // 回退一个字节开始识别单词流sea nn er(fp);}}while(ch!='#'); return(O);}4.实验结果解析源文件:void mai n(){int a=3;a+=b;prin tf("%d",a);return;}#解析结果:5•实验总结分析通过本次实验,让再次浏览了有关c语言的一些基本知识,特别是对文件,字符串进行基本操作的方法。
编译原理_词法分析器_实验报告
![编译原理_词法分析器_实验报告](https://img.taocdn.com/s3/m/c8b3a1f8680203d8ce2f24c0.png)
词法分析器实验报告实验目的:设计、编制、调试一个词法分析子程序-识别单词,加深对词法分析原理的理解。
功能描述:该程序要实现的是一个读单词过程,从输入的源程序中,识别出各个具有独立意义的单词,即基本保留字、标识符、常数、运算符、分隔符五大类。
并依次输出各个单词的内部编码及单词符号自身值。
(遇到错误时可显示“Error!”,然后跳过错误部分继续进行)设计思想:设计该词法分析器的过程中虽然没有实际将所有的状态转移表建立出来,但是所用的思想是根据状态转移表实现对单词的识别。
首先构造一个保留字表,然后,每输入一个字符就检测应该进入什么状态,并将该字符连接到d串后继续输入,如此循环,最后根据所在的接受状态以及保留字表识别单词。
符号表:记号类别属性值ws - -const 保留字 1var 保留字 1call 保留字 1begin 保留字 1if 保留字 1while 保留字 1do 保留字 1odd 保留字 1end 保留字 1then 保留字 1procedure 保留字 1= 运算符 2< 运算符 2<= 运算符 2<> 运算符 2> 运算符 2>= 运算符 2* 运算符 2+ 运算符 2- 运算符 2/ 运算符 2:= 运算符 2ident 标识符 3number 常数 4 ( 分隔符 5) 分隔符 5; 分隔符 5, 分隔符 5. 分隔符 5状态转换图:①标识符及保留字:letter or digittStart letter②number:③关系操作符:0 21 435startdigit.digit E+ | -digitdigitdigitdigitEdigit otherother④分隔符:start< other =(<=, 2) >= other>=* * (<>, 2)(<,2)(=, 2)(>=, 2)(>, 2):=(:=,2)⑤算术运算符:使用环境:Windows xp 下的visual c++6.0程序测试: input1 : int a,b;start;( ),.( ; ,5)( (,5)( ),5) ( , ,5)( . ,5)start+- * /( + ,2) ( -,2)( *,2) ( / ,2). a=b+2;input2:while(a>=0)do7x=x+6.7E+23;end;input3:begin:x:=9if x>0 then x:=x+1;while a:=0 dob:=2*x/3,c:=a;end;output1: 3,int 3,a 5,,3,b 5,;3,a2,=3,b2,+4,2 5,; output2:output2:1,while5,(3,a2,>=4,05,)1,doerror line 32,=3,x2,+4,6.7E+235,;1,end5,;output3:output3:1,beginerror line 13,x2,:=4,91,if3,x2,>4,01,then3,x2,:=3,x2,+4,15,;1,while3,a2,:=4,01,do 3,b 2,:= 4,2 2,* 3,x 2,/4,35,,3,c2,:=3,a5,;1,end5,;测试结果与预期结果一致源程序代码:#include<stdio.h>#include<string.h>void main(){int i=0,j,k=0,state=1,f=0,linenum=1;chara[11][10]={"const","var","call","begin","if","while","do","odd","end","then","proc edure"};char b,d[40]={"\0"};freopen("input.txt","r",stdin);freopen("output.txt","w",stdout);b=getchar();while(b!=EOF)/*判断所输入字符是否为结束符*/{if(b==' '||b=='\n'||b=='\t')/*滤过空格、换行等分隔符号*/{ if(b='\n') linenum++;b=getchar();}else if((b>='a'&&b<='z')||(b>='A'&&b<='Z'))/*识别标识符以及保留字*/{d[i++]=b;b=getchar();while((b>='a'&&b<='z')||(b>='A'&&b<='Z')||(b>='0'&&b<='9')){d[i++]=b;b=getchar();}for(j=0;j<11;j++)/*查询保留字表确定该单词是否是保留字*/{ if(strcmp(d,a[j])==0){ printf("1,%s\n",d);k=1;break;}}if(k==0)/*在保留字表中没有查到该单词,是标识符*/printf("3,%s\n",d);for(j=0;j<=i;j++)d[j]='\0';i=0;k=0;}else if(b>='0'&&b<='9')/*识别常数*/{ d[i++]=b;b=getchar();while(f!=1){switch (state) {case 1:if(b>='0'&&b<='9') {state=1;d[i++]=b;b=getchar();}else if(b=='.') { state=2;d[i++]=b;b=getchar();}else if(b=='E') { state=4;d[i++]=b;b=getchar();}else state=7;break;case 2:if(b>='0'&&b<='9') {state=3;d[i++]=b;b=getchar();}else state=8;break;case 3:if(b>='0'&&b<='9') {state=3;d[i++]=b;b=getchar();}else if(b=='E') { state=4;d[i++]=b;b=getchar();}else state=7;break;case 4:if(b=='+'||b=='-') { state=5;d[i++]=b;b=getchar();}else if(b>='0'&&b<='9'){ state=6;d[i++]=b;b=getchar();} else state=8;break;case 5:if(b>='0'&&b<='9'){ state=6;d[i++]=b;b=getchar();}else state=8;break;case 6:if(b>='0'&&b<='9'){ state=6;d[i++]=b;b=getchar();}else state=7;break;case 7: f=1;break;case 8: f=1;break;}}if(state==7&&(b<'a'||b>'z')&&(b<'A'||b>'Z'))printf("4,%s\n",d);else if(state==7&&(b>='a'&&b<='z')||(b>='A'&&b<='Z'))/*数字后接字母的出错控制*/{while((b>='a'&&b<='z')||(b>='A'&&b<='Z')){ d[i++]=b;b=getchar();}printf("error line %d\n",linenum);}else printf("error line %d\n",linenum);for(j=0;j<=i;j++)d[j]='\0';i=0;f=0;state=1;}else if(b=='<')/*识别'<'、'<='和'<>'*/{ d[i++]=b;b=getchar();if(b=='='||b=='>'){ d[i++]=b;b=getchar();printf("2,%s\n",d);for(j=0;j<=i;j++)d[j]='\0';i=0;}else{ printf("2,%s\n",d);for(j=0;j<=i;j++)d[j]='\0';i=0;}}else if(b=='>')/*识别'>'和'>='*/{ d[i++]=b;b=getchar();if(b=='='){ d[i++]=b;b=getchar();printf("2,%s\n",d);for(j=0;j<=i;j++)d[j]='\0';i=0;}else{ printf("2,%s\n",d);for(j=0;j<=i;j++)d[j]='\0';i=0;}}else if(b==':')/*识别':='*/{ d[i++]=b;b=getchar();if(b=='='){ d[i++]=b;b=getchar();printf("2,%s\n",d);}else printf("error line %d\n",linenum);for(j=0;j<=i;j++)d[j]='\0';i=0;}else if(b=='*'||b=='+'||b=='-'||b=='/'||b=='=')/*识别运算符*/{ printf("2,%c\n",b);b=getchar();}else if(b=='('||b==')'||b==','||b==';'||b=='.')/*识别分隔符*/{ printf("5,%c\n",b);b=getchar();}else{ printf("error line %d\n",linenum);b=getchar();}}}实验心得:此次实验让我了解了如何设计、编制并调试词法分析程序,并加深了我对词法分析器原理的理解;熟悉了直接构造词法分析器的方法和相关原理,并学会使用c语言直接编写词法分析器;同时更熟练的掌握用c语言编写程序,实现一定的实际功能。
词法分析器实验报告
![词法分析器实验报告](https://img.taocdn.com/s3/m/423824f2e109581b6bd97f19227916888486b9c9.png)
实验报告【实验过程记录(源程序、测试用例、测试结果及心得体会等)】1、程序源代码:#include "fstream.h"#include "iostream.h"#include "string.h"#include "ctype.h"char ch ; // 存放当前的输入字符int lineno = 1; // 记录当前的行号void main()//主函数{void Reserve(ifstream&);ifstream fin("input.txt",ios::nocreate); //用ifstream的对象fin打开input文件,文件不存在时,不创建if (fin.fail()) cout << "找不到文件" << endl;Reserve(fin);fin.close();//fout.close();// ferr.close();}int judge(char *string) // 判断是否为关键字{char *keywords[1000]={"if","int","else","for","while","do","return","break","continue"};//关键字表,按相应类型号排序for(int i = 0;i <= 8;i++) //遍历keywords数组{if (!strcmp(string,*(keywords+i))){return 1; //是关键字,返回对应的类型值}}return 0; //不是关键字,返回0}void Reserve(ifstream &fin) //词法分析程序,用引用传递参数{char temp[100]; // 临时存放已读入但无法判断类型的字符int j = 0;int value_judge ;//存放函数judge的返回值while (fin.get(ch)){if (ch == '\n') {lineno += 1; }else if (ch == '\t'||ch == ' ') {} //排除制表、空格字符else if (isalpha(ch)) //当前输入符为字母{while (isalpha(ch)||isdigit(ch)){temp[j] = ch;j++;fin.get(ch);}temp[j] = '\0'; //标志字符串结束j = 0;if (value_judge = judge(temp)) // 判断是否为关键字{cout << "(1, "<< "\""<<temp<<"\")" << endl;}else cout << "(2, "<< "\""<<temp<<"\")" << endl;fin.seekg(-1,ios::cur); //回退1个字符}else if (isdigit(ch)){while (isdigit(ch)){temp[j] = ch;j++;fin.get(ch);}temp[j] = '\0'; //标志字符串结束j = 0;cout << "(3, "<< "\""<<temp<<"\")" << endl;fin.seekg(-1,ios::cur); //回退一个字符}//+、-、*、/、=、>、<、>=、<=、<>else if (ch == '+') cout << "(4, "<< "\"+\")" << endl;else if (ch == '-') cout << "(4, "<< "\"-\")" << endl;else if (ch == '*') cout << "(4, "<< "\"*\")" << endl;else if (ch == '/') cout << "(4, "<< "\"/\")" << endl;else if (ch == '=') cout << "(4, "<< "\"=\")" << endl;else if (ch == '>') cout << "(4, "<< "\">\")" << endl;else if (ch == '<') cout << "(4, "<< "\"<\")" << endl;else if (ch == '>=') cout << "(4, "<< "\">=\")" << endl;else if (ch == '<=') cout << "(4, "<< "\"<=\")" << endl;else if (ch == '<>') cout << "(4, "<< "\"<>\")" << endl;//,、;、{、}、(、)else if (ch == ',') cout << "(5, "<< "\",\")" << endl;else if (ch == ';') cout << "(5, "<< "\";\")" << endl;else if (ch == '(') cout << "(5, "<< "\"(\")" << endl;else if (ch == ')') cout << "(5, "<< "\")\")" << endl;else if (ch == '{') cout << "(5, "<< "\"{\")" << endl;else if (ch == '}') cout << "(5, "<< "\"}\")" << endl;ch = '\0';}}2、程序设计截图3、程序运行结果截图。
实验1. 词法分析实验报告
![实验1. 词法分析实验报告](https://img.taocdn.com/s3/m/842629c408a1284ac85043f0.png)
实验1. 词法分析实验报告一、实验目的调试并完成一个词法分析程序,加深对词法分析原理的理解。
二、实验要求1、待分析的简单语言的词法(1)关键字:begin if then while do end所有关键字都是小写。
(2)运算符和界符::= + –* / < <= <> > >= = ; ( ) #(3) 其他单词是标识符(ID)和整型常数(NUM),通过以下正规式定义:ID=letter(letter| digit)*NUM=digit digit *(4)空格由空白、制表符和换行符组成。
空格一般用来分隔ID、NUM,运算符、界符和关键字,词法分析阶段通常被忽略。
2、各种单词符号对应的种别码3、词法分析程序的功能输入:所给文法的源程序字符串。
输出:二元组(syn,token或sum)构成的序列。
其中:syn为单词种别码;token为存放的单词自身字符串;sum为整型常数。
三、源程序代码#include<stdio.h>#include<string.h>#include<iostream.h>char prog[80],token[8];char ch;int syn,p,m=0,n,sum=0; //p是缓冲区prog的指针,m是token的指针char *rwtab[6]={"begin","if","then","while","do","end"};void scaner(){for(n=0;n<8;n++) token[n]=NULL;ch=prog[p++];while(ch==' ')ch=prog[p++];if((ch>='a'&&ch<='z')||(ch>='A'&&ch<='Z')){m=0;while((ch>='A'&&ch<='Z')||(ch>='a'&&ch<='z')||(ch>='0'&&ch<='9')){token[m++]=ch;ch=prog[p++];}token[m++]='\0';p--;syn=10;for(n=0;n<6;n++)if(strcmp(token,rwtab[n])==0){syn=n+1;break;}}elseif((ch>='0'&&ch<='9')){sum=0;while((ch>='0'&&ch<='9')){sum=sum*10+ch-'0';ch=prog[p++];}p--;syn=11;if(sum>32767)syn=-1;}elseswitch(ch){case'<':m=0;token[m++]=ch;ch=prog[p++];if(ch=='>'){syn=21;token[m++]=ch;}else if(ch=='='){syn=22;token[m++]=ch;}else{syn=23; p--;}break;case'>':m=0;token[m++]=ch;ch=prog[p++];if(ch=='='){syn=24;token[m++]=ch;}else{syn=20;p--;}break;case':':m=0;token[m++]=ch;ch=prog[p++];if(ch=='='){syn=18;token[m++]=ch;}else{syn=17;p--;}break;case'*':syn=13;token[0]=ch;break;case'/':syn=14;token[0]=ch;break;case'+':syn=15;token[0]=ch;break;case'-':syn=16;token[0]=ch;break;case'=':syn=25;token[0]=ch;break;case';':syn=26;token[0]=ch;break;case'{':syn=27;token[0]=ch;break;case'}':syn=28;token[0]=ch;break;case'#':syn=0;token[0]=ch;break;case'\n':syn=-2;break;default: syn=-1;break;}}void main(){p=0;printf("\n please input string:\n");do{ch=getchar();prog[p++]=ch;}while(ch!='#');p=0;do{scaner();switch(syn){case 11: printf("\n(11,%d)",sum);break;case -1: printf("\nerror!");break;default: printf("\n(%d,%s)",syn,token);break;}}while(syn!=0);getch();}四、结果验证(1) 给定源程序begin x:=9;if x>0 then x:=2*x+1/3; end#输出结果。
实验一 词法分析器的设计
![实验一 词法分析器的设计](https://img.taocdn.com/s3/m/cd2c308971fe910ef12df855.png)
实验一词法分析器的设计 (2)1.1 词法分析器的结构和主要任务 (2)1.1.1 输入输出接口 (2)1.1.2 条件限制 (2)1.2 词法分析程序的总体设计 (3)1.3 词法分析程序的详细设计 (4)1.4实验步骤 (5)1.5输入数据 (15)1.6结果输出 (15)实验一词法分析器的设计实验目的:掌握词法分析的概念,设计方法,熟悉高级语言中词法的定义,词法分析程序的编写。
实验要求:在8学时内实现SAMPLE语言的词法分析器,要求用VC窗口界面实现。
实验内容:分为4次实验完成。
1.1 词法分析器的结构和主要任务1.1.1 输入输出接口图1-1词法分析器的输入输出界面词法分析程序的主要任务是从左到右扫描每行源程序,拼成单词,换成统一的内部表示(token)输出,送给语法分析器。
具体包括:1.组织源程序的输入;2.按规则拼单词,并转换成二元形式;3.滤掉空白符,跳过注释、换行符及一些无用的符号(如字符常数的引号)4.进行行列计数,用于指出出错的行列号,并复制出错部分;5.列表打印源程序;6.发现并定位词法错误;7.生成符号表。
token文件和符号表用作语法分析的输入部分。
1.1.2 条件限制本实验可以作如下假定:(1) 假定SAMPLE语言采用自由格式书写;(2) 可以使用注解,用/*……*/或者{……}标识,但注解不能插在单词内部,注解要在一行内结束,若一行结束,没有遇到注释后面的结束标记,自动认为注释也结束;(3) 一行可以有多个语句,一个语句也可以分布在多行中,单词之间和语句之间可以插入任意空格,单词中间不能有空白符号,单词中间也不能有回车换行符,即单词不能跨行书写;(4) 关键字都是保留字。
1.2 词法分析程序的总体设计图1-2 词法分析程序的顶层数据流图图1-2是词法分析程序的顶层数据流图,即是词法分析程序的输入输出界面图,由此可以看出词法分析程序的功能就是从源程序中读入一个个字符,依据一定的构词规则,识别出各类有用的单词。
编译原理实验报告(词法分析器语法分析器)
![编译原理实验报告(词法分析器语法分析器)](https://img.taocdn.com/s3/m/53c29be5dd3383c4bb4cd2e9.png)
编译原理实验报告实验一一、实验名称:词法分析器的设计二、实验目的:1,词法分析器能够识别简单语言的单词符号2,识别出并输出简单语言的基本字.标示符.无符号整数.运算符.和界符。
三、实验要求:给出一个简单语言单词符号的种别编码词法分析器四、实验原理:1、词法分析程序的算法思想算法的基本任务是从字符串表示的源程序中识别出具有独立意义的单词符号,其基本思想是根据扫描到单词符号的第一个字符的种类,拼出相应的单词符号。
2、程序流程图(1)主程序(2)扫描子程序3、各种单词符号对应的种别码五、实验容:1、实验分析编写程序时,先定义几个全局变量a[]、token[](均为字符串数组),c,s( char型),i,j,k (int型),a[]用来存放输入的字符串,token[]另一个则用来帮助识别单词符号,s用来表示正在分析的字符。
字符串输入之后,逐个分析输入字符,判断其是否‘#’,若是表示字符串输入分析完毕,结束分析程序,若否则通过int digit(char c)、int letter(char c)判断其是数字,字符还是算术符,分别为用以判断数字或字符的情况,算术符的判断可以在switch语句中进行,还要通过函数int lookup(char token[])来判断标识符和保留字。
2 实验词法分析器源程序:#include <stdio.h>#include <math.h>#include <string.h>int i,j,k;char c,s,a[20],token[20]={'0'};int letter(char s){if((s>=97)&&(s<=122)) return(1);else return(0);}int digit(char s){if((s>=48)&&(s<=57)) return(1);else return(0);}void get(){s=a[i];i=i+1;}void retract(){i=i-1;}int lookup(char token[20]){if(strcmp(token,"while")==0) return(1);else if(strcmp(token,"if")==0) return(2);else if(strcmp(token,"else")==0) return(3);else if(strcmp(token,"switch")==0) return(4);else if(strcmp(token,"case")==0) return(5);else return(0);}void main(){printf("please input string :\n");i=0;do{i=i+1;scanf("%c",&a[i]);}while(a[i]!='#');i=1;j=0;get();while(s!='#'){ memset(token,0,20);switch(s){case 'a':case 'b':case 'c':case 'd':case 'e':case 'f':case 'g':case 'h':case 'i':case 'j':case 'k':case 'l':case 'm':case 'n':case 'o':case 'p':case 'q':case 'r':case 's':case 't':case 'u':case 'v':case 'w':case 'x':case 'y':case 'z':while(letter(s)||digit(s)){token[j]=s;j=j+1;get();}retract();k=lookup(token);if(k==0)printf("(%d,%s)",6,token);else printf("(%d,-)",k);break;case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9':while(digit(s)){token[j]=s;j=j+1;get();}retract();printf("%d,%s",7,token);break;case '+':printf("('+',NULL)");break;case '-':printf("('-',null)");break; case '*':printf("('*',null)");break;case '<':get();if(s=='=') printf("(relop,LE)");else{retract();printf("(relop,LT)");}break;case '=':get();if(s=='=')printf("(relop,EQ)");else{retract();printf("('=',null)");}break;case ';':printf("(;,null)");break;case ' ':break;default:printf("!\n");}j=0;get();} }六:实验结果:实验二一、实验名称:语法分析器的设计二、实验目的:用C语言编写对一个算术表达式实现语法分析的语法分析程序,并以四元式的形式输出,以加深对语法语义分析原理的理解,掌握语法分析程序的实现方法和技术。
词法分析器实验报告
![词法分析器实验报告](https://img.taocdn.com/s3/m/2d7ec907326c1eb91a37f111f18583d049640f03.png)
词法分析器实验报告一、实验目的本实验旨在通过构建一个简单的词法分析器来加深对编译原理中词法分析的理解,并掌握基本的词法分析算法和程序设计技巧。
二、实验环境操作系统:Windows 10编程语言:C/C++开发环境:Visual Studio 2019三、实验内容1. 设计并实现一个词法分析器,要求具备以下功能:(1)能够识别并区分关键字、标识符、字符常量、字符串常量、整型常量和浮点型常量等基本单词;(2)能够跳过注释、空格、制表符和换行符等无用字符;(3)能够给出错误提示并指明错误所在位置。
2. 对设计的词法分析器进行测试,并记录测试结果,分析测试结果的正确性和效率。
四、实验方法1. 分析待处理的源程序,并确定需要识别的词法单元;2. 设计状态转换图或状态转换表,并将其转化为程序代码;3. 开发测试程序,对所设计的词法分析器进行测试。
五、实验结果1. 实现的词法分析器程序可以正确识别出源程序中的各个单词,并能够跳过无用字符;2. 在测试过程中发现了一些错误,比如未能正确识别一些特殊情况下的单词,或者给出了错误的错误提示等。
经过修改后,程序可以正确识别这些情况,并给出正确的错误提示信息;3. 程序的效率较高,能够在短时间内对源程序进行词法分析。
六、实验体会通过本次实验,我对编译原理中词法分析的概念、算法和程序设计技巧有了更加深入的了解和掌握。
在实践中,我遇到了许多问题,比如如何设计状态转换图,如何正确识别一些特殊的单词等。
这些问题一一解决后,我对词法分析有了更加深刻的理解。
通过本次实验,我还深刻体会到了编译器设计过程中的思维方式和技术要求。
编译器是计算机科学中的一项重要技术,对于提高程序运行效率、保证程序安全性、增强程序可读性和扩展程序功能等都有重要作用。
因此,编译原理作为计算机科学的重要组成部分,对于我以后的学习和研究具有重要意义。
编译原理实验一:词法分析实验
![编译原理实验一:词法分析实验](https://img.taocdn.com/s3/m/e06cf241fe4733687e21aa84.png)
实验一:词法分析实验一.实验要求1.编写一个词法分析程序,使之能识别输入串,并把分析结果(单词符号,标识符,关键字等等)以二元式的形式输出.输入源程序,输入单词符号。
2.本词法分析器可以辨别关键字,标识符,无符号整数,运算符号和定界符等。
3.运用文件读入来获取源程序代码,再对该源程序代码进行词法分析4.注意:本程序输入为程序文件,输出为二元组输入的文件为:var A,B:integer;function f(x);beginA:=A+1;X:=3end;程序执行结果为:var 31A 34- 44B 34- 50integer 34- 52function 34f 34- 39x 34- 40- 52begin 3A 34- 50- 56A 34- 431 35- 52X 34- 50- 563 35end 11- 52二.实验时间:3次课完成第1次课:查找资料,提出设计思路(每组提交电子文档说明设计思路)第2次课:设计并修改程序,测试程序(每组提交电子版源程序)第3次课:完成实验报告,课堂检查(每组提交纸质报告并抽查答辩)三.实验步骤1.写出词法分析能识别的字符串的正规文法2.正规文法转换为正规式3.正规式转换为DFA并化简4.根据DFA编写程序四.实验报告1.模块设计:将程序分成合理的多个模块(函数)及各模块功能2.设计方案:模块关系图,流程图,函数接口等3.程序编写风格:注意空行,注释,缩进4.测试过程:至少有3组测试数据5.实验总结:编程和实现的过程;遇到哪些问题;你的收获和体会。
词法分析器实验报告
![词法分析器实验报告](https://img.taocdn.com/s3/m/89237b5e26d3240c844769eae009581b6bd9bdc3.png)
词法分析器实验报告词法分析器是编译器的一个重要组成部分,用于将输入的字符流转换成一个个词法单元(token)。
本次实验使用Python语言实现了一个简单的词法分析器。
主要包括以下几个步骤:1. 预处理:去除源代码中的空格、换行符等无意义字符,并进行必要的错误检查。
2. 正则表达式定义词法单元:利用正则表达式定义源代码可以被识别为词法单元的模式。
例如,整数可以定义为由数字组成的串,标识符可以定义为以字母或下划线开头,后面跟着任意个字母、数字或下划线的串。
3. 正则表达式匹配:利用Python的re模块,使用定义好的正则表达式对预处理后的源代码进行匹配。
如果匹配成功,则生成对应的词法单元,并存储起来。
4. 输出词法单元:将生成的词法单元按照一定的格式输出。
实验结果:通过对不同的源代码进行测试,可以得到正确的词法单元输出。
例如,对于以下的源代码:```pythonx = 123 + 456 * (789 - 100)```经过词法分析器处理后,可以得到以下的词法单元输出:```Token(ID, 'x')Token(ASSIGN, '=')Token(INT, '123')Token(PLUS, '+')Token(INT, '456')Token(LPAREN, '(')Token(INT, '789')Token(MINUS, '-')Token(INT, '100')Token(RPAREN, ')')```总结与收获:通过本次实验,我对词法分析器的基本原理和实现方法有了更深入的了解。
同时,我学会了如何使用正则表达式进行模式匹配,以及如何使用Python的re模块进行正则表达式匹配。
这对于我进一步学习和理解编译原理以及编译器的工作原理有很大帮助。
编译原理词法分析器实验报告
![编译原理词法分析器实验报告](https://img.taocdn.com/s3/m/9f42f284d4bbfd0a79563c1ec5da50e2524dd19a.png)
编译原理词法分析器实验报告1. 引言编译原理是计算机科学中的重要概念,它涉及将高级语言程序转换为计算机可执行的低级指令。
词法分析是编译过程中的第一个阶段,它负责将源代码分解为词法单元,为后续的语法分析做准备。
本实验旨在设计和实现一个基本的词法分析器,以了解词法分析的原理和实际应用。
2. 实验目标本实验的主要目标是实现一个基本的词法分析器,能够识别并提取源代码中的各种词法单元。
具体而言,我们将设计一个针对某种编程语言的词法分析器,能够识别关键字、标识符、算术运算符、括号、常量等。
3. 实验环境为了完成本实验,我们需要使用以下工具和环境:•一种编程语言,例如Python、Java或C++•一个文本编辑器,例如Visual Studio Code或Sublime Text•一个命令行终端4. 实验步骤4.1 定义词法规则首先,我们需要定义词法分析器的词法规则。
这些规则描述了编程语言中各种词法单元的模式。
例如,关键字可以被定义为由特定字符组成的字符串,标识符可以被定义为以字母开头并由字母和数字组成的字符串。
4.2 实现词法分析器接下来,我们将根据定义的词法规则,使用编程语言实现一个词法分析器。
在实现过程中,我们可以使用正则表达式来匹配和提取各种词法单元。
4.3 编写测试用例完成词法分析器的实现后,我们需要编写一些测试用例来验证其正确性。
测试用例应该包含各种可能的输入情况,以确保词法分析器能够正确地识别和提取词法单元。
4.4 运行测试用例最后,我们将使用编写的测试用例来运行词法分析器,并检查输出是否符合预期。
如果测试通过,说明词法分析器能够正常工作;否则,我们需要检查代码并进行调试。
5. 实验结果经过实验,我们成功地设计并实现了一个基本的词法分析器。
该词法分析器能够按照预定义的词法规则,正确地识别和提取源代码中的各种词法单元。
在运行测试用例时,词法分析器能够产生符合预期的输出,表明其具有良好的准确性和可靠性。
实验一 词法分析器
![实验一 词法分析器](https://img.taocdn.com/s3/m/1fe8410479563c1ec5da7167.png)
实验一词法分析器一.实验目的1.掌握词法分析的原理2.设计一个词法分析程序,掌握程序设计语言中的各类单词的词法分析方法,加深对词法分析原理的理解。
3.熟悉保留字表等相关的数据结构与单词的分类方法。
4.掌握词法分析器的设计与调试。
二.实验要求2.1根据编译中的分词原理,编写一个词法分析程序:(1)输入:所给文法的源程序字符串。
(2)处理:对输入的内容进行分析,分离出保留字、标识符、常量、算符和界符。
(3)输出:对应的二元式(类别编码由自己定,一个单词符号对应一个类别码)2.2需要分析的简单的词法(1)关键字:begin if then while do end所有的关键字都是小写。
(2)运算符和界符: = + - * / < <= <> > >= = ; ( ) #(3)其他单词是标识符(ID)和整型常数(SUM),通过以下正规式定义:ID = letter (letter | digit)*NUM = digit digit*(4)空格由空白、制表符和换行符组成。
空格一般用来分隔ID、SUM、运算符、界符和关键字,词法分析阶段通常被忽略2.3各种单词符号对应的类别码1.算法的基本任务是从字符串表示的源程序中识别出具有独立意义的单词符号,词法分析基本思想是从左向右扫描每行源程序的符号,拼成单词,换成统一的二元式 (单词种别码,单词符号的属性值)表示。
对给定的程序通过词法分析器识别一个个单词符号,并以二元式(单词种别码,单词符号的属性值)显示。
(1)主程序示意图主程序的初始包括以下两个方面:① 关键字表的初值。
关键字作为特殊标识符处理,把它们预先放在一张表中(称为关键字表),当扫描程序识别出标识符时,查关键字表。
如能查到匹配的单词,则该单词为关键字,否则为一般标识符。
关键字表为一个字符串数组,其描述如下:否首先设置3个变量:(1)token 用来存放构成单词符号的字符串;(2)sum 用来存放整型单词(3)syn 用来存放单词符号的类别码。
编译原理实验报告(词法分析器-语法分析器)
![编译原理实验报告(词法分析器-语法分析器)](https://img.taocdn.com/s3/m/48c0484b6137ee06eef91859.png)
else if(strcmp(token,"if")==0) return(2);
else if(strcmp(token,"else")==0) return(3);
else if(strcmp(token,"switch")==0) return(4);
}
j=0;
get();
}}
六:实验结果:
实验二
一、实验名称:语法分析器的设计
二、实验目的:
用C语言编写对一个算术表达式实现语法分析的语法分析程序,并以四元式的形式输出,以加深对语法语义分析原理的理解,掌握语法分析程序的实现方法和技术。
三、 实验原理:
1、算术表达式语法分析程序的算法思想
首先通过关系图法构造出终结符间的左右优先函数f(a),g(a)。在分析的过程中,通过左右优先函数比较当前读入终结符和前一个读入终结符间的优先关系,分析后适时的以四元式形式输出相关的符号。
编
译
原
理
实
验
报
告
实验一
一、实验名称:词法分析器的设计
二、实验目的:1,词法分析器能够识别简单语言的单词符号
2,识别出并输出简单语言的基本字.标示符.无符号整数.运算符.和界符。
三、实验要求:给出一个简单语言单词符号的种别编码词法分析器
四、实验原理:
1、词法分析程序的算法思想
算法的基本任务是从字符串表示的源程序中识别出具有独立意义的单词符号,其基本思想是根据扫描到单词符号的第一个字符的种类,拼出相应的单词符号。
i=1;
j=0;
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
实验一:词法分析器编制实验一教学重点与实现的关键技术1.1词法分析概述人们理解一篇文章(或解析一个程序)起码是在单词级别上来思考的。
同样,编译程序也是在单词的级别上来分析和翻译源程序的。
词法分析的任务是:从左至右逐个字符地对源程序进行扫描,产生一个个的单词符号(token),把作为字符串的源程序改造成单词符号串的中间程序。
因此,词法分析是编译的基础。
执行词法分析的程序称为词法分析器。
构造词法分析器的方法分为手工编制和自动生成(如用著名的词法分析器的自动生成工具Lex自动为某种语言的编译构造词法分析器)两种,本实验要求学生利用所学习掌握的知识手工编制一个小型的词法分析器。
1.2词法分析器的设计要求1.2.1词法分析器的功能和输出形式词法分析器的功能是输入源程序,输出单词符号。
单词符号是一个程序语言的基本语法符号。
程序语言的单词符号一般可分为下列五种。
(1)关键字是由程序语言定义的具有固定意义的标志符。
有时称这些标志符为保留字或基本字。
例如,Pascal中的begin,end,if,while都是保留字。
这些字通常不用作一般标志符。
(2)标识符用来表示各种名字,如变量名、数组名、过程名等等。
(3)常数常数的类型一般有整型、实型、布尔型、文字型等等。
例如,100,3.14159,TRUE,‘Sample’。
(4)运算符如+、-、*、/等等(5)界符如逗号、分号、括号、/*,*/等等。
一个程序语言的关键字、运算符和界符都是确定的,一般只有几十个或上百个。
而对于标识符或常数的使用通常都不加什么限制。
词法分析器所输出的单词符号常常表示成如下的二元式:(单词种别,单词符号的属性值)单词种别通常用整数编码。
一个语言的单词符号如何分种,分成几种,怎么编码,是一个技术性的问题。
它主要取决于处理上的方便。
标识符一般统归为一种。
常数则宜按类型(整、实、布尔等)分种。
关键字可将其全体视为一种,也可以一字一种。
采用一字一种的分法实际处理起来较为方便。
运算符可采用一符一种的分法,但也可以把具有一定共性的运算符视为一种。
至于界符一般用一符一种的分法。
如果一个种别只含一个单词符号,那么,对于这个单词符号,种别编码就完全代表它自身了。
若一个种别含有多个单词符号,那么,对于它的每个单词符号,除了给出种别编码之外,还应给出有关单词符号的属性信息。
单词符号的属性是指单词符号的特性或特征。
属性值则是反映特性或特征的值。
例如,对于某个标识符,常将存放它的有关信息的符号表项的指针作为其属性值;对于某个常数,则将存放它的常数表项的指针作为其属性值。
在这里,我们给出一种编码方法(以FORTRAN语言为例):单词符号编码举例单词符号种别编码内部值助记符DIM1$DIMIF2$IF DO3$DO STOP4$STOP END5$END标识符6内部符号串$IDN整数7标准二进制$INT=8$ASG+9$PLUS*10$STAR**11$POWER,12$COMMA(13$SLP)14$SRP1.2.2词法分析器作为一个独立子程序为何将词法分析作为一个独立阶段呢?是否还应该将它安排为独立的一遍呢?把词法分析安排为一个独立阶段的好处是,它可使整个编译程序的结构更简洁、清晰和条理化。
词法分析比语法分析要简单得多,可用更有效的特殊方法和工具进行处理。
但是,这并不意味着我们也必须把词法分析作为独立的一遍。
当然,也可以把词法分析安排成独立的一遍。
让它把整个源程序翻译成一连串的单词符号存放于文件中。
待语法分析器进入工作是在对从文件输进的这些单词符号进行分析。
这种做法意味着必须在文件中保存整个源程序的内码形式,这似乎是没有必要的。
我们可以把词法分析器安排成一个子程序,每当语法分析器需要一个单词符号时就调用这个子程序。
每一次调用,词法分析器就从输入串中识别出一个单词符号,把它交给语法分析器。
这样,把词法分析器安排成一个子程序就比较自然。
1.3 词法分析器的实现技术在以下的讨论中,我们将按照词法分析的任务和作为一个独立子程序的要求来考虑词法分析器的设计。
1.3.1 输入、预处理词法分析器工作的第一步是输入源程序文本。
输入串一般是放在一个缓冲区中,这个缓冲区称输入缓冲区。
词法分析的工作可以直接在这个缓冲区中进行。
但在很多情况下,把输入串预处理一下,对单词符号的识别工作将是比较方便的。
对于许多程序语言来说,空白符、跳格符、回车符和换行符等编辑性字符除了出现在文字常数中之外,在别处的任何出现都没有意义。
对于它们,预处理时可以将其剔掉。
我们可以设想构造一个预处理子程序来完成预处理功能。
每当词法分析器调用它时,它就处理出一串确定长度的输入字符,并将其装进词法分析器所指定的缓冲区中(称为扫描缓冲区)。
这样,分析器就可以在此缓冲区中直接进行单词符号的识别,而不必照管其它繁琐事务。
分析器对扫描缓冲区进行扫描时一般用两个指示器,一个指向当前正在识别的单词的开始位置(指向新单词的首字符),另一个用于向前搜索以寻找单词的终点。
不论扫描缓冲区设的多大都不能保证单词符号不会被他的边界所打断。
因此,扫描缓冲区最好使用一个如下所示的一分为二的区域,即著名的双缓冲区设计。
具体的操作步骤如下图所示:1.3.2 单词符号的识别:状态转换图使用状态转换图是设计词法分析器的一种好途径。
转换图是一张有限方向图(有向图)。
在状态转换图中,结点代表状态,用圆圈表示。
状态之间用箭弧连接。
箭弧上的标记(字符)代表在射出结点(即箭弧始结点)状态下可能出现的输入字符或字符类。
举例:对于正规式IDN→letter(letter|digit)*描述的标识符,其状态图如下所示:letter,digit,_)INC→++ADD→+1.3.3 利用状态转换图识别单词(Token)的步骤1. 从初态出发2. 读入一字符3. 按当前字符转入下一状态4. 重复2,3 直到无法继续转移注:在遇到读入的字符是Token的分割符时,若当前状态是终止状态,说明读入的字符组成一单词;否则,说明输入不符合词法规则。
1.3.4算法描述★子程序scan( )⏹输入:字符流⏹输出:⏹Symbol(Code) :单词种别⏹Attr(value):属性(全局变量)★数据结构与子例程⏹数据结构⏹ch 当前输入字符⏹token 输入缓冲区(字符数组)⏹symbol 单词种别(子程序的返回值)⏹attr 属性(全局变量)⏹子例程⏹Lookup(token):将token 存入符号表,返回入口指针⏹isKeyword(token):判别token是关键字?返回关键字种别或-1⏹getchar():从输入缓冲区中读入一个字符放入ch⏹isdigit() isalpha()★该例的实现算法1. getchar()2. WHILE ch 是空格//跳过空格2.1 DO getchar();3. CASE ch OF4. isdigit(ch) :4.1 ch→token; getchar();4.2 WHILE isdigit(ch) DOch→token; getchar();4.3 输入指针回退一个字符;4.4 将token中的字符串变成数值→attr4.5 返回NUM5. isalpha(ch) :5.1 ch→token; getchar();5.2 WHILE isalpha(ch) OR isdigit(ch)DO ch→token; getchar();5.3输入指针回退一个字符;5.4 key = isKeyword(token);5.5 IF key≥0 THEN 返回key5.6 Lookup(token)→attr;5.7 返回IDN6 ':' : getchar();6.1 IF ch等于'=' THEN 返回ASG6.2 出错处理7 '+' : 返回ADD8 '-' : 返回SUB9 '*' : 返回MUL10 '/' : 返回DIV11 '=' : 返回EQ12 '>' : 返回GT13 '<' : 返回LT14 '(' : 返回LP15 ')' : 返回RP16 ';' : 返回SEMI17 其它: 出错处理18 END OF CASE1.4实现的关键技术提示除了前述的双缓冲区设计、识别单词的状态转换图等,符号表的组织与实现也是不容忽视的一项关键技术。
但由于学生初次接触编译系统的设计,往往忽略符号表的设计,即使想到了也无从下手。
有的学生甚至认为标识符表既是符号表的全部——编译的运行环境只需要(也只能有)一张标识符表。
这种理解上的偏差正是由于对符号表的作用(特别是对标识符表的特定用途)理解不够,而多数教科书在这个问题上往往只是给出一些宏观上的引导所至。
下面将分别对符号表的作用与具体实现进行阐述。
1.4.1 符号表的作用为了检查语义的正确性和生成代码,编译程序需要知道用户源程序中所使用的各种标识符的属性,这些属性信息常常由编译程序集中起来并存放于一张标识符表或符号表中。
符号表用于存放程序中出现的有关各种名字的属性信息,以反应名字的语义特征,编译的各阶段均涉及符号表的操作。
符号表的作用主要有以下几个方面:1)收集符号的各种属性。
如名字、类型、定义的层次等。
2)作为语义的合法性检查的依据。
如引用时类型是否一致、层次是否得当等。
3)作为目标代码生成阶段地址分配的依据。
如根据符号表中该变量的特性可为其在适当的存储区域分配大小合适的存储空间。
1.4.2 符号表的建立符号表一般在编译程序的开始阶段(词法分析或语法分析阶段)就建立了,其内容的填写一般在词法分析、语法分析、语义分析阶段陆续填入,而它的使用与管理则贯穿于整个编译程序工作的各个阶段。
1.4.3 符号表的内容符号表的每一项(也称入口)由若干域构成,存放一个符号的所有属性信息。
程序设计语言中的符号一般分为两大部分:固定部分和非固定部分。
(1)固定部分符号表固定部分包括符号的名字域和种属域。
(2)非固定部分符号表的非固定部分包括符号的各种信息域。
不同种属的符号有不同的信息域,如简单变量有类型、地址、存储类别、作用域等信息域,数组名可有类型、内情向量地址等信息域,过程名、函数名可有参数个数、参数表地址、入口地址等信息域。
1.4.4 符号表的组织符号表的组织直接关系到语义功能的实现和语义处理的时空效率。
★符号表的总体组织所谓符号表的总体组织就是构造多少张符号表,以及哪些符号放在同一张表中,一般可选以下三种方式之一:1)将属性完全相同的符号(即同一种属的符号)组织在一起构成一张符号表,从而编译程序将使用多张符号表。