Pl/0语言文法的BNF表示:
〈程序〉→〈分程序>.
〈分程序〉→ [<常量说明部分>][<变量说明部分>][<过程说明部分>]〈语句〉
<常量说明部分> → CONST<常量定义>{ ,<常量定义>};
<常量定义> → <标识符>=<无符号整数>
<无符号整数> → <数字>{<数字>}
<变量说明部分> → VAR<标识符>{ ,<标识符>};
<标识符> → <字母>{<字母>|<数字>}
<过和说明部分> → <过程首部><分程序>;{<过程说明部分>}
<过程首部> → procedure<标识符>;
<语句> → <赋值语句>|<条件语句>|<当型循环语句>|<过程调用语句>|<读语句>|<写语句>|<复合语句>|<空>
<赋值语句> → <标识符>:=<表达式>
<复合语句> → begin<语句>{ ;<语句>}<end>
<条件> → <表达式><关系运算符><表达式>|ood<表达式>
<表达式> → [+|-]<项>{<加减运算符><项>}
<项> → <因子>{<乘除运算符><因子>}
<因子> → <标识符>|<无符号整数>|(<表达式>)
<加减运符> → +|-
<乘除运算符> → *|/
<关系运算符> → =|#|<|<=|>|>=
<条件语句> → if<条件>then<语句>
<过程调用语句> → call<标识符>
<当型循环语句> → while<条件>do<语句>
<读语句> → read(<标识符>{ ,<标识符>})
<写语句> → write(<标识符>{,<标识符>})
<字母> → a|b|c…x|y|z
<数字> → 0|1|2…7|8|9
一. 为PL/0语言建立一个词法分程序GETSYM(函数)
把关键字、算符、界符称为语言固有的单词,标识符、常量称为用户自定义的单词。为此设置三个全程量:SYM,ID,NUM 。
SYM:存放每个单词的类别,为内部编码的表示形式。
ID:存放用户所定义的标识符的值,即标识符字符串的机内表示。
NUM:存放用户定义的数。
GETSYM要完成的任务:
- 滤掉单词间的空格。
- 识别关键字,用查关键字表的方法识别。当单词是关键字时,将对应的类别放在SYM中。如IF的类别为IFSYM,THEN的类别为THENSYM。
- 识别标识符,标识符的类别为IDENT,IDRNT放在SYM中,标识符本身的值放在ID中。关键字或标识符的最大长度是10。
- 拼数,将数的类别NUMBER放在SYM中,数本身的值放在NUM中。
- 拼由两个字符组成的运算符,如:>=、<=等等,识别后将类别存放在SYM中。
- 打印源程序,边读入字符边打印。
由于一个单词是由一个或多个字符组成的,所以在词法分析程序GETSYM中定义一个读字符过程GETCH。
二. 为PL/0语言建立一个语法分析程序BLOCK(函数)
PL/0编译程序采用一遍扫描的方法,所以语法分析和代码生成都有在BLOCK中完成。BLOCK的工作分为两步:
a) 说明部分的处理
说明部分的处理任务就是对每个过程(包括主程序,可以看成是一个主过程)的说明对象造名字表。填写所在层次(主程序是0层,在主程序中定义的过程是1层,随着嵌套的深度增加而层次数增大。PL/0最多允许3层),标识符的属性和分配的相对地址等。标识符的属性不同则填写的信息不同。
所造的表放在全程量一维数组TABLE中,TX为指针,数组元素为结构体类型数据。LEV给出层次,DX给出每层的局部量的相对地址,每说明完一个变量后DX加1。
例如:一个过程的说明部分为:
const a=35,b=49;
var c,d,e;
procedure p;
var g;
对它的常量、变量和过程说明处理后,TABLE表中的信息如下:
NAME: a NAME: b NAME: c NAME: d NAME: e NAME: p |
KIND: CONSTANT KIND: CONSTANT KIND: VARIABLE KIND: VARIABLE KIND: VAEIABLE KIND: PROCEDURE |
VAL: 35 VAL: 49 LEVEL: LEV LEVEL: LEV LEVEL: LEV LEVEL: LEV |
ADR: DX ADR: DX+1 ADR: DX+2 ADR: |
NAME: g 。 。 。 |
KIND: VARIABLE 。 。 。 |
LEVEL: LEV+1 。 。 。 |
ADR: DX 。 。 。 |
对于过程名的ADR域,是在过程体的目标代码生成后返填过程体的入口地址。
TABLE表的索引TX和层次单元LEV都是以BLOCK的参数形式出现,在主程序调用BLOCK时实参的值为0。每个过程的相对起始位置在BLOCK内置初值DX=3。
2.语句处理和代码生成
对语句逐句分析,语法正确则生目标代码,当遇到标识符的引用则去查TABLE表,看是否有过正确的定义,若有则从表中取出相关的信息,供代码生成用。PL/0语言的代码生成是由过程GEN完成。GEN过程有三个参数,分别代表目标代码的功能码、层差、和位移量。生成的目标代码放在数组CODE中。CODE是一维数组,数组元素是结构体类型数据。
PL/0语言的目标指令是一种假想的栈式计算机的汇编语言,其格式如下:
f | l | a |
其中f代表功能码,l代表层次差,a代表位移量。
目标指令有8条:
① LIT:将常数放到运栈顶,a域为常数。
② LOD:将变量放到栈顶。a域为变量在所说明层中的相对位置,l为调用层与说明层的层差值。
③ STO:将栈顶的内容送到某变量单元中。a,l域的含义与LOD的相同。
④ CAL:调用过程的指令。a为被调用过程的目标程序的入中地址,l为层差。
⑤ INT:为被调用的过程(或主程序)在运行栈中开辟数据区。a域为开辟的个数。
⑥ JMP:无条件转移指令,a为转向地址。
⑦ JPC:条件转移指令,当栈顶的布尔值为非真时,转向a域的地址,否则顺序执行。
⑧ OPR:关系和算术运算。具体操作由a域给出。运算对象为栈顶和次顶的内容进行运算,结果存放在次顶。a域为0时是退出数据区。
三. 建立一个解释执行目标程序的函数
编译结束后,记录源程序中标识符的TABLE表已退出内存,内存中只剩下用于存放目标程序的CODE数组和运行时的数据区S。S是由解释程序定义的一维整型数组。解释执行时的数据空间S为栈式计算机的存储空间。遵循后进先出的规则,对每个过程(包括主程序)当被调用时,才分配数据空间,退出过程时,则所分配的数据空间被释放。
为解释程序定义四个寄存器:
1. I:指令寄存器,存放当前正在解释的一条目标指令。
2. P:程序地址寄存器,指向下一条要执行的目标指令(相当于CODE数组的下标)。
3. T:栈顶寄存器,每个过程运行时要为它分配数据区(或称为数据 段),该数据区分为两部分。
静态部分:包括变量存放区和三个联单元。
动态部分:作为临时工作单元和累加器用。需要时临时分配,用完立即释放。栈顶寄存器T指出了当前栈中最新分配的单元(T也是数组S的下标)。
4. B:基地址寄存器,指出每个过程被调用时,在数据区S中给出它分配的数据段起始地址,也称为基地址。每个过程被调用时,在栈顶分配三个联系单元。这三个单元的内容分别是:
SL:静态链,它是指向定义该过程的直接外过程运行时数据段的基地址。
DL:动态链,它是指向调用该过程前正在运行过程的数据段的基地址。
RA:返回地址,记录调用该过程时目标程序的断点,即当时的程序地址寄存器P的值。
具体的过程调用和结束,对上述寄存器及三个联系单元的填写和恢复由下列目标指令完成。
1. INT 0 a
a:为局部量个数加3
2. OPR 0 0
恢复调用该过程前正在运行过程(或主程序)的数据段的基地址寄存器的值,恢复栈顶寄存器T的值,并将返回地址送到指令寄存器P中。
3. CAL l a
a为被调用过程的目标程序的入口,送入指令地址寄存器P中。
CAL指令还完成填写静态链,动态链,返回地址,给出被调用过程的基地址值,送入基址寄存器B中。
例:一个Pl/0源程序及生成的目标代码:
const a=10;
var b,c;
procedure p;
begin
c:=b+a
end;
2 int 0 3
3 lod 1 3
4 lit 0 10
5 opr 0 2
6 sto 1 4
7 opr 0 0
begin
read(b);
while b#0 do
begin
call p;
write(2*c);
read(b)
end
end .
8 int 0 5
9 opr 0 16
10 sto 0 3
11 lod 0 3
12 lit 0 0
13 opr 0 9
14 jpc 0 24
15 cal 0 2
16 lit 0 2
17 lod 0 4
18 opr 0 4
19 opr 0 14
20 opr 0 15
21 opr 0 16
22 sto 0 3
23 jmp 0 11
24 opr 0 0
下面是comp.h文件
1 #pragma once 2 #include <iostream> 3 #include <cstdio> 4 #include <cstdlib> 5 #include <string> 6 #include <algorithm> 7 #include <vector> 8 9 using namespace std; 10 11 const static int maxIdLength = 10; 12 const static int numLinkData = 3; 13 14 enum Token 15 { 16 TMP, IDENT, NUM, PERIOD, CONSTSYM, COMMA, LPAREN, RPAREN, EQ, SEMICOLON, COLON, 17 ASSIGN, VARSYM, PROCSYM, BEGINSYM, ENDSYM, ODDSYM, IFSYM, THENSYM, 18 CALLSYM, WHILESYM, DOSYM, WRITESYM, READSYM, PLUS, MINUS, TIMES, SPLASH, 19 NEQ, LSS, LE, GT, GE 20 }; 21 enum SymbolType 22 { 23 CONST, VARIABLE, PROCEDURE 24 }; 25 struct Symbol 26 { 27 int type; 28 char name[maxIdLength + 1]; 29 int value; 30 int level; 31 int address; 32 }; 33 enum 34 { 35 LIT, LOD, STO, CAL, INT, JMP, JPC, OPR 36 }; 37 enum OPS 38 { 39 OP_RET = 0, OP_ADD = 2, OP_MINUS = 3, OP_TIMES = 4, OP_DIV = 5, 40 OP_NEQ = 9, OP_EQ = 8, OP_LSS = 7, OP_LE = 6, OP_GT = 10, OP_GE = 11, 41 OP_READ = 16, OP_WRITE = 15 42 }; 43 struct PCode 44 { 45 int op; 46 int l; 47 int a; 48 PCode(int op = -1, int l = 0, int a = 0) 49 { 50 this->op = op; 51 this->l = l; 52 this->a = a; 53 } 54 }; 55 56 extern const char CodeTable[8][4]; 57 58 vector<Symbol> symTable(1000); 59 vector<PCode> code(1000); 60 extern int sym, num; 61 extern char id[maxIdLength + 1]; 62 extern int pc; 63 extern int line; 64 FILE *f; 65 66 int findKeyword(const char *str); 67 68 int getSym(FILE *in); 69 70 inline int getSym() 71 { 72 return getSym(f); 73 } 74 75 int block(int level, int index); 76 int constDeclaration(int index); 77 int varDeclaration(int level, int index); 78 int procDeclaration(int level, int index); 79 int statement(int level, int index); 80 int assignStatement(int level, int index); 81 int ifStatement(int level, int index); 82 int whileStatement(int level, int index); 83 int callStatement(int level, int index); 84 int readStatement(int level, int index); 85 int writeStatement(int level, int index); 86 int compositeStatement(int level, int index); 87 int condition(int level, int index); 88 int expression(int level, int index); 89 int term(int level, int index); 90 int factor(int level, int index); 91 92 int find(int from, int to, const char *name); 93 void printErr(const char *err); 94 95 inline void genCode(int op, int l, int a); 96 97 void interprete();
下面是 comp.cpp文件
1 #include "comp.h" 2 3 const char CodeTable[8][4] = { "LIT", "LOD", "STO", "CAL", "INT", "JMP", "JPC", "OPR" }; 4 5 int sym, num; 6 char id[maxIdLength + 1]; 7 int pc = 1; 8 int line = 1; 9 10 void printErr(const char *err) 11 { 12 printf("Line %d:%s\n", line, err); 13 exit(1); 14 } 15 16 int findKeyword(const char *str) 17 { 18 if (!strcmp(str, "const")) 19 return CONSTSYM; 20 if (!strcmp(str, "var")) 21 return VARSYM; 22 if (!strcmp(str, "procedure")) 23 return PROCSYM; 24 if (!strcmp(str, "begin")) 25 return BEGINSYM; 26 if (!strcmp(str, "end")) 27 return ENDSYM; 28 if (!strcmp(str, "odd")) 29 return ODDSYM; 30 if (!strcmp(str, "if")) 31 return IFSYM; 32 if (!strcmp(str, "then")) 33 return THENSYM; 34 if (!strcmp(str, "call")) 35 return CALLSYM; 36 if (!strcmp(str, "while")) 37 return WHILESYM; 38 if (!strcmp(str, "do")) 39 return DOSYM; 40 if (!strcmp(str, "write")) 41 return WRITESYM; 42 if (!strcmp(str, "read")) 43 return READSYM; 44 return -1; 45 } 46 47 int getSym(FILE *in) 48 { 49 extern int sym, num; 50 extern char id[maxIdLength + 1]; 51 char buf[maxIdLength + 1]; 52 int pos = 0; 53 char ch = ‘ ‘; 54 while (ch == ‘ ‘ || ch == ‘\t‘ || ch == ‘\r‘ || ch == ‘\n‘) 55 { 56 if ((ch = fgetc(in)) == EOF) 57 { 58 return -1; 59 } 60 if (ch == ‘\n‘) 61 line++; 62 } 63 if (isalpha(ch)) 64 { 65 while (isalpha(ch) || isdigit(ch)) 66 { 67 if (pos >= maxIdLength) 68 return -1; 69 buf[pos++] = ch; 70 ch = fgetc(in); 71 } 72 ungetc(ch, in); 73 buf[pos++] = ‘\0‘; 74 sym = findKeyword(buf); 75 if (sym<0) 76 { 77 sym = IDENT; 78 strcpy(id, buf); 79 return 0; 80 } 81 } 82 else if (isdigit(ch)) 83 { 84 while (isdigit(ch)) 85 { 86 if (pos >= maxIdLength) 87 return -1; 88 buf[pos++] = ch; 89 ch = fgetc(in); 90 } 91 ungetc(ch, in); 92 buf[pos++] = ‘\0‘; 93 sym = NUM; 94 num = atoi(buf); 95 return 0; 96 } 97 else if (ch == ‘(‘) 98 sym = LPAREN; 99 else if (ch == ‘)‘) 100 sym = RPAREN; 101 else if (ch == ‘=‘) 102 sym = EQ; 103 else if (ch == ‘#‘) 104 sym = NEQ; 105 else if (ch == ‘+‘) 106 sym = PLUS; 107 else if (ch == ‘-‘) 108 sym = MINUS; 109 else if (ch == ‘*‘) 110 sym = TIMES; 111 else if (ch == ‘/‘) 112 sym = SPLASH; 113 else if (ch == ‘,‘) 114 sym = COMMA; 115 else if (ch == ‘;‘) 116 sym = SEMICOLON; 117 else if (ch == ‘.‘) 118 sym = PERIOD; 119 else if (ch == ‘:‘) 120 { 121 ch = fgetc(in); 122 if (ch == ‘=‘) 123 sym = ASSIGN; 124 else 125 { 126 ungetc(ch, in); 127 sym = COLON; 128 } 129 } 130 else if (ch == ‘>‘) 131 { 132 ch = fgetc(in); 133 if (ch == ‘=‘) 134 sym = GE; 135 else 136 { 137 ungetc(ch, in); 138 sym = GT; 139 } 140 } 141 else if (ch == ‘<‘) 142 { 143 ch = fgetc(in); 144 if (ch == ‘=‘) 145 sym = LE; 146 else 147 { 148 ungetc(ch, in); 149 sym = LSS; 150 } 151 } 152 else return -1; 153 return 0; 154 } 155 156 int block(int level, int index) 157 { 158 int count = 0, dx = 0; 159 int tpc = pc; 160 genCode(JMP, 0, 0); 161 bool flag = false; 162 if (sym == CONSTSYM) 163 { 164 165 count = constDeclaration(index); 166 } 167 if (sym == VARSYM) 168 { 169 getSym(); 170 count += (dx = varDeclaration(level, index + count)); 171 } 172 if (sym == PROCSYM) 173 { 174 flag = true; 175 getSym(); 176 int px = count + index; 177 count += procDeclaration(level + 1, px); 178 } 179 if (!flag) 180 pc--; 181 else 182 code[tpc].a = pc; 183 genCode(INT, 0, numLinkData + dx); 184 statement(level, index + count); 185 genCode(OPR, 0, OP_RET); 186 return count; 187 } 188 189 int constDeclaration(int index) 190 { 191 Symbol sb; 192 sb.type = CONST; 193 int count = 0; 194 do 195 { 196 getSym(); 197 if (sym != IDENT) 198 printErr("identifier expected!"); 199 if (find(0, index + count, id) >= 0) 200 printErr("duplicated identifier!"); 201 strcpy(sb.name, id); 202 getSym(); 203 if (sym != EQ) 204 printErr("a ‘=‘ expected!"); 205 getSym(); 206 if (sym != NUM) 207 printErr("number expected!"); 208 sb.value = num; 209 symTable[index + count++] = sb; 210 getSym(); 211 if (!(sym == COMMA || sym == SEMICOLON)) 212 printErr("comma or semicolon expected!"); 213 } while (sym != SEMICOLON); 214 getSym(); 215 return count; 216 } 217 218 int varDeclaration(int level, int index) 219 { 220 Symbol sb; 221 sb.type = VARIABLE; 222 sb.level = level; 223 sb.address = 0; 224 int count = 0; 225 int tsym = sym; 226 do 227 { 228 if (sym != IDENT) 229 printErr("identifier expected!"); 230 if (find(0, index + count, id) >= 0) 231 printErr("duplicated expected!"); 232 strcpy(sb.name, id); 233 symTable[index + count++] = sb; 234 sb.address++; 235 getSym(); 236 if (!(sym == COMMA || sym == SEMICOLON)) 237 printErr("comma or semicolon expected!"); 238 tsym = sym; 239 getSym(); 240 } while (tsym != SEMICOLON); 241 return count; 242 } 243 244 int procDeclaration(int level, int index) 245 { 246 int count = 0; 247 if (sym != IDENT) 248 printErr("identifier expected!"); 249 Symbol sb; 250 strcpy(sb.name, id); 251 sb.type = PROCEDURE; 252 sb.level = level - 1; 253 sb.address = pc; 254 symTable[index + count++] = sb; 255 getSym(); 256 if (sym != SEMICOLON) 257 printErr("semicolon expected!"); 258 getSym(); 259 block(level, index + count); 260 if (sym != SEMICOLON) 261 printErr("semicolon expected!"); 262 getSym(); 263 if (sym == PROCSYM) 264 { 265 getSym(); 266 count += procDeclaration(level, index + count); 267 } 268 return count + 1; 269 } 270 271 int find(int from, int to, const char *name) 272 { 273 for (int i = to - 1; i >= from; i--) 274 if (!strcmp(name, symTable[i].name)) 275 return i; 276 return -1; 277 } 278 279 void genCode(int op, int l, int a) 280 { 281 PCode pcode(op, l, a); 282 code[pc++] = pcode; 283 } 284 285 int statement(int level, int index) 286 { 287 if (sym == IFSYM) 288 { 289 getSym(); 290 ifStatement(level, index); 291 } 292 else if (sym == WHILESYM) 293 { 294 getSym(); 295 whileStatement(level, index); 296 } 297 else if (sym == CALLSYM) 298 { 299 getSym(); 300 callStatement(level, index); 301 } 302 else if (sym == WRITESYM) 303 { 304 getSym(); 305 writeStatement(level, index); 306 } 307 else if (sym == READSYM) 308 { 309 getSym(); 310 readStatement(level, index); 311 } 312 else if (sym == BEGINSYM) 313 { 314 getSym(); 315 compositeStatement(level, index); 316 } 317 else if (sym == IDENT) 318 { 319 assignStatement(level, index); 320 } 321 else 322 return 0; 323 return 0; 324 } 325 326 int ifStatement(int level, int index) 327 { 328 condition(level, index); 329 int cpc = pc; 330 genCode(JPC, 0, 0); 331 if (sym != THENSYM) 332 printErr("then clause expected!"); 333 getSym(); 334 statement(level, index); 335 code[cpc].a = pc; 336 return 0; 337 } 338 339 int whileStatement(int level, int index) 340 { 341 int cpc = pc; 342 condition(level, index); 343 int jpc = pc; 344 genCode(JPC, 0, 0); 345 if (sym != DOSYM) 346 { 347 printErr("do expected!"); 348 } 349 getSym(); 350 statement(level, index); 351 genCode(JMP, 0, cpc); 352 code[jpc].a = pc; 353 return 0; 354 } 355 356 int callStatement(int level, int index) 357 { 358 if (sym != IDENT) 359 printErr("syntax error!"); 360 int i = find(0, index, id); 361 if (i<0) 362 printErr("identifier not found!"); 363 if (symTable[i].type != PROCEDURE) 364 printErr("syntax error!"); 365 genCode(CAL, level - symTable[i].level, symTable[i].address); 366 getSym(); 367 return 0; 368 } 369 370 int readStatement(int level, int index) 371 { 372 if (sym != LPAREN) 373 printErr(" ( expected"); 374 getSym(); 375 while (sym != RPAREN) 376 { 377 if (sym != IDENT) 378 printErr("variable expected!"); 379 int i = find(0, index, id); 380 if (i<0) 381 printErr("identifier not found!"); 382 if (symTable[i].type != VARIABLE) 383 printErr("variable expected!"); 384 genCode(OPR, 0, OP_READ); 385 genCode(STO, level - symTable[i].level, symTable[i].address + numLinkData); 386 getSym(); 387 if (sym != COMMA&&sym != RPAREN) 388 printErr("syntax error!"); 389 } 390 getSym(); 391 return 0; 392 } 393 394 int writeStatement(int level, int index) 395 { 396 if (sym != LPAREN) 397 printErr(" ( expected"); 398 getSym(); 399 while (sym != RPAREN) 400 { 401 expression(level, index); 402 genCode(OPR, 0, OP_WRITE); 403 if (sym != COMMA&&sym != RPAREN) 404 printErr("syntax error!"); 405 } 406 getSym(); 407 return 0; 408 } 409 410 int compositeStatement(int level, int index) 411 { 412 statement(level, index); 413 while (sym == SEMICOLON) 414 { 415 getSym(); 416 statement(level, index); 417 } 418 if (sym != ENDSYM) 419 printErr("end expected!"); 420 getSym(); 421 return 0; 422 } 423 424 int assignStatement(int level, int index) 425 { 426 int i = find(0, index, id); 427 if (i<0) 428 { 429 printErr("Variable not found!"); 430 } 431 if (symTable[i].type == CONST) 432 printErr("constant can‘t be a r-value!"); 433 getSym(); 434 if (sym != ASSIGN) 435 { 436 printErr(":= expected!"); 437 } 438 getSym(); 439 expression(level, index); 440 genCode(STO, level - symTable[i].level, numLinkData + symTable[i].address); 441 return 0; 442 } 443 444 int condition(int level, int index) 445 { 446 if (sym == ODDSYM) 447 { 448 getSym(); 449 expression(level, index); 450 genCode(LIT, 0, 0); 451 genCode(OPR, 0, OP_NEQ); 452 } 453 else 454 { 455 expression(level, index); 456 int op = sym; 457 if (sym != NEQ&&sym != EQ&&sym != LSS&&sym != LE&&sym != GT&&sym != GE) 458 printErr("error!"); 459 getSym(); 460 expression(level, index); 461 switch (op) 462 { 463 case NEQ: 464 genCode(OPR, 0, OP_NEQ); break; 465 case EQ: 466 genCode(OPR, 0, OP_EQ); break; 467 case LSS: 468 genCode(OPR, 0, OP_LSS); break; 469 case LE: 470 genCode(OPR, 0, OP_LE); break; 471 case GT: 472 genCode(OPR, 0, OP_GT); break; 473 case GE: 474 genCode(OPR, 0, OP_GE); break; 475 } 476 } 477 return 0; 478 } 479 480 int expression(int level, int index) 481 { 482 483 int op = sym; 484 if (sym == PLUS || sym == MINUS) 485 { 486 getSym(); 487 } 488 factor(level, index); 489 if (op == MINUS) 490 { 491 genCode(LIT, 0, 0); 492 genCode(OPR, 0, OP_MINUS); 493 } 494 do{ 495 op = sym; 496 if (sym == PLUS || sym == MINUS) 497 { 498 getSym(); 499 factor(level, index); 500 if (op == PLUS) 501 genCode(OPR, 0, OP_ADD); 502 else 503 genCode(OPR, 0, OP_MINUS); 504 } 505 } while (sym == PLUS || sym == MINUS); 506 return 0; 507 } 508 509 int factor(int level, int index) 510 { 511 512 term(level, index); 513 int op = sym; 514 if (op != TIMES&&op != SPLASH) 515 return 0; 516 do{ 517 getSym(); 518 term(level, index); 519 if (op == TIMES) 520 genCode(OPR, 0, 4); 521 else 522 genCode(OPR, 0, OP_DIV); 523 op = sym; 524 } while (sym == TIMES || sym == SPLASH); 525 return 0; 526 } 527 528 int term(int level, int index) 529 { 530 if (sym == IDENT) 531 { 532 int i = find(0, index, id); 533 if (i<0) 534 { 535 printErr("Identifier not found!"); 536 } 537 if (symTable[i].type == CONST) 538 genCode(LIT, 0, symTable[i].value); 539 else if (symTable[i].type == VARIABLE) 540 genCode(LOD, level - symTable[i].level, numLinkData + symTable[i].address); 541 else 542 { 543 printErr("error!"); 544 } 545 getSym(); 546 } 547 else if (sym == NUM) 548 { 549 genCode(LIT, 0, num); 550 getSym(); 551 } 552 else if(sym==LPAREN) 553 { 554 getSym(); 555 expression(level, index); 556 if (sym != RPAREN) 557 printf(") expected"); 558 getSym(); 559 } 560 else{ 561 printErr("error!"); 562 } 563 return 0; 564 } 565 566 void interprete() 567 { 568 const static int ret_addr = 0, dynamic_link = 1, static_link = 2; 569 PCode ir; 570 int ip = 1, sp = 0, bp = 0; 571 int stack[1000] = { 0 }; 572 int sp_stack[10]; 573 int sp_top = 0; 574 while (ip<pc) 575 { 576 ir = code[ip++]; 577 switch (ir.op) 578 { 579 case LIT: 580 stack[sp++] = ir.a; break; 581 case LOD: 582 { 583 if (ir.l == 0) 584 stack[sp++] = stack[bp + ir.a]; 585 else 586 { 587 int outer_bp = stack[bp + static_link]; 588 while (--ir.l) 589 outer_bp = stack[outer_bp + static_link]; 590 stack[sp++] = stack[outer_bp + ir.a]; 591 } 592 break; 593 } 594 case STO: 595 { 596 if (ir.l == 0) 597 stack[bp + ir.a] = stack[sp - 1]; 598 else 599 { 600 int outer_bp = stack[bp + static_link]; 601 while (--ir.l) 602 outer_bp = stack[outer_bp + static_link]; 603 stack[outer_bp + ir.a] = stack[sp - 1]; 604 } 605 break; 606 } 607 case CAL: 608 { 609 stack[sp + ret_addr] = ip; 610 stack[sp + dynamic_link] = bp; 611 stack[sp + static_link] = bp; 612 ip = ir.a; 613 bp = sp; 614 break; 615 } 616 case INT: 617 { 618 sp_stack[sp_top++] = sp; 619 sp += ir.a; 620 break; 621 } 622 case JMP: 623 { 624 ip = ir.a; 625 break; 626 } 627 case JPC: 628 { 629 if (stack[sp - 1] == 0) 630 ip = ir.a; 631 break; 632 } 633 case OPR: 634 { 635 switch (ir.a) 636 { 637 case OP_RET: 638 { 639 ip = stack[bp + ret_addr]; 640 bp = stack[bp + dynamic_link]; 641 sp = sp_stack[--sp_top]; 642 if (sp_top <= 0) 643 { 644 printf("program exited normally!\n"); 645 return; 646 } 647 break; 648 } 649 case OP_ADD: 650 { 651 stack[sp - 2] = stack[sp - 1] + stack[sp - 2]; 652 sp--; 653 break; 654 } 655 case OP_MINUS: 656 { 657 stack[sp - 2] = stack[sp - 1] - stack[sp - 2]; 658 sp--; 659 break; 660 } 661 case OP_TIMES: 662 { 663 stack[sp - 2] = stack[sp - 1] * stack[sp - 2]; 664 sp--; 665 break; 666 } 667 case OP_DIV: 668 { 669 stack[sp - 2] = stack[sp - 2] / stack[sp - 1]; 670 sp--; 671 break; 672 } 673 case OP_NEQ: 674 { 675 stack[sp - 2] = (stack[sp - 2] != stack[sp - 1]) ? 1 : 0; 676 sp--; 677 break; 678 } 679 case OP_EQ: 680 { 681 stack[sp - 2] = (stack[sp - 2] == stack[sp - 1]) ? 1 : 0; 682 sp--; 683 break; 684 } 685 case OP_LSS: 686 { 687 stack[sp - 2] = (stack[sp - 2]<stack[sp - 1]) ? 1 : 0; 688 sp--; 689 break; 690 } 691 case OP_LE: 692 { 693 stack[sp - 2] = (stack[sp - 2] <= stack[sp - 1]) ? 1 : 0; 694 sp--; 695 break; 696 } 697 case OP_GT: 698 { 699 stack[sp - 2] = (stack[sp - 2]>stack[sp - 1]) ? 1 : 0; 700 sp--; 701 break; 702 } 703 case OP_GE: 704 { 705 stack[sp - 2] = (stack[sp - 2] >= stack[sp - 1]) ? 1 : 0; 706 sp--; 707 break; 708 } 709 case OP_READ: 710 { 711 cout << "Please input a number:" << endl; 712 cin >> stack[sp++]; 713 break; 714 } 715 case OP_WRITE: 716 { 717 cout << stack[sp - 1] << endl; 718 break; 719 } 720 default: 721 { 722 printf("Unexpected operation!\n"); return; 723 } 724 } 725 break; 726 } 727 default: 728 printf("Unexpected instruction!\n"); return; 729 } 730 } 731 } 732 733 int main(int argc, char *argv[]) 734 { 735 f = fopen("test.txt","r"); 736 getSym(); 737 block(0, 0); 738 for (int i = 1; i<pc; i++) 739 { 740 cout << i << ":\t" << CodeTable[code[i].op] << " " << code[i].l << " " << code[i].a << endl; 741 } 742 interprete(); 743 return 0; 744 }
下面是test.txt文件
const a=10; var b,c; procedure p; begin c:=b+a end; begin read(b); while b#0 do begin call p; write(2*c); read(b) end end