COMPILER-PL0语言的示例-语法描述
《编译原理(实验部分)》实验3_PL0语法分析

《编译原理(实验部分)》实验3_PL0语法分析《编译原理》(实验部分)实验3_PL0语法分析一、实验目的加深和巩固对于语法分析的了解和掌握;给出PL/0文法规范,要求编写PL/0语言的语法分析程序。
二、实验设备1、PC 兼容机一台;操作系统为WindowsWindowsXP。
2、Visual C++ 6.0 或以上版本, Windows 2000 或以上版本,汇编工具(在Software 子目录下)。
三、实验原理PL/O语言的编译程序,是用高级语言PASCAL语言书写的。
整个编译过程是由一些嵌套及并列的过程或函数完成。
语法分析是由过程BLOCK完成。
采用自顶向下的递归子程序法。
所产生的目标程序为假象栈式计算机的汇编语言。
对目标程序的执行是由PASCAL语言书写的解释程序进行的。
四、实验步骤实验代码int lp=0;int rp=0;#define getsymdo if(-1==getsym()) return -1#define expressiondo() if(-1==expression()) return -1#define termdo() if(-1==term()) return -1#define factordo() if(-1==factor()) return -1int expression();//语法分析int factor(){if(sym!=ident &&sym!=number&&sym!=lparen){err++;if(err==1) printf("语法错误: \n");printf("error----Factor Needs Ident or Number or Lparen\n");}if ((sym == ident) || (sym == number) || (sym == lparen)){if (sym == ident){WordAnalyse();if(getsym()==-1){return -1;}if(sym!=times&&sym!=slash&&sym!=plus&&sym!=minus &&sym!=rparen){err++;if(err==1) printf("语法错误: \n");printf("变量后没有跟上+-*\\ \n");}if(lp==0 && sym==rparen){err++;if(err==1) printf("语法错误: \n");printf("没有左括号匹配\n");}}else if (sym == number){WordAnalyse();if(getsym()==-1){return -1;}if(sym!=times&&sym!=slash&&sym!=plus&&sym!=minus &&sym!=rparen) {err++;if(err==1) printf("语法错误: \n");printf("数字后没有跟上+-*\\ \n");}if(lp==0 && sym==rparen){err++;if(err==1) printf("语法错误: \n");printf("没有左括号匹配\n");}}else if (sym == lparen){WordAnalyse();lp++;if(getsym()==-1){lp--;err++;if(err==1) printf("语法错误: \n");printf("error----Needs Rparen \n");return -1;}expressiondo();if (sym == rparen){WordAnalyse();lp--;if(getsym()==-1){return -1;}if(sym!=times&&sym!=slash&&sym!=plus&&sym!=minus) {err++;if(err==1) printf("语法错误: \n");printf("括号后没有跟上+-*\\ \n");}}else{err++;if(err==1) printf("语法错误: \n");printf("error----Needs Rparen \n");}}}return 0;}int term(){factordo();if(sym!=times&&sym!=slash&&sym!=plus&&sym!=minus&&sym!=ident&&sym!=number&&sym!=lparen&&sym!=rparen) {err++;if(err==1) printf("语法错误: \n");printf("不能识别字符\n");}while ((sym == times) || (sym == slash)){WordAnalyse();if(getsym()==-1){err++;if(err==1) printf("语法错误: \n");printf("* \\ 后缺项\n");return -1;}factordo();}return 0;}int expression(){if ((sym == plus) || (sym == minus)){//cout<<strlen(id)<<endl;< p="">if (sym==minus&&2==strlen(ID)+1)flg=1;else{flg=0;WordAnalyse();}getsymdo;termdo();}else{//WordAnalyse();termdo();}if(sym!=times&&sym!=slash&&sym!=plus&&sym!=minus &&sym!=ident&&sym!=number&&sym!=lparen&&sym!=rparen){err++;if(err==1) printf("语法错误: \n");printf("不能识别字符\n");}while ((sym == plus) || (sym == minus)){WordAnalyse();if(getsym()==-1){err++;if(err==1) printf("语法错误: \n");printf("+ - 后缺项\n");return -1;}termdo();}return 0;}int main(int argc, char* argv[]){init();err=0;ifstream fin("in.txt");ofstream fout("out.txt");ch=' ';lp=0;getsymdo;expression();if(err==0) cout<<"语法正确"<<endl;< p="">elsecout<<"语法错误,错误个数: "<<err<<=""></err< </endl;<></strlen(id)<<endl;<>。
第二章PL0编译程序的实现

PL/0编译程序的总体设计
词法分析程序和代码生成程序都作为一个过 程,当语法分析需要读单词时就调用词法分 析程序,而当语法、语义分析正确,需要生 成相应的目标代码时,则调用代码生成程序
表格管理程序实现变量,常量和过程标识符 的信息的登录与查找。
出错处理程序,对词法和语法、语义分析遇 到的错误给出在源程序中出错的位置和与错 误 性质有关的编号,并进行错误恢复。
read(b);
end
end.
2.1.2 PL/0语言文法的EBNF表示
BNF(BACKUS-NAUR FORM)是根据美国 的John W.Backus与丹麦的Peter Naur来 命名的,它从语法上描述程序设计语言的元 语言(metalanguage)。
采用BNF就可说明哪些符号序列是对于某给 定语言在语法上有效的程序。
自顶向下的语法分析<程序>
<分程序>
.
VAR A; BEGIN READ(A) END.
<变量说明部分> <语句>
VAR <标识符> ; <复合语句> BEGIN <语句> END
A <读语句>
READ ( <标识符> )
A
递归子程序法
递归子程序法:对应每个非终结符语法单元,
编一个独立的处理过程(或子程序)。 语法分析从读入第一个单词开始由非终结符
非终结符(non-terminal symbol)—在描述 过程中定义的,代表某一类语法单位的集合 的,需要继续定义的符号。
终结符(terminal symbol)—最终定义的不能 用更小的语法单位替换的符号。
编译原理实验报告-简单 PL0编译程序及其扩展

一、题目:简单PL0编译程序及其扩展表示多行表达式的<表达式序列>文法如下:<表达式序列>-> <表达式> ↙<表达式序列> |<表达式>↙↙<表达式> -> [<变量>=] [+|-]<项>{(+|-)<项>}<项> -> <因子>{(* | /)<因子>}<因子> -> <无符号实数>|<变量>|<标准函数>‘(’<表达式>‘)’|‘(’ <表达式>‘)’<标准函数> -> sin | cos | tan | exp其中的变量无需定义且其作用域为第一次赋值处至最后。
递归下降方式设计其编译程序,生成PL/0栈式指令代码,然后解释执行。
二、编译技术,主要数据结构及算法Class:MyPL0int getch();void error(int n);int gen(string function,int lev,string a);int factor();int term();int expression();void listcode();void interpret();void GetFile();void start();void Check(int i);void run(string str);Class:Code主要数据结构:数组,栈,链表三、测试本程序的测试源程序在test.txt中:a=1+2*3-4/(2*3) //检测是否实现基本文法b=sin2+cos6+tan10 //检测是否扩展标准函数(本组没能实现exp)c=9*(3+ //检测出错纠察—缺少右括号d=x+3 //检测变量无定义e=48*+33 //检测表达式非法用于测试的源代码用户也可以自己定义四、遗留问题及思考没有解决exp的识别和计算,有待考究追加通过对书后标准程序的改造和学习,本小组加深了PL0编译程序的执行过程,了解到栈式目标代码的具体生成过程,。
编译原理课程实验指导书-PL0语言及其编译器

《编译原理》课程实验指导书(Compiler Principle)目录序言 (1)一、实验安排 (2)第一阶段:编译器的词法分析 (2)第二阶段:编译器的语法分析 (2)第三阶段:编译器的代码生成 (3)二、考核方式及评定标准 (4)三、参考资料与编译器分析 (4)第一部分PL语言及其编译器 (4)1. PL语言介绍 (4)1.1 PL语言的语法图 (5)2. PL语言编译器 (8)2.1 词法分析 (9)2.2 语法分析 (9)2.3 语义分析 (11)2.4代码生成 (11)2.5 代码执行 (13)2.6 错误诊断处理 (15)2.7 符号表管理 (17)2.8其他 (18)第二部分上机实验要求 (19)第三部分PL语言编译器源程序与示例 (21)1.示例与结果表示 (21)1.1 PL语言源程序 (21)1.2 生成的代码(片段) (28)2.PL语言编译器源程序 (28)序言本《编译原理》实验,其目的是让大家动手设计和实现一个规模适中的语言的编译器,该编译器不仅涉及编译程序的各个阶段,而且也强调了编译的总体设计、各个阶段的接口安排等等。
通过上机实践,来设计这个相对完整的编译器,一方面可以使同学们增加对编译程序的整体认识和了解——巩固《编译原理》课程所学知识,另一方面,通过上机练习,学生也可以学到很多程序调试技巧和设计大型程序一般的原则,如模块接口的协调,数据结构的合理选择等等。
为了使学生能尽早动手实践,我们建议把实践分成三部分,首先阅读本教程第一部分,在这部分就PL语言的语法及其编译程序的各个阶段作了简单介绍,以便对PL编译程序有个初步的印象。
其次要认真阅读理解第三部分所给出的PL编译器源程序及示例,使上一阶段的初步印象得以加深、具体化。
最后按照第二部分的实验要求扩充PL语言的功能并加以实现。
具体操作时分成三个阶段:词法分析、语法分析及代码生成。
最后再统一组装成一个完整的PL编译器,并适当进行改进、补充。
pl0编译程序文本c语言版使用,编译原理pl0c语言版pl0.h文件

pl0编译程序⽂本c语⾔版使⽤,编译原理pl0c语⾔版pl0.h⽂件#include# define norw 13 /*关键字个数*/# define txmax 100 /*名字表容量*/# define nmax 14 /*number的最⼤位数*/# define al 10 /*符号的最⼤长度*/# define amax 2047 /*地址上界*/# define levmax 3 /*最⼤允许过程嵌套声明层数[0,lexmax]*/# define cxmax 200 /*最多的虚拟机代码数*//*符号*/enum symbol{nul, ident, number, plus, minus,times, slash, oddsym, eql, neq,lss, leq, gtr, geq, lparen,rparen, comma, semicolon, period, becomes,beginsym, endsym, ifsym, thensym, whilesym,writesym, readsym, dosym, callsym, constsym,varsym, procsym,};#define symnum 32/*-------------*/enum object{constant,variable,procedur,};/*--------------*/enum fct{lit, opr, lod, sto, cal, inte, jmp, jpc,};#define fctnum 8/*--------------*/struct instruction{enum fct f;int l;int a;};FILE *fas;FILE *fa;FILE *fa1;FILE *fa2;bool tableswitch;bool listswitch;char ch;enum symbol sym;char id[al + 1];int num;int cc, ll;int cx;char line[81];char a[al + 1];struct instruction code[cxmax];char word[norw][al];enum symbol wsym[norw];enum symbol ssym[256];char mnemonic[fctnum][5];bool declbegsys[symnum];bool statbegsys[symnum];bool facbegsys[symnum];/*------------------------------*/struct tablestruct{char name[al]; /*名字*/enum object kind; /*类型:const,var,array or procedure*/ int val; /*数值,仅const使⽤*/int level; /*所处层,仅const不使⽤*/int adr; /*地址,仅const不使⽤*/int size; /*需要分配的数据区空间,仅procedure使⽤*/};struct tablestruct table[txmax]; /*名字表*/FILE * fin;FILE* fout;char fname[al];int err; /*错误计数器*//*当函数中会发⽣fatal error时,返回-1告知调⽤它的函数,最终退出程序*/#define getsymdo if(-1==getsym())return -1#define getchdo if(-1==getch())return -1#define testdo(a,b,c) if(-1==test(a,b,c))return -1#define gendo(a,b,c) if(-1==gen(a,b,c))return -1#define expressiondo(a,b,c) if(-1==expression(a,b,c))return -1#define factordo(a,b,c) if(-1==factor(a,b,c))return -1#define termdo(a,b,c) if(-1==term(a,b,c))return -1#define conditiondo(a,b,c) if(-1==condition(a,b,c))return -1#define statementdo(a,b,c) if(-1==statement(a,b,c))return -1#define constdeclarationdo(a,b,c) if(-1==constdeclaration(a,b,c))return -1 #define vardeclarationdo(a,b,c) if(-1==vardeclaration(a,b,c))return -1void error(int n);int getsym();int getch();void init();int gen(enum fct x, int y, int z);int test(bool*s1, bool*s2, int n);int inset(int e, bool*s);int addset(bool*sr, bool*s1, bool*s2, int n);int subset(bool*sr, bool*s1, bool*s2, int n);int mulset(bool*sr, bool*s1, bool*s2, int n);int block(int lev, int tx, bool* fsys);void interpret();int factor(bool* fsys, int* ptx, int lev);int term(bool*fsys, int*ptx, int lev);int condition(bool*fsys, int*ptx, int lev);int expression(bool*fsys, int*ptx, int lev);int statement(bool*fsys, int*ptx, int lev);void listcode(int cx0);int vardeclaration(int* ptx, int lev, int* pdx);int constdeclaration(int* ptx, int lev, int* pdx);int position(char* idt, int tx);void enter(enum object k, int* ptx, int lev, int* pdx); int base(int l, int* s, int b);。
编译原理实验报告-pl0

《编译原理》实验报告———编写编译程序实现多行表达式的<表达式序列>的文法语言的编译执行组长:组员:一、实验项目名称:有表示多行表达式的<表达式序列>文法如下:<表达式序列>-> <表达式> ↙<表达式序列> |<表达式>↙↙<表达式> -> [<变量>=] [+|-]<项>{(+|-)<项>}<项> -> <因子>{(* | /)<因子>}<因子> -> <无符号实数>|<变量>|<标准函数>…(‟<表达式>…)‟|…(‟ <表达式>…)‟<标准函数> -> sin | cos | tan | exp其中的变量无需定义且其作用域为第一次赋值处至最后。
试按递归下降方式设计其编译程序,生成PL/0栈式指令代码,然后解释执行。
二、实验要求:·将编译和解释执行分成完全独立的两个阶段;·对栈式指令进行适当扩充,使之能处理标准函数的调用;·剔除本题目不需要的PL/0栈式指令,并说明理由;·简化PL/0运行栈,使之满足本题目要求既可;·注意<表达式>定义中的可选项[变量=]引起的歧义性:如a=1+2与a+2,前一个a属于<表达式>,而后一个a属于<项>,思考如何解决;·以“表达式↙目标码序列↙结果↙”方式输出运行结果;·设计一个测试,使之能充分测试你的实现;·对正确列出的目标码、执行并按适当方式演示运行栈的变化,计算出值;对错误的指出其出错位置和错误性质三、设计概述:·实现平台:VC++6.0·运行平台:xindows xp四、结构设计说明:结构图:五、具体实现过程:1、词法分析(斯琴)词法分析子程序名为getsym,功能是从源程序中读出一个单词符号,把它的信息放入全局变量sym,值放入id中,语法分析需要单词时,直接从变量中获得。
一、PL0语言的扩展
课程实践项目1、课程实践要完成下列要求(1)给PL/0语言增加像C语言那样的形式为/*……*/的注释。
(2)给PL/0语言增加带else子句的条件语句和exit语句。
(3)给PL/0语言增加输入输出语句。
(4)给PL/0语言增加带参数的过程。
(5)给PL/0语言增加布尔类型。
(6)给PL/0语言增加数组类型。
(7)给PL/0语言增加函数类型。
(8)给PL/0语言增加实数类型。
(9)分离解释器和编译器为两个独立的程序。
2、扩展后的PL/0语言的语法Program →Block .Block →[ConstDecl][TypeDecl][V arDec l][FuncDecl] begin Stmt {; Stmt } end ConstDecl →const ConstDef ; {ConstDef ;}ConstDef →ident = number ;TypeDecl →type TypeDef {TypeDef }TypeDef →ident = TypeExp ;TypeExp →integer | real | Boolean | array‘[’number .. number‘]’of TypeExp V arDecl →var V arDec {V arDec }V arDec →ident {, ident} : Type ;Type →integer | real | Boolean | identFuncDecl→FuncDec { FuncDec }FuncDec→procedure ident [ ( ForParal ) ]; Block ; |function ident [ ( ForParal ) ] : Type ; Block ;ForParal →ident : Type {; ident : Type }Stmt →IdentRef := Exp | if Exp then Stmt | if Exp then Stmt else Stmt |begin Stmt {; Stmt } end | while Exp do Stmt | exit | ε |call ident [ ( ActParal ) ] | write ( Exp {, Exp } ) |read (IdentRef {, IdentRef } )IdentRef →ident [ ‘[’Exp‘]’ { ‘[’Exp‘]’ } ]ActParal →Exp {, Exp }Exp →SimpExp RelOp SimpExp | SimpExpRelOp →= | <> | < | > | <= | >=SimpExp →[+ | - ] Term {+ Term | - Term | or Term}Term →Factor {* Factor | / Factor | div Factor | mod Factor | and Factor} Factor →IdentRef | number | ( Exp ) | not Factor | ident [ ( ActParal ) ] |odd (SimpExp) | true | false有关该扩展的说明如下:(1)描述语言的部分符号的解释符号→、|、[、]、{和}是描述语言的符号,其中方括号[…]中的部分可以出现0次或1次,花括号{…}中的部分可以出现任意次数,包括0次。
pl0文法
pl0文法PL0文法PL0是一种简单的编程语言,其语法规则可以用BNF(巴克斯范式)表示。
PL0文法是由Niklaus Wirth于1972年提出的,它是一种上下文无关文法(CFG),可以被用来生成PL0程序。
1. PL0的基本结构一个PL0程序由以下几个部分组成:- 常量定义- 变量定义- 过程定义- 主程序体2. BNF表示PL0文法在BNF中,每个非终结符都有一个产生式(production rule),它指定了如何将该非终结符替换为终结符和其他非终结符的序列。
以下是PL0文法的BNF表示:<program> ::= <block> "."<block> ::= [<const-declaration-part>] [<var-declaration-part>] [<procedure-declaration-part>] <statement-part><const-declaration-part> ::= "const" <constant-definition> {"," <constant-definition>} ";"<constant-definition> ::= <identifier> "=" <number><var-declaration-part> ::= "var" <variable-declaration> {","<variable-declaration>} ";"<variable-declaration> ::= <identifier><procedure-declaration-part> ::= {<procedure-definition>}<procedure-definition> ::= "procedure" <identifier> ";"[<parameter-list>] ";" <block><parameter-list> ::= "(" <formal-parameter-section> {";"<formal-parameter-section>} ")"<formal-parameter-section>::= ["var"] <identifier><statement-part>::=<compound-statement><compound-statement>::="begin" <statement> {";"<statement>} "end"<statement> ::= <simple-statement>|<structured-statement> <simple-statement>::=<assignment-statement>|<procedure-call>|<read-statement>|<write-statement><assignment-statement>::=<variable> ":=" <expression><variable>::=<identifier><expression>::=<simple-expression>|<simple-expression><relational-operator> <simple-expression><relational-operator>::="="|"<>"|"<"|">"|"<="|">="<simple-expression>::=[ "+"|"-"] <term> {("+"|"-"|"or") <term>} <term>::=<factor> {("*"|"/"|"and") <factor>}<factor>::=<variable>|<number>| "(" <expression>")"| "not" <factor>3. PL0文法的解释- program:程序是由一个代码块和一个终止符号(.)组成的。
PL0文档
具体要求题目:对现存的PL/0编译程序可做如下修改或扩充。
(1)注释注释由(*和*)包含,不允许嵌套。
(2)布尔类型的数据布尔类型的BNF为:var_option → ε| var var_decl_listvar_decl_list → var_decl | var_decl_list var_declvar_decl → ident_list : data_typedata_type → integer | boolean这种修改包括:(i)区别整型与布尔型变量、常量和表达式。
(ii)增加按严格计算的布尔类型运算符and、or和not。
这些算符以及己有的运算符的优先级与Pascal语言相同。
(iii)能够使用布尔常量true和false。
(3)数组增加由任何数据类型构造的一维数组。
数组的下标限于纯量类型。
注意:数组可以由其它的数组来构造,因而必须考虑多维数组的情况。
数组的上下界可为任意的纯量常数。
数组的定义如下:data_type → integer | boolean | array [const..const] of data_typeconst → ident | number语言中允许有数组说明,对数组元素赋值,在表达式中引用数组元素。
为了便于解释执行,可能要增加新的PL/0机器操作指令。
(4)参数语法同Pascal,采用值-结果方式传递(不用var声明)。
(5)函数语法同Pascal。
(6)else子句(7)for语句,语法参照Pascal或C语言。
(8)exit语句(退出当前执行过程)和break语句(跳出包含它的最内层循环)注意:上面的这些要求有时会互相影响:例如实现布尔类型数据,则数组和参数就应该能处理其相互组合的情况,如布尔型数组(包括多维数组)、布尔型作为下标的数组、布尔型作为参数传递。
甚至能够实现数组作为参数传递等。
另外,为了实现以上功能,你可任意增加PL/0处理机的指令。
编译原理实践PL0的词法分析程序构造
字符串源程序
词法分析器
送符号
语法分析器
程序getsym
本课程采用第2种方案,程序名getsym,预先 审视源程序下一个符号,并将读入的符号放在 变量sym中,语法分析的判断分析将以这个读 入的符号为基础 具体任务:
跳过空格字符 识别像begin、end、if、while等这样的保留字 识别非保留字,作为标识符处理 识别数字 识别专用符号组合,如:=、<=、>= 识别特殊的单个字符,如+、-、/、* 跳过注释行(书中例子程序没有体现)
if i-1>j then sym:=wsym[k] else sym:=ident end else…
3)处理常数
相关变量/常量说明 num:integer (*词法分析器输出结果之用*) nmax=14 (*数字允许的最长位数*)
if ch in ['0'..'9'] then begin (* number *) k:=0; num:=0; sym:=number; repeat num:=10*num+(ord(ch)-ord('0')); k:=k+1; getch; until not (ch in ['0'..'9']); if k> nmax then error(30) end else…
word:array[1..norw] of alfa word[1]~word[11] (*保留字表,长度为10的保留字,多余用空格 填充,以便词法分析时用二分法查找保留字*) wsym:array[1..norw] of symbol wsym[1]~wsym[11] (*在上面的保留字表中找到保留字后可以在本 表中相应位置找到保留字类型*) ssym:array [char] of symbol ssym[‘+’]~ssym[‘;’] (*符号表,把可能出现的符号赋予上相应的类 型,其余符号为nul*) 相关变量说明 sym:symbol (*词法分析器输出结果之用*) id:alfa (*词法分析器输出结果之用*) num:integer (*词法分析器输出结果之用*) i,j,k:integer (*局部变量*) a:alfa (*词法分析器中用于临时存放正在分析的词*) kk:integer (*引入此变量为了性能,初始为10 *)