计算机编译原理实验报告
编译原理实验报告

编译原理实验报告一、实验目的和要求本次实验旨在对PL_0语言进行功能扩充,添加新的语法特性,进一步提高编译器的功能和实用性。
具体要求如下:1.扩展PL_0语言的语法规则,添加新的语法特性;2.实现对新语法的词法分析和语法分析功能;3.对扩展语法规则进行语义分析,并生成中间代码;4.验证扩展功能的正确性。
二、实验内容1.扩展语法规则本次实验选择扩展PL_0语言的语句部分,添加新的控制语句,switch语句。
其语法规则如下:<switch_stmt> -> SWITCH <expression> CASE <case_list><default_stmt> ENDSWITCH<case_list> -> <case_stmt> , <case_stmt> <case_list><case_stmt> -> CASE <constant> : <statement><default_stmt> -> DEFAULT : <statement> ,ε2.词法分析和语法分析根据扩展的语法规则,需要对新的关键字和符号进行词法分析,识别出符号类型和记号类型。
然后进行语法分析,建立语法树。
3.语义分析在语义分析阶段,首先对switch语句的表达式进行求值,判断其类型是否为整型。
然后对case语句和default语句中的常量进行求值,判断是否与表达式的值相等。
最后将语句部分生成中间代码。
4.中间代码生成根据语法树和语义分析的结果,生成对应的中间代码。
例如,生成switch语句的跳转表,根据表达式的值选择相应的跳转目标。
5.验证功能的正确性设计一些测试用例,验证新语法的正确性和扩展功能的实用性。
三、实验步骤与结果1.扩展语法规则,更新PL_0语法分析器的词法规则和语法规则。
编译原理实验报告

编译原理实验报告一、实验目的本次编译原理实验的主要目的是通过实践加深对编译原理中词法分析、语法分析、语义分析和代码生成等关键环节的理解,并提高实际动手能力和问题解决能力。
二、实验环境本次实验使用的编程语言为 C/C++,开发工具为 Visual Studio 2019,操作系统为 Windows 10。
三、实验内容(一)词法分析器的设计与实现词法分析是编译过程的第一个阶段,其任务是从输入的源程序中识别出一个个具有独立意义的单词符号。
在本次实验中,我们使用有限自动机的理论来设计词法分析器。
首先,我们定义了单词的种类,包括关键字、标识符、常量、运算符和分隔符等。
然后,根据这些定义,构建了相应的状态转换图,并将其转换为程序代码。
在实现过程中,我们使用了字符扫描和状态转移的方法,逐步读取输入的字符,判断其所属的单词类型,并将其输出。
(二)语法分析器的设计与实现语法分析是编译过程的核心环节之一,其任务是在词法分析的基础上,根据给定的语法规则,判断输入的单词序列是否构成一个合法的句子。
在本次实验中,我们采用了自顶向下的递归下降分析法来实现语法分析器。
首先,我们根据给定的语法规则,编写了相应的递归函数。
每个函数对应一种语法结构,通过对输入单词的判断和递归调用,来确定语法的正确性。
在实现过程中,我们遇到了一些语法歧义的问题,通过仔细分析语法规则和调整函数的实现逻辑,最终解决了这些问题。
(三)语义分析与中间代码生成语义分析的任务是对语法分析所产生的语法树进行语义检查,并生成中间代码。
在本次实验中,我们使用了四元式作为中间代码的表示形式。
在语义分析过程中,我们检查了变量的定义和使用是否合法,类型是否匹配等问题。
同时,根据语法树的结构,生成相应的四元式中间代码。
(四)代码优化代码优化的目的是提高生成代码的质量和效率。
在本次实验中,我们实现了一些基本的代码优化算法,如常量折叠、公共子表达式消除等。
通过对中间代码进行分析和转换,减少了代码的冗余和计算量,提高了代码的执行效率。
编译原理实验报告总结

