编译原理项目——C++实现C语言编译器输出为8086级汇编(代码/报告材料)
完整的材料 代码见文章末尾 以下为核心内容和部分结果
项目介绍
一个小型的c语言编译器,实现的功能如下:
- 可以定义多个变量,并且能初始化。
- 可以支持基本的加减乘除运算。
- 可以支持带括号的多个变量的四则混合运算。
- 可以支持单行注释和多行注释。
- 可以输出%d格式的整数。
- 可以定义int 类型。
- 可以输出字符串。
- 可以输出2位整数
- 可以支持简单的if{}else{}语句。(大于和小于比较条件)
- 以上支持的语法可以混合在同一个源程序中。
- 部分错误语法可以报错。
环境
- 汇编器、MASM
- 汇编语言:8086汇编
- 源代码:C++,用VS2019
用masm打开生成的asm文件直接运行
设计流程
扫源代码 --> 词法分析 --> 语法分析 -->目标代码 --> 汇编代码
词法分析器的实现:使用正则表达式或有限状态机(Finite State Machine, FSM)来识别和生成词法单元。
语法分析器的实现:使用递归下降分析或者其他方法(如LR分析)构建语法分析器,生成抽象语法树。
语义分析:检查类型、作用域等语义信息,确保生成的代码符合语言规范。
中间代码生成:根据抽象语法树生成中间表示形式,如三地址码或四元式。
目标代码生成:将中间代码翻译为8086汇编代码,考虑寄存器分配、指令选择等。
汇编代码生成:将生成的汇编代码输出为文件,或直接进行后续的汇编和链接操作。
部分核心代码展示(asm文件)
#include"asm.h"
#include"define.h"
extern vector<Target> target_code;
extern vector<Variable> var_table;
extern char lab;
string asmfile(string source)
{
if (source.size() == 0)
{
cout << "源文件名不能为空" << endl;
exit(-1);
}
string temp = "";
int i, j;
j = source.size();
for (i = j - 1; i >= 0; i--)
{
// if(source[i] == '\\' || source[i]== '/')
// break;
if (source[i] == '.')
{
j = i;
break;
}
}
temp = source.substr(0, j) + ".asm";
return temp;
}
void add_target_code(string dsf, string op, string dst, string dsc, string mark, string step)
{
Target tmp;
tmp.dsf = dsf;
tmp.op = op;
tmp.dst = dst;
tmp.dsc = dsc;
tmp.mark = mark;
tmp.step = step;
target_code.push_back(tmp);
}
void addsub_asm(ofstream& out, string dsf, string op, string dst, string dsc)
{
out << " mov BL," << dst << endl;
if (op == "+")
out << " add BL," << dsc << endl;
else
out << " sub BL," << dsc << endl;
out << " mov " << dsf << ",BL" << endl;
}
void mul_asm(ofstream& out, string dsf, string dst, string dsc)
{
out << " mov AL," << dst << endl;
out << " mov BH," << dsc << endl;
out << " mul BH" << endl;
out << " mov BL,1" << endl;
out << " div BL" << endl;
out << " mov " << dsf << ",AL" << endl;
}
void div_asm(ofstream& out, string dsf, string dst, string dsc)
{
out << " mov AL," << dst << endl;
out << " CBW" << endl;
out << " mov BL," << dsc << endl;
out << " div BL" << endl;
out << " mov " << dsf << ",AL" << endl;
}
void sign_asm(ofstream& out, string dsf, string dst)
{
out << " mov BL," << dst << endl;
out << " mov " << dsf << ",BL" << endl;
}
void print_asm(ofstream& out, string dsf, string mark)
{
//以字符格式输出
if (mark == "%c")
{
out << " mov DL," << dsf << endl;
out << " mov AH,02H" << endl;
out << " int 21H" << endl;
}
//以整数格式输出
else if (mark == "%d")
{
out << " mov AL," << dsf << endl;
out << " CBW" << endl;
out << " mov BL,10" << endl;
out << " DIV BL" << endl;
out << " mov BH,AH" << endl;
out << " add BH,30H" << endl;
out << " add AL,30H" << endl;
out << " CMP AL,48" << endl;
//确定十位是否是0
lab = lab + 2;
string step2 = "step" + char_to_str(lab);
out << " JE " << step2 << endl;
string step1 = "step" + char_to_str(lab - 1);
out << " " << step1 << ":" << endl;
out << " mov DL,AL" << endl;
out << " mov AH,2" << endl;
out << " int 21H" << endl;
//输出个位
out << " " << step2 << ":" << endl;
out << " mov DL,BH" << endl;
out << " mov AH,2" << endl;
out << " int 21H" << endl;
}
//字符串输出
else
{
out << " LEA DX," << mark << endl;
out << " mov AH,09" << endl;
out << " int 21H" << endl;
}
}
void if_asm(ofstream& out, string dst, string dsc, string mark, string step)
{
out << " mov AL," << dst << endl;
out << " CMP AL," << dsc << endl;
if (mark == ">")
out << " JG " << step << endl;
else if (mark == "<")
out << " JL " << step << endl;
else
{
cout << "暂不支持其他条件判断" << endl;
exit(-1);
}
}
void create_asm(string file)
{
//变量声明
ofstream wfile(file.c_str());
if (!wfile.is_open())
cout << "无法创建汇编文件" << endl;
vector<Variable>::iterator it_var;
wfile << "ASSUME CS:codesg,DS:datasg" << endl;
//数据段
wfile << "datasg segment" << endl;
for (it_var = var_table.begin(); it_var != var_table.end(); it_var++)
{
wfile << " " << it_var->var << " DB ";
if (it_var->value != "")
wfile << it_var->value << endl;
else
wfile << "\'?\'" << endl;
}
wfile << "datasg ends" << endl;
//代码段
wfile << "codesg segment" << endl;
wfile << " start:" << endl;
wfile << " mov AX,datasg" << endl;
wfile << " mov DS,AX" << endl;
vector<Target>::iterator it;
Target tmp;
for (it = target_code.begin(); it != target_code.end(); it++)
{
//加减法转化
if (it->op == "+" || it->op == "-")
addsub_asm(wfile, it->dsf, it->op, it->dst, it->dsc);
//乘法转换
else if (it->op == "*")
mul_asm(wfile, it->dsf, it->dst, it->dsc);
//除法转换
else if (it->op == "/")
div_asm(wfile, it->dsf, it->dst, it->dsc);
//赋值运算
else if (it->op == "=")
sign_asm(wfile, it->dsf, it->dst);
//输出操作
else if (it->op == "p")
print_asm(wfile, it->dsf, it->mark);
//if语法分析
else if (it->op == "if")
{
if_asm(wfile, it->dst, it->dsc, it->mark, it->step);
}
else if (it->op == "else")
{
cout << "else 没有找到匹配的 if" << endl;
exit(-1);
}
//跳转语句
else if (it->op == "jmp")
{
wfile << " JMP " << it->step << endl;
}
//跳转语句段标识
else if (it->op == "pstep")
{
wfile << " " << it->step << ":" << endl;
}
//其他
else
{
cout << "编译器暂不支持该语法操作" << endl;
exit(-1);
}
}
//代码段结束
wfile << " mov ax,4C00H" << endl;
wfile << " int 21H" << endl;
wfile << "codesg ends" << endl;
wfile << " end start" << endl;
wfile.close();
}
asmfile,生成汇编文件的名称。
执行逻辑:
- 检查源文件名是否为空,如果为空则报错退出。
- 从源文件名中去掉扩展名,并添加.asm作为新文件名的扩展名。
- 返回生成的汇编文件名。
add_target_code,将目标代码添加到目标代码向量中。
执行逻辑:
- 创建一个临时的Target结构体,赋值各个字段。
- 将该结构体添加到目标代码向量中。
addsub_asm,生成加法和减法的汇编代码。
执行逻辑:
- 将目的操作数加载到寄存器BL。
- 根据操作符执行加法或减法运算。
- 将结果存储到目标操作数中。
mul_asm,生成乘法的汇编代码。
执行逻辑:
- 将目的操作数加载到寄存器AL。
- 将源操作数加载到寄存器BH。
- 执行乘法运算,并将结果存储在AL中。
- 将结果存储到目标操作数中。
div_asm,生成除法的汇编代码。
执行逻辑:
- 将目的操作数加载到寄存器AL。
- 执行符号扩展(CBW)。
- 将源操作数加载到寄存器BL。
- 执行除法运算,并将结果存储在AL中。
- 将结果存储到目标操作数中。
sign_asm,生成赋值运算的汇编代码。
执行逻辑:
- 将源操作数加载到寄存器BL。
- 将结果存储到目标操作数中。
print_asm,生成输出操作的汇编代码。
执行逻辑:
- 根据标记符(%c或%d)判断输出格式。
- 如果是字符输出,加载字符到寄存器DL并调用中断21H。
- 如果是整数输出,执行整数的转换和输出。
- 如果是字符串输出,加载字符串地址到寄存器DX并调用中断21H。
if_asm,生成if语句的汇编代码。
执行逻辑:
- 将目的操作数加载到寄存器AL。
- 比较目的操作数和源操作数。
- 根据条件标记符(>或<)生成相应的条件跳转指令。
create_asm,生成汇编文件。
执行逻辑:
- 打开汇编文件进行写操作。
- 写入数据段和代码段的开始部分。
- 遍历目标代码向量,生成相应的汇编代码(加法、减法、乘法、除法、赋值、输出、if语句、跳转等)。
- 写入代码段的结束部分,并关闭文件。
结果展示
测试文件如下:
main()
{
int a,b;
a = 4;
b = 2;
if(a>b)
{
a = a+1;
}
if(b<1)
{
b = b-1;
}
else
{
b = b+1;
}
printf("a=%d b=%d",a,b);
}
8086汇编如下:
ASSUME CS:codesg,DS:datasg
datasg segment
a DB '?'
b DB '?'
tmpB DB '?'
tmpC DB '?'
tmpD DB '?'
tmpE DB 'a=$'
tmpF DB ' b=$'
datasg ends
codesg segment
start:
mov AX,datasg
mov DS,AX
mov BL,4
mov a,BL
mov BL,2
mov b,BL
mov AL,a
CMP AL,b
JG stepB
JMP stepC
stepB:
mov BL,a
add BL,1
mov tmpB,BL
mov BL,tmpB
mov a,BL
JMP stepC
stepC:
mov AL,b
CMP AL,1
JL stepD
mov BL,b
add BL,1
mov tmpC,BL
mov BL,tmpC
mov b,BL
JMP stepE
stepD:
mov BL,b
sub BL,1
mov tmpD,BL
mov BL,tmpD
mov b,BL
JMP stepE
stepE:
LEA DX,tmpE
mov AH,09
int 21H
mov AL,a
CBW
mov BL,10
DIV BL
mov BH,AH
add BH,30H
add AL,30H
CMP AL,48
JE stepG
stepF:
mov DL,AL
mov AH,2
int 21H
stepG:
mov DL,BH
mov AH,2
int 21H
LEA DX,tmpF
mov AH,09
int 21H
mov AL,b
CBW
mov BL,10
DIV BL
mov BH,AH
add BH,30H
add AL,30H
CMP AL,48
JE stepI
stepH:
mov DL,AL
mov AH,2
int 21H
stepI:
mov DL,BH
mov AH,2
int 21H
mov ax,4C00H
int 21H
codesg ends
end start
获取方式
点这里 只需要一点点辛苦费,不需要你写材料 报告。