📄 compiler.cpp
字号:
#include <string.h>
#include <string>
#include <iostream>
#include <conio.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
using namespace std;
//定义一些常量
#define NORW 13 //保留字的个数
#define TXMAX 100 //标识符表的长度
#define NMAX 14 //数字允许的最长位数
#define AL 10 //标识符最长长度
#define AMAX 2047 //寻址空间
#define LEVMAX 3 //最大允许的块嵌套层数
#define CXMAX 200 //目标代码数组的大小
#define STACKSIZE 500//栈的深度
/*char *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"
}; //程序中用到的标识
/*typedef enum{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
} symbol;*/
//typedef set<symbol> symset;
enum object{constant,variable,procedur}; //object 为三种标识符的类型
enum object kind;
char *word[NORW]={"begin","call","const","do","end","if","odd","procedure",
"read","then","var","while","write"
};//pascal源程序关键字(保留字)
char *wsym[NORW]={"beginsym","callsym","constsym","dosym","endsym","ifsym",
"oddsym","procsym","readsym","thensym","varsym","whilesym","writesym"
}; //中间代码关键字,与保留字相对应
FILE *fa; //文件fa用于列出源程序
FILE *fa1,*fa2; //文件fa1用于列出类PCODE代码,fa2用于记录解释执行类PCODE代码的过程
char ch; //主要用于词法分析器,存放最近一次从文件读出的字符
//symbol sym; //词法分析器输出结果之用,存放最近一次识别出来的token的类型
char sym[10];
char id[AL]; //词法分析器输出结果之用,存放最近一次识别出来的标识符的名字
char line[81]; //行缓冲区,用于从文件读出一行,供词法分析获取单词时之用
char a[AL]; //词法分析器中用于临时存放正在分析的词
enum fct{lit,opr,lod,sto,cal,ini,jmp,jpc}; //类PCODE的各条指令
struct instruction{ //生成代码的格式
enum fct f; //操作码
int l; //层次值
int a; //地址
};
struct instruction code[CXMAX+1]; //生成的类PCODE代码表,存放编译得到的类PCODE代码
bool listswitch; //如果值为true,程序编译后将为列出类PCODE代码
//否则不列出类PCODE代码
int num; //存放最近一次识别出来的数字的值
int cc; //字符计数(character count)
int ll; //行缓冲长度(line length)
int kk=AL; //预计要读的单词的长度
int cx=0; //代码分配指针,代码生成模块总在cx所指位置生成新的代码
int codeNo=0;//代码所在的行号
//vector<string> errorString;
int linecnt=0;
int lev=0;//层次数
int tx=0; //table指针
int dx=0; //在栈中相对的位置
char *mnemonic[8]={"lit","opr","lod","sto","cal","ing","jmp","jpc"};//类PCODE指令助记符表
struct table{ //符号表
char name[AL]; //符号的名字
enum object kind; //符号的类型
int val; //val中放常量的值
int level,adr,size;//存放层差,偏移地址和大小
};
struct table table1[TXMAX+1];
FILE *fin,*fout; //fin文件用于指向输入的源程序文件 fout用于指向输出的源程序文件
char fname[AL]; //存放PL/0源文件的文件名
int err; //出错总次数
struct node{ //单词表
char *pa[32];
};
struct node *declbegsys; //声明开始
struct node *statbegsys; //表达式开始
struct node *facbegsys; //因子开始
struct node *tempsetsys; //项开始符号
string errStr[]={" ",
"error 0001: 常数说明中=写成:=",
"error 0002: 常数说明中的“=”后应为数字",
"error 0003: 常数说明中的标识符后应是“=”",
"error 0004: const,var,procedure后应为标识符",
"error 0005: 漏掉了‘,’或‘;’",
"error 0006: 过程说明后的符号不正确(应是语句开始符或过程开始符)",
"error 0007: 应是语句开始符",
"error 0008: 过程体内语句部分的后继符不正确",
"error 0009: 程序没有以‘.’结尾",
"error 0010: 语句之间漏了‘;’",
"error 0011: 标识符没说明",
"error 0012: 赋值语句中,赋值号左部标识符属性应是变量",
"error 0013: 赋值语句左部标识符应是赋值号:=",
"error 0014: call后应为标识符",
"error 0015: call后标识符属性应为过程",
"error 0016: 条件语句中丢了then",
"error 0017: 复合语句丢了end或;",
"error 0018: while型循环语句中丢了do",
"error 0019: 语句后的标识符不正确",
"error 0020: 表达式中有非法关系运算符",
"error 0021: 表达式内标识符属性不能是过程",
"error 0022: 表达式中漏掉了右括号‘)’",
"error 0023: 因子不能以此符号结束",
"error 0024: 表达式开始符不能是此符号",
"error 0025: ","error 0026: ",
"error 0027: ","error 0028: ","error 0029: ",
"error 0030: 常数越界",
"error 0031: 表达式内常数越界",
"error 0032: 嵌套深度超过允许值",
"error 0033: read 或 write 语句中缺右括号"
"error 0034: read或write语句中标识符未说明"};
//输出错误信息(错误类型代码)并记录总错误数
/*void error(int n)
{
int i;
printf("***");
fputs("***",fa1);
for(i=0;i<cc;i++)
{
printf("*");
}
for(i=0;i<cc;i++)
{
fputs("*",fa1);
}
printf("\nerror: %d\t",n);
fprintf(fa1,"\nerror: %d\t",n);
switch(n)
{
case 1:
printf("常量说明中的'='写成了':='!\n");
fprintf(fa1,"常量说明中的'='写成了':='!\n");
break;
case 2:
printf("常量说明中的'='之后不是数字!\n");
fprintf(fa1,"常量说明中的'='之后不是数字!\n");
break;
case 3:
printf("常量说明中的标识符的后继符号不是'='!\n");
fprintf(fa1,"常量说明中的标识符的后继符号不是'='!\n");
break;
case 4:
printf("CONST、VAR、PROCEDURE的后继符号不是标识符!\n");
fprintf(fa1,"CONST、VAR、PROCEDURE的后继符号不是标识符!\n");
break;
case 5:
printf("漏了','或';'!\n");
fprintf(fa1,"漏了','或';'!\n");
break;
case 6:
printf("过程说明结束符;的后继符号既不是语句开始符也不是其它说明符(PROCEDURE)!\n");
fprintf(fa1,"过程说明结束符;的后继符号既不是语句开始符也不是其它说明符(PROCEDURE)!\n");
break;
case 7:
printf("过程说明结束符;的后继符号既不是语句开始符也不是其它说明符!\n");
fprintf(fa1,"过程说明结束符;的后继符号既不是语句开始符也不是其它说明符!\n");
break;
case 8:
printf("程序体内语句部分的后继符号不正确!\n");
fprintf(fa1,"程序体内语句部分的后继符号不正确!\n");
break;
case 9:
printf("程序没有以'.'结尾!\n");
fprintf(fa1,"程序没有以'.'结尾!\n");
break;
case 10:
printf("语句之间缺';'!\n");
fprintf(fa1,"语句之间缺';'!\n");
break;
case 11:
printf("标识符未说明!\n");
fprintf(fa1,"标识符未说明!\n");
break;
case 12:
printf("赋值号左部标识符的属性不是变量!\n");
fprintf(fa1,"赋值号左部标识符的属性不是变量!\n");
break;
case 13:
printf("赋值号左部标识符的后继符号不是':='!\n");
fprintf(fa1,"赋值号左部标识符的后继符号不是':='!\n");
break;
case 14:
printf("CALL后继符号不是标识符!\n");
fprintf(fa1,"CALL后继符号不是标识符!\n");
break;
case 15:
printf("CALL后继标识符的属性不是过程!\n");
fprintf(fa1,"CALL后继标识符的属性不是过程!\n");
break;
case 16:
printf("条件语句缺'THEN'!\n");
fprintf(fa1,"条件语句缺'THEN'!\n");
break;
case 17:
printf("复合语句缺'END'!\n");
fprintf(fa1,"复合语句缺'END'!\n");
break;
case 18:
printf("WHILE型循环语句缺'DO'!\n");
fprintf(fa1,"WHILE型循环语句缺'DO'!\n");
break;
case 19:
printf("语句的后继符号不正确!\n");
fprintf(fa1,"语句的后继符号不正确!\n");
break;
case 20:
printf("布尔表达式中有非法关系运算符!\n");
fprintf(fa1,"布尔表达式中有非法关系运算符!\n");
break;
case 21:
printf("表达式内不能有过程标识符!\n");
fprintf(fa1,"表达式内不能有过程标识符!\n");
break;
case 22:
printf("因子中缺匹配的')'!\n");
fprintf(fa1,"因子中缺匹配的')'!\n");
break;
case 23:
printf("因子不能以此符号结束!\n");
fprintf(fa1,"因子不能以此符号结束!\n");
break;
case 24:
printf("因子不能以此符号开始!\n");
fprintf(fa1,"因子不能以此符号开始!\n");
break;
case 30:
printf("常数越界!\n");
fprintf(fa1,"常数越界!\n");
break;
case 31:
printf("表达式内常数越界!\n");
fprintf(fa1,"表达式内常数越界!\n");
break;
case 32:
printf("嵌套深度超过允许值!\n");
fprintf(fa1,"嵌套深度超过允许值!\n");
break;
case 33:
printf("READ或WRITE语句中缺')'!\n");
fprintf(fa1,"READ或WRITE语句中缺')'!\n");
break;
case 34:
printf("READ或WRITE语句中缺'('!\n");
fprintf(fa1,"READ或WRITE语句中缺'('!\n");
break;
case 35:
printf("READ语句中标识符未说明!\n");
fprintf(fa1,"READ语句中标识符未说明!\n");
break;
default:
printf("未处理的异常!\n");
fprintf(fa1,"未处理的异常!\n");
break;
}
err=err+1;
}
*/
void error(int n) //错误处理
{
int i=n;
string errString=errStr[i];
//cout<<"****第"<<codeNo<<"行出现错误";
//cout<<":"<<errStr[i]<<"******";
cout<<"****** "<<errString<<" ******"<<endl;
err= err+1; //错误数加一
}//error end
void getCh() //读取字符
{
if(cc == ll+1) //如果行缓冲区指针指向行缓冲区最后一个字符就从文件读一行到行缓冲区
{
if(feof(fin)) //如果到达文件末尾
{
cout<<"程序代码没有结束!"<<endl;
exit(0);
}
ll=0; //行缓冲区长度置0
cc=0; //行缓冲区指针置行首
// while(!feof(fin))
while(feof(fin)==false&&(ch=fgetc(fin))!='\n'&&ch!=-1)//尚未结束,将一行记录输出打印
{
putchar(ch);
fputc(ch,fa1);
line[ll++]=ch;
}
/*codeNo++;
line[ll]=ch;
cout<<endl;
fprintf(fa1,"\n");*/
line[ll]=ch;
cout<<endl;
//line[ll]=ch;
fprintf(fa1,"\n");
}
ch=line[cc++];//行缓冲区指针加一,读出字符,放入全局变量ch
if(ch>='A'&&ch<='Z')
{
ch=ch+32;
}
} //getCh end
void getsym()
{
int i,j,k;
while(ch==' '||ch=='\t'||ch=='\n')
{
getCh();//读字符
}
if(ch>='a'&&ch<='z')
{
k=0; //标识符缓冲区指针置0
do{
if(k<AL)
{
a[k]=ch;
k++;
}
getCh();
}while((ch>='a'&&ch<='z')||(ch>=0&&ch<=9));
//直到读出的不是字母或数字--标识符由字字母开头,后面跟若干个字母或数字
if(k>=kk)
{
kk=k; //如果当前获得的标识符长度大于或等于kk,令kk为当前标识符长度
}
else
{
/* while(k<kk)
{
a[kk]=' ';//该循环把标识符缓冲后部没有填入相应字母或空格的空间用空格补足
kk--;
}*/
if(k<kk-1)
a[k++]='\0';
}
//下面开始二分法查找看读出的标识符是不是保留字之一
strcpy(id,a); //最后读出标识符a拷贝到id中
i=0; //i指向第一个保留字
j=NORW-1; //j指向最后一个保留字
do
{
k=(i+j)/2; //k指向中间一个保留字
if((strcmp(id,word[k]))<=0)//如果当前的标识符小于k所指的保留字
j=k-1; //移动指针j
if((strcmp(id,word[k]))>=0)//如果当前的标识符大于k所指的保留字
i=k+1; //移动指针i
}while(i<=j);
if(i-1>j)//表明在保留字表中找到相应的项,id中存的是保留字
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -