恰好上当编译原理了

就把课后的打了一下

希望对各位有帮助QwQ

pl0.h

#ifndef PL0_H_INCLUDED
#define PL0_H_INCLUDED
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,levmax]*/
#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);#endif // PL0_H_INCLUDED

main.c

/* 编译和运行环境:* 1 Visual C++ 6.0,Visual C++.NET and Visual C++.NET 2003*   WinNT,Win2000,WinXP and Win2003* 2 gcc version 3.32 20031022(Red Hat Linux 3.3.2-1)*   Redhat Fedora core 1*   Intel 32 platform* 使用方法:* 运行后输入PL/0源程序文件名* 回答是否输出虚拟机代码* 回答是否输出名字表* fa.tmp 输出虚拟机代码* fa1.tmp 输出源文件及其各行对应的首地址* fa2.tmp 输出结果* fas.tmp 输出名字表*/#include <stdio.h>
#include "pl0.h"
#include "string.h"
#include <stdlib.h>
/* 解释执行时使用的栈 */
#define stacksize 500
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("fa1.tmp","w");fprintf(fa1,"Input 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;/* 设置单字符符号 */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[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);fprintf(fa1,"****%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)                                   /* 忽略空格、换行和TAB */{getchdo;}if(ch>='a'&&ch<='z'){                                                               /* 名字或保留字以a..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'){                                                           /* 检测是否为数字:以0..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;}}}}}}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{constdeclaration(&tx,lev,&dx);                          /* dx的值会被constdeclaration改变,使用指针 */while(sym==comma){getsymdo;constdeclaration(&tx,lev,&dx);}if(sym==semicolon){getsymdo;}else{error(5);                                           /* 漏掉了逗号或者分号 */}}while(sym==ident);}if(sym==varsym)                                                 /* 收到变量声明符号,开始处理变量声明 */{getsymdo;do{vardeclaration(&tx,lev,&dx);while(sym==comma){getsymdo;vardeclaration(&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);                                               /* [rpcedire后应为标识符 */}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,"val=%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 addr=%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);                                   /* 分段程序没有补救集合 */testdo(fsys,nxtlev,8);                                                  /* 检测后跟符号正确性 */listcode(cx0);                                                          /* 输出代码 */return 0;
}
/**在名字表中加入一项** k:名字种类const,var or procedure* ptx:名字表尾指针的指针,为了可以改变名字表尾指针的值* lev:名字所在的层次,以后所有的lev都是这样* pdx:dx为当前应分配的变量的相对地址,分配后要增加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=(*ptx);(*ptx)++;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);                                                      /* var后应是标识 */}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){                                                       /* expression将执行一系列指令,但最终结果将会保存在栈顶,执行sto命令完成赋值 */gendo(sto,lev-table[i].level,table[i].adr);}}}//if(i==0)}else{if(sym==readsym)                                                /* 准备按照read语句处理 */{getsymdo;if(sym!=lparen){error(34);                                              /* 格式错误,应是左括号 */}else{do{getsymdo;if(sym==ident){i=position(id,*ptx);                            /* 查找要读的变量 */}else{i=0;}if(i==0){error(35);                                      /* read()中应是声明过的变量名 */}else{gendo(opr,0,16);                                /* 生成输入指令,读取值到栈顶 */gendo(sto,lev-table[i].level,table[i].adr);}getsymdo;}while(sym==comma);}if(sym!=rparen){error(33);while(!inset(sym,fsys)){getsymdo;}}else{getsymdo;}}else{if(sym==writesym){getsymdo;if(sym==lparen){do{getsymdo;memcpy(nxtlev,fsys,sizeof(bool)*symnum);nxtlev[rparen]=true;nxtlev[comma]=true;expression(nxtlev,ptx,lev);gendo(opr,0,14);}while(sym==comma);if(sym!=rparen){error(33);}else{getsymdo;}}gendo(opr,0,15);}else{if(sym==callsym){getsymdo;if(sym!=ident){error(14);}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);}else{error(15);}}getsymdo;}}else{if(sym==ifsym){getsymdo;memcpy(nxtlev,fsys,sizeof(bool)*symnum);nxtlev[thensym]=true;nxtlev[dosym]=true;condition(nxtlev,ptx,lev);if(sym==thensym){getsymdo;}else{error(16);}cx1=cx;gendo(jpc,0,0);statementdo(fsys,ptx,lev);code[cx1].a=cx;}else{if(sym==beginsym){getsymdo;memcpy(nxtlev,fsys,sizeof(bool)*symnum);nxtlev[semicolon]=true;nxtlev[endsym]=true;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);}}else{if(sym==whilesym){cx1=cx;getsymdo;memcpy(nxtlev,fsys,sizeof(bool)*symnum);nxtlev[dosym]=true;conditiondo(nxtlev,ptx,lev);cx2=cx;gendo(jpc,0,0);if(sym==dosym){getsymdo;}else{error(18);}statementdo(fsys,ptx,lev);gendo(jmp,0,cx1);code[cx2].a=cx;}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){getsymdo;expressiondo(fsys,ptx,lev);gendo(opr,0,6);}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: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;case 16:printf("?");fprintf(fa2,"?");scanf("%d",&(s[t]));fprintf(fa2,"%d\n",s[t]);t++;break;}break;case lod:s[t]=s[base(i.l,s,b)+i.a];t++;break;case sto: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;s[t+1]=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);
}
/* 通过过程基址求上一层过程的基址 */
int base(int l,int* s,int b)
{int b1;b1=b;while(l>0){b1=s[b1];l--;}return b1;
}

