编译原理3-语义分析及抽象机

语义分析说白了就是修改语法分析,在语法分析的同时加上程序要执行的相应动作,生成中间代码,本程序生成的中间代码是三元式的形式。

语法分析实现使用的递归下降的方法,大佬们可以去试试用LL(1)程序生成四元式。

TEST语言的语法制导翻译方案(test语法请看语法分析博客)

1)S↑t → {A↑pB↑r} 
2)  A↑t→C↑pA↑t | ε
3)C↑t → int ID↑p; 
4)B↑t→D↑pB↑t | ε
5)D↑t → E↑t | F↑t | G↑t | H↑t | I↑t | J↑t | K↑t | ; 
6)E↑t → if ( L↑q ) D↑r E1↓p↑t
E1↓p↑t → ε | else D↑r
7)F↑t → while (L↑q) D↑r
8)G↑t → for (M↑r; L↑q; M↑r)D↑p 
9)I↑t → write N↑p; 
10)H↑t → read ID↑p; 
11)J↑t → {B↑r} 
12)M↑t → ID↑p=N↑r@EQUAL↑t,r,t0
13)K↑t →M↑r; 
14)L↑t → N↑pL1↓p↑t
L1 ↓p↑t→>N↑r@GREATER↓p,r,t0 | < N↑r@LESS↓p,r,t0 | == N↑r@EQUAL↓p,r,t0 | != N↑r@NOTEQUAL↓p,r,t0|>=N↑r@GAE↓p,r,t0 | <=N↑r@LAE↓p,r,t0 
15)N↑t→O↑pN”↓p↑t
		N”↓p↑t →-O↑r@SUB↓p,r,t0N”↓t0↑t | +O↑r@ADD↓p,r,t0N”↓t0↑t | ε
16)O↑t→P↑rO”↓p↑t
		O”↓p↑t → *P↑r@MULT↓p,r,t0O”↓t0↑t | /P↑r@DIV↓p,r,t0O”↓t0↑t | ε
17)P↑t → (N↑t) | ID↑t | NUM↑t 

构造test测试程序 

该程序实验从1到10做加法运算并输出,1到10做乘法运算并输出

{
int n;
int k;
int i;
int temp;
n = 0;
k = 1;
for( i = 1; i <= 10; i = i + 1 )
{
read temp;
n = temp + n;
k = k * temp;
}
write n;
write k;
}

词法分析结果:红箭头表示分隔,

语义分析程序:

//语法、语义分析及代码生成
#include<stdio.h>

/*
没有stype.h
未导入ctring.h
缺少入口函数
287 多了一个空格
354 359 360 中文引号
59 383  406 425用strcpy_s代替strcpy
86 少了一个形参 &fp
102 少了一个形参&fout
95 100 用fopen_s代替fopen
213 代码不完整 缺少 )
207——213未定义tokenm
94 127 134 170 175 178 215 218 225 234 248 251 258 270 273 280 291 299 312 318 326 334 337 345 356 358 379 402 421 436 441 451 458 用fscanf代替fscanf
375 函数体缺少代码
无法解析的外部符号 删掉第44行中的extern
*/
#include<ctype.h>
#include<conio.h>
#include<string>
#define maxvartablep 500  //定义符号表容量
int TESTparse();
int program();
int compound_stat();
int statement();
int arithmetic_expression();
int assignment_expression();
int assignment_stat();
int bool_expression();
int term();
int factor();
int flagout = 0;
int if_stat();
int while_stat();
int for_stat();
int write_stat();
int read_stat();
int declaration_stat();
int declaration_list();
int statement_list();
int compound_stat();
int name_def(char *name);
char token[20], taken[40];//token保存单词符号,taken保存单词值
char Scanout[300], Codeout[300];//保存词法分析输出文件名
FILE * fp, *fout;//用于指向输入输出文件的指针
struct {//定义符号表结构
	char name[8];
	int address;
}vartable[maxvartablep];
int vartablep = 0, labelp = 0, datap = 0;   //改符号表最多容纳maxvartablep个记录

//插入符号表动作@name-def n,t的程序如下:
int name_def(char *name)
{
	int i, es = 0;
	if (vartablep >= maxvartablep)   return(21);
	for (i = vartablep - 1; i == 0; i--)    //查符号表
	{
		if (strcmp(vartable[i].name, name) == 0)
		{
			es = 22;     //22表示变量重复声明
			break;
		}
	}
	if (es > 0)    return(es);
	strcpy_s(vartable[vartablep].name, name);
	vartable[vartablep].address = datap;
	datap++;         //分配一个单元,数据区指针加1
	vartablep++;
	return(es);
}

