input.txt 文件内容
INT 0 3
LIT 0 2
LIT 0 3
OPR 0 2
OPR 0 14
OPR 0 0
#include <stdio.h>
#include <string.h>
#define stacksize 512
enum cmd {
// lit = 0,
// opr = 1,
// lod = 2,
// sto = 3,
// cal = 4,
// inte = 5,
cmp=6,
// jmp = 7,
// jpc = 8,
// error = 9
// 重新按照字符顺序排列,这样序号和后面的字符对应,就可以根据操作码查字符是否翻译正确而不是偏移
cal=0,
inte=1,
jmp=2,
jpc=3,
lit=4,
lod=5,
opr=6,
sto=7,
error=8
};
// 338 词法分析使用
char word[20][10];
enum cmd wsym[10];
void init() {
/*设置保留字名字,按照字母顺序,便于折半查找*/
// 大小写也不相同
// strcpy(&(word[0][0]), "cal");
strcpy(&(word[1][0]),"cmp");
// strcpy(&(word[2 - 1][0]), "inte");
// strcpy(&(word[3 - 1][0]), "jmp");
// strcpy(&(word[4 - 1][0]), "jpc");
// strcpy(&(word[5 - 1][0]), "lit");
// strcpy(&(word[6 - 1][0]), "lod");
// strcpy(&(word[7 - 1][0]), "opr");
// strcpy(&(word[8 - 1][0]), "sto");
strcpy(&(word[0][0]), "CAL");
// strcpy(&(word[1][0]),"cmp");
strcpy(&(word[2 - 1][0]), "INT"); //INTE INT
strcpy(&(word[3 - 1][0]), "JMP");
strcpy(&(word[4 - 1][0]), "JPC");
strcpy(&(word[5 - 1][0]), "LIT");
strcpy(&(word[6 - 1][0]), "LOD");
strcpy(&(word[7 - 1][0]), "OPR");
strcpy(&(word[8 - 1][0]), "STO");
// 二分查找后 字符与指令对应,字符折半,翻译区间折半对应
wsym[0] = cal;
// wsym[1]=cmp;
wsym[2 - 1] = inte;
wsym[3 - 1] = jmp;
wsym[4 - 1] = jpc;
wsym[5 - 1] = lit;
wsym[6 - 1] = lod;
wsym[7 - 1] = opr;
wsym[8 - 1] = sto;
// strcpy(&(word[9][0]),"if");
// strcpy(&(word[10][0]),"int");
// strcpy(&(word[11][0]),"odd");
// strcpy(&(word[12][0]),"procedure");
// strcpy(&(word[13][0]),"read");
// strcpy(&(word[14][0]),"then");
// strcpy(&(word[15][0]),"to"); //新增to
// strcpy(&(word[16][0]),"var");
// strcpy(&(word[17][0]),"while");
// strcpy(&(word[18][0]),"write");
}
//*x:instruction.f; //操作码
//*y:instruction.l; //跳转指令需要的层次差
//*z:instruction.a; //地址或操作数
struct instruction {
// int f; // opr 之类开头字母
cmd f;
int l; // 第几号
int a; // 参数
};
struct instruction code[1000];
FILE* fa2; // 输出结果
cmd getoption(char* id) {
int i, j, k;
int norw = 8; // 9 不行 // 8个
// char* id=new char[20];
cmd sym; // 翻译的指令
// k=0;
i = 0;
j = norw - 1;
do {
k = (i + j) / 2;
if (strcmp(id, word[k]) <= 0) {
j = k - 1;
// printf("字符小于列表\n");
// printf("%s\n",id);
}
if (strcmp(id, word[k]) >= 0) {
i = k + 1;
}
// if (strcmp(id, word[k]) == 0) {
// break;
// }
// printf("%s\n",word[k]);
// printf("%d\n",k);
} while (i <= j);
printf("匹配字位置 %d\n", k);
if (i - 1 > j) {
sym = wsym[k]; //保留字
//printf("识别出保留字\n");
return sym;
} else {
// sym=ident; //标识符
//printf("识别出标识符\n");
sym = error;
return sym;
}
}
// 每一个开头字符
int transop(char* cmdstr, instruction* code) {
char* p = cmdstr;
char op[100];
int cnt = 0;
while ((*p) != ' ') {
op[cnt] = *p;
cnt++;
p++;
}
op[cnt] = '\0';
// printf("%s", op);
enum cmd opv2 ;
opv2 = getoption(op);
if (opv2 == error) {
printf("操作码查询失败\n");
printf("无效命令 --%s--\n", op);
} else {
printf("翻译参数\n");
code->f = opv2;
printf("op = %d\n",opv2);
printf("%s\n", cmdstr);
printf("%s\n",word[opv2]);
// 字符串转数字
// 发现两个空格
// p++;
// p++;
while (*p == ' ') {
p++;
}
int num = 0;
while ((*p) != ' ') {
// printf("kkk %c\n", *p);
num = num * 10 + *p - '0';
p++;
}
code->l = num;
printf("%d\n", num);
//
// while (*p == ' ') {
// p++;
// }
//
// int lnumv2[20];
// int iv2 = 0;
// while ((*p) != ' '&&(*p)!='\0'&&(*p)!='\n') {
// lnum[iv2] = *p - '0';
// printf("end2=%c\n",*p);
// iv2++;
// p++;
// }
// int numv2 = 0;
//
// while (iv2 > 0) {
// iv2--;
// numv2 = numv2 * 10 + lnumv2[iv2];
// }
// printf("a=%d\n", numv2);
// code->a = numv2;
while (*p == ' ') {
p++;
}
int numv2 = 0;
while ((*p) != ' ' && (*p) != '\0' && (*p) != '\n') {
// while ((*p) != ' ' && (*p) != '\0') {
// if(*p=='\n'){
// printf("发现回车\n");
// *p='\0';
// break;
// }
numv2 = numv2 * 10 + (*p) - '0';
printf("a=%c\n", *p);
p++;
}
// numv2= numv2/10-('\n'-'0');
printf("numv2=%d\n",numv2);
code->a = numv2;
}
return 1;
}
/**
* 通过目标层次callee与当前层次caller层差来获声明callee的最近活动记录基址
* @param L 目标层次与当前层次的层次差
* @param stack 运行栈
* @param base 当前活动记录基址
* @return 目标活动记录的基址
*/
int base(int L, int* stack, int base) {
int pointer = base;
while (L > 0) {
pointer = stack[pointer];
L--;
}
return pointer;
}
/*
* PL0 解释程序
* 来源:清华大学,王生原等,《编译原理》附录A
**/
void interpret() {
int p, b, t; /* 指令指针,指令基址,栈顶指针 */
struct instruction i; /* 存放当前指令 */
int s[stacksize]; /* 栈 */
for(int n=0;n<stacksize;n++){
s[n]=0;
}
fa2=fopen("output.txt","w"); // 发现命令中有文件输出,所以之前需要开启文件
printf("start pl0\n");
t = 0;
b = 0;
p = 0;
s[0] = s[1] = s[2] = 0;
do {
printf("%d,%d,%d,%d\n", p, code[p].f, code[p].l, code[p].a);
for(int k=10;k>0;k--){
printf("%d\n",s[k]);
}
i = code[p]; /* 读当前指令 */
p++;
switch (i.f) {
case lit: /* 将a的值取到栈顶 */
s[t] = i.a;
t++;
break;
case opr: /* 数学、逻辑运算 */
switch (i.a) {
case 0:
printf("最后退出 opr 0 0 0指令\n");
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: /* 取相对当前过程的数据基地址为a的内存的值到栈顶 */
s[t] = s[base(i.l, s, b) + i.a];
t++;
break;
case sto: /* 栈顶的值存到相对当前过程的数据基地址为a的内存 */
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; /* 将本过程基地址入栈,此两项用于base函数 */
s[t + 2] = 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);
// fa2 = fopen("output.txt", "w");
// for (int i = 0; i < t; i++) {
// printf("%d\n", t);
// fprintf(fa2, "%d\n", s[t]);
// }
fclose(fa2);
}
int main() {
init();
FILE* fp;
fp = fopen("input.txt", "r");
char* str = new char[200];
char** cmd = new char*[200];
for (int i = 0; i < 100; i++) {
cmd[i] = new char[200];
}
int cnt = 0;
while (fgets(str, 200, fp) != NULL) {
if (strcmp(str, "\n") == 0) {
// printf("发现空\n");
// printf("--%s--\n", str);
} else if (str[0] == '\n') {
} else {
strcpy(cmd[cnt], str); // 存储命令
printf("--%s--\n", str);
// printf("%d\n",strlen(str));
cnt++;
}
}
for (int i = 0; i < cnt; i++) {
if (cmd[i][0] != '\0')
transop(cmd[i], &code[i]);
}
for (int i = 0; i < 10; i++) {
printf("%d,%d,%d\n", code[i].f, code[i].l, code[i].a);
}
// fa2 = fopen("output.txt", "w");
// fprintf(s[t],fa2);
interpret();
// fclose(fa2);
fclose(fp);
return 0;
}