(编译原理)逆波兰式算法的源代码

(编译原理)逆波兰式算法的源代码
(编译原理)逆波兰式算法的源代码

(编译原理)逆波兰式算法的源代码

一.实验目的

1.深入理解算符优先分析法

2.掌握FirstVt和LastVt集合的求法有算符优先关系表的求法

3.掌握利用算符优先分析法完成中缀表达式到逆波兰式的转化

二.实验内容及要求

将非后缀式用来表示的算术表达式转换为用逆波兰式来表示的算术表达式,并计算用逆波兰式来表示的算术表达式的值。

程序输入/输出示例:

输出的格式如下:

(1)

(2)输入一以#结束的中缀表达式(包括+—*/()

数字#)

(3)

(4)逆波兰式

备注:(1)在生成的逆波兰式中如果两个数相连则用&分隔,如28和68,中间用&分隔;

串。

注意:1.表达式中允许使用运算符(+-*/)、分割符(括号)、数字,结束符#;

2.如果遇到错误的表达式,应输出错误提示信息

(该信息越详细越好);

3.对学有余力的同学,测试用的表达式事先放在

文本文件中,一行存放一个表达式,同时以分号分割。同时将预期的输出结果写在另一个文本文件中,以便和输出进行对照;

三.实验过程

1、逆波兰式定义

将运算对象写在前面,而把运算符号写在后面。用这种表示法表示的表达式也称做后缀式。逆波兰式的特点在于运算对象顺序不变,运算符号位置反映运算顺序。采用逆波兰式可以很好的表示简单算术表达式,其优点在于易于计算机处理表达式。

2、产生逆波兰式的前提

中缀算术表达式

3、逆波兰式生成的实验设计思想及算法

(1)首先构造一个运算符栈,此运算符在

栈内遵循越往栈顶优先级越高的原则。

(2)读入一个用中缀表示的简单算术表达

式,为方便起见,设该简单算术表达式的右端多加上了优先级最低的特殊符号“#”。

(3)从左至右扫描该算术表达式,从第一

个字符开始判断,如果该字符是数字,则分析到该数字串的结束并将该数字串直接输出。

(4)如果不是数字,该字符则是运算符,

此时需比较优先关系。

做法如下:将该字符与运算符栈顶的运算符的优先关系相比较。如果,该字符优先关系高于此运算符栈顶的运算符,则将该运算符入栈。倘若不是的话,则将此运算符栈顶的运算符从栈中弹出,将该字符入栈。

(5)重复上述操作(1)-(2)直至扫描完整个简单算

术表达式,确定所有字符都得到正确处理,我们便可以将中缀式表示的简单算术表达式转化为逆波兰表示的简单算术表达式。

3、逆波兰式计算的实验设计思想及算法

(1)构造一个栈,存放运算对象。

(2)读入一个用逆波兰式表示的简单算术表达式。

(3)自左至右扫描该简单算术表达式并判断该字符,如果该字符是运算对象,则将该字符入栈。若是运算符,如果此运算符是二目运算符,则将对栈顶部的两个运算对象进行该运算,将运算结果入栈,并且将执行该运算的两个运算对象从栈顶弹出。如果该字符是一目运算符,则对栈顶部的元素实施该运算,将该栈顶部的元素弹出,将运算结果入栈。

(4)重复上述操作直至扫描完整个简单算术表达式的逆波兰式,确定所有字符都得到正确处理,我们便可以求出该简单算术表达式的

值。

4.实验的源程序代码如下:

#include

#include

#define max 100

char ex[max]; /*存储后缀表达式*/ void trans(){ /*将算术表达式转化为后缀表达式*/

char str[max]; /*存储原算术表达式*/

char stack[max]; /*作为栈使用*/

char ch;

int sum,i,j,t,top=0;

printf("**************************** *************\n");

printf("*输入一个求值的表达式,以#结束。*\n");

printf("**************************** **************\n");

printf("算数表达式:");

i=0; /*获取用户输入的表达式*/

do{

i++;

scanf("%c",&str[i]);

}while(str[i]!='#' && i!=max);

sum=i;

t=1;i=1;

ch=str[i];i++;

while(ch!='#'){

switch(ch){

case '(': /*判定为左括号*/

top++;stack[top]=ch;

break;

case ')': /*判定为右括号*/

while(stack[top]!='('){

ex[t]=stack[top];top--;t++;

}

top--;

break;

case '+': /*判定为加减号*/

case '-':

while(top!=0&&stack[top]!='('){

ex[t]=stack[top];top--;t++;

}

top++;stack[top]=ch;

break;

case '*': /*判定为乘除号*/

case '/':

while(stack[top]=='*'||stack[top]=='/'){

ex[t]=stack[top];top--;t++;

}

top++;stack[top]=ch;

break;

case ' ':break;

default:while(ch>='0'&&ch<='9'){

/*判定为数字*/

ex[t]=ch;t++;

ch=str[i];i++;

}

i--;

ex[t]='#';t++;

}

ch=str[i];i++;

}

while(top!=0){

ex[t]=stack[top];t++;top--;

}

ex[t]='#';

printf("\n\t原来表达式:");

for(j=1;j

printf("%c",str[j]);

printf("\n\t后缀表达式:",ex);

for(j=1;j

printf("%c",ex[j]);

}

void

compvalue(){

/*计算后缀表达式的值*/

float stack[max],d; /*作为栈使用*/

char ch;

int t=1,top=0; /*t为ex下标,top为stack下标*/

ch=ex[t];t++;

while(ch!='#'){

switch(ch){

case '+':

stack[top-1]=stack[top-1]+stack[top];

top--;

break;

case '-':

stack[top-1]=stack[top-1]-stack[top];

top--;

break;

case '*':

stack[top-1]=stack[top-1]*stack[top];

top--;

break;

case '/':

if(stack[top]!=0)

stack[top-1]=stack[top-1]/stack[top];

else{

printf("\n\t除零错误!\n");

exit(0);

/*异常退出*/

}

top--;

break;

default:

d=0;

while(ch>='0'&&ch<='9'){

d=10*d+ch-'0';

/*将数字字符转化为对应的数值*/

ch=ex[t];t++;

}

top++;

stack[top]=d;

}

ch=ex[t];t++;

}

printf("\n\t计算结果:%g\n",stack[top]);

}

main(){

trans();

compvalue();

}

5.程序的运行结果如下:

四.实验总结(心得)

通过本实验的学习,主要掌握了逆波兰式算法的含义,结合书本知识,让我更加清楚此算法实现的主要过程,以及使用该算法的好处,通过对程序实现的分析,对于逆波兰式算法的细节了解的更加清楚,从中学到了很多的东西。

语法制导把表达式翻译成逆波兰式

实验报告成绩:指导教师审核(签名):年月日 预习报告□实验报告□ 语法制导把表达式翻译成逆波兰式 (一)实验目的 进一步掌握语法制导翻译的概念,理解中间语言,设计出错处理程序方法,掌握把表达式翻译成中间语言的算法。 (二)实验内容 1.从左到右扫描中缀表达式,经语法分析找出中缀表达式出现的错误并给出错误的具体位置和类型。一个运算符栈存放暂时不能出现的运算符,逆波兰区存放逆波兰表达式。 2.测试所编程序,给出正确和错误的结果。 (三)实验要求 1.学生课前要认真阅读实验指导,理解实验内容与相关理论知识的关系,并完成预习报告 2.用C语言或其它高级语言编写程序 3.写出实验报告

实验报告成绩:指导教师审核(签名):年月日 预习报告□实验报告□ 语法制导把表达式翻译成逆波兰式 (一)实验目的 通过上机实习加深对语法指导翻译原理的理解,掌握运算符优先权的算法,将语法分析所识别的表达式变换成中间代码的翻译方法。 (二)实验内容 同预习报告 (三)实验要求 1.学生课前要认真阅读实验指导,理解实验内容与相关理论知识的关系,并完成预习报告 2.用C语言或其它高级语言编写程序 3.写出实验报告 (四)实验设计思路 1)表达式生成逆波兰式的算法 1、初始化△送到运算符栈。 2、扫描左括号“(”,把△送到运算符栈。 3、扫描到变量,把它送到逆波兰区。 4、扫描到运算符 ( 1)栈内运算符比较 a.栈内运算符>=栈外运算符,把栈内运算符送到逆波兰区。 b.栈内运算符<栈外运算符,把栈外运算符入栈。 ( 2 ) 栈内是△把运算符入栈。 5、扫描右括号“)”。 ( 1 )栈内是运算符,把栈内运算符送到逆波兰区。 ( 2 )栈内是△则△退栈,读入下一个字符。 6、扫描到#(结束符) ( 1 )栈内是运算符,把栈内运算符送到逆波兰区。 ( 2 )栈内是△结束,否则继续分析。

(编译原理)逆波兰式算法的源代码

一.实验目的 1.深入理解算符优先分析法 2.掌握FirstVt和LastVt集合的求法有算符优先关系表的求法 3.掌握利用算符优先分析法完成中缀表达式到逆波兰式的转化 二.实验内容及要求 将非后缀式用来表示的算术表达式转换为用逆波兰式来表示的算术表达式,并计算用逆波兰式来表示的算术表达式的值。 程序输入/输出示例: 输出的格式如下: (1) (2)输入一以#结束的中缀表达式(包括+—*/()数字#) (3) (4)逆波兰式 备注:(1)在生成的逆波兰式中如果两个数相连则用&分隔,如28和68,中间用&分隔; 注意:1.表达式中允许使用运算符(+-*/)、分割符(括号)、数字,结束符#; 2.如果遇到错误的表达式,应输出错误提示信息(该信息越详细越好); 3.对学有余力的同学,测试用的表达式事先放在文本文件中,一行存放一个表达式,同时以分号分割。同时将预期的输出结果写在另一个文本文件中,以便和输出进行对照; 三.实验过程 1、逆波兰式定义 将运算对象写在前面,而把运算符号写在后面。用这种表示法表示的表达式也称做后缀式。逆波兰式的特点在于运算对象顺序不变,运算符号位置反映运算顺序。采用逆波兰式可以很好的表示简单算术表达式,其优点在于易于计算机处理表达式。 2、产生逆波兰式的前提 中缀算术表达式 3、逆波兰式生成的实验设计思想及算法

(1)首先构造一个运算符栈,此运算符在栈内遵循越往栈顶优先级越高的原则。 (2)读入一个用中缀表示的简单算术表达式,为方便起见,设该简单算术表达式的右端多加上了优先级最低的特殊符号“#”。 (3)从左至右扫描该算术表达式,从第一个字符开始判断,如果该字符是数字,则分析到该数字串的结束并将该数字串直接输出。 (4)如果不是数字,该字符则是运算符,此时需比较优先关系。 做法如下:将该字符与运算符栈顶的运算符的优先关系相比较。如果,该字符优先关系高于此运算符栈顶的运算符,则将该运算符入栈。倘若不是的话,则将此运算符栈顶的运算

编译原理复习题(经典)

编译原理复习题 一、是非题 1.计算机高级语言翻译成低级语言只有解释一种方式。(×) 3.每个文法都能改写为 LL(1) 文法。 (×) 4.算符优先关系表不一定存在对应的优先函数。 (√) 5.LR分析方法是自顶向下语法分析方法。 (×) 6.“用高级语言书写的源程序都必须通过编译,产生目标代码后才能投入运行”这种说法。(× ) 7.一个句型的句柄一定是文法某产生式的右部。 (√) 8.仅考虑一个基本块,不能确定一个赋值是否真是无用的。 (√ ) 9.在中间代码优化中循环上的优化主要有不变表达式外提和削减运算强度。 (× ) 10.对于数据空间的存贮分配,FORTRAN采用动态贮存分配策略。(×) 11.甲机上的某编译程序在乙机上能直接使用的必要条件是甲机和乙机的操作系统功能完全相同。(× ) 12.递归下降分析法是自顶向下分析方法。(√ ) 13.产生式是用于定义词法成分的一种书写规则。 (×) 14.在 SLR(1)分析法的名称中,S的含义是简单的。(√) 15.综合属性是用于“自上而下”传递信息。(× ) 16.符号表中的信息栏中登记了每个名字的属性和特征等有关信息,如类型、种属、所占单元大小、地址等等。(×) 17.程序语言的语言处理程序是一种应用软件。 (×) 18.解释程序适用于 COBOL 和 FORTRAN 语言。 (×) 19.一个 LL(l)文法一定是无二义的。 (√) 20.正规文法产生的语言都可以用上下文无关文法来描述。 (√) 21.一张转换图只包含有限个状态,其中有一个被认为是初态,最多只有一个终态。 (×) 22.目标代码生成时,应考虑如何充分利用计算机的寄存器的问题。 (√) 22.逆波兰法表示的表达式亦称后缀式。 (√ ) 23.如果一个文法存在某个句子对应两棵不同的语法树,则称这个文法是二义的。 (√ ) 24.数组元素的地址计算与数组的存储方式有关。(√) 25.算符优先关系表不一定存在对应的优先函数。 (×) 26.编译程序是对高级语言程序的解释执行。(× ) 27.一个有限状态自动机中,有且仅有一个唯一的终态。(×) 28.一个算符优先文法可能不存在算符优先函数与之对应。 (√ ) 29.语法分析时必须先消除文法中的左递归。 (×) 30.LR分析法在自左至右扫描输入串时就能发现错误,但不能准确地指出出错地点。 (√) 31.逆波兰表示法表示表达式时无须使用括号。 (√ ) 32.静态数组的存储空间可以在编译时确定。 (√) 33.进行代码优化时应着重考虑循环的代码优化,这对提高目标代码的效率将起更大作用。 (√) 34.两个正规集相等的必要条件是他们对应的正规式等价。 (√) 35.一个语义子程序描述了一个文法所对应的翻译工作。 (×) 36.设r和s分别是正规式,则有L(r|s)=L(r)L(s)。(×) 37.确定的自动机以及不确定的自动机都能正确地识别正规集。(√) 38.词法分析作为单独的一遍来处理较好。 (× ) 39.构造LR分析器的任务就是产生LR分析表。 (√) 40.规范归约和规范推导是互逆的两个过程。 (√) 41.同心集的合并有可能产生新的“移进”/“归约”冲突。 (× ) 42.LR分析技术无法适用二义文法。 (× )

编译原理-逆波兰式的产生及计算

编译原理上机报告 名称:逆波兰式的产生及计算 学院:信息与控制工程学院 专业:计算机科学与技术 班级:计算机1401班 姓名:叶达成 2016年11月4日

一、上机目的 通过设计、编制、调试一个典型的语法分析程序,实现对词法分析程序所提供的单词序列进行语法检查和结构分析,进一步掌握常用的语法分析方法。 1、选择最有代表性的语法分析方法,如LL(1) 语法分析程序、算符优先分析程序和LR分析分析程序,并至少完成两个题目。 2、选择对各种常见程序语言都用的语法结构,如赋值语句(尤指表达式)作为分析对象,并且与所选语法分析方法要比较贴切。 ⑴实验前的准备 按实验的目的和要求,编写语法分析程序,同时考虑相应的数据结构。 ⑵调试 调试例子应包括符合语法规则的算术表达式,以及分析程序能够判别的若干错例。 ⑶输出 对于所输入的算术表达式,不论对错,都应有明确的信息告诉外界。 ⑷扩充 有余力的同学,可适当扩大分析对象。譬如: ①算术表达式中变量名可以是一般标识符,还可含一般常数、数组元素、函数调用等等。 ②除算术表达式外,还可扩充分析布尔、字符、位等不同类型的各种表达式。③加强语法检查,尽量多和确切地指出各种错误。 二、基本原理和上机步骤 基本原理: 将运算对象写在前面,而把运算符号写在后面。用这种表示法表示的表达式也称做后缀式。逆波兰式的特点在于运算对象顺序不变,运算符号位置反映运算顺序。采用逆波兰式可以很好的表示简单算术表达式,其优点在于易于计算机处理表达式。 上机步骤: (1)构造一个栈,存放运算对象。 (2)读入一个用逆波兰式表示的简单算术表达式。 (3)自左至右扫描该简单算术表达式并判断该字符,如果该字符是运算对象,则将该字符入栈。若是运算符,如果此运算符是二目运算符,则将对栈顶部的两个运算对象进行该运算,将运算结果入栈,并且将执行该运算的两个运算对象从栈顶弹出。如果该字符是一目运算符,则对栈顶部的元素实施该运算,将该栈顶部的元素弹出,将运算结果入栈。 (4)重复上述操作直至扫描完整个简单算术表达式的逆波兰式,确定所有字符都得到正确处理,我们便可以求出该简单算术表达式的值。 三、上机结果 程序清单: #include #include #include #include #include #include using namespace std;

编译原理知识点汇总

编译原理的复习提纲 1.编译原理=形式语言+编译技术 2.汇编程序: 把汇编语言程序翻译成等价的机器语言程序 3.编译程序: 把高级语言程序翻译成等价的低级语言程序 4.解释执行方式: 解释程序,逐个语句地模拟执行 翻译执行方式: 翻译程序,把程序设计语言程序翻译成等价的目标程序 5.计算机程序的编译过程类似,一般分为五个阶段: 词法分析、语法分析、语义分析及中间代码生成、代码优化、目标代码生成 词法分析的任务: 扫描源程序的字符串,识别出的最小的语法单位(标识符或无正负号数等) 语法分析是: 在词法分析的基础上的,语法分析不考虑语义。语法分析读入词法分析程序识别出的符号,根据给定的语法规则,识别出各个语法结构。 语义分析的任务是检查程序语义的正确性,解释程序结构的含义,语义分析包括检查变量是否有定义,变量在使用前是否具有值,数值是否溢出等。

语法分析完成之后,编译程序通常就依据语言的语义规则,利用语法制导技术把源程序翻译成某种中间代码。所谓中间代码是一种定义明确、便于处理、独立于计算机硬件的记号系统,可以认为是一种抽象机的程序 代码优化的主要任务是对前一阶段产生的中间代码进行等价变换,以便产生速度快、空间小的目标代码 编译的最后一个阶段是目标代码生成,其主要任务是把中间代码翻译成特定的机器指令或汇编程序 编译程序结构包括五个基本功能模块和两个辅助模块 6.编译划分成前端和后端。 编译前端的工作包括词法分析、语法分析、语义分析。编译前端只依赖于源程序,独立于目标计算机。前端进行分析 编译后端的工作主要是目标代码的生成和优化后端进行综合。独立于源程序,完全依赖于目标机器和中间代码。 把编译程序分为前端和后端的优点是: 可以优化配置不同的编译程序组合,实现编译重用,保持语言与机器的独立性。 7.汇编器把汇编语言代码翻译成一个特定的机器指令序列 第二章 1.符号,字母表,符号串,符号串的长度计算P18,子符号串的含义,符号串的简单运算XY,Xn, 2.符号串集合的概念,符号串集合的乘积运算,方幂运算,闭包与正闭包的概念P19,P20A0 ={ε} 3.重写规则,简称规则。非xx(V

(完整版)编译原理课后习题答案

第一章 1.典型的编译程序在逻辑功能上由哪几部分组成? 答:编译程序主要由以下几个部分组成:词法分析、语法分析、语义分析、中间代码生成、中间代码优化、目标代码生成、错误处理、表格管理。 2. 实现编译程序的主要方法有哪些? 答:主要有:转换法、移植法、自展法、自动生成法。 3. 将用户使用高级语言编写的程序翻译为可直接执行的机器语言程序有哪几种主要的方式? 答:编译法、解释法。 4. 编译方式和解释方式的根本区别是什么? 答:编译方式:是将源程序经编译得到可执行文件后,就可脱离源程序和编译程序单独执行,所以编译方式的效率高,执行速度快; 解释方式:在执行时,必须源程序和解释程序同时参与才能运行,其不产生可执行程序文件,效率低,执行速度慢。

第二章 1.乔姆斯基文法体系中将文法分为哪几类?文法的分类同程序设计语言的设计与实现关 系如何? 答:1)0型文法、1型文法、2型文法、3型文法。 2) 2. 写一个文法,使其语言是偶整数的集合,每个偶整数不以0为前导。 答: Z→SME | B S→1|2|3|4|5|6|7|8|9 M→ε | D | MD D→0|S B→2|4|6|8 E→0|B 3. 设文法G为: N→ D|ND D→ 0|1|2|3|4|5|6|7|8|9 请给出句子123、301和75431的最右推导和最左推导。 答:N?ND?N3?ND3?N23?D23?123 N?ND?NDD?DDD?1DD?12D?123 N?ND?N1?ND1?N01?D01?301 N?ND?NDD?DDD?3DD?30D?301 N?ND?N1?ND1?N31?ND31?N431?ND431?N5431?D5431?75431 N?ND?NDD?NDDD?NDDDD?DDDDD?7DDDD?75DDD?754DD?7543D?75431 4. 证明文法S→iSeS|iS| i是二义性文法。 答:对于句型iiSeS存在两个不同的最左推导: S?iSeS?iiSes S?iS?iiSeS 所以该文法是二义性文法。 5. 给出描述下面语言的上下文无关文法。 (1)L1={a n b n c i |n>=1,i>=0 } (2)L2={a i b j|j>=i>=1} (3)L3={a n b m c m d n |m,n>=0} 答: (1)S→AB A→aAb | ab B→cB | ε (2)S→ASb |ab