//查询符号表返回地址
int lookup(char *name, int *paddress)
{
	int i, es = 0;
	for (i = 0; i < vartablep; i++)
	{
		if (strcmp(vartable[i].name, name) == 0)
		{
			*paddress = vartable[i].address;
			return(es);
		}
	}
	es = 23;
	return(es);   //变量没有声明
}

//语法、语义分析及代码生成程序
int TESTparse()
{
	int es = 0;
	fp = fopen("词法分析输出.txt", "r");
	if (!fp)
	{
		printf("\n打开%s错误!\n", "cifa.txt");
		es = 10;
		return(es);
	}
	/*printf("请输入目标文件名(包含路径):");
	scanf_s("%s", Codeout, 128);*/
	fout = fopen("yuyi.txt", "w");
	if (!fout)
	{
		printf("\n创建%s错误!\n", Codeout);
		es = 10;
		return(es);
	}
	if (es == 0)
		es = program();
	printf("==语法、语义分析及代码生成程序结果==\n");
	switch (es)
	{
	case 0:printf("语法、语义分析成功并抽象机汇编生成代码!\n"); break;
	case 10:printf("打开文件%s失败!\n", Scanout); break;
	case 1:printf("缺少{!\n"); break;
	case 2:printf("缺少}!\n"); break;
	case 3:printf("缺少标识符!\n"); break;
	case 4:printf("少分号!\n"); break;
	case 5:printf("缺少(!\n"); break;
	case 6:printf("缺少)!\n"); break;
	case 7:printf("缺少操作数!\n"); break;
	case 21:printf("符号表溢出!\n"); break;
	case 22:printf("变量重复定义!\n"); break;
	case 23:printf("变量未声明!\n"); break;
	}
	fclose(fp);
	fclose(fout);
	return(es);
}
//program::={<declaration_list><statement_list>}
int program()
{
	int es = 0, i;
	fscanf(fp, "%s	:	%s\n", token, taken);
	printf("%s	:	%s\n", token, taken);
	if (strcmp(token, "{"))    //判断是否'{'
	{
		es = 1;  //不是{
		return(es);
	}
	fscanf(fp, "%s	:	%s\n", token, taken);
	printf("%s	:	%s\n", token, taken);
	es = declaration_list();
	if (es > 0)    return(es);
	printf("符号表:\n");
	printf(" 名字 地址\n");
	for (i = 0; i < vartablep; i++)
		printf("   %s   %d\n", vartable[i].name, vartable[i].address);
	es = statement_list();
	if (es > 0)    return(es);
	if (strcmp(token, "}"))   //判断是否'}'
	{
		es = 2;
		return(es);
	}
	fscanf(fp, "%s	:	%s\n", token, taken);
	printf("%s	:	%s\n", token, taken);
	es = statement_list();
	fprintf(fout, "    STOP\n");    //产生停止指令
	return(es);
}
int declaration_list()
{
	int es = 0;
	while (strcmp(token, "int") == 0)
	{
		es = declaration_stat();
		if (es > 0)    return (es);
	}
	return(es);
}
int declaration_stat()
{
	int es = 0;
	fscanf(fp, "%s : %s\n", &token, &taken);
	printf("%s : %s\n", token, taken);
	if (strcmp(token, "ID"))  return(es = 3);   //不是标识符
	es = name_def(taken);                    //插入符号表
	if (es > 0)    return(es);
	fscanf(fp, "%s : %s\n", &token, &taken);
	printf("%s : %s\n", token, taken);
	if (strcmp(token, ";"))   return(es == 4);
	fscanf(fp, "%s : %s\n", &token, &taken);
	printf("%s : %s\n", token, taken);
	return(es);
}
int statement_list()
{
	int es = 0;
	while (strcmp(token, "}"))
	{
		es = statement();
		if (es > 0)    return(es);
	}
	return (es);
}
int statement()
{
	int es = 0;
	if (es == 0 && strcmp(token, "if") == 0)  es = if_stat();  //if语句
	if (es == 0 && strcmp(token, "while") == 0)   es = while_stat();  //while语句
	if (es == 0 && strcmp(token, "for") == 0)   es = for_stat();  //for语句
	if (es == 0 && strcmp(token, "read") == 0)   es = read_stat();  //read语句
	if (es == 0 && strcmp(token, "write") == 0)   es = write_stat();  //write语句
	if (es == 0 && strcmp(token, "{") == 0)   es = compound_stat();  //复合语句
	if (es == 0 && (strcmp(token, "ID") == 0)) //赋值语句
		es = assignment_stat();
	return(es);
}
int if_stat()
{
	int es = 0, label1, label2;                //if
	fscanf(fp, "%s : %s\n", &token, &taken);
	printf("%s : %s\n", token, taken);
	if (strcmp(token, "("))   return(es = 5);  //少左括号
	fscanf(fp, "%s : %s\n", &token, &taken);
	printf("%s : %s\n", token, taken);
	es = bool_expression();
	if (es > 0)    return(es);
	if (strcmp(token, ")"))   return(es = 6);  //少右括号
	label1 = labelp++;   //用label1记住条件为假时要转向的标号
	fprintf(fout, "      BRF LABEL %d\n", label1);  //输出假转移指令
	fscanf(fp, "%s : %s\n", &token, &taken);
	printf("%s : %s\n", token, taken);
	es = statement();
	if (es > 0)    return(es);
	label2 = labelp++;  //用label2记住要转向的标号
	fprintf(fout, "      BR LABEL %d\n", label2);  //输出无条件转移指令
	fprintf(fout, "LABEL%d:\n", label1);  //设置label1要标记的符号
	if (strcmp(token, "else") == 0)  //else部分处理
	{
		fscanf(fp, "%s : %s\n", &token, &taken);
		printf("%s : %s\n", token, taken);
		es = statement();
		if (es > 0)    return(es);
	}
	fprintf(fout, "LABEL%d:\n", label2);  //设置label2记住的标号
	return(es);
}
int while_stat()
{
	int es = 0, label1, label2;
	label1 = labelp++;
	fprintf(fout, "LABEL%d:\n", label1);//设置label1标号
	fscanf(fp, "%s : %s\n", &token, &taken);
	printf("%s : %s\n", token, taken);
	if (strcmp(token, "("))   return(es = 5);//少左括号
	fscanf(fp, "%s : %s\n", &token, &taken);
	printf("%s : %s\n", token, taken);
	es = bool_expression();
	if (es > 0)    return(es);
	if (strcmp(token, ")"))   return(es = 6);//少右括号
	label2 = labelp++;
	fprintf(fout, "      BRF LABEL %d\n", label2);//输出假转移指令
	fscanf(fp, "%s : %s\n", &token, &taken);
	printf("%s : %s\n", token, taken);
	es = statement();
	if (es > 0)    return(es);
	fprintf(fout, "      BR LABEL %d\n", label1);//输出无条件转移指令
	fprintf(fout, "LABEL%d:\n", label2);//设置label2标号
	return(es);
}
int for_stat()
{
	int es = 0, label1, label2, label3, label4;
	fscanf(fp, "%s : %s\n", &token, &taken);
	printf("%s : %s\n", token, taken);
	if (strcmp(token, "("))   return (es = 5);//少左括号
	fscanf(fp, "%s : %s\n", &token, &taken);
	printf("%s : %s\n", token, taken);
	es = assignment_expression();
	if (es > 0)    return(es);
	if (strcmp(token, ";"))   return(es = 4);//少分号
	label1 = labelp++;
	fprintf(fout, "LABEL%d:\n", label1);//设置label1标号
	fscanf(fp, "%s : %s\n", &token, &taken);
	printf("%s : %s\n", token, taken);
	es = bool_expression();
	if (es > 0)    return(es);
	label2 = labelp++;
	fprintf(fout, "      BRF LABEL%d\n", label2);//输出假条件转移指令
	label3 = labelp++;
	fprintf(fout, "      BR LABEL%d\n", label3);//输出无条件转移指令
	if (strcmp(token, ";"))   return(es = 4);//少分号
	label4 = labelp++;
	fprintf(fout, "LABEL%d:\n", label4);//设置label4标号
	fscanf(fp, "%s : %s\n", &token, &taken);
	printf("%s : %s\n", token, taken);
	es = assignment_expression();
	if (es > 0)    return(es);
	fprintf(fout, "      POP\n");//输出出栈指令
	fprintf(fout, "      BR LABEL%d\n", label1);//输出无条件转移指令
	if (strcmp(token, ")"))   return(es = 6);//缺少右括号
	fprintf(fout, "LABEL%d:\n", label3);//设置label3标号
	fscanf(fp, "%s : %s\n", &token, &taken);
	printf("%s : %s\n", token, taken);
	es = statement();
	if (es > 0)    return(es);
	fprintf(fout, "      BR LABEL%d\n", label4);//输出无条件转移指令
	fprintf(fout, "LABEL%d:\n", label2);//设置label2标号
	return(es);

}
int write_stat()
{

	int es = 0;
	fscanf(fp, "%s : %s\n", token, &taken);
	int address;
	flagout = 1;
	es = lookup(taken, &address);
	printf("%s : %s\n", token, taken);
	es = arithmetic_expression();
	if (es > 0)    return(es);
	if (strcmp(token, ";"))   return(es = 4);//少分号

	fprintf(fout, "      OUT %d\n", address);
	flagout = 0;
	fscanf(fp, "%s : %s\n", token, &taken);
	printf("%s : %s\n", token, taken);
	return(es);
}
int read_stat()
{
	int es = 0, address;
	fscanf(fp, "%s : %s\n", token, &taken);
	printf("%s : %s\n", token, taken);
	if (strcmp(token, "ID"))  return(es = 3);//少标识符
	es = lookup(taken, &address);
	if (es > 0)    return(es);
	fprintf(fout, "      IN  \n");//输出指令
	fprintf(fout, "      STO  %d\n", address);//输出STO指令
	fprintf(fout, "      POP  \n");
	fscanf(fp, "%s : %s\n", token, &taken);
	printf("%s : %s\n", token, taken);
	if (strcmp(token, ";"))   return(es = 4);//少分号
	fscanf(fp, "%s : %s\n", token, &taken);
	printf("%s : %s\n", token, taken);
	return(es);
}
int compound_stat()
{
	int es = 0;
	fscanf(fp, "%s : %s\n", token, &taken);
	printf("%s : %s\n", token, taken);
	es = statement_list();
	return(es);
}
int assignment_expression()
{
	int es = 0, address;
	if (strcmp(token, "ID")) return es = 9;
	es = lookup(taken, &address);
	if (es > 0)return es;
	fscanf(fp, "%s : %s\n", &token, &taken);
	printf("%s : %s\n", token, taken);
	if (strcmp(token, "=")) return es = 10;
	fscanf(fp, "%s : %s\n", &token, &taken);
	printf("%s : %s\n", token, taken);
	es = arithmetic_expression();
	if (es > 0)return es;
	fprintf(fout, "STO %d\n", address);
	fprintf(fout, " POP\n");
	return(es);
}
int assignment_stat()
{
	int es = 0;
	while (strcmp(token, "ID") == 0)
	{
		es = assignment_expression();
		if (es > 0)    return (es);
		fscanf(fp, "%s : %s\n", token, &taken);
		printf("%s : %s\n", token, taken);
	}


	return(es);
}
int bool_expression()
{
	int es = 0;
	es = arithmetic_expression();
	if (es > 0)    return(es);
	if (strcmp(token, ">") == 0 || strcmp(token, ">=") == 0
		|| strcmp(token, "<") == 0 || strcmp(token, "<=") == 0
		|| strcmp(token, "==") == 0 || strcmp(token, "!=") == 0)
	{
		char token2[20];
		strcpy_s(token2, token);//保存运算符
		fscanf(fp, "%s : %s\n", token, &taken);
		printf("%s : %s\n", token, taken);
		es = arithmetic_expression();
		if (es > 0)    return(es);
		if (strcmp(token2, ">") == 0)   fprintf(fout, "      GT\n");
		if (strcmp(token2, ">=") == 0)   fprintf(fout, "      GE\n");
		if (strcmp(token2, "<") == 0)   fprintf(fout, "      LES\n");
		if (strcmp(token2, "<=") == 0)   fprintf(fout, "      LE\n");
		if (strcmp(token2, "==") == 0)   fprintf(fout, "      EQ\n");
		if (strcmp(token2, "!=") == 0)   fprintf(fout, "      NOTEQ\n");
	}
	return(es);
}
int arithmetic_expression()
{
	int es = 0;
	es = term();
	if (es > 0)    return(es);
	while (strcmp(token, "+") == 0 || strcmp(token, "-") == 0)
	{
		char token2[20];
		strcpy_s(token2, token);//保存运算符
		fscanf(fp, "%s : %s\n", token, &taken);
		printf("%s : %s\n", token, taken);
		es = term();
		if (es > 0)    return(es);
		if (strcmp(token2, "+") == 0)   fprintf(fout, "      ADD\n");
		if (strcmp(token2, "-") == 0)   fprintf(fout, "      SUB\n");
	}
	return(es);
}
int term()
{
	int es = 0;
	es = factor();
	if (es > 0)    return(es);
	while (strcmp(token, "*") == 0 || strcmp(token, "/") == 0)
	{
		char token2[20];
		strcpy_s(token2, token);
		fscanf(fp, "%s : %s\n", token, &taken);
		printf("%s : %s\n", token, taken);
		es = factor();
		if (es > 0)    return(es);
		if (strcmp(token2, "*") == 0)   fprintf(fout, "      MULT\n");
		if (strcmp(token2, "/") == 0)   fprintf(fout, "      DIV\n");
	}
	return(es);
}
int factor()
{
	int es = 0;
	if (strcmp(token, "(") == 0)
	{
		fscanf(fp, "%s : %s\n", token, &taken);
		printf("%s : %s\n", token, taken);
		es = arithmetic_expression();
		if (es > 0)    return(es);
		if (strcmp(token, ")"))   return(es = 6);//缺少右括号
		fscanf(fp, "%s : %s\n", token, &taken);
		printf("%s : %s\n", token, taken);
	}
	else
	{
		if (strcmp(token, "ID") == 0)
		{
			int address;
			es = lookup(taken, &address);//查符号表,获取变量地址
			if (es > 0)    return(es);
			if (flagout == 0)
				fprintf(fout, "      LOAD %d\n", address);
			//fprintf(fout, "      LOAD %d\n", address);
			fscanf(fp, "%s : %s\n", token, &taken);
			printf("%s : %s\n", token, taken);
			return(es);
		}
		if (strcmp(token, "NUM") == 0)
		{
			fprintf(fout, "      LOADI %s\n", taken);
			fscanf(fp, "%s : %s\n", token, &taken);
			printf("%s : %s\n", token, taken);
			return(es);
		}
		else
		{
			es = 7;//缺少操作数
			return(es);
		}
	}
	return(es);
}

