编译原理词法分析器
编译原理-实验二-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、环境及工具操作系统:windows XP ;使用工具:Microsoft Visual C++ 6.0; 编程语言:C 语言;4、分析程序输入:从文件中读入程序段;程序输出:由单词种别和单词符号的属性值组成的二元式;单词种别通常使用整数编码,编码方式可以有多种,在设计词法分析器之前应确定一种程序处理起来较方便的编码方式。
当一个种别中含有多个单词符号时,在分析出其属于哪个种别的时候应同时给出其单词符号属性,本程序为方便起见,采用单词符号本身来作为其属性,以标识同种别种的不同单词符号。
标识符及关键字的识别:字母开头的字母和数字组成的串是多数编程语言的标识符,所以我们的简易词法分析器中,将标识符定义为这种字母数字串。
当第一个字母为字母且紧接着的字符为数字或字母时,应将其串接在一起为一个单词,直到紧跟着的不在是字母数字时。
由于关键字通常为一个单词,则这样得到的串可能是标识符也可能是关键字,又因为一种语言的关键字通常是有限个,则我们可以构造一个存放所有关键字的表,查询关键字表,可以判断得到的串是否为关键字。
界符和运算符的识别:它们多为当个字符,建立两个分别存放界符合运算符的表,读取字符后,进行查表便可以得出它们的类型。
为方便词法分析器的设计,可以使用状态转换图,根据一种特定的编程语言先设计出其状态转换图才能更好将其用代码实现。
典型状态转换图结构如下:(a)有不含回路含分支的状态节点:对应if …else if …else …语句;(b)有含回路的状态节点:对应while …if …语句。
(b )5、状态转换图6、程序框架描述程序中编写了以下函数,各个函数实现的作用如下:1. GetChar():将下一输入的字符读入到全局变量ch中,搜素指示器前移一个字符的位置。
编译原理词法分析器-ll1-lr0-python实现代码

