PL0_C语言源代码

合集下载

PL0编译程序源程序

PL0编译程序源程序

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

用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语言编译程序C++面向对象实现

PL0语言编译程序C++面向对象实现

PL0语言编译程序C++面向对象实现类关系:源码:头文件Lexa.h(词法分析)#ifndef LEXA_H#define LEXA_H#include <fstream>#include "sysdef.h"#include <iostream>using namespace std;// 词法符号struct Symbol{int kind;int value;char str[20];};// 词法分析const int BufferSize = 160; // 双缓冲,每一个大小为80 class Buffer{public:Buffer();void putback();bool Getch(char&);void init();private:ifstream in;char data[BufferSize];int curPos;bool last;// 是否是最后一次缓冲int lastIndex;friend class LexA;};class LexA{public:LexA(char* filename = NULL);bool Open(char* filename);bool GetSym();inline bool IsSpace(char);inline bool IsNumber(char);inline bool IsChar(char);inline bool IsOperator(char);inline bool IsSeparator(char);/*debuginline int GetType(){return V alue.kind;}inline int GetV alue(){return V alue.value;}*/private:Symbol V alue;Buffer buf;friend class SynA;};bool LexA::IsChar(char ch){return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'); }bool LexA::IsNumber(char ch){return (ch >= '0' && ch <= '9');}bool LexA::IsOperator(char ch){return (ch =='+' || ch == '-' || ch == '*' || ch == '/'|| ch == '>' || ch == '<' || ch == '=' || ch == '#' || ch == ':'); }bool LexA::IsSeparator(char ch){return (ch == '.' || ch == ',' || ch == ';' || ch == '(' || ch == ')'); }bool LexA::IsSpace(char ch){return (ch == ' ' || ch == '\t' || ch == '\n');}#endifSyna.h(语法分析)#ifndef SYNA_H#define SYNA_H#include "sysdef.h"#include "lexa.h"// 错误处理类struct ErrorItem{int id;int hang;int lie;};const int MaxErrorNum = 100;class Error{public:Error(){ErrorNum = 0;}int Add(int id, int hang, int lie = 0){if(ErrorNum < MaxErrorNum){error[ErrorNum].id = id;error[ErrorNum].hang = hang;error[ErrorNum++].lie = lie;}else return -1;return 1;}void OutPut(){for(int i = 0; i <= ErrorNum-1; i++)cout << error[i].id << endl;}private:ErrorItem error[MaxErrorNum];int ErrorNum;// 语法分析需要处理错误,表项管理把错误编号返回friend class SynA;};const int MAXNAMELEN = 30;struct tableItem{char name[MAXNAMELEN];int kind;int value_lev;int adr;int size;};const int TableSize = 100;class Table{public:Table():tx(0), lev(0){}int enter(tableItem&);int find(Symbol& sym, int& result);int ChangeLev(int dir);void List(){cout << "变量名\t类型\t值或者层\t地址" << endl;for(int i = 0; i <= tx-1; i++){cout << data[i].name << '\t';if(data[i].kind == V ARIABLE){cout << "variable" << '\t' << data[i].value_lev << '\t' <<data[i].adr;}else if(data[i].kind == CONSTANT){cout << "constant" << '\t' << data[i].value_lev;}else{cout << "procedure" << '\t' << data[i].value_lev << '\t' << data[i].adr;}cout << endl;}}private:tableItem data[TableSize];// tx为即将填入的地方int tx, lev;friend class SynA;};// 语法分析struct Code{int fun;int lev;int a;};struct Buff{Buff(){full = false;};bool full;Symbol sym;};const char FUN[8][4] = {"LIT", "LOD", "STO", "CAL", "INT", "JMP", "JPC", "OPR"};class SynA{public:SynA(char* filename);bool GetSym(Symbol& sym);int block();int program(int& start);int constProcess();int varProcess();int procedureProcess();int Statement();int Condition();int Expression();int Item();int Factor();void ListCode(){for(int i = 0; i <= cx-1; i++){cout << i << '\t' << FUN[code[i].fun-60] << ' ' << code[i].lev << ' ' << code[i].a <<endl;}}void ListError(){err.OutPut();}void ListTable(){table.List();}private:LexA lex;int cx, dx; //当前代码行数Table table;tableItem tbItem;Code code[100];Error err;Buff buf;};#endifCpp文件lexa.cpp#include "lexa.h"// 关键字表const int KeyWordNum = 13;struct KeyWord{char name[10];int ID;};KeyWord KeyWordTable[KeyWordNum] = {{"const", CONST}, {"var", V AR}, {"procedure", PROCEDURE}, {"call", CALL}, {"begin", BEGIN}, {"end", END},{"if", IF}, {"then", THEN}, {"while", WHILE},{"do", DO}, {"read", READ}, {"write", WRITE},{"odd", ODD}};// 运算符表const int OperatorNum = 11;struct Operator{char name[3];int ID;};Operator OperatorTable[OperatorNum]= {{"+", PLUS}, {"-", MINUS}, {"*", TIME}, {"/", DEVIDE},{">", GREA TER}, {"<", SMALLER}, {"=", EQUAL}, {"#", UNEQUAL}, {">=", GE}, {"<=", SE}, {":=", EQUAL1}};//分隔符表const int SeparatorNum = 5;struct Separator{char name;int ID;};Separator SeparatorTable[SeparatorNum] = {{'.', PERIOD}, {',', COMMA}, {';', SEMICOLON},{'(', LPARENTHESIS}, {')', RPARENTHESIS}};Buffer::Buffer(){last = false;}// 遇到文件尾,返回falsebool Buffer::Getch(char& ch){if(last){if(curPos == lastIndex) return false;ch = data[curPos++];curPos %= BufferSize;return true;}if(BufferSize/2+1 == curPos && !last){if(!in.read(data, BufferSize/2)){lastIndex = in.gcount();last = true;}}if(curPos == 1 && !last){if(!in.read(data+BufferSize/2, BufferSize/2)){lastIndex = in.gcount()+BufferSize/2;last = true;}}ch = data[curPos++];curPos %= BufferSize;return true;}void Buffer::putback(){if(curPos == 0) curPos = BufferSize-1;else{curPos -= 1;curPos %= BufferSize;}}void Buffer::init(){if(!in.read(data, BufferSize/2)){last = true;lastIndex = in.gcount();}curPos = 0;}LexA::LexA(char* filename){if(filename){buf.in.open(filename);if(buf.in.fail()){cout << "Can't open file:" << filename << endl;return;}buf.init();}}bool LexA::Open(char* filename){buf.in.open(filename);if(buf.in.fail()){cout << "Can't open file:" << filename << endl;return false;}buf.init();return true;}bool LexA::GetSym(){char ch;do{if(!buf.Getch(ch)) return false;}while(IsSpace(ch));if(IsNumber(ch)){int temp = ch-'0';do{if(buf.Getch(ch)){if(IsNumber(ch)){temp *= 10;temp += ch-'0';}else{buf.putback();break;}}else break;}while(!IsSpace(ch));V alue.kind = NUMBER;V alue.value = temp;return true;}if(IsChar(ch)){int i = 0;V alue.str[i] = ch;do{i++;if(buf.Getch(ch)){if(IsChar(ch) || IsNumber(ch)){V alue.str[i] = ch;}else if(IsSpace(ch)) break;else{buf.putback();break;}}else{break;}}while(1);V alue.str[i] = 0;for(i = 0; i <= KeyWordNum-1; i++){if(strcmp(V alue.str, KeyWordTable[i].name) == 0){ V alue.kind = KEYWORD;V alue.value = KeyWordTable[i].ID;return true;}}V alue.kind = IDENTSYM;return true;}if(IsOperator(ch)){char temp[3];temp[0] = ch;temp[1] = 0;buf.Getch(ch);if(!IsOperator(ch)) buf.putback();else if(ch == '='){if(temp[0] == '<' || temp[0] == '>' || temp[0] == ':'){temp[1] = '=';temp[2] = 0;}}else buf.putback();for(int i = 0; i <= OperatorNum-1; i++){if(strcmp(temp, OperatorTable[i].name) == 0){V alue.kind = OPERA TORSYM;V alue.value = OperatorTable[i].ID;return true;}}}if(IsSeparator(ch)){for(int i = 0; i <= SeparatorNum-1; i++){if(ch == SeparatorTable[i].name){V alue.kind = SEPARA TORSYM;V alue.value = SeparatorTable[i].ID;return true;}}}return false;}Syna.cpp#include "lexa.h"#include "syna.h"// table成员函数的实现// 返回错误号,1表示成功int Table::enter(tableItem& item){if(tx+1 == TableSize){return UNKNOWERROR;}data[tx].adr = item.adr;data[tx].kind = item.kind;strcpy(data[tx].name, );data[tx].size = item.size;data[tx++].value_lev = item.value_lev;return 1;}// 找到sym后返回1,result为data中序号int Table::find(Symbol& sym, int& result){for(int i = tx-1; i >= 0; i--){if(sym.kind == NUMBER){if(sym.value == data[i].value_lev){result = i;return 1;}}else if(sym.kind == IDENTSYM){if(strcmp(sym.str, data[i].name) == 0){result = i;return 1;}}else{return UNKNOWERROR;}}return 1;}int Table::ChangeLev(int dir){if(dir == -1) lev --;else lev ++;if(lev < 0){return UNKNOWERROR;}if(lev > 3){return UNKNOWERROR;}return 1;}// 语法分析类的实现SynA::SynA(char* filename){if(!lex.Open(filename)) exit(1);cx = 1;dx = 3;}bool SynA::GetSym(Symbol& sym){if(buf.full){sym = buf.sym;buf.full = false;return true;}if(!lex.GetSym()){err.Add(UNKNOWERROR, 0, 0);return false;};sym = lex.V alue;return true;}int SynA::block(){Symbol sym;int start;if(program(start) != 1) return -1;if(!GetSym(sym)) return -1;if(sym.value != PERIOD) return -1;if(GetSym(sym)){// 不明文件尾err.Add(UNKNOWERROR, 0, 0);return -1;}return 1;}int SynA::program(int& start){Symbol sym;if(!GetSym(sym)) return -1;if(sym.value == CONST){if(constProcess() != 1) return -1;if(!GetSym(sym)) return -1;}if(lex.V alue.value == V AR){if(varProcess() != 1) return -1;if(!GetSym(sym)) return -1;}if(lex.V alue.value == PROCEDURE){ int temp = dx;dx = 3;table.ChangeLev(1);if(procedureProcess() != 1) return -1;table.ChangeLev(-1);dx = temp;}else{buf.full = true;buf.sym = sym;}if(table.lev == 0){code[0].fun = JMP;code[0].lev = 0;code[0].a = cx;}start = cx;int var_num = cx++;//int指令将要写入的位置int var_num_lev = table.lev;do{int tttemp = Statement();if(tttemp == 0) break;else if(tttemp != 1) return -1;else{}Symbol sym1;if(table.lev != 0){if(!GetSym(sym1)) return -1;if(sym1.value == SEMICOLON){break;}else{buf.full = true;buf.sym = sym1;}}}while(1);code[cx].fun = OPR;code[cx].lev = 0;code[cx++].a = 0;int temp_lev = table.data[table.tx-1].value_lev, num = 0; for(int i = table.tx-1; i >= 0; i--){if(temp_lev == table.data[i].value_lev) num ++;else break;}if(var_num_lev == table.lev){code[var_num].fun = INT;code[var_num].lev = 0;code[var_num].a = num;}return 1;}int SynA::constProcess(){Symbol sym;tbItem.kind = CONSTANT;do{if(!GetSym(sym)) return -1;if(sym.kind == IDENTSYM){strcpy(, sym.str);if(!GetSym(sym)) return -1;if(sym.value == EQUAL){if(!GetSym(sym)) return -1;if(sym.kind == NUMBER) tbItem.value_lev = sym.value;table.enter(tbItem);}else if(sym.value == EQUAL1){err.Add(UNKNOWERROR, 0, 0);return -1;}else{err.Add(UNKNOWERROR, 0, 0);return -1;}}else{err.Add(UNKNOWERROR, 0, 0);return -1;}if(!GetSym(sym)) return -1;}while(sym.value == COMMA);if(sym.value != SEMICOLON){err.Add(UNKNOWERROR, 0, 0);return -1;}return 1;}int SynA::varProcess(){Symbol sym;tbItem.kind = V ARIABLE;do{if(!GetSym(sym)) return -1;if(sym.kind == IDENTSYM){tbItem.adr = dx++;tbItem.value_lev = table.lev;strcpy(, sym.str);table.enter(tbItem);// 重名错误}else{err.Add(UNKNOWERROR, 0, 0);return -1;}if(!GetSym(sym)) return -1;}while(sym.value == COMMA);if(sym.value != SEMICOLON){err.Add(UNKNOWERROR, 0, 0);return -1;};return 1;}int SynA::procedureProcess(){Symbol sym;tbItem.kind = PROCEDURE;if(!GetSym(sym)) return -1;if(sym.kind == IDENTSYM){strcpy(, sym.str);tbItem.adr = cx;table.enter(tbItem);int temp = cx++;if(!GetSym(sym)) return -1;if(sym.value != SEMICOLON){err.Add(UNKNOWERROR, 0, 0);return -1;}int start;if(program(start) != 1) return -1;code[temp].fun = JMP;code[temp].lev = 0;code[temp].a = start;}else{err.Add(UNKNOWERROR, 0, 0);return -1;}return 1;}int SynA::Statement(){int result, temp, temp1;Symbol sym;if(!GetSym(sym)) return -1;if(sym.kind == IDENTSYM){if(!table.find(sym, result)) return false;if(table.data[result].kind != V ARIABLE) return -1;if(!GetSym(sym)) return -1;if(sym.value == EQUAL1){if(Expression() != 1) return -1;code[cx].fun = STO;code[cx].lev = table.lev-table.data[result].value_lev;code[cx++].a = table.data[result].adr;}else return -1;return 1;}switch(sym.value){case CALL:if(!GetSym(sym)) return -1;if(sym.kind == IDENTSYM){if(!table.find(sym, result)) return -1;if(table.data[result].kind != PROCEDURE) return -1;code[cx].fun = CAL;code[cx].lev = table.lev-table.data[result].value_lev;code[cx++].a = table.data[result].adr;}break;case BEGIN:do{int ttemp = Statement();if(ttemp != 1 && ttemp != 0){return -1;}if(!GetSym(sym)) return -1;if(sym.value == SEMICOLON){continue;}else if(sym.value == END)break;else return -1;}while(1);break;case IF:if(Condition() != 1) return -1;//判断条件是否成立code[cx].fun = JPC;code[cx].lev = 0;temp = cx;cx ++;if(!GetSym(sym)) return -1;if(sym.value != THEN) return -1;if(Statement() != 1) return -1;code[temp].a = cx;break;case WHILE:temp1 = cx;if(Condition() != 1) return -1;code[cx].fun = JPC;code[cx].lev = 0;temp = cx;cx ++;if(!GetSym(sym)) return -1;if(sym.value != DO) return -1;if(Statement() != 1) return -1;code[cx].fun = JMP;code[cx].lev = 0;code[cx++].a = temp1;code[temp].a = cx;break;case READ:if(!GetSym(sym)) return -1;if(sym.value !=LPARENTHESIS) return -1;do{if(!GetSym(sym)) return -1;if(sym.kind == IDENTSYM){if(!table.find(sym, result)) return -1;else{if(table.data[result].kind == V ARIABLE){code[cx].fun = OPR;code[cx].lev = 0;code[cx++].a = 16;code[cx].fun = STO;code[cx].lev = 0;code[cx++].a = table.data[result].adr;}else return -1;}}else return -1;if(!GetSym(sym)) return -1;if(sym.value != COMMA) break;}while(1);if(sym.value != RPARENTHESIS) return -1;break;case WRITE:if(!GetSym(sym)) return -1;if(sym.value !=LPARENTHESIS) return -1;do{if(Expression() != 1) return -1;code[cx].fun = OPR;code[cx].lev = 0;code[cx++].a = 15;if(!GetSym(sym)) return -1;if(sym.value != COMMA) break;}while(1);if(sym.value != RPARENTHESIS) return -1;break;default:// 空语句,返回0buf.full = true;buf.sym = sym;return 0;}return 1;}int SynA::Condition(){Symbol sym;Symbol temp_sym;if(!GetSym(sym)) return -1;if(sym.value == ODD){if(Expression() != 1) return -1;code[cx].fun = OPR;code[cx].lev = 0;code[cx++].a = 6;}else{buf.full = true;buf.sym = sym;if(Expression() != 1) return -1;if(!GetSym(temp_sym)) return -1;if(Expression() != 1) return -1;code[cx].fun = OPR;code[cx].lev = 0;switch(temp_sym.value){case EQUAL:code[cx].a = 8;break;case UNEQUAL:code[cx].a = 9;break;case SMALLER:code[cx].a = 10;break;case SE:code[cx].a = 11;break;case GREA TER:code[cx].a = 12;break;case GE:code[cx].a = 13;break;default:return -1;}cx ++;}return 1;}int SynA::Expression(){Symbol sym;bool Minus = false;if(!GetSym(sym)) return -1;if(sym.value == MINUS){//将-1放到栈顶,并乘法Minus = true;}else{buf.full = true;buf.sym = sym;}bool first = true;int value;do{if(Item() != 1) return -1;if(!first){// 生成加减法指令code[cx].fun = OPR;if(value == PLUS) code[cx].a = 2;else code[cx].a = 3;code[cx++].lev = 0;}first = false;if(!GetSym(sym)) return -1;if(sym.value == PLUS || sym.value == MINUS){ value = sym.value;}else{buf.full = true;buf.sym = sym;break;}}while(1);if(Minus){// 生成乘以-1的指令code[cx].fun = LIT;code[cx].a = -1;code[cx++].lev = 0;code[cx].fun = OPR;code[cx].a = 4;code[cx++].lev = 0;}return 1;}int SynA::Item(){Symbol sym;bool first = true;int value;do{if(Factor() != 1) return -1;if(!first){// 生成乘法或除法指令code[cx].fun = OPR;if(value == TIME) code[cx].a = 4;else code[cx].a = 5;code[cx++].lev = 0;}first = false;if(!GetSym(sym)) return -1;if(sym.value == TIME || sym.value == DEVIDE){value = sym.value;}else{buf.full = true;buf.sym = sym;return 1;}}while(1);}int SynA::Factor(){int result;Symbol sym;if(!GetSym(sym)) return -1;if(sym.kind == IDENTSYM){if(table.find(sym, result) == 1){//取变量到栈顶if(table.data[result].kind == V ARIABLE){code[cx].fun = LOD;code[cx].lev = table.lev-table.data[result].value_lev;code[cx++].a = table.data[result].adr;}else if(table.data[result].kind == CONSTANT){//取常量到栈顶code[cx].fun = LIT;code[cx].lev = 0;code[cx++].a = table.data[result].value_lev;}else{return -1;}}else return -1;}else if(sym.kind == NUMBER){//取数到栈顶code[cx].fun = LIT;code[cx].lev = 0;code[cx++].a = sym.value;}else if(sym.kind == LPARENTHESIS){if(Expression() != 1) return -1;if(!GetSym(sym)) return -1;if(sym.kind != RPARENTHESIS) return -1;}else{// buf.full = true;// buf.sym = sym;return -1; //并非程序错误,返回上一级继续判断}return 1;}T est.cpp#include "lexa.h"#include "syna.h"// 词法分析测试/*int main(){LexA lex("in4.txt");while(lex.GetSym()){}return 0;}*/int main(){SynA syn("in4.txt");if(syn.block() != 1){cout << "Have Error List:" << endl;syn.ListError();}cout << "Table:" << endl;syn.ListTable();cout << endl;cout << "Code:" << endl;syn.ListCode();return 0;}测试数据:const a=10;var b,c;procedure p;beginc:=b+aend;beginread(b);while b#0 dobegincall p;write(2*c);read(b) end;end.以上数据保存在in4.txt中结果:a)一个能正确运行的例子结果完全正确b)源代码存在错误的情况:结尾出现多余代码,输出Error提示指出了源代码有错误,但未明确指出错误位置和类型。

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

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

