《编译原理》实验报告姓名:余同庆班级:软件1005班学号:3902100509日期:2012-6-7中南大学软件学院2012年06月第一部分词法分析词法分析程序设计与实现一、实验目的加深对词法分析器的工作过程的理解;加强对词法分析方法的掌握;能够采用一种编程语言实现简单的词法分析程序;能够使用自己编写的分析程序对简单的程序段进行词法分析。二、实验内容自定义一种程序设计语言,或者选择已有的一种高级语言,编制它的词法分析程序。词法分析程序的实现可以采用任何一种编程语言和编程工具。从输入的源程序中,识别出各个具有独立意义的单词,即关键字、标识符、常数、运算符、界符。并依次输出各个单词的内部编码及单词符号自身值。(遇到错误时可显示“Error”,然后跳过错误部分继续显示)三、实验要求1.对单词的构词规则有明确的定义;2.编写的分析程序能够正确识别源程序中的单词符号;3.识别出的单词以种别码,值的形式保存在符号表中,正确设计和维护符号表;4.对于源程序中的词法错误,能够做出简单的错误处理,给出简单的错误提示,保证顺利完成整个源程序的词法分析;四、程序设计思路这里以开始定义的C语言子集的源程序作为词法分析程序的输入数据。在词法分析中,自文件头开始扫描源程序字符,一旦发现符合“单词”定义的源程序字符串时,将它翻译成固定长度的单词内部表示,并查、填适当的信息表。经过词法分析后,源程序字符串(源程序的外部表示)被翻译成具有等长信息的单词串(源程序的内部表示),并产生两个表格:常数表和标识符表,它们分别包含了源程序中的所有常数和所有标识符。1.定义部分:定义常量、变量、数据结构。2.初始化:从文件将源程序全部输入到字符缓冲区中。3.取单词前:去掉多余空白。4.取单词:利用实验一的成果读出单词的每一个字符,组成单词,分析类型。5.显示结果。五、实验步骤1.定义目标语言的可用符号表和构词规则;2.依次读入源程序符号,对源程序进行单词切分和识别,直到源程序结束;3.对正确的单词,按照它的种别以种别码,值的形式保存在符号表中;4.对不正确的单词,做出错误处理。六、实验代码Lexer.javapackagelexer;importjava.io.BufferedReader;importjava.io.FileReader;importjava.io.FileWriter;importjava.io.IOException;publicclassLexer{//关键字列表privateString[]keyWords={if,int,for,while,do,return,break,continue};//分隔符列表privatechar[]separators={',',';','{','}','(',')','\'','\'};//运算符列表privatechar[]operators={'=','+','-','*','/','%'};//关系运算符列表privatechar[]relelationOpts={'','','!','='};privateStringfileName;//文件名privateStringBufferbuffer=newStringBuffer();//动态Buffer数组,用于存储从文件中读取的字符串privatestaticintindex=0;privateFileWriterwriter=null;//选择带分析文件publicvoidOpenFile(StringfileName){this.fileName=fileName;}//从文件中读取要分析的C语言程序publicvoidreadFile(){try{//读取文件流BufferedReaderfileReader=newBufferedReader(newFileReader(this.fileName));Stringtemp=null;//定义一个临时字符串,用于暂时存放读取的文件内容while((temp=fileReader.readLine())!=null){buffer.append(temp);//将读取的文件内容追价至动态buffer数组中}}catch(Exceptione){System.out.println(文件操作错误:+e.toString());}}publicvoidwriteFile(StringfileName){try{writer=newFileWriter(fileName);}catch(IOExceptione){System.out.println(文件操作错误:+e.toString());}}publicvoidcloseStream(){try{writer.flush();writer.close();}catch(IOExceptione){e.printStackTrace();}}//判断是否为关键字booleanisKeyWord(Stringch){//依次匹配关键字表for(inti=0;ikeyWords.length;i++){if(keyWords[i].equals(ch)){returntrue;}}returnfalse;}//判断是否为数字booleanisDigit(charch){if(ch=48&&ch=57)returntrue;elsereturnfalse;}//判断是否为字母booleanisLetter(charch){//分别对应大写字母,小写字母,下划线if((ch=65&&ch=90)||(ch=97&&ch=122)||(ch==95))returntrue;elsereturnfalse;}//判断是否为标识符或关键字booleanisToken(charch){if(isLetter(ch)){StringBuffertemp=newStringBuffer();temp.append(ch);ch=buffer.charAt(++index);while(isLetter(ch)||isDigit(ch)){temp.append(ch);ch=buffer.charAt(++index);}if(isKeyWord(temp.toString())){translate(1,temp.toString());returntrue;}else{translate(2,temp.toString());returntrue;}}elsereturnfalse;}//判断是否是分隔符booleanisSeparator(charch){//依次匹配关键字表for(inti=0;iseparators.length;i++){if(separators[i]==ch){translate(5,String.valueOf(ch));index++;returntrue;}}returnfalse;}//判断是否是常数booleanisConstant(charch){if(isDigit(ch)){StringBuffertemp=newStringBuffer();while(isDigit(ch)){temp.append(ch);ch=buffer.charAt(++index);}translate(3,temp.toString());returntrue;}returnfalse;}//判断是否是运算符booleanisOperator(charch){//依次匹配运算符表for(inti=0;ioperators.length;i++){if(operators[i]==ch){translate(4,String.valueOf(ch));index++;returntrue;}}//依次匹配关系运算符表for(inti=0;irelelationOpts.length;i++){if(relelationOpts[i]==ch){translate(4,String.valueOf(ch));index++;returntrue;}}returnfalse;}//输出格式voidtranslate(intnum,Stringch){try{//输出到文件writer.write((+num+,\+ch+\));writer.write(\r\n);//换行writer.flush();}catch(IOExceptione){e.printStackTrace();}System.out.println((+num+,\+ch+\));}//词法分析过程publicvoidanalyze(){charch;while(indexbuffer.length()){ch=buffer.charAt(index);//利用短路运算if(isToken(ch)||isSeparator(ch)||isConstant(ch)||isOperator(ch)){}else{index++;//字符指针前移}}}}TestLexer.javapackagetestCompiler;importlexer.Lexer;publicclassTestLexer{publicstaticvoidmain(String[]args){Lexerlexer=newLexer();lexer.OpenFile(F:/test.txt);lexer.writeFile(F:/words.txt);lexer.readFile();lexer.analyze();lexer.closeStream();}}七、实验结果对于这一段程序:其运行结果如图所示:第二部分语法分析预测分析法设计与实现一、实验目的加深对语法分析器工作过程的理解;加强对预测分析法实现语法分析程序的掌握;能够采用一种编程语言实现简单的语法分析程序;能够使用自己编写的分析程序对简单的程序段进行语法翻译。二、实验内容在实验1的基础上,用预测分析法编制语法分析程序,语法分析程序的实现可以采用任何一种编程语言和工具。三、实验要求1.对语法规则有明确的定义;2.编写的分析程序能够对实验一的结果进行正确的语法分析;3.对于遇到的语法错误,能够做出简单的错误处理,给出简单的错误提示,保证顺利完成语法分析过程;4.实验报告要求用文法的形式对语法定义做出详细说明,说明语法分析程序的工作过程,说明错误处理的实现。四、程序设计思路所谓LL(1)分析法,就是指从左到右扫描输入串(源程序),同时采用最左推导,且对每次直接推导只需向前看一个输入符号,便可确定当前所应当选择的规则。实现LL(1)分析的程序又称为LL(1)分析程序或LL(1)分析器。我们知道一个文法要能进行LL(1)分析,那么这个文法应该满足:无二义性,无左递归,无左公因子。当文法满足条件后,再分别构造文法每个非终结符的FIRST和FOLLOW集合,然后根据FIRST和FOLLOW集合构造LL(1)分析表,最后利用分析表,根据LL(1)语法分析构造一个分析器。LL(1)的语法分析程序包含了三个部分,总控程序,预测分析表函数,先进先出的语法分析栈,本程序也是采用了同样的方法进行语法分析,该程序是采用了C++语言来编写,其逻辑结构图如下:LL(1)预测分析程序的总控程序在任何时候都是按STACK栈顶符号X和当前的输入符号a做哪种过程的。对于任何(X,a),总控程序每次都执行下述三种可能的动作之一:(1)若X=a=‘#’,则宣布分析成功,停止分析过程。(2)若X=a‘#’,则把X从STACK栈顶弹出,让a指向下一个输入符号。(3)若X是一个非终结符,则查看预测分析表M。若M[A,a]中存放着关于X的一个产生式,那么,首先把X弹出STACK栈顶,然后,把产生式的右部符号串按反序一一弹出STACK栈(若右部符号为ε,则不推什么东西进STACK栈)。若M[A,a]中存放着“出错标志”,则调用出错诊断程序ERR