编译原理-实验报告4-逆波兰

计算机硬件实验室实验报告 姓名学号班级成绩 设备名称及软件环境逆波兰 一、实验目的: 将非后缀式用来表示的算术表达式转换为用逆波兰式来表示的算术表达式,并计算用逆波兰式来表示的算术表达式的值。 二、实验要求: 输出的格式如下: (1)逆波兰式的生成及计算程序,编制人:姓名,学号,班级 (2)输入一以#结束的中缀表达式(包括+—*/()数字#):在此位置输入符 号串如(28+68)*2# (3)逆波兰式为:28&68+2* (4)逆波兰式28&68+2*计算结果为192 备注:(1)在生成的逆波兰式中如果两个数相连则用&分隔,如28和68,中间用&分隔; (2)在此位置输入符号串为用户自行输入的符号串。 注意: 1.表达式中允许使用运算符(+-*/)、分割符(括号)、数字,结束符#; 2.如果遇到错误的表达式,应输出错误提示信息(该信息越详细越好); 三、实验过程: (一)准备: 1.阅读课本有关章节, 2.考虑好设计方案; 3.设计出模块结构、测试数据,初步编制好程序。 (1)定义部分:定义常量、变量、数据结构。 (2)初始化:设立算符优先分析表、初始化变量空间(包括堆栈、结构体、数组、临时变量等); (3)控制部分:从键盘输入一个表达式符号串; (4)利用算符优先分析算法进行表达式处理:根据算符优先分析表对表达式符号串进行堆栈(或其他)操作,输出分析结果,如果遇到错误则显示错误信息。 (5)对生成的逆波兰式进行计算。 (二)上课上机: 将源代码拷贝到机上调试,发现错误,再修改完善。第二次上机调试通过。 四、实验结果 (1)写出程序流程图 (2)给出运行结果