/*PL/0编译程序(C语言版)*编译和运行环境:*Visual C++*WinXP/7*利用方式:*运行后输入PL/0源程序文件名*回答是不是将虚拟机代码写入文件*回答是不是将符号表写入文件*执行成功会产生四个文件(词法分析结果.txt符号表.txt虚拟代码.txt源程序和地址.txt)*/#include <>#include""#include"string"#define stacksize 500xt","w");fa1=fopen("源程序和地址.txt","w");xt","w");fas=fopen("符号表.txt","w");addset(nxtlev,declbegsys,statbegsys,symnum);nxtlev[period]=true;if(-1==block(0,0,nxtlev)){n\n");fprintf(cifa,"源程序显现错误,请检查!!!");fprintf(fa1,"源程序显现错误,请检查!!!");fprintf(fa,"源程序显现错误,请检查!!!");fprintf(fas,"源程序显现错误,请检查!!!");}fclose(fa);fclose(fa1);fclose(fas);}fclose(fin);}else{printf("Can't open file!\n");}fclose(cifa);]=period;ssym['#']=neq;ssym[';']=semicolon;strcpy(&(word[0][0]),"begin");\n\n" );fprintf(fa1,"\t\t程序结尾丢了句号“.”\n");break;case 10:printf("\t\t语句之间漏了“;”\n" );fprintf(fa1,"\t\t语句之间漏了“;”\n");break;case 11:printf("\t\t标识符拼写错误或未说明\n" );fprintf(fa1,"\t\t标识符拼写错误或未说明\n");break;case 12:printf("\t\t赋值语句中,赋值号左部标识符属性应是变量\n" );fprintf(fa1,"\t\t赋值语句中,赋值号左部标识符属性应是变量\n");break;case 13:printf("\t\t赋值语句左部标识符后应是复制号“:=”\n" );fprintf(fa1,"\t\t赋值语句左部标识符后应是复制号“:=”\n");break;case 14:printf("\t\tcall后应为标识符\n" );fprintf(fa1,"\t\tcall后应为标识符\n");break;case 15:printf("\t\tcall后标识符属性应为进程\n" );fprintf(fa1,"\t\tcall后标识符属性应为进程\n");break;case 16:printf("\t\t条件语句中丢了then\n" );fprintf(fa1,"\t\t条件语句中丢了then\n");break;case 17:printf("\t\t丢了“end”或“;”\n" );fprintf(fa1,"\t\t丢了“end”或“;”\n");break;case 18:printf("\t\twhile型循环语句中丢了“do”\n" ); fprintf(fa1,"\t\twhile型循环语句中丢了“do”\n");break;case 19:printf("\t\t语句后的符号不正确\n" );fprintf(fa1,"\t\t语句后的符号不正确\n" );break;case 20:printf("\t\t应为关系运算符\n" );fprintf(fa1,"\t\t应为关系运算符\n");break;case 21:printf("\t\t表达式内标示符属性不能是进程\n" ); fprintf(fa1,"\t\t表达式内标示符属性不能是进程\n");break;case 22:printf("\t\t表达式漏掉了右括号\n" );fprintf(fa1,"\t\t表达式漏掉了右括号\n");break;case 23:printf("\t\t因子后的非法符号\n" );fprintf(fa1,"\t\t因子后的非法符号\n");break;case 24:printf("\t\t表达式的开始符不能是此符号\n" );fprintf(fa1,"\t\t表达式的开始符不能是此符号\n");break;case 25:printf("\t\t标识符越界\n" );fprintf(fa1,"\t\t标识符越界\n");break;case 26:printf("\t\t非法字符\n" );fprintf(fa1,"\t\t非法字符\n");break;case 31:printf("\t\t数越界\n");fprintf(fa1,"\t\t数越界\n");break;case 32:printf("\t\tread语句括号中的标识符不是变量\n" );fprintf(fa1,"\t\tread语句括号中的标识符不是变量\n");break;case 33:printf("\t\twrite()或read()中应为完整表达式\n" );fprintf(fa1,"\t\twrite()或read()中应为完整表达式\n");break;default:printf("\t\t显现未知错误\n" );fprintf(fa1,"\t\t显现未知错误\n");}err++;}:break;default :error(26);}if(sym!=period){t\tperiod\n");}}}}}}return 0;}=x;code[cx].l=y;code[cx].a=z;cx++;return 0;}dr=cx;gendo(jmp,0,0);if(lev>levmax){dr].a=cx;dr=cx;ize=dx;cx0=cx;gendo(inte,0,dx);ind){case constant:fprintf(fas,"%d const %s ",i,table[i].name);fprintf(fas,"val=%d\n",table[i].val);break;case variable:fprintf(fas,"%d var %s ",i,table[i].name);fprintf(fas,"lev=%daddr=%d\n",table[i].level,table[i].adr);break;case procedur:fprintf(fas,"%d proc %s ",i,table[i].name);fprintf(fas,"lev=%daddr=%dsize=%d\n", table[i].level,table[i].adr,table[i].size);break;}}}memcpy(nxtlev,fsys,sizeof(bool)*symnum);ame,id);table[(* ptx)].kind=k;switch(k){case constant:if(num>amax){error(31);num=0;}table[(*ptx)].val=num;break;case variable:table[(*ptx)].level=lev;table[(*ptx)].adr=(*pdx);(*pdx)++;break;case procedur:table[(*ptx)].level=lev;break;}}ame,idt);i=tx;ame,idt)!=0){i--;}return i;}],code[i].l,code[i],a);}}}ind!=variable){error(12);i=0;}else{getsymdo;if(sym==becomes){getsymdo;printf("该语句为赋值语句。