编译原理实验报告总结一、实验目的编译原理是计算机科学中的一门重要课程,通过实验可以更深入地理解编译过程的各个阶段,包括词法分析、语法分析、语义分析、中间代码生成、代码优化和目标代码生成等。
本次编译原理实验的目的主要有以下几点:1、加深对编译原理理论知识的理解和掌握,将抽象的概念通过实际操作转化为具体的实现。
2、培养实际动手能力和解决问题的能力,通过编写代码实现编译程序的各个模块,提高编程技能和调试能力。
3、熟悉编译程序的开发流程和工具,掌握相关编程语言和开发环境的使用。
4、培养团队合作精神和沟通能力,在实验过程中与小组成员共同探讨、解决问题,提高协作效率。
二、实验环境本次实验使用的编程语言为 C/C++,开发环境为 Visual Studio 2019。
同时,使用了一些辅助工具,如调试工具、代码管理工具等,以提高开发效率和代码质量。
三、实验内容1、词法分析任务:使用正则表达式或有限自动机实现对输入源程序的词法分析,将源程序分解为一个个单词,并识别出单词的类型,如标识符、关键字、常量、运算符等。
实现方法:采用有限自动机的方法,设计状态转移图,根据输入字符的类型进行状态转移,最终确定单词的类型。
遇到的问题及解决方法:在处理一些边界情况时,如字符串中的转义字符,出现了识别错误。
通过仔细分析正则表达式和有限自动机的规则,对代码进行了相应的修改和完善,解决了问题。
2、语法分析任务:使用自顶向下或自底向上的语法分析方法,对词法分析得到的单词序列进行语法分析,构建语法树。
实现方法:选择了自顶向下的递归下降分析法,根据语法规则编写递归函数,逐个处理单词,构建语法树。
遇到的问题及解决方法:在处理复杂的语法结构时,出现了回溯和左递归的问题,导致分析效率低下。
通过消除左递归和提取公共因子,优化了语法分析算法,提高了分析效率。
3、语义分析任务:在语法分析的基础上,进行语义分析,检查语法正确的程序是否在语义上也是正确的,如类型匹配、变量未定义等。
编译原理实验报告

编译原理实验报告一、实验概述本次实验旨在设计并实现一个简单的词法分析器,即实现编译器的第一个阶段,词法分析。
词法分析器将一段源程序代码作为输入,将其划分为一个个的词法单元,并将其作为输出。
二、实验过程1.设计词法规则根据编程语言的规范和所需实现的功能,设计词法规则,以明确规定如何将源程序代码分解为一系列的词法单元。
2.实现词法分析器采用合适的编程语言,根据所设计的词法规则,实现词法分析器。
词法分析器的主要任务是读入源程序代码,并将其根据词法规则进行分解,生成对应的词法单元。
3.测试词法分析器设计测试用例,用于检验词法分析器的正确性和性能。
测试用例应包含各种情况下的源程序代码。
4.分析和修正错误根据测试过程中发现的问题,分析产生错误的原因,并进行修正。
重复测试和修正的过程,直到词法分析器能够正确处理所有测试用例。
三、实验结果我们设计了一个简单的词法分析器,并进行了测试。
测试用例涵盖了各种情况下的源程序代码,包括正确的代码和错误的代码。
经过测试,词法分析器能够正确处理所有的测试用例。
词法分析器将源程序代码分解为一系列的词法单元,每个词法单元包含了单词的种类和对应的值。
通过对词法单元的分析,可以进一步进行语法分析和语义分析,从而完成编译过程。
四、实验总结通过本次实验,我深入了解了编译原理的词法分析阶段。
词法分析是编译器的第一个重要阶段,它将源程序代码分解为一个个的词法单元,为后续的语法分析和语义分析提供基础。
在实现词法分析器的过程中,我学会了如何根据词法规则设计词法分析器的算法,并使用编程语言实现词法分析器。
通过测试和修正,我掌握了调试和错误修复的技巧。
本次实验的经验对我今后的编程工作有很大帮助。
编译原理是计算机科学与技术专业的核心课程之一,通过实践能够更好地理解和掌握其中的概念和技术。
我相信通过进一步的学习和实践,我能够在编译原理领域取得更大的成果。
编译原理实验报告

