2018~2019年春季学期《编译原理》课程实验报告实验一词法分析器构造专业班级:学生姓名:学生学号:序号:一、实验目的和要求通过对给定源语言词法分析程序的设计,加深对词法分析原理的理解,掌握源语言的接收、存贮、预处理和扫描分析,生成正确的单词符号串二元式序列。二、实验内容编程实现下述C语言子集的词法分析程序,C语言子集的文法描述如下:语句→赋值语句|条件语句|转移语句|带标号的赋值语句带标号的赋值语句→〈标号〉〈赋值语句〉赋值语句→变量=算术表达式条件语句→IF布尔表达式THEN语句|IF布尔表达式THEN语句ELSE语句转移语句→GOTO标号变量→标识符标识符→字母|标识符数字字母→A|B|…|Z|a|b|…|z数字→0|1|…|9算术表达式→项|算术表达式+项|算术表达式-项项→因子|项*因子|项/因子|因子↑项因子→变量|常数|(表达式)布尔表达式→算术表达式关系符算术表达式关系符→||=|=|=|标号→常数常数→数字|常数数字对语言的几点限制:关键字不允许作为标识符使用。关键字、标识符、常数、标号之间若没有确定的运算符或界符,则必须用空格符隔开。源程序书写按C标准格式。续行最多不得超过5行。三、实验的实现1.主要设计思想大体分为三个步骤:(1)预处理用正则表达式去掉源文件中的注释,将’\’换行内容整理为一行,用split()进行分割,使源文件变成一个一个的表达式。(2)识别对每一个表达式用正则表达式将表达式以符号分割,对分割出的每一项进行类型判断,打印结果并返回该表达式中的所有项的二元式组成的列表(3)保存将之前的二元式列表合并后保存到文件中。2.实现算法及程序流程图3.主要技术问题的处理方法(1)开始时只能用正则表达式匹配单行注释,无法识别/**/之间有换行符的情况。查资料后,在编译表达式模板时,可使用re.DOTALL,如此即可识别换行符。(2)Split()函数认识不清,最初代码中还有一步是将\n换行符替换为空格,然后再用split(),后来发现split()函数可以直接分割空白字符包括换行符,制表符和空格等(3)提取标号时也遇到困难,经研究可以直接用正则表达式\d:的形式识别数字冒号连在一起的形式,直接将标号识别出来了。4.程序代码:实验实现的源程序,要求符合一般的程序书写风格,并包括必要的注释。importre#K:关键字I:标识符C:常数O:运算符P:界符L:标号KEYWORD=['IF','THEN','ELSE','GOTO']开始预处理识别保存结束OP=['+','-','*','/','','','=','=','=','']INTERPUNCTION=[',',':','(',')']#预处理#1.用正则表达式去掉源文件中的注释,#2.将’\’换行内容整理为一行#3.用split()进行分割,生成表达式列表#4.返回分割结果defpre_process(text):cmt_regex=r'(/\*.+?\*/|//.+?\n)'cmt_pattern=re.compile(cmt_regex,re.DOTALL)comments=cmt_pattern.findall(text)forcmtincomments:text=text.replace(cmt,'')text=text.replace('\\\n','')formulas=text.split()returnformulas#处理#将传入的表达式列表元素依次识别,存入二元式列表defprocess(formulas):binarys=[]forformulainformulas:binarys.extend(identify(formula))returnbinarys#识别#将传入的表达式进行识别#1.用正则表达式将表达式以符号分割#2.对分割出的每一项进行类型判断#3.打印结果并返回该表达式中的所有项的二元式组成的列表defidentify(str):splt_regex=r'(=|=||\d+?:|[=:()\+\*-/])'splt_pattern=re.compile(splt_regex)sections=splt_pattern.split(str)binarys=[]print(\n+str)forsectioninsections:binary=''ifnotsection:continueifsectioninKEYWORD:binary='(K,'+section+')\n'print('关键字:(K,%4s)'%section)elifsectioninOP:binary='(O,'+section+')\n'print('运算符:(O,%4s)'%section)elifsectioninINTERPUNCTION:binary='(P,'+section+')\n'print('界符:(P,%4s)'%section)elif':'insection:binary='(L,'+section[:-1]+')\n'binarys.append(binary)print('标号:(L,%4s)'%section[:-1])binary='(P,:)\n'print('界符:(P,%4s)'%':')elifsection.isdigit():binary='(C,'+section+')\n'print('常数:(C,%4s)'%section)else:binary='(I,'+section+')\n'print('标识符:(I,%4s)'%section)binarys.append(binary)returnbinarys#读取文件#返回类型为字符串defread_file(filename):withopen(filename,'r')asf:returnf.read()#保存文件#将传入信息写入文件defsave_file(filename,binarys):withopen(filename,'w')asf:f.writelines(binarys)#主函数defmain():srcFileName='source.txt'distFileName='binarys.txt'text=read_file(srcFileName)formulas=pre_process(text)binarys=process(formulas)save_file(distFileName,binarys)if__name__=='__main__':main()5.实验运行结果及分析源程序:命令行显示:生成二元式文件:经测试,本程序可以将类c语言源程序经过词法分析,化为二元式表四、本次实验总结体会在本次实验中,我通过对给定源语言词法分析程序的设计,加深了对词法分析原理的理解,慢慢掌握了源语言的接收、存贮、预处理和扫描分析等过程,最终能够用程序生成正确的单词符号串二元式序列。用实验的方式,从事实验证的角度,深刻的认识到了编译原理词法分析的重要性,锻炼了自身能力的同时还拓宽了我的视野,十分感谢老师和学校给予我们这次实验的机会。五、对本实验过程及方法、手段的改进建议例程使用C语言编写,实验中编写程序时难度较高,若只是要求学生了解词法分析过程,对程序执行效率基本无要求的话,不如使用Python+正则表达式,轻松加愉快的完成实验。