编译原理课件-PL0编译程序

编译原理课件-PL0编译程序

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)

编写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();}。

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

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

下载可编辑/*PL/0编译程序(C语言版)*编译和运行环境:*Visual C++6.0*WinXP/7*使用方法:*运行后输入 PL/0 源程序文件名*回答是否将虚拟机代码写入文件*回答是否将符号表写入文件* 执行成功会产生四个文件(词法分析结果.txt符号表.txt虚拟代码.txt源程序和地址.txt)*/#include <stdio.h>#include"pl0.h"#include"string"#define stacksize 500//解释执行时使用的栈int main(){bool nxtlev[symnum];printf("请输入源程序文件名:");scanf("%s",fname);fin=fopen(fname,"r");//以只读方式打开pl0 源程序文件cifa=fopen(" 词法分析结果.txt","w");fa1=fopen(" 源程序和地址 .txt","w");//输出源文件及各行对应的首地址fprintf(fa1,"输入 pl0 源程序文件名:");fprintf(fa1,"%s\n",fname);if(fin){printf("是否将虚拟机代码写入文件?(Y/N)");//是否输出虚拟机代码scanf("%s",fname);listswitch=(fname[0]=='y'||fname[0]=='Y');printf("是否将符号表写入文件?(Y/N)");//是否输出符号表scanf("%s",fname);tableswitch=(fname[0]=='y'||fname[0]=='Y');init();//初始化err=0;cc=cx=ll=0;ch=' ';if(-1!=getsym()){fa=fopen("虚拟代码.txt","w");fas=fopen(" 符号表 .txt","w");addset(nxtlev,declbegsys,statbegsys,symnum);nxtlev[period]=true;if(-1==block(0,0,nxtlev)){//调用编译程序fclose(fa);fclose(fa1);fclose(fas);fclose(fin);return 0;}if(sym!=period){error(9);//结尾丢失了句号}if(err!=0){printf("pl0源程序出现错误,退出编译!!!请从第一个错误处开始修改 .\n\n");fprintf(cifa,"源程序出现错误,请检查!!!");fprintf(fa1,"源程序出现错误,请检查!!!");fprintf(fa,"源程序出现错误,请检查!!!");fprintf(fas,"源程序出现错误,请检查!!!");}fclose(fa);fclose(fa1);fclose(fas);}fclose(fin);}else{printf("Can't open file!\n");}fclose(cifa);//printf("\n");return 0;}void init(){//初始化int i;for(i=0;i<=255;i++)ssym[i]=nul;//设置单字符符号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[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;}void error(int n){//出错处理,打印出错位置和错误编码char space[81];memset(space, 32,81);space[cc-1]=0;printf("error(%d)",n);fprintf(fa1,"error(%d)",n);case 1:printf("\t\t常量说明中的“=”写成“ := ” \n");fprintf(fa1,"\t\t常量说明中的“=”写成“ := ”\n");break;case 2:printf("\t\t常量说明中的=后应该是数字\n");fprintf(fa1,"\t\t常量说明中的 =后应该是数字\n");break;case 3:printf("\t\t常量说明符中的表示符应该是=\n" );fprintf(fa1,"\t\t常量说明符中的表示符应该是=\n");break;case 4:printf("\t\tconst,var,procedure后应为标识符 \n" );fprintf(fa1,"\t\tconst,var,procedure后应为标识符\n");break;case 5:printf("\t\t漏掉了“ , ”或“ ; ” \n" );fprintf(fa1,"\t\t漏掉了“ , ”或“ ; ”\n" );break;case 6:printf("\t\t过程说明后的符号不正确\n" );fprintf(fa1,"\t\t过程说明后的符号不正确\n");break;case 7:printf("\t\t应是语句开始符\n" );fprintf(fa1,"\t\t应是语句开始符\n" );break;case 8:printf("\t\t程序体语句部分的后跟符不正确\n" );fprintf(fa1,"\t\t程序体语句部分的后跟符不正确\n" );break;case 9:printf("\t\t程序结尾丢了句号“. ”\n\n" );fprintf(fa1,"\t\t程序结尾丢了句号“. ” \n");break;case 10:printf("\t\t语句之间漏了“; ” \n" );fprintf(fa1,"\t\t语句之间漏了“; ” \n");break;case 11:printf("\t\t标识符拼写错误或未说明\n" );fprintf(fa1,"\t\t标识符拼写错误或未说明\n");break;case 12:printf("\t\t赋值语句中,赋值号左部标识符属性应是变量\n" );fprintf(fa1,"\t\t赋值语句中,赋值号左部标识符属性应是变量\n");break;case 13:printf("\t\t赋值语句左部标识符后应是复制号“:= ” \n" );fprintf(fa1,"\t\t赋值语句左部标识符后应是复制号“:= ” \n");break;case 14:printf("\t\tcall后应为标识符 \n" );fprintf(fa1,"\t\tcall后应为标识符 \n");break;case 15:printf("\t\tcall后标识符属性应为过程\n" );fprintf(fa1,"\t\tcall后标识符属性应为过程\n");break;case 16:printf("\t\t条件语句中丢了then\n" );fprintf(fa1,"\t\t条件语句中丢了then\n");break;case 17:printf("\t\t丢了“ end”或“ ; ” \n" );fprintf(fa1,"\t\t丢了“ end”或“ ; ”\n");break;case 18:printf("\t\twhile型循环语句中丢了“do” \n" );fprintf(fa1,"\t\twhile型循环语句中丢了“do” \n");break;case 19:printf("\t\t语句后的符号不正确\n" );fprintf(fa1,"\t\t语句后的符号不正确\n" );break;case 20:printf("\t\t应为关系运算符\n" );fprintf(fa1,"\t\t应为关系运算符\n");break;case 21:printf("\t\t表达式标示符属性不能是过程\n" );fprintf(fa1,"\t\t表达式标示符属性不能是过程\n");break;case 22:printf("\t\t表达式漏掉了右括号\n" );fprintf(fa1,"\t\t表达式漏掉了右括号\n");break;case 23:printf("\t\t因子后的非法符号\n" );fprintf(fa1,"\t\t因子后的非法符号\n");break;case 24:printf("\t\t表达式的开始符不能是此符号\n" );fprintf(fa1,"\t\t表达式的开始符不能是此符号\n");break;case 25:printf("\t\t标识符越界 \n" );fprintf(fa1,"\t\t标识符越界 \n");break;case 26:printf("\t\t非法字符 \n" );fprintf(fa1,"\t\t非法字符 \n");break;case 31:printf("\t\t数越界 \n");fprintf(fa1,"\t\t数越界 \n");break;case 32:printf("\t\tread语句括号中的标识符不是变量\n" );fprintf(fa1,"\t\tread语句括号中的标识符不是变量\n");break;case 33:printf("\t\twrite()或 read() 中应为完整表达式\n" );fprintf(fa1,"\t\twrite()或 read() 中应为完整表达式\n");break;default:printf("\t\t出现未知错误 \n" );fprintf(fa1,"\t\t出现未知错误 \n");}err++;}// 漏掉空格,读取一个字符,每次读一行,存入line缓冲区,line被getsym取空后再读一// 行,被函数getsym 调用int getch(){if(cc==ll){if(feof(fin)){printf("program incomplete");return-1;}ll=0;cc=0;printf("\n%d ",cx);fprintf(fa1,"\n%d ",cx);ch=' ';while(ch!=10){if(EOF==fscanf(fin,"%c",&ch)){line[ll]=0;break;}printf("%c",ch);fprintf(fa1,"%c",ch);line[ll]=ch;ll++;}fprintf(cifa,"\n");}ch=line[cc];cc++;return 0;}int getsym(){//词法分析int i,j,k,l;while(ch==' '||ch==10||ch==9)//忽略空格换行TABgetchdo;if(ch>='a'&&ch<='z'){//以字母开头的为保留字或者标识符k=0,l=1;do{if(k<al){//al为标识符或保留字最大长度a[k]=ch;k++;}if(k==al&&l==1){error(25);l=0;}getchdo;}while(ch>='a'&&ch<='z'||ch>='0'&&ch<='9');a[k]=0;//末尾存零strcpy(id,a);i=0;j=norw-1;do{//开始折半查找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){//找到即为保留字sym=wsym[k];fprintf(cifa,"%s\t\t%ssym\n",id,id);//printf("%s\t\t%ssym\n",id,id);}else{//否则为标识符或数字sym=ident;fprintf(cifa,"%s\t\tident\n",id);//printf("%s\t\tident\n",id);}}else {if(ch>='0'&&ch<='9'){k=0;num=0;sym=number;do{num=10*num+ch-'0';//数字的数位处理k++;getchdo;}while(ch>='0'&&ch<='9');k--;if(k>nmax){//数字的长度限制fprintf(cifa,"0\t\tnumber\n");num=0;error(31);}elsefprintf(cifa,"%d\t\tnumber\n",num);//printf("%d\t\tnumber\n",num);}else{if(ch==':'){//检测赋值符号,:只能和=匹配,否则不能识别getchdo;if(ch=='='){sym=becomes;fprintf(cifa,":=\t\tbecomes\n");getchdo;}else{sym=nul;}}else{if(ch=='<'){getchdo;if(ch=='='){sym=leq;//小于等于fprintf(cifa,"<=\t\tleq\n");getchdo;}else{sym=lss;//小于fprintf(cifa,"<\t\tlss\n");}}else{if(ch=='>'){getchdo;if(ch=='='){sym=geq;// 大于等于fprintf(cifa,">=\t\tgeq\n");getchdo;}else{sym=gtr;//大于fprintf(cifa,">\t\tgtr\n");}}else{sym=ssym[ch];//不满足上述条件时按单字// 符处理switch(ch){case'+':fprintf(cifa,"%c\t\tplus\n",ch);break;case '-':fprintf(cifa,"%c\t\tminus\n",ch);break;case '*':fprintf(cifa,"%c\t\ttimes\n",ch);break;case '/':fprintf(cifa,"%c\t\tslash\n",ch);break;case '(':fprintf(cifa,"%c\t\tlparen\n",ch);break;case ')':fprintf(cifa,"%c\t\trparen\n",ch);break;case '=':fprintf(cifa,"%c\t\teql\n",ch);break;case ',':fprintf(cifa,"%c\t\tcomma\n",ch);break;case '#':fprintf(cifa,"%c\t\tneq\n",ch);break;case ';':fprintf(cifa,"%c\t\tsemicolon\n",ch);break;case '.':break;default :error(26);}if(sym!=period){//判断是否结束getchdo;}else{printf("\n");fprintf(cifa,".\t\tperiod\n");}}}}}}return 0;}//生成目标代码 // 目标代码的功能码,层差和位移量int gen(enum fct x,int y,int z){if(cx>=cxmax){//如果目标代码索引过大,报错printf("Program too long");return -1;}code[cx].f=x;code[cx].l=y;code[cx].a=z;cx++;return 0;}//测试字符串int test(bool* s1,bool* s2,int n){if(!inset(sym,s1)){//测试sym是否属于s1,不属于则报错n error(n);while((!inset(sym,s1))&&(!inset(sym,s2))){//检测不通过时,不停获得符号,直到它属于需要或补救的集合getsymdo;}}return 0;}// 编译程序主体//lev:当前分程序所在层,tx: 名字表当前尾指针fsys :当前模块后跟符号集合int block(int lev,int tx,bool* fsys){int i;int dx;//名字分配到的相对地址int tx0;//保留初始txint cx0;//保留初始cxbool nxtlev[symnum];dx=3;//相对地址从 3 开始,前 3 个单元即0、 1、 2 单元分别为SL: 静态链;//DL :动态链; RA:返回地址tx0=tx;//记录本层的初始位置table[tx].adr=cx;gendo(jmp,0,0);if(lev>levmax){//层数超过3error(32);}do{if(sym==constsym){//收到常量声明printf("该语句为常量定义语句\n");getsymdo;do{constdeclarationdo(&tx,lev,&dx);//常量声明处理,dx 会改 // 变所以使用指针while(sym==comma){//处理一次多常量定义getsymdo;constdeclarationdo(&tx,lev,&dx);}if(sym==semicolon){//常量声明处理结束getsymdo;}else{error(5);//漏掉了逗号或者分号(一般是分号)}}while(sym==ident);}if(sym==varsym){//收到变量声明printf("该语句为变量声明语句\n");getsymdo;do{vardeclarationdo(&tx,lev,&dx);//变量声明处理while(sym==comma){//处理一次多变量定义getsymdo;vardeclarationdo(&tx,lev,&dx);}if(sym==semicolon){//变量声明处理结束getsymdo;}else{error(5);//漏掉逗号或者分号}}while(sym==ident);}while(sym==procsym){//收到过程声明printf("该语句为过程声明语句\n");getsymdo;if(sym==ident){enter(procedur,&tx,lev,&dx);//记录过程名getsymdo;}else{error(4);//过程声明后应为标识符}if(sym==semicolon){getsymdo;}else{error(5);//漏掉了分号}memcpy(nxtlev,fsys,sizeof(bool)*symnum);nxtlev[semicolon]=true;if(-1==block(lev+1,tx,nxtlev)){return -1;}if(sym==semicolon){getsymdo;memcpy(nxtlev,statbegsys,sizeof(bool)*symnum);nxtlev[ident]=true;nxtlev[procsym]=true;testdo(nxtlev,fsys,6);}else{error(5);}}memcpy(nxtlev,statbegsys,sizeof(bool)*symnum);nxtlev[ident]=true;nxtlev[period]=true;testdo(nxtlev,declbegsys,7);}while(inset(sym,declbegsys));//直到没有声明符号code[table[tx0].adr].a=cx;//开始生成当前过程代码table[tx0].adr=cx;//当前过程代码地址table[tx0].size=dx;cx0=cx;gendo(inte,0,dx);//生成分配存代码if(tableswitch){//输出符号表if(tx0+1<tx){fprintf(fas,"TABLE:\n");//printf("NULL\n");}for(i=tx0+1;i<=tx;i++){switch(table[i].kind){case constant:fprintf(fas,"%d const %s ",i,table[i].name);fprintf(fas,"val=%d\n",table[i].val);break;case variable:fprintf(fas,"%d var %s ",i,table[i].name);fprintf(fas,"lev=%daddr=%d\n",table[i].level,table[i].adr);break;case procedur:fprintf(fas,"%d proc %s ",i,table[i].name);fprintf(fas,"lev=%daddr=%dsize=%d\n",table[i].level,table[i].adr,table[i].size);break;}}}memcpy(nxtlev,fsys,sizeof(bool)*symnum);//每个后跟符号集和都包含上层后跟符// 号集和,以便补救nxtlev[semicolon]=true;nxtlev[endsym]=true;statementdo(nxtlev,&tx,lev);gendo(opr,0,0);//每个过程出口都要使用的释放数据指令memset(nxtlev,0,sizeof(bool)*symnum);//分程序没有补救集合testdo(fsys,nxtlev,8);//检测后跟符号集的正确性listcode(cx0);//输出代码return 0;}//k:const var procedure//ptx:符号表尾的指针//pdx:dx为当前应分配变量的相对地址//lev: 符号名字所在的层次// 往符号表中添加void enter(enum object k,int* ptx,int lev,int* pdx){(* ptx)++;strcpy(table[(*ptx)].name,id);table[(* ptx)].kind=k;switch(k){case constant:if(num>amax){error(31);num=0;}table[(*ptx)].val=num;break;case variable:table[(*ptx)].level=lev;table[(*ptx)].adr=(*pdx);(*pdx)++;break;case procedur:table[(*ptx)].level=lev;break;}}//寻找符号在符号表中的地址int position(char*idt,int tx){int i;strcpy(table[0].name,idt);i=tx;//符号表尾while(strcmp(table[i].name,idt)!=0){i--;}return i;}//常量声明处理int constdeclaration(int* ptx,int lev,int* pdx){if(sym==ident){getsymdo;if(sym==eql||sym==becomes){if(sym==becomes){error(1);}getsymdo;if(sym==number){enter(constant,ptx,lev,pdx);getsymdo;}else{error(2);}}else{error(3);}}else{error(4);}return 0;}//变量声明处理int vardeclaration (int* ptx,int lev,int* pdx){if(sym==ident){enter(variable,ptx,lev,pdx);getsymdo;}else{error(4);}return 0;}//输出目标代码清单void listcode(int cx0){int i;if(listswitch){for(i=cx0;i<cx;i++){fprintf(fa,"%d %s %d %d\n",i,mnemonic[code[i].f],code[i].l,code[i],a);}}}//语句处理int statement(bool* fsys,int* ptx,int lev){int i,cx1,cx2;bool nxtlev[symnum];if(sym==ident){i=position(id,*ptx);if(i==0){error(11);}else{if(table[i].kind!=variable){error(12);i=0;}else{getsymdo;if(sym==becomes){getsymdo;printf("该语句为赋值语句。

