电子科大-计算机专业课程编译原理实验报告_第1页
电子科大-计算机专业课程编译原理实验报告_第2页
电子科大-计算机专业课程编译原理实验报告_第3页
电子科大-计算机专业课程编译原理实验报告_第4页
电子科大-计算机专业课程编译原理实验报告_第5页
已阅读5页,还剩40页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、计算机专业类课程实验报告课程名称:编译原理学院:计算机科学与工程学院专业:计算机科学与技术专业学生姓名:郫县库里学号:2014666666666指导教师:日期: 2017年 5月 14日电 子 科 技 大 学实 验 报 告实验一1、 实验名称:词法分析器的设计与实现2、 实验学时:43、 实验内容和目的:(一)实验内容:1.源语言:求n!的极小语言2.输入输出:源程序*.pas文件作为输入,经过自己编程实现的词法分析器进行处理,生成二元式,保存到*.dyd文件中,如下图所示。(二)实验目的:通过设计词法分析器的实验,使同学们了解和掌握词法分析程序设计的原理及相应的程序设计方法,同时提高编程能力

2、。4、 实验原理:(一) 结合“数据结构”进行分析:1. 二元式文件*.dyd(1) 二元式形式:分析:由输出二元式形式可知,使用printf输出可以很方便达到要求:(2) 每行后加一分析:对输入文件中的换行符“n”,要采取相应的策略:(3) 文件结尾加分析:对于文件末尾的“EOF”,要采取相应的策略:2. 错误信息文件:*.err(1) 错误信息格式分析:设置出错处理的函数,并且需要记录错误行号、错误性质:(2) 注意:进入每一阶段, 首先打开*.err, 如果无错误, 则*.err为空。(二) 词法分析的实现方法利用状态转换分析:根据状态转化图,编写读到不同的内容时的状态转化函数,是设计词

3、法分析器的核心。(三) 对“输入输出”文件的分析文件相关操作因为需要读写文件,并生成错误文件,涉及许多文件相关操作,通过相关函数函数实现功能:5、 实验器材(设备、元器件)(一) 操作系统:Windows 8 Professional (二) 开发工具:Visual Studio 2015(三) 编程语言:C6、 实验步骤:(一) 启动Visual Studio 2015,新建一个项目LxicalAnalyzer(二) 编写LxicalAnalyzer.h文件,声明项目将要用到的自定义函数:(三) 编写LxicalAnalyzer.cpp文件,根据“状态转化图”、“单词符号与种别对照表”实现L

4、xicalAnalyzer.h中声明的函数(详细代码附在实验报告最后);(四) 编写main.cpp文件,完成编码;(五) 根据给出的测试程序,编写输入文件test.pas(六) 运行写好的词法分析器程序,并结合输出文件test.err、test.dyd进行调试;(七) 完成实验。7、 实验数据及结果分析:(一) 输入文件test.pas(二) 执行词法分析器程序(三) 检查输出文件test.err因为输入文件中测试程序没有错误,所以文件为空:(四) 检查输出文件test.dyd检查可知,输出文件内容为符合实验要求的二元式: (五) 修改输入文件,在输入文件中添加错误(六) 再次执行词法分析器

5、程序(七) 重新检查输出文件test.err可见,本词法分析器成功实现检查多处词法错误:8、 实验结论、心得体会和改进建议:(一) 实验结论通过编码与反复调试,成功完成了词法分析器的设计与实现,能够对给出文法的测试程序进行正确的词法分析,按要求输出二元式的*.dyd文件。同时,也可以检测出所给源程序中的多处词法错误。(二) 心得体会1. 对于这种需要多次重复同一操作的实验,将相应的操作写成函数,可以方便编码,减少错误和代码行数。2. 第一次编码忽略了状态转化之后的回退工作,导致bug的出现,以后需要吸取经验教训。3. 尽量在第一次编写程序时,写出较多的提示信息和注释,便于发现bug后的调试。(

6、三) 改进建议上课使用的教材P134页“第六章 词法分析”中的内容对本实验的完成有很大帮助,认真阅读后思路更加清晰。*为便于老师评阅报告,两次实验代码都添加底纹后放在在文档最后部分*电 子 科 技 大 学实 验 报 告实验二1、 实验名称:递归下降分析器的设计与实现2、 实验学时:43、 实验内容和目的:(一)实验内容:根据给定的方法,编写相应的递归下降的语法分析程序,实现对词法分析后的单词序列的语法检查和程序结构的分析,生成相应的变量名表和过程名表,并将编译中语法检查出来的错误写入相应的文件。语法错分类:(1)缺少符号错;(2)符号匹配错;(3)符号无定义或重复定义。(二)实验目的:通过设计

