PL0源代码(C语言版)
pl0(pascal version)编译器
![pl0(pascal version)编译器](https://img.taocdn.com/s3/m/0488371dc5da50e2524d7fe4.png)
program pl0(input,output);{pl/0 compiler with code generation} label 99;const norw = 11; {no. of reserved words} {保留字个数} txmax = 100; {length of identifier table} { 标识符变长度}nmax = 14; {max. no. of digits in numbers}{ }al = 10; {length of identifiers} {标识符的长度。
为10} amax = 2047; {maximum address} {最大地址}levmax = 3; {maximum depth of block nesting} {}cxmax = 200; {size of code array} {代码数组长度}type symbol =(nul,ident,number,plus,minus,times,slash,oddsym,{等号,标识符,数字, + , - ,* , / ,wsym[ 7] := oddsym } eql,neq,lss,leq,gtr,geq,lparen,rparen,comma,semicolon,{=,#,<, [ , >, ], ( , ) , ‘ , ’, ; }period,becomes,beginsym,endsym,ifsym,thensym,{‘ . ’, 赋值,开始,结束,if , then } {不确定}whilesym,dosym,callsym,constsym,varsym,procsym);{while , do , call , const, var , procedure} {不确定}alfa = packed array [1..al] of char;{字符数组,存放关键字}object1 = (constant,varible,proc);{判断标识符是常量、变量还是过程?}symset = set of symbol;fct = (lit,opr,lod,sto,cal,int,jmp,jpc); {functions目标代码的功能码,具体如下:}instruction = packed record {指令记录目标代码结构}f: fct; {function code} {}l: 0..levmax; {level层数}a: 0..amax {displacement address}end;{ lit 0,a : load constant aopr 0,a : execute operation alod l,a : load varible l,asto l,a : store varible l,acal l,a : call procedure a at level lint 0,a : increment t-register by ajmp 0,a : jump to ajpc 0,a : jump conditional to a }var ch: char; {last character read 当前字符}sym: symbol; {last symbol read 当前读入的符号}id: alfa; {last identifier read 当前标识符}num: integer; {last number read} {当前数字}cc: integer; {character count} {当前读入字符数目}ll: integer; {line length} {当前行数}kk, err: integer;cx: integer; {code allocation index} {??????}line: array [1..81] of char; {当前读入的一行}a: alfa;code: array [0..cxmax] of instruction; {存放生成的目标代码}word: array [1..norw] of alfa; {存放的关键字数组}wsym: array [1..norw] of symbol; {标识符字符集}ssym: array [char] of symbol; {符号语义字符集识别符号类似token.seman} mnemonic: array [fct] ofpacked array [1..5] of char; {功能码字符数组} declbegsys, statbegsys, facbegsys: symset;table: array [0..txmax] of { 符号表???}record name: alfa;case kind: object1 ofconstant: (val: integer);varible, proc: (level, adr: integer)end;fin:text; {存放源文件。
PL0编译程序源程序
![PL0编译程序源程序](https://img.taocdn.com/s3/m/0b825f51f01dc281e53af059.png)
procedure constdeclaration; (*常量定义的处理*) begin if sym = ident then begin getsym; if sym in [eql,becomes] then begin if sym = becomes then error(1); getsym; if sym = number then begin enter(constant); getsym; end else error(2) end else error(3) end else error(4); end; (*constdeclaration 结束*)
until kk = k; id:= a; i:= 1; (*二分法查保留字表*) j:= norw; repeat k:= (i+j) div 2; if id <= word[k] then j:= k-1; if id >= word[k] then i:= k+1 until i>j; if i-1 > j then sym:= wsym[k] else sym:= ident; end else 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 if ch = ':' then begin getch; if ch = '=' then begin sym:= becomes; getch; end else sym:= nul; end else (*<=*)
用C语言编写一个PL
![用C语言编写一个PL](https://img.taocdn.com/s3/m/150af606a6c30c2259019e19.png)
用C语言编写一个PL/0词法分析器,为语法语义分析提供单词,使之能把输入的字符串形式的源程序分割成一个个单词符号传递给语法语义分析,并把分析结果(基本字,运算符,标识符,常数以及界符)输出。
#include <iostream>#include<string>using namespace std;#define MAX 22char ch =' ';string key[15]={"begin","end","if","then","else","while","write","read","do", "call","const","char","until","procedure","repeat"};int Iskey(string c){ //关键字判断int i;for(i=0;i<MAX;i++) {if(key[i].compare(c)==0) return 1;}return 0;}int IsLetter(char c) { //判断是否为字母if(((c<='z')&&(c>='a'))||((c<='Z')&&(c>='A'))) return 1;else return 0;}int IsDigit(char c){ //判断是否为数字if(c>='0'&&c<='9') return 1;else return 0;}void analyse(FILE *fpin){string arr="";while((ch=fgetc(fpin))!=EOF) {arr="";if(ch==' '||ch=='t'||ch=='n'){}else if(IsLetter(ch)){while(IsLetter(ch)||IsDigit(ch)) {if((ch<='Z')&&(ch>='A')) ch=ch+32;arr=arr+ch;ch=fgetc(fpin);}fseek(fpin,-1L,SEEK_CUR);if (Iskey(arr)){cout<<arr<<"t$关键字"<<endl;}else cout<<arr<<"t$普通标识符"<<endl;}else if(IsDigit(ch)){while(IsDigit(ch)||ch=='.'&&IsDigit(fgetc(fpin))){arr=arr+ch;ch=fgetc(fpin);}fseek(fpin,-1L,SEEK_CUR);cout<<arr<<"t$无符号实数"<<endl;}else switch(ch){case'+':case'-' :case'*' :case'=' :case'/' :cout<<ch<<"t$运算符"<<endl;break;case'(' :case')' :case'[' :case']' :case';' :case'.' :case',' :case'{' :case'}' :cout<<ch<<"t$界符"<<endl;break;case':' :{ch=fgetc(fpin);if(ch=='=') cout<<":="<<"t$运算符"<<endl;else {cout<<"="<<"t$运算符"<<endl;;fseek(fpin,-1L,SEEK_CUR);}}break;case'>' :{ch=fgetc(fpin);if(ch=='=') cout<<">="<<"t$运算符"<<endl;if(ch=='>')cout<<">>"<<"t$输入控制符"<<endl;else {cout<<">"<<"t$运算符"<<endl;fseek(fpin,-1L,SEEK_CUR);}}break;case'<' :{ch=fgetc(fpin);if(ch=='=')cout<<"<="<<"t$运算符"<<endl;else if(ch=='<')cout<<"<<"<<"t$输出控制符"<<endl;else if(ch=='>') cout<<"<>"<<"t$运算符"<<endl;else{cout<<"<"<<"t$运算符"<<endl;fseek(fpin,-1L,SEEK_CUR);}}break;default : cout<<ch<<"t$无法识别字符"<<endl;}}}void main(){char in_fn[30];FILE * fpin;cout<<"请输入源文件名(包括路径和后缀名):";for(;;){cin>>in_fn;if((fpin=fopen(in_fn,"r"))!=NULL) break;else cout<<"文件路径错误!请输入源文件名(包括路径和后缀名):";}cout<<"n********************分析如下*********************"<<endl;analyse(fpin);fclose(fpin);}。
编译原理课件-PL0编译程序
![编译原理课件-PL0编译程序](https://img.taocdn.com/s3/m/cacb3d73bceb19e8b9f6ba17.png)
OPR 0 0 OPR 0 1 OPR 0 2 OPR 0 3 OPR 0 4 OPR 0 5 OPR 0 6 OPR 0 7 OPR 0 8 OPR 0 9 OPR 0 10 OPR 0 11
过程调用结束后,返回调用点并退栈 栈顶元素取反 次栈顶与栈顶相加,退两个栈元素,结果值进栈 次栈顶减去栈顶,退两个栈元素,结果值进栈 次栈顶乘以栈顶,退两个栈元素,结果值进栈 次栈顶除以栈顶,退两个栈元素,结果值进栈 栈顶元素的奇偶判断,结果值在栈顶
word[1]:=‘begin
‘;word[2]:=‘call
...
word[13]:=‘write ‘;
查到時找到相應的內部表示
Wsym[1]:=beginsym; wsym[2]:=callsym;
…
wsym[13]:=writesym;
‘;
字元對應的單詞表: ssym[‘+’]:=plus; ssym[‘-’]:=minus;
所有運算都在棧頂(零地址機) 指令格式:
fla
f
功能碼
l 層次差 (識別字引用層減去定義層)
a
根據不同的指令有所區別
目標指令有8條:
①LIT:將常量值取到運行棧頂。a域為常數值。 ② LOD:將變數放到棧頂。a域為變數在所說明層中的相對位置, l為調用層 與說明層的層差值。 ③ STO:將棧頂的內容送入某變數單元中。a,l域的含意同LOD指令。 ④ CAL:調用過程的指令。a為被調用過程的目標程式入口地址,l為層差。 ⑤ INT:為被調用的過程(或主程序)在運行棧中開闢數據區。a域為開闢的單 元個數。 ⑥ JMP:無條件轉移指令,a為轉向地址。 ⑦ JPC:條件轉移指令,當棧頂的布爾值為非真時,轉向a域的地址,否則順 序執行。 ⑧ OPR:關係運算和算術運算指令。將棧頂和次棧頂的內容進行運算,結果 存放在次棧頂,此外還可以是讀寫等特殊功能的指令,具體操作由a域值給 出。(詳見解釋執行程式)。
编写PL-0语言词法分析程序(c)
![编写PL-0语言词法分析程序(c)](https://img.taocdn.com/s3/m/9de82dd650e2524de4187e06.png)
编写PL/0语言的词法分析程序要求:1、读入用PL/0语言编写的源程序,正确的进行词法分析,并输出二元式序列。
2、若源程序有词法错误,能够给出出错的准确位置。
3、词法代号如下(+,+);(-,-);(*,*);(/,/);((,();(),));(,,,);(;,;);(.,.);(#,#);(=,=);(>,>);(<,<);(:=,a);(>=,b);(<=,c);(数字,d);(标识符,e);关键字代号:(begin,f);(call,g);(const,h);(do,i);(end,j);(if,k);(odd,l);(procedure,m);(read,n);(then,o);(var,p);(while,q);(write,r);4、等于运算符号为一个 =测试程序:A.C======================CONST A=10;VAR B,C;PROCEDURE P;VAR D;PROCEDURE Q;VAR X;BEGINREAD(X);D:=X;WHILE X<0DO CALL P;END;BEGINWRITE(D);CALL Q;END;BEGINCALL P;END.*//*program name:chifufenxi*//*作者:小万 qq:421404493*//*date:2004.10.11*/#include<stdio.h>#include<stdlib.h>#include<conio.h>#include<ctype.h>#include<string.h>#define N 256//每一行的字符数不能超过256个char buffer[N]; //用作存放一行字符char word[20]; //用作存放经过分析单词char *kword[13]={"begin","call","const","do","end","if","odd","procedure","read","then","var","while","write"};char ktype[13]={'f','g','h','i','j','k','l','m','n','o','p','q','r'};int len;//记录每一行的长度int count=0;//用来记录行数void write(char *wstr,char wc,FILE *wout)//将分析结果按照规则写入到文件{fputc('(',wout);fputs(wstr,wout);fputc(',',wout);fputc(wc,wout);fputc(')',wout);}int readbuffer(FILE *fp){char ch;len=0;ch=fgetc(fp);while(!feof(fp) && ch!='\n')//读取字符到缓冲区{buffer[len]=ch;ch=fgetc(fp);len++;}len--;//用来控制词法分析时行分析中字母的个数if(feof(fp))//标志文件是否结束return 0;elsereturn 1;}void error(int type){if(type==1)printf("为无效字符,第%d行词法出错,标志符不能以数字开头\n",count); else if(type==2)printf("第%d行词法出错,赋值符应为\:\= \n ",count);else printf("为无效字符,第%d行词法出错\n",count);}void check(char *str,FILE *out);//声明函数,此函数用来分类单词void fenxi(char *row,FILE *op)//此函数用来对每一行的单词进行语法分析{//printf("%d\n",count);int k=0;//用作控制临时存放单词的变量str0int i=0;//定义两个变量用作控制每一行是否结束,int ferror=0;//用作出错标志char str0[20];//临时存放单词的变量while(i<=len){k=0;//将k置0strcpy(word,"\0");//将存放单词的变量清空/*去除空格*/if(isspace(row[i]))//去出空格,跳格符,换行符{i++;continue;}/*去出无效字符*/while(!isalpha(row[i])&&!isdigit(row[i])&&i<=len&&!isspace(row[i])&&!(row[i]=='\0'||row[i]==':'||row[i]=='>'|| row[i]=='<'||row[i]=='+' || row[i]=='-' || row[i]=='*' || row[i]=='/' || row[i]=='(' || row[i]==')' || row[i]==',' || row[i]==';' || row[i]=='.'|| row[i]=='#' || row[i]=='=')){putchar(row[i]);i++;ferror=1;//设置错误标志符}if(ferror==1){error(3);//调用出错处理函数ferror=0;}/*对注释进行处理,假设此语言的注释只能单行注释以双斜杠“//”为注释开始标志*/if(row[i]=='/'){i++;if(row[i]=='/'){i=len+1;//忽略注释符后面的单词continue;}elsei--;}/*判断是否为数字*/if(isdigit(row[i])){while(i<=len&&!isspace(row[i])&&!(row[i]=='\0'||row[i]==':'||row[i]=='>'||row[i]=='<'||row[i]=='+' || row[i]==' -' || row[i]=='*' || row[i]=='/' || row[i]=='(' || row[i]==')' || row[i]==',' || row[i]==';'|| row[i]=='.'|| row[i]=='#' || row[i]= ='='))//当不到行尾,是数字或字母当然有可能是无效字符{if(isdigit(row[i]))//是数字则将字符逐个存入临时数组{str0[k]=row[i];i++;k++;// putchar('e');}else //数字中加有字母或无效字符则报错{// putchar('x');ferror=1;break;//已经出错设置标志并退出循环}}if(ferror==1)//检测是否出错{ /*将刚刚的那个单词后面的数字和字母清空,如123abc123或则123$$23等,当出现错误后,需要消除abc123和$$23以免误作为下一个标志符*/for(int j=0;j<k;j++)putchar(str0[j]);while(i<=len&&!isspace(row[i])&&!(row[i]=='\0'||row[i]==':'||row[i]=='>'||row[i]=='<'||row[i]=='+' || row[i]=='-' || row[i]=='*' || row[i]=='/' || row[i]=='(' || row[i]==')' || row[i]==',' || row[i]==';'|| row[i]=='.'|| row[i]=='#' || row[i]==' =')){putchar(row[i]);i++;}error(1);//putchar('e');//调用出错处理函数ferror=0;//重新设置错误标志位//i--;//strcpy(word,"");}else//未出错照常处理{str0[k]='\0';strcpy(word,str0);i--;//减一是为了使最后取出的那个字符不在被下面的程序判断// str0[0]='\0';}}/*判断是否为标志符和关键字即由字母开头并且不含标点符号用ispunct(int ch)判断标点符号*/if(isalpha(row[i]))//标志符或关键字由字母开头{k=0;while(i<=len&&row[i]!=32&&!(row[i]=='\0'||row[i]==':'||row[i]=='>'||row[i]=='<'||row[i]=='+' || row[i]=='-' || ro w[i]=='*' || row[i]=='/' || row[i]=='(' || row[i]==')' || row[i]==',' || row[i]==';'|| row[i]=='.'|| row[i]=='#' || row[i]=='='))/ /关键字和标志符由数字和字母组成{if(isalpha(row[i])||isdigit(row[i]))//由数字和字母组成{str0[k]=row[i];i++;k++;}else//出错,原因可能是出现了不可识别的字符{ferror=1;break;}}if(ferror){for(int j=0;j<k;j++)putchar(str0[j]);while(i<=len&&!isspace(row[i])&&!(row[i]=='\0'||row[i]==':'||row[i]=='>'||row[i]=='<'||row[i]=='+' || row[i]=='-' || row[i]=='*' || row[i]=='/' || row[i]=='(' || row[i]==')' || row[i]==',' || row[i]==';'|| row[i]=='.'|| row[i]=='#' || row[i]==' =')){putchar(row[i]);//消除整个非法单词i++;}ferror=0;error(3);//i--;}else{str0[k]='\0';strcpy(word,str0);str0[0]='\0';i--;}}/*判断运算符*/if(row[i]=='+' ||row[i]=='-' ||row[i]=='*' || row[i]=='/' || row[i]=='(' || row[i]==')' || row[i]==',' || row[i]==';'||row[ i]=='.'||row[i]=='#' || row[i]=='='){str0[0]=row[i];str0[1]='\0';strcpy(word,str0);str0[0]='\0';}//要先判断单个字符的运算符,以避免诸如>=的运算符后面的=再次被判断if(row[i]==':'){i++;if(row[i]=='='){//word[0]=':';//word[1]='=';//word[2]='\0';strcpy(word,">=");}else{error(2);//出错后调用处理函数i--;}}if(row[i]=='>'){i++;if(row[i]=='='){strcpy(word,">=");}else{strcpy(word,">");i--;}}if(row[i]=='<'){i++;if(row[i]=='='){strcpy(word,"<=");}else{strcpy(word,"<");i--;}}//puts(word);check(word,op);/*调用分类函数,辨别每一个单词的类别要求输入的每一个单词必须符合词法规则*///word[0]='\0';i++;//使指针后移,取出下一个字母}}void check(char *str,FILE *out){if(isdigit(str[0]))/*如果第一个字符是数字那么整个单词都是数字组成的,即为常数*/ {write(str,'d',out);//调用写函数将分好类的单词写入文件}if(isalpha(str[0]))/*如果第一个字符是字母,那么这个单词是标志符或关键字*/ {int fyiyong=0;//用作标记这个单词是否已被分类/*以下判别是否是关键字*/for(int ct=0;ct<13;ct++){if(!strcmp(str,kword[ct])){write(str,ktype[ct],out);fyiyong=1;}}/*经过以上判别,可以判别是否是关键字,不是即为标志符*/if(fyiyong!=1){write(str,'e',out);}}/*以下对运算符分类*/if(str[0]=='>'){if(str[1]=='='){write(str,'b',out);}else{write(str,'>',out);}}if(str[0]=='<'){if(str[1]=='='){write(str,'c',out);else{write(str,'<',out);}}if(!strcmp(str,":=")){write(str,'a',out);}if(str[0]=='+' || str[0]=='-' || str[0]=='*' || str[0]=='/' || str[0]=='(' || str[0]==')' || str[0]==',' || str[0]==';'|| str[0]=='.'|| st r[0]=='#' || str[0]=='=' ){write(str,str[0],out);}}void main(){count=1;char scfilename[20],rsfilename[20];//定义用来存放输入源文件和输出目标文件的名字printf("Please input your source file name:");gets(scfilename);printf("Please input your result file name:");gets(rsfilename);FILE *fp,*op;fp=fopen(scfilename,"r");op=fopen(rsfilename,"w");if(fp)//打开文件成功后调用函数对源文件进行词法分析{while(readbuffer(fp)){fenxi(buffer,op);count++;//行加一}}else//while the file not exist{printf("Your souce file not exist\n"); exit(0);}fclose(fp);//close the filesfclose(op);printf("ok!");//output the mark of end getchar();}。
第2章 PL0语言简介
![第2章 PL0语言简介](https://img.taocdn.com/s3/m/b2a4463331126edb6f1a10a8.png)
常量说明部分 *) 变量说明部分 *) 过程说明部分 *)
PL/0程序 示例
DO
Q的过程体
P的过程体 主程序体
程序
分程序
.
内的文字表示非终结符 或 内的文字或符号表示终结符
分程序
const
ident ,
=
number
;
var
, ;
ident
;
procedure
ident
;
分〉的递归子程序实现
procedure term; begin factor; while sym in [ times, slash ] do begin getsym; factor; end end;
〈因子〉的递归子程序实现 procedure factor; begin if sym <> ident then begin if sym <> number then begin if sym = ‘(‘ then begin getsym; expr; if sym = ‘)’ then getsym else error end else error end end end;
READ ( <标识符> )
A
递归子程序法
递归子程序法:对应每个非终结符语法单元,,编一 个独立的处理过程(或子程序)。语法分析从读入第 一个单词开始,由非终结符<程序>(即开始符)出发, 沿语法描述图箭头所指出的方向进行分析。当遇到非 终结符时,则调用相应的处理过程,从语法描述图看, 也就进入了一个语法单元,再沿当前所进入的语法单 元所指箭头方向继续进行分析。当遇到描述图中是终 结符时,则判断当前读入的单词是否与图中的终结符 相匹配,若匹配,再读取下一个单词继续分析。遇到 分支点时,将当前的单词与分支点上多个终结符逐个 相比较,若都不匹配时可能是进入下一个非终结符语 法单位或是出错。
词法分析程序(C语言编写,针对PL_0语言)
![词法分析程序(C语言编写,针对PL_0语言)](https://img.taocdn.com/s3/m/0397880fbb68a98271fefa74.png)
#include <stdio.h>#include <stdlib.h>#include <string.h>#define NORW 13 /* of reserved words */#define TXMAX 100 /* length of identifier table */#define NMAX 14 /* max number of digits in numbers */#define AL 10 /* length of identifiers */#define AMAX 2047 /* maxinum address */#define LEVMAX 3 /* max depth of block nesting */#define CXMAX 200 /* size of code array */#define STACKSIZE 500char *symbol[32]= {"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"}; /* type of symbols */c har *word[NORW]={"begin","call","const","do","end","if","odd","procedure","read","then","var","while","write"}; /* table of reserved words */ char *wsym[NORW]={ "beginsym","callsym","constsym","dosym","endsym","ifsym", "oddsym","procsym","readsym","thensym","varsym","whilesym","writesym"};char *mnemonic[8]= {"lit","opr","lod","sto","cal","ini","jmp","jpc"};char ch; /* last char read */char id[AL+1]; /*last identifier read */char sym[10]; /* last symbol read */char line[81];char a[AL+1],fname[AL+1];enum object{constant,variable,procedur};enum object kind;enum fct{lit,opr,lod,sto,cal,ini,jmp,jpc};enum listswitcher{false,true}; /*true set list object code */enum listswitcher listswitch;FILE *fa;FILE *fa1, *fa2;FILE *fin, *fout;int num; /* last number read */int cc; /* character count */int ll; /* line length */int cx; /* code allocation index */int err;int lev=0,tx=0,dx=3;int linecnt=0;struct instruction{enum fct f; /* function code */int l; /* level */int a; /* displacement addr */}; /* lit 0,a: load constant aopr 0,a: execute opr alod l,a: load variable 1, asto l,a: store variable 1, acal l,a: call procedure a at level 1int 0,a: increment t-register by ajmp 0,a: jump to ajpc 0,a: jump conditional to a */ struct instruction code[CXMAX+1];struct table1{char name[AL+1];enum object kind;int val,level,adr,size;};struct table1 table[TXMAX+1];struct node{c har *pa[32];}*declbegsys,*statbegsys,*facbegsys,*tempsetsys; int in(str, set)char *str;struct node *set;{i nt i=0;w hile(set->pa[i]!=NULL){if(strcmp(str,set->pa[i])==0)return( 1 );elsei++;}r eturn( 0 );}struct node *add(set1,set2)struct node *set1,*set2;{i nt i=0,j=0,k=0,cnt;s truct node *pt;p t=(struct node *)malloc(sizeof(struct node));f or(cnt=0; cnt < 32; cnt++)pt->pa[cnt]=(char*)malloc(10*sizeof(char));w hile(set1->pa[i]!=NULL)strcpy(pt->pa[j++],set1->pa[i++]);w hile(set2->pa[k]!=NULL){if (in(set2->pa[k],set1)==0)strcpy(pt->pa[j++],set2->pa[k++]);elsek++;}p t->pa[j]=NULL;r eturn( pt );}error(int n){i nt i;p rintf ("***");f puts ("***", fa1);f or (i=0;i<cc;i++){printf (" ");}f or (i=0;i<cc;i++){fputs (" ",fa1);}p rintf ("error%d\n",n);f printf (fa1, "error%d\n",n);e rr=err+1;}void get_ch( ){i f (cc==ll+1){if (feof(fin)){printf ("program incomplete");}ll= 0;cc= 0;while ((!feof(fin)) && ((ch=fgetc(fin))!='\n')){putchar(ch);fputc(ch,fa1);line[ll++]=ch;}printf ("\n");line[ll]=ch;fprintf (fa1,"\n");}c h=line[cc++];}void getsym( ){i nt i,j,k;w hile(ch==' '||ch=='\t'||ch=='\n')get_ch( );i f (ch>='a'&&ch<='z'){ /* id or reserved word */k=0;do {if(k<AL){a[k]=ch;k=k+1;}get_ch( );}while((ch>='a'&&ch<='z')||(ch>='0'&&ch<='9'));a[k]='\0';strcpy(id,a);i=0;j=NORW-1;do { /* look up reserved words by binary search */k=(i+j)/2;if (strcmp(id,word[k])<=0) j=k-1;if (strcmp(id,word[k])>=0) i=k+1;}while (i<=j);if (i-1>j) strcpy(sym,wsym[k]);else strcpy(sym,"ident");}e lse if (ch>='0'&&ch<='9'){ /* number */k=0;num=0;strcpy(sym,"number");do {num=10*num+(int)ch-'0';k=k+1;get_ch( );}while(ch>='0'&&ch<='9');if(k>NMAX) error(30);}e lse if (ch==':'){get_ch( );if (ch=='='){strcpy(sym,"becomes");get_ch( );}else strcpy(sym,"nul");}e lse if (ch=='<'){get_ch( );if (ch=='='){strcpy(sym,"leq");get_ch( );}else strcpy(sym,"lss");}e lse if (ch=='>'){get_ch( );if (ch=='='){strcpy(sym,"geq");get_ch( );}else strcpy(sym,"gtr");}e lse {switch(ch){case '+': strcpy(sym,"plus");break;case '-': strcpy(sym,"minus");break;case '*': strcpy(sym,"times");break;case '/': strcpy(sym,"slash");break;case '(': strcpy(sym,"lparen");break;case ')': strcpy(sym,"rparen");break;case '=': strcpy(sym,"eql");break;case ',': strcpy(sym,"comma");break;case '.': strcpy(sym,"period");break;case '#': strcpy(sym,"neq");break;case ';': strcpy(sym,"semicolon");break;}get_ch( );}}void gen(x,y,z)enum fct x;int y,z;{i f (cx>CXMAX){printf("program too long");}c ode[cx].f=x;c ode[cx].l=y;c ode[cx].a=z;c x++;}void test(s1,s2,n)struct node *s1,*s2;int n;{i f (in(sym,s1)==0){error(n);s1=add(s1,s2);while(in(sym,s1)==0) getsym( );}}void enter(k) /* enter object into table */ enum object k;{t x=tx+1;s trcpy(table[tx].name,id);t able[tx].kind=k;s witch(k){case constant:if (num>NMAX){error(31);num=0;}table[tx].val=num;break;case variable:table[tx].level=lev;table[tx].adr=dx;dx++;break;case procedur:table[tx].level=lev;break;}}int position(id) /* find identifier in table */ char id[10];{i nt i;s trcpy(table[0].name,id);i=tx;w hile (strcmp(table[i].name,id)!=0)i--;r eturn i;}void constdeclaration( ){i f (strcmp(sym,"ident")==0){getsym( );if (strcmp(sym,"eql")==0||strcmp(sym,"becomes")==0){if (strcmp(sym,"becomes")==0) error(1);getsym( );if (strcmp(sym,"number")==0){enter(constant);getsym( );}else error(2);}else error(3);}e lse error(4);}void vardeclaration( ){i f (strcmp(sym,"ident")==0){enter(variable);getsym( );}e lse error(4);}void listcode(int cx0) /* list code generated for this block */ {i nt i;i f (listswitch==true){for(i=cx0;i<=cx-1;i++){printf("%2d %5s %3d %5d\n",i,mnemonic[(int)code[i].f],code[i].l,code[i].a);fprintf(fa,"%2d %5s %3d %5d\n",i,mnemonic[(int)code[i].f],code[i].l,code[i].a);}}}void factor(fsys)struct node *fsys;{v oid expression( );i nt m=0,n=0,i;c har *tempset[ ]={"rparen",NULL};s truct node *temp;t emp=(struct node *)malloc(sizeof(struct node));w hile(tempset[m]!=NULL)temp->pa[n++]=tempset[m++];t emp->pa[n]=NULL;t est(facbegsys,fsys,24);w hile(in(sym,facbegsys)==1){if (strcmp(sym,"ident")==0){i=position(id);if (i==0) error(11);else switch(table[i].kind){case constant: gen(lit,0,table[i].val);break; /*some thing error here(lev)*/ case variable: gen(lod,lev-table[i].level,table[i].adr);/*must use para pass in*/break;case procedur: error(21);break;}getsym( );}else if (strcmp(sym,"number")==0){if (num>AMAX){error(31);num=0;}gen(lit,0,num);getsym( );}else if (strcmp(sym,"lparen")==0){getsym( );expression(add(temp,fsys));if (strcmp(sym,"rparen")==0) getsym( );else error(22);}test(fsys,facbegsys,23);}}void term(fsys)struct node *fsys;{i nt i=0,j=0;c har mulop[10];c har *tempset[ ]={"times","slash",NULL};s truct node *temp;t emp=(struct node *)malloc(sizeof(struct node));w hile(tempset[i]!=NULL)temp->pa[i++]=tempset[j++];t emp->pa[i]=NULL;f actor(add(temp,fsys));w hile (in(sym,temp)==1){strcpy(mulop,sym);getsym( );factor(add(temp,fsys));if (strcmp(mulop,"times")==0) gen(opr,0,4);else gen(opr,0,5);}}void expression(fsys)struct node *fsys;{i nt m=0,n=0;c har addop[10];c har *tempset[ ]={"plus","minus",NULL};s truct node *temp;t emp=(struct node *)malloc(sizeof(struct node));w hile(tempset[m]!=NULL)temp->pa[n++]=tempset[m++];t emp->pa[n]=NULL;i f(in(sym,temp)==1){strcpy(addop,sym);getsym( );term(add(fsys,temp));if (strcmp(addop,"minus")==0) gen(opr,0,1);}e lse term(add(fsys,temp));w hile (in(sym,temp)==1){strcpy(addop,sym);getsym( );term(add(fsys,temp));if (strcmp(addop,"plus")==0) gen(opr,0,2);else gen(opr,0,3);}}void condition(fsys)struct node *fsys;{i nt i=0,j=0;c har relop[10];c har *tempset[ ]={"eql","neq","lss","leq","gtr","geq",NULL}; s truct node *temp;t emp=(struct node *)malloc(sizeof(struct node));w hile(tempset[i]!=NULL)temp->pa[j++]=tempset[i++];t emp->pa[j]=NULL;i f (strcmp(sym,"oddsym")==0){getsym( );expression(fsys);gen(opr,0,6);}e lse {expression(add(temp,fsys));if (in(sym,temp)==0) error(20);else {strcpy(relop,sym);getsym( );expression(fsys);if(strcmp(relop,"eql")==0) gen(opr,0,8);if(strcmp(relop,"neq")==0) gen(opr,0,9);if(strcmp(relop,"lss")==0) gen(opr,0,10);if(strcmp(relop,"geq")==0) gen(opr,0,11);if(strcmp(relop,"gtr")==0) gen(opr,0,12);if(strcmp(relop,"leq")==0) gen(opr,0,13);}}}void statement(fsys,plev)struct node *fsys;int plev;{i nt i,cx1,cx2,m=0,n=0;c har *tempset1[ ]={"rparen","comma",NULL};c har *tempset2[ ]={"thensym","dosym",NULL};c har *tempset3[ ]={"semicolon","endsym",NULL};c har *tempset4[ ]={"semicolon",NULL};c har *tempset5[ ]={"dosym",NULL};c har *tempset6[ ]={NULL};s truct node *temp1,*temp2,*temp3,*temp4,*temp5,*temp6; t emp1=(struct node *)malloc(sizeof(struct node));t emp2=(struct node *)malloc(sizeof(struct node));t emp3=(struct node *)malloc(sizeof(struct node));t emp4=(struct node *)malloc(sizeof(struct node));t emp5=(struct node *)malloc(sizeof(struct node));t emp6=(struct node *)malloc(sizeof(struct node));w hile(tempset1[m]!=NULL)temp1->pa[n++]=tempset1[m++];t emp1->pa[n]=NULL;m=0;n=0;w hile(tempset2[m]!=NULL)temp2->pa[n++]=tempset2[m++];t emp2->pa[n]=NULL;m=0;n=0;w hile(tempset3[m]!=NULL)temp3->pa[n++]=tempset3[m++];t emp3->pa[n]=NULL;m=0;n=0;w hile(tempset4[m]!=NULL)temp4->pa[n++]=tempset4[m++];t emp4->pa[n]=NULL;m=0;n=0;w hile(tempset5[m]!=NULL)temp5->pa[n++]=tempset5[m++];t emp5->pa[n]=NULL;m=0;n=0;w hile(tempset6[m]!=NULL)temp6->pa[n++]=tempset6[m++];t emp6->pa[n]=NULL;m=0;n=0;i f (strcmp(sym,"ident")==0){i=position(id);if (i==0)error(11);else {if (table[i].kind!=variable){error(12);i=0;}}getsym( );if (strcmp(sym,"becomes")==0) getsym( );else error(13);expression(fsys);if (i!=0)gen(sto,plev-table[i].level,table[i].adr);}e lse if (strcmp(sym,"readsym")==0){getsym( );if (strcmp(sym,"lparen")!=0) error(24);else {do{getsym( );if (strcmp(sym,"ident")==0) i=position(id);else i=0;if (i==0) error(35);else {gen(opr,0,16);gen(sto,plev-table[i].level,table[i].adr);}getsym( );}while(strcmp(sym,"comma")==0);}if (strcmp(sym,"rparen")!=0) {error(22);while(in(sym,fsys)==0) getsym( );}else getsym( );}e lse if (strcmp(sym,"writesym")==0){getsym( );if (strcmp(sym,"lparen")==0){do{getsym( );expression(add(temp1,fsys));gen(opr,0,14);}while(strcmp(sym,"comma")==0);if (strcmp(sym,"rparen")!=0) error(33);else getsym( );}gen(opr,0,15);}e lse if (strcmp(sym,"callsym")==0){getsym( );if (strcmp(sym,"ident")!=0) error(14);else {i=position(id);if (i==0) error(11);else {if (table[i].kind==procedur)gen(cal,plev-table[i].level,table[i].adr);else error(15);}getsym( );}}e lse if (strcmp(sym,"ifsym")==0){getsym( );condition(add(temp2,fsys));if (strcmp(sym,"thensym")==0) getsym( );else error(16);cx1=cx;gen(jpc,0,0);statement(fsys,plev);code[cx1].a=cx;}e lse if (strcmp(sym,"beginsym")==0){getsym( );statement(add(temp3,fsys),plev);while(in(sym,add(temp4,statbegsys))==1){if (strcmp(sym,"semicolon")==0) getsym( );else error(10);statement(add(temp3,fsys),plev);}if (strcmp(sym,"endsym")==0) getsym( );else error(17);}e lse {if (strcmp(sym,"whilesym")==0){cx1=cx;getsym( );condition(add(temp5,fsys));cx2=cx;gen(jpc,0,0);if (strcmp(sym,"dosym")==0) getsym( );else error(18);statement(fsys,plev);gen(jmp,0,cx1);code[cx2].a=cx;}}t est(fsys,temp6,19);}void block(plev,fsys)int plev;struct node *fsys;{i nt m=0,n=0;i nt dx0=3; /* data allocation index */ i nt tx0; /* initial table index */i nt cx0; /* initial code index */c har *tempset1[ ]={"semicolon","endsym",NULL};c har *tempset2[ ]={"ident","procsym",NULL};c har *tempset3[ ]={"semicolon",NULL};c har *tempset4[ ]={"ident",NULL};c har *tempset5[ ]={NULL};s truct node *temp1,*temp2,*temp3,*temp4,*temp5;t emp1=(struct node *)malloc(sizeof(struct node));t emp2=(struct node *)malloc(sizeof(struct node));t emp3=(struct node *)malloc(sizeof(struct node));t emp4=(struct node *)malloc(sizeof(struct node));t emp5=(struct node *)malloc(sizeof(struct node));w hile(tempset1[m]!=NULL)temp1->pa[n++]=tempset1[m++];t emp1->pa[n]=NULL;m=0;n=0;w hile(tempset2[m]!=NULL)temp2->pa[n++]=tempset2[m++];t emp2->pa[n]=NULL;m=0;n=0;w hile(tempset3[m]!=NULL)temp3->pa[n++]=tempset3[m++];t emp3->pa[n]=NULL;m=0;n=0;w hile(tempset4[m]!=NULL)temp4->pa[n++]=tempset4[m++];t emp4->pa[n]=NULL;m=0;n=0;w hile(tempset5[m]!=NULL)temp5->pa[n++]=tempset5[m++];t emp5->pa[n]=NULL;m=0;n=0;l ev=plev;t x0=tx;t able[tx].adr=cx;g en(jmp,0,1);i f (plev>LEVMAX) error(32);d o{if (strcmp(sym,"constsym")==0){getsym( );do{constdeclaration( );while(strcmp(sym,"comma")==0){getsym( );constdeclaration( );}if (strcmp(sym,"semicolon")==0) getsym( );else error(5);}while(strcmp(sym,"ident")==0);}if (strcmp(sym,"varsym")==0){getsym( );do{dx0++;vardeclaration( );while (strcmp(sym,"comma")==0){getsym( );dx0++;vardeclaration( );}if (strcmp(sym,"semicolon")==0) getsym( );else error(5);}while(strcmp(sym,"ident")==0);}while (strcmp(sym,"procsym")==0){getsym( );if (strcmp(sym,"ident")==0){enter(procedur);getsym( );}else error(4);if (strcmp(sym,"semicolon")==0) getsym( );else error(5);block(plev+1,add(temp3,fsys));lev=lev-1;if (strcmp(sym,"semicolon")==0){getsym( );test(add(statbegsys,temp2),fsys,6);}else error(5);}test(add(statbegsys,temp4),declbegsys,7);}while(in(sym,declbegsys)==1);c ode[table[tx0].adr].a=cx;t able[tx0].adr=cx;t able[tx0].size=dx0;c x0=cx;g en(ini,0,dx0);s tatement(add(temp1,fsys),plev);g en(opr,0,0);t est(fsys,temp5,8);l istcode(cx0);}int base(l,b,s)int l;int *b;int s[STACKSIZE];{int b1;b1=*b; /*find base l level down */ while(l>0){b1=s[b1];l=l-1;}return b1;}void interpret( ){i nt p=0; /* p:program register*/ i nt b=1; /* b:base register*/i nt t=0; /* t:topstack registers */ s truct instruction i;i nt s[STACKSIZE]; /* datastore */p rintf("start pl0\n");s[0]=0;s[1]=0;s[2]=0;s[3]=0;d o{i=code[p];p=p+1;switch(i.f){case lit: t=t+1;s[t]=i.a;break;case opr:switch(i.a){ /*operator*/case 0: t=b-1; /*return*/p=s[t+3];b=s[t+2];break;case 1: s[t]=-s[t];break;case 2: t=t-1; /*plus*/s[t]=s[t]+s[t+1];break;case 3: t=t-1; /*minus*/s[t]=s[t]-s[t+1];break;case 4: t=t-1; /*times*/s[t]=s[t]*s[t+1];break;case 5: t=t-1;s[t]=s[t]/s[t+1];break;case 6: if (s[t]%2==0) s[t]=0;else s[t]=1;break;case 8: t=t-1;if (s[t]==s[t+1]) s[t]=1;else s[t]=0;break;case 9: t=t-1;if (s[t]==s[t+1]) s[t]=0;else s[t]=1;break;case 10:t=t-1;if (s[t]<s[t+1]) s[t]=1;else s[t]=0;break;case 11:t=t-1;if (s[t]>=s[t+1]) s[t]=1;else s[t]=0;break;case 12:t=t-1;if (s[t]>s[t+1]) s[t]=1;else s[t]=0;break;case 13:t=t-1;if (s[t]<=s[t+1]) s[t]=1;else s[t]=0;break;case 14:printf("%d",s[t]);fprintf(fa2,"%d",s[t]);t=t-1;break;case 15:printf("\n");fprintf(fa2,"\n");break;case 16:t=t+1;printf("?");fprintf(fa2,"?");scanf("%d",&s[t]);fprintf(fa2,"%d",s[t]);break;}break;case lod: t=t+1;s[t]=s[base(i.l,&b,s)+i.a];break;case sto: s[base(i.l,&b,s)+i.a]=s[t]; /*ptrintf("%d",s[t])*/t=t-1;break;case cal: s[t+1]=base(i.l,&b,s); /*generate new block mark */ s[t+2]=b;s[t+3]=p;b=t+1;p=i.a;break;case ini:t=t+i.a;break;case jmp:p=i.a;break;case jpc:if (s[t]==0) p=i.a;t=t-1;break;}}while(p!=0);f close(fa2);}main( ){i nt m=0,n=0;c har *declbeg[ ]={"constsym","varsym","procsym",NULL};c har *statbeg[ ]={"beginsym","callsym","ifsym","whilesym",NULL};c har *facbeg[ ]={"ident","number","lparen",NULL};c har *tempset[ ]={"period","constsym","varsym","procsym",NULL};d eclbegsys=(struct node *)malloc(sizeof(struct node));s tatbegsys=(struct node *)malloc(sizeof(struct node));f acbegsys=(struct node *)malloc(sizeof(struct node));t empsetsys=(struct node *)malloc(sizeof(struct node));w hile(declbeg[m]!=NULL)declbegsys->pa[n++]=declbeg[m++];d eclbegsys->pa[n]=NULL;m=0;n=0;w hile(statbeg[m]!=NULL)statbegsys->pa[n++]=statbeg[m++];s tatbegsys->pa[n]=NULL;m=0;n=0;w hile(facbeg[m]!=NULL)facbegsys->pa[n++]=facbeg[m++];f acbegsys->pa[n]=NULL;m=0,n=0;w hile(tempset[m]!=NULL)tempsetsys->pa[n++]=tempset[m++];t empsetsys->pa[n]=NULL;i f((fa1=fopen("fa1.txt","w"))==NULL){printf("Cannot open file\n");exit( 0 );}p rintf("Input file?\n");f printf(fa1,"Input file?\n");s canf("%s",fname);f printf(fa1,"%s",fname);i f((fin=fopen(fname,"r"))==NULL){printf("Cannot open file according to given filename\n");exit( 0 );}p rintf("list object code?\n");s canf("%s",fname);f printf(fa1,"list object code?\n");i f (fname[0]=='y')listswitch=true;e lselistswitch=false;e rr=0;c c=1; cx=0; ll=0;c h=' ';g etsym( );i f((fa=fopen("fa.txt","w"))==NULL){printf("Cannot open fa.txt file\n");exit( 0 );}i f((fa2=fopen("fa2.txt","w"))==NULL){printf("Cannot open fa2.txt file\n");exit( 0 );}b lock(0,add(statbegsys,tempsetsys));f close(fa);f close(fa1);i f (strcmp(sym,"period")!=0)error(9);i f (err==0)interpret( );elseprintf("%d errors in PASCAL program\n",err);f close (fin);}。
pl0函数注释
![pl0函数注释](https://img.taocdn.com/s3/m/5314d9d5195f312b3169a50e.png)
// pl0 compiler source code#include <stdio.h>#include <stdlib.h>#include <string.h>#include <ctype.h>#include "set.h"#include "pl0.h"//////////////////////////////////////////////////////////////////////// print error message.//出错报告过程void error(n){//打印字符串数组err_msg对应的下标为n的字符串int i;printf(" ");for (i = 1; i <= cc - 1; i++)printf(" ");fprintf(outfile, " ");fprintf(outfile, "^\n");printf("^\n");fprintf(outfile, "Error %3d: %s\n", n, err_msg[n]);printf("Error %3d: %s\n", n, err_msg[n]);err++;} // error//////////////////////////////////////////////////////////////////////void getch(void)//获得字符{if (cc == ll){if (feof(infile))//检查文件是否结束结束返回非零值否则返回0{printf("\nPROGRAM INCOMPLETE\n");exit(1);}ll = cc = 0;//line length ,character countfprintf(outfile, "%5d ", cx);printf("%5d ", cx);while ( (!feof(infile)) // added & modified by alex 01-02-09&& ((ch = getc(infile)) != '\n'))//从文件infile中读取字符并放ch中{fprintf(outfile, "%c", ch);printf("%c", ch);line[++ll] = ch;//将从文件中读取的字符存储在数组line中} // whilefprintf(outfile, "\n");printf("\n");line[++ll] = ' ';}ch = line[++cc];//将当前第一个读取到的字符赋值给ch;字符数+1;} // getch//////////////////////////////////////////////////////////////////////// gets a symbol from input stream.void getsym(void){int i, k;char a[MAXIDLEN + 1];while (ch == ' '|| ch == '\t') //若是空格或是制表符直接跳过获取下一字符// modified by yzhang 02-03-12,add some white spacegetch();//判断ch是保留字或者是标识符if (isalpha(ch))//判断字符ch是否为英文字母若为英文字母返回非零值否则返回零{ // symbol is a reserved word or an identifier. 判断是为标识符和保留字k = 0;//k记录当前数组a中存入的字符个数do{if (k < MAXIDLEN)a[k++] = ch;//将ch放进数组a中getch();//读取下一字符}//若当前字符是字母或者数字循环执行while (isalpha(ch) || isdigit(ch));//isdigit函数判断字符c是否为数字若为数字返回非零a[k] = 0;strcpy(id, a);//id在文件p10.h中声明为char型数组将数组a中的内容给数组idword[0] = id;//word在文件p10.h中声明为存储保留字的字符串数组将该数组的第一个元素赋值为idi = NRW;//令i的值为保留字的数目while (strcmp(id, word[i--]));//将字符串id与Word中保留字对应的字符串进行比较if (++i)//表示id是已存在于word数组中的保留字sym = wsym[i]; // symbol is a reserved wordelse//id不是已定义的保留字是标识符sym = SYM_IDENTIFIER; // symbol is an identifier}//判断ch是否是数字else if (isdigit(ch))//判断字符ch是否为数字若为数字返回非零值否则返回零{ // symbol is a number.k = num = 0;sym = SYM_NUMBER;do{num = num * 10 + ch - '0';//将读进的数字转化为对应的十进制数存储在num 中k++;getch();//读取下一字符}while (isdigit(ch));//当为数字是循环写入if (k > MAXNUMLEN) //该数字中所含数字的个数大于MAXNUMLENerror(25); // The number is too great.该数字过大}//判断ch是否是关系运算符else if (ch == ':')//如果当前字符是':'{getch();//获取下一字符if (ch == '=')//下一字符为'=',表示赋值{sym = SYM_BECOMES; // :=getch();//继续读取字符}else//非法字符{sym = SYM_NULL; // illegal?}}else if (ch == '>')//如果当前字符为'>'{getch();//获取下一字符if (ch == '=')//下一字符为'=' ,表示>={sym = SYM_GEQ; // >=getch();}else//表示>{sym = SYM_GTR; // >}}else if (ch == '<')//如果当期字符为'<'{getch();if (ch == '=')//读取下一字符为'=',表示<={sym = SYM_LEQ; // <=getch();}else if (ch == '>')//读取下一字符为'>',表示<>不相等{sym = SYM_NEQ; // <>getch();}else//表示'<'{sym = SYM_LES; // <}}//判断ch是否是算术运算符else//是其他字符{ // other tokensi = NSYM;//令i的值为NSYMcsym[0] = ch;//令数组csym的0号元素为当前字符chwhile (csym[i--] != ch);//在csym中查找是否存在ch ,判断ch是否是运算符if (++i)//存在,表示ch为运算符{sym = ssym[i];getch();}else//出错ch为未知符号{printf("Fatal Error: Unknown character.\n");fprintf(outfile, "Fatal Error: Unknown character.\n");exit(1);}}} // getsym//////////////////////////////////////////////////////////////////////// generates (assembles) an instruction.//代码生成void gen(int x, int y, int z)//将x,y,z放入code数组{if (cx > CXMAX)//cx的值大于CXMAX(size of code array)当前生成代码的行号大于允许的最大代码行数//报错{fprintf(outfile, "Fatal Error: Program too long.\n");printf("Fatal Error: Program too long.\n");exit(1);}//将x,y,z 对应赋值给数组code中下标为cx的元素//把代码写进当前目标代码数组当前cx所指的位置code[cx].f = x;code[cx].l = y;code[cx++].a = z;//并移动cx指向下一个空位} // gen//////////////////////////////////////////////////////////////////////// tests if error occurs and skips all symbols that do not belongs to s1 or s2.//测试是否出现错误并跳过所有不属于s1和s2的符号//出错恢复过程void test(symset s1, symset s2, int n){//s1:当语法分析进入或退出某一语法单元时当前单词符合应属于的集合//s2:在某一出错状态下,可恢复语法分析正常工作的补充单词集合//n:出错信息编号,当当前符号不属于合法的s1集合时发出的出错信息symset s;if (! inset(sym, s1))//调用inset函数判断sym是否在s1中{//当前符号符号不在s1中showset(s1);//调用showset 函数输出s1和s2中的元素showset(s2);printf("sym=%d, id=%s\n", sym, id);error(n);//报错s = uniteset(s1, s2);//将s1和s2合并并赋值给swhile(! inset(sym, s))getsym();//通过循环找到下一个合法的符号,以恢复语法分析工作destroyset(s);//删除s}} // test//////////////////////////////////////////////////////////////////////int dx; // data allocation index 数据分配指数// enter object(constant, variable or procedre) into table.//登陆名字表过程void enter(int kind){mask* mk;// added by yzhang 02-02-28//id在table中已经存在报错标识符重复定义if ( position(id)> 0 ){error(26); //Redeclared identifier.}// end//id在table中不存在tx++;//table中所含标识符个数+1strcpy(table[tx].name, id);//将id赋值给table中第tx号元素table[tx].kind = kind;switch (kind)//判别id类型{case ID_CONSTANT://常数if (num > MAXADDRESS)//该数中所含数字个数过多{error(25); // The number is too great.num = 0;}table[tx].value = num;break;case ID_VARIABLE://变量mk = (mask*) &table[tx];mk->level = level;mk->address = dx++;break;case ID_PROCEDURE://程序mk = (mask*) &table[tx];mk->level = level;break;} // switch} // enter//////////////////////////////////////////////////////////////////////// locates identifier in symbol table.//查找id在table中的位置,并将位置返回//查询名字表过程int position(char* id){int i;strcpy(table[0].name, id);//将id赋值给table中的0号元素i = tx + 1;while (strcmp(table[--i].name, id) != 0);return i;//返回id在table中对应的下标} // position////////////////////////////////////////////////////////////////////////常量定义分析过程void constdeclaration(){if (sym == SYM_IDENTIFIER)//当前为标识符{getsym();//调用getsym函数,获取下一个tokenif (sym == SYM_EQU || sym == SYM_BECOMES)//当前字符特征表示为=或:={if (sym == SYM_BECOMES)//若为:=报错(常量声明中应为等号不是赋值号) error(1); // Found ':=' when expecting '='.1号错误getsym();//调用getsym(),获取下一个tokenif (sym == SYM_NUMBER)//读取的是数字{enter(ID_CONSTANT);//调用enter函数并传递参数ID_CONTANT 常数,把这个常量登录到符号表getsym();//调用getsym(),获取下一个token}else//读到的不是数字报错{error(2); // There must be a number to follow '='.等号后应接数字}}//常量标识符后接的不是=或:=else{error(3); // There must be an '=' to follow the identifier.}}//常量声明过程中遇到的第一个符号不是标识符报错else //added by yzhang 02-02-28error(4); // There must be an identifier to follow 'const', 'var', or 'procedure'.} // constdeclaration////////////////////////////////////////////////////////////////////////变量定义分析过程void vardeclaration(void){if (sym == SYM_IDENTIFIER)//当前为标识符{enter(ID_V ARIABLE);//将参数ID_V ARIABLE传递给函数enter,登陆到符号表getsym();//继续读取,获取下一个token}else//变量声明后遇到的第一个符号不是标识符报错{error(4); // There must be an identifier to follow 'const', 'var', or 'procedure'.}} // vardeclaration////////////////////////////////////////////////////////////////////////列出code代码过程void listcode(int from, int to){int i;printf("\n");fprintf(outfile, "\n");for (i = from; i < to; i++)//列出从from 到to-1的代码{printf("%5d %s\t%d\t%d\n", i, mnemonic[code[i].f], code[i].l, code[i].a);//同时打印进文件fprintf(outfile, "%5d %s\t%d\t%d\n", i, mnemonic[code[i].f], code[i].l, code[i].a);}printf("\n");fprintf(outfile, "\n");} // listcode////////////////////////////////////////////////////////////////////////因子处理过程void factor(symset fsys){void expression();int i;symset set;test(facbegsys, fsys, 24); // The symbol can not be as the beginning of an expression.// 开始因子处理前,先检查当前token是否在facbegsys 集合中while (inset(sym, facbegsys))//循环处理因子{if (sym == SYM_IDENTIFIER)//遇到的是标识符{if ((i = position(id)) == 0)//查符号表,找到当前标识符在符号表中的位置{error(11); //表示没有找到标识符// Undeclared identifier.}else//如果在符号表中找到了当前标识符的位置,开始生成相应代码{switch (table[i].kind){mask* mk;case ID_CONSTANT://如果这个标识符对应的是常量,值为value,生成lit 指令,把value放到栈顶gen(LIT, 0, table[i].value);break;case ID_VARIABLE:// 如果标识符是变量名,生成lod指令,//把位于距离当前层level的层的偏移地址为address 的变量放到栈顶mk = (mask*) &table[i];gen(LOD, level - mk->level, mk->address);break;case ID_PROCEDURE://如果在因子处理中遇到的标识符是过程名,出错,抛21号错error(21); // Procedure identifier can not be in an expression.break;} // switch}getsym();//获取下一个token}else if (sym == SYM_NUMBER)//遇到的是数字{if (num > MAXADDRESS)//数字过大,抛出25号错误{error(25); // The number is too great.num = 0;//把数字按0处理}gen(LIT, 0, num);//生成lit指令,把这个数值常量放到栈顶getsym();//获取下一个token}else if (sym == SYM_LPAREN)//遇到的是左括号{getsym();//获取下一个tokenset = uniteset(createset(SYM_RPAREN, SYM_NULL), fsys);//合并expression(set);//调用expression表达式分析过程,分析setdestroyset(set);//删除setif (sym == SYM_RPAREN)//遇到的是右括号{getsym();//获取下一个token}else//否则抛出错误,缺少右括号{error(22); // Missing ')'.}}else // added by yzhang 02-02-28test(fsys, createset(SYM_LPAREN, SYM_NULL), 23);//一个因子处理完毕,遇到的token应在fsys集合中,如果不是,抛23号错,//并找到下一个因子的开始,使语法分析可以继续运行下去} // while} // factor////////////////////////////////////////////////////////////////////////项处理过程void term(symset fsys){int mulop;symset set;set = uniteset(fsys, createset(SYM_TIMES, SYM_SLASH, SYM_NULL));factor(set);//调用因子处理过程,每一个项都应该由因子开始,因此调用factor子程序分析因子while (sym == SYM_TIMES || sym == SYM_SLASH)//一个因子后应当遇到乘号或除号{mulop = sym;//保存当前运算符getsym();//获取下一个tokenfactor(set);//运算符后应是一个因子,故调factor子程序分析因子if (mulop == SYM_TIMES)//遇到乘号{gen(OPR, 0, OPR_MUL);//生成乘法指令}else{gen(OPR, 0, OPR_DIV);//生成除法指令}} // whiledestroyset(set);//删除set} // term////////////////////////////////////////////////////////////////////////表达式处理过程void expression(symset fsys){int addop;symset set;set = uniteset(fsys, createset(SYM_PLUS, SYM_MINUS, SYM_NULL));//将fsys与新建的含有'+','-'的链表合并if (sym == SYM_PLUS || sym == SYM_MINUS)//若当前为'+'或'-',//一个表达式可能会由加号或减号开始,表示正负号{addop = sym;//把当前符号保存,并继续向下读取getsym();//获取下一个tokenterm(set);//调用项处理过程termif (addop == SYM_MINUS)//保存下来的是'-'{gen(OPR, 0, OPR_NEG);//生成取反指令}}else//如果不是由正负号开头,就应是一个项开头{term(set);//调用term子程序分析项}while (sym == SYM_PLUS || sym == SYM_MINUS)//项后应该是加减运算{addop = sym;//保存运算符getsym();//获取下一个tokenterm(set);//加减运算符后应跟一个项,调用term 分析项if (addop == SYM_PLUS)//保存的是'+',生成加法指令{gen(OPR, 0, OPR_ADD);}else//否则生成减法指令{gen(OPR, 0, OPR_MIN);}} // whiledestroyset(set);//删除set} // expression////////////////////////////////////////////////////////////////////////条件处理过程//fsys: 如果出错可用来恢复语法分析的符号集合void condition(symset fsys){int relop;//用来临时记录token内容symset set;if (sym == SYM_ODD)//如果是odd运算符{getsym();//获取下一个tokenexpression(fsys);//调用expression 进行处理运算gen(OPR, 0, 6);//生成6号指令:奇偶判断}else//不是odd运算符{set = uniteset(relset, fsys);//relset中存储逻辑运算符expression(set);//对表达式左部进行处理运算destroyset(set);if (! inset(sym, relset))//如果不是逻辑运算符,抛出20号错误{error(20);}else{relop = sym;//记录当前逻辑运算符getsym();//获取下一个tokenexpression(fsys);//对表达式右边进行处理switch (relop)//分析保存下来的逻辑运算符{case SYM_EQU://'=',生成判断相等的指令gen(OPR, 0, OPR_EQU);break;case SYM_NEQ://'-',生成判断不等的指令gen(OPR, 0, OPR_NEQ);break;case SYM_LES://'<',生成小于指令gen(OPR, 0, OPR_LES);break;case SYM_GEQ://'>=',生成大于等于的指令gen(OPR, 0, OPR_GEQ);break;case SYM_GTR://'>',生成大于的指令gen(OPR, 0, OPR_GTR);break;case SYM_LEQ://'<=',生成小于等于的指令gen(OPR, 0, OPR_LEQ);break;} // switch} // else} // else} // condition////////////////////////////////////////////////////////////////////////fsys:如果出错可用来恢复语法分析的符号集合void statement(symset fsys)//语句分析过程{int i, cx1, cx2;symset set1, set;if (sym == SYM_IDENTIFIER)//类型为标识符{ // variable assignmentmask* mk;if (! (i = position(id)))//id不在符号表中报错{error(11); // Undeclared identifier.}else if (table[i].kind != ID_V ARIABLE)//如果在符号表中找到该标识符,但不是变量报错{error(12); // Illegal assignment.i = 0;//i置0作为错误标志}getsym();//获取下一个tokenif (sym == SYM_BECOMES)//当前token为赋值{//读取下一个tokengetsym();}else//否则报错{error(13); // ':=' expected.}expression(fsys);//调用表达式处理过程expressionmk = (mask*) &table[i];if (i)//如果不曾出错,i将不为0,i所指为当前语名左部标识符在符号表中的位置{//产生一行把表达式值写往指定内存的STO目标代码gen(STO, level - mk->level, mk->address);}}else if (sym == SYM_CALL)//如果是CALL{ // procedure callgetsym();//获取下一个tokenif (sym != SYM_IDENTIFIER)//不是标识符,14号错误,call后应连接标识符{error(14); // There must be an identifier to follow the 'call'.}else{if (! (i = position(id)))//未在符号表中查找到该标识符,11号错误{error(11); // Undeclared identifier.}else if (table[i].kind == ID_PROCEDURE)//该标识符是过程名{mask* mk;mk = (mask*) &table[i];gen(CAL, level - mk->level, mk->address);//生成call目标代码,呼叫该过程}else//不是过程名,15号错误{error(15); // A constant or variable can not be called.}getsym();//或取下一个token} // else}else if (sym == SYM_IF)//如果是if{ // if statementgetsym();//获取下一个token(应为一个逻辑表达式)set1 = createset(SYM_THEN, SYM_DO, SYM_NULL);set = uniteset(set1, fsys);//出错恢复集中加入then和do语句condition(set);////对逻辑表达式进行分析计算destroyset(set1);//删除set1,setdestroyset(set);if (sym == SYM_THEN)//遇到then{getsym();//获取下一个token(应为一个语句)}else//没有遇到then,16号错误{error(16); // 'then' expected.}cx1 = cx;//记下当前代码分配指针位置gen(JPC, 0, 0);//生成跳转指令,跳转位置暂时填0,分析完语句后再填写statement(fsys);//分析then后语句code[cx1].a = cx;// 上一行指令(cx1所指的)的跳转位置应为当前cx所指位置}else if (sym == SYM_BEGIN)//如果遇到begin{ // blockgetsym();//获取下一个tokenset1 = createset(SYM_SEMICOLON, SYM_END, SYM_NULL);set = uniteset(set1, fsys);statement(set);//对begin和end之间的语句进行处理while (sym == SYM_SEMICOLON || inset(sym, statbegsys))//如果分析完一句后遇到分号或语句开始符{//循环分析if (sym == SYM_SEMICOLON)//遇到分号{getsym();//获取下一个token}else//否则报错{error(10);}statement(set);//分析语句} // whiledestroyset(set1);destroyset(set);if (sym == SYM_END)//遇到end{getsym();//或取下一个token}else//否则报错{error(17); // ';' or 'end' expected.}}else if (sym == SYM_WHILE)//遇到while{ // while statementcx1 = cx;//记下当前代码分配位置,这是while循环的开始位置getsym();//获取下一个tokenset1 = createset(SYM_DO, SYM_NULL);set = uniteset(set1, fsys);condition(set);//进行分析运算destroyset(set1);destroyset(set);cx2 = cx;//记下当前代码分配位置,这是while的do中的语句的开始位置gen(JPC, 0, 0);//生成条件跳转指令,跳转位置暂时填0if (sym == SYM_DO)//遇到do{getsym();//获取下一个token}else//报错{error(18); // 'do' expected.}statement(fsys);//分析do后的语句gen(JMP, 0, cx1);//循环跳转到cx1位置,即再次进行逻辑判断code[cx2].a = cx;//把刚才填0的跳转位置改成当前位置,完成while语句的处理}else //added by yzhang 02-02-28test(fsys, phi, 19);// 至此一个语句处理完成,一定会遇到fsys集中的符号,如果没有遇到,就抛19号错} // statement////////////////////////////////////////////////////////////////////////程序分析过程//fsys:用于出错恢复的单词集合void block(symset fsys){int cx0; // initial code index 记录本层开始时代码段分配位置mask* mk;//mask是在pl0.h中声明的结构体定义mask类的指针mkint block_dx;int savedTx;symset set1, set;dx = 3;//声明的全局变量数据分配指数//地址指示器给出每层局部量当前已分配到的相对位置。
PL0编译器源程序分析
![PL0编译器源程序分析](https://img.taocdn.com/s3/m/db64107e9b6648d7c1c746cb.png)
PL/0编译器源程序分析PL/0语言是Pascal语言的一个子集,我们这里分析的PL/0的编译程序包括了对PL/0语言源程序进行分析处理、编译生成类PCODE代码,并在虚拟机上解释运行生成的类PCODE代码的功能。
PL/0语言编译程序采用以语法分析为核心、一遍扫描的编译方法。
词法分析和代码生成作为独立的子程序供语法分析程序调用。
语法分析的同时,提供了出错报告和出错恢复的功能。
在源程序没有错误编译通过的情况下,调用类PCODE解释程序解释执行生成的类PCODE代码。
词法分析子程序分析:词法分析子程序名为getsym,功能是从源程序中读出一个单词符号(token),把它的信息放入全局变量sym、id和num中,语法分析器需要单词时,直接从这三个变量中获得。
(注意!语法分析器每次用完这三个变量的值就立即调用getsym子程序获取新的单词供下一次使用。
而不是在需要新单词时才调用getsym过程。
)getsym过程通过反复调用getch子过程从源程序过获取字符,并把它们拼成单词。
getch过程中使用了行缓冲区技术以提高程序运行效率。
词法分析器的分析过程:调用getsym时,它通过getch过程从源程序中获得一个字符。
如果这个字符是字母,则继续获取字符或数字,最终可以拼成一个单词,查保留字表,如果查到为保留字,则把sym变量赋成相应的保留字类型值;如果没有查到,则这个单词应是一个用户自定义的标识符(可能是变量名、常量名或是过程的名字),把sym置为ident,把这个单词存入id变量。
查保留字表时使用了二分法查找以提高效率。
如果getch获得的字符是数字,则继续用getch获取数字,并把它们拼成一个整数,然后把sym置为number,并把拼成的数值放入num变量。
如果识别出其它合法的符号(比如:赋值号、大于号、小于等于号等),则把sym则成相应的类型。
如果遇到不合法的字符,把sym置成nul。
语法分析子程序分析:语法分析子程序采用了自顶向下的递归子程序法,语法分析同时也根据程序的语意生成相应的代码,并提供了出错处理的机制。
PL0词法分析器
![PL0词法分析器](https://img.taocdn.com/s3/m/87972bde7f1922791688e891.png)
PL0词法分析器#include<stdio.h>#include<string.h>char symbol[] = {'+','-','*','/','(',')','=',',','.','#',';'};char ssym[][20] = {"plus","minus","tsimes","slash","lparen","rparen","eql","comma","peroid","neg","semicolon"}; char word[][20] = {"begin","call","const","do","end","if","odd","procedure","read","then","var","while","write"}; char wsym[][20] = {"beginsym","callsym","constsym","dosym","endsym","ifsym","oddsym","procsym","readsym"," thensym","varsym","whilesym","writesym"};intnumWord = 13; //保留字的个数为13个intnumSymbol = 11; //单符号个数FILE * fin;voidgetsym();void judgeConst(char* str); //保留字判断intjudgeSignel(char ch); //单符号判断boolchecknumber(char ch); //数字变量错误判断int main(){fin=fopen("in.txt","r");getsym();fclose(fin);return 0;}voidgetsym(){charch;ch = fgetc(fin);while(ch != '#'){if(ch>='a' &&ch<='z'){ //判断保留字与自定义变量charstr[50]="";do{str[strlen(str)]=ch;str[strlen(str)]='\0';ch = fgetc(fin);}while(ch>='a' &&ch<='z' || ch>='0' &&ch<='9');judgeConst(str);}else{if(ch>='0' &&ch<='9'){ //检测是否为数字:以0..9开头doublenum = 0.0;do{num = 10 * num + ch - '0'; //将char变为doublech = fgetc(fin);}while(ch>='0' &&ch<='9');if(!checknumber(ch)){printf("error : a word can't be in a number\n");return;}long div = 1;if (ch == '.'){//实型数的判断ch = fgetc(fin);while(ch>='0' &&ch<='9'){div = div * 10;num = num +static_cast<double>(ch-'0') / div; //转换ch = fgetc(fin); //强制装换成double.}if(!checknumber(ch)){printf("error : a word can't be in a number\n");return;}}printf("类型number , 名称%g\n",num);}else{if (ch == ':'){ //检测赋值符号charstr[50]="";str[strlen(str)]=ch;str[strlen(str)]='\0';ch = fgetc(fin);if (ch == '='){str[strlen(str)]=ch;str[strlen(str)]='\0';printf("类型becomes , 名称%s\n",str);}else{printf("类型notBecomes , 名称%s\n",str);}ch = fgetc(fin);}else{if (ch == '<'){ //检测小于或小于等于符号charstr[50]="";str[strlen(str)]=ch;str[strlen(str)]='\0';ch = fgetc(fin);if (ch == '='){str[strlen(str)]=ch;str[strlen(str)]='\0';printf("类型leq , 名称%s\n",str);}else{printf("类型less , 名称%s\n",str);}ch = fgetc(fin);}else{if (ch == '>'){ //检测大于或大于等于符号charstr[50]="";str[strlen(str)]=ch;str[strlen(str)]='\0';ch = fgetc(fin);if (ch == '='){str[strlen(str)]=ch;str[strlen(str)]='\0';printf("类型geq , 名称%s\n",str);}else{printf("类型gtr , 名称%s\n",str);}ch = fgetc(fin);}else{if(judgeSignel(ch) != -1){inti=judgeSignel(ch);printf("类型%s , 名称%c\n", ssym[i],ch);ch = fgetc(fin);}else ch = fgetc(fin); //忽略空格、换行}}}}}}}voidjudgeConst(char * str){inti = 0;for (i=0; i<numWord; i++){if (stricmp( str, word[i]) == 0){printf("类型%s , 名称%s\n",wsym[i],str);break;}}if (i == numWord){ //一直未找到匹配的保留字符。
PL0编译器源程序分析
![PL0编译器源程序分析](https://img.taocdn.com/s3/m/f6ec175a5a8102d276a22ff1.png)
PL/0编译器源程序分析PL/0语言是Pascal语言的一个子集,我们这里分析的PL/0的编译程序包括了对PL/0语言源程序进行分析处理、编译生成类PCODE代码,并在虚拟机上解释运行生成的类PCODE代码的功能。
PL/0语言编译程序采用以语法分析为核心、一遍扫描的编译方法。
词法分析和代码生成作为独立的子程序供语法分析程序调用。
语法分析的同时,提供了出错报告和出错恢复的功能。
在源程序没有错误编译通过的情况下,调用类PCODE解释程序解释执行生成的类PCODE代码。
词法分析子程序分析: 词法分析子程序名为getsym,功能是从源程序中读出一个单词符号(token),把它的信息放入全局变量sym、id和num中,语法分析器需要单词时,直接从这三个变量中获得。
(注意!语法分析器每次用完这三个变量的值就立即调用getsym子程序获取新的单词供下一次使用。
而不是在需要新单词时才调用getsym过程。
)getsym过程通过反复调用getch 子过程从源程序过获取字符,并把它们拼成单词。
getch过程中使用了行缓冲区技术以提高程序运行效率。
词法分析器的分析过程:调用getsym时,它通过getch过程从源程序中获得一个字符。
如果这个字符是字母,则继续获取字符或数字,最终可以拼成一个单词,查保留字表,如果查到为保留字,则把sym变量赋成相应的保留字类型值;如果没有查到,则这个单词应是一个用户自定义的标识符(可能是变量名、常量名或是过程的名字),把sym置为ident,把这个单词存入id变量。
查保留字表时使用了二分法查找以提高效率。
如果getch获得的字符是数字,则继续用getch获取数字,并把它们拼成一个整数,然后把sym置为number,并把拼成的数值放入num变量。
如果识别出其它合法的符号(比如:赋值号、大于号、小于等于号等),则把sym则成相应的类型。
如果遇到不合法的字符,把sym置成nul。
语法分析子程序分析: 语法分析子程序采用了自顶向下的递归子程序法,语法分析同时也根据程序的语意生成相应的代码,并提供了出错处理的机制。
PL0源代码(C语言版)
![PL0源代码(C语言版)](https://img.taocdn.com/s3/m/881cdea2bd64783e08122b4f.png)
/*PL/0 编译系统C版本头文件pl0.h*/# define norw 13 //a number of reserved word /*关键字个数*/# define txmax 100 //length of identifier table /*名字表容量*/# define nmax 14 //max number of digits in numbers /*number的最大位数*/ # define al 10 //length of identifier /*符号的最大长度*/# define amax 2047 //maximum address /*地址上界*/# define levmax 3 //max depth of block nesting /*最大允许过程嵌套声明层数[0,lexmax]*/# define cxmax 200 //size of code array /*最多的虚拟机代码数*//*符号*/enum symbol{nul, ident, number, plus, minus,times, slash, oddsym, eql, neq, //slash斜线lss, leq, gtr, geq, lparen, //leq :less than or equal to; gtr: great than;lparen:left parenthesisrparen, comma, semicolon,period, becomes,//comma逗号semicolon分号period句号becomes赋值号beginsym, endsym, ifsym, thensym, whilesym,writesym, readsym, dosym, callsym, constsym,varsym, procsym,};#define symnum 32/*-------------*/enum object{ //object为三种标识符的类型constant,variable,procedur,};/*--------------*/enum fct{ //fct类型分别标识类PCODE的各条指令lit, opr, lod, sto, cal, inte, jmp, jpc, //书本P23};#define fctnum 8/*--------------*/struct instruction //指令{enum fct f; //功能码int l; //层次差int a; //P23};FILE * fas; //输出名字表FILE * fa; //输出虚拟机代码FILE * fa1; //输出源文件及其各行对应的首地址FILE * fa2; //输出结果bool tableswitch; //显示名字表与否bool listswitch; //显示虚拟机代码与否char ch; //获取字符的缓冲区,getch使用enum symbol sym; //当前符号char id[al+1]; //当前ident,多出一个字节用于存放0int num; //当前numberint cc,ll; //getch使用的计数器,cc表示当前字符(ch)的位置int cx; //虚拟机代码指针,取值范围[0,cxmax-1]char line[81]; //读取行缓冲区char a[al+1]; //临时符号,多出的一个字节用于存放0struct instruction code[cxmax]; //存放虚拟机代码的数组char word[norw][al]; //保留字enum symbol wsym[norw]; //保留字对应的符号值enum symbol ssym[256]; //单字符的符号值char mnemonic[fctnum][5]; //虚拟机代码指令名称bool declbegsys[symnum]; //表示声明开始的符号集合,declaring begin symbol set bool statbegsys[symnum]; //表示语句开始的符号集, statementbool facbegsys[symnum]; //表示因子开始的符号集合,factor/*------------------------------*/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; //fin文本文件用于指向输入的源程序文件FILE* fout; //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 -1 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 position(char* idt,int tx);void enter(enum object k,int* ptx,int lev,int* pdx);int base(int l,int* s,int b);//A.2 C 版本/*编译和运行环境:*1Visual C++6.0,VisualC++.NET and Visual C++.NET 2003*WinNT, Win 200, WinXP and Win2003*2 gcc version 3.3.2 (Red Hat Linux*Redhat Fedora core 1*Intel 32 platform*使用方法:*运行后输入PL/0 源程序文件名*回答是否输出虚拟机代码*回答是否输出名字表*fa.tmp 输出虚拟机代码*fa1.tmp 输出源文件及其各行对应的首地址*fa2.tmp 输出结果*fas.tmp 输出名字表*/#include<stdio.h>#include"pl0.h"#include"string.h"/*解释执行时使用的栈*/#define stacksize 500int main(){bool nxtlev[symnum];printf("Input pl/0 file ?");scanf("%s",fname); /*输入文件名*/fin=fopen(fname,"r"); //返回值:文件顺利打开后,指向该流的文件指针就会被返回。
pl0词法分析器C版
![pl0词法分析器C版](https://img.taocdn.com/s3/m/9d92759c84868762cbaed505.png)
#include <iostream> #include<stdio.h> #include<string.h>#define LINE 100 //源程序每行至多100个字符using namespace std;char buf[LINE]; //按行存放字符 int length; //记录每行长度char *key[9] = { "PROGRAM", "BEGIN", "END", "CONST", "V AR", "WHILE", "DO", "IF", "T HEN" }; // 关键字char *ch[15] = { "+", "-", "*", "/", ":=", "=", "<", ">", ">=", "<=", "(", ")", ";", "," }; // 限定符/界符int readfile(FILE *fp) //读取.txt文件,只读取一行{char ch; //存放读取的单个字符 length=0;ch=fgetc(fp); //调用函数fgetc()读取文件内容while(!feof(fp) && ch!='\n') //读取字符到buf[]数组{buf[length]=ch; ch=fgetc(fp); length++;}if(length!=0)return 1;elsereturn 0;}void lexical(char *buf,int length)法分析函数{ int i;char buffer[LINE];for(i=0;i<length;i++){buffer[i]=*buf;buf++;} for(i=0;i<length;i++){ //判断是否为“常数”if(buffer[i]=='0'||buffer[i]=='1'||buffer[i]=='2'||buffer[i]=='3'||buffer[i]=='4'||buffer[i]=='5'||buffer[i] =='6'||buffer[i]=='7'||buffer[i]=='8'||buffer[i]=='9'){cout<<"常数 "<<buffer[i];while(1){i++;if(buffer[i]=='0'||buffer[i]=='1'||buffer[i]=='2'||buffer[i]=='3'||buffer[i]=='4'||buffer[i]=='5'||buffer[i] =='6'||buffer[i]=='7'||buffer[i]=='8'||buffer[i]=='9')cout<<buffer[i];else break;}cout<<endl;} //判断是否为“算符/界符”else if (buffer[i] == '+' || buffer[i] == '-' || buffer[i] == '*' || buffer[i] == '/' || buffer[i] == '=' || buffer[ i] == '(' || buffer[i] == ')' || buffer[i] == ';' || buffer[i] == ',')cout << "算符/界符" << " "<<buffer[i] << endl;// else if (buffer[i] == '>' || buffer[i] == '<'){ if (buffer[i + 1] == '=')cout << "算符/界符" << " " << buffer[i] << buffer[i+1] << endl;else cout << "算符/界符" << " " << buffer[i] << endl;}else if (buffer[i] == ':'&&buffer[i + 1] == '=')cout << "算符/界符" << " " <<buffer[i]<< buffer[i + 1] << endl;//判断是否为“关键字”或“标识符”else if(buffer[i]>='A'&&buffer[i]<='Z'){char a1[]="PROGRAM";char a2[]="BEGIN";char a3[]="END";char a4[]="CONST";char a5[]="V AR";char a6[]="WHILE";char a7[]="DO";char a8[]="IF";char a9[]="THEN";char s1[20];for(int j=0;buffer[i]!=' ';i++,j++)//for(int j=0;buffer[i]=='_'||(buffer[i]>='0'&&buffer[i]<='9')||(buffer[i]>='a'&&buffer[i]<='z')||(buff er[i]>='A'&&buffer[i]<='Z');i++,j++)s1[j]=buffer[i];s1[j]='\0';if(!strcmp(s1,a1))cout<<"关键字 "<<a1<<endl;else if(!strcmp(s1,a2))cout<<"关键字 "<<a2<<endl;else if(!strcmp(s1,a3))cout<<"关键字 "<<a3<<endl;else if(!strcmp(s1,a4))cout<<"关键字 "<<a4<<endl;else if(!strcmp(s1,a5))cout<<"关键字 "<<a5<<endl;else if(!strcmp(s1,a6))cout<<"关键字 "<<a6<<endl;else if(!strcmp(s1,a7))cout<<"关键字 "<<a7<<endl;else if(!strcmp(s1,a8))cout<<"关键字 "<<a8<<endl;else if(!strcmp(s1,a9))cout<<"关键字 "<<a9<<endl;else cout<<"标识符 "<<s1<<endl;i--;}else if(buffer[i]>='a'&& buffer[i]<='z') {int j;char s1[20];for(j=0;buffer[i]=='_'||(buffer[i]>='0'&&buffer[i]<='9')||(buffer[i]>='a'&&buffer[i]<='z' )||(buffer[i]>='A'&&buffer[i]<='Z');){s1[j]=buffer[i];i++;j++;}s1[j]='\0';cout<<"标识符 "<<s1<<endl; i--;}}}int main() { char sourcefile[20]; //定义源文件 cout<<"请输入源文件名字:"; cin>>sourcefile; FILE *fp; fp=fopen(sourcefile,"r"); //读文件 if(fp) { while(readfile(fp)) //调用读文件函数 lexical(buf,length); //调用词法分析函数 fclose(fp); } else cout<<"没有找到源文件!"<<endl; getchar(); return 0; }。
编译原理PL0报告(附源码教程)
![编译原理PL0报告(附源码教程)](https://img.taocdn.com/s3/m/4bc58547fe4733687e21aae6.png)
编译原理课程设计学院计算机学院专业计算机科学与技术班级学号姓名指导教师20 年月日一、课程设计要求基本内容(成绩范围:“中”、“及格”或“不及格”)(1)扩充赋值运算:*= 和/=扩充语句(Pascal的FOR语句):①FOR <变量>:=<表达式> TO <表达式> DO <语句>②FOR <变量>:=<表达式> DOWNTO <表达式> DO <语句>其中,语句①的循环变量的步长为2,语句②的循环变量的步长为-2。
(3)增加运算:++ 和--。
选做内容(成绩评定范围扩大到:“优”和“良”)(1)增加类型:①字符类型;②实数类型。
(2)扩充函数:①有返回值和返回语句;②有参数函数。
(3)增加一维数组类型(可增加指令)。
(4)其他典型语言设施。
二、概述目标:实现PL0某些特定语句实现语言:C语言实现工具平台:VS201运行平台:WIN7三、结构设计说明与功能块描述PL/0编译程序的结构图PL/0编译程序的总体流程图四、主要成分描述1、符号表编译程序里用了一个枚举类型enum symbol,然后定义了enum symbol sym来存放当前的符号,前面讲过,主程序定义了一个以字符为元素的一维数组word,称保留字表,这个保留字表也存放在符号表里,为了识别当前的符号是属于哪些保留字;还有标识符,拼数,拼符合词等的符号名都存放在符号表里,当sym存放当前的符号时,我们可以判断它是属于哪类的符号,然后加以处理。
在运行的过程中,主程序中又定义了一个名字表,也就是符号表,来专门存放变量、常量和过程名的各个属性,里面的属性包括name,kind,val/level,adr,size,我们来举一个PL/0语言过程说明部分的片段:Const a=35,b=49;Var c,d,e;Procedure p;Var g;当遇到标识符的引用时就调用position函数,根据当前sym的符号类型来查table表,看是否有过正确的定义,若已有,则从表中取相应的有关信息,供代码的生成用。
实验一PL0编译程序
![实验一PL0编译程序](https://img.taocdn.com/s3/m/675aab3754270722192e453610661ed9ad51552e.png)
实验一PL0编译程序编译原理上机实验一1.软件准备(1)、pl/0编译程序:pl0 .exe(2)、pl/0编译程序源代码程序(PASCAL程序):pl0.pas(或pl0pl0.pas)(3)、pl/0程序实例(文本文件):text.pl0, text1.pl0, test2.pl0, … text9.pl0共10个例子2.实验要求:(1)阅读pl/0源程序实例(text.pl0,test1.pl0,………text9.pl0共10个例子)理解每个PL0程序的功能;熟悉并掌握pl/0语言相关规则。
(2)用pl/0编译程序,对提供的10个例子逐一进行编译并运行。
熟悉pl/0编译程序使用操作方法。
通过理解每个实例程序的功能,编程思想,进一步理解PL/0语言的语法及其语义;提高阅读程序的能力,应用程序设计语言的编程能力;增强程序语言语法、语义意识。
(3)用pl/0语言编写以下程序,进一步熟悉PL/0语言:a、由三角形的三条边长计算三角形面积。
b、编写一个PL0过程,计算以a为直径的圆的面积。
用主程序确定圆的直径,输出计算结果。
c、编写递归程序,计算n!。
d、计算1000之内的所有素数,并输出结果。
求出1000之内所有素数之和。
(要求编写3个以上的pl/0过程实现)3.文件(软件)使用说明(1)、打开文件目录“PL0编译…”,运行PL/0编译程序(pl0.exe),按提示要求输入PL0源程序文件名(如test1.pl0),┉(2)、打开Fa2.txt文件,可看到当前经过编译并运行后的pl/0程序的目标代码及其执行结果。
(3)、打开out1.txt或out2.txt、┉或out9.txt文件,可看到各个pl/0程序实例的编译、运行、操作过程结果。
4.提交实验报告及要求(1)、简述test4.pl0 …test7.pl0各程序语法含义,执行结果。
(2)、提交实验要求编写的4个PL/0源程序及其执行结果。
(3)、简写本次实验的收获与体会。
pl0词法分析器(C语言版)
![pl0词法分析器(C语言版)](https://img.taocdn.com/s3/m/0bb75a5c52d380eb63946d2e.png)
#include<stdio.h>#include<string.h>#include<stdlib.h>void init();void getsym();enum symbol {nul,ident,number,plus,minus,times,slash,oddsym,eql,neq, beginsym,endsym,ifsym,thensym,whilesym,writesym,readsym,dosym,callsym, constsym,varsym,procsym,programsym,};#define norw 14#define al 10#define nmax 10char word [norw][al];char ch;enum symbol sym;enum symbol wsym[norw];enum symbol ssym[256];FILE *fin,*fout;void main(){printf("please input outfile's name:\n");//词法分析之后的结果要输出到的文件}char outname[30],inname[30]; scanf("%s",outname);if((fout=fopen(outname,"w"))==NULL){printf("cannot open output file!");exit(0);}printf("please input infile's name:\n");//需要词法分析的源程序scanf("%s",inname);if((fin=fopen(inname,"r"))==NULL){printf("cannot open file!\n");exit(0);}ch=fgetc(fin);while(ch!=EOF){}getsym();//读取源文件void getsym(){long m;char id[al+1],a[al+1];int i,k;init();if(ch==' '||ch==10||ch==9){}else {if(ch>='a'&&ch<='z'||ch>='A'&&ch<='Z'){k=0;ch=fgetc(fin);do {if(k<al){a[k]=ch;k++;}ch=fgetc(fin);}while((ch>='a'&&ch<='z'||ch>='0'&&ch<='9')||(ch>='A'&&ch<='Z'||ch>='0'&&ch<='9') );a[k]=0;strcpy(id,a);for(i=0;i<norw;i++){if(strcmp(id,word[i])==0){sym=wsym[i]; printf("%s %ssym\n",id,id);fprintf(fout,"%s %ssym\n",id,id);break;}else {if(i==(norw-1)){sym=ident;printf("%s ident\n",id);fprintf(fout,"%s ident\n",id);}}}}else {if(ch>='0'&&ch<='9'){k=0;m=0;sym=number;do}{m=10*m+ch-'0';k++;ch=getc(fin);}while(ch>='0'&&ch<='9');if(k>=nmax){printf("error!数值太大!\n");//exit(0);}printf("%d number\n",m);fprintf(fout,"%d number\n",m); else {if(ch==':'){ch=getc(fin);printf(":fprintf(fout,":ch=fgetc(fin);}else {}sym=nul; fprintf(fout,":nul\n");printf(":nul\n");else {if(ch=='<'){ch=fgetc(fin); if(ch=='='){sym=leq;printf("<=lep\n");fprintf(fout,"<=ch=fgetc(fin);}else {sym=lss; printf("<fprintf(fout,"<}}else {if(ch=='>'){ch=fgetc(fin); if(ch=='='){sym=geq;printf(">=fprintf(fout,">=ch=fgetc(fin);}else {sym=gtr;printf(">fprintf(fout,">}}else {sym=ssym[ch];if(ch=='+'){printf("+plus\n");ch=fgetc(fin);}else lep\n");lss\n");lss\n");geq\n");geq\n");gtr\n");gtr\n");plus\n");fprintf(fout,"+if(ch=='-'){printf("-minus\n");fprintf(fout,"-else if(ch=='*'){printf("*times\n");fprintf(fout,"*elseif(ch=='/'){printf("/slash\n");fprintf(fout,"/minus\n");ch=fgetc(fin);} times\n");ch=fgetc(fin);}slash\n");ch=fgetc(fin);}if(ch=='('){printf("(rparen\n");ch=fgetc(fin);}eql\n");ch=fgetc(fin);}neq\n");ch=fgetc(fin);}period\n");ch=fgetc(fin);}semicoln\n");ch=fgetc(fin);}nul\n",ch);ch=fgetc(fin);}}}}}}}}//对关键字等实现初始化void init(){int i;for(i=0;i<=255;i++){elselparen\n");fprintf(fout,"(elseif(ch==')'){printf(")elseif(ch=='='){printf("=elseif(ch==','){printf(",elseif(ch=='#'){printf("#elseif(ch=='.'){printf(".elseif(ch==';'){printf(";else{printf("%c lparen\n");ch=fgetc(fin);}rparen\n");fprintf(fout,")neq\n");fprintf(fout,"#period\n");fprintf(fout,".semicoln\n");fprintf(fout,"; nul\n",ch);fprintf(fout,"%c }ssym[i]=nul;}ssym['+']=plus;ssym['-']=minus;ssym['*']=times;ssym['/']=slash;ssym['(']=lparen;ssym[')']=rparen;ssym['=']=eql;ssym['.']=period;ssym['#']=neq;ssym[';']=semicolon;strcpy(&(word[0][0]),"begin");strcpy(&(word[1][0]),"call");strcpy(&(word[2][0]),"const");strcpy(&(word[3][0]),"do");strcpy(&(word[4][0]),"end");strcpy(&(word[5][0]),"if");strcpy(&(word[6][0]),"odd");strcpy(&(word[7][0]),"procedure");strcpy(&(word[8][0]),"read");strcpy(&(word[9][0]),"program"); strcpy(&(word[10][0]),"var"); strcpy(&(word[11][0]),"whlie"); strcpy(&(word[12][0]),"write"); strcpy(&(word[13][0]),"then"); wsym[0]=beginsym;wsym[1]=callsym;wsym[2]=constsym;wsym[3]=dosym;wsym[4]=endsym;wsym[5]=ifsym;wsym[6]=oddsym;wsym[7]=procsym;wsym[8]=readsym;wsym[9]=programsym;wsym[10]=varsym;wsym[11]=whilesym;wsym[12]=writesym;wsym[13]=thensym;。
pl0
![pl0](https://img.taocdn.com/s3/m/e1b6477e27284b73f24250a7.png)
已增加了else的支持。
需要在保留字中增加"else",对应符号为elsesym(不要告诉我你不知道在哪加,^_^)C/C++ code//statement()函数在处理if语句的地方进行修改,支持可选的elseif (sym == ifsym) /* 准备按照if语句处理 */{...cx1 = cx; /* 保存当前指令地址 */gendo(jpc, 0, 0); /* 生成条件跳转指令,跳转地址未知,暂时写0 */statementdo(fsys, ptx, lev); /* 处理then后的语句 *////////以下增加了else关键字的词法分析和代码生成//////////* 根据else之后是否有then子句进行不同处理 */if (sym == elsesym){cx2 = cx;gendo(jmp, 0, 0); /* then处理完应该跳转到else子句之后 */code[cx1].a = cx; /* 判断条件不成立时,跳到这里,else子句入口 */getsymdo;statementdo(fsys, ptx, lev);code[cx2].a = cx; /* then处理完跳转到这里,else出口 */}else{code[cx1].a = cx; /* 没有else子句时,条件语句跳转到then之后 */}}lz附件中的PL/0,能够解释执行的程序如下所示(个人觉得有点像pascal)。
贴出两个例子程序(lz在帖子附件未提供),有兴趣的朋友也看看~~ 更希望lz自己先尝试尝试,呵呵//程序1: 简单输出Delphi(Pascal) codeconst a=10; var result;procedure average;var temp, addition, count;procedure add;begintemp:=temp+2;write(temp);end;begintemp:=a;count:=1;addition:=temp;while temp<=20 dobegincall add;count:=count+1;addition:=addition+temp;end;result:=addition/count;end;beginwrite(a);call average;write(result);end.//程序二:扩展后支持如下的数组Delphi(Pascal) codeconst m = 4;var a(1:m), ended, n;begina(1) := 1; a(2) := 2; a(3) := 3; a(4) := 4; ended := 0;if ended = 0 then beginwrite (a(1), a(2), a(3), a(4));n := m;end;end.* 对我有用[0]* 丢个板砖[0]* 引用* 举报* 管理* TOP** ltc_mouse* (野地芳菲)** 等级:* 2#8楼得分:0回复于:2007-12-28 01:47:56数组的定义和访问挺麻烦的,不知道处理对了没有。
pl0 词法分析 c程序
![pl0 词法分析 c程序](https://img.taocdn.com/s3/m/e31810523c1ec5da50e27013.png)
/*PL/0编译系统C++版本*/
#include "pl0.h"
#include "string.h"
/*解释执行时使用的栈*/
#define stacksize 500
int ty;
void printTokens();
int main()
{
k++;
}
getchdo;
}while(ch>='a'&&ch<='z'||ch>='0'&&ch<='9');
a[k]=0;
strcpy(id,a);
i=0;
j=norw-1;
do{ /*搜索当前符号是否为保留字*/
memset(space,32,81);
space[cc-1]=0;
printf("****%s!%d\n",space,n);
fprintf(fa1,"****%s!%d\n",space,n);
err++;
}
/*
/*
*漏掉空格,读取一个字符。
*
*每次读一行,存入line缓冲区,line被getsym取空后再读一行
//fprintf(fa1,"%d",cx);
ch=' ';
while(ch!=10)
{
if(EOF==fscanf(fin,"%c",&ch))
编译原理实践-PL0的词法分析程序构造
![编译原理实践-PL0的词法分析程序构造](https://img.taocdn.com/s3/m/a9d08528a55177232f60ddccda38376bae1fe06c.png)
通过本次演讲,将带你领略编译原理的奇妙之处,并深入介绍PL0语言的词 法分析及程序构造,让你轻松掌握。
编译原理简介
编译原理是计算机科学的重要基础,涉及源代码的解析、优化和转换过程。它是开发高效程序和语言的 关键。
PL0语言简介
PL0是一种简单且易于学习的编程语言,适合编译原理教学。它具有C语言的 语法特点,是学习编译原理的理想选择。
词法分析的概念和作用
词法分析是编译过程中的第一步,将源代码分解为各种标记(Token)。它有助于语法分析和语义分析的 进行。
PL0的词法规则
PL0的词法规则定义了它的各类标记,如关键字、标识符、运算符和常量。了解规则对于正确理解代码 至关重要。
词法分析程序的设计思路
设词法分析程序需要考虑标识符的判别、关键字的识别等问题。采用有限自动机是一种常用的设计方 法。
PL0的词法分析程序实现
使用C语言编写PL0的词法分析程序,结合有限自动机算法,有效地识别源代 码中的各种标记。
实验结果与总结
通过实验,我们验证了词法分析程序的正确性和性能。深入总结实验结果,对编译原理的学习和应用有 了更深入的理解。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
/*PL/0 编译系统C版本头文件pl0.h*/# define norw 13 //a number of reserved word /*关键字个数*/# define txmax 100 //length of identifier table /*名字表容量*/# define nmax 14 //max number of digits in numbers /*number的最大位数*/# define al 10 //length of identifier /*符号的最大长度*/# define amax 2047 //maximum address /*地址上界*/# define levmax 3 //max depth of block nesting /*最大允许过程嵌套声明层数[0,lexmax]*/# define cxmax 200 //size of code array /*最多的虚拟机代码数*//*符号*/enum symbol{nul, ident, number, plus, minus,times, slash, oddsym, eql, neq, //slash斜线lss, leq, gtr, geq, lparen, //leq :less than or equal to; gtr: great than;lparen:left parenthesisrparen, comma, semicolon,period, becomes,//comma逗号semicolon分号period句号becomes赋值号beginsym, endsym, ifsym, thensym, whilesym,writesym, readsym, dosym, callsym, constsym,varsym, procsym,};#define symnum 32/*-------------*/enum object{ //object为三种标识符的类型constant,variable,procedur,};/*--------------*/enum fct{ //fct类型分别标识类PCODE的各条指令lit, opr, lod, sto, cal, inte, jmp, jpc, //书本P23};#define fctnum 8/*--------------*/struct instruction //指令{enum fct f; //功能码int l; //层次差int a; //P23};FILE * fas; //输出名字表FILE * fa; //输出虚拟机代码FILE * fa1; //输出源文件及其各行对应的首地址FILE * fa2; //输出结果bool tableswitch; //显示名字表与否bool listswitch; //显示虚拟机代码与否char ch; //获取字符的缓冲区,getch使用enum symbol sym; //当前符号char id[al+1]; //当前ident,多出一个字节用于存放0int num; //当前numberint cc,ll; //getch使用的计数器,cc表示当前字符(ch)的位置int cx; //虚拟机代码指针,取值范围[0,cxmax-1]char line[81]; //读取行缓冲区char a[al+1]; //临时符号,多出的一个字节用于存放0struct instruction code[cxmax]; //存放虚拟机代码的数组char word[norw][al]; //保留字enum symbol wsym[norw]; //保留字对应的符号值enum symbol ssym[256]; //单字符的符号值char mnemonic[fctnum][5]; //虚拟机代码指令名称bool declbegsys[symnum]; //表示声明开始的符号集合,declaring begin symbol set bool statbegsys[symnum]; //表示语句开始的符号集, statementbool facbegsys[symnum]; //表示因子开始的符号集合,factor/*------------------------------*/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; //fin文本文件用于指向输入的源程序文件FILE* fout; //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 -1 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 position(char* idt,int tx);void enter(enum object k,int* ptx,int lev,int* pdx);int base(int l,int* s,int b);//A.2 C 版本/*编译和运行环境:*1Visual C++6.0,VisualC++.NET and Visual C++.NET 2003*WinNT, Win 200, WinXP and Win2003*2 gcc version 3.3.2 20031022(Red Hat Linux 3.3.2-1)*Redhat Fedora core 1*Intel 32 platform*使用方法:*运行后输入PL/0 源程序文件名*回答是否输出虚拟机代码*回答是否输出名字表*fa.tmp 输出虚拟机代码*fa1.tmp 输出源文件及其各行对应的首地址*fa2.tmp 输出结果*fas.tmp 输出名字表*/#include<stdio.h>#include"pl0.h"#include"string.h"/*解释执行时使用的栈*/#define stacksize 500int main(){bool nxtlev[symnum];printf("Input pl/0 file ?");scanf("%s",fname); /*输入文件名*/fin=fopen(fname,"r"); //返回值:文件顺利打开后,指向该流的文件指针就会被返回。
如果文件打开失败则返回NULL,并把错误代码存在errno 中if(fin){printf("List object code ?(Y/N)"); /*是否输出虚拟机代码*/scanf("%s",fname);listswitch=(fname[0]=='y'||fname[0]=='Y');printf("List symbol table ? (Y/N)"); /*是否输出名字表*/scanf("%s",fname);tableswitch=(fname[0]=='y'||fname[0]=='Y');fa1=fopen("fa1.tmp","w");fprintf(fa1,"Iput pl/0 file ?");fprintf(fa1,"%s\n", fname);init(); /*初始化*/err=0; //错误计数器置0cc=cx=ll=0;ch=' ';if(-1!=getsym()){fa=fopen("fa.tmp","w");fas=fopen("fas.tmp","w");addset(nxtlev,declbegsys,statbegsys,symnum);nxtlev[period]=true;if(-1==block(0,0,nxtlev)) /*调用编译程序*/{fclose(fa);fclose(fa1);fclose(fas);fclose(fin);printf("\n");return 0;}fclose(fa);fclose(fa1);fclose(fas);if(sym!=period){error(9);}if(err==0){fa2=fopen("fa2.tmp", "w");interpret();fclose(fa2);}else{printf("Errors in pl/0 program");}}fclose(fin);}else{printf("Can't open file! \n");}printf("\n");return 0;}/**初始化*/void init(){int i;for(i=0;i<=255;i++){ssym[i]=nul; //ssym:单字符的符号值}ssym['+']=plus;ssym['-']=minus;ssym['*']=times;ssym['/']=slash;ssym['(']=lparen;ssym[')']=rparen;ssym['=']=eql;ssym[',']=comma;ssym['.']=period;ssym['#']=neq;ssym[';']=semicolon;/*设置保留字名字,按照字母顺序,便于折半查找*/ strcpy(&(word[0][0]),"begin");strcpy(&(word[1][0]),"call");strcpy(&(word[2][0]),"const");strcpy(&(word[3][0]),"do");strcpy(&(word[4][0]),"end");strcpy(&(word[5][0]),"if");strcpy(&(word[6][0]),"odd");strcpy(&(word[7][0]),"procedure");strcpy(&(word[8][0]),"read");strcpy(&(word[9][0]),"then");strcpy(&(word[10][0]),"var");strcpy(&(word[11][0]),"while");strcpy(&(word[12][0]),"write");/*设置保留字符号*/wsym[0]=beginsym;wsym[1]=callsym;wsym[2]=constsym;wsym[3]=dosym;wsym[4]=endsym;wsym[5]=ifsym;wsym[6]=oddsym;wsym[7]=procsym;wsym[8]=readsym;.wsym[9]=thensym;wsym[10]=varsym;wsym[11]=whilesym;wsym[12]=writesym;/*设置指令名称*/strcpy(&(mnemonic[lit][0]),"lit");strcpy(&(mnemonic[opr][0]),"opr");strcpy(&(mnemonic[lod][0]),"lod");strcpy(&(mnemonic[sto][0]),"sto");strcpy(&(mnemonic[cal][0]),"cal");strcpy(&(mnemonic[inte][0]),"int");strcpy(&(mnemonic[jmp][0]),"jmp");strcpy(&(mnemonic[jpc][0]),"jpc");/*设置符号集*/for(i=0;i<symnum;i++){declbegsys[i]=false;statbegsys[i]=false;facbegsys[i]=false;}/*设置声明开始符号集*/declbegsys[constsym]=true;declbegsys[varsym]=true;declbegsys[procsym]=true;/*设置语句开始符号集*/statbegsys[beginsym]=true;statbegsys[callsym]=true;statbegsys[ifsym]=true;statbegsys[whilesym]=true;/*设置因子开始符号集*/facbegsys[ident]=true;facbegsys[number]=true;facbegsys[lparen]=true;}/**用数组实现集合的集合运算*/int inset(int e,bool* s){return s[e];}int addset(bool* sr,bool* s1,bool* s2,int n){int i;for(i=0;i<n;i++){sr[i]=s1[i]||s2[i];}return 0;}int subset(bool* sr,bool* s1,bool* s2,int n){int i;for(i=0;i<n;i++){sr[i]=s1[i]&&(!s2[i]);}return 0;}int mulset(bool* sr,bool* s1,bool* s2,int n){int i;for(i=0;i<n;i++){sr[i]=s1[i]&&s2[i];}return 0;}/**出错处理,打印出错位置和错误编码*/void error(int n){char space[81];memset(space,32,81); printf("-------%c\n",ch);space[cc-1]=0;//出错时当前符号已经读完,所以cc-1printf("****%s!%d\n",space,n);err++;}/** 漏掉空格,读取一个字符** 每次读一行,存入line缓冲区,line被getsym取空后再读一行** 被函数getsym调用*/int getch(){if(cc==ll){if(feof(fin)) //如果文件结束,则返回非0值,否则返回0,文件结束符只能被clearerr()清除。