程序: #include #include #include #define max 100 char ex[max]; /*存储后缀表达式*/ void trans(){ /*将算术表达式转化为后缀表达式*/ char str[max]; /*存储原算术表达式*/ char stack[max]; /*作为栈使用*/ char ch; int sum,i,j,t,top=0; // printf("*****************************************\n"); printf("逆波兰式的生成及计算程序,编制人:武普泉,20号,1020562班\n"); printf("输入一以#结束的中缀表达式(包括+ - * /()数字# ):"); // printf("******************************************\n"); // printf("算数表达式:"); i=0; /*获取用户输入的表达式*/ do{ i++; scanf("%c",&str[i]); }while(str[i]!='#' && i!=max); sum=i; t=1;i=1; ch=str[i];i++; while(ch!='#'){ switch(ch){ case '(': /*判定为左括号*/ top++;stack[top]=ch; break; case ')': /*判定为右括号*/ while(stack[top]!='('){ ex[t]=stack[top];top--;t++; } top--; break; case '+': /*判定为加减号*/ case '-': while(top!=0&&stack[top]!='('){ ex[t]=stack[top];top--;t++; } top++;stack[top]=ch; break; case '*': /*判定为乘除号*/ case '/':

编译原理(PL0编译程序源代码)

/*PL/0编译程序(C语言版) *编译和运行环境: *Visual C++6.0 *WinXP/7 *使用方法: *运行后输入PL/0源程序文件名 *回答是否将虚拟机代码写入文件 *回答是否将符号表写入文件 *执行成功会产生四个文件(词法分析结果.txt符号表.txt虚拟代码.txt源程序和地址.txt) */ #include #include"pl0.h" #include"string" #define stacksize 500//解释执行时使用的栈 int main(){ bool nxtlev[symnum]; printf("请输入源程序文件名:"); scanf("%s",fname); fin=fopen(fname,"r");//以只读方式打开pl0源程序文件 cifa=fopen("词法分析结果.txt","w"); fa1=fopen("源程序和地址.txt","w");//输出源文件及各行对应的首地址 fprintf(fa1,"输入pl0源程序文件名:"); fprintf(fa1,"%s\n",fname); if(fin){ printf("是否将虚拟机代码写入文件?(Y/N)");//是否输出虚拟机代码 scanf("%s",fname); listswitch=(fname[0]=='y'||fname[0]=='Y'); printf("是否将符号表写入文件?(Y/N)");//是否输出符号表scanf("%s",fname); tableswitch=(fname[0]=='y'||fname[0]=='Y'); init();//初始化 err=0; cc=cx=ll=0; ch=' '; if(-1!=getsym()){ fa=fopen("虚拟代码.txt","w"); fas=fopen("符号表.txt","w"); addset(nxtlev,declbegsys,statbegsys,symnum); nxtlev[period]=true; if(-1==block(0,0,nxtlev)){//调用编译程序 fclose(fa); fclose(fa1); fclose(fas); fclose(fin); return 0; } if(sym!=period){ error(9);//结尾丢失了句号 }