7、递归下降分析器的设计与实现实验,使同学们掌握自上而下的递归分析法的语法分析原理和程序设计方法。4、 实验原理:(一)语法分析的定义和功能语法分析是根据语法规则,将单词符号构成各类语法单位,并进行语法检查。在本实验中,对源程序经过词法分析后转换成的单词流按方法规则进行判断,对能构成正确句子的单词流,给出相应的语法树;对不能构成正确句子的单词流判断其语法错误并做出相应处理。(二)语法分析的方法语法分析方法有自上而下和自下而上的分析方法。(1)自上而下语法分析法:或从开始符号出发,找最左推导;或从根开始,构造推导树。(2)自下而上语法分析法:从输入串开始,归约,直至文法开始符。本实验中,我们采用自上

8、而下的递归下降分析法,在不含左递归的文法G中,如果对每一个非终结符的所有候选式的第一个终结符都是两两不相交的(即无公共左因子),则可能构造出一个不带回溯的自上而下的分析程序,这个分析程序由一组递归过程组成,每个过程对应文法的一个非终结符。这样的分析程序称为递归下降分析程序。(三)数据结构1.*.dys同*.dyd2.变量名表·变量名vname: char(16)·所属过程vproc:char(16)·分类vkind: 0.1(0变量、1形参)·变量类型vtype: types·变量层次vlev: int·变量在变量表中的位置vadr:

9、 int(相对第一个变量而言)3.过程名表·过程名pname: char(16)·过程类型ptype: types·过程层次plev: int·第一个变量在变量表中的位置fadr: int·最后一个变量在变量表中的位置ladr: int4.四元式表 (oprd, op1, op2, result)·oprd整数码·op1第一操作数·op2第二操作数·result结果·op1、op2、result可用“值/地址”表示5.目标代码P码 (四)给定文法产生式实验中给定文法如下:<程序>&l

10、t;分程序><分程序>begin <说明语句表>;<执行语句表> end<说明语句表><说明语句><说明语句表> ;<说明语句><说明语句><变量说明><函数说明><变量说明>integer <变量><变量><标识符><标识符><字母><标识符><字母> <标识符><数字><字母>abcdefghijklmno pq rstuvwxyz&l

11、t;数字>0123456789<函数说明>integer function <标识符>(<参数>);<函数体><参数><变量><函数体>begin <说明语句表>;<执行语句表> end<执行语句表><执行语句><执行语句表>;<执行语句><执行语句><读语句><写语句><赋值语句><条件语句><读语句>read(<变量>)<写语句>wri

12、te(<变量>)<赋值语句><变量>:=<算术表达式><算术表达式><算术表达式>-<项><项><项><项>*<因子><因子><因子><变量><常数><函数调用><常数><无符号整数><无符号整数><数字><无符号整数><数字><条件语句>if<条件表达式>then<执行语句>else <执行

13、语句><条件表达式><算术表达式><关系运算符><算术表达式><关系运算符> <<=>>=<>5、 实验器材(设备、元器件)(一)操作系统:Windows 8 Professional (二)开发工具:Visual Studio 2015(三)编程语言:C6、 实验步骤:(一) 启动Visual Studio 2015,新建一个项目GrammerAnalyzer;(二) 消除文法中的左递归;(三)编写GrammerAnalyzer.h文件,定义将要用到的结构,并声明项目将要用到的自定义函数:(

14、四)编写GrammerAnalyzer.cpp文件,根据“文法产生式”实现LxicalAnalyzer.h中声明的函数和具体的递归下降分析法(详细代码附在实验报告最后);(五)编写main.cpp文件,完成编码;(五)将词法分析器的输出文件test.dyd作为实现的语法分析器的输入文件: (六)运行写好的词法分析器程序,并结合输出文件test.dys、变量名表文件test.var、过程名表文件、错误文件等进行调试;(七)完成实验。7、 实验数据及结果分析:(一)输入文件test.dyd,内容为2元式子 (二)执行词法分析器程序(三)检查输出文件test.dys,与输入文件相同,