void yufa()
{
	int es = 0;
	es = TESTparse();
}

 语义分析生成的三元式:

TEST 语言抽象机,其指令系统各指令及含义描述如下: 
LOAD D 将内存单元 D 中的内容加载到操作数栈。 
LOADI  常量 将常量压入操作数栈。 
STO D  将操作数栈栈顶单元内容存入内存单元 D,且栈顶单元内容保持不变。 
ADD    将次栈顶单元与栈顶单元内容出栈并相加,和置于栈顶。 
SUB    将次栈顶单元减去栈顶单元内容并出栈,差置于栈顶。 
MULT   将次栈顶单元与栈顶单元内容出栈并相乘,积置于栈顶。 
DIV    将次栈顶单元与栈顶单元内容出栈并相除,商置于栈顶。 
BR   lab  无条件转移到标号 lab。 
BRF  lab  检查栈顶单元逻辑值,若为假(0)则转移到标号 lab。 
EQ     将栈顶两单元做等于比较,并将结果1或0置于栈顶。 
NOTEQ  将栈顶两单元做不等于比较,并将结果1或0置于栈顶。 
GT     次栈顶大于栈顶操作数,则栈顶置 1,否则置 0。 
LES    次栈顶小于栈顶操作数,则栈顶置 1,否则置 0。 
GE     次栈顶大于等于栈顶操作数,则栈顶置 1,否则置 0。 
LE     次栈顶小于等于栈顶操作数,则栈顶置 1,否则置 0。 
AND    将栈顶两单元做逻辑与运算,并将结果1或0置于栈顶。 
OR     将栈顶两单元做逻辑或运算,并将结果1或0置于栈顶。 
NOT    将栈顶的逻辑值取反。 
IN     从标准输入设备(键盘)读入一个整型数据,并入操作数栈。 
OUT    将栈顶单元内容出栈,并输出到标准输出设备上(显示器)。 
STOP   停止执行。