中缀表达式转逆波兰式并求值

中缀表达式转逆波兰式并求值 // 标题: 栈的应用——中缀表达式转逆波兰式 // 时间: 2015年4月14日// 所有者: Vae #include #include #include #include #include #define STACK_INIT_SIZE 100 #define STACKCREATE 10 #define OK 1 #define ERROR 0 typedef struct double_stack { int *num; int *index; }DOUBLESTACK; typedef struct SqStack { DOUBLESTACK top; DOUBLESTACK base; int stacksize; }SqStack; // 函数名: InitStack // 形参类型: SqStack * // 函数功能构造一个栈void InitStack(SqStack *S) { S->base.index = (int *)malloc(sizeof(int)*STACK_INIT_SIZE);

S->base.num = (int *)malloc(sizeof(int)*STACK_INIT_SIZE); if (!(S->base.num && S->base.index)) { printf("构造栈失败!\n"); exit(-1); } S->top.num = S->base.num; S->top.index = S->base.index; S->stacksize = STACK_INIT_SIZE; return ; } // 函数名: Push // 形参类型: SqStack *, int, int // 函数功能插入e为新的栈顶元素int Push(SqStack *S, int m, int n) { if ((S->top.num - S->base.num) >= S->stacksize) { S->base.index = (int *)realloc(S- >base.index,sizeof(int)*(STACK_INIT_SIZE+STACKCREATE)); S->base.num = (int *)realloc(S- >base.num,sizeof(int)*(STACK_INIT_SIZE+STACKCREATE)); if (!(S->base.num || S->base.index))

逆波兰式

塔里木大学信息工程学院 论文 编译原理课程设计 课目:编译原理 学生姓名:\ 学号: 学生姓名 学号: 所属学院:信息工程学院 班级:

设计任务书 指导教师(签章): 年月日

摘要: 编译原理是计算机科学与技术专业最重要的一门专业基础课程,内容庞大,涉及面广,知识点多。编译原理旨在介绍编译程序构造的一般原理和基本方法。内容包括语言和文法、词法分析、语法分析、语法制导翻译、中间代码生成、存储管理、代码优化和目标代码生成。它是计算机科学与技术专业最重要的一门专业基础课程,内容庞大,涉及面广,知识点多。由于该课程教、学难度都非常大,往往费了大量时间而达不到预期教学效果俗语说:学习的最好方法是实践。本课程设计正是基于此,力求为学生提供一个理论联系实际的机会,通过布置一定难度的课题,要求学生独立完成。我们这次课程设计的主要任务是编程实现对输入合法的中缀表达式进行词法分析、语法分析,构造相应的逆波兰式,计算后缀表达式的值输出结果。比如中缀表达式:C*(E+F),其后缀表达式为:CEF+*。逆波兰式也叫后缀表达式,即将运算符写在操作数之后。通过实践,建立系统设计的整体思想,锻炼编写程序、调试程序的能力,学习文档编写规范,培养独立学习、吸取他人经验、探索前言知识的习惯,树立团队协作精神。同时,课程设计可以充分弥补课堂教学及普通实验中知识深度与广度有限的缺陷,更好地帮助学生从全局角度把握课程体系。 关键字:逆波兰式;语法分析;中缀表达式

1 课设综述 1.1 课设来源 在通常的表达式中,二元运算符总是置于与之相关的两个运算对象之间,所以,这种表示法也称为中缀表示。对中缀表达式的计值,并非按运算符出现的自然顺序来执行其中的各个运算,而是根据算符间的优先关系来确定运算的次序,此外,还应顾及括号规则。因此,要从中缀表达式直接产生目标代码一般比较麻烦。相对的,逆波兰式在计算机看来却是比较简单易懂的结构。因为计算机普遍采用的内存结构是栈式结构,它执行先进后出的顺序。 1.2 设计意义 对于实现逆波兰式算法,难度并不大,但为什么要将看似简单的中缀表达式转换为逆波兰式,原因就在于这个简单是相对人类的思维结构来说的,对计算机而言中缀表达式是非常复杂的结构。相对的,逆波兰式在计算机看来却是比较简单易懂的结构。因为计算机普遍采用的内存结构是栈式结构,它执行先进后出的顺序。在逆波兰式中,不存在运算符的优先级问题,也不存在任何括号,计算的顺序完全按照运算符出现的先后次序进行。比中缀表达式的求值要简单得多。1.3 设计目标 编写程序,实现逆波兰式的生成和计算。首先对输入的表达式进行词法分析,然后进行语法分析,最后进行逆波兰式的输出和计算。过实践,建立系统设计的整体思想,锻炼编写程序、调试程序的能力,学习文档编写规范,培养独立学习、吸取他人经验、探索知识的习惯。 1.4 遇到的问题 如何通过递归下降方法分析表达式,并且输出词法分析、语法分析过程及结果。如何实现把中缀表达式转换成后缀表达式,并计算表达式的结果。 1.5 需解决的关键技术 本次课程设计中的关键是:通过递归下降方法分析表达式,主要有词法分析和语法分析,输出分析结果,判断表达式是否合法。如何确定操作符的优先顺序,确定数据的进栈及出栈顺序,根据后缀表达式计算表达式的结果。以及如何编写、调试、修改代码。还要了解一个题目有许多种解决方法。锻炼我们的思维能力。