15、正确: (四)检查变量名表文件test.var,符合要求:(五)检查过程名表文件,符合要求:(六)检查过程名表文件test.err,基本符合要求:8、 实验结论、心得体会和改进建议:(一)实验结论:本实验程序较好地完成了递归下降分析器的设计与实现,能够对所给文法的程序进行语法分析,生成变量名表和过程名表,如果源程序有语法错误则给出出错类型及所在行数。(二)心得体会:1.标识符中不能包含关键字,以免出错;2.要注意文法中公共左因子的消除;3.思路要清晰,加一些提示信息,避免出现逻辑错误;4.由于对Pascal语言语法细节不是特别熟悉,所以对错误的识别不一定准确,还有改正和提高的空

16、间,期末考试过后有时间,可以做进一步的完善。(三)改进建议:可以改成对C语言等我们经常接触到的语言作为本次实验的源语言,实验做起来可能会更有趣。*以下为实验一源代码,共三个文件*(一) LexicalAnalyzer.h#pragma once#ifndef LEXICALANALYZER_H#define LEXICALANALYZER_Hchar getNextC(); /获取下一个字符bool lexAnalyzer(); /用于词法分析的函数bool isLetter(char ch); /判断ch是否为字母bool isDigit(char ch); /判断ch是否为数字void r

17、etract(char& ch); /回退字符int reserve(char* token); /返回保留字对应种别int symbol(); /返回标识符的对应种别int constant(); /返回常数的对应种别void output_token(const char* token, int kindNum); /按要求格式输出单词符号和种别bool printError(int lineNum, int errNum); /按要求打印错误提醒void getPath(char* in, char* out); /获得路径void getFilename(char* in, c

18、har*out); /获得文件名bool init(int argc, char* argv); /初始化函数#endif / ! LEXICALANALYZER_H(二) LexicalAnalyzer.cpp#include "LexicalAnalyzer.h"#include <string>#define MAX_COUNT 1024#define ILLEGAL_CHAR_ERROR 1#define UNKNOWN_OPERATOR_ERROR 2FILE *file;bool lexAnalyzer() /用于词法分析的函数 if (feof(f

19、ile) return false; static int lineNum = 1; char ch; char token17 = "" ch = getNextC(); switch (ch) case 'r': case 'n': /每行后加一ÈEOLNÈ24 output_token("EOLN", 24); lineNum+; break; case EOF: /结尾加 EOFÈ25 output_token("EOF", 25); return false; c

20、ase '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&#

21、39;: case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case &#

22、39;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': c

23、ase 'Y': case 'Z': while (isLetter(ch)|isDigit(ch) ) char s2 = ch ; strcat(token, s); ch = getchar(); retract(ch); int num; num = reserve(token); if (num != 0) output_token(token, num); else int val; val = symbol(); /标识符 output_token(token, val); break; case '0': case '1&

24、#39;: case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': while (isDigit(ch) char s2 = ch ; strcat(token, s); ch = getchar(); retract(ch); int val; val = constant(); output_token(token, val); break; case '

25、;=': output_token("=", 12); break; case '<': ch = getchar(); if (ch = '>') output_token("<>", 13); else if (ch = '=') output_token("<=", 14); else retract(ch); output_token("<", 15); break; case '>': ch

26、= getchar(); if (ch = '=') output_token(">=", 16); else retract(ch); output_token(">", 17); break; case '-': output_token("-", 18); break; case '*': output_token("*", 19); break; case ':': ch = getchar(); if (ch = '=&#

27、39;) output_token(":=", 20); else printError(lineNum, 2); /输出“未知运算符”错误 break; case '(': output_token("(", 21); break; case ')': output_token(")", 22); break; case '': output_token("", 23); break; default: printError(lineNum, 1); /输出&quo

28、t;出现字母表以外的非法字符"错误 return true;bool isLetter(char ch) /判断ch是否为字母 if (ch >= 'a'&&ch <= 'z') | (ch >= 'A' && ch <= 'Z') return true; else return false;bool isDigit(char ch) /判断ch是否为数字 if (ch >= '0')&& (ch <= '9&#