编译原理(第二版)张素琴 课后代码 A.2 C版本相关推荐

  1. 【编译原理】《编译原理第二版》LR0例题代码

    以下是本人关于<编译原理第二版>里LR0例题的理解以及代码实现: /*广西师范大学 计算机科学与工程学院 GuangXi Normal University College of Comp ...

  2. 编译原理第二版6.2答案

    6.2 节的练习 6.2.1 将算数表达式 a±(b+c) 翻译成 抽象语法树 四元式序列 三元式序列 间接三元式序列 解答 抽象语法树 四元式序列 op arg1 arg2 result 0 + b ...

  3. 计算机网络(第二版)--清华大学出版社课后习题答案

    计算机网络(第二版)清华大学出版社课后习题答案 第一章 1.计算机网络的发展可以划分为几个阶段?每个阶段各有什么特点? 答:可以划分为四个阶段: 第一阶段:20世纪50年代-------面向终端 计算 ...

  4. 《Android移动应用基础教程》(Android Studio)(第二版)黑马教程 课后题答案 第7章

    <Android移动应用基础教程>(Android Studio)(第二版)黑马教程 课后题答案 第7章 一.判断题 1.对 2.对 3.对 4.错 5.对 二.选择题 1.C 2.B 3 ...

  5. 《Android移动应用基础教程》(Android Studio)(第二版)黑马教程 课后题答案第一章

    <Android移动应用基础教程>(Android Studio)(第二版)黑马教程 课后题答案 第一章 一.填空题 1.dex 2.@color 3.AndroidManifest.xm ...

  6. 计算机科学与技术第二章ppt,计算机科学与技术-编译原理-第二章重点.ppt

    计算机科学与技术-编译原理-第二章重点.ppt * 自下而上分析法举例 例2解: a b b c d e (1) a b b c d e A A (2) a b b c d e A A (3) a b ...

  7. 数据结构(C语言)第二版 第四章课后答案

    数据结构(C语言)第二版 第四章课后答案 1~5 B B C A B 6~10 B B C B B 11~15 A B D (C,B) C 1.选择题 (1)串是一种特殊的线性表,其特殊性体现在(B) ...

  8. 编译原理——C++版桌面计算器

    编译原理--C++版桌面计算器 系统描述 设计并实现一个桌面计算器,支持基本四则运算,关系运算,可编程运算 基本功能 (1)以命令行方式解析用户输入的表达式,计算并显示结果: (2)支持基本的整型和浮 ...

  9. 数据结构(C语言)第二版 第三章课后答案

    数据结构(C语言)第二版 第三章课后答案 1~5 C C D A A 6~10 D A B C D 11~15 D D B C B 1.选择题 (1)若让元素1, 2, 3 , 4, 5 依次进栈,则 ...

最新文章

  1. “不会Linux,怎么当程序员?”骨灰级程序员:干啥都不行。
  2. 数据中心冷却技术在企业持续发展中的应用
  3. linux 修改用户组_linux小白到大神的成长之路:linux系统用户组的管理!
  4. java线程如何避免死锁_Java面试问题,如何避免Java线程中的死锁?
  5. for循环和while循环
  6. Python模拟大整数乘法的小学竖式计算过程
  7. 两个实际任务掌握图像分类【Keras】(转)
  8. 排序算法的总结与使用题型
  9. 嵌入式ctags跳转和全局打印日志
  10. MarkDown的下载、安装和基础使用
  11. SEO网站优化步骤超详细完整版教程
  12. 信息系统项目管理师 - 项目沟通管理
  13. win10桌面快捷方式变白,解决方式
  14. 注意力机制如何助力GAN生成更高质量的图像?
  15. [luoguT30208]太极剑
  16. 文件上传和OSS上传至阿里云
  17. 计算机系统与配置要求,电脑系统以及Adobe Audition的版本配置要求-喜马拉雅
  18. element--icon图标
  19. nginx安装部署和配置管理
  20. 给你一碗孟婆汤,你会选择遗忘什么?

热门文章

  1. 数学分析:集合的基本运算
  2. Flash:快速导出png(jsfl)
  3. 畅销图书排行榜TOP10(2009上半年)
  4. php 搜索字符串ctrl f_js搜索关键字(Ctrl + F)
  5. 天大《西方经济学》大作业期末考核
  6. 转盘and狼人杀源码
  7. 计算机主机配置一般有机箱主板cpu,1500元电脑主机配置有哪些 1500电脑主机配置推荐【图文】...
  8. SCAU 1028 求素数
  9. 和Leo一起做爱线段树的好孩子之火车运输
  10. getchar ,putchar,gets,puts的辨析