编译原理波兰式和四元式

实验三波兰式和四元式及计算 课程编译原理实验名称波兰式和四元式第页班级11计本学号姓名 实验日期:2013年月日报告退发(订正、重做) 一、实验目的: 将非后缀式用来表示的算术表达式转换为用逆波兰式来表示的算术表达式,并计算用逆波兰式来表示的算术表达式的值。 二、实验说明 1、逆波兰式定义 将运算对象写在前面,而把运算符号写在后面。用这种表示法表示的表达式也称做后缀式。逆波兰式的特点在于运算对象顺序不变,运算符号位置反映运算顺序。采用逆波兰式可以很好的表示简单算术表达式,其优点在于易于计算机处理表达式。 2、产生逆波兰式的前提 中缀算术表达式 3、逆波兰式生成的实验设计思想及算法

(1)首先构造一个运算符栈,此运算符在栈内遵循越往栈顶优先级越高的原则。 (2)读入一个用中缀表示的简单算术表达式,为方便起见,设该简单算术表达式的右端多加上了优先级最低的特殊符号“#”。 (3)从左至右扫描该算术表达式,从第一个字符开始判断,如果该字符是数字,则分析到该数字串的结束并将该数字串直接输出。 (4)如果不是数字,该字符则是运算符,此时需比较优先关系。 做法如下:将该字符与运算符栈顶的运算符的优先关系相比较。如果,该字符优先关系高于此运算符栈顶的运算符,则将该运算符入栈。倘若不是的话,则将此运算符栈顶的运算符从栈中弹出,将该字符入栈。 (5)重复上述操作(1)-(2)直至扫描完整个简单算术表达式,确定所有字符都得 到正确处理,我们便可以将中缀式表示的简单算术表达式转化为逆波兰表示的简单算术表达式。 3、逆波兰式计算的实验设计思想及算法 (1)构造一个栈,存放运算对象。 (2)读入一个用逆波兰式表示的简单算术表达式。 (3)自左至右扫描该简单算术表达式并判断该字符,如果该字符是运算对 象,则将该字符入栈。若是运算符,如果此运算符是二目运算符,则将对栈顶部的两个运算对象进行该运算,将运算结果入栈,并且将执行该运算的两个运算对象从栈顶弹出。如果该字符是一目运算符,则对栈顶部的元素实施该运算,将该栈顶部的元素弹出,将运算结果入栈。 (4)重复上述操作直至扫描完整个简单算术表达式的逆波兰式,确定所有 字符都得到正确处理,我们便可以求出该简单算术表达式的值。

编译原理第三版附带的实验源码

Scanner: #include #include #include #define _KEY_WORD_END "waiting for your expanding" typedef struct { int typenum; char * word; } WORD; char input[255]; char token[255]=""; int p_input; int p_token; char ch; char* KEY_WORDS[]={"main","int","char","if","else","for","while",_KEY_WORD_END}; WORD* scaner(); void main() { int over=1; WORD* oneword=new WORD; printf("Enter Your words(end with $):"); scanf("%[^$]s",input); p_input=0; printf("Your words:\n%s\n",input); while(over<1000&&over!=-1){ oneword=scaner(); if(oneword->typenum<1000) printf("(%d,%s)",oneword->typenum,oneword->word); over=oneword->typenum; } printf("\npress # to exit:"); scanf("%[^#]s",input); } char m_getch(){ ch=input[p_input]; p_input=p_input+1; return (ch); } void getbc(){

编译原理-逆波兰式的产生及计算

学号07 成绩 编译原理上机报告 名称:逆波兰式的产生及计算 学院:信息与控制工程学院 专业:计算机科学与技术 班级:计算机1401班 姓名:叶达成 2016年11月4日

一、上机目的 通过设计、编制、调试一个典型的语法分析程序,实现对词法分析程序所提供的单词序列进行语法检查和结构分析,进一步掌握常用的语法分析方法。 1、选择最有代表性的语法分析方法,如LL(1) 语法分析程序、算符优先分析程序和LR分析分析程序,并至少完成两个题目。 2、选择对各种常见程序语言都用的语法结构,如赋值语句(尤指表达式)作为分析对象,并且与所选语法分析方法要比较贴切。 ⑴实验前的准备 按实验的目的和要求,编写语法分析程序,同时考虑相应的数据结构。 ⑵调试 调试例子应包括符合语法规则的算术表达式,以及分析程序能够判别的若干错例。 ⑶输出 对于所输入的算术表达式,不论对错,都应有明确的信息告诉外界。 ⑷扩充 有余力的同学,可适当扩大分析对象。譬如: ①算术表达式中变量名可以是一般标识符,还可含一般常数、数组元素、函数调用等等。 ②除算术表达式外,还可扩充分析布尔、字符、位等不同类型的各种表达式。③加强语法检查,尽量多和确切地指出各种错误。 二、基本原理和上机步骤 基本原理: 将运算对象写在前面,而把运算符号写在后面。用这种表示法表示的表达式也称做后缀式。逆波兰式的特点在于运算对象顺序不变,运算符号位置反映运算顺序。采用逆波兰式可以很好的表示简单算术表达式,其优点在于易于计算机处理表达式。 上机步骤: (1)构造一个栈,存放运算对象。 (2)读入一个用逆波兰式表示的简单算术表达式。 (3)自左至右扫描该简单算术表达式并判断该字符,如果该字符是运算对象,则将该字符入栈。若是运算符,如果此运算符是二目运算符,则将对栈顶部的两个运算对象进行该运算,将运算结果入栈,并且将执行该运算的两个运算对象从栈顶弹出。如果该字符是一目运算符,则对栈顶部的元素实施该运算,将该栈顶部的元素弹出,将运算结果入栈。 (4)重复上述操作直至扫描完整个简单算术表达式的逆波兰式,确定所有字符都得到正确处理,我们便可以求出该简单算术表达式的值。 三、上机结果 程序清单: #include #include<> #include<> #include #include #include using namespace std;