编译原理词法分析器-ll1-lr0-python实现代码计算机科学与通信工程学院编译原理实验报告题目: 1.词法分析器2. LL(1)分析器3. LR(0)分析器班级:姓名:学号:指导老师:2017年月目录一、实验题目 (1)二、实验目的和要求 (1)三、代码实现 (2)四、总结 (25)一、实验题目1.词法分析器分析一段程序代码,将代码中的单词符号分解出来,并对其进行检查,输出token表和error表2.LL(1)文法分析器分析给定文法。
求出文法的FIRST集,FOLLOW集,并构建分析表,对给定输入串进行分析。
3.LR(0)文法分析器分析给定文法。
用Ꜫ_CLOSURE方法构造文法的LR(0)项目集规范族,根据状态转换函数GO构造出文法的DFA,并转换为分析表,对给定输入串进行分析。
二、实验目的和要求1.学会词法分析器的实现思路。
2.学会求解FIRST集, FOLLOW集,构造LL(1)分析表。
3.学会Ꜫ_CLOSURE方法,状态转换函数GO, 构造LR(0)分析表。
三、代码实现1.词法分析器program.txt 中存放要分析的文法:E->TRR->+TR|-TR|~T->FGG->*FG|/FG|~F->(E)|i代码:KEYWORD_LIST = ['while', 'if', 'else', 'switch', 'case']SEPARATOR_LIST = [';', ':', ',', '(', ')', '[', ']', '{', '}']OPERATOR_LIST1 = ['+', '-', '*']OPERATOR_LIST2 = ['<=', '<', '==', '=', '>', '>=']CATEGORY_DICT = {# KEYWORD"while": {"while": ""},"if": {"if": ""},"else": {"else": ""},"switch": {"switch": ""},"case": {"case": ""},# OPERATOR"+": {"+": ""},"-": {"-": ""},"*": {"*": ""},"<=": {"relop": "LE"},"<": {"relop": "LT"},">=": {"relop": "GE"},">": {"relop": "GT"},"==": {"relop": "EQ"},"=": {"=": ""},# SEPARATOR";": {";": ""},":": {":": ""},",": {",": ""},"(": {"(": ""},")": {")": ""},"[": {"]": ""},"]": {"]": ""},"{": {"{": ""},"}": {"}": ""},}CONSTANTTABLE = []TOKENTABLE = []OPERATORTABLE = []KEYWORDTABLE = []SEPARATORTABLE = []UNDEFINEDTABLE = []# READ FILEdef read_file(path, method):temp_str = ""try:file = open(path, method)for line in file:line = line.replace('\n', " ") temp_str += linetemp_str = str(temp_str)except IOError as e:print(e)exit()finally:file.close()return temp_str.strip() + " "# GETBEdef getbe():global tokengetchar()token = ""return# GETCHARdef getchar():global characterglobal locationwhile all_string[location] == " ":location = location + 1character = all_string[location]return character# LINK TOKENdef concatenation():global tokenglobal charactertoken = token + character# IS NUMBERdef digit():if '0' <= character <= '9':return Truereturn False# IS ALPHABETdef letter():if 'A' <= character <= 'Z' or 'a' <= character <= 'z': return Truereturn False# IS IDENTIFIERdef reserve():if token in KEYWORD_LIST:return CATEGORY_DICT[token]else:return 0# RETRACTdef retract():global locationglobal character# location = location - 1character = ""return# MAIN FUNCTIONdef main():global tokenglobal characters = getchar()getbe()if 'a' <= s <= 'z' or 'A' <= s <= 'Z':while letter() or digit():concatenation()location = location + 1character = all_string[location]retract()c = reserve()if c == 0:TOKENTABLE.append(token)print("这是标识符:{'", token, "':'", TOKENTABLE.index(token), "'}") else:KEYWORDTABLE.append(token)print("这是保留字:", CATEGORY_DICT[token])elif '0' <= s <= '9':while digit():concatenation()location = location + 1character = all_string[location]retract()CONSTANTTABLE.append(token)print("这是常数:{'", token, "':'", CONSTANTTABLE.index(token), "'}") elif s in OPERATOR_LIST1:location = location + 1OPERATORTABLE.append(s)print("这是单操作符:", CATEGORY_DICT[s])elif s in OPERATOR_LIST2:location = location + 1character = all_string[location]if character == '=':OPERATORTABLE.append(s + character)print("这是双操作符:", CATEGORY_DICT[s + character])else:retract()location = location + 1OPERATORTABLE.append(s)print("这是单操作符:", CATEGORY_DICT[s])elif s in SEPARATOR_LIST:location = location + 1SEPARATORTABLE.append(s)print("这是分隔符:", CATEGORY_DICT[s])else:UNDEFINEDTABLE.append(s)print("error:undefined identity :'", s, "'")if __name__ == '__main__':character = ""token = ""all_string = read_file("program.txt", "r")location = 0while location + 1 < len(all_string):main()print('KEYWORDTABLE:', KEYWORDTABLE)print('TOKENTABLE:', TOKENTABLE)print('CONSTANTTABLE:', CONSTANTTABLE)print('OPERATORTABLE:', OPERATORTABLE)print('SEPARATORTABLE:', SEPARATORTABLE)运行结果:2.LL(1)分析器program.txt 中存放要分析的文法:E->TRR->+TR|-TR|~T->FGG->*FG|/FG|~F->(E)|i输入串:i+i*i代码:NonTermSet = set() # 非终结符集合TermSet = set() # 终结符集合First = {} # First集Follow = {} # Follow集GramaDict = {} # 处理过的产生式Code = [] # 读入的产生式AnalysisList = {} # 分析表StartSym = "" # 开始符号EndSym = '#' # 结束符号为“#“Epsilon = "~" # 由于没有epsilon符号用“~”代替# 构造First集def getFirst():global NonTermSet, TermSet, First, Follow, FirstAfor X in NonTermSet:First[X] = set() # 初始化非终结符First集为空for X in TermSet:First[X] = set(X) # 初始化终结符First集为自己Change = Truewhile Change: # 当First集没有更新则算法结束Change = Falsefor X in NonTermSet:for Y in GramaDict[X]:k = 0Continue = Truewhile Continue and k < len(Y):if not First[Y[k]] - set(Epsilon) <= First[X]: # 没有一样的就添加,并且改变标志if Epsilon not in First[Y[k]] and Y[k] in NonTermSet and k > 0: # Y1到Yi候选式都有~存在Continue = Falseelse:First[X] |= First[Y[k]] - set(Epsilon)Change = Trueif Epsilon not in First[Y[k]]:Continue = Falsek += 1if Continue: # X->~或者Y1到Yk均有~产生式First[X] |= set(Epsilon)# FirstA[Y] |= set(Epsilon)# 构造Follow集def getFollow():global NonTermSet, TermSet, First, Follow, StartSymfor A in NonTermSet:Follow[A] = set()Follow[StartSym].add(EndSym) # 将结束符号加入Follow[开始符号]中Change = Truewhile Change: # 当Follow集没有更新算法结束Change = Falsefor X in NonTermSet:for Y in GramaDict[X]:for i in range(len(Y)):if Y[i] in TermSet:continueFlag = Truefor j in range(i + 1, len(Y)): # continueif not First[Y[j]] - set(Epsilon) <= Follow[Y[i]]:Follow[Y[i]] |= First[Y[j]] - set(Epsilon) # 步骤2 FIRST(β)/~ 加入到FOLLOW(B)中。
编译原理词法分析器实验报告

一、实验目的设计一个简单的词法分析器,从而进一步加深对词法分析器工作原理的明白得。
二、实验要求一、该个词法分析器要求至少能够识别以下几类单词:(1)关键字:else if int return void while共6个,所有的关键字都是保留字,而且必需是小写;(2)标识符:识别与C语言词法规定相一致的标识符,通过以下正那么表达式概念:ID = letter (letter | digit)*;(3)常数:NUM = digit digit*(.digit digit* |ε)(e(+ | - |ε) digit digit* |ε),letter = a|..|z|A|..|Z|,digit = 0|..|9,包括整数,如123等;小数,如123.45等;科学计数法表示的常数,如1.23e3,2.3e-9等;(4)专用符号:+ - * / < <= > >= == != = ; , ( ) [ ] { } /* */;二、分析器的输入为由上述几类单词组成的程序,输出为该段程序的机内表示形式,即关键字、运算符、界限符变成其对应的机内符,常数利用二进制形式,标识符利用相应的标识符表指针表示。
3、词法分析器应当能够指出源程序中的词法错误,如不可识别的符号、错误的词法等。
三、实验环境实验环境为win7系统、vs2005。
四、实验内容1、词法分析程序的功能:输入:所给文法的源程序字符串。
输出:二元组(syn,token)或(sum或fsum,对应二进制)组成的序列。
其中:syn为单词类别码;token为寄存的单词自身字符串;sum为整型常数;fsum为浮点型常数。
二、各类单词符号类别码如下表:五、要紧函数说明一、程序全局变量char inputstr[300],token[8];//别离寄存程序段、组成单词符号的字符串char ch;//输入字符int syn;//单词字符的类别码int p;//缓冲区inputstr的指针int sum;//整型常量float fsum;//浮点型常量char *rwtab[6]={"else","if","int","return","void","while"};//关键字数组二、语法分析函数void scaner()该函数完成所有的语法分析,关于输入的程序片段,第一去掉空格和换行,然后逐字符分析,找出各个单词(存入token[8]),判别它们的类型(确信syn 值,若是是整数那么是sum值,若是是浮点数那么是fsum)。
编译原理词法分析器

编译原理词法分析器
编译原理词法分析器是编译器中的一个重要组成部分。
它负责将源代码分解成一个个词素(token)。
在进行词法分析过程中,我们需要定义各种词法规则,例如标识符的命名规则、关键字的集合、运算符的定义以及常量的表示方式等。
词法分析器通常使用有限自动机来实现。
有限自动机是一种能接受或拒绝某个输入序列的计算模型。
在词法分析器中,有限自动机可以方便地根据输入字符的不同状态进行相应的转移,直至得到一个完整的词法单元。
在编写词法分析器时,我们通常会先定义各个词法规则,然后将其转化为正则表达式或有限自动机的形式。
接下来,我们会根据这些规则生成一个词法分析器的状态转换图,并使用该图构建词法分析器的代码。
词法分析器的工作过程如下:输入源代码文本,逐个读取字符并根据当前状态进行状态转移。
如果当前字符能够完成一个词法单元的匹配,那么就将当前词法单元输出,并进入下一个状态。
如果当前字符不能完成一个词法单元的匹配,则继续读取下一个字符,直至完成一个词法单元的匹配或遇到非法字符。
通过词法分析器,我们可以将源代码文本转化为一系列的词法单元,例如关键字、标识符、运算符、常量等。
这些词法单元将作为编译器后续阶段的输入,用于进行语法分析和语义分析。
词法分析器是编译器的重要基础工具之一,它能够帮助我们更好地理解和处理源代码。
编译原理实验——flex语法实现简单词法分析器

flex提供的2个全局变量:
yytext:刚刚匹配到的字符串 yyleng:刚刚匹配到的字符串的长度
代码段如下(注意:规则行务必没有缩进,且对应的动作必须在同一行开始):
%{ #include <stdio.h> #include <string.h>
%}
ALPHA [a-zA-Z] ID {ALPHA}+[a-zA-Z0-9_]* KEY begin|if|then|while|do|end NUM [\-]?[1-9][0-9]*|0
四、实验结果
1. 用管理员身份打开cmd窗口 2. 进入到该代码文本文件所在的文件夹内 3. 然后输入下面两行命令,完成对代码的编译生成。
flex test.l //此后会生成C文件lex.yy.c gcc lex.yy.c //使用gcc编译成可执行文件 4. 我这里生成的是a.exe文件,在窗口中输入a.exe或a回车,运行该文件 即可输入字符串来验证结果。
2.3 词法分析程序的功能: 输入:所给文法的源程序字符串。 输出:二元组(syn,token或num)构成的序列。 其中:syn为单词种别码; token为存放的单词自身字符串; num为整型常数。 例如:对源程序begin x:=9; if x>9 then x:=2*x+1/3; end #的Pascal源文件,经过词法分析后输出如下序列: (1,begin)(10,x)(18,:=)(11,9)(26,;)(2,if)…
printf("(4,%s)",yytext);
else if(yytext[0]=='d')
printf("(5,%s)",yytext);
编译原理 第五章 词法分析

三、LEX编译程序的工作过程:
1.根据每条识别规则Pi {ACTION i}构造相应的非确 定有限自动机NFA,分别画出它们的状态转换图; 2.将所有的状态转换图连接成一个完整的状态转换图; 3.由状态转换图构造状态转换矩阵; 4.将状态转换矩阵确定化; 5.根据DFA,构造词法分析器;
预处理 子程序 扫描器 单词符号
输入 列表 输入缓冲区
扫描缓冲区
词法分析器的结构
三、设置缓冲器的必要性
之所以要设置缓冲器,是因为对于许多源程序而言,有 时词法分析器为了得到某个单词符号的确切性质,只从该符 号本身所含有的字符不能作出判定,还需要超前扫描若干字 符之后,才能作出确切的分析。 例如:有合法的Fortran语句: DO99K=1,10 和 DO99K=1.10 前者是循环语句,后者是赋值语句,两者的区别在于等 号后的第一个界符不同,前者是逗号,后者是句号,因此为 了识别前者中的关键字‘“DO”,必须超前扫描若干字符之 后,才能作出确切的判定。
3、词法分析器和语法分析器作为协同程序 如果两个或两个以上的程序,他们之间交叉执行,这些程序称为协同程 序。词法分析器和语法分析器也可协工作的方式安排在同一遍中,以生产 者和消费者的关系同步运行。
1.词法分析单独作为一遍
S.P.(字符串)
第一 遍 词法分析 单词 串 S.P.(符号串) 第二 遍 语法分析
例如:
%{ int wordCount = 0; int noCount = 0; %} chars [A-za-z] numbers ([0-9])+ words {chars}+ 注意:凡是对已经定义的正则表达式的名字的引用,都必须用花括 号将它们括起来。在LEX源程序中,起标识作用的符号%%,%{以及%}都 必须处在所在行的最左字符位置。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
一、实验目的了解词法分析程序的两种设计方法: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.能对任何S语言源程序进行分析在运行词法分析程序时,应该用问答形式输入要被分析的S源语言程序的文件名,然后对该程序完成词法分析任务。
2.能检查并处理某些词法分析错误词法分析程序能给出的错误信息包括:总的出错个数,每个错误所在的行号,错误的编号及错误信息。
本实验要求处理以下两种错误(编号分别为1,2):1:非法字符:单词表中不存在的字符处理为非法字符,处理方式是删除该字符,给出错误信息,“某某字符非法”。
2:源程序文件结束而注释未结束。
注释格式为:/* …… */三、实验程序设计说明1.实验方案设计包括设计词法分析器模块调用结构图和各模块流程图。
模块结构:1.Initscanner函数:程序初始化:输入并打开源程序文件和目标程序文件,初始化保留字表2.Scanner函数:若文件未结束,反复调用lexscan函数识别单词。
3.Lexscan函数:根据读入的单词的第一个字符确定调用不同的单词识别函数4.Isalpha函数:识别保留字和标识符5.Isnumber函数:识别整数,如有精力,可加入识别实数部分工功能6.Isanotation函数:处理除号/和注释7.Isother函数识别其他特殊字符8.Output函数:输出单词的二元式到目标文件,输出格式(单词助记符,单词内码值),如(int,-)(rlop,>)……9.Error函数:输出错误信息到屏幕10.除此之外,还可以设置查符号表,填写符号表等函数,学生可自行设计。
2.程序源代码#include<stdio.h>#include<string.h>#include<stdlib.h>#define LENGTH 46#define N 100//************************typedef struct token{char name[30];int code;int addr;}token;typedef struct KeyWord{char name[30];int code;}KeyWord;typedef struct symble{char name[30];//字符名字int number;//字符编码int type;}symble;//********************************** char ch;int error_count; //错误出现的个数int var_count; //int num_count; //int label_count;int code_count; //int addr_count; //内码编址int LineOfPro; //错误出现的行号char filename[30];FILE *SourceFin; //源文件FILE *TokenFout; //输出文件FILE *SymbleFout; //符号表FILE *NumFout; //常量表KeyWordkey[14]={{"void",1},{"main",2},{"int",3},{"f loat",4},{"const",5},{"for",6},{"if",7},{"else",8},{"then",9},{"while",10},{" switch",11},{"break",12},{"begin",13},{"end" ,14}};token CurrentToken;token zancun;symble CurrentSimble;symble SymbleList[N];symble NumList[N];//*********************************** void Scanner(); //主程序void IsAlpha(); //关键字void IsNumber(); //数字void IsAnotation(); //注释void IsOther(); //其它void OutPut(); //输出void Error(int a); //错误类型int Flag_WordHave(); //查添符号表int Flag_NumHave(); //查添常量表//************************************ *int main(){int i=0,j=0;code_count=0;var_count=1;label_count=1;addr_count=0;num_count=0;LineOfPro=0; //行号Scanner();printf("输出标识符表:\n");for(i=0;i<var_count-1;i++)printf("<%s,%d>",SymbleList[i].name,i+ 1);printf("\n");printf("输出数字表:\n");for(i=0;i<num_count;i++)printf("<%s,%d>",NumList[i-1].name,i+ 1);return 0;}//*************主程序*************** void Scanner(){int i=0;if((SourceFin=fopen("sun.txt","r"))==NU LL){printf("无法打开文件%s!\n",filename);exit(1);}if((TokenFout=fopen("输出文件.txt","w"))==NULL){printf("无法打开文件输出文件.txt!\n");exit(1);}if((SymbleFout=fopen("符号文件.txt","w"))==NULL){printf("无法打开符号文件.txt!\n");exit(1);}if((NumFout=fopen("常量文件.txt","w"))==NULL){printf("无法打开文件常量.txt!\n");exit(1);}ch=fgetc(SourceFin);while(ch!=EOF){for(i=0;i<30;i++)[i]='\0';//将单词缓冲区初始化if((ch>47)&&(ch<58))IsNumber();if(((ch>='a')&&(ch<='z'))||((ch>='A')&&(ch<='Z'))||(ch=='_')){IsAlpha();}if(ch=='/')IsAnotation();elseIsOther();}fclose(TokenFout);fclose(SymbleFout);fclose(NumFout);printf("词法分析完毕。
\n");}//************数字处理**************** void IsNumber(){int k=0;while(((ch>='0')&&(ch<='9'))){[k++]=ch;//将数字放入单词缓冲区ch=fgetc(SourceFin);}CurrentToken.code=18;//数字的机内码是18OutPut();}//************是否为关键字****************void IsAlpha(){int i,h;h=0;i=0;while(((ch>='a')&&(ch<='z'))||((ch>='A') &&(ch<='Z'))||ch=='_')//将完整的单词放入单词缓冲区{[i++]=ch;ch=fgetc(SourceFin);}zancun=CurrentToken;for(i=0;i<14;i++)//将单词缓冲区中的词和关键字数组中的词比较,看是不是关键字{for(int j=0;j<30;j++){if([j]==key[i].name[j] )h=0;else{h=1;break;}}if(h==0)break;}if(h==0){CurrentToken.code=key[i].code;//将第i个关键字的机内码给单词缓冲区中现有单词的机内码CurrentToken.addr=-1;//关键字地址为-1OutPut();}else{CurrentToken.code=17;CurrentToken.addr=addr_count++;//如果不是关键字就是普通标识符,地址加1OutPut();}}//**************处理注释*****************void IsAnotation(){char ch1;ch1=ch;ch=fgetc(SourceFin);if(ch=='*'){for(;;){ch=fgetc(SourceFin);if(ch==EOF){Error(2);break;}//到最后没有*说明注释不完全,有错误if(ch=='*'){ch1=ch;ch=fgetc(SourceFin);if(ch=='/')//如果最后有*/说明注释完整{ch=fgetc(SourceFin);break;}}}}else{ error_count++;Error(2);[0]='/';//如果注释不完整,将第一个字母看成/CurrentToken.code=22;CurrentToken.addr=-1;//符号的地址是-1OutPut();}}//***************其它************ void IsOther(){char ch1;int i;for(i=0;i<30;i++){ [i]='\0';}//将缓冲区初始化switch(ch){case'+':{ch1=fgetc(SourceFin);if(ch1=='='){[0]='+';[1]='=';CurrentToken.code=38;CurrentToken.addr=-1;OutPut();ch=fgetc(SourceFin);break;}else{[0]='+';CurrentToken.code=19;CurrentToken.addr=-1;OutPut();ch=fgetc(SourceFin);break;}}case'-':{ch1=fgetc(SourceFin);if(ch1=='='){[0]='-';[1]='=';CurrentToken.code=39;CurrentToken.addr=-1;OutPut();ch=fgetc(SourceFin);break;}else{[0]='-';CurrentToken.code=20;CurrentToken.addr=-1;OutPut();ch=fgetc(SourceFin);break;}}case'*':{ch1=fgetc(SourceFin);if(ch1=='='){[0]='*';[1]='=';CurrentToken.code=40;CurrentToken.addr=-1;OutPut();ch=fgetc(SourceFin);break;}else{[0]='*';CurrentToken.code=21;CurrentToken.addr=-1;OutPut();ch=fgetc(SourceFin);break;}}case'%':{if(ch1=='='){[0]='%';[1]='=';CurrentToken.code=41;CurrentToken.addr=-1;OutPut();ch=fgetc(SourceFin);break;}else{[0]='%';CurrentToken.code=23;CurrentToken.addr=-1;OutPut();ch=fgetc(SourceFin);break;}}case'(':{[0]='(';CurrentToken.code=24;CurrentToken.addr=-1;OutPut();ch=fgetc(SourceFin);break;}case')':{[0]=')';CurrentToken.code=25;CurrentToken.addr=-1;OutPut();ch=fgetc(SourceFin);break;}case'[':{[0]='[';CurrentToken.code=26;CurrentToken.addr=-1;OutPut();ch=fgetc(SourceFin);break;}case']':{[0]=']';CurrentToken.code=27;CurrentToken.addr=-1;OutPut();ch=fgetc(SourceFin);break;}case'<':{ch1=fgetc(SourceFin);if(ch1=='='){[0]='<';[1]='=';CurrentToken.code=31;CurrentToken.addr=-1;OutPut();ch=fgetc(SourceFin);break;}else{[0]='<';CurrentToken.code=29;CurrentToken.addr=-1;OutPut();ch=fgetc(SourceFin);break;}}case'>':{ch1=fgetc(SourceFin);if(ch1=='='){[0]='>';[1]='=';CurrentToken.code=32;CurrentToken.addr=-1;OutPut();ch=fgetc(SourceFin);break;}else{[0]='>';CurrentToken.code=30;CurrentToken.addr=-1;OutPut();ch=fgetc(SourceFin);break;}}case'=':{[0]='=';CurrentToken.code=33;CurrentToken.addr=-1;OutPut();ch=fgetc(SourceFin);break;}case'!':{ch1=fgetc(SourceFin);if(ch1=='='){[0]='!';[1]='=';CurrentToken.code=34;CurrentToken.addr=-1;OutPut();ch=fgetc(SourceFin);break;}else{[0]='n';[1]='o';[2]='t';CurrentToken.code=44;CurrentToken.addr=-1;OutPut();ch=fgetc(SourceFin);break;}}case';':{[0]=';';CurrentToken.code=35;CurrentToken.addr=-1;OutPut();ch=fgetc(SourceFin);break;}case'|':{ch1=fgetc(SourceFin);if(ch1=='|'){[0]='O';[1]='R';CurrentToken.code=42;CurrentToken.addr=-1;OutPut();ch=fgetc(SourceFin);break;}}case'&':{ch1=fgetc(SourceFin);if(ch1=='&'){[0]='A';[1]='N';[2]='D';CurrentToken.code=43;CurrentToken.addr=-1;OutPut();ch=fgetc(SourceFin);break;}}case 10: // /n 换行{LineOfPro++;ch=fgetc(SourceFin);break;}case 13: // 回车换行{LineOfPro++;ch=fgetc(SourceFin);break;}case' ': // 空格CurrentToken.code=60;ch=fgetc(SourceFin);break;default:Error(1);ch=fgetc(SourceFin);break;}}//************错误类型************ void Error(int a){error_count++;switch(a){case 1:{printf("error %2d 非法字符%3d 行.\n",error_count,LineOfPro+1);break;}case 2:{printf("error %2d 没有匹配的注释符%3d 行.\n",error_count,LineOfPro+1);break;}}return;}void OutPut(){int i=0;//输出形式if(CurrentToken.code==17) // 标志符输出{CurrentSimble.number=CurrentToken.ad dr;CurrentSimble.type=CurrentToken.code;strcpy(,CurrentToke );Flag_WordHave();fprintf(TokenFout,"<id,%d>",addr_count );printf("<id,%d>",addr_count);}elseif(CurrentToken.code==18)// 数字输出{CurrentSimble.number=CurrentToken.addr;CurrentSimble.type=CurrentToken.code;strcpy(,CurrentToken.na me);Flag_NumHave();fprintf(TokenFout,"<num , %s>",CurrentToke );printf("<num , %d>",num_count);}elseif((CurrentToken.code>=1)&&(CurrentToken. code<=14))//关键字的输出{fprintf(TokenFout,"<%s,_>",zancun.nam e);printf("<%s ,_>",);}else//符号的输出{fprintf(TokenFout,"<%s,_>",CurrentToke );printf("<%s ,_>",);}}//查添符号int Flag_WordHave(){int flag,i=0;//用缓冲符号表中的符号和符号数组中的比较for(i=0;i<(var_count-1);i++){flag=strcmp(,Symbl eList[i].name);if(flag==0){CurrentToken.addr=var_count;//如果存在,将符号数组的地址返回return 0;}}SymbleList[var_count-1].number=Curren tToken.addr;SymbleList[var_count-1].type=CurrentToken. code;strcpy(SymbleList[var_count-1].name,Cu );//不存在写入fprintf(SymbleFout,"<%s ,%3d >",Symbl eList[var_count-1].name,var_count);//符号的输出模式//printf("<%s ,%3d >",SymbleList[var_cou nt-1].name,var_count);var_count=var_count+1;return 1;}//常量int Flag_NumHave(){int flag,i=0;//用缓冲常量表中的常量和常量数组中的比较for(i=0;i<(num_count-1);i++){flag=strcmp(,NumLi st[i].name);if(flag==0){CurrentToken.addr=num_count;//如果存在,将符号数组的地址返回return 0;}}NumList[num_count-1].number=Current Token.addr;NumList[num_count-1].type=CurrentToken.c ode;strcpy(NumList[num_count-1].name,Cur );//不存在写入fprintf(NumFout,"<%s ,%3d >",NumList [num_count-1].name,num_count);//符号的输出模式num_count=num_count+1;return 1;}3.程序的执行结果输入文件,输出结果文件及屏幕信息:输入文件如图1-1屏幕显示结果1-2符号文件1-3常量文件1-4输出文件1-54.实验程序的优点和特色从输入的源程序中,识别出各个具有独立意义的单词,即关键字、其他标识符、整型常数、运算符、界符五大类。