编译原理实验报告编译原理实验报告一、实验目的1. 了解编译器的基本原理和工作过程;2. 掌握编译器设计和实现的基本方法和技巧;3. 通过设计和实现一个简单的编译器,加深对编程语言和计算机系统的理解和认识。
二、实验原理编译器是将高级语言程序翻译成机器语言程序的一种软件工具。
它由编译程序、汇编程序、链接程序等几个阶段组成。
本次实验主要涉及到的是编译程序的设计和实现。
编译程序的基本原理是将高级语言程序转换为中间代码,再将中间代码转换为目标代码。
整个过程可以分为词法分析、语法分析、语义分析、代码生成和代码优化几个阶段。
三、实验内容本次实验的设计目标是实现一个简单的四则运算表达式的编译器。
1. 词法分析根据规定的语法规则,编写正则表达式将输入的字符串进行词法分析,将输入的四则运算表达式划分成若干个单词(Token),例如:运算符、操作数等。
2. 语法分析根据定义的语法规则,编写语法分析程序,将词法分析得到的Token序列还原成语法结构,构建抽象语法树(AST)。
3. 语义分析对AST进行遍历,进行语义分析,判断表达式是否符合语法规则,检查语义错误并给出相应的提示。
4. 代码生成根据AST生成目标代码,目标代码可以是汇编代码或者机器码。
四、实验过程和结果1. 首先,根据输入的表达式,进行词法分析。
根据所定义的正则表达式,将输入的字符串划分成Token序列。
例如:输入表达式“2+3”,经过词法分析得到的Token序列为["2", "+", "3"]。
2. 然后,根据语法规则,进行语法分析。
根据输入的Token序列,构建抽象语法树。
3. 接着,对抽象语法树进行语义分析。
检查表达式是否符合语法规则,给出相应的提示。
4. 最后,根据抽象语法树生成目标代码。
根据目标代码的要求,生成汇编代码或者机器码。
五、实验总结通过本次实验,我对编译器的工作原理有了更深入的认识,掌握了编译器设计和实现的基本方法和技巧。
编译原理实习报告

