编译原理实践(实现减除语句)
编译原理实验报告总结

编译原理实验报告总结一、实验目的编译原理是计算机科学中的一门重要课程,通过实验可以更深入地理解编译过程的各个阶段,包括词法分析、语法分析、语义分析、中间代码生成、代码优化和目标代码生成等。
本次编译原理实验的目的主要有以下几点: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、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 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的值。