抽象机代码

// ConsoleApplication2.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。


#include <iostream>
using namespace std;
#include <stdio.h>
#include<string>
#include <ctype.h>
#include <stdlib.h>

//int TESTmachine();
extern void cifa();
extern void yufa();
int TESTmachine()
{
	int es = 0, i, k = 0;
	int codecount;//单词数
	int stack[1000] , stacktop = 0;//操作数栈,操作数栈顶
	char Codein[300];//文件路径
	char code[1000][20];//接收单词
	int data[1000]; //表示i地址的数据
	int label[100] = { 0 };//每个三元式的标号
	char lno[4];//
	FILE *fin;	//用于指向输入输出文件的指针
	printf("请输入目标文件名(包括路径):") ; 
	scanf("%s", Codein);
	if ((fin = fopen(Codein, "r")) == NULL)
	{
		printf("\n 打开%s错误!\n", Codein);
		es = 10;
		return(es);
	}
	codecount = 0;//先初始化单词数为0
	fscanf(fin, "%s", &code[codecount]);//将单词读入到code[i]字符数组中
	while (!feof(fin))//程序文件读入
	{
		
		i = strlen(code[codecount]) - 1;  
		if (code[codecount][i] == ':')  //查找字符数组“label:”符号
		{
			i = i - 5;
			for (int j = 0; j < i; j++)
			{
				lno[j] = code[codecount][j+5];
			}
			lno[i] = '\0';
			label[atoi(lno)] = codecount;	//用label数组记住每个标号的地址 lno是标签的数字 给每个单词标号
			printf("label[ %d]= %d \n", atoi(lno), label[atoi(lno)]);//输出label[i]在code字符数组中的位置
			code[codecount][i+5] = ':';
			code[codecount][i+6] = '\0';
			strcat(code[codecount], lno);//将标号与code[codecount]进行字符串连接操作
			k++;//暂时不晓得有什么用
		}
		codecount++;
		fscanf(fin, "%s", &code[codecount]);//继续读单词
	}
	fclose(fin);
	
	for (i = 0; i < codecount; i++) { // 处理
		int l = strlen(code[i]);
		if ((l > 1) && (code[i][1] == 'A')) {
			lno[0] = code[i][l - 1];
			lno[1] = '\0';
			itoa(label[atoi(lno)], code[i], 10);
		}
		printf("%s\n", code[i]);
	}

	i = 0;

	while (i < codecount)	//执行每条指令
	{
		//	printf("code % d %s \n", i,code[i]);
		if (strcmp(code[i], "LOAD") == 0)	  //LOAD 将D中的内容加载到操作数栈
		{
			i++;
			stack[stacktop] = data[atoi(code[i])];
			stacktop++;
		}
		else if (strcmp(code[i], "LOADI") == 0)	 //LOADI 将常量己压入操作数栈
		{
			i++;
			stack[stacktop] = atoi(code[i]);//字符串转int,栈顶保存数字
			stacktop++;
		}
		//STO D将操作数栈栈顶单元内容存入0,且栈顶单元内容保持不变 
		else if (strcmp(code[i], "STO") == 0)
		{
			i++;
			data[atoi(code[i])] = stack[stacktop - 1];//data[0]='0'
			printf("sto stack %d\n", stack[stacktop - 1]);//先输出栈顶元素
			printf("sto data %d\n", data[atoi(code[i])]);//输出data[0]的数据
		}
		//POP桟顶单元内容出桟 
		else if (strcmp(code[i], "POP") == 0)
		{
			stacktop--;
		}
		//八00将次桟顶单元与栈顶单元内容出栈并相加,和置于栈顶 
		else if (strcmp(code[i], "ADD") == 0)
		{
			stack[stacktop - 2] = stack[stacktop - 2] + stack[stacktop - 1];
			printf("add % d\n", stack[stacktop - 1]);
			stacktop--;
		}
		//SUB 将次栈顶单元减去栈顶单元内容并出栈,差置于栈顶 
		else if (strcmp(code[i], "SUB") == 0)
		{
			stack[stacktop - 2] = stack[stacktop - 2] - stack[stacktop - 1];
			stacktop--;
		}
		//MULT 将次栈顶单元与栈顶单元内容出栈并相乘,积置于栈顶 
		else if (strcmp(code[i], "MULT") == 0)
		{
			stack[stacktop - 2] = stack[stacktop - 2] * stack[stacktop - 1];
			printf("mult % d\n", stack[stacktop - 1]);
			stacktop--;
		}
		//DIV 将次栈顶单元与栈顶单元内容出栈并相除,商置于栈顶 
		else if (strcmp(code[i], "DIV") == 0)
		{
			stack[stacktop - 2] = stack[stacktop - 2] / stack[stacktop - 1];
			stacktop--;
		}
		//BR lab无条件转移到lab 
		else if (strcmp(code[i], "BR") == 0)
		{
			i++;
			i = atoi(code[i]);
		}
		//BRF lab检查栈顶单元逻辑值并出栈,若为假(0)则转移到lab 
		else if (strcmp(code[i], "BRF") == 0)
		{
			i++;
			if (stack[stacktop - 1] == 0) i = atoi(code[i]);
			stacktop--;
		}
		//EQ将栈顶两单元做等于比较并出栈,并将结果真或假(1或0)置于栈顶 
		else if (strcmp(code[i], "EQ") == 0)
		{
			stack[stacktop - 2] = stack[stacktop - 2] == stack[stacktop - 1];
			stacktop--;
		}
		//NOTEQ栈顶两单元做不等于比较并出栈,并将结果真或假(1或0)置于栈顶 
		else if (strcmp(code[i], "NOTEQ") == 0)
		{
			stack[stacktop - 2] = stack[stacktop - 2] != stack[stacktop - 1];
			stacktop--;
		}
		//GT 次栈顶大于栈顶操作数并出栈,则栈顶置1,否则置0 
		else if (strcmp(code[i], "GT") == 0)
		{
			stack[stacktop - 2] = stack[stacktop - 2] > stack[stacktop - 1];
			stacktop--;
		}
		//LES次桟顶小于栈顶操作数并出栈,则栈顶置1,否则置0 
		else if (strcmp(code[i], "LES") == 0)
		{
			stack[stacktop - 2] = stack[stacktop - 2] < stack[stacktop - 1];
			stacktop--;
		}
		//GE次栈顶大于等手栈顶操作数并出栈,则桟顶置1,否则置0 
		else if (strcmp(code[i], "GE") == 0)
		{
			stack[stacktop - 2] = stack[stacktop - 2] >= stack[stacktop - 1];
			stacktop--;
		}
		//LE次栈顶小于等于桟顶操作数并出栈,则栈顶置1,否则置0 
		else if (strcmp(code[i], "LE") == 0)
		{
			stack[stacktop - 2] = stack[stacktop - 2] <= stack[stacktop - 1];
			stacktop--;
		}
		//AND将栈顶两单元做逻辑与运算并出栈,并将结果真或假(1或0>置于栈顶 
		else if (strcmp(code[i], "AND") == 0)
		{
			stack[stacktop - 2] = stack[stacktop - 2] && stack[stacktop - 1];
			stacktop--;
		}
		//0R将栈顶两单元做逻辑或运算并出栈,并将结果真或假(1或0)置于栈顶 
		else if (strcmp(code[i], "OR") == 0)
		{
			stack[stacktop - 2] = stack[stacktop - 2] || stack[stacktop - 1];
			stacktop--;
		}
		//NOT将栈顶的逻辑值取反 
		else if (strcmp(code[i], "NOT") == 0)
		{
			stack[stacktop - 1] = !stack[stacktop - 1];
		}
		//IN从标准输入设备(键盘)读入一个整型数据,并入栈 
		else if (strcmp(code[i], "IN") == 0)
		{
			printf("请输入数据:");
			scanf("%d", &stack[stacktop]);
			stacktop++;
		}
		//OUT将栈顶单元内容出栈,并输出到标准输出设备上(显示器) 
		else if (strcmp(code[i], "OUT") == 0)
		{
		    i++;
			printf("程序输出 %d\n", data[atoi(code[i])]);
			stacktop--;
		}
		//STOP停止执行
		else if (strcmp(code[i], "STOP") == 0)
		{
		    printf("虚拟机运行成功\n");
			stack[stacktop] = '\n';
			return es=0;
		}
		i++;
	}
	return (es);
}
int main()
{
	int es = 0;
	cifa();//词法分析
	yufa();//语义分析
	es = TESTmachine();//调用抽象机代码运行模拟
}

抽象机运行结果: 

此实验代码并非博主所写,但是一个非完整代码(),博主进行补全并修改直至调通,大概耗时8小时。

评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值