编译原理实习报告一、实习目的和意义编译原理是计算机科学的核心分支之一,涉及到将一种编程语言转换成另一种编程语言的过程。
通过本次实习,我希望能够深入理解编译原理的基本概念、方法和实现技术,提高自己的编程能力和软件设计能力。
二、实习内容和步骤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 实现语义分析器语义分析器的主要任务是对语法树进行遍历和分析,检查程序中的语义错误并生成中间代码。
编译原理实习报告
一、实习背景与目的随着计算机技术的飞速发展,编译原理作为计算机科学的重要基础理论之一,其研究与应用越来越受到重视。
为了更好地理解和掌握编译原理的基本原理和方法,提高自己的编程能力和设计能力,我参加了编译原理的实习课程。
本次实习旨在通过设计和实现一个简单的编译程序,加深对编译原理的理解,掌握编译程序的设计与实现方法,提高自己的编程能力,并培养自己的计算思维。
二、实习内容本次实习主要分为以下几个部分: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. 理解编译原理的基本概念和原理。
2. 掌握文法分析、词法分析和语法分析的基本方法。
3. 学会使用编译工具,如Lex和Yacc,实现简单的编译器。
三、实验内容本次实验主要分为三个部分:1. 词法分析2. 语法分析3. 编译器构建四、实验步骤1. 词法分析- 使用Lex工具实现词法分析器。
- 定义输入文件格式,包括源代码和标记。
- 编写Lex规则,将源代码转换为标记序列。
- 使用Flex生成词法分析器程序。
2. 语法分析- 使用Yacc工具实现语法分析器。
- 定义语法规则,包括产生式和文法符号。
- 编写Yacc规则,将标记序列转换为语法分析树。
- 使用Bison生成语法分析器程序。
3. 编译器构建- 将词法分析器和语法分析器程序结合,构建简单的编译器。
- 实现编译器的中间代码生成功能。
- 实现编译器的目标代码生成功能。
五、实验结果1. 词法分析- 输入:`int a = 10;`- 输出:`TOKEN: int, TOKEN: a, TOKEN: =, TOKEN: 10, TOKEN: ;`2. 语法分析- 输入:`int a = 10;`- 输出:`Syntax Tree: Program -> Declaration -> Variable Declaration -> Identifier -> a, Token -> int, Token -> =, Token -> 10, Token -> ;`3. 编译器构建- 输入:`int a = 10;`- 输出:`Target Code: int a = 10;`六、实验心得1. 通过本次实验,我深入理解了编译原理的基本概念和原理,包括词法分析、语法分析和编译器构建。
2. 我学会了使用Lex和Yacc等编译工具,实现了简单的编译器。
3. 本次实验让我认识到编译原理在软件开发中的重要性,以及编译器在代码生成和优化方面的作用。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
编译原理实验报告实验一词法分析设计一、实验功能:1、对输入的txt文件内的内容进行词法分析:2、由文件流输入test.txt中的内容,对文件中的各类字符进行词法分析3、打印出分析后的结果;二、程序结构描述:(源代码见附录)1、分别利用k[],s1[],s2[],s3[]构造关键字表,分界符表,算术运算符表和关系运算符表。
2、bool isletter(){} 用来判断其是否为字母,是则返回true,否则返回false;bool isdigit(){} 用来判断其是否为数字,是则返回true,否则返回false;bool iscalcu(){} 用来判断是否为算术运算符,是则返回true,否则返回false;bool reserve(string a[]){} 用来判断某字符是否在上述四个表中,是则返回true,否则返回false;void concat(){} 用来连接字符串;void getn(){} 用来读取字符;void getb(){} 用来对空格进行处理;void retract(){}某些必要的退格处理;int analysis(){} 对一个单词的单词种别进行具体判断;在主函数中用switch决定输出。
三、实验结果四、实验总结词法分析器一眼看上去很复杂,但深入的去做就会发现并没有一开始想象的那么困难。
对于一个字符的种别和类型可以用bool函数来判断,对于关键字和标示符的识别(尤其是3b)则费了一番功夫,最后对于常数的小数点问题处理更是麻烦。
另外,这个实验要设定好时候退格,否则将会导致字符漏读甚至造成字符重复读取。
我认为,这个实验在程序实现上大体不算困难,但在细节的处理上则需要好好地下功夫去想,否则最后的程序很可能会出现看上去没有问题,但实际上漏洞百出的状况。
将学过的知识应用到实际中并不简单,只有自己不断尝试将知识转化成程序才能避免眼高手低,对于知识的理解也必将更加深刻。
实验二LL(1)分析法一、实验原理:1、写出LL(1)分析法的思想:当一个文法满足LL(1)条件时,我们就可以为它构造一个不带回溯的自上而下的分析程序,这个分析程序是有一组递归过程组成的,每个过程对应文法的一个非终结符。
实现LL(1)分析的一种有效的方法是使用一张分析表和一个站进行联合控制。
预测分析表是一个M[A,a]形式的矩阵,存储着分析规则;栈STACK用于存放文法符号。
从栈顶取符号,按照分析表给出的规则进行有步骤的分析。
2.实验要求实现的文法:(1)E->TG(2)G->+TG|—TG(3)G->ε(4)T->FS(5)S->*FS|/FS(6)S->ε(7)F->(E)(8)F->i二、程序结构:string M[5][8] 用来定义分析表;char input[50] 用来存放输入的句子;vector<char> analysis 用来存放分析栈;bool flag = true 用来判断是否成功的标志;reference(char a,char i){} 查询分析表,其中a为分析栈顶符号,i为输入串符号;pro(char a,char in){} 用以做出具体的分析;三、实验结果:运行程序,输入需要分析的语句,结果如下:四、实验总结:本次试验用代码实现了LL(1)文法,在过程中对于非终结符向终结符转换的过程中出现了一些问题,之后通过向同学请教得已解决。
本代码中的分析表写在了主函数中,可以说本程序只对这一个文法有效,这也是这个程序的局限性。
实验三LR(1)分析法一、实验原理LR(1)分析法实验设计思想及算法(1)总控程序,也可以称为驱动程序。
对所有的LR分析器总控程序都是相同的。
(2)分析表或分析函数,不同的文法分析表将不同,同一个文法采用的LR分析器不同时,分析表将不同,分析表又可以分为动作表(ACTION)和状态转换(GOTO)表两个部分,它们都可用二维数组表示。
(3)分析栈,包括文法符号栈和相应的状态栈,它们均是先进后出栈。
分析器的动作就是由栈顶状态和当前输入符号所决定。
二、程序结构action[12][6] 定义动作表;go[12][3] 定义转换表;input[50] 存放输入串;referaction(int s,char i){} 查询action表,a为分析栈顶的状态,i为输入串的符号;refergo(int s,char i){} 查询go表;reduce(int n){} 就近规约;analysis(int st,char in){} 具体分析;◆其中:SP为栈指针,S[i]为状态栈,X[i]为文法符号栈。
状态转换表用GOTO[i,X]=j表示,规定当栈顶状态为i,遇到当前文法符号为X时应转向状态j,X为终结符或非终结符。
◆ACTION[i,a]规定了栈顶状态为i时遇到输入符号a应执行。
动作有四种可能:(1)移进:action[i,a]= Sj:状态j移入到状态栈,把a移入到文法符号栈,其中i,j表示状态号。
(2)归约:action[i,a]=rk:当在栈顶形成句柄时,则归约为相应的非终结符A,即文法中有A- B的产生式,若B的长度为R(即|B|=R),则从状态栈和文法符号栈中自顶向下去掉R个符号,即栈指针SP减去R,并把A移入文法符号栈内,j=GOTO[i,A]移进状态栈,其中i为修改指针后的栈顶状态。
(3)接受acc:当归约到文法符号栈中只剩文法的开始符号S时,并且输入符号串已结束即当前输入符是'#',则为分析成功。
(4)报错:当遇到状态栈顶为某一状态下出现不该遇到的文法符号时,则报错,说明输入端不是该文法能接受的符号串。
三、实验结果:输入需要规约的字符串,结果如下:四、实验总结1、与算符优先分析方法比较,用LR分析时,设计特定出错处理子程序比较容易,因为不会发生不正确的归约。
在分析表的每一个空项内,可以填入一个指示器,指向特定的出错处理子程序,第一类错误的处理一般采用插入、删除或修改的办法,但要注意,不能从栈内移去任何那种状态,它代表已成功地分析了程序中的某一部分。
2、LR分析法的归约过程是规范推导的逆过程,所以LR分析过程是一种规范归约过程。
LR 分析法正是给出一种能根据当前分析栈中的符号串(通常以状态表示)和向右顺序查看输入串的K个(K≥0)符号就可唯一地确定分析器的动作是移进还是归约和用哪个产生式归约,因而也就能唯一地确定句柄。
其中LR(0)分析器是在分析过程中不需向右查看输入符号,因而它对文法的限制较大,然而,它是构造其它LR类分析器的基础。
因此,首先应学好LR(0)项目集规范族构造的基本原理和方法。
当K=1时,已能满足当前绝大多数高级语言编译程序实现的需要。
SLR(1)分析是为学习LR(1)分析做准备,LR(1)项目集族的构造是LALR(1)分析器的构造原理和基础。
LALR(1) 分析器是当前大多数高级程序设计语言编译程序所采用的语法分析技术,也是编译程序语法分析器自动构造工具YACC的实现基本原理。
由此,LR(0)、SLR(1)、LALR(1)、LR(1)四种分析器的构造方法都必须深入理解和掌握。
3、经过以上三个实验的锤炼,不得不说自己编译原理这门课的认识又提高了一个阶层,对编译原理的知识运用更加深入,编写过程中遇到不少的问题,结合课本及强大的网络资源,在完成的过程中得到很多收获,不仅来自于对知识点的了解更加深入,更是对自己编程能力的一次很好的锻炼,希望有更多这样实验的机会。
4、本人很希望在完成实验后,老师可以根据自己讲的课本,将自己所写的程序花一段时间来讲解,我想这样会对不会编写的是一种教学,对会了的同学是一种榜样效应,可以让我们有个目标追求,这样我们收获了的也会更加准确与丰富。
附录:实验一源代码:#include <iostream>#include <string>#include <fstream>using namespace std;string k[] = {"do","end","for","if","printf","scanf","then","while"};//关键字string s1[]= {",",";","(",")","[","]"};//分界符string s2[]= {"+","-","*","/","++","--"};//算术运算符string s3[]= {"<","<=","=",">",">=","!="};//关系运算符string id[100];string ci[100];ifstream in;char ch;int row =1,col = 0;//行数与列数int idcount = 0,cicount = 0;string strtoken;bool isletter(){//用来判断其是否为字母if(ch >= 'A' && ch <= 'z')return true;elsereturn false;}bool isdigit(){//用来判断其是否为数字if(ch >= '0' && ch <= '9')return true;elsereturn false;}bool iscalcu(){//用来判断是否为算术运算符if(ch=='+'||ch=='-'||ch=='*'||ch=='/')return true;elsereturn false;}void insertid(){id[idcount] = strtoken;idcount++;}void insertci(){ci[cicount] = strtoken;cicount++;}bool reserve(string a[]){//用来判断某字符是否在表中int count;if(a[0] == "do") count = 8;else if(a[0] == ",")count = 6;else if(a[0] == "+")count = 6;else if(a[0] == "<")count = 6;for(int i = 0; i < count; i++){if(a[i] == strtoken)return true;}return false;}void concat(){//用来连接字符串strtoken += ch;}void getn(){//读取字符in.read(&ch, 1);if(ch == '\n'){in.read(&ch,1);row++;col = 1;}}void getb(){//空格处理while(ch == ' ')in.read(&ch,1);}void retract(){//某些必要的退格处理int size=sizeof(ch);in.seekg(-size*2,ios::cur);}int analysis(){//对一个单词的单词种别进行具体判断col++;getn();getb();if(in.eof())return 7;if(isletter()){while(isletter()||isdigit()){concat();getn();}retract();if(reserve(k)){return 1;}else{insertid();return 6;}}else if(isdigit()){bool multipoint = false;bool insertpoint = false;while(isdigit()||ch == '.'){if(ch == '.'){if(insertpoint == false){concat();getn();insertpoint = true;}else{concat();getn();multipoint = true;}}if(isdigit()){concat();getn();}}bool haveletter = false;while(isletter()){haveletter = true;concat();getn();}retract();if(haveletter)return 0;if(multipoint)return 0;insertci();return 5;}else if(iscalcu()){while(iscalcu()){concat();getn();}if(reserve(s2))return 3;elsereturn 0;}concat();if(reserve(s1))return 2;else if(reserve(s3)){getn();if(ch == '='){concat();if(reserve(s3))return 4;}else{retract();return 4;}}return 0;}int main(){in.open("file.txt");if(!in){cerr<<"文件不存在"<<endl;return 1;}cout<<"文件成功读取"<<endl;int code;cout<<"***********************分析结果如下***********************"<<endl;cout<<"单词"<<"\t\t"<<"二元序列"<<"\t"<<"类型"<<"\t\t"<<"位置"<<endl<<endl;while(!in.eof()){strtoken = "\0";code = analysis();switch(code){case0:cout<<strtoken<<"\t\t"<<"Error"<<"\t\t"<<"Error"<<"\t\t"<<'('<<row<<','<<col<<')'<<endl;brea k;case 1:if(strtoken.size() < 4)cout<<strtoken<<"\t\t"<<'('<<code<<','<<strtoken<<')'<<"\t\t"<<"关键字"<<"\t\t"<<'('<<row<<','<<col<<')'<<endl;elsecout<<strtoken<<"\t\t"<<'('<<code<<','<<strtoken<<')'<<"\t"<<"关键字"<<"\t\t"<<'('<<row<<','<<col<<')'<<endl;break;case 2:cout<<strtoken<<"\t\t"<<'('<<code<<','<<strtoken<<')'<<"\t\t"<<"分界符"<<"\t\t"<<'('<<row<<','<<col<<')'<<endl;break;case 3:cout<<strtoken<<"\t\t"<<'('<<code<<','<<strtoken<<')'<<"\t\t"<<"算术运算符"<<"\t"<<'('<<row<<','<<col<<')'<<endl;break;case 4:cout<<strtoken<<"\t\t"<<'('<<code<<','<<strtoken<<')'<<"\t\t"<<"关系运算符"<<"\t"<<'('<<row<<','<<col<<')'<<endl;break;case 5:cout<<strtoken<<"\t\t"<<'('<<code<<','<<strtoken<<')'<<"\t\t"<<"常数"<<"\t\t"<<'('<<row<<','<<col<<')'<<endl;break;case 6:cout<<strtoken<<"\t\t"<<'('<<code<<','<<strtoken<<')'<<"\t\t"<<"标识符"<<"\t\t"<<'('<<row<<','<<col<<')'<<endl;break;}}return 0;}实验二源代码:#include <iostream>#include <string>#include <vector>#include <iomanip>#include <algorithm>using namespace std;string M[5][8] ;//定义分析表char input[50];//用来存放输入的句子vector<char> analysis;//用来存放分析栈bool flag = true;//用来判断是否成功的标志,false为成功int i = 0; //输入串的指针string reference(char a,char i){//查询分析表,其中a为分析栈顶符号,i为输入串符号int x,y;switch(a){case 'E':x = 0;break;case 'T':x = 1;break;case 'F':x = 2;break;case 'G':x = 3;break;case 'S':x = 4;break;}switch(i){case '(':y = 0;break;case ')':y = 1;break;case '+':y = 2;break;case '-':y = 3;break;case '*':y = 4;break;case '/':y = 5;break;case 'i':y = 6;break;case '#':y = 7;break;}return M[x][y];}void print(char i){cout<<i;}void prin(){//用来打印输入串int j = i;for(;input[j] != '\0';j++)cout<<input[j];}void pro(char a,char in){//分析程序if(a == in)if(a == '#'){flag = false;cout<<"分析已全部完成"<<endl;return;}else{i++;analysis.pop_back();for_each( analysis.begin(), analysis.end(),print);cout<<"\t\t";prin();cout<<"\t\t"<<"\t\t"<<"GETNEXT(I)"<<endl;return;}else{string expre = reference(a,in);analysis.pop_back();//出栈int j = expre.size() - 1;while(expre[j] != '>'){analysis.push_back(expre[j]);j--;}for_each( analysis.begin(), analysis.end(),print);cout<<"\t\t";prin();if(expre.length()>3)cout<<"\t\t"<<expre<<"\t\t"<<"POP,PUSH("<<expre<<")"<<endl;elsecout<<"\t\t"<<expre<<"\t\t"<<"POP"<<endl;}int main(){M[0][0] = "E->TG";M[0][6] = "E->TG";M[1][0] = "T->FS";M[1][6] = "T->FS";M[2][0] = "F->(E)";M[2][6] = "F->i";M[3][1] = "G->";M[3][2] = "G->+TG";M[3][3] = "G->-TG";M[3][7] = "G->";M[4][1] = "S->";M[4][2] = "S->";M[4][3] = "S->";M[4][4] = "S->*FS";M[4][5] = "S->/FS";M[4][7] = "S->";analysis.push_back('#');analysis.push_back('E');cout<<"输入语句,以#结束:";cin>>input;cout<<"分析栈"<<"\t\t"<<"剩余输入串"<<"\t"<<"所用产生式"<<"\t"<<"动作"<<endl;for_each( analysis.begin(), analysis.end(),print);cout<<"\t\t";prin();cout<<"\t\t"<<"\t\t"<<"初始化"<<endl;while(flag){pro(analysis.back(),input[i]);}return 0;}实验三源代码:#include <iostream>#include <string>#include <vector>#include <algorithm>using namespace std;string action[12][6] = {"S5","","","S4","","","","S6","","","","acc","","r2","S7","","r2","r2","","r4","r4","","r4","r4","S5","","","S4","","","","r6","r6","","r6","r6","S5","","","S4","","","S5","","","S4","","","","S6","","","S11","","","r1","S7","","r1","r1","","r3","r3","","r3","r3","","r5","S5","","r5","r5",};//定义动作表string grammer[6] = {"E->E+T","E->T","T->T*F","T->F","F->(E)","F->i"}; //文法int go[12][3];//定义转换表char input[50];//存放输入串int i = 0;bool flag = true;//判断是否成功vector<char> symbol;//定义分析表vector<int> status;//定义符号栈string referaction(int s,char i){//查询action表,a为分析栈顶的状态,i为输入串的符号int y;switch(i){case 'i':y = 0;break;case '+':y = 1;break;case '*':y = 2;break;case '(':y = 3;break;case ')':y = 4;break;case '#':y = 5;break;}return action[s][y];}int refergo(int s,char i){//查询go表int y;switch(i){case 'E':y = 0;break;case 'T':y = 1;break;case 'F':y = 2;break;}return go[s][y];}void printint(int n){cout<<n;}void printchar(char c){cout<<c;}void prin(){//用来打印输入串int j = i;for(;input[j] != '\0';j++)cout<<input[j];}void reduce(int n){//就近规约int j = grammer[n].size() - 3;while(j--){status.pop_back();symbol.pop_back();}symbol.push_back(grammer[n][0]);int stu = refergo(status.back(),symbol.back());cout<<grammer[n]<<"归约,GOTO("<<status.back()<<','<<symbol.back()<<")="<<stu<<" 入栈"<<endl;status.push_back(stu);}void analysis(int st,char in){string ac = referaction(st,in);if(ac[0] == 'S'){for_each(status.begin(),status.end(),printint); cout<<"\t\t";for_each(symbol.begin(),symbol.end(),printchar); cout<<"\t\t";prin();cout<<"\t\t";symbol.push_back(input[i]);int stat = ac[1] - 48;status.push_back(stat);i++;cout<<ac<<":状态"<<stat<<"入栈"<<endl;return;}if(ac[0] == 'r'){for_each(status.begin(),status.end(),printint); cout<<"\t\t";for_each(symbol.begin(),symbol.end(),printchar); cout<<"\t\t";prin();cout<<"\t\t";cout<<ac<<':';int g = ac[1] - 48 - 1;reduce(g);return;}if(ac == "acc"){for_each(status.begin(),status.end(),printint); cout<<"\t\t";for_each(symbol.begin(),symbol.end(),printchar); cout<<"\t\t";prin();cout<<"\t\t";cout<<"Acc:分析成功";flag = false;}}int main(){go[0][0] = 1;go[0][1] = 2;go[0][2] = 3;go[4][0] = 8;go[4][1] = 2;go[4][2] = 3;go[6][1] = 9;go[6][2] = 3;go[7][2] = 10;symbol.push_back('#');status.push_back(0);cout<<"输入语句,以#结束:";cin>>input;cout<<"状态栈"<<"\t\t"<<"符号栈"<<"\t\t"<<"剩余输入串"<<"\t"<<"动作"<<endl;while(flag){analysis(status.back(),input[i]);}return 0;}。