📄 unit1.~cpp
字号:
/*** PL0 COMPILER WITH CODE GENERATION ***/
//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
int COD=1;//0为词法分析
int choice=1;//0为IF未改
const AL = 10; /*标示符的长度为10*/
const NORW = 19; /*保留字的个数为19*/
const TXMAX = 100; /* 标示符表的最大长度为100*/
const NMAX = 14; /* 数字最大位数为14*/
const AMAX =2047; /* 最大寻址为2047*/
const LEVMAX= 3; /* 嵌套最大层数为3*/
const CXMAX = 200; /* 代码数组最大为200*/
const NumOfSybol=43;//定义关键保留字43个
typedef int *ERRORPOINT;
typedef enum { NUL, IDENT, NUMBER, PLUS, MINUS, TIMES,
SLASH, ODDSYM, EQL, NEQ, LSS, LEQ, GTR, GEQ,
LPAREN, RPAREN,
QUOT,//单引号
COMMA, SEMICOLON, PERIOD,
BECOMES,
PLUSBECOMES,//+=
MINUSBECOMES,//-=
DOUBLEPLUS, //++
DOUBLEMINUS, //--
BEGINSYM, ENDSYM, IFSYM, THENSYM,
WHILESYM, WRITESYM, READSYM, DOSYM, CALLSYM,
CONSTSYM, VARSYM, PROCSYM, PROGSYM,CHARSYM,//字符类型
ELSESYM,//在此加了ELSE
FORSYM, //加了FOR
TOSYM, //加了TO
DOWNTOSYM //加了DOWMTO
} SYMBOL; /*词汇表,其中控制程序结构的保留字14个*/
char *SYMOUT[] = {"NUL", "IDENT", "NUMBER", "PLUS", "MINUS", "TIMES",
"SLASH", "ODDSYM", "EQL", "NEQ", "LSS", "LEQ", "GTR", "GEQ",
"LPAREN", "RPAREN",
"QUOT",//单引号
"COMMA", "SEMICOLON", "PERIOD",
"BECOMES",
"PLUSBECOMES", //+=
"MINUSBECOMES", //-=
"DOUBLEPLUS", //++
"DOUBLEMINUS", //--
"BEGINSYM", "ENDSYM", "IFSYM", "THENSYM",
"WHILESYM", "WRITESYM", "READSYM", "DOSYM", "CALLSYM",
"CONSTSYM", "VARSYM", "PROCSYM", "PROGSYM", "CHARSYM", //字符类型
"ELSESYM", //在此加了ELSE
"FORSYM",//加了FOR
"TOSYM",//加了TO
"DOWNTOSYM"//加了DOWMTO
};
typedef int *SYMSET; //字符集;
typedef char ALFA[11];
typedef enum { CONSTANT, VARIABLE, PROCEDUR,CHARACTOR } OBJECTS ;
typedef enum { LIT, OPR, LOD, STO, CAL, INI, JMP, JPC } FCT;
typedef struct {
FCT F; /*函数命令*/
int L; /*0..LEVMAX LEVEL*/
int A; /*0..AMAX DISPLACEMENT ADDR*/
} INSTRUCTION;
/*
LIT 0 A 将常数值取到栈顶,A为常数值
LOD L A 将变量值取到栈顶,A为偏移量,L为层差
STO L A 将栈顶内容送入某一变量单元中,A为偏移量,L为层差
CAL L A 调用过程,A为过程地址,L为层差
INT 0 A 在运行栈中为被调用的过程开辟A个单元的数据区
JMP 0 A 无条件跳转到A地址
JPC 0 A 条件跳转,当栈顶布尔值非真则跳转到A地址,否则顺序执行
OPR 0 0 过程调用结束后,返回调用点并退栈
OPR 0 1 栈顶元素取反
OPR 0 2 次栈顶与栈顶相加,退两个栈元素,结果值进栈
OPR 0 3 次栈顶减去栈顶,退两个栈元素,结果值进栈
OPR 0 4 次栈顶乘以栈顶,退两个栈元素,结果值进栈
OPR 0 5 次栈顶除以栈顶,退两个栈元素,结果值进栈
OPR 0 6 栈顶元素的奇偶判断,结果值在栈顶
OPR 0 7
OPR 0 8 次栈顶与栈顶是否相等,退两上栈元素,结果值进栈
OPR 0 9 次栈顶与栈顶是否不等,退两个栈元素,结果值进栈
OPR 0 10 次栈顶是否小于栈顶,退两个栈元素,结果值进栈
OPR 0 11 次栈顶是否大于等于栈顶,退两个栈元素,结果值进栈
OPR 0 12 次栈顶是否大于栈顶,退两个栈元素,结果值进栈
OPR 0 13 次栈顶是否小于等于栈顶,退两个栈元素,结果值进栈
OPR 0 14 栈顶值输出到屏幕
OPR 0 15 屏幕输出换行
OPR 0 16 从命令行读入一个输入置于栈顶
*/
char CH; /*最近读进的字符*/
SYMBOL SYM; /*存放每个单词的类别,用内部编码形式表示*/
ALFA ID; /*存放用户所定义的标识符的值,即字符串的机内表示*/
int NUM; /*用户所定义的数*/
int CC; /*CHARACTER COUNT*/
int LL; /*缓冲器的长度*/
int CX; /*CODE数组的下标索引*/
char LINE[81];
INSTRUCTION CODE[CXMAX];
ALFA KWORD[NORW+1];
SYMBOL WSYM[NORW+1]; //存放保留字
SYMBOL SSYM['^'+1]; //在' '到'^'才是可用
ALFA MNEMONIC[9];
SYMSET DECLBEGSYS, STATBEGSYS, FACBEGSYS;
struct {
ALFA NAME; //名称
OBJECTS KIND; //类型
union {
int VAL; /*常量*/
struct {
int LEVEL,ADR,SIZE;
} vp; /*变量或者过程*/
};
} TABLE[TXMAX]; //即TABLE[100]
FILE *FIN,*FOUT; //输入输出文件的指针
int ERR; //错误个数统计
String ERRORKIND[34] = {"",
"常数说明中的'='写成':='", //1
"常数说明中的'='后应是数字", //2
"常数说明中的标识符后应是=号", //3
"CHAR,CONST,VAR,PROCEDURE 后应为标识符", //4
"漏掉了','或';'", //5
"过程说明后的符号不正确", //6
"应是语句开始符", //7
"程序体内语句部分的后跟符不正确", //8
"程序结尾丢了句号'.'", //9
"语句之间漏了';'", //10
"标识符未说明", //11
"赋值语句中,赋值号左部标识符属性应是变量", //12
"赋值语句左部标识符后应是赋值号':='", //13
"CALL后应为标识符", //14
"CALL后标识符属性应为过程", //15
"条件语句中丢了'THEN'或'ELSE'", //16
"丢了'END'或';'", //17
"WHILE型循环语句中丢了'DO'", //18
"语句后的符号不正确", //19
"应为关系运算符", //20
"表达式内标识符属性不能是过程", //21
"表达式中漏掉右括号')'", //22
"因子后的非法符号", //23
"表达式的开始符不能是此符号", //24
"FOR 语句后应有TO或DOWN", //25
"字符类型不符", //26
"字符类型漏了'''单引号", //27
"READ 函数内的标识符没定义", //28
"NUL", //~30
"数越界", //31
"READ语句括号中的标识符不是变量" //32
"NUL" //33
"NUL" //34
};
void EXPRESSION(SYMSET FSYS, int LEV, int &TX);
void TERM(SYMSET FSYS, int LEV, int &TX);
//---------------------------------------------------------------------------
int SymIn(SYMBOL SYM, SYMSET S1) {
return S1[SYM];
}
//---------------------------------------------------------------------------
SYMSET SymSetUnion(SYMSET S1, SYMSET S2) {
SYMSET S=(SYMSET)malloc(sizeof(int)*NumOfSybol);
for (int i=0; i<NumOfSybol; i++)
if (S1[i] || S2[i]) S[i]=1;
else S[i]=0;
return S;
}
//---------------------------------------------------------------------------
SYMSET SymSetAdd(SYMBOL SY, SYMSET S) {
SYMSET S1;
S1=(SYMSET)malloc(sizeof(int)*NumOfSybol);
for (int i=0; i<NumOfSybol; i++) S1[i]=S[i];
S1[SY]=1;
return S1;
}
//---------------------------------------------------------------------------
SYMSET SymSetNew(SYMBOL a) {
SYMSET S; int i,k;
S=(SYMSET)malloc(sizeof(int)*NumOfSybol);
for (i=0; i<NumOfSybol; i++) S[i]=0;
S[a]=1;
return S;
}
//---------------------------------------------------------------------------
SYMSET SymSetNew(SYMBOL a, SYMBOL b) {
SYMSET S; int i,k;
S=(SYMSET)malloc(sizeof(int)*NumOfSybol);
for (i=0; i<NumOfSybol; i++) S[i]=0;
S[a]=1; S[b]=1;
return S;
}
//---------------------------------------------------------------------------
SYMSET SymSetNew(SYMBOL a, SYMBOL b, SYMBOL c) {
SYMSET S; int i,k;
S=(SYMSET)malloc(sizeof(int)*NumOfSybol);
for (i=0; i<NumOfSybol; i++) S[i]=0;
S[a]=1; S[b]=1; S[c]=1;
return S;
}
//---------------------------------------------------------------------------
SYMSET SymSetNew(SYMBOL a, SYMBOL b, SYMBOL c, SYMBOL d) {
SYMSET S; int i,k;
S=(SYMSET)malloc(sizeof(int)*NumOfSybol);
for (i=0; i<NumOfSybol; i++) S[i]=0;
S[a]=1; S[b]=1; S[c]=1; S[d]=1;
return S;
}
//---------------------------------------------------------------------------
SYMSET SymSetNew(SYMBOL a, SYMBOL b, SYMBOL c, SYMBOL d,SYMBOL e) {
SYMSET S; int i,k;
S=(SYMSET)malloc(sizeof(int)*NumOfSybol);
for (i=0; i<NumOfSybol; i++) S[i]=0;
S[a]=1; S[b]=1; S[c]=1; S[d]=1; S[e]=1;
return S;
}
//---------------------------------------------------------------------------
SYMSET SymSetNew(SYMBOL a, SYMBOL b, SYMBOL c, SYMBOL d,SYMBOL e, SYMBOL f) {
SYMSET S; int i,k;
S=(SYMSET)malloc(sizeof(int)*NumOfSybol);
for (i=0; i<NumOfSybol; i++) S[i]=0;
S[a]=1; S[b]=1; S[c]=1; S[d]=1; S[e]=1; S[f]=1;
return S;
}
//---------------------------------------------------------------------------
SYMSET SymSetNULL() {
SYMSET S; int i,n,k;
S=(SYMSET)malloc(sizeof(int)*NumOfSybol);
for (i=0; i<NumOfSybol; i++) S[i]=0;
return S;
}
//---------------------------------------------------------------------------
/* 错误处理: 打印出错位置和错误编码
*/
void Error(int n) {
String s = "***"+AnsiString::StringOfChar(' ', CC-1)+"^";
s=s+n+ERRORKIND[n];
Form1->printfs(s.c_str());
// Form1->printls(s.c_str(),n);
//Form1->printls(
fprintf(FOUT,"%s%d\n", s.c_str(), n);
ERR++;
} /*Error*/
//---------------------------------------------------------------------------
void GetCh() { /*漏掉空格,读取一个字符*/
/*
CH:存放当前读取的字符,初始值为空
LINE:为一维数组,其数组元素是字符,界对为1:800.用于读入一行的缓冲区.
LL:计数器,初始值为0.
CC:计数器,初始值为0.
*/
if (CC==LL) { //缓冲区是否结束?
//是则执行下边
if (feof(FIN)) {//判断文件是否结束
Form1->printfs("PROGRAM INCOMPLETE");
fprintf(FOUT,"PROGRAM INCOMPLETE\n");
fclose(FOUT);
exit(0); //goto 199;出口
}
LL=0; CC=0;
CH=' ';
while (!feof(FIN) && CH!=10) //ASCII码 换行符
{ CH=fgetc(FIN); LINE[LL++]=CH; } //逐个放到LINE缓冲区啊
LINE[LL-1]=' '; LINE[LL]=0;
String s=IntToStr(CX);
while(s.Length()<3) s=" "+s;
s=s+" "+LINE;
Form1->printfs(s.c_str());
fprintf(FOUT,"%s\n",s);
}
CH=LINE[CC++]; //否
} /*GetCh()*/
//---------------------------------------------------------------------------
void GetSym() {/*词法分析,读取一个单词*/
/*完成的任务:
(1)滤空格:
(2)识别保留字:设有一张保留字表,对每个字母打头的字母,数字字符串要查此表
若查着则为保留字,将对应的类别放在SYM中,若查不着,则认为是用户定义的标识符
(3)识别标识符:对用户定义的标识符将IDENT放在SYM中,标识符本身的值放在ID中;
(4)拼数:当所取的单词是数字时,将数的类别NUMBER放在SYM中,数值本身的值存放的NUM中.
(5)拼复用词:对两处字符组成的算符识别后将类别送SYM中;
(6)输出源程序:为边读入字符边输出(可输出在文件中).
A:一维数组.数组元素为字符,界对[1:10],存放读进的标识符.
ID:同A.
WORD:保留字表,一维数组.数组元素是以字符为元素的一维数组.界对为[1:13].
查表方式采用二分法.
*/
int i,J,K; ALFA A; //存放读进的标识符.
while (CH<=' ') GetCh(); //滤空格并滤掉控制字符,因为' '之前的都是控制字符
if (CH>='A' && CH<='Z') { /*如果是标识符*/
K=0;
do {
if (K<AL) A[K++]=CH;
GetCh();
}while((CH>='A' && CH<='Z')||(CH>='0' && CH<='9'));
A[K]='\0';
strcpy(ID,A); //将A的内容COPY给ID
i=1; J=NORW;//NORW是关键保留字的个数初始时为14
do { //以下为 查表方式采用二分法方式查表方式.
K=(i+J) / 2;
if (strcmp(ID,KWORD[K])<=0) J=K-1;
if (strcmp(ID,KWORD[K])>=0) i=K+1;
}while(i<=J);
if (i-1 > J) SYM=WSYM[K]; //若查找到,则是关键保留字
else SYM=IDENT; //否则为用户定义的标识符
}
else if (CH>='0' && CH<='9') { /*数字处理*/
K=0; NUM=0; //值放在NUM中
SYM=NUMBER; //类型为数字
do {
NUM=10*NUM+(CH-'0');
K++; GetCh();
}while(CH>='0' && CH<='9');
if (K>NMAX) Error(30); //若K大于数值的最大位数NMAX14位时则出错
}
else if (CH==':') {
GetCh();
if (CH=='=') { SYM=BECOMES; GetCh(); }
else SYM=NUL;
}
else if (CH=='<') { /* 处理<, <=,> */
GetCh();
if (CH=='=') { SYM=LEQ; GetCh(); }
else if(CH=='>') { SYM=NEQ; GetCh(); }
else SYM=LSS;
}
else if (CH=='>') {/* 处理> ,>=的关系 */
GetCh();
if (CH=='=') { SYM=GEQ; GetCh(); }
else SYM=GTR;
}
else if(CH=='+'){//处理以'+'开头的
GetCh();
if (CH=='=') { SYM=PLUSBECOMES; GetCh(); }
else if(CH=='+') { SYM=DOUBLEPLUS; GetCh(); }
else { SYM=PLUS; }
}
else if(CH=='-'){//处理以'-'开头的
GetCh();
if (CH=='=') { SYM=MINUSBECOMES; GetCh(); }
else if(CH=='-') { SYM=DOUBLEMINUS; GetCh(); }
else { SYM=MINUS;}
}
else if(CH=='\''){SYM=QUOT;GetCh();}
else { SYM=SSYM[CH]; GetCh(); }
} /*GetSym()*/
//---------------------------------------------------------------------------
void GEN(FCT X, int Y, int Z) {
/* 完成任务:生成目标代码,并送入目标程序区
FCT:功能代码
Y:层差
Z:位移量
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -