logo资料库

pl0语言扩充源代码.doc

第1页 / 共32页
第2页 / 共32页
第3页 / 共32页
第4页 / 共32页
第5页 / 共32页
第6页 / 共32页
第7页 / 共32页
第8页 / 共32页
资料共32页,剩余部分请下载后查看
PL/0语言中的数据类型只有整型,没有浮点数,所以圆周率只能近似为3。数字最多为14位。标识符的有效
PL/0语言允许过程嵌套定义和递归调用的。过程最多可嵌套三层。
过程可以引用自己定义的局部标识符,也可以引用包围在它的外过程(包括主程序)定义的标识符。
(a) PL/0语言文法的EBNF表示
补充: PL/0 语言及其编译程序的实现 1 概述  PL/0 语言的编译程序把 PL/0 语言程序翻译成为一种称 为 类 pcode 的假想的栈式计算机汇编语言程序。这种 汇编语言与机器无关,若要在某一机器上实现 PL/0 语 言程序,只需用机器上配置的任何语言对类 pcode 语言 程序进行解释执行。  世界著名计算机科学家 N.Wirth 编写了 "PL/0 语言的 编译程序"。  后面附了 PL/0 编译程序源代码。 2. PL/0 语言描述  何为 PL/0 语言 - PL/0 语言是 PASCAL 语言的子集. 具备了一般高级语言的必备部分. (如: read,write,if-then,do,while,call,begin-end,赋值语句)  PL/0 语言中的数据类型只有整型,没有浮点数,所以圆周率只能近似为 3。数字最多为 14 位。标识符的有效长度是 10  PL/0 语言允许过程嵌套定义和递归调用的。过程最多可嵌套三层。  过程可以引用自己定义的局部标识符,也可以引用包围在它的外过程(包括主程序)定义的标识符。 1
以下将用 扩充的巴科斯-瑙尔范式(BACKUS-NAUR FORM)和 语法图 (EBNF)两种形式给出 PL/0 语言的语法描述。 ------------------------------------------------------------------------------------------------------------------------------------------------------- (a) PL/0 语言文法的 EBNF 表示 EBNF 表示的符号说明 1) 〈 〉:用左右尖括号括起来的中文字表示语法构造成分,或称语法单位,为非终结符。 2) ∷= :该符号的左部由右部定义,可读作'定义为'。 3) 4) | :表示'或',为左部可由多个右部定义。 <标识符 | 常量> 是不允许的. 因为非终结符作为一个独立的单位,不可分割 { } :花括号表示其内的语法成分可以重复。在不加上下界时可重复 0 到任意次数,有上下界时为可重复次数的限制。 如:{*}表示*重复任意次,{*}38 表示*重复 3-8 次。例如<标识符>::= l{l|d}09 表示标识符的长度小于等于 10. 5) 6) [ ] :方括号表示其内的成分为任选项。 ( ) :表示圆括号内的成分优先。 PL/0 语言文法的 EBNF 表示为: 〈程序〉∷=〈分程序〉. 〈分程序〉∷=[〈常量说明部分〉][〈变量说明部分〉][〈过程说明部分〉]〈语句〉 〈常量说明部分〉∷=CONST〈常量定义〉 {,〈常量定义〉}; 〈常量定义〉∷=〈标识符〉=〈无符号整数〉 〈无符号整数〉∷=〈数字〉{〈数字〉} 〈变量说明部分〉∷=VAR〈标识符〉{,〈标识符〉}; 〈标识符〉∷=〈字母〉{〈字母〉|〈数字〉} 〈过程说明部分〉∷=〈过程首部〉〈分程序〉{;〈过程说明部分〉}; 〈过程首部〉∷=PROCEDURE〈标识符〉; 〈语句〉∷=〈赋值语句〉|〈条件语句〉|〈当型循环语句〉| 〈过程调用语句〉|〈读语句〉|〈写语句〉|〈复合语句〉|〈空〉 〈赋值语句〉∷=〈标识符〉∶=〈表达式〉 〈复合语句〉∷=BEGIN〈语句〉{;〈语句〉}END 〈条件〉∷=〈表达式〉〈关系运算符〉〈表达式〉|ODD〈表达式〉 〈表达式〉∷=[+|-]〈项〉{〈加法运算符〉〈项〉} 〈项〉∷=〈因子〉{〈乘法运算符〉〈因子〉} 〈因子〉∷=〈标识符〉|〈无符号整数〉|'('〈表达式〉')' 〈加法运算符〉∷=+|- 〈乘法运算符〉∷=*|/ 〈关系运算符〉∷=#|=|<|<=|>|>= 〈条件语句〉∷=IF〈条件〉THEN〈语句〉 〈过程调用语句〉∷=CALL〈标识符〉 〈当型循环语句〉∷=WHILE〈条件〉DO〈语句〉 〈读语句〉∷=READ'('〈标识符〉{,〈标识符〉}')' 〈写语句〉∷=WRITE'('〈表达式〉{,〈表达式〉}')' 〈字母〉∷=a|b|…|X|Y|Z 〈数字〉∷=0|1|2|…|8|9 2
(b) PL/0 语言的语法描述图  用椭圆和圆圈中的英文字表示终结符,用长方形内的中文字表示非终结符。 内的文字表示非终结符 或 内的文字或符号表示终结符  画语法图时要注意箭头方向和弧度,语法图中应该无直角,如图 2.1 给出的 PL/0 语法描述图。沿语法图分析时不能走 尖狐线。 图 2.1(a) 程序语法描述图 p9 按照上图,不能将常量定义写在变量定义前面. 图 2.1(b) 分程序语法描述图 p10 3
可以改动上图, 增加 else 语句 if 条件 then 语句 else 语句 图 2.1(c) 语句语法描述图 可以改动上图, 使 do 语句可以处理多条语句. do 语句 , 图 2.1(d) 条件语法描述图 4
图 2.1(e) 表达式语法描述图 图 2.1(f) 项语法描述图 图 2.1(g) 因子语法描述图 5
附录: 源代码 pl0c.h /* 关键字个数 */ #define norw 13 /* 名字表容量 */ #define txmax 100 /* 所有的add1用于定义数组 */ #define txmaxadd1 101 /* number的最大位数 */ #define nmax 14 /* 符号的最大长度 */ #define al 10 /* 地址上界 */ #define amax 2047 /* 最大允许过程嵌套声明层数 */ #define levmax 3 /* 最多的虚拟机代码数 */ #define cxmax 200 #define cxmaxadd1 201 /* 当函数中会发生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 -1 typedef enum {false,true} bool; /* 符号 */ enum symbol {nul,ident,number,plus,minus,times,slash,oddsym,eql,neq,lss,leq,gtr,geq,lparen,rparen,comma,semicolon,perio d,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 6
/* 虚拟机代码结构 */ struct instruction { }; enum fct f; /* 虚拟机代码指令 */ int l; /* 引用层与声明层的层次差 */ int a; /* 根据f的不同而不同 */ FILE* fas; /* 输出名字表 */ FILE* fa; /* 输出虚拟机代码 */ FILE* fa1; /* 输出源文件及其各行对应的首地址 */ FILE* fa2; /* 输出结果 */ bool listswitch; /* 显示虚拟机代码与否 */ bool tableswitch; /* 显示名字表与否 */ char ch; /* 获取字符的缓冲区,getch 使用 */ enum symbol sym; /* 当前的符号 */ char id[al]; /* 当前ident */ int num; /* 当前number */ int cc,ll,kk; /* getch使用的计数器,cc表示当前字符(ch)的位置 */ int cx; /* 虚拟机代码指针 */ char line[81]; /* 读取行缓冲区 */ char a[al]; /* 临时符号 */ struct instruction code[cxmaxadd1]; /* 存放虚拟机代码的数组 */ 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 or procedure */ int val; /* 数值,仅const使用 */ int level; /* 所处层,仅const不使用 */ int adr; /* 地址,仅const不使用 */ int size; /* 需要分配的数据区空间,仅procedure使用 */ struct tablestruct table[txmaxadd1]; /* 名字表 */ FILE* fin; FILE* fout; char fname[al]; int err; /* 错误计数器 */ 7
void 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 postion(char* idt,int tx); void enter(enum object k,int* ptx,int lev,int* pdx); int base(int l,int* s,int b); pl0c.c /* Windows 下c语言PL/0编译程序 在Visual C++ 6.0和Visual C.NET上运行通过 使用方法: 运行后输入PL/0源程序文件名 回答是否输出虚拟机代码 回答是否输出名字表 fa.tmp输出虚拟机代码 fa1.tmp输出源文件及其各行对应的首地址 fa2.tmp输出结果 fas.tmp输出名字表 */ #include #include "pl0c.h" #include "string.h" /* 解释执行时使用的栈 */ #define stacksize 500 8
分享到:
收藏