编译原理实验剖析

编译原理实验剖析
定次数 [ ] :表示方括号内的语法成分为任选项 ( ) :表示圆括号内的成分优先
例:用EBNF描述分程序的定义
<分程序>∷=[<常量说明部分>][<变量说明 部分>][<过程说明部分>] <语句> <常量说明部分>∷= CONST<常量定义>
{, <常量定义>}; <常量定义>∷= <标识符>=<无符号整数> <变量说明部分>∷= VAR <标识符>
任务一:读程序
内容
读程序GetSym()
识别保留字 识别标识符 拼数 拼双字符单词 识别单字符单词
要求
每班前十名同学给予检查
任务二:扩充单词
内容
增加保留字:FOR、DOWNTO和TO 增加双字符单词:*=和/=
要求
设计测试方式,测试单词是否能被识别 每班前十名同学给予检查
5. 语法分析
—递归子程序法
PL/0语言是PASCAL语言的子集
数据类型,只有整型 数据结构 ,只有简变和常量 整数最多为14位 标识符的有效长度是10位 过程最多可嵌套三层 作用域规则(内层可引用包围它的外层 定义的标识符),过程可嵌套定义,可递 归调用
2.2 语法描述图
内的文字或符号表示非终结符 或 内的文字或符号表示终结符
符号表
重要变量及过程
type symbol=( nul, ident, number, plus, …,
varsym, procsym );
保留字表: word[1]:=‘BEGIN‘; word[2]:=‘CALL‘;
... word[13]:=‘WRITE‘;

