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("该语句为赋值语句。

PL/0编译器的实现文档

PL/0编译器的实现文档

第二章PL/0编译程序的实现【课前思考】复习第1章介绍的一个高级程序设计语言编译程序的功能和实现的步骤。

编译程序就是一个语言的翻译程序,通常是把一种高级程序设计语言(称源语言)书写的程序翻译成另一种等价功能语言(称目标语言)的程序。

换句话说,编译是指把一种用源语言表示的算法转换到另一种等价的用目标语言表示的算法。

编译程序实现的必要步骤有词法、语法、语义分析和代码生成。

此外必需有符号表管理程序和出错处理程序。

本章介绍的PL/0编译程序的实现是用PASCAL语言书写的【学习目标】本章目的:以PL/0语言编译程序为实例,学习编译程序实现的基本步骤和相关技术,对编译程序的构造和实现得到一些感性认识和建立起整体概念,为后面的原理学习打下基础。

◇了解并掌握用语法图和扩充的巴科斯-瑙尔范式(EBNF)对PL/0语言的形式描述。

◇了解并掌握PL/0语言编译程序构造和实现的基本技术和步骤。

◇了解并掌握PL/0语言编译程序的目标程序在运行时数据空间的组织管理。

【学习指南】◇要求读者阅读PL/0语言编译程序文本,了解一个编译程序构造的必要步骤和实现技术。

一个编译程序的实现比较复杂,读懂一个典型的程序从设计思想到实现技术也有一定难度,特别是入门开始需要耐心。

一但读懂,不仅了解编译程序的实现方法和技术,还可学到许多编程技巧和好的编程风格。

◇阅读PL/0语言编译程序文本时,应从整体结构开始逐步细化,弄清楚每个过程的功能和实现方法及过程之间的相互关系。

◇建议用一个PL/0源程序的例子为导引作为阅读PL/0语言编译程序文本的入门,然后再逐步全面读懂。

◇通过对PL/0语言编译程序某些指定功能的扩充,加深对编译程序构造步骤和实现技术的理解,并能在实践中应用。

【难重点】重点:◇弄清源语言(PL/0)、目标语言(类pcode)与实现语言(C)这3个语言之间的关系和作用。

◇掌握用语法图和扩充的巴科斯-瑙尔范式(EBNF)对一个高级程序设计语言的形式描述。

编译原理(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编译程序及其扩展

一、题目:简单PL0编译程序及其扩展表示多行表达式的<表达式序列>文法如下:<表达式序列>-> <表达式> ↙<表达式序列> |<表达式>↙↙<表达式> -> [<变量>=] [+|-]<项>{(+|-)<项>}<项> -> <因子>{(* | /)<因子>}<因子> -> <无符号实数>|<变量>|<标准函数>‘(’<表达式>‘)’|‘(’ <表达式>‘)’<标准函数> -> sin | cos | tan | exp其中的变量无需定义且其作用域为第一次赋值处至最后。

递归下降方式设计其编译程序,生成PL/0栈式指令代码,然后解释执行。

二、编译技术,主要数据结构及算法Class:MyPL0int getch();void error(int n);int gen(string function,int lev,string a);int factor();int term();int expression();void listcode();void interpret();void GetFile();void start();void Check(int i);void run(string str);Class:Code主要数据结构:数组,栈,链表三、测试本程序的测试源程序在test.txt中:a=1+2*3-4/(2*3) //检测是否实现基本文法b=sin2+cos6+tan10 //检测是否扩展标准函数(本组没能实现exp)c=9*(3+ //检测出错纠察—缺少右括号d=x+3 //检测变量无定义e=48*+33 //检测表达式非法用于测试的源代码用户也可以自己定义四、遗留问题及思考没有解决exp的识别和计算,有待考究追加通过对书后标准程序的改造和学习,本小组加深了PL0编译程序的执行过程,了解到栈式目标代码的具体生成过程,。

编译原理课程实验指导书-PL0语言及其编译器

编译原理课程实验指导书-PL0语言及其编译器

《编译原理》课程实验指导书(Compiler Principle)目录序言 (1)一、实验安排 (2)第一阶段:编译器的词法分析 (2)第二阶段:编译器的语法分析 (2)第三阶段:编译器的代码生成 (3)二、考核方式及评定标准 (4)三、参考资料与编译器分析 (4)第一部分PL语言及其编译器 (4)1. PL语言介绍 (4)1.1 PL语言的语法图 (5)2. PL语言编译器 (8)2.1 词法分析 (9)2.2 语法分析 (9)2.3 语义分析 (11)2.4代码生成 (11)2.5 代码执行 (13)2.6 错误诊断处理 (15)2.7 符号表管理 (17)2.8其他 (18)第二部分上机实验要求 (19)第三部分PL语言编译器源程序与示例 (21)1.示例与结果表示 (21)1.1 PL语言源程序 (21)1.2 生成的代码(片段) (28)2.PL语言编译器源程序 (28)序言本《编译原理》实验,其目的是让大家动手设计和实现一个规模适中的语言的编译器,该编译器不仅涉及编译程序的各个阶段,而且也强调了编译的总体设计、各个阶段的接口安排等等。

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

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

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

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

具体操作时分成三个阶段:词法分析、语法分析及代码生成。

最后再统一组装成一个完整的PL编译器,并适当进行改进、补充。

PL0源代码(C语言版)

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语言及其编译器.

《编译原理》课程实验指导书(Compiler Principle)目录序言 (1)一、实验安排 (2)第一阶段:编译器的词法分析 (2)第二阶段:编译器的语法分析 (2)第三阶段:编译器的代码生成 (3)二、考核方式及评定标准 (4)三、参考资料与编译器分析 (4)第一部分PL语言及其编译器 (4)1. PL语言介绍 (4)1.1 PL语言的语法图 (5)2. PL语言编译器 (8)2.1 词法分析 (9)2.2 语法分析 (9)2.3 语义分析 (11)2.4代码生成 (11)2.5 代码执行 (13)2.6 错误诊断处理 (15)2.7 符号表管理 (17)2.8其他 (18)第二部分上机实验要求 (19)第三部分PL语言编译器源程序与示例 (21)1.示例与结果表示 (21)1.1 PL语言源程序 (21)1.2 生成的代码(片段) (28)2.PL语言编译器源程序 (28)序言本《编译原理》实验,其目的是让大家动手设计和实现一个规模适中的语言的编译器,该编译器不仅涉及编译程序的各个阶段,而且也强调了编译的总体设计、各个阶段的接口安排等等。

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

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

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

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

具体操作时分成三个阶段:词法分析、语法分析及代码生成。

最后再统一组装成一个完整的PL编译器,并适当进行改进、补充。

pl0词法分析器C版

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; }。

(完整word版)PL0源程序-编译原理实验代码

(完整word版)PL0源程序-编译原理实验代码

附件1 小组成员:程序清单Main.c#include<stdio.h>#include<stdlib.h>#include<string.h>void error(int n);void getsym();//void enter(enum object k,int *ptx,int lev,int *pdx);int position(char*idt,int tx);int constdeclaration(int *ptx,int lev,int *pdx);int vardeclaration(int *ptx,int lev,int *pdx);int factor(int*ptx,int lev);int term(int *ptx,int lev);int expression(int *ptx,int lev);int statement(int *ptx,int lev);int block();enum object{constant,variable,procedure};struct tab{char name[14];enum object kind;int val;int level;int adr;int size;}table[100];enum symbol{nul,ident,number,plus,minus,times,slash,oddsym,eql,neq,lss,leq,gtr,geq,lparen,r paren,comma,semicolon,period,becomes,beginsym,endsym,ifsym,thensym,whilesym,writesym,readsym,dosym,ca llsym,constsym,varsym,procsym,progsym,};enum symbol sym=nul;enum symbol mulop;enum symbol wsym[14];enum symbol ssym[256];char ch=' ';char *str;charword[14][10]={"begin","call","const","do","end","if","odd","procedure","program ","read","then","var","while","write"};//设置保留字名字int num;int lev=0;int tx=0;int k;int *mm;//=(int *)malloc(sizeof(int));char *id,sign[14];char a[14];FILE *fp1,*fp2,*fp3;void error(int n){switch(n){case 1:printf("常数说明中的\"=\"写成了\":=\"。

编译原理实验-(词法语法分析-附源代码

编译原理实验-(词法语法分析-附源代码

编译原理实验报告**************************************************************************************************************************************************************PL0语言功能简单、结构清晰、可读性强,而又具备了一般高级程序设计语言的必须部分,因而PL0语言的编译程序能充分体现一个高级语言编译程序实现的基本方法和技术。

PL/0语言文法的EBNF表示如下:<程序>::=<分程序>.<分程序> ::=[<常量说明>][<变量说明>][<过程说明>]<语句><常量说明> ::=CONST<常量定义>{,<常量定义>};<常量定义> ::=<标识符>=<无符号整数><无符号整数> ::= <数字>{<数字>}<变量说明> ::=V AR <标识符>{, <标识符>};<标识符> ::=<字母>{<字母>|<数字>}<过程说明> ::=<过程首部><分程序>{; <过程说明> };<过程首部> ::=PROCEDURE <标识符>;<语句> ::=<赋值语句>|<条件语句>|<当循环语句>|<过程调用语句>|<复合语句>|<读语句><写语句>|<空><赋值语句> ::=<标识符>:=<表达式><复合语句> ::=BEGIN <语句> {;<语句> }END<条件语句> ::= <表达式> <关系运算符> <表达式> |ODD<表达式><表达式> ::= [+|-]<项>{<加法运算符> <项>}<项> ::= <因子>{<乘法运算符> <因子>}<因子> ::= <标识符>|<无符号整数>| ‘(’<表达式>‘)’<加法运算符> ::= +|-<乘法运算符> ::= *|/<关系运算符> ::= =|#|<|<=|>|>=<条件语句> ::= IF <条件> THEN <语句><过程调用语句> ::= CALL 标识符<当循环语句> ::= WHILE <条件> DO <语句><读语句> ::= READ‘(’<标识符>{,<标识符>}‘)’<写语句> ::= WRITE‘(’<表达式>{,<表达式>}‘)’<字母> ::= a|b|…|X|Y|Z<数字> ::= 0|1|…|8|9【预处理】对于一个pl0文法首先应该进行一定的预处理,提取左公因式,消除左递归(直接或间接),接着就可以根据所得的文法进行编写代码。

编译原理PL0报告(附源码教程)

编译原理PL0报告(附源码教程)

编译原理课程设计学院计算机学院专业计算机科学与技术班级学号姓名指导教师20 年月日一、课程设计要求基本内容(成绩范围:“中”、“及格”或“不及格”)(1)扩充赋值运算:*= 和/=扩充语句(Pascal的FOR语句):①FOR <变量>:=<表达式> TO <表达式> DO <语句>②FOR <变量>:=<表达式> DOWNTO <表达式> DO <语句>其中,语句①的循环变量的步长为2,语句②的循环变量的步长为-2。

(3)增加运算:++ 和--。

选做内容(成绩评定范围扩大到:“优”和“良”)(1)增加类型:①字符类型;②实数类型。

(2)扩充函数:①有返回值和返回语句;②有参数函数。

(3)增加一维数组类型(可增加指令)。

(4)其他典型语言设施。

二、概述目标:实现PL0某些特定语句实现语言:C语言实现工具平台:VS201运行平台:WIN7三、结构设计说明与功能块描述PL/0编译程序的结构图PL/0编译程序的总体流程图四、主要成分描述1、符号表编译程序里用了一个枚举类型enum symbol,然后定义了enum symbol sym来存放当前的符号,前面讲过,主程序定义了一个以字符为元素的一维数组word,称保留字表,这个保留字表也存放在符号表里,为了识别当前的符号是属于哪些保留字;还有标识符,拼数,拼符合词等的符号名都存放在符号表里,当sym存放当前的符号时,我们可以判断它是属于哪类的符号,然后加以处理。

在运行的过程中,主程序中又定义了一个名字表,也就是符号表,来专门存放变量、常量和过程名的各个属性,里面的属性包括name,kind,val/level,adr,size,我们来举一个PL/0语言过程说明部分的片段:Const a=35,b=49;Var c,d,e;Procedure p;Var g;当遇到标识符的引用时就调用position函数,根据当前sym的符号类型来查table表,看是否有过正确的定义,若已有,则从表中取相应的有关信息,供代码的生成用。

实验一PL0编译程序

实验一PL0编译程序

实验一PL0编译程序编译原理上机实验一1.软件准备(1)、pl/0编译程序:pl0 .exe(2)、pl/0编译程序源代码程序(PASCAL程序):pl0.pas(或pl0pl0.pas)(3)、pl/0程序实例(文本文件):text.pl0, text1.pl0, test2.pl0, … text9.pl0共10个例子2.实验要求:(1)阅读pl/0源程序实例(text.pl0,test1.pl0,………text9.pl0共10个例子)理解每个PL0程序的功能;熟悉并掌握pl/0语言相关规则。

(2)用pl/0编译程序,对提供的10个例子逐一进行编译并运行。

熟悉pl/0编译程序使用操作方法。

通过理解每个实例程序的功能,编程思想,进一步理解PL/0语言的语法及其语义;提高阅读程序的能力,应用程序设计语言的编程能力;增强程序语言语法、语义意识。

(3)用pl/0语言编写以下程序,进一步熟悉PL/0语言:a、由三角形的三条边长计算三角形面积。

b、编写一个PL0过程,计算以a为直径的圆的面积。

用主程序确定圆的直径,输出计算结果。

c、编写递归程序,计算n!。

d、计算1000之内的所有素数,并输出结果。

求出1000之内所有素数之和。

(要求编写3个以上的pl/0过程实现)3.文件(软件)使用说明(1)、打开文件目录“PL0编译…”,运行PL/0编译程序(pl0.exe),按提示要求输入PL0源程序文件名(如test1.pl0),┉(2)、打开Fa2.txt文件,可看到当前经过编译并运行后的pl/0程序的目标代码及其执行结果。

(3)、打开out1.txt或out2.txt、┉或out9.txt文件,可看到各个pl/0程序实例的编译、运行、操作过程结果。

4.提交实验报告及要求(1)、简述test4.pl0 …test7.pl0各程序语法含义,执行结果。

(2)、提交实验要求编写的4个PL/0源程序及其执行结果。

(3)、简写本次实验的收获与体会。

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

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

#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))
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
int num;
char str[81];
int slen;
/*alfa word[norw + 1];*/
int cx;
int lev;
int dx;
BOOL labeled;
int nl; /* as namelist[-1] */
int namelist[lmax];
int ix, tx; /* indices in tables */
casesym, repeatsym, untilsym, forsym, tosym, downtosym,
notsym, divsym, modsym, andsym, orsym, constsym, varsym,
typesym, arraysym, ofsym, recordsym, progsym, funcsym,
symbol search()
{
int i;
for(i = norw; i >= 1; i--)
{
if(strcmp(id, word[i].name) == 0)
return word[i].lex;
}
return ident;
}
void error(int n)
else
sym = gtr;
}
else if(ch == ''<'')
{
getch();
if(ch == ''='')
{
getch();
sym = leq;
}
else if(ch == ''>'')
{
getch();
}
else if(ch == ''\'''')
{
slen = 0;
strend = FALSE;
sym = sstring;
do{
if(cc == ll)
error(101);
这是我编译原理课程的课程设计时写的,对PL0文法进行了扩充,主要增加了数组及结构体的功能,并用C语言实现了之。可能有人需要,就在这贴出来了。
#include "stdio.h"
#include "string.h"
#include "stdlib.h"
#include "ctype.h"
leqi, gtri, geqi, dupl, swap, andb, orb,
load, stor, hhalt, wri, wrc, wrl, rdi, rdc, rdl, eol,
ldc, ldla, ldl, ldg, stl, stg, move, copy, addc, mulc,
}; /*函数类型的属性*/
};
}ITAB;
ITAB itab[imax + 1];
/* type table */
typedef struct TTAB{
int size;
tpkind kind;
union{
struct{
int low;
int high;
exit(1);
}
void getch()
{
if (cc == ll)
{
memset(line, 0, 129);
if(feof(source))
{
fprintf(stderr, "program incomplete\n");
exit(0);
}
/* identifier table */
typedef struct ITAB{
alfa name;
int link;
int tip;
idkind kind;
union{
int val; /*常量类型的值*/
struct{
int vlevel;
int vadr;
{
num = 0;
sym = number;
do{
num = 10 * num + (ch - ''0'');
getch();
}while(isdigit(ch));
}
else if(ch == '':'')
{
getch();
if(ch == ''='')
#define freadln 8
#define feoln 9
/* standard types */
#define intip 1
#define booltip 2
#define chartip 3
/*指令码*/
typedef enum opcode{
add, neg, mul, divd, remd, div2, rem2, eqli, neqi, lssi,
}tpkind;
typedef char alfa[al+1];
instr code[cxmax + 1];
int m[amax + 1];
/*词法分析相关全局变量*/
char ch;
int cc = 0, ll = 0;
char line[129];
symbol sym;
alfa id;
/* standard function */
#define fabs 0
#define fsqr 1
#define fodd 2
#define fchr 3
#define ford 4
#define fwrite 5
#define fwriteln 6
#define fread 7
{ "", -1 },
{ "begin", beginsym },
{ "end", endsym },
{ "if", ifsym },
{ "then", thensym },
{ "else", elsesym },
{ "while", whilesym },
{ "do", dosym },
{
memset(id, 0, al+1);
k = 0;
do{
if(k != al)
{
id[k] = ch;
k++;
}
getch();
}while(isalnum(ch));
sym = search();
}
else if(isdigitfor(i = 0; i < ll; i++)
putchar(line[i]);
for(i = 0; i <= cc - 1; i++)
putchar('' '');
printf("^\n");
printf("error %d detected\n", n);
ll = 0;
cc = 0;
while(!feof(source) && (ch = getc(source)) != ''\n'')
{
line[ll] = ch;
ll++;
}
if(ch == ''\n'')
{
line[ll] = ch;
#define tmax 100 /* length of type table */
#define lmax 10 /* maximum level */
#define al 10 /* length of identifiers */
#define norw 27 /* number of reserverd words */
BOOL refpar;
}; /*变量类型的属性*/
int offset; /*域类型的偏移地址*/
struct{
int flevel;
int fadr;
int lastpar;
int resultadr;
BOOL inside;
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
typedef int BOOL;
#define cxmax 2000
#define amax 16383
#define imax 100 /* length of identifier table */
ll++;
}
}
ch = line[cc];
cc++;
}
void getsym()
{
int k;
int strend;
while(ch == '' '' || ch == ''\t'' || ch == ''\n'')
相关文档
最新文档