实验五 编译 用语法制导方式生成中间代码生成器
编译原理课件05语法制导翻译技术和中间代码生成

5.4 中间代码
四元式的特点: 1. 四元式出现的顺序和语法成份的计值 顺序相一致. 2. 四元式之间的联系是通过临时变量实 现的,这样易于调整和变动四元式. 3. 便于优化处理.
5.4 中间代码
编译系统中,有时将四元式表示成另一 种更直观,更易理解的形式——三地址代 码或三地址语句. 三地址代码形式定义为: result := arg1 OP arg2 三地址语句:语句中是三个量的赋值语句, 三地址语句 每个量占一个地址.
5.5 自下而上的语法制导翻译
例3 简单算术表达式翻译到四元式的 语义描述 例如,设有简单算术表达式的文法: E→E+E | E*E | (E) | i
T R / S T
c S a c
c R S
输入是bR / bTc / bSc /ac 输出为: 1 4 5 314 24 31 给出相应语义动作(翻 译方案) S→bTc { print "1"} { print "2"} S→a R T→R { print "3"} R→R/S { print "4"} R→S { print "5"}
5.1 概述
例如: 表达式 A+B*C 对运算对象进行类型检查, 对变 量进行先定义后使用检查 执行真正的翻译 如果静态语义正确, 语义处理则要执 行真正的翻译, 即生成程序的某种中间 代码的形式或直接生成目标代码.
5.1 概述
目前多数编译程序进行语义分析的方 法是采用语法制导翻译法 .它不是一种 采用语法制导翻译法 形式系统, 但它比较接近形式化. 语法制导翻译法使用属性文法为工具 来描述程序设计语言的语义.
5.4 中间代码
中间代码生成实验报告doc

中间代码生成实验报告篇一:编译方法实验报告(中间代码生成器)编译方法实验报告XX年10月一、实验目的熟悉算术表达式的语法分析与中间代码生成原理。
实验内容二、(1)设计语法制导翻译生成表达式的四元式的算法;(2)编写代码并上机调试运行通过。
输入——算术表达式;输出——语法分析结果;相应的四元式序列。
(3)设计LL(1)分析法或LR(0)分析法的属性翻译文法,并根据这些属性翻译文法,使用扩展的语法分析器实现语法制导翻译。
三、实验原理及基本步骤●算术表达式文法:G(E):E ? E ω0 T | TT ? T ω1 F | FF ? i | (E)●文法变换:G’(E) E ? T {ω0 T(本文来自:小草范文网:中间代码生成实验报告)}T ? F {ω1 F}F ? i | (E)●属性翻译文法:E ? T {ω0 “push(SYN, w)” T “QUAT”}T ? F {ω1 “push(SYN, w)” F “QUAT”}F ? i “push(SEM, entry(w))” | (E)其中:push(SYN, w) —当前单词w入算符栈SYN;push(SEM, entry(w)) —当前w在符号表中的入口值压入语义栈SEM;QUAT —生成四元式函数i.T = newtemp;ii.QT[j] =( SYN[k], SEM[s-1], SEM[s], T); j++;iii.pop( SYN, _ ); pop( SEM, _ ); pop( SEM, _ );push( SEM, T );●递归下降子程序:数据结构:SYN —算符栈;SEM —语义栈;四、数据结构设计使用递归的结构进行四元式的设计,同时,运用堆栈结构将四元式的输出序列打印出来while ( exp[i]=='+' || exp[i]=='-'){syn[++i_syn]=exp[i];//push(SYN,w)i++; //read(w)T();quat();}while ( exp[i]=='*' || exp[i]=='/'){syn[++i_syn]=exp[i];//push(SYN,w)i++; //read(w)F();quat();}void quat(){strcpy(qt[j],"(, , , )");//QT[j]:=(SYN[k],SEM[s-1],SEM[s],temp);qt[j][1]=syn[i_syn];qt[j][3]=sem[i_sem-1];qt[j][5]=sem[i_sem];qt[j][7]=temp;j++;i_syn--;//pop(SYN);i_sem--;//pop(SEM);i_sem--;//pop(SEM);sem[++i_sem]=temp; //push(SEM,temp); temp++;}五、关键代码分析(带注释)及运行结果#include#include "string.h"#include "stdio.h"using namespace std;char syn[10]; //文法符号栈int i_syn;char sem[10]; //运算对象栈int i_sem;char exp[50]; //算术表达式区int i;char qt[30][15];//四元式区int j=0;char temp='q'; //临时变量,取值为r--z int E();int T();int F();void quat();//生成四元式函数int main(int argc, char* argv[]){printf("please input your expression:"); scanf("%s",exp); //输入四元式i=0; //read(w)E();if (exp[i]=='\0')for (i=0;i printf("%s\n",qt[i]);elseprintf("err");return 0;}int E(){T();while ( exp[i]=='+' || exp[i]=='-'){syn[++i_syn]=exp[i];//push(SYN,w)i++; //read(w)T();quat();}return 1;}int T(){F();while ( exp[i]=='*' || exp[i]=='/'){syn[++i_syn]=exp[i];//push(SYN,w)i++; //read(w)F();quat();}return 1;}int F(){if ( exp[i]=='('){i++; //read(w)E();if ( exp[i]!=')'){printf("err");return 0;}}else if ((exp[i]>='a' && exp[i]='0' && exp[i] sem[++i_sem]=exp[i]; } //push(SEM,w)else{printf("err");return 0;}i++; //read(w)return 1;}void quat(){strcpy(qt[j],"( , , , )");//QT[j]:=(SYN[k],SEM[s-1] ,SEM[s],temp);qt[j][1]=syn[i_syn];qt[j][3]=sem[i_sem-1];qt[j][5]=sem[i_sem];qt[j][7]=temp;j++;i_syn--; //pop(SYN);i_sem--; //pop(SEM);i_sem--; //pop(SEM);sem[++i_sem]=temp;//push(SEM,temp);temp++;}篇二:中间代码生成实验报告一、实验目的通过在实验二的基础上,增加中间代码生成部分,使程序能够对实验二中的识别出的赋值语句,if语句和while语句进行语义分析,生成四元式中间代码。
编译原理第五章 语法制导翻译及中间代码生成

式①中的运算符U_minus表示一元减运算。
翻译程序中使用的辅助函数
⒈int LookUp(char *Name)—以Name查 符号表,若查到则返回相应登记项的序号 (≥1),否则返回0。 ⒉int Enter(char* Name)—以Name为名 字在符号表中登录新的一项,返回值为该项 的序号。 ⒊int Entry(char *Name)—以Name为名 字查、填符号表:
定义 5.3 对每个产生式p:X0→X1X2…Xn , 设属性定义性出现的集合为 AF(p)={Xi.a|Xi.a=f(Xk1.ak1,…,Xkm.ak m) ∈R(p), 0≤kj≤n} 若Xi 是产生式左部的非终结符(即i=0),则称 属 性 Xi.a 是 综 合 属 性 (Synthesized Synthesized Attributes);若Xi 出现在产生式的右部(即 Attributes 1≤i≤n),则称Xi.a是继承属性(Inherited Inherited Attributes)。 Attributes
逆波兰表示
每一运算符都置于其运算对象之后,故称 为后缀表示。 特点: 特点:表达式中各个运算 运算是按运算符出现的 运算符出现的 顺序进行的,无须使用括号来指示运算顺 顺序进行的 序,因而又称为无括号式 无括号式。
逆波兰表示逆波兰表示-例子
中缀表示 后缀表示
A+B AB+ A+B*C ABC*+ (A+B)*(C+D) AB+CD+* x/y^z-d*e xyz^/de*(a=0∧b>3)∨(e∧x<>y) 思考:能否表示if e then s1 else s2这样的语句? a0=b3>∧exy<>∧∨ ∧ ∧∨ 将后缀式的符号存放在POST[n]中,
编译原理-语法制导翻译和中间代码生成

例:类型、运算、维数、越界
–语义处理:
执行真正的翻译,生成程序的中间代码目标代码。
–例:变量的存储分配
–例:表达式的求值
–例:语句的翻译(中间代码的生成)
3
8.1 属性文法
• 语义分析的描述 –描述语法规则的同时,编写相应的语义 动作和计算顺序
• 语义的形式化描述 –操作语义学、公理语义学、指称语义学
例8-3 3*5+4 的 语法树与属性计算
T.val=3 F.val=3 digit.lexval=3
E.val=15 T.val=15
*
L Print(19)
E.val=19 +
T.val=4
F.val=4
F.val=5
digit.lexval=4
dgit.lexval=5
19
T.type=real
• 继承属性 – 从其兄弟结点和父结点的属性值计算出来的 – 如:L.in
• 固有属性(单词属性)
17
属性的计算
• 语法制导翻译:作语法分析,构造语法树,然 后在树的每个结点上添加相应的语义规则
• 综合属性 – 自底向上按照语义规则来计算各结点的综合 属性值
• 继承属性 –需要探讨计算次序
18
文法
E→ -E1 E.p:= mknode('-', 0, E1.p)
E→ (E1) E.p:= E1.p E→ id E.p:= mkleaf(id, id.entry) E→ num E.p:=mkleaf(num,num.val)
37
生成后缀式的属性文法
产生式
语义规则
S→id:=E Print( || E.code || “:=”)
编译方法实验报告(中间代码生成器)

编译方法实验报告2011年10月一、实验目的熟悉算术表达式的语法分析与中间代码生成原理。
二、实验内容(1)设计语法制导翻译生成表达式的四元式的算法;(2)编写代码并上机调试运行通过。
输入——算术表达式;输出——语法分析结果;相应的四元式序列。
(3)设计LL(1)分析法或LR(0)分析法的属性翻译文法, 并根据这些属性翻译文法, 使用扩展的语法分析器实现语法制导翻译。
三、实验原理及基本步骤●算术表达式文法:G(E): E ( E ω0 T | TT →T ω1 F | FF → i | (E)●文法变换:G’(E) E →T {ω0 T}T →F {ω1 F}F → i | (E)●属性翻译文法:E →T {ω0“push(SYN, w)” T “QUAT”}T →F {ω1“push(SYN, w)” F “QUAT”}F →i “push(SEM, entry(w))” | (E)其中:push(SYN, w) —当前单词w入算符栈SYN;push(SEM, entry(w)) —当前w在符号表中的入口值压入语义栈SEM;QUAT —生成四元式函数i. T = newtemp;ii. QT[j] =( SYN[k], SEM[s-1], SEM[s], T);j++;iii. pop( SYN, _ ); pop( SEM, _ ); pop( SEM, _ );push( SEM, T );●递归下降子程序:数据结构: SYN —算符栈;SEM —语义栈;四、数据结构设计使用递归的结构进行四元式的设计, 同时, 运用堆栈结构将四元式的输出序列打印出来while ( exp[i]=='+' || exp[i]=='-'){syn[++i_syn]=exp[i]; //push(SYN,w)i++; //read(w)T();quat();}while ( exp[i]=='*' || exp[i]=='/'){syn[++i_syn]=exp[i]; //push(SYN,w)i++; //read(w)F();quat();}void quat(){strcpy(qt[j],"(, , , )"); //QT[j]:=(SYN[k],SEM[s-1],SEM[s],temp);qt[j][1]=syn[i_syn];qt[j][3]=sem[i_sem-1];qt[j][5]=sem[i_sem];qt[j][7]=temp;j++;i_syn--; //pop(SYN);i_sem--; //pop(SEM);i_sem--; //pop(SEM);sem[++i_sem]=temp; //push(SEM,temp);temp++;}五、关键代码分析(带注释)及运行结果#include <iostream>#include "string.h"#include "stdio.h"using namespace std;char syn[10]; //文法符号栈int i_syn;char sem[10]; //运算对象栈int i_sem;char exp[50]; //算术表达式区int i;char qt[30][15]; //四元式区int j=0;char temp='q'; //临时变量, 取值为r--zint E();int T();int F();void quat(); //生成四元式函数int main(int argc, char* argv[]){printf("please input your expression:");scanf("%s",exp); //输入四元式i=0; //read(w)E();if (exp[i]=='\0')for (i=0;i<j;i++) //输出四元式序列printf("%s\n",qt[i]);elseprintf("err");return 0;}int E(){T();while ( exp[i]=='+' || exp[i]=='-'){syn[++i_syn]=exp[i]; //push(SYN,w)i++; //read(w)T();quat();}return 1;}int T(){F();while ( exp[i]=='*' || exp[i]=='/'){syn[++i_syn]=exp[i]; //push(SYN,w)i++; //read(w)F();quat();}return 1;}int F(){if ( exp[i]=='('){i++; //read(w)E();if ( exp[i]!=')'){printf("err");return 0;}}else if ((exp[i]>='a' && exp[i]<='p')||(exp[i]>='0' && exp[i]<='9')){ sem[++i_sem]=exp[i]; } //push(SEM,w) else{printf("err");return 0;}i++; //read(w)return 1;}void quat(){strcpy(qt[j],"( , , , )"); //QT[j]:=(SYN[k],SEM[s-1],SEM[s],temp);qt[j][1]=syn[i_syn];qt[j][3]=sem[i_sem-1];qt[j][5]=sem[i_sem];qt[j][7]=temp;j++;i_syn--; //pop(SYN);i_sem--; //pop(SEM);i_sem--; //pop(SEM);sem[++i_sem]=temp; //push(SEM,temp);temp++;}六、总结与分析我们知道, 定义一种语言除了要求定义语法外, 还要求定义语义, 即对语言的各种语法单位赋予具体的意义。
中间代码生成实验报告

中间代码生成实验报告《中间代码生成实验报告》摘要:本实验旨在通过编写中间代码生成程序,实现将高级语言源代码转换为中间代码的功能。
通过实验,我们掌握了中间代码的生成过程和相关算法,并对编译器的工作原理有了更深入的理解。
本实验采用了C语言作为源语言,通过词法分析、语法分析和语义分析,生成了对应的中间代码。
一、实验目的1. 理解编译器的工作原理,掌握中间代码生成的基本概念和方法;2. 掌握中间代码的表示方法和生成算法;3. 通过实践,提高编程能力和对编译原理的理解。
二、实验环境1. 操作系统:Windows 10;2. 编程语言:C语言;3. 开发工具:Visual Studio 2019。
三、实验内容1. 设计并实现中间代码生成程序,将给定的C语言源代码转换为中间代码;2. 实现词法分析、语法分析和语义分析,生成对应的中间代码;3. 测试程序,验证中间代码的正确性和有效性。
四、实验步骤1. 设计中间代码的表示方法,包括四元式、三地址码等;2. 实现词法分析器,将源代码转换为词法单元序列;3. 实现语法分析器,将词法单元序列转换为语法树;4. 实现语义分析器,对语法树进行语义检查并生成中间代码;5. 测试程序,验证中间代码的正确性和有效性。
五、实验结果经过测试,中间代码生成程序能够正确地将C语言源代码转换为中间代码,并且生成的中间代码能够正确地表达源代码的语义和逻辑结构。
通过实验,我们成功地掌握了中间代码的生成过程和相关算法,加深了对编译器工作原理的理解。
六、实验总结通过本次实验,我们深入了解了编译器的工作原理和中间代码生成的基本概念和方法。
通过实践,我们提高了编程能力和对编译原理的理解,为进一步深入学习编译原理和设计编译器打下了良好的基础。
希望通过不断的实践和学习,能够更加熟练地掌握编译原理的知识,为今后的学习和工作打下坚实的基础。
编译原理中间代码生成

编译原理中间代码生成在编译原理中,中间代码生成是编译器的重要阶段之一、在这个阶段,编译器将源代码转换成一种中间表示形式,这种中间表示形式通常比源代码抽象得多,同时又比目标代码具体得多。
中间代码既能够方便地进行优化,又能够方便地转换成目标代码。
为什么需要中间代码呢?其一,中间代码可以方便地进行编译器优化。
编译器优化是编译器的一个核心功能,它能够对中间代码进行优化,以产生更高效的目标代码。
在中间代码生成阶段,编译器可以根据源代码特性进行一些优化,例如常量折叠、公共子表达式消除、循环不变式移动等。
其二,中间代码可以方便地进行目标代码生成。
中间代码通常比较高级,比目标代码更具有表达力。
通过中间代码,编译器可以将源代码转换成与目标机器无关的形式,然后再根据目标机器的特性进行进一步的优化和转换,最终生成目标代码。
中间代码生成的过程通常可以分为以下几步:1.词法分析和语法分析:首先需要将源代码转换成抽象语法树。
这个过程涉及到词法分析和语法分析两个步骤。
词法分析将源代码划分成一个个的词法单元,例如标识符、关键字、运算符等等。
语法分析将词法单元组成树状结构,形成抽象语法树。
2.语义分析:在语义分析阶段,编译器会对抽象语法树进行静态语义检查,以确保源代码符合语言的语义规定。
同时,还会进行类型检查和类型推导等操作。
3.中间代码生成:在中间代码生成阶段,编译器会将抽象语法树转换成一种中间表示形式,例如三地址码、四元式、特定的中间代码形式等。
这种中间表示形式通常比较高级,能够方便进行编译器的优化和转换。
4.中间代码优化:中间代码生成的结果通常不是最优的,因为生成中间代码时考虑的主要是功能的正确性,并没有考虑性能的问题。
在中间代码生成之后,编译器会对中间代码进行各种优化,以产生更高效的代码。
例如常量折叠、循环优化、死代码删除等等。
5.中间代码转换:在完成了中间代码的优化之后,编译器还可以对中间代码进行进一步的转换。
这个转换的目的是将中间代码转换成更具体、更低级的形式,例如目标机器的汇编代码。
编译原理中间代码生成实验报告

竭诚为您提供优质文档/双击可除编译原理中间代码生成实验报告篇一:编译原理-分析中间代码生成程序实验报告课程名称编译原理实验学期至学年第学期学生所在系部年级专业班级学生姓名学号任课教师实验成绩计算机学院制开课实验室:年月日篇二:编译原理实验中间代码生成实验四中间代码生成一.实验目的:掌握中间代码的四种形式(逆波兰式、语法树、三元式、四元式)。
二.实验内容:1、逆波兰式定义:将运算对象写在前面,而把运算符号写在后面。
用这种表示法表示的表达式也称做后缀式。
2、抽象(语法)树:运算对象作为叶子结点,运算符作为内部结点。
3、三元式:形式序号:(op,arg1,arg2)4、四元式:形式(op,arg1,arg2,result)三、以逆波兰式为例的实验设计思想及算法(1)首先构造一个运算符栈,此运算符在栈内遵循越往栈顶优先级越高的原则。
(2)读入一个用中缀表示的简单算术表达式,为方便起见,设该简单算术表达式的右端多加上了优先级最低的特殊符号“#”。
(3)从左至右扫描该算术表达式,从第一个字符开始判断,如果该字符是数字,则分析到该数字串的结束并将该数字串直接输出。
(4)如果不是数字,该字符则是运算符,此时需比较优先关系。
做法如下:将该字符与运算符栈顶的运算符的优先关系相比较。
如果,该字符优先关系高于此运算符栈顶的运算符,则将该运算符入栈。
倘若不是的话,则将此运算符栈顶的运算符从栈中弹出,将该字符入栈。
(5)重复上述操作(1)-(2)直至扫描完整个简单算术表达式,确定所有字符都得到正确处理,我们便可以将中缀式表示的简单算术表达式转化为逆波兰表示的简单算术表达式。
四、程序代码://这是一个由中缀式生成后缀式的程序#include#include#include#include#definemaxbuffer64voidmain(){chardisplay_out(charout_ch[maxbuffer],charch[32]);//intcaculate_array(charout_ch[32]);staticinti=0;staticintj=0;charch[maxbuffer],s[maxbuffer],out[maxbuffer];cout cin>>ch;for(i=0;i {out[i]=ch[i];}cout while(out[j]!=#)cout j++;}cout display_out(s,out);//caculate_array;}chardisplay_out(charout_ch[32],charch[]) {inttop=-1;inti=0,data[maxbuffer],n;intj=0;charsta[20];while(ch[i]!=#){if(isalnum(ch[i])){while(isalnum(ch[i])){out_ch[j]=ch[i];j++;i++;}out_ch[j]=;j++;else{switch(ch[i]){case+:case-:if(sta[top]==(||top==-1) {top++;sta[top]=ch[i];i++;}else{//j--;out_ch[j]=sta[top];j++;top--;//i++;}break;//break;case*:case/:if(sta[top]==*/) {out_ch[j]=sta[top];j++;//i++;top--;}else{top++;sta[top]=ch[i];i++;}break;//break;case(:top++;sta[top]=ch[i];i++;break;case):if(sta[top]==() {top--;i++;}if(top==-1){//cout }else{//while(sta[top]!=?(?){ out_ch[j]=sta[top];top--;j++;//}break;}break;/*case?#?:out_ch[j]=?#?; j++;break;*/default:cout ch[i]=#;j=0;break;}}}while(top!=-1){out_ch[j]=sta[top];j++;top--;}out_ch[j]=#;n=0;co(:编译原理中间代码生成实验报告)utwhile(out_ch[n]!=#){cout n++;}cout j=0;returnout_ch[maxbuffer];}五、实验结果:要求:自己给出3个测试用例,观察结果。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
实验5 用语法制导方式生成中间代码生成器一、实验目的掌握语法制导定义和翻译的原理和技术,在语法分析器的基础上,加上语义分析,构造一个中间代码生成器。
二、实验内容在实验四生成的语法分析器基础上加入语义动作,将源程序翻译为对应的中间代码序列。
三、实验要求1. 个人完成,提交实验报告。
实验报告必须包括设计的思路,以及测试报告(输入测试例子,输出结果)。
2. 实验报告中给出采用测试源代码片断,及其对应的三地址码形式(内部表示形式可以自行考虑)。
例如,程序片断对应的中间代码为:四、实验过程本次实验运用flex和bison工具进行中间代码的生成。
并自动生成中间代码。
1.首先创建一个example文件夹,该文件夹中包含有flex.exe2.用文本编译器编辑相应的flex文件mylex.l,此次mylex.l可以在上次实验的l文件上做一些修改,再利用flex将l文件生成相应的lex.yy.c程序,mylex.l 的代码如下所示:mylex.l%{#include "myyacc.tab.h"%}delim [ \t\n\r]ws {delim}+letter [A-Za-z]digit [0-9]id {letter}({letter}|{digit})*integer {digit}+exponent E[+-]?{integer}number {integer}{exponent}?real integer(\.integer)?{exponent}?%option noyywrap%%"<"|"<="|">"|">="|"!="|"==" { filloperator(&yylval, yytext); return( REL); }if { return( IF ); }else { return( ELSE ); }while { return( WHILE ); }do { return( DO ); }for { return( FOR ); }switch { return( SWITCH ); }case { return( CASE ); }default { return( DEFAULT ); }break { return( BREAK ); }true { return( TRUE ); }false { return( FALSE ); }int { return( INT ); }long { return( LONG ); }char { return( CHAR ); }bool { return( BOOL ); }float { return( FLOAT ); }double { return( DOUBLE ); }"&&" { return( AND ); }"||" { return( OR ); }"!" { return( '!'); }"++" { return( INC ); }"--" { return( DEC ); }"+" { return( '+' ); }"-" { return( '-' ); }"*" { return( '*' ); }"/" { return( '/' ); }"=" { return( '=' ); }"{" { return( '{' ); }"}" { return( '}' ); }"[" { return( '[' ); }"]" { return( ']' ); }"(" { return( '(' ); }")" { return( ')' ); }";" { return( ';' ); }{ws} { }{id} { filllexeme(&yylval, yytext); return( ID ); }{number} { filllexeme(&yylval, yytext); return( NUMBER ); }{real} { filllexeme(&yylval, yytext); return( REAL ); }%%在代码中,先定义正则定义,即对letter,digit,专用符号, 空格进行声明;接着在转换规则中,定义一些识别规则的代码。
完成词法分析后,就可以将获取的每一个词素用于语法分析器使用。
将mylex.l与myyacc.y相结合的方法是在每获得一个词素,则用return语句返回,即如果获得的是if,则return(if),并且在头文件中加入#include "myYacc.tab.h",则在myyacc中定义的类型在mylex中可利用,否则会出现返回的单元未定义的错误。
3.用文本编译器编辑相应的bison文件myyacc.y,myyacc.y文件中,在每个生成式后加上语法制导翻译,主要是依据truelist和falselist来实现回填功能。
编写完后,在myyacc.y中以头文件的方式加入自己编写的myyacc.h文件,编译即可。
Myyacc.y的代码如下所示:Myyacc.y%{#include "myyacc.h"#define YYSTYPE node#include "myyacc.tab.h"int yyerror();int yyerror(char* msg);extern int yylex();codelist* list;%}%token BASIC NUMBER REAL ID TRUE FALSE%token INT LONG CHAR BOOL FLOAT DOUBLE%token REL%token IF ELSE WHILE DO BREAK FOR SWITCH CASE DEFAULT%token OR AND%left OR%left AND%right '!'%left '+' '-'%left '*' '/'%right UMINUS%right INC DEC%%program : block { };block : '{' decls statementlist '}' { };decls : decls decl { }| { };decl : type ID ';' { };type : type '[' NUMBER ']' {}| BASIC { };statementlist : statementlist M statement { backpatch(list, $1.nextlist, $2.instr);$$.nextlist = $3.nextlist; }| statement { $$.nextlist = $1.nextlist; };Statement : IF '(' boolean ')' M statement ELSE N M statement{ backpatch(list, $3.truelist, $5.instr);backpatch(list, $3.falselist, $9.instr);$6.nextlist = merge($6.nextlist, $8.nextlist);$$.nextlist = merge($6.nextlist, $10.nextlist); }| IF '(' boolean ')' M statement { backpatch(list, $3.truelist, $5.instr);$$.nextlist = merge($3.falselist, $6.nextlist); }| WHILE M '(' boolean ')' M statement { backpatch(list, $7.nextlist, $2.instr);backpatch(list, $4.truelist, $6.instr);$$.nextlist = $4.falselist;gen_goto(list, $2.instr); }| DO M statement M WHILE '(' boolean ')' M ';'{ backpatch(list, $3.nextlist, $4.instr);backpatch(list, $7.truelist, $9.instr);$$.nextlist = $7.falselist;gen_goto(list, $2.instr); }| FOR '(' assignment ';' M boolean ';' M assignment ')' N M statement { backpatch(list, $6.truelist, $12.instr);backpatch(list, $11.nextlist, $5.instr);backpatch(list, $13.nextlist, $8.instr);$$.nextlist = $6.falselist;gen_goto(list, $8.instr); }| BREAK ';' { }| '{' statementlist '}' { $$.nextlist = $2.nextlist; }| assignment ';' { $$.nextlist = NULL; };assignment : ID '=' boolean { copyaddr(&$1, $1.lexeme);gen_assignment(list, $1, $3); };loc : loc '[' boolean ']' { }| ID { copyaddr(&$$, $1.lexeme); };boolean : boolean OR M boolean { backpatch(list, $1.falselist, $3.instr);$$.truelist = merge($1.truelist, $4.truelist);$$.falselist = $4.falselist; }| boolean AND M boolean { backpatch(list, $1.truelist, $3.instr);$$.truelist = $4.truelist;$$.falselist = merge($1.falselist, $4.falselist); }| '!' boolean { $$.truelist = $1.falselist;$$.falselist = $1.truelist; }| '(' boolean ')' { $$.truelist = $1.truelist;$$.falselist = $1.falselist; }| expression REL expression { $$.truelist =new_instrlist(nextinstr(list));$$.falselist = new_instrlist(nextinstr(list)+1);gen_if(list, $1, $2.oper, $3);gen_goto_blank(list); }| TRUE { copyaddr(&$$, "TRUE");gen_goto_blank(list); }| FALSE { copyaddr(&$$, "FALSE");gen_goto_blank(list); }| expression { copyaddr_fromnode(&$$, $1); };M : { $$.instr = nextinstr(list); };N : { $$.nextlist = new_instrlist(nextinstr(list));gen_goto_blank(list); };expression : expression '+' expression { new_temp(&$$,get_temp_index(list)); gen_3addr(list, $$, $1, "+", $3); }| expression '-' expression { new_temp(&$$,get_temp_index(list)); gen_3addr(list, $$, $1, "-", $3); }| expression '*' expression { new_temp(&$$,get_temp_index(list)); gen_3addr(list, $$, $1, "*", $3); }| expression '/' expression { new_temp(&$$,get_temp_index(list)); gen_3addr(list, $$, $1, "/", $3); }| '-' expression %prec UMINUS { new_temp(&$$,get_temp_index(list)); gen_2addr(list, $$, "-", $2); }| loc { copyaddr_fromnode(&$$, $1); }| NUMBER { copyaddr(&$$, $1.lexeme); }| REAL { copyaddr(&$$, $1.lexeme); };%%int yyerror(char* msg){printf("\nERROR with message: %s\n", msg);return 0;}int main(){list = newcodelist();freopen("text.in", "rt+", stdin);freopen("text.out", "wt+", stdout);yyparse();print(list);fclose(stdin);fclose(stdout);return 0;}在代码中,先定义一些头文件,extern int yylex(); extern int yyerror();这两个语句是必须的,引用全局变量是为了能够使用之前词法分析器所获取的词素。