词法分析程序(C语言编写,针对PL_0语言)

词法分析程序(C语言编写,针对PL_0语言)

#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语言简介

4
#define #define #define #define #define #define #define #define #define #define #define
becomes beginsym endsym ifsym thensym whilesym dosym callsym constsym varsym procsym
0x80000 0x100000 0x200000 0x400000 0x800000 0x1000000 0x2000000 0x4000000 0x8000000 0x10000000 0x20000000
enum object { constant, variable, proc }; enum fct { lit, opr, lod, sto, cal, Int, jmp, jpc }; typedef struct{ enum fct f; // function code long l; // level long a; // displacement address } instruction; /* lit 0, a : load constant a opr 0, a : execute operation a lod l, a : load variable l, a sto l, a : store variable l, a cal l, a : call procedure a at level l Int 0, a : increment t-register by a jmp 0, a : jump to a jpc 0, a : jump conditional to a */ char ch; unsigned long sym; char id[al+1]; long num; long cc; long ll; long kk, err; long cx; char line[81]; // // // // // // last character read last symbol read last identifier read last number read character count line l包括标准输入和输出)操作有较大区别。 (9)两种语言的注释形式不同。 (10)由于 int 是 C 语言的关键字,因此中间语言指令的操作码 int 被改成 Int。 (11)改写版本中增加了制表符作为单词的分隔符,因为现在大家已经习惯用制表符。 带来的问题是编译器报错的箭头所指位置可能不准确。 Niklaus Wirth 设计的编译器中有一些不影响大局的小问题 (也许是 Niklaus Wirth 有意为 之) ,我们也没有修改。例如: (1)没有检查一个分程序中的名字是否重复声明,导致出现重复声明的名字时,默认 的是最后出现的那一个。 (2)按附录 1.1 节的文法,常量定义和变量声明用逗号分隔,但实际情况是用分号分 隔也被认可。 (3)无符号整数超过一定位数时,以报告编号为 30 而不是 31 的错误更为准确。 下面是编译器两个文件 pl0.h 和 pl0.c 的代码。 (1)文件 pl0.h #include <stdio.h> #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define norw txmax nmax al amax levmax cxmax nul ident number plus minus times slash oddsym eql neq lss leq gtr geq lparen rparen comma semicolon period 11 100 14 10 2047 3 2000 0x1 0x2 0x4 0x8 0x10 0x20 0x40 0x80 0x100 0x200 0x400 0x800 0x1000 0x2000 0x4000 0x8000 0x10000 0x20000 0x40000 // // // // // // // no. of reserved words length of identifier table max. no. of digits in numbers length of identifiers maximum address maximum depth of block nesting size of code array

PL0编译器源程序分析

PL0编译器源程序分析

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语法分析
/
/如果上述的任意一个步骤出了问题都会有错误提示,并指出是在源文件中的第几行,是哪 一个定义出了问题
/当一个<语句>【复合语句除外】判断成功之后,在词法分析的结果找到这个语句的开始和 结束,并输出这个语句是什么语句
/语法分析的实际操作类似一个走迷宫的搜索问题,找到一个可行的方向就前进,直到走到 把所有单词都分析完,或者走不通了,一层层回溯返回FALSE合出错误信息
bool isChengXu(int lev);
bool isFenChengXu(int lev);
bool isChengXuShouBu();
bool isChangLiangShuoMing();
bool isBianLiangShuoMing();
bool isGuoChengShuoMing(int lev); bool isYuJuBuFen();
/
/语法分析过程中
/利用词法分析的结果进行分析
/严格按照PL0程序定义来编写
/
/<程序> ::= <程序首部> <分程序>.
/<程序首部> ::=PROGRAM<标识符>;
/<分程序> ::= [<常量说明部分>][<变量说明部分>][<过程说明部分>]<语句部分> /<常量说明部分> ::=CONST<常量定义>{,<常量定义>};
bool isChangLiangDingYi();
bool isGuoChengShouBu(int lev);
bool isYuJu();
bool isFuHeYuJu();
bool isFuZhiYuJu();
bool isWhileDoYuJu();
bool isIfYuJu();
bool isCallYuJu();

PL0源代码(C语言版)

PL0源代码(C语言版)

/*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语言语法分析器实验报告

PL0语言语法分析器实验报告

PL/0语言语法分析器实验报告信息资源管理学院10级档案班马雪静2010202609 一、实验内容用bison工具生成一个PL/0语言的语法分析程序,对PL/0源程序进行语法分析,并输出归约时所用的语法规则。

二、实验环境语法分析器生成工具:bison编程语言:C三、程序设计原理与方法1.cifa.l%{#include<stdio.h>#include<string.h>#include<stdlib.h>%}Letter [A-Za-z]Digit [0-9]D [1-9]LetterDigit [A-Za-z0-9]SPACE [\n\t\f\040]%%"+" {return ADD;}"-" {return MINUS;}"*" {return MULTIPL Y;}"/" {return DIVIDE;}"=" {return EQUAL;}"#" {return UNEQUAL;}"<" {return LESS;}"<=" {return LESSEQUAL;}">" {return MORE;}">=" {return MOREEQUAL;}":=" {return EV ALUATE;}"(" {return LPARENTHESES;}")" {return RPARENTHESES;}"," {return COMMA;}";" {return SEMICOLON;}"." {return DOT;}"if"|"IF" {return IF;}"then"|"THEN" {return THEN;}"while"|"WHILE" {return WHILE;}"do"|"DO" {return DO;}"read"|"READ" {return READ;}"write"|"WRITE" {return WRITE;}"call"|"CALL" {return CALL;}"begin"|"BEGIN" {return BEG;}"end"|"END" {return END;}"const"|"CONST" {return CONST;}"var"|"V AR" {return V AR;}"procedure"|"PROCEDURE" {return PROCEDURE;}"odd"|"ODD" {return ODD;}{D}{Digit}*|"0" {return NOSIGNINTEGER;}{Letter}{LetterDigit}* {return IDENT;}{Digit}{LetterDigit}* {return ERROR;}{SPACE}* {}. {return ERRORCHAR;}%%int yywrap(){return 1;}2.Yufa.y%{#include<stdio.h>#include<string.h>#include"lex.yy.c"%}%token IF THEN WHILE DO READ WRITE CALL BEG END CONST V AR PROCEDURE ODD%token ADD MINUS MULTIPL Y DIVIDE EQUAL UNEQUAL LESS LESSEQUAL MORE MOREEQUAL EV ALUA TE%token LPARENTHESES RPARENTHESES COMMA SEMICOLON DOT ERROR ERRORCHAR%token NOSIGNINTEGER IDENT%%//<程序> ::= <分程序>.Program:PartialProgram DOT {printf("<程序> --> <分程序>.\n");};//<分程序> ::= [<常量说明部分>][<变量说明部分>][<过程说明部分>]<语句> PartialProgram:ConstantDeclaration VariableDeclaration ProcedureDeclaration Statement {printf("<分程序> --> <常量说明部分><变量说明部分><过程说明部分><语句>\n");}|VariableDeclaration ProcedureDeclaration Statement {printf("<分程序> --> <变量说明部分><过程说明部分><语句>\n");}|ConstantDeclaration ProcedureDeclaration Statement {printf("<分程序> --> <常量说明部分><过程说明部分><语句>\n");}|ConstantDeclaration VariableDeclaration Statement {printf("<分程序> --> <常量说明部分><变量说明部分><语句>\n");}|ConstantDeclaration Statement {printf("<分程序> --> <常量说明部分><语句>\n");}|VariableDeclaration Statement {printf("<分程序> --> <变量说明部分><语句>\n");}|ProcedureDeclaration Statement {printf("<分程序> --> <过程说明部分><语句>\n");}|Statement {printf("<分程序> --> <语句>\n");};//<常量说明部分> ::= CONST<常量定义>{,<常量定义>};ConstantDeclaration:CONST ConstList SEMICOLON {printf("<常量说明部分> --> CONST <常量定义串>;\n");} ;//<常量定义串> ::= <常量定义>|<常量定义串>,<常量定义>ConstList:ConstDefination {printf("<常量定义串> --> <常量定义>\n");}|ConstList COMMA ConstDefination {printf("<常量定义串> --> <常量定义串>,<常量定义>\n");};//<常量定义> ::= <标识符>:=<无符号整数>ConstDefination:IDENT EVALUATE NOSIGNINTEGER {printf("<常量定义> --> <标识符>:=<无符号整数>\n");};//<变量说明部分> ::= V AR<标识符>{,<标识符>};VariableDeclaration:V AR IdentList SEMICOLON {printf("<变量说明部分> --> V AR <标识符串>;\n");};//<标识符串> ::= <标识符>|<标识符串>,<标识符>IdentList:IDENT {printf("<标识符串> --> <标识符>\n");}|IdentList COMMA IDENT {printf("<标识符串> --> <标识符串>,<标识符>\n");}//<过程说明部分> ::= <过程首部><分程序>{;<过程说明部分>};ProcedureDeclaration:ProcedureHead PartialProgram SEMICOLON ProcedureDeclaration SEMICOLON {printf("<过程说明部分>--><过首部><分程序>;<过程说明部分>;");}|ProcedureHead PartialProgram SEMICOLON {printf("<过程说明部分>--><过程首部><分程序>;\n");};//<过程首部> ::= PROCEDURE<标识符>;ProcedureHead:PROCEDURE IDENT SEMICOLON {printf("<过程首部> --> PROCEDURE<标识符>;\n");} ;//<语句> ::= <赋值语句>|<复合语句>|<条件语句>|<当型循环语句>|<过程调用语句>|<读语句>|<写语句>|<空>Statement:EvaluateStatement {printf("<语句> --> <赋值语句>\n");}|ComplexStatement {printf("<语句> --> <复合语句>\n");}|ConditionStatement {printf("<语句> --> <条件语句>\n");}|WhileStatement {printf("<语句> --> <当型循环语句>\n");}|ProcedureCallStatement {printf("<语句> --> <过程调用语句>\n");}|ReadStatement {printf("<语句> --> <读语句>\n");}|WriteStatement {printf("<语句> --> <写语句>\n");}| {printf("<语句> --> <空>\n");};//<赋值语句> ::= <标识符>:=<表达式>EvaluateStatement:IDENT EVALUATE Expression {printf("<赋值语句> --> <标识符>:=<表达式>\n");};//<复合语句> ::= BEGIN<语句>{;<语句>}ENDComplexStatement:BEG StatementList END {printf("<复合语句> --> BEGIN<语句串>END\n");};//<语句串> ::= <语句>|<语句串>;<语句>StatementList:Statement {printf("<语句串> --> <语句>\n");}|StatementList SEMICOLON Statement {printf("<语句串> --> <语句串>;<语句>\n");};//<条件> ::= <表达式><关系运算符><表达式>|ODD<表达式>Condition:Expression RelationOperator Expression {printf("<条件> --> <表达式><关系运算符><表达式>\n");}|ODD Expression {printf("<条件> --> ODD<表达式>\n");};//<条件语句> ::= IF<条件>THEN<语句>ConditionStatement:IF Condition THEN Statement {printf("<条件语句> --> IF<条件>THEN<语句>\n");};//<表达式> ::= [+|-]<项>{<加法运算符><项>}Expression:ADD TermList {printf("<表达式> --> +<项串>\n");}|MINUS TermList {printf("<表达式> --> -<项串>\n");}|TermList {printf("<表达式> --> <项串>\n");};// <项串> ::= <项>|<项串><加法运算符><项>TermList:Term {printf("<项串> --> <项>\n");}|TermList ADD Term {printf("<项串> --> <项串>+<项>\n");}|TermList MINUS Term {printf("<项串> --> <项串>-<项>\n");};//<项> ::= <因子>{<乘法运算符><因子>}Term:GeneList {printf("<项> --> <因子串>\n");};//<因子串> ::= <因子>|<因子串><乘法运算符><因子>GeneList:Gene {printf("<因子串> --> <因子>\n");}|GeneList MULTIPL Y Gene {printf("<因子串> --> <因子串>*<因子>\n");}|GeneList DIVIDE Gene {printf("<因子串> --> <因子串>/<因子>\n");};//<因子> ::= <标识符>|<无符号整数>|'('<表达式>')'Gene:IDENT {printf("<因子> --> <标识符>\n");}|NOSIGNINTEGER {printf("<因子> --> <无符号整数>\n");}|LPARENTHESES Expression RPARENTHESES {printf("<因子> --> '('<表达式>')'\n");};//<关系运算符> ::= =|#|<|<=|>|>= */RelationOperator:EQUAL {printf("<关系运算符> --> =\n");}|UNEQUAL {printf("<关系运算符> --> #\n");}|LESS {printf("<关系运算符> --> <\n");}|LESSEQUAL {printf("<关系运算符> --> <=\n");}|MORE {printf("<关系运算符> --> >\n");}|MOREEQUAL {printf("<关系运算符> --> >=\n");};//<当型循环语句> ::= WHILE<条件>DO<语句>WhileStatement:WHILE Condition DO Statement{printf("<当型循环语句> --> WHILE<条件>DO<语句>\n");} ;//<过程调用语句> ::= CALL<标识符> */ProcedureCallStatement:CALL IDENT {printf("<过程调用语句> --> CALL<标识符>\n");};//<读语句> ::= READ'('<标识符>{,<标识符>}')'ReadStatement:READ LPARENTHESES IdentList RPARENTHESES {printf("<读语句> --> READ(<标识符串>)\n");};//<写语句> ::= WRITE'('<表达式>{,<表达式>}')'WriteStatement:WRITE LPARENTHESES ExpressionList RPARENTHESES {printf("<写语句> --> WRITE(<表达式串>)\n");};//<表达式串> ::= <表达式>|<表达式串>,<表达式>ExpressionList:Expression {printf("<表达式串> --> <表达式>\n");}|ExpressionList COMMA Expression {printf("<表达式串> --> <表达式串>,<表达式>\n");};%%int main(){char filename[20];printf("file name:");scanf("%s",filename);yyin=fopen(filename,"r");if(!yyin){printf("\nno files\n");return 0;}yyparse();fclose(yyin);return 0;}yyerror(char *s){printf("Error!\n");}四、实验结果1.源文件:column.pl0var r, h, len, a1, a2, volumn;beginread(r);read(h);len := 2 * 3 * r;a1 := 3 * r * r;a2 := a1 + a1 + len * h;volumn := a1 * h;write(len);write(a1);write(a2);write(volumn);end.2.归约结果:。

pl0词法分析器C版

pl0词法分析器C版

#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词法分析器(C语言版)

pl0词法分析器(C语言版)

#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 词法分析 c程序

pl0 词法分析 c程序
#include <stdio.h>
/*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))

第2章 PL0编译程序的实现(4学时)

第2章 PL0编译程序的实现(4学时)
13 13
表格管理举例
CONST A=35,B=49; VAR C,D,E; PROCEDURE P; VAR G
名字
TX0 NAME:A
类型
层次/值
地址
存储空间
NAME:B NAME:C NAME:D NAME:E NAME:P TX1 NAME:G ……
KIND:CONSTANT KIND:CONSTANT KIND:VARIABLE KIND:VARIABLE KIND:VARIABLE KIND:PROCEDUR KIND:VARIABLE ……
何为PL/0语言?
PL/0语言: PASCAL语言的子集,功 能简单,结构清晰,可 读性强,具备了一般高 级语言的必备部分。
PL/0程序示例: CONST A=10; VAR B,C; PROCEDURE P; VAR D; PROCEDURE Q; VAR X; BEGIN READ(X); D:=X; WHILE X#0 DO CALL P; END; BEGIN WRITE(D); CALL Q; END; BEGIN CALL P; END.
存储空间
SIZE:4
ADR:DX SIZE:4 SIZE:5 ADR:DX ADR:DX ADR:DX+1 SIZE:5 ADR:DX ADR:DX+1
15 15
2.5 PL/0编译程序的目标代码结构和代码生成
• 目标代码pcode是一种假想栈式计算机的汇编语言。
• 指令格式 功能码
f l
a
层次差 通常为“位移量” 根据不同的指令 有所不同
18
Const a=10; var b,c; procedure p; begin c:=b+a; end; begin read(b); call p; write(c); end.

编译原理PL0教程

编译原理PL0教程

序言 (1)第一部分PL/0语言及其编译器 (2)1.PL/0语言介绍 (2)1.1 PL/0语言的语法图 (3)2.PL/0语言编译器 (6)2.1词法分析 (7)2.2 语法分析 (7)2.3 语义分析 (9)2.4 代码生成 (9)2.5 代码执行 (11)2.6 错误诊断处理 (13)2.7 符号表管理 (15)2.8其他 (16)第二部分上机实践要求 (17)第三部分PL/0语言编译器源程序 (19)1.一个例子 (19)1.1 PL/0语言源程序 (19)1.2 生成的代码(片段) (21)2.PL/0语言编译器源程序 (21)编译原理实践教程序言《编译原理和技术》的课程实践至少有两种可能的安排。

其一,为配合编译课程教学,而安排多次小型实践,分别支持编译程序的各个阶段。

其二,针对某一规模适中的语言来设计和实现一个相对完整、独立编译器。

《编译原理实践教程》作为《编译原理和技术》课程的延伸,其目的是让大家动手设计和实现某一规模适中的语言的编译器,该编译器不仅涉及编译程序的各个阶段,而且也强调了编译的总体设计、各个阶段的接口安排等等。

通过上机实践,来设计这个相对完整的编译器,一方面可以使学生增加对编译程序的整体认识和了解——巩固《编译原理和技术》课程所学知识,另一方面,通过上机练习,学生也可以学到很多程序调试技巧和设计大型程序一般的原则,如模块接口的协调,数据结构的合理选择等等。

为了使学生能尽早动手实践,我们建议把实践分成三部分,首先阅读本教程第一部分,在这部分就PL/0语言的语法及其编译程序的各个阶段作了简单介绍,以便对PL/0编译程序有个初步的印象。

其次要认真阅读理解第三部分所给出的PL/0编译器源程序,使上一阶段的初步印象得以加深、具体化。

最后按照第二部分的实验要求扩充PL/0语言的功能并加以实现。

第一部分 PL/0语言及其编译器1. PL/0语言介绍PL/0程序设计语言是一个较简单的语言,它以赋值语句为基础,构造概念有顺序、条件和重复(循环)三种。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

//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>/*PL/0 编译系统C版本头文件pl0.h*/#include"string.h"/*解释执行时使用的栈*/#define stacksize 500//typedef enum {// false,// true//}bool;# 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; /*根据f的不同而不同*/};FILE * fas; /*输出名字表*/FILE * fa; /*输出虚拟机代码*/FILE * fa1; /*输出源文件及其各行对应的首地址*/FILE * fa2; /*输出结果*/bool listswitch; /*显示虚拟机代码与否*/bool tableswitch; /*显示名字表与否*/char ch; /*获得字符的缓冲区,getch使用*/enum symbol sym; /*当前的符号*/char id[al+1]; /*ident,多出的一个字节用于存放0*/int num; /*当前number*/int cc,ll; /*getch使用的计数器,cc表示当前字符(ch)的位置*/ int cx; /*虚拟机代码指针,取值范围[0,cxmax-1]*/char line[81]; /*读取行缓冲区*/char a[al+1]; /*临时符号,多出的一个字节用于存放0*/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);int main(){bool nxtlev[symnum];printf("Input pl/0 file ?");scanf("%s",&fname); /*输入文件名*/fin=fopen(fname,"r");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("fal.tmp","w");fprintf(fa1,"Iput pl/0 file ?");fprintf(fa1,"%s\n", fname);init();/*初始化*/err=0;cc=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;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]),"inte");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);space[cc-1]=0;//出错时当前符号已经读完,所以cc-1printf("****%s!%d\n",space,n);err++;}/** 漏掉空格,读取一个字符** 每次读一行,存入line缓冲区,line被getsym取空后再读一行** 被函数getsym调用*/int getch(){if(cc==ll){if(feof(fin)){printf("program incomplete");return -1;}ll=0;cc=0;printf("%d,cx");fprintf(fa1,"%d",cx);ch=' ';while(ch!=10){//fscanf(fin,"%c",&ch)if(EOF==fscanf(fin,"%c",&ch)){line[ll]=0;break;}printf("%c",ch);fprintf(fa1,"%c",ch);line[ll]=ch;ll++;}printf("\n");fprintf(fa1,"\n");}ch=line[cc];cc++;return 0;}/*词法分析,获取一个符号*/int getsym(){int i,j,k;while( ch==' '||ch==10||ch==9){getchdo ;}if(ch>='a'&&ch<='z'){k=0;do{if(k<al){ a[k]=ch;k++;}getchdo;}while(ch>='a'&&ch<='z'||ch>='0'&&ch<='9'); a[k]=0;strcpy(id,a);i=0;j=norw-1;do{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){sym=wsym[k];}else{sym=ident;}}else{if(ch>='0'&&ch<='9'){k=0;num=0;sym=number;do{num=10*num+ch-'0';k++;getchdo;}while(ch>='0'&&ch<='9'); /*获取数字的值*/k--;if(k>nmax){error(30);}}else{if(ch==':') /*检测赋值符号*/{getchdo;if(ch=='='){sym=becomes;getchdo;}else{sym=nul; /*不能识别的符号*/}}else{if(ch=='<') /*检测小于或小于等于符号*/{getchdo;if(ch=='='){sym=leq;getchdo;}else{sym=lss;}}else{if(ch=='>') /*检测大于或大于等于符号*/{getchdo;if(ch=='='){sym=geq;getchdo;}else{sym=gtr;}}else{sym=ssym[ch];/* 当符号不满足上述条件时,全部按照单字符号处理*/ //getchdo;//richardif(sym!=period){getchdo;}//end richard}}}}}return 0;}/**生成虚拟机代码**x:instruction.f;*y:instruction.l;*z:instruction.a;*/int gen(enum fct x,int y,int z){if(cx>=cxmax){printf("Program too long"); /*程序过长*/return -1;}code[cx].f=x;code[cx].l=y;code[cx].a=z;cx++;return 0;}/**测试当前符号是否合法**在某一部分(如一条语句,一个表达式)将要结束时时我们希望下一个符号属于某集合*(该部分的后跟符号)test 负责这项检测,并且负责当检测不通过时的补救措施*程序在需要检测时指定当前需要的符号集合和补救用的集合(如之前未完成部分的后跟*符号),以及不通过时的错误号**S1:我们需要的符号*s2:如果不是我们需要的,则需要一个补救用的集合*n:错误号*/int test(bool* s1,bool* s2,int n){if(! inset(sym,s1)){error(n);/*当检测不通过时,不停获取符号,直到它属于需要的集合或补救的集合*/while((! inset(sym,s1))&&(! inset(sym,s2))){getsymdo;}}return 0;}/**编译程序主体**lev:当前分程序所在层*tx:名字表当前尾指针*fsys:当前模块后跟符号集合*/int block(int lev,int tx,bool* fsys){int i;int dx; /*名字分配到的相对地址*/int tx0; /*保留初始tx*/int cx0; /*保留初始cx*/bool nxtlev[symnum]; /*在下级函数的参数中,符号集合均为值参,但由于使用数组实现,传递进来的是指针,为防止下级函数改变上级函数的集合,开辟新的空间传递给下级函数*/ dx=3;tx0=tx; /*记录本层名字的初始位置*/table[tx].adr=cx;gendo(jmp,0,0);if(lev > levmax){error(32);}do{if(sym==constsym) /*收到常量声明符号,开始处理常量声明*/{getsymdo;do{constdeclarationdo(&tx,lev,&dx); /*dx的值会被constdeclaration改变,使用指针*/while(sym==comma){getsymdo;constdeclarationdo(&tx,lev,&dx);}if(sym==semicolon){getsymdo;}else{error(5); /*漏掉了逗号或者分号*/}}while(sym==ident);}if(sym==varsym)/*收到变量声名符号,开始处理变量声名*/ {getsymdo;do{vardeclarationdo(&tx,lev,&dx);while(sym==comma){getsymdo;vardeclarationdo(&tx,lev,&dx);}if(sym==semicolon){getsymdo;}else{error(5);}}while(sym==ident);}while(sym==procsym)/*收到过程声名符号,开始处理过程声名*/ {getsymdo;if(sym==ident){enter(procedur,&tx,lev,&dx);/*记录过程名字*/getsymdo;}else{error(4);/*procedure后应为标识符*/}if(sym==semicolon){getsymdo;}else{error(5);/*漏掉了分号*/}memcpy(nxtlev,fsys,sizeof(bool)*symnum);nxtlev[semicolon]=true;if(-1==block(lev+1,tx,nxtlev)){return -1;/*递归调用*/}if(sym==semicolon){getsymdo;memcpy(nxtlev,statbegsys,sizeof(bool)*symnum);nxtlev[ident]=true;nxtlev[procsym]=true;testdo(nxtlev,fsys,6);}else{error(5); /*漏掉了分号*/}}memcpy(nxtlev,statbegsys,sizeof(bool)*symnum);nxtlev[ident]=true;nxtlev[period]=true;testdo(nxtlev,declbegsys,7);}while(inset(sym,declbegsys)); /*直到没有声明符号*/code[table[tx0].adr].a=cx; /*开始生成当前过程代码*/table[tx0].adr=cx; /*当前过程代码地址*/table[tx0].size=dx; /*声明部分中每增加一条声明都会给dx增加1,声明部分已经结束,dx就是当前过程数据的size*/cx0=cx;gendo(inte,0,dx); /*生成分配内存代码*/if(tableswitch) /*输出名字表*/{printf("TABLE:\n");if(tx0+1>tx){printf("NULL\n");}for(i=tx0+1;i<=tx;i++){switch(table[i].kind){case constant:printf("%d const %s",i,table[i].name);printf("val=%d\n",table[i].val);fprintf(fas,"%d const %s",i,table[i].name);fprintf(fas,"val=%d\n",table[i].val);break;case variable:printf("%d var%s",i,table[i].name);printf("lev=%d addr=%d\n",table[i].level,table[i].adr);fprintf(fas,"%d var %s",i,table[i].name);fprintf(fas,"lev=%d addr=%d\n",table[i].level,table[i].adr);break;case procedur:printf("%d proc%s",i,table[i].name);printf("lev=%d addr=%d size=%d\n",table[i].level,table[i].adr,table[i].size);fprintf(fas,"%d proc%s",i,table[i].name);fprintf(fas,"lev=%d adr=%d size=%d \n",table[i].level,table[i].adr,table[i].size);break;}}printf("\n");}/*语句后跟符号为分号或end*/memcpy(nxtlev,fsys,sizeof(bool)*symnum);/*每个后跟符号集和都包含上层后跟符号集和,以便补救*/nxtlev[semicolon]=true;nxtlev[endsym]=true;statementdo(nxtlev,&tx,lev);gendo(opr,0,0); /*每个过程出口都要使用的释放数据段命令*/memset(nxtlev,0,sizeof(bool)*symnum); /*分程序没有补救集合*/test(fsys,nxtlev,8); /*检测后跟符号正确性*/listcode(cx0); /*输出代码*/return 0;}/**在名字表中加入一项**k:名字种类const,var or procedure*ptx:名字表尾指针的指针,为了可以改变名字表尾指针的数值*lev:名字所在的层次,以后所有的lev都是这样*pdx:为当前应分配的变量的相对地址,分配后要增加1*/void enter (enum object k,int *ptx,int lev, int *pdx){(*ptx)++;strcpy(table[(*ptx)].name,id); /*全局变量id中已存有当前名字的名字*/ table[(*ptx)].kind=k;switch(k){case constant: /*常量名字*/if (num>amax){error(31);num=0;}table[(*ptx)].val=num;break;case variable: /*变量名字*/table[(*ptx)].level=lev;table[(*ptx)].adr=(*pdx);(*pdx)++;break; /*过程名字*/case procedur:table[(*ptx)].level=lev;break;}}/**查找名字的位置*找到则返回在名字表中的位置,否则返回0**idt: 要查找的名字*tx::当前名字表尾指针*/int position(char * idt,int tx){int i;strcpy(table[0].name,idt);i=tx;while(strcmp(table[i].name,idt)!=0){i--;}return i;}/**常量声明处理*/int constdeclaration(int * ptx,int lev,int * pdx){if(sym==ident){getsymdo;if(sym==eql ||sym==becomes){if(sym==becomes){error(1); /*把=写出成了:=*/ }getsymdo;if(sym==number){enter(constant,ptx,lev,pdx);getsymdo;}else{error(2); /*常量说明=后应是数字*/}}else{error(3); /*常量说明标识后应是=*/}}else{error(4); /*const后应是标识*/}return 0;}/***/int vardeclaration(int * ptx,int lev,int * pdx){if(sym==ident){enter(variable,ptx,lev,pdx);//填写名字表getsymdo;}else{error(4);}return 0;}/**输入目标代码清单*/void listcode(int cx0){int i;if (listswitch){for(i=cx0;i<cx;i++){printf("%d%s%d%d\n",i,mnemonic[code[i].f],code[i].l,code[i].a);fprintf(fa,"%d%s%d%d\n",i,mnemonic[code[i].f],code[i].l,code[i].a);}}}/**语句处理*/int statement(bool* fsys,int * ptx,int lev){int i,cx1,cx2;bool nxtlev[symnum];if(sym==ident){i=position(id,*ptx);if(i==0){error(11);}else{if(table[i].kind!=variable){error(12);i=0;}else{getsymdo;if(sym==becomes){getsymdo;}else{error(13);}memcpy(nxtlev,fsys,sizeof(bool)* symnum);expressiondo(nxtlev,ptx,lev);if(i!=0){gendo(sto,lev-table[i].level,table[i].adr);}}}}else{if(sym==readsym){getsymdo;if(sym!=lparen){error(34);}else{do{getsymdo;if(sym==ident){i=position(id, *ptx);}else{i=0;}if(i==0){error(35);}else{gendo(opr,0,16);gendo(sto,lev-table[i].level,table[i].adr); /* 储存到变量*/ }getsymdo;}while (sym==comma); /*一条read语句可读多个变量*/ }if(sym!=rparen){error(33); /* 格式错误,应是右括号*/while(!inset(sym,fsys))/* 出错补救,直到收到上层函数的后跟符号*/{getsymdo;}}else{getsymdo;}}else{if(sym==writesym) /* 准备按照write语句处理,与read类似*/ {getsymdo;if(sym==lparen){do{getsymdo;memcpy(nxtlev,fsys,sizeof(bool)*symnum);nxtlev[rparen]=true;nxtlev[comma]=true; /* write的后跟符号为)or,*/expressiondo(nxtlev,ptx,lev);/* 调用表达式处理,此处与read不同,read 为给变量赋值*/gendo(opr,0,14);/* 生成输出指令,输出栈顶的值*/}while(sym==comma);if(sym!=rparen){error(33);/* write()应为完整表达式*/}else{getsymdo;}}gendo(opr,0,15); /* 输出换行*/}else{if(sym==callsym) /* 准备按照call语句处理*/{getsymdo;if(sym!=ident){error(14); /*call后应为标识符*/}else{i=position(id,*ptx);if(i==0){error(11); /*过程未找到*/}else{if(table[i].kind==procedur){gendo(cal,lev-table[i].level,table[i].adr); /*生成call指令*/}else{error(15); /*call后标识符应为过程*/}}getsymdo;}}else{if(sym==ifsym) /*准备按照if语句处理*/{getsymdo;memcpy(nxtlev,fsys,sizeof(bool)*symnum);nxtlev[thensym]=true;nxtlev[dosym]=true; /*后跟符号为then或do*/conditiondo(nxtlev,ptx,lev); /*调用条件处理(逻辑运算)函数*/if(sym==thensym){getsymdo;}else{error(16); /*缺少then*/}cx1=cx; /*保存当前指令地址*/gendo(jpc,0,0); /*生成条件跳转指令,跳转地址暂写0*/statementdo(fsys,ptx,lev); /*处理then后的语句*/code[cx1].a=cx; /*经statement处理后,cx为then后语句执行完的位置,它正是前面未定的跳转地址*/}else{if(sym==beginsym) /*准备按照复合语句处理*/{getsymdo;memcpy(nxtlev,fsys,sizeof(bool)*symnum);nxtlev[semicolon]=true;nxtlev[endsym]=true;/*后跟符号为分号或end*//*循环调用语句处理函数,直到下一个符号不是语句开始符号或收到end*/statementdo(nxtlev,ptx,lev);while(inset(sym,statbegsys)||sym==semicolon){if(sym==semicolon){getsymdo;}else{error(10);/*缺少分号*/}statementdo(nxtlev,ptx,lev);}if(sym==endsym){getsymdo;}else{error(17); /*缺少end或分号*/}}else{if(sym==whilesym)/*准备按照while语句处理*/{cx1=cx; /*保存判断条件超作的位置*/getsymdo;memcpy(nxtlev,fsys,sizeof(bool)*symnum);nxtlev[dosym]=true;/*后跟符号为do*/conditiondo(nxtlev,ptx,lev); /*调用条件处理*/cx2=cx; /*保存循环体的结束的下一个位置*/gendo(jpc,0,0);/*生成条件跳转,但跳出循环的地址未知*/if(sym==dosym){getsymdo;}else{error(18); /*缺少do*/}statementdo(fsys,ptx,lev); /*循环体*/gendo(jmp,0,cx1);/*回头重新判断条件*/code[cx2].a=cx; /*反填跳出循环的地址,与if类似*/}else{memset(nxtlev,0,sizeof(bool)*symnum);/*语句结束无补救集合*/testdo(fsys,nxtlev,19);/*检测语句结束的正确性*/}}}}}}}return 0;}/**表达式处理*/int expression(bool*fsys,int*ptx,int lev){enum symbol addop; /*用于保存正负号*/bool nxtlev[symnum];if(sym==plus||sym==minus) /*开头的正负号,此时当前表达式被看作一个正的或负的项*/{addop=sym; /*保存开头的正负号*/getsymdo;memcpy(nxtlev,fsys,sizeof(bool)*symnum);nxtlev[plus]=true;nxtlev[minus]=true;termdo(nxtlev,ptx,lev); /*处理项*/if(addop==minus){gendo(opr,0,1); /*如果开头为负号生成取负指令*/}}else /*此时表达式被看作项的加减*/{memcpy(nxtlev,fsys,sizeof(bool)*symnum);nxtlev[plus]=true;nxtlev[minus]=true;termdo(nxtlev,ptx,lev); /*处理项*/}while(sym==plus||sym==minus){addop=sym;getsymdo;memcpy(nxtlev,fsys,sizeof(bool)*symnum);nxtlev[plus]=true;nxtlev[minus]=true;termdo(nxtlev,ptx,lev); /*处理项*/if(addop==plus){gendo(opr,0,2); /*生成加法指令*/}else{gendo(opr,0,3); /*生成减法指令*/}}return 0;}/**项处理*/int term(bool*fsys,int *ptx,int lev){enum symbol mulop; /*用于保存乘除法符号*/ bool nxtlev[symnum];memcpy(nxtlev,fsys,sizeof(bool)*symnum) ;nxtlev[times]=true;nxtlev[slash]=true;factordo(nxtlev,ptx,lev); /*处理因子*/while(sym==times||sym==slash){mulop=sym;getsymdo;factordo(nxtlev,ptx,lev);if(mulop==times){gendo(opr,0,4); /*生成乘法指令*/}else{gendo(opr,0,5) ; /*生成除法指令*/}}return 0;}/**因子处理*/int factor(bool*fsys,int *ptx,int lev){int i;bool nxtlev[symnum];testdo(facbegsys,fsys,24); /*检测因子的开始符好号*/while(inset(sym,facbegsys)) /*循环直到不是因子开始符号*/{if(sym==ident) /*因子为常量或者变量*/{i=position(id,*ptx); /*查找名字*/if(i==0){error(11); /*标识符未声明*/}else{switch(table[i].kind){case constant: /*名字为常量*/ gendo(lit,0,table[i].val); /*直接把常量的值入栈*/break;case variable: /*名字为变量*/ gendo(lod,lev-table[i].level,table[i].adr); /*找到变量地址并将其值入栈*/break;case procedur: /*名字为过程*/ error(21); /*不能为过程*/break;}}getsymdo;}else{if(sym==number) /*因子为数*/ {if(num>amax){error(31);num=0;}gendo(lit,0,num);getsymdo;}else{if(sym==lparen) /*因子为表达式*/ {getsymdo;memcpy(nxtlev,fsys,sizeof(bool)*symnum);nxtlev[rparen]=true;expressiondo(nxtlev,ptx,lev);if(sym==rparen){getsymdo;}else{error(22); /*缺少右括号*/ }}testdo(fsys,facbegsys,23); /*银子后有非法符号*/}}}return 0;}/**条件处理*/int condition(bool* fsys, int* ptx,int lev){enum symbol relop;bool nxtlev[symnum];if(sym == oddsym) /*准备按照odd运算处理*/ {getsymdo;expressiondo(fsys,ptx,lev);gendo(opr,0,6); /*生成odd指令*/}else{memcpy(nxtlev,fsys,sizeof(bool)*symnum);nxtlev[eql]=true;nxtlev[neq]=true;nxtlev[lss]=true;nxtlev[leq]=true;nxtlev[gtr]=true;nxtlev[geq]=true;expressiondo(nxtlev,ptx,lev);if(sym!=eql&&sym!=neq&&sym!=lss&&sym!=leq&&sym!=gtr&&sym!=geq) {error(20);}else{relop=sym;getsymdo;expressiondo(fsys,ptx,lev);switch(relop){case eql:gendo(opr,0,8);break;case neq:gendo(opr,0,9);break;case lss:gendo(opr,0,10);break;case geq:gendo(opr,0,11);break;case gtr:gendo(opr,0,12);break;case leq:gendo(opr,0,13);break;}}}return 0;} /*解释程序*/ void interpret(){int p,b,t; /*指令指针,指令基址,栈顶指针*/struct instruction i; /*存放当前指令*/int s[stacksize]; /*栈*/printf("start pl0\n");t=0;b=0;p=0;s[0]=s[1]=s[2]=0;do {i=code[p]; /*读当前指令*/p++;switch(i.f){case lit: /*将a的值取到栈顶*/s[t]=i.a;t++;break;case opr: /*数字、逻辑运算*/switch(i.a){case 0:t=b;p=s[t+2];b=s[t+1];break;case 1:s[t-1]=-s[t-1];break;case 2:t--;s[t-1]=s[t-1]+s[t];break;case 3:t--;s[t-1]=s[t-1]-s[t];break;case 4:t--;s[t-1]=s[t-1]*s[t];break;case 5:t--;s[t-1]=s[t-1]/s[t];break;case 6:s[t-1]=s[t-1]%2;break;case 8:t--;s[t-1]=(s[t-1]==s[t]);break;case 9:t--;s[t-1]=(s[t-1]!=s[t]);break;case 10:t--;s[t-1]=(s[t-1]<s[t]);break;case 11:t--;s[t-1]=(s[t-1]>=s[t]);break;case 12:t--;s[t-1]=(s[t-1]>s[t]);break;case 13:t--;s[t-1]=(s[t-1]<=s[t]);break;case 14:printf("%d",s[t-1]);fprintf(fa2,"%d",s[t-1]);t--;break;case 15:printf("\n");fprintf(fa2,"\n");break;printf("?");fprintf(fa2,"?");scanf("%d",&(s[t]));fprintf(fa2,"%d\n",s[t]);t++;break;}break;case lod: /*取相对当前过程的数据基地址为a的内存的值到栈顶*/ s[t]=s[base(i.l,s,b)+i.a];t++;break;case sto: /*栈顶的值存到相对当前过程的数据基地址为a的内存*/ t--;s[base(i.l,s,b)+i.a]=s[t];break;case cal: /*调用子程序*/s[t]=base(i.l,s,b); /*将父过程基地址入栈*/s[t+1]=b; /*将本过程基地址入栈,此两项用于base函数*/s[t+2]=p; /*将当前指令指针入栈*/b=t; /*改变基地址指针值为新过程的基地址*/p=i.a; /*跳转*/break;case inte: /*分配内存*/t+=i.a;break;case jmp: /*直接跳转*/p=i.a;break;case jpc: /*条件跳转*/t--;if(s[t]==0){p=i.a;}break;}}while (p!=0);}/*通过过程基址求上1层过程的基址*/int base(int l,int * s,int b){b1=b;while(l>0){b1=s[b1];l--;}return b1;}。

相关文档
最新文档