29、39;) return true; else return false;void retract(char& ch) /回退字符 ungetc(ch, stdin); ch = NULL;int reserve(char* token) /返回保留字对应种别 if (strcmp(token, "begin") = 0) return 1; else if (strcmp(token, "end") = 0) return 2; else if (strcmp(token, "integer") = 0) return 3;

30、else if (strcmp(token, "if") = 0) return 4; else if (strcmp(token, "then") = 0) return 5; else if (strcmp(token, "else") = 0) return 6; else if (strcmp(token, "function") = 0) return 7; else if (strcmp(token, "read") = 0) return 8; else if (strcmp(to

31、ken, "write") = 0) return 9; else return 0;int symbol() /返回标识符对应种别 return 10;int constant() /返回保常数对应种别 return 11;void output_token(const char* token, int kindNum) /按要求输出二元式 printf("%16s %2dn", token, kindNum);bool printError(int lineNum, int errNum) /按要求输出错误 char * errInfo; switc

32、h (errNum) case ILLEGAL_CHAR_ERROR: errInfo = "出现字母表以外的非法字符" break; case UNKNOWN_OPERATOR_ERROR: errInfo = "出现未知运算符(“:”后无“=”)" break; default: errInfo = "未知错误" if (fprintf(stderr, "*LINE:%d %sn", lineNum, errInfo) >= 0) return true; else return false;char g