编译原理习题答案

《编译原理》习题答案: 第一次: P14 2、何谓源程序、目标程序、翻译程序、汇编程序、编译程序和解释程序?它们之间可能有何种关系? 答:被翻译的程序称为源程序; 翻译出来的程序称为目标程序或目标代码; 将汇编语言和高级语言编写的程序翻译成等价的机器语言,实现此功能的程序称为翻译程序; 把汇编语言写的源程序翻译成机器语言的目标程序称为汇编程序; 解释程序不是直接将高级语言的源程序翻译成目标程序后再执行,而是一个个语句读入源程序,即边解释边执行; 编译程序是将高级语言写的源程序翻译成目标语言的程序。 关系:汇编程序、解释程序和编译程序都是翻译程序,具体见P4 图 1.3。 P14 3、编译程序是由哪些部分组成?试述各部分的功能? 答:编译程序主要由8个部分组成:(1)词法分析程序;(2)语法分析程序;(3)语义分析程序;(4)中间代码生成;(5)代码优化程序;(6)目标代码生成程序;(7)错误检查和处理程序;(8)信息表管理程序。具体功能见P7-9。 P14 4、语法分析和语义分析有什么不同?试举例说明。 答:语法分析是将单词流分析如何组成句子而句子又如何组成程序,看句子乃至程序是否符合语法规则,例如:对变量 x:= y 符合语法规则就通过。语义分析是对语句意义进行检查,如赋值语句中x与y类型要一致,否则语法分析正确,语义分析则错误。 P15 5、编译程序分遍由哪些因素决定? 答:计算机存储容量大小;编译程序功能强弱;源语言繁简;目标程序优化程度;设计和实现编译程序时使用工具的先进程度以及参加人员多少和素质等等。 补充: 1、为什么要对单词进行内部编码?其原则是什么?对标识符是如何进行内部编码的? 答:内部编码从“源字符串”中识别单词并确定单词的类型和值;原则:长度统一,即刻画了单词本身,也刻画了它所具有的属性,以供其它部分分析使用。对于标识符编码,先判断出该单词是标识符,然后在类别编码中写入相关信息,以表示为标识符,再根据具体标识符的含义编码该单词的值。 补充: 2、赋值语句: A:= 5 * C的语法和语义指的是什么? 答:语法分析将检查该语句是否符合赋值语句规则,语义是指将 5 * C 的结果赋值为 A 。

后缀表达式的算法和实现

