编译原理实践(实现减除语句)
编译原理实验报告总结
编译原理实验报告总结一、实验目的编译原理是计算机科学中的一门重要课程,通过实验可以更深入地理解编译过程的各个阶段,包括词法分析、语法分析、语义分析、中间代码生成、代码优化和目标代码生成等。
本次编译原理实验的目的主要有以下几点:1、加深对编译原理理论知识的理解和掌握,将抽象的概念通过实际操作转化为具体的实现。
2、培养实际动手能力和解决问题的能力,通过编写代码实现编译程序的各个模块,提高编程技能和调试能力。
3、熟悉编译程序的开发流程和工具,掌握相关编程语言和开发环境的使用。
4、培养团队合作精神和沟通能力,在实验过程中与小组成员共同探讨、解决问题,提高协作效率。
二、实验环境本次实验使用的编程语言为 C/C++,开发环境为 Visual Studio 2019。
同时,使用了一些辅助工具,如调试工具、代码管理工具等,以提高开发效率和代码质量。
三、实验内容1、词法分析任务:使用正则表达式或有限自动机实现对输入源程序的词法分析,将源程序分解为一个个单词,并识别出单词的类型,如标识符、关键字、常量、运算符等。
实现方法:采用有限自动机的方法,设计状态转移图,根据输入字符的类型进行状态转移,最终确定单词的类型。
遇到的问题及解决方法:在处理一些边界情况时,如字符串中的转义字符,出现了识别错误。
通过仔细分析正则表达式和有限自动机的规则,对代码进行了相应的修改和完善,解决了问题。
2、语法分析任务:使用自顶向下或自底向上的语法分析方法,对词法分析得到的单词序列进行语法分析,构建语法树。
实现方法:选择了自顶向下的递归下降分析法,根据语法规则编写递归函数,逐个处理单词,构建语法树。
遇到的问题及解决方法:在处理复杂的语法结构时,出现了回溯和左递归的问题,导致分析效率低下。
通过消除左递归和提取公共因子,优化了语法分析算法,提高了分析效率。
3、语义分析任务:在语法分析的基础上,进行语义分析,检查语法正确的程序是否在语义上也是正确的,如类型匹配、变量未定义等。
编译原理实训课程学习总结
编译原理实训课程学习总结在编译原理实训课程学习的一段时间里,我深入学习了编译器的基本原理和相关技术,通过实际动手实践编写了一个简单的编译器。
本文将对我的学习经验和收获进行总结,并分享一些编译原理实践的心得体会。
一、学习背景和目标编译原理是计算机科学中的重要基础课程之一,其主要目标是教授学生编译器设计和实现的基本概念、技术和方法。
在这门实训课程中,我希望能够深入理解编译器的运行原理,掌握实际编译器的设计和实现方法,提升自己的编程能力和软件开发水平。
二、课程内容和学习体会1. 课程内容本实训课程主要包括编译器的前端和后端两个模块。
在前端模块中,我学习了词法分析和语法分析的基本理论和技术,掌握了正则表达式、文法和BNF范式等相关知识;在后端模块中,我学习了中间代码的生成与优化、代码生成等内容,并通过实践掌握了中间代码的表示方法和相关算法。
2. 学习体会通过这门课程的学习,我深刻认识到编译器是如何将源代码转化为可执行代码的重要工具。
我学到了很多编译器的内部工作原理,比如词法分析器如何将字符序列转化为单词流、语法分析器如何构建抽象语法树等等。
这些知识让我对编程语言的语法和结构有了更深入的理解。
在实践环节中,我通过使用工具和编写代码实现了一个简单的编译器。
这个过程既考验了我的编程技巧,也检验了我对编译原理的理解程度。
我遇到了许多实际问题,比如处理语法错误、优化中间代码等,但通过不断查找资料和与同学交流,最终解决了这些问题并顺利完成了项目。
三、学习收获和成长通过编译原理实训课程的学习,我收获了诸多知识和技能:1. 深入理解编译器的工作原理和内部机制,包括词法分析、语法分析、中间代码生成和代码优化等。
2. 掌握了常见编译原理算法和数据结构,如正则表达式、LL(1)文法、LR分析器等。
3. 提升了自己的编程能力和代码调试能力,学会了使用编译器相关工具和库进行开发和调试。
4. 锻炼了团队协作和沟通能力,在与同学的合作中互相学习和帮助,共同解决问题。
中北编译原理实验报告
一、实验目的1. 理解编译原理的基本概念,掌握编译程序的设计方法和流程。
2. 掌握编译过程中的词法分析、语法分析、语义分析、中间代码生成、代码优化和目标代码生成等基本步骤。
3. 提高实际编程能力,培养严谨的编程思维。
二、实验环境1. 操作系统:Windows 102. 编译器:Visual Studio 20193. 编译原理实验平台:C++语言编写三、实验内容1. 词法分析器设计(1)词法分析器原理:词法分析器是编译程序中的第一个阶段,其作用是将源程序中的字符序列转换为一系列的单词符号。
本实验采用正则表达式来定义单词符号,并使用有限自动机实现词法分析。
(2)实验步骤:a. 定义单词符号:根据实验要求,设计正则表达式来定义单词符号。
b. 构建有限自动机:根据正则表达式,构建有限自动机的状态转移图。
c. 实现词法分析器:编写C++代码实现词法分析器,包括有限自动机的构建和状态转移过程。
2. 语法分析器设计(1)语法分析器原理:语法分析器是编译程序中的第二个阶段,其作用是检查源程序中的语法结构是否正确。
本实验采用递归下降分析法实现语法分析。
(2)实验步骤:a. 定义语法规则:根据实验要求,设计语法规则。
b. 构建语法分析树:根据语法规则,构建语法分析树。
c. 实现语法分析器:编写C++代码实现语法分析器,包括递归下降分析法和语法分析树的构建。
3. 语义分析器设计(1)语义分析器原理:语义分析器是编译程序中的第三个阶段,其作用是检查源程序中的语义是否正确。
本实验采用符号表来实现语义分析。
(2)实验步骤:a. 设计符号表:根据实验要求,设计符号表结构。
b. 实现语义分析器:编写C++代码实现语义分析器,包括符号表的构建和语义检查过程。
4. 中间代码生成(1)中间代码生成原理:中间代码生成是编译程序中的第四个阶段,其作用是将源程序转换为中间代码。
本实验采用三地址码作为中间代码。
(2)实验步骤:a. 设计三地址码:根据实验要求,设计三地址码格式。
编译原理实验报告
编译原理实验报告一、实验目的编译原理是计算机科学中的重要学科,它涉及到将高级编程语言转换为计算机能够理解和执行的机器语言。
本次实验的目的是通过实际操作和编程实践,深入理解编译原理中的词法分析、语法分析、语义分析以及中间代码生成等关键环节,提高我们对编译过程的认识和编程能力。
二、实验环境本次实验使用的编程语言为C++,开发环境为Visual Studio 2019。
此外,还使用了一些相关的编译工具和调试工具,如 GDB 等。
三、实验内容(一)词法分析器的实现词法分析是编译过程的第一步,其任务是将输入的源程序分解为一个个单词符号。
在本次实验中,我们使用有限自动机的理论来设计和实现词法分析器。
首先,定义了各种单词符号的类别,如标识符、关键字、常量、运算符等。
然后,根据这些类别设计了相应的状态转换图,并将其转换为代码实现。
在实现过程中,使用了正则表达式来匹配输入字符串中的单词符号。
对于标识符和常量等需要进一步处理的单词符号,使用了相应的规则进行解析和转换。
(二)语法分析器的实现语法分析是编译过程的核心环节之一,其任务是根据给定的语法规则,分析输入的单词符号序列是否符合语法结构。
在本次实验中,我们使用了递归下降的语法分析方法。
首先,根据实验要求定义了语法规则,并将其转换为相应的递归函数。
在递归函数中,通过对输入单词符号的判断和处理,逐步分析语法结构。
为了处理语法错误,在分析过程中添加了错误检测和处理机制。
当遇到不符合语法规则的输入时,能够输出相应的错误信息,并尝试进行恢复。
(三)语义分析及中间代码生成语义分析的目的是对语法分析得到的语法树进行语义检查和语义处理,生成中间代码。
在本次实验中,我们使用了三地址码作为中间代码的表示形式。
在语义分析过程中,对变量的定义和使用、表达式的计算、控制流语句等进行了语义检查和处理。
对于符合语义规则的语法结构,生成相应的三地址码指令。
四、实验步骤(一)词法分析器的实现步骤1、定义单词符号的类别和对应的正则表达式。
编译原理实习报告
编译原理实习报告一、实习目的和意义编译原理是计算机科学的核心分支之一,涉及到将一种编程语言转换成另一种编程语言的过程。
通过本次实习,我希望能够深入理解编译原理的基本概念、方法和实现技术,提高自己的编程能力和软件设计能力。
二、实习内容和步骤1. 阅读实习指导书和相关的理论知识,了解编译程序的基本思想和构造方法。
2. 选择一个自己熟悉的程序设计语言,例如C语言,作为编译对象。
3. 设计并实现一个C语言子集的编译程序,包括词法分析、语法分析和语义分析等功能。
4. 对编译程序进行测试和调试,修复可能存在的问题和错误。
5. 撰写实习报告,总结实习过程中的经验和教训。
三、实习过程和成果在实习过程中,我首先阅读了相关的理论知识和实习指导书,对编译原理的基本概念和实现方法有了更深入的理解。
然后,我选择了C语言作为编译对象,并设计了一个C语言子集的编译程序。
在实现编译程序的过程中,我首先编写了词法分析器,用于识别源代码中的单词和符号。
然后,我编写了语法分析器,用于分析源代码的语法结构。
最后,我编写了语义分析器,用于检查源代码中的语义错误。
在完成编译程序的实现后,我对程序进行了测试和调试,发现并修复了一些可能的问题和错误。
通过测试,我发现我的编译程序能够正确地编译和生成目标代码。
最后,我撰写了实习报告,总结了实习过程中的经验和教训。
我意识到编译原理不仅是理论知识的掌握,还需要通过实践来加深理解和提高能力。
同时,我也学会了如何设计和实现一个简单的编译程序,提高了自己的编程能力和软件设计能力。
四、实习收获和展望通过本次实习,我对编译原理的基本概念和实现方法有了更深入的理解,提高了自己的编程能力和软件设计能力。
我学会了如何设计和实现一个简单的编译程序,并能够将其应用于实际的编程实践中。
在未来的学习和工作中,我将继续深入学习和研究编译原理相关的知识和技术,提高自己的专业水平和竞争力。
同时,我也希望能够将编译原理的应用扩展到更多的编程语言和领域中,为自己的职业发展打下更坚实的基础。
编译原理实验报告
编译原理实验报告一、引言编译原理是计算机科学中的重要课程,它研究了将高级语言翻译为机器语言的方法和技术。
编译器作为实现这一目标的关键工具,扮演着至关重要的角色。
本实验报告将介绍编译原理实验的相关内容,包括实验目的、实验环境、实验步骤和实验结果等。
二、实验目的编译原理实验的主要目的是通过设计和实现一个简单的编译器,来加深对编译原理相关概念和技术的理解。
具体目标包括: 1. 理解词法分析、语法分析、语义分析等编译器的基本原理和流程; 2. 掌握使用Lex和Yacc工具进行词法分析和语法分析的方法; 3. 学会使用C/C++等编程语言实现编译器的基本功能。
三、实验环境本实验使用的实验环境包括: 1. 操作系统:Windows 10; 2. 开发工具:Visual Studio Code; 3. 编程语言:C/C++; 4. 辅助工具:Lex、Yacc。
四、实验步骤本实验的主要步骤如下:4.1 设计语言文法在开始实验之前,我们首先需要设计我们要实现的编程语言的文法。
文法是描述编程语言语法结构的形式化规则,它指定了合法的语法结构和语句构造方法。
我们可以使用BNF(巴科斯范式)或EBNF(扩展巴科斯范式)来表示文法。
4.2 实现词法分析器词法分析器的主要任务是将输入的字符流转换为一个个的词法单元(token)。
词法单元是编程语言中的最小语法单位,例如关键字、标识符、常量等。
我们可以使用Lex工具来实现词法分析器,它可以根据我们定义的正则表达式规则来生成词法分析器的代码。
4.3 实现语法分析器语法分析器的主要任务是根据语言文法,将词法单元序列转换为语法树。
语法树是描述程序语法结构的一种树状数据结构,它可以帮助我们理解和处理程序的语义。
我们可以使用Yacc工具来实现语法分析器,它可以根据我们定义的文法规则来生成语法分析器的代码。
4.4 实现语义分析器语义分析器的主要任务是对语法树进行遍历和分析,检查程序中的语义错误并生成中间代码。
北大2022编译原理实践(CC++)
北⼤2022编译原理实践(CC++)这是今年新推出的实践⽅案,由往年的sysy->IR1->IR2->RISC V变成了sysy->Koopa->RISC V,通过增量的⽅式让整个实践过程更容易上⼿所以先在这⾥简要记录⼀下整个实践过程那么环境安装的部分我们就先略过,直接开始正题lv0:⾸先我们要注意的是我们要使⽤的是你⾃⼰的路径,⽐如我的电脑在输⼊指令docker run compiler-dev ls -l /时会报错,原因就是路径不对,实际上应当⽤的是docker run maxxing/compiler-dev ls -l /接下来所有的路径都要注意这点。
tips:这些指令是很长的,⽽且我们也没有必要把他们背下来,可如果每次去找⼜要花费不少时间,建议⾃⼰开⼀个.txt之类的⽂件存储常⽤的指令那么我们就可以快乐地进⼊lv1lv1:进⼊lv1之后我们要处理的是最简单的int main(){//可能有这样的注释,但是模板⾥已经帮你处理过了/*你需要⾃⼰处理这样的注释仔细思考怎么处理,提⽰:.不能匹配换⾏符*/return0;}我们观察下发的模板,发现我们实际上需要四个⽂件:sysy.l和sysy.y(⽤来进⾏词法分析、语法分析之类的),main.cpp(你的编译器从这⾥运⾏),以及你⾃⼰建⽴的AST.h(⽤来定义⼀些AST)所谓AST,我们可以直观理解成语法结构,我们只需每次按照该部分的EBNF定义即可,⽐如⽂档中(lv1.3)提供了例⼦,这⾥就不赘述了在lv1中,我们其实应当注意的问题是不要⾃⼰乱动东西,这是后⾯所有增量操作的基础——除了你新增加的功能以及为了实现新功能前⾯确实需要修改的内容外,你不应当改动前⾯你(或模板)已经正确实现的任何内容举例:当我们在做解析的时候,原版(lv1.2提供,正确)可能是长成这个样⼦的:Stmt: RETURN Number ';' {auto number = unique_ptr<string>($2);$$ = new string("return " + *number + ";");};你需要修改他的功能,于是你类⽐这段代码(lv1.3提供,正确)FuncDef: FuncType IDENT '('')' Block {auto ast = new FuncDefAST();ast->func_type = unique_ptr<BaseAST>($1);ast->ident = *unique_ptr<string>($2);ast->block = unique_ptr<BaseAST>($5);$$ = ast;};写出了这种东西Stmt: "return" Number ';'{auto ast=new Stmt();ast->num= $2;$$=ast;};然后你觉得这很正确,因为EBNF就是这么说的呀?CompUnit ::= FuncDef;FuncDef ::= FuncType IDENT "("")" Block;FuncType ::= "int";Block ::= "{" Stmt "}";Stmt ::= "return" Number ";";Number ::= INT_CONST;但是请注意!这样的字符串关键字是需要在.l⽂件⾥⾯进⾏声明的!如果你查看.l⽂件,会看到这样的内容:"int" { return INT; }"return" { return RETURN; }也就是说我们实际应该匹配的是RETURN,⽽不是"return"这⼀点当你做到lv3或者lv4的时候会再次遇到,⽐如你想匹配⼀个const关键字,那么你应当先在.l⽂件⾥加上⼀⾏"const" { return CONST; }然后就可以在.y⽂件⾥写类似这样的东西了ConstDecl: CONST INT MulConstDef ';'{auto ast=new ConstDecl();ast->const_decl=unique_ptr<BaseAST>($3);$$=ast;} ;但是在⼀开始,显然你并没有对这些事情有充分的理解(本博客讲解的是⼀个⼩菜鸡做lab的⼼路历程,不建议巨佬⾷⽤),因此最好的⽅法就是不要动,反正我return的这个内容没有变,那我为什么要把他帮你写好的RETURN改成"return"呢?那么你⼀阵瞎写,终于完成了这个.y⽂件,接下来我们按照编译⽂档上的指⽰,先make再build/compiler -koopa hello.c -o hello.koopa如果没有什么提⽰,那么我们就可以认为我们的解析过程是正确的了!当然,如果有提⽰,⼀般来讲提⽰信息⼤概长这样:compiler: /root/compiler/template/src/my.cpp:264: int main(int, const char **): Assertion `!ret' failed.Aborted这是啥?观察我们的.y⽂件,我们不难发现我们还定义了⼀个报错函数void yyerror(std::unique_ptr<BaseAST> &ast, const char *s) {cerr << "error: " << s << endl;}那么如果出现错误,我们可以⽤这个报错函数帮我们获取错误信息,我们把报错函数修改成这样:void yyerror(std::unique_ptr<BaseAST> &ast, const char *s) {extern int yylineno; // defined and maintained in lexextern char *yytext; // defined and maintained in lexint len=strlen(yytext);int i;char buf[512]={0};for (i=0;i<len;++i){sprintf(buf,"%s%d ",buf,yytext[i]);}fprintf(stderr, "ERROR: %s at symbol '%s' on line %d\n", s, buf, yylineno);}那么你看到的报错信息就会变成:ERROR: syntax error at symbol '33 ' on line 1compiler: /root/compiler/template/src/my.cpp:264: int main(int, const char **): Assertion `!ret' failed.Aborted好极了!第⼀⾏告诉我们在⼀⾏中出现了语法错误(syntax error),原因是它不能识别ascii码为33的字符!那么这个错误有两个可能的原因,⼀个是我们的测试程序本⾝就有语法错误(这⾥所谓的语法错误,是指按我们当前体系设计不能识别的内容),⽐如如果我们把hello.c写成这个样⼦:int main(){return !0;}按我们的认知来说这其实没错,但别忘了我们还在lv1,我们只能处理return 0,所以这样的语句就会产⽣上⾯的报错信息(!的ascii码为33)另⼀种可能(也是可能性⽐较⼤的情况)就是我们的.y写错了,本应识别的东西没有识别,⽐如如果你把这个程序喂给了你在lv3中写的编译器,它还给你报上⾯的错,就说明你的.l,.y⽂件哪⾥写的出问题了好,你通过不断地修改,终于让你的编译器能正确识别了(可喜可贺)但可惜我们的编译过程还没有进⾏到⼀半因为我们的编译过程应当是sysy->Koopa->RISC V,可是我们现在连Koopa都没有,我们只是得到了⼀堆数据结构。
编译原理的应用实例
编译原理的应用实例1. 概述编译原理是计算机科学与技术中的重要分支,它研究如何将高级语言程序转化为机器语言执行。
在实际应用中,编译原理可以用于许多领域,包括编程语言设计、编译器开发、优化技术等。
本文将介绍编译原理在实际应用中的几个示例。
2. 编译器开发编译器是将高级语言程序转化为机器语言的重要工具。
在编译器开发中,编译原理扮演了核心的角色。
下面是编译器开发中编译原理的应用实例:•词法分析:编译器首先需要将源代码分割成一个个标记,这个过程叫做词法分析。
词法分析器根据语法规则将字符序列分割成有意义的标记,例如,将for关键字识别为一个标记,将变量名识别为一个标记等。
•语法分析:语法分析是将词法分析器生成的标记序列转化为抽象语法树(AST)的过程。
语法分析器根据语法规则检查标记序列的合法性,并生成对应的语法结构。
例如,将for循环的语法结构表示为AST中的一个节点。
•语义分析:语义分析器对AST进行语义检查,确保源代码的合理性。
它检查变量的声明和作用域、类型匹配等问题,以及进行常量折叠和局部优化等。
•中间代码生成:编译器生成中间代码作为后续优化和目标代码生成的基础。
中间代码包含了高级语言程序的抽象表示,通常是一种中间形式的代码,例如三地址码、虚拟机代码等。
3. 编程语言设计编译原理对于编程语言的设计非常重要。
下面是编程语言设计中编译原理的应用实例:•语法设计:编译原理可以帮助设计合理的编程语言语法规则。
语法规则定义了编程语言的语法结构,例如语句、表达式、函数定义等。
编译原理的知识可以帮助设计易读易写、符合人类思维习惯的语法规则。
•语义设计:编译原理可以帮助设计编程语言的语义规则,即程序的含义和行为。
语义规则定义了变量的作用域、类型系统、函数调用机制等。
编译原理的知识可以帮助设计清晰、严谨的语义规则,提高编程语言的可靠性。
•编译器前端设计:编译器前端负责将源代码转化为中间表示,它包括词法分析、语法分析和语义分析等阶段。
编译原理实习报告
一、实习背景与目的随着计算机技术的飞速发展,编译原理作为计算机科学的重要基础理论之一,其研究与应用越来越受到重视。
为了更好地理解和掌握编译原理的基本原理和方法,提高自己的编程能力和设计能力,我参加了编译原理的实习课程。
本次实习旨在通过设计和实现一个简单的编译程序,加深对编译原理的理解,掌握编译程序的设计与实现方法,提高自己的编程能力,并培养自己的计算思维。
二、实习内容本次实习主要分为以下几个部分:1. 词法分析:识别源程序中的单词,将其转换为对应的词法单元。
2. 语法分析:根据文法规则,分析源程序的语法结构,生成抽象语法树(AST)。
3. 语义分析:检查AST的语义正确性,进行类型检查等。
4. 中间代码生成:将AST转换为中间代码。
5. 代码优化:对中间代码进行优化,提高程序性能。
6. 目标代码生成:将优化后的中间代码转换为特定平台的目标代码。
三、实习过程1. 词法分析:- 首先,分析源程序的文法规则,确定需要识别的单词种类和对应的正则表达式。
- 然后,设计状态转换图,实现词法分析器。
- 最后,编写测试用例,验证词法分析器的正确性。
2. 语法分析:- 分析文法规则,确定语法结构,设计抽象语法树(AST)。
- 选择合适的语法分析方法,如递归下降分析、LL分析、LR分析等。
- 实现语法分析器,将词法分析器生成的词法单元转换为AST。
3. 语义分析:- 根据AST,检查语义正确性,如类型检查、作用域分析等。
- 实现语义分析器,处理语义错误,并给出错误信息。
4. 中间代码生成:- 根据AST,生成中间代码,如三地址代码、四元式等。
- 实现中间代码生成器,将AST转换为中间代码。
5. 代码优化:- 分析中间代码,找出可优化的部分。
- 实现代码优化器,优化中间代码,提高程序性能。
6. 目标代码生成:- 根据目标平台的指令集,生成目标代码。
- 实现目标代码生成器,将优化后的中间代码转换为目标代码。
四、实习成果通过本次实习,我成功地设计和实现了一个简单的编译程序,实现了词法分析、语法分析、语义分析、中间代码生成、代码优化和目标代码生成等功能。
编译原理的实验报告
一、实验目的1. 理解编译原理的基本概念和原理。
2. 掌握编译器的各个阶段及其实现方法。
3. 能够运用编译原理的知识解决实际问题。
二、实验环境1. 操作系统:Windows 102. 编程语言:C++3. 开发工具:Visual Studio 20194. 实验内容:词法分析、语法分析、语义分析、中间代码生成、代码优化、目标代码生成三、实验内容1. 词法分析(1)实验目的:实现一个简单的词法分析器,将源代码中的字符序列转换为词法符号序列。
(2)实验步骤:1)定义词法符号类型,包括标识符、关键字、运算符、常量等。
2)设计词法分析器算法,对源代码进行遍历,将字符序列转换为词法符号序列。
3)实现词法分析器程序,输出词法符号序列。
(3)实验结果:输入源代码:int a = 10;输出词法符号序列:{<int, int>, <a, a>, <=, =>, <10, 10>, <;, ;>}2. 语法分析(1)实验目的:实现一个简单的语法分析器,将词法符号序列转换为抽象语法树(AST)。
(2)实验步骤:1)定义语法规则,包括产生式、非终结符、终结符等。
2)设计语法分析算法,根据语法规则对词法符号序列进行解析,生成AST。
3)实现语法分析器程序,输出AST。
(3)实验结果:输入词法符号序列:{<int, int>, <a, a>, <=, =>, <10, 10>, <;, ;>}输出AST:```AST:- ExpressionStatement- Expression- BinaryExpression- Identifier: a- Operator: =- Constant: 10```3. 语义分析(1)实验目的:实现语义分析器,对AST进行语义检查,确保程序的正确性。
(2)实验步骤:1)定义语义规则,包括类型检查、作用域检查等。
《编译原理实践及应用》习题的参考答案
附录部分习题参考答案第1章参考答案:1,2,3,4,5,6,7解答:略!第2章参考答案:1,2,3:解答:略!4. 解答:A:① B:③ C:① D:②5. 解答:用E表示<表达式>,T表示<项>,F表示<因子>,上述文法可以写为:E → T | E+TT → F | T*FF → (E) | i最左推导:E=>E+T=>E+T+T=>T+T+T=>F+T+T=>i+T+T=>i+F+T=>i+i+T=>i+i+F=>i+i+iE=>E+T=>T+T=>F+T=>i+T=>i+T*F=>i+F*F=>i+i*F=>i+i*i 最右推导:E=>E+T=>E+F=>E+i=>E+T+i=>E+F+i=>E+i+i=>T+i+i=>F+i+i=>i+i+iE=>E+T=>E+T*F=>E+T*i=>E+F*i=>E+i*i=>T+i*i=>F+i*i =>i+i*ii+i+i和i+i*i的语法树如下图所示。
i+i+i、i+i*i的语法树6. 解答:(1) 终结符号为:{or,and,not,(,),true,false}非终结符号为:{bexpr,bterm,bfactor}开始符号为:bexpr(2) 句子not(true or false)的语法树为:7. 解答:(1) 把a n b n c i分成a n b n和c i两部分,分别由两个非终结符号生成,因此,生成此文法的产生式为:S → ABA → aAb|abB → cB|ε(2) 令S为开始符号,产生的w中a的个数恰好比b多一个,令E为一个非终结符号,产生含相同个数的a和b的所有串,则产生式如下:S → aE|Ea|bSS|SbS|SSbE → aEbE|bEaE|ε(3) 设文法开始符号为S,产生的w中满足|a|≤|b|≤2|a|。
广东海洋大学编译原理(实验1消除程序中的注释)
GDOU-B-11-112广东海洋大学学生实验报告书(学生用表)实验名称实验1:消除程序中的注释课程名称编译原理课程号学院(系)数计学院专业计算机科学与技术班级计科1141学生姓名学号实验地点科425实验日期一、实验目的对使用高级程序设计语言编写的源程序进行处理,为词法分析做准备二、实验内容及步骤对C或C++等高级程序设计语言编写的源程序中的else..语句加以判断,并做出相应的处理。
在这里还有可能出现另一种情况,上述两种注释符号可能出现在引号中,出现在引号中的注释符号并没有注释功能,因此在引号中出现的注释符号不应该被消除。
所以,本实验所要编写的程序将要分三种情况分析。
在这里,我们先对引号情况进行处理。
程序在对源程序进行一个一个字符读取,若是遇到第一个双引号,则用变量temp保存起来,然后在对接下来读取到的字符,与它将temp进行比较,不等,则输出到目标文件,相等,则把第二个双引号输出到目标文件后,重新循环接下来的字符,看它属性第几种情况。
第二种情况是对单行注释进行处理。
若在读取源文件时,遇到了第一个斜杠,则保存在变量temp2,此时的斜杠不可能在双引号中,因为它已经经过了第一种情况的判断。
接下来对斜杠下一个字符进行读取,若为斜杠,则是单行注释,若为*,则是多行注释。
单行注释后的字符不输出到目标文件,直到遇到换行符。
多行注释则寻找*/。
若两种情况都不是,则输出之前保存的值,即temp2的值到目标文件,这种情况针对字符/,即单引号中的/。
四、源代码#include<iostream>#include<fstream>#include<iomanip>#include<cstdlib>using namespace std;int main() {cout << '/';ifstream ifile; pp"); bj");if () || ()) { pp目标文件源.obj六、实验小结此次实验实现了对C或C++高级语言的注释消除。
编译原理实验报告小结
一、实验背景编译原理是计算机科学的一个重要分支,主要研究如何将高级语言源代码转换为计算机可以执行的机器代码。
本实验旨在通过实践操作,加深对编译原理基本概念和算法的理解,提高编程能力和解决问题的能力。
二、实验目的1. 理解编译原理的基本概念和流程;2. 掌握词法分析和语法分析的基本方法;3. 熟悉编译过程中的中间代码生成和代码优化;4. 培养编程能力和团队协作精神。
三、实验内容1. 词法分析词法分析是编译过程的第一步,其主要任务是将源代码中的字符序列转换成一个个有意义的符号(单词)。
本实验中,我们实现了词法分析器,能够识别出标识符、关键字、运算符、常量等单词。
2. 语法分析语法分析是编译过程的核心,其主要任务是将词法分析器生成的单词序列按照一定的语法规则进行组织,形成语法树。
本实验中,我们实现了递归下降解析法,对表达式、赋值语句、函数定义等语法结构进行了分析。
3. 中间代码生成中间代码生成是编译过程中的一个重要环节,其主要任务是将语法树转换为一种抽象的、与具体机器无关的中间代码。
本实验中,我们实现了三地址代码生成,将语法树转换为三地址代码。
4. 代码优化代码优化是编译过程中的一个关键步骤,其主要任务是在保证程序正确性的前提下,提高程序的性能。
本实验中,我们实现了简单的代码优化,如常数传播、变量替换等。
四、实验结果与分析1. 实验结果通过实验,我们成功实现了词法分析、语法分析、中间代码生成和代码优化等功能。
以一个简单的C语言程序为例,我们能够将其转换为三地址代码,并进行简单的优化。
2. 实验分析(1)词法分析:本实验中,我们通过定义状态转换表和动作表,实现了对C语言源代码的词法分析。
实验结果表明,词法分析器能够准确地识别出标识符、关键字、运算符、常量等单词。
(2)语法分析:递归下降解析法是一种较为直观的语法分析方法。
本实验中,我们实现了递归下降解析法,对表达式、赋值语句、函数定义等语法结构进行了分析。
编译原理实验报告
编译原理实验报告一、实验目的编译原理是计算机科学中的一门重要课程,通过实验,旨在加深对编译原理相关理论知识的理解,提高实践动手能力和问题解决能力。
具体目标包括:1、熟悉编译程序的基本结构和工作流程。
2、掌握词法分析、语法分析、语义分析及中间代码生成等主要阶段的实现方法。
3、培养运用编程语言实现编译算法的能力。
二、实验环境本次实验使用的编程语言为_____,开发工具为_____,操作系统为_____。
三、实验内容(一)词法分析词法分析是编译过程的第一个阶段,其任务是从输入的源程序中识别出一个个单词符号。
使用正则表达式和有限自动机的理论,设计并实现了词法分析器。
首先,定义了单词的类别,如标识符、关键字、运算符、常量等。
然后,根据不同单词类别的特征,编写了相应的正则表达式模式。
在实现过程中,通过对输入的源程序进行逐字符扫描,利用正则表达式匹配来识别单词,并将其分类存储。
(二)语法分析语法分析是编译过程的核心部分,其目的是确定输入的单词序列是否符合给定的语法规则。
采用了自顶向下的递归下降分析法和自底向上的算符优先分析法。
对于递归下降分析法,根据语法规则编写了相应的递归函数。
每个函数处理一种语法结构,通过递归调用实现对整个语法的分析。
算符优先分析法则通过定义算符的优先级和结合性,构建算符优先关系表,然后依据表进行语法分析。
(三)语义分析语义分析阶段主要检查语法正确的句子是否具有实际的意义,并进行类型检查、语义计算等操作。
在实现中,通过构建符号表来记录变量的信息,包括名称、类型、作用域等。
同时,在语法分析的过程中,根据语义规则进行相应的检查和计算。
(四)中间代码生成中间代码生成是将源程序转换为一种便于优化和目标代码生成的中间表示形式。
选择了三地址码作为中间代码。
在生成中间代码时,根据语法分析和语义分析的结果,按照一定的规则将源程序转换为三地址码的形式。
四、实验步骤1、需求分析仔细研究实验要求,明确各个阶段的任务和目标,确定所需的数据结构和算法。
实验内容-编译原理及实践教程(第3版)-黄贤英-清华大学出版社
• 查找识别出的单词的种别码,将输出形式改为二元形式 • 画出该高级语言中其他单词类别的状态转换图,并编写
识别函数,并给出测试用例进行测试 • 利用可视化界面展示自己的实验结果
– (3)完成实验报告
实验二:词法分析自动生成器 (2学时+课外)
• 实验内容:利用flex词法分析自动生成工具(或者其他的 词法分析工具),生成Sample语言的词法分析程序。要求:
(含关系表达式)的文法 • 利用递归下降的方法编写判断给定的单词串能否构成一
个正确的布尔表达式的函数
– (3)完成实验报告
实验四:语句的分析(2学时+课外)
• 实验内容:根据Sample语言的语法规则判定输入的一串单 词能否构成一个正确的语句。要求: – (1)基本内容:
• 写出Sample语言(或你所选定的语言)的赋值语句的文 法
– (5)完成实验报告
实验七:运行时存储空间分配 (2学时+课外)
• 实验内容:利用VC++或者其他语言的反汇编程序查看C语 言程序生成的汇编代码,观察程序在内存中的存储情况。 – (1)基本内容:
• 分析程序运行时代码和数据是如何在内存中分配空间的 • 分析一个函数在内存中占用的空间是如何分配的 • 分析函数调用时实在参数和形式参数如何存储和传递 • 分析全局变量是如何在内存中存储的
• 编写Lex源程序,去掉给定Sample语言程序中的注释, 并将所有关键字变为小写
• 编写Lex源程序,能识别Sample语言(或者自选语言) 的所有单词,生成词法分析程序
– (3)完成实验报告
实验三:表达式的分析 (4学时+课外)
• 实验内容:根据Sample语言的语法规则判定输入的一串单 词能否构成一个正确的表达式。要求: – (1)基本内容1:
武汉大学编译原理实习报告——文法分类
编译原理实习1报告问题定义:简单的文法分类。
系统输入任意文法G的Vn,P和S,系统输出文法形式化表示G=(Vn,Vt,P,S),文法的Chomsky类型(0型、1型、2型、3型)。
为简单起见,文法符号都采用单字符符号。
有多个候选式的产生式允许采用缩写形式(α::=β1|β2|β3|……|βn)。
需求分析:输入:G[N]、Vn、P输出:G[N] = (Vn,Vt,P,P0)和该文法的Chomsky类型。
用例图如下图所示:根据输入和输出要求,可以得到以下需要解决的问题:1.需要从输入数据中找出起始状态P0;2.需要从输入数据中提取出Vt集合;3.需要从输入数据中得到该文法G[N]的Chomsky类型。
问题1:需要从输入数据中找出起始状态P0。
分析:起始状态P0在输入数据G[N]中已经给出,根据定义和问题描述,起始状态P0仅包含一个字符,因此仅需找出G[N]中’[’符号的位置,即可得到P0。
问题2:需要从输入数据中提取出Vt集合。
分析:终止符号集合需要根据Vn,从P中提取出来。
P的输入格式为:α::=β1|β2|β3|……|βn终止符号有可能出现在左边α部分,也有可能出现在右边β部分。
所以仅需确定字符串”::=”的位置,然后分别提取左边和右边部分,分别扫描字符,如果字符a不在Vn中,便将a加入Vt。
右边部分扫描时需要排除掉字符’|’。
最后的结果便是最终确定的终结符号集合Vt。
问题3:需要从输入数据中得到该文法G[N]的Chomsky类型。
分析:文法Chomsky类型的判断方法如下图所示:根据上图,出现3个问题,即3个文法类型判断条件:判断条件1:左部是否是单个非终结符。
确定左部是否是单个非终结符,仅需确定每一个产生式的第一个字符是否在Vn中,并且字符串”::=”的起始位置在产生式的第二个字符位上,即左部长度只能为1。
判断条件2:右部是否是单一终结符或单一终结符跟着单一非终结符。
确定右部第一个字符是否是终结符,如果右部字符串长度为1,则结束判断,若是终结符,则为3型,否则为2型;如果右部长度为2,判断第二个字符是否是非终结符,是则非终结符为3型,否则为2型;如果右部字符串长度大于2,则为2型。
华工编译原理实验报告
一、实验目的通过本次实验,加深对编译原理中语法分析部分的理解,掌握递归下降分析法和LR(1)分析法的原理和实现方法,并能够运用所学知识对简单的文法进行语法分析。
二、实验内容本次实验主要分为两个部分:1. 递归下降分析法- 实验要求:针对给定的文法,编写递归下降分析程序,实现对输入的字符串进行语法分析。
- 文法示例:```S -> A BA -> a A | εB -> b B | ε```- 实现过程:- 定义文法的非终结符号、终结符号和开始符号。
- 设计递归下降分析函数,按照文法的产生式进行递归调用。
- 处理输入字符串,调用递归下降分析函数进行语法分析。
2. LR(1)分析法- 实验要求:针对给定的文法,编写LR(1)分析程序,实现对输入的字符串进行语法分析。
- 文法示例:```S -> A BA -> a A | εB -> b B | ε```- 实现过程:- 求解文法的 FIRST 集和 FOLLOW 集。
- 构建LR(1)分析表,包括状态转移函数、接受状态和错误处理函数。
- 设计LR(1)分析程序,根据分析表进行状态转移和语法分析。
三、实验步骤1. 递归下降分析法- 步骤一:定义文法的非终结符号、终结符号和开始符号。
- 步骤二:设计递归下降分析函数,按照文法的产生式进行递归调用。
- 步骤三:编写主函数,读取输入字符串,调用递归下降分析函数进行语法分析。
2. LR(1)分析法- 步骤一:求解文法的 FIRST 集和 FOLLOW 集。
- 步骤二:构建LR(1)分析表,包括状态转移函数、接受状态和错误处理函数。
- 步骤三:设计LR(1)分析程序,根据分析表进行状态转移和语法分析。
四、实验结果1. 递归下降分析法- 对于输入字符串 "aaabbb",程序能够正确分析并输出分析结果。
2. LR(1)分析法- 对于输入字符串 "aaabbb",程序能够正确分析并输出分析结果。
编译原理教程实验报告
一、实验目的本次实验旨在使学生通过编译原理的学习,了解编译程序的设计原理及实现技术,掌握编译程序的各个阶段,并能将所学知识应用于实际编程中。
二、实验内容1. 词法分析2. 语法分析3. 语义分析4. 中间代码生成5. 代码优化6. 目标代码生成三、实验步骤1. 词法分析(1)设计词法分析器,识别输入源代码中的各种词法单元;(2)使用C语言实现词法分析器,并进行测试。
2. 语法分析(1)根据文法规则设计语法分析器,识别输入源代码的语法结构;(2)使用C语言实现语法分析器,并进行测试。
3. 语义分析(1)设计语义分析器,检查语法分析后的语法树,确保语义正确;(2)使用C语言实现语义分析器,并进行测试。
4. 中间代码生成(1)设计中间代码生成器,将语义分析后的语法树转换为中间代码;(2)使用C语言实现中间代码生成器,并进行测试。
5. 代码优化(1)设计代码优化器,对中间代码进行优化,提高程序性能;(2)使用C语言实现代码优化器,并进行测试。
6. 目标代码生成(1)设计目标代码生成器,将优化后的中间代码转换为特定目标机的汇编语言;(2)使用C语言实现目标代码生成器,并进行测试。
四、实验结果与分析1. 词法分析实验结果:成功识别输入源代码中的各种词法单元,包括标识符、关键字、运算符、常量等。
2. 语法分析实验结果:成功识别输入源代码的语法结构,包括表达式、语句、程序等。
3. 语义分析实验结果:成功检查语法分析后的语法树,确保语义正确。
4. 中间代码生成实验结果:成功将语义分析后的语法树转换为中间代码,为后续优化和目标代码生成提供基础。
5. 代码优化实验结果:成功对中间代码进行优化,提高程序性能。
6. 目标代码生成实验结果:成功将优化后的中间代码转换为特定目标机的汇编语言,为程序在目标机上运行做准备。
五、实验心得1. 编译原理是一门理论与实践相结合的课程,通过本次实验,我对编译程序的设计原理及实现技术有了更深入的了解。
计算机基础知识点编译原理实践案例
计算机基础知识点编译原理实践案例首先,我们需要了解编译原理的基本概念和原理。
编译原理是计算机科学中的一个重要分支,它研究将高级语言编写的程序转换为底层机器语言的过程。
在编译原理中,有一些基本概念是我们需要了解的,接下来,我们通过一个实践案例来深入学习和理解这些知识点。
案例背景:假设我们有一个简单的编程语言,叫做MiniLang。
它具有基本的算术运算和控制流语句,可以用于编写简单的计算程序。
我们的目标是设计一个编译器,将MiniLang代码编译为目标机器语言。
1. 词法分析在编译器的第一个阶段,我们需要对源代码进行词法分析。
词法分析的任务是将源代码分割成一个个的词法单元。
对于MiniLang,可能的词法单元包括数字、算术运算符、关键字和标识符等。
我们可以使用正则表达式来定义词法单元的模式,并利用有限状态自动机来实现词法分析。
2. 语法分析在词法分析完成后,我们需要进行语法分析。
语法分析的任务是根据词法单元序列生成抽象语法树(AST)。
AST是表达源代码结构的一种数据结构,它将源代码转化为一颗可以被编译器进一步处理的树形结构。
对于MiniLang,我们可以利用上下文无关文法来定义它的语法规则,并使用自顶向下或自底向上的语法分析算法生成AST。
3. 语义分析在语法分析阶段生成AST后,我们需要进行语义分析。
语义分析的任务是检查源代码的语义是否符合语言规范,并进行类型检查等操作。
对于MiniLang,我们可以检查变量是否被声明和初始化,函数调用是否正确,以及类型是否匹配等。
语义分析可以通过遍历AST并应用语义规则来完成。
4. 中间代码生成在语义分析完成后,我们就可以进行中间代码生成了。
中间代码是一种抽象的机器无关的代码表示,它将源代码转化为一种更加便于后续优化和生成目标代码的形式。
对于MiniLang,我们可以将中间代码表示为三地址码或者四元式等。
中间代码的生成可以在语义分析的同时进行,或者在语义分析完成后再进行。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
实验二算数表达式的扩充一、实验目的掌握LR分析表的设计方法和语义加工程序的扩充。
二、实验内容算术表达式文法扩充如下:E→E+E|E-E|E*E|E/E|(E)|i试根据该文法添加单词“-”、“/”的内部定义以及重新设计LR分析表,并修改语义加工程程序,最后验证修改的结果。
三、L R分析表的构造四、编译程序的修改与扩充定义符号减和除的编号#define sub 35//减#define div 37//除重新构造LR分析表action1static int action1[14][9]={{3,-1,-1,2,-1,-1,1,-1,-1,}, {-1,4,6,-1,-1,ACC,-1,5,7}, {3,-1,-1,2,-1,-1,8,-1,-1},{-1,104,104,-1,104,104,-1,104,104},{3,-1,-1,2,-1,-1,9,-1,-1},{3,-1,-1,2,-1,-1,10,-1,-1},{3,-1,-1,2,-1,-1,11,-1,-1},{3,-1,-1,2,-1,-1,12,-1,-1},{-1,4,6,-1,13,-1,-1,5,7},{-1,101,6,-1,101,101,-1,101,7},{-1,105,6,-1,105,105,-1,105,7},{-1,102,102,-1,102,102,-1,102,102},{-1,106,106,-1,106,106,-1,106,106},{-1,103,103,-1,103,103,-1,103,103}};在扫描程序中添加-,/情况case '-':buf[count].sy1=sub;count++;break;case '/':buf[count].sy1=div;count++;break;change1(int chan)//action1的符号查找排序(i,+,*,(,),#,E,-,/)加入:case sub:return 7;//-case div:return 8;// /lrparse1语义分析中状态数增加if((lr1<14)&&(lr1>=0))//在0~13个状态之中规约增加数if((lr1>=100)&&(lr1<107))case 105:E.pos=newtemp();//E->E-Egen("-",sstack[ssp-2],sstack[ssp],E.pos+100);ssp=ssp-2;sstack[ssp].sy1=tempsy;sstack[ssp].pos=E.pos;sp1=sp1-3;break;case 106:E.pos=newtemp();//E->E/Egen("/",sstack[ssp-2],sstack[ssp],E.pos+100);ssp=ssp-2;sstack[ssp].sy1=tempsy;sstack[ssp].pos=E.pos;sp1=sp1-3;break;测试字符是否为表达式中的值(不包括":"),test(int value)增加:case sub:case div:五、编译程序的验证测试用例:while (a>b) dobeginif m>=n then a:=a-1elsewhile k=h do x:=x/2;m:=n+x*(m+y)end#~测试结果:六、实验体会经过一个星期的编译原理课程设计,本人在李艳老师的指导下,顺利完成该课程设计。
通过该课程设计,收获颇多。
1.对实验原理有更深的理解通过该课程设计,掌握了什么是编译程序,编译程序工作的基本过程及其各阶段的基本任务,熟悉了编译程序总流程框图,了解了编译程序的生成过程、构造工具及其相关的技术对课本上的知识有了更深的理解,课本上的知识师机械的,表面的。
通过把该算法的内容,算法的执行顺序在计算机上实现,把原来以为很深奥的书本知识变的更为简单,对实验原理有更深的理解。
2.对该理论在实践中的应用有深刻的理解通过把该算法的内容,算法的执行顺序在计算机上实现,知道和理解了该理论在计算机中是怎样执行的,对该理论在实践中的应用有深刻的理解。
3.激发了学习的积极性通过该课程设计,全面系统的理解了编译原理程序构造的一般原理和基本实现方法。
把死板的课本知识变得生动有趣,激发了学习的积极性。
把学过的计算机编译原理的知识强化,能够把课堂上学的知识通过自己设计的程序表示出来,加深了对理论知识的理解。
以前对与计算机操作系统的认识是模糊的,概念上的,现在通过自己动手做实验,从实践上认识了操作系统是如何处理命令的,如何协调计算机内部各个部件运行,对计算机编译原理的认识更加深刻。
课程设计中程序比较复杂,在调试时应该仔细,在程序调试时,注意指针,将不必要的命令去除。
在这次课程设计中,我就是按照实验指导的思想来完成。
加深了理解文件系统的内部功能及内部实现,培养实践动手能力和程序开发能力的目的。
四、理解了该知识点以及学科之间的融合渗透本次课程设计程序部分是用c语言编写的,把《计算机操作系统》,《编译原理》,《算法分析与设计》《c语言》四门学科联系起来,把各个学科之间的知识融合起来,把各门课程的知识联系起来,对计算机整体的认识更加深刻。
使我加深了对《计算机操作系统》,《编译原理》,《算法分析与设计》《c 语言》四门课程的认识。
七、源码#include "stdio.h"#include "string.h"#define ACC -2/**************************************/#define sy_if 0#define sy_then 1#define sy_else 2#define sy_while 3#define sy_begin 4#define sy_do 5#define sy_end 6#define a 7#define semicolon 8#define e 9#define jinghao 10#define S 11#define L 12#define tempsy 15#define EA 18#define E0 19#define plus 34#define sub 35//减#define times 36#define div 37//除#define becomes 38#define op_and 39#define op_or 40#define op_not 41#define rop 42#define lparent 48#define rparent 49#define ident 56#define intconst 57/********************************************/char ch='\0';//可用于存放读出的一个字符int count=0;//词法分析结果缓冲区计数器static char spelling[10]={""};//存放是别的字static char line[81]={""};//一行字符缓冲区char *pline;//line的指针static char ntab1[100][10];//变量类型名表struct ntab{int tc;//真int fc;//假}ntab2[200];//用于存放布尔表达式的值int label=0;//指向ntab2的指针struct rwords{char sp[10];int sy;};//匹配表结构体struct rwords reswords[10]={{"if",sy_if},{"do",sy_do},{"else",sy_else},{"while",sy_while},{"then",sy_then},{"begin",sy_begin},{"end",sy_end},{"and",op_and},{"or",op_or},{"not",op_not}};//初始化匹配表,用于关键字的匹配struct aa{int sy1;//存放变量的类型名int pos;//存放该变量在自己表中的位置}buf[1000],//词法分析结果缓冲区n,//存放二元式当前字符n1,//表达式当前的字符E,//非终结符sstack[100],//算术表达式和布尔表达式的符号栈ibuf[100],//算术表达式和布尔表达式的缓冲区stack[1000];//语法分析的符号栈struct aa oth;//四元式中没有填写的空白位置struct fourexp//四元式结构体{char op[10];struct aa arg1;struct aa arg2;int result;}fexp[200];int ssp=0;//指向 sstack的指针struct aa *pbuf=buf;//词法分析结果缓冲区的指针int nlength=0;//词法分析中记录单词的长度int lnum=0;//行数计数源程序int tt1=0;//变量类型名表的指针FILE *cfile;//源程序文件/********************************************************/int newt=0;//临时变量计数器int nxq=100;//总是指向下一个要形成的四元式每次执行gen()int lr;//用于存放action1中的当前状态int lr1;//用于存放action2,3中的当前状态int sp=0;//LR分析表栈顶指针int stack1[100];//状态栈1int sp1=0;//状态栈的指针int num=0;//算术表达式或布尔表达式的指针struct ll{int nxq1;//指向下一条四元式的指针int tc1;//真值链int fc1;//假值链}labelmark[10];//记录嵌套中每层布尔表达式e的首地址int labeltemp[10];//记录每层else之前四元式的地址int pointmark=-1,pointtemp=-1;//labelmark的指针,labelmark的指针int sign=0;// sign=1 赋值语句,sign=2 while语句,sign=3 if语句/********************程序语句的LR分析表********************/ static int action[19][13]={{2,-1,-1,3,4,-1,-1,5,-1,-1,10,1,-1},{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,ACC,-1,-1},{-1,-1,-1,-1,-1,-1,-1,-1,-1,6,-1,-1,-1},{-1,-1,-1,-1,-1,-1,-1,-1,-1,7,-1,-1,-1},{2,-1,-1,3,4,-1,-1,5,-1,-1,-1,9,8},{-1,-1,104,-1,-1,-1,104,-1,104,-1,104,-1,-1},{-1,10,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},{-1,-1,-1,-1,-1,11,-1,-1,-1,-1,-1,-1,-1},{-1,-1,-1,-1,-1,-1,12,-1,-1,-1,-1,-1,-1},{-1,-1,-1,-1,-1,-1,105,-1,13,-1,-1,-1,-1},{2,-1,-1,3,4,-1,-1,5,-1,-1,-1,14,-1},{2,-1,-1,3,4,-1,-1,5,-1,-1,-1,15,-1},{-1,-1,103,-1,-1,-1,103,-1,103,-1,103,-1,-1},{2,-1,-1,3,4,-1,-1,5,-1,-1,-1,9,16},{-1,-1,17,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},{-1,-1,102,-1,-1,-1,102,-1,102,-1,102,-1,-1},{-1,-1,-1,-1,-1,-1,106,-1,-1,-1,-1,-1,-1},{2,-1,-1,3,4,-1,-1,5,-1,-1,-1,18,-1},{-1,-1,101,-1,-1,-1,101,-1,101,-1,101,-1,-1}};/********************算术表达式的LR分析表********************/ static int action1[14][9]={{3,-1,-1,2,-1,-1,1,-1,-1,},{-1,4,6,-1,-1,ACC,-1,5,7},{3,-1,-1,2,-1,-1,8,-1,-1},{-1,104,104,-1,104,104,-1,104,104},{3,-1,-1,2,-1,-1,9,-1,-1},{3,-1,-1,2,-1,-1,10,-1,-1},{3,-1,-1,2,-1,-1,11,-1,-1},{3,-1,-1,2,-1,-1,12,-1,-1},{-1,4,6,-1,13,-1,-1,5,7},{-1,101,6,-1,101,101,-1,101,7},{-1,105,6,-1,105,105,-1,105,7},{-1,102,102,-1,102,102,-1,102,102},{-1,106,106,-1,106,106,-1,106,106},{-1,103,103,-1,103,103,-1,103,103}};/********************布尔表达式的LR分析表*********************/ static int action2[16][11]={{1,-1,4,-1,5,-1,-1,-1,13,7,8},{-1,2,-1,101,-1,101,101,101,-1,-1,-1},{3,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},{-1,-1,-1,102,-1,102,102,102,-1,-1,-1},{1,-1,4,-1,5,-1,-1,-1,11,7,8},{1,-1,4,-1,5,-1,-1,-1,6,7,8},{-1,-1,-1,104,-1,9,10,104,-1,-1,-1},{1,-1,4,-1,5,-1,-1,-1,14,7,8},{1,-1,4,-1,5,-1,-1,-1,15,7,8},{105,-1,105,-1,105,-1,-1,-1,-1,-1,-1},{107,-1,107,-1,107,-1,-1,-1,-1,-1,-1},{-1,-1,-1,12,-1,9,10,-1,-1,-1,-1},{-1,-1,-1,103,-1,103,103,103,-1,-1,-1},{-1,-1,-1,-1,-1,9,10,ACC,-1,-1,-1},{-1,-1,-1,106,-1,9,10,106,-1,-1,-1},{-1,-1,-1,108,-1,9,10,108,-1,-1,-1}};/********************从文件读一行到缓冲区**********************/ readline()//读一行{char ch1;pline=line;ch1=fgetc(cfile);//从文件中取一个while((ch1!='\n')&&(ch1!=EOF))//把字符缓冲区填满{*pline=ch1;pline++;ch1=fgetc(cfile);}*pline='\0';//结尾终结符pline=line;//字符缓冲区指针重新回到字符缓冲区的第一个字符位置}/**********************从缓冲区读取一个字符*********************/ readch()//读一个{if(ch=='\0')//读到尾姐再来一行,行数加一{readline();lnum++;}ch=*pline;//从行缓冲区读取一个字符pline++;//字符缓冲区指针后移}/***********************标识符和关键字的识别********************/find(char spel[])//在变量表中查询{int ss1=0;// 是否查到的变量的标志(1为查到,0为没查到)int ii=0;//记录查到变量表第几条while((ss1==0)&&(ii<nlength))//只要没有查到,或没有超过变量表表长,就继续查{if(!strcmp(spel,ntab1[ii]))ss1=1;ii++;}if(ss1==1)//查到了return ii-1;//返回在表量表的地址(-1的原因是上面的ii++最后多加了一次) else return -1;//没查到,返回-1}identifier()//关键字或变量或常量查询{int iii=0,j,k;//iii关键字表中的指针位置int ss=0;//关键字是否匹配到的标识k=0;//存放的识别的字的指针(spelling[k])do//将取出的字符放入识别的字 spelling数组中{spelling[k]=ch;k++;readch();//取一个字符}while(((ch>='a')&&(ch<='z'))||((ch>='0')&&(ch<='9')));//数字或小写字母 pline--;//取字时多加的一个,-1可使 *pline指向字符缓冲区行尾spelling[k]='\0';while((ss==0)&&(iii<10)){if(!strcmp(spelling,reswords[iii].sp))//在关键字表中查询ss=1;//查到标志置1iii++;}/*关键字匹配*/if(ss==1)//在关键字表中查到{buf[count].sy1=reswords[iii-1].sy;//关键字名字放入结果缓冲区}else//没查到{buf[count].sy1=ident;//将变量名置入结果缓冲区j=find(spelling);//变量表查询,查到就把变量在变量表的地址赋给jif(j==-1)//没查到就新建一个变量{buf[count].pos=tt1;//将其在变量表中的地址放入结果缓冲区中的地址栏strcpy(ntab1[tt1],spelling);//将识别的变量名放入变量名表tt1++;nlength++;//变量名表长加一}else buf[count].pos=j;//查到后,将变量名表中变量的地址放入结果缓冲区该变量的地址栏中}count++;//指向结果缓冲区下一位置for(k=0;k<10;k++) spelling[k]=' ';//以识别的临时字符清空}/**********************数字识别*************************/number(){int ivalue=0;int digit;do{digit=ch-'0';//取出的字符转换为数字ivalue=ivalue*10+digit;//数字地址从10后开始记录readch();//取一个字符}while((ch>='0')&&(ch<='9'));buf[count].sy1=intconst;//常量名存入结果缓冲区buf[count].pos=ivalue;//该常量地址存入结果缓冲区count++;// 向结果缓冲区下一位置pline--;//指向行缓冲区尾字符}/***********************扫描主程序************************/scan(){int i;while(ch!='~')//~为程序结束符{switch(ch){case ' ':break;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':identifier();break;//关键词或变量查询case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9':number();break;//数字查询case '<':readch();//6种关系运算符buf[count].pos=(<=为0,<为1,>=为2,>为3,<>为4,=为5)if(ch=='=')buf[count].pos=0;else{if(ch=='>') buf[count].pos=4;else{buf[count].pos=1;pline--;}}buf[count].sy1=rop;//关系运算符名存入结果 count++;//结果指针后移break;case '>':readch();if(ch=='=')buf[count].pos=2;else{buf[count].pos=3;pline--;}buf[count].sy1=rop;count++;break;case '(':buf[count].sy1=lparent;count++;break;case ')':buf[count].sy1=rparent;count++;break;case '#':buf[count].sy1=jinghao;count++;break;case '+':buf[count].sy1=plus;count++;break;case '-':buf[count].sy1=sub;count++;break;case '*':buf[count].sy1=times;count++;break;case '/':buf[count].sy1=div;count++;break;case ':':readch();if(ch=='=')buf[count].sy1=becomes;count++;break;case '=':buf[count].sy1=rop;buf[count].pos=5;count++;break;case ';':buf[count].sy1=semicolon;count++;break;}readch();// 取下一个字符}buf[count].sy1=-1;//结束了}/*******************************************************/readnu()//读取当前结果缓冲区的二元式存入struct aa n中,pbuf指向结果缓冲区中下一位置的指针{if(pbuf->sy1>=0){n.sy1=pbuf->sy1;//存放当前二元式字符名称n.pos=pbuf->pos;//存放当前二元式字符位置pbuf++;}}/***********************中间变量的生成*********************/newtemp()//返回目前临时变量数{newt++;//临时变量计数器+1return newt;}/***********************生成四元式**************************/gen(char op1[],struct aa arg11,struct aa arg22,int result1)//op1算符,arg11操作数1,arg22操作数2, result1结果{strcpy(fexp[nxq].op,op1);//为四元式传入算符fexp[nxq].arg1.sy1=arg11.sy1;//为四元式操作数1传入名字fexp[nxq].arg1.pos=arg11.pos;// 为四元式操作数1传入地址fexp[nxq].arg2.sy1=arg22.sy1;//为四元式操作数2传入名字fexp[nxq].arg2.pos=arg22.pos;// 为四元式操作数2传入地址fexp[nxq].result=result1;// 为四元式结果传入结果nxq++;//每次指向下一个要生成的四元式地址return nxq-1;//当前四元式地址}/***********************布尔表达式的匹配**********************/merg(int p1,int p2)// 将链首“指针”分别为p1和p2的两条链合并为一条,并返回新链的链首“指针”(此处的“指针”实际上是四元式的序号,应为整型值){int p;if(p2==0) return p1;else{p=p2;while(fexp[p].result!=0)p=fexp[p].result;fexp[p].result=p1;return p2;}}backpatch(int p,int t)//用四元式序号t回填以p为首的链,将链中每个四元式的Result域改写为t的值。