33、etNextC() /获取下一个字符 char ch; ch = getchar(); while (true) if (ch = 'r' | ch = 't' | ch = ' ') / ch = getchar(); else break; return ch; void getPath(char* in, char* out) /获得路径 char* name; name = strrchr(in, ''); if (name != NULL) strncpy(out, in, strlen(in) - strlen(nam

34、e) + 1); else strcpy(out, "");void getFilename(char* in, char* out) /获得文件名 char* fullName; char* extension; fullName = strrchr(in, ''); extension = strrchr(in, '.'); if (fullName != NULL) strncpy(out, fullName + 1, strlen(fullName) - 1 - strlen(extension); else strncpy(out,

35、 in, strlen(in) - strlen(extension);bool init(int argc, char* argv) /初始化函数 if (0) return false; else char* inFilename = "test.pas" char outFilenameMAX_COUNT = "" char errFilenameMAX_COUNT = "" char filenameMAX_COUNT = "" char pathMAX_COUNT = "" /获得文件

36、名(不包括扩展名)和路径 getFilename(inFilename, filename); getPath(inFilename, path); /生成输出文件全部路径 strcat(outFilename, path); strcat(outFilename, filename); strcat(outFilename, ".dyd"); /生成错误文件全部路径 strcat(errFilename, path); strcat(errFilename, filename); strcat(errFilename, ".err"); if (fil

37、e = freopen(inFilename, "r", stdin)= NULL) printf("文件打开错误"); return false; if (file = freopen(outFilename, "w", stdout) = NULL) printf("缓存区写入错误"); return false; if (file = freopen(errFilename, "w", stderr) = NULL) printf("错误区写入错误"); return

38、false; return true; (三) main.cpp#include "LexicalAnalyzer.h"#include <stdio.h>int main(int argc, char* argv) if (init(argc, argv) while (lexAnalyzer(); fclose(stdin); fclose(stdout); fclose(stderr); return 0;*以下为实验二源代码,共三个文件*(一)GrammerAnalyzer.h#pragma once#ifndef GRAMMERANALYZER_H#d

39、efine GRAMMERANALYZER_Htypedef enum integer types; /types是支持类型的集合typedef struct /记录变量信息的结构体 char vname17; char vproc17; bool vkind; types vtype; int vlev; int vadr; varRecord;typedef struct /记录过程信息的结构体 char pname17; types ptype; int plev; int varNum; int fadr; int ladr; int parameter; bool parameter

40、IsDefined; proRecord;void A(); /A:程序 A->Bvoid B(); /B:分程序 B->begin C;M endvoid C(); /C:说明与句表 C->DC'void C_(); /C_:DC'|void D(); /D:说明语句 D->E|Jvoid E(); /E:变量说明 E->integer Fvoid F(); /F:变量 F->Gvoid G(); /G:标识符 G->HG' G'->HG'|IG'|void J(); /J:函数说明 J->

41、integer function G(K);Lvoid K(); /K:参数 K->Fvoid L(); /L:函数体 L->begin C;M endvoid M(); /M:执行语句表 M->NM'void M_(); /M'->NM'|void N(); /N:执行语句 N->O|P|Q|Wvoid O(); /O:读语句 O->read(F)void P(); /P:写语句 P->write(F)void Q(); /Q:赋值语句 Q->F:=Rvoid R(); /R:算术表达式 R->SR'voi

42、d R_(); /R'->-SR'|void S(); /S:项 S->TS'void S_(); /S'->*TS'|void T(); /T:因子 T->F|U|Zvoid U(); /U:常数 U->Vvoid W(); /W:条件语句 W->if X then N else Nvoid X(); /X:条件表达式 X->RYRvoid Y(); /Y:关系运算符 Y-><|<=|>|>=|=|<>void Z(); /Z:函数调用 Z->G(R)bool i

43、nit(int argc, char* argv);/初始化函数:从输入文件读取数据,建立各个文件,初始化全局变量bool final(); /结束处理函数,将var和pro数组中的元素输出到相应文件,填充输出文件bool error(int lineNum, int errNum, const char* sign); /错误处理函数,参数分别为行号、错误码和错误符号void getPath(char* in, char* out); /获得所处目录路径,包括最后斜杠,或者为空void getFilename(char* in, char* out); /获得文件名,不包括扩展bool ne

44、xtToken(); /获得下一符号,true表示已到队尾,false表示还未到队尾bool nextChar(); /获得当前符号的下一字符,true表示已到'0'bool isVarExisted(char* vname, char* vproc, bool vkind); /判断变量是否已存在bool isProExisted(char* vname); /判断过程是否已存在,参数为过程名int getNextToken(); /获得下一符号,指针不变#endif / !GRAMMERANALYZER_H(二)GrammerAnalyzer.cpp#include &qu

45、ot;GrammerAnalyzer.h"#include <stdio.h>#include <string.h>#include <Windows.h>#define MAX_COUNT 1024#define SIGN_UNDEFINED_ERR 1#define SIGN_REDEFINED_ERR 2#define SIGN_EXECUTE_ERR 3#define NO_SIGN_ERR 4#define SIGN_RESERVE_ERR 5#define NO_PARA_ERR 6char inputMAX_COUNT17;/存放输入

46、文件所有符号的数组int kindMAX_COUNT;int inputCount;/输入符号的数量int pToken;/指向当前输入符号int pChar;/指向当前输入符号中的当前字符varRecord currentVar;/存放当前变量的信息proRecord currentPro;/存放当前过程的信息int lineNum;/当前行号varRecord varMAX_COUNT;/存放变量名表项数组proRecord proMAX_COUNT;/存放过程名表项数组int varCount;/变量的数量int proCount;/过程的数量FILE* inFile;/输入文件句柄FI

47、LE* outFile;/输出文件句柄FILE* errFile;/错误文件句柄FILE* varFile;/变量文件句柄FILE* proFile;/过程文件句柄bool init(int argc, char* argv) if (0) return false; else char* inFilename ="test.dyd"/argv1 char outFilenameMAX_COUNT = "" char errFilenameMAX_COUNT = "" char varFilenameMAX_COUNT = "

48、;" char proFilenameMAX_COUNT = "" char filenameMAX_COUNT = "" char pathMAX_COUNT = "" /获得文件名(不包括扩展名)和路径 getFilename(inFilename, filename); getPath(inFilename, path); /生成输出文件全部路径 strcat(outFilename, path); /strcat(outFilename, ""); strcat(outFilename, file

49、name); strcat(outFilename, ".dys"); /生成错误文件全部路径 strcat(errFilename, path); /strcat(errFilename, ""); strcat(errFilename, filename); strcat(errFilename, ".err"); /生成变量文件全部路径 strcat(varFilename, path); /strcat(varFilename, ""); strcat(varFilename, filename); str

50、cat(varFilename, ".var"); /生成过程文件全部路径 strcat(proFilename, path); /strcat(proFilename, ""); strcat(proFilename, filename); strcat(proFilename, ".pro"); /打开文件句柄 if (inFile = fopen(inFilename, "r") && (outFile = fopen(outFilename, "w") && (errFile = fopen(errFilename, "w") && (varFile = fopen(varFilename, "w") && (proFile = fopen(proFilename, "w") /初始

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论