数据结构—中缀表达式转后缀表达式算法及实现—栈的应用—计算表达式(C++代... 理论:(这部分很重要,看明白了,可以写出实现算法) 表达式的表示形式有中缀、前缀和后缀3中形式。中缀表达式按操作符的优先级进行计算(后面代码实现只包括+、-、*、\,小括号),即数学运算。后缀表达式中只有操作数和操作符。操作符在两个操作数之后。它的计算规则非常简单,严格按照从左到右的次序依次执行每一个操作。每遇到一个操作符,就将前面的两个数执行相应的操作。 由后缀表达式计算中缀表达式原理:计算机处理后缀表达式求值问题是比较方便的,即将遇到的操作数暂存于一个操作数栈中,凡是遇到操作数,便从栈中pop出两个操作数,并将结果存于操作数栈中,直到对后缀表达式中最后一个操作数处理完,最后压入栈中的数就是后最表达式的计算结果。 中缀表达式转换为等价的后缀表达式 中缀表达式不方便与计算机处理,通常要讲中缀表达式转换为一个与之等价的后缀表达式。等价是指两个表达式的计算顺序和计算结果完全相同。 中缀表达式:0.3/(5*2+1)# 的等价后缀表达式是:0.3 5 2 * 1 + /# 仔细观察这两个等价的表达式可知,操作数的出现次序是相同的,但运算符的出现次序是不同的。在后缀表达式中,运算符的出现次序是实际进行操作的次序;在中追表达式中,由于受到操作符的优先级和括号的影响,操作符出现次序与实际进行操作的次序很可能是不一样的。

算法描述: 将中缀表达式转换为等价的后缀表达式的过程要使用一个栈放“(”,具体可以按照下面的方式进行。 (1)从左到右一次扫描中缀表达式的每一个字符,如果是数字字符和圆点“.”则直接将它们写入后缀表达式中。 (2)如果遇到的是开括号“(”,则将它们压入一个操作符栈(不需要与栈顶操作符相比较),它表明一个新的计算层次的开始,在遇到和它匹配的闭括号“)”时,将栈中的元素弹出来并放入后缀表达式中,直到栈顶元素为“(”时,将栈顶元素“(”弹出(不需要加入后缀表达式),表明这一层括号内的操作处理完毕。 (3)如果遇到的是操作符,则将该操作符和操作符栈顶元素比较: 1、当所遇到的操作符的优先级小于或等于栈顶元素的优先级时,则取出栈顶元素放入后缀表式, 并弹出该栈顶元素,反复执行直到栈顶元素的优先级小于当前操作符的优先级; 2、当所遇到的操作符的优先级大于栈顶元素的优先级的时则将它压入栈中。 (4)重复上述步骤直到遇到中缀表达式的结束符标记“#”,弹出栈中的所有元素并放入后缀表达式中,转换结束。 如果有算法方描述的不清楚,敬请网友指出,本人表达能力较差,欢迎提出问题。 C++ 代码描述算法:

编译原理课后习题答案+清华大学出版社第二版

第 1 章引论 第1 题 解释下列术语: (1)编译程序 (2)源程序 (3)目标程序 (4)编译程序的前端 (5)后端 (6)遍 答案: (1)编译程序:如果源语言为高级语言,目标语言为某台计算机上的汇编语言或机器语言,则此翻译程序称为编译程序。 (2)源程序:源语言编写的程序称为源程序。 (3)目标程序:目标语言书写的程序称为目标程序。 (4)编译程序的前端:它由这样一些阶段组成:这些阶段的工作主要依赖于源语言而与目标机无关。通常前端包括词法分析、语法分析、语义分析和中间代码生成这些阶 段,某些优化工作也可在前端做,也包括与前端每个阶段相关的出错处理工作和符 号表管理等工作。 (5)后端:指那些依赖于目标机而一般不依赖源语言,只与中间代码有关的那些阶段,即目标代码生成,以及相关出错处理和符号表操作。 (6)遍:是对源程序或其等价的中间语言程序从头到尾扫视并完成规定任务的过程。 第2 题 一个典型的编译程序通常由哪些部分组成?各部分的主要功能是什么?并画出编译程序的总体结构图。 答案: 一个典型的编译程序通常包含8个组成部分,它们是词法分析程序、语法分析程序、语义分析程序、中间代码生成程序、中间代码优化程序、目标代码生成程序、表格管理程序和错误处理程序。其各部分的主要功能简述如下。 词法分析程序:输人源程序,拼单词、检查单词和分析单词,输出单词的机内表达形式。 语法分析程序:检查源程序中存在的形式语法错误,输出错误处理信息。 语义分析程序:进行语义检查和分析语义信息,并把分析的结果保存到各类语义信息表中。 中间代码生成程序:按照语义规则,将语法分析程序分析出的语法单位转换成一定形式的中间语言代码,如三元式或四元式。 中间代码优化程序:为了产生高质量的目标代码,对中间代码进行等价变换处理。目标代码生成程序:将优化后的中间代码程序转换成目标代码程序。

逆波兰式求值

一、需求分析 1.从键盘中输入一个后缀表达式,该表达式包括加减乘除等操作符,以及正整数做诶操作数等。 2.需要利用堆栈来实现。 3.在Visual C++6.0界面操作。 问题描述: 读入一个后缀表达式,利用堆栈来计算该表达式的值,同时要校验后缀表达式是否正确。 测试数据用例 (1)输入:2 3 * 1 - # 输出:5 (2)输入:2 3 * 1 - * # 输出:表达式有误 (3)输入: 2 0 / 4 * # 输出:表达式有误 二、概要设计 抽象数据类型 为实现上述程序的功能,则以字符型数据存储用户的输入。若为数值,则用自定义函数将其转化为整形数据;若为操作符,则仍为字符型数据,以便计算出的结果。 算法的基本思想 根据题目要求,采用堆栈来实现。该算法的基本思想是运用自定义函数求解逆波兰表达式求值问题问题。 程序的流程 程序由三个模块组成: (1)输入模块:完成表达式的输入,存入栈S中。 (2)计算模块:利用自定义函数,计算逆波兰表达式的值。 (3)输出模块:屏幕上显示出最终计算结果。 三、详细设计

物理数据类型 程序中要求输入的表达式为任意的,但必须以#标志表达式输入的结束,只有正确的逆波兰表达式才能显示出最终计算结果。 算法的具体步骤 算法的具体步骤为: 建立一个名为s的栈。 将表达式的值一个个压入栈S中。在循环中,需要分类讨论:如果表达式中的值为“#”,则将#前的元素弹出栈中;如果表达式中的值为空格,那么继续压入,如果表达式中的值为0至9的字符,则要通过一个自定义的转换函数将其转换为int型数值;如果连续几个0至9的字符中间无空格隔开,则在计算中应将其还原为多位数;若表达式中的值为运算符,则要将栈S中所压入数值弹出栈,进行相应的计算后,再将结果压入栈中(值得注意的是,运算符是不入栈的);除此之外的情况都归类为输入的表达式错误。 相应的入栈出栈及数值计算部分都由自定义函数来完成。 输入和输出的格式 输入 在字符界面上输入一个后缀表达式,其中两相邻操作数之间利用空格隔开。以“#”表示结束。 输出 如果该后缀表达式正确,那么在字符界面上输出其结果,计算结果小数点后面保留两位有效数字,如果不正确,请在字符界面上输出表达式错误提示。 四、调试分析 略。(已在老师面前调试) 五、测试结果

编译原理实验 中间代码生成

实验四中间代码生成 一.实验目的: 掌握中间代码的四种形式(逆波兰式、语法树、三元式、四元式)。 二.实验内容: 1、逆波兰式定义:将运算对象写在前面,而把运算符号写在后面。用这种表示法表示的表 达式也称做后缀式。 2、抽象(语法)树:运算对象作为叶子结点,运算符作为内部结点。 3、三元式:形式序号:(op,arg1,arg2) 4、四元式:形式(op,arg1,arg2,result) 三、以逆波兰式为例的实验设计思想及算法 (1)首先构造一个运算符栈,此运算符在栈内遵循越往栈顶优先级越高的原则。 (2)读入一个用中缀表示的简单算术表达式,为方便起见,设该简单算术表达式的右端多加上了优先级最低的特殊符号“#”。 (3)从左至右扫描该算术表达式,从第一个字符开始判断,如果该字符是数字,则分析到该数字串的结束并将该数字串直接输出。 (4)如果不是数字,该字符则是运算符,此时需比较优先关系。 做法如下:将该字符与运算符栈顶的运算符的优先关系相比较。如果,该字符优先关系高于此运算符栈顶的运算符,则将该运算符入栈。倘若不是的话,则将此运算符栈顶的运算符从栈中弹出,将该字符入栈。 (5)重复上述操作(1)-(2)直至扫描完整个简单算术表达式,确定所有字符都得到正确处理,我们便可以将中缀式表示的简单算术表达式转化为逆波兰表示的简单算术表达式。 四、程序代码: //这是一个由中缀式生成后缀式的程序 #include<> #include<> #include<> #include<> #define maxbuffer 64 void main() { char display_out(char out_ch[maxbuffer], char ch[32]); //int caculate_array(char out_ch[32]); static int i=0; static int j=0; char ch[maxbuffer],s[maxbuffer],out[maxbuffer]; cout<<"请输入中缀表达式: ";

相关文档
最新文档