编译原理项目——C++实现C语言编译器输出为8086级汇编(代码/报告材料)

news2024/11/16 2:31:34

完整的材料 代码见文章末尾 以下为核心内容和部分结果

项目介绍

一个小型的c语言编译器,实现的功能如下:

  1. 可以定义多个变量,并且能初始化。
  2. 可以支持基本的加减乘除运算。
  3. 可以支持带括号的多个变量的四则混合运算。
  4. 可以支持单行注释和多行注释。
  5. 可以输出%d格式的整数。
  6. 可以定义int 类型。
  7. 可以输出字符串。
  8. 可以输出2位整数
  9. 可以支持简单的if{}else{}语句。(大于和小于比较条件)
  10. 以上支持的语法可以混合在同一个源程序中。
  11. 部分错误语法可以报错。

环境

  • 汇编器、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

获取方式

点这里 只需要一点点辛苦费,不需要你写材料 报告。

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2104723.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

指数分布的两种形式

指数分布是连续概率分布的一种&#xff0c;常用于描述等待时间、寿命等随机变量的分布。 1. 标准形式的指数分布 标准形式的指数分布的概率密度函数&#xff08;PDF&#xff09;为&#xff1a; f ( x ; λ ) { λ e − λ x if x ≥ 0 0 if x < 0 f(x; \lambda) \begi…

MYSQL:删除指定时间范围内每个电站每天发电数据除最大值以外的记录

有一个需求&#xff0c;需要保留每个电站每一天发电数据的最大值记录&#xff0c;其余删除。 表数据大概长这样&#xff1a; MYSQL 5.7写法&#xff1a;&#xff08;因为不支持ROW_NUMBER()函数&#xff0c;采用自定义的变量来代替&#xff09; 首次清理一年内数据&#xff1…

5是否有路通向AGI

5.1是否有路通向AGI

如何在算家云搭建模型Stable-diffusion-webUI(AI绘画)

一、Stable Diffusion WebUI简介 Stable Diffusion WebUI 是一个网页版的 AI 绘画工具&#xff0c;基于强大的绘画模型Stable Diffusion &#xff0c;可以实现文生图、图生图等。 二、模型搭建流程 1.选择主机和镜像 &#xff08;1&#xff09;进入算家云的“应用社区”&am…

一本书加印19次,回答小伙伴们几个写书的疑问

前几天又有一个高校老师加松哥微信&#xff0c;表示本学期选了松哥的书做教材&#xff1a; 松哥在 2019 年 1 月份出版了《Spring BootVue 全栈开发实战》这本书&#xff0c;到现在已经是第六年了。 今年 1 月份收到出版社稿酬的时候&#xff0c;我特意去看了下稿酬通知单&…

渣土车识别算法解决城市治理难题

随着城市化进程的加速&#xff0c;渣土车作为建筑工程中不可或缺的运输工具&#xff0c;其频繁的穿行和装载运输过程往往引发一系列问题&#xff0c;如超载、扬尘污染、乱倒渣土等&#xff0c;对城市环境和交通秩序造成了不良影响。为了解决这些问题&#xff0c;采用基于视觉分…

一文教你StableDiffusion图生图批量处理!

今天给大家讲解一下SD图生图的批量处理功能应该如何使用&#xff5e; 一、图生图批量处理功能的基本用法 首先打开webUI&#xff0c;在图生图页面下我们先找到批量处理的菜单&#xff1a; 最简单的批量处理方法只需要用到【输入目录】和【输出目录】两个功能&#xff1a; 第一…

Java:正则表达式 matches

文章目录 正则表达式作用基本用法小结代码 案例&#xff1a;校验用户输入的电话&#xff0c;邮箱&#xff0c;是否合法\\.是什么意思 黑马学习笔记 正则表达式 由一些特定的字符组成&#xff0c;代表的是一个规则 作用 用来校验数据格式是否合法在一段文本中查找满足要求的内…

计算机毕业设计选题推荐-高校科研工作管理系统-Java/Python项目实战

✨作者主页&#xff1a;IT毕设梦工厂✨ 个人简介&#xff1a;曾从事计算机专业培训教学&#xff0c;擅长Java、Python、微信小程序、Golang、安卓Android等项目实战。接项目定制开发、代码讲解、答辩教学、文档编写、降重等。 ☑文末获取源码☑ 精彩专栏推荐⬇⬇⬇ Java项目 Py…

【GIS开发小课堂】vue3+Cesium.js三维WebGIS项目实战(一)

随着市场对数字孪生的需求日益增多&#xff0c;对于前端从业者的能力从对框架vue、react的要求&#xff0c;逐步扩展到2D、3D空间的交互&#xff0c;为用户提供更紧密的立体交互。近年来前端对GIS的需求日益增多。 本文档详细介绍了使用Vue3和Cesium.js构建三维WebGIS项目的步骤…

数据结构07

文章目录 二叉树的坡度二叉树的右视图 二叉树的坡度 /*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode() : val(0), left(nullptr), right(nullptr) {}* TreeNode(int x) : val(x), l…

配置vscode终端自动激活anaconda的python环境

前言 每次使用vscode写python代码的时候&#xff0c;都需要在外面跑一个anaconda prompt&#xff0c;激活环境&#xff0c;然后进入对应的文件夹&#xff0c;运行代码&#xff0c;特别麻烦&#xff0c;所以想&#xff0c;能不能直接在vscode终端里面激活环境然后运行。 第一步…

FIFO求和实验

前言 FIFO&#xff08;先进先出&#xff09;队列在图像处理中的应用非常广泛&#xff0c;特别是在需要处理实时数据流和保证数据顺序的场景中。以下是一些具体应用实例&#xff1a;在实时视频流处理中&#xff0c;FIFO队列用于缓存图像帧。这样可以确保图像数据按照捕获顺序被处…

828华为云征文|华为云Flexus X实例docker部署harbor镜像仓库

828华为云征文&#xff5c;华为云Flexus X实例docker部署harbor镜像仓库 华为云最近正在举办828 B2B企业节&#xff0c;Flexus X实例的促销力度非常大&#xff0c;特别适合那些对算力性能有高要求的小伙伴。如果你有自建MySQL、Redis、Nginx等服务的需求&#xff0c;一定不要错…

如何培养积极的心态:策略与建议

积极的心态是通往幸福与成功的关键。它不仅影响着我们的日常生活质量&#xff0c;还决定了我们在面对困难时的态度和反应。本文将介绍一些实用的方法&#xff0c;帮助你建立并维持一种积极向上的生活态度。 积极心态的意义 拥有积极心态的人往往能够&#xff1a; 更快地恢复…

avi转换成mp4,这6种方法助你快速转换

视频格式的兼容性一直是用户关注的焦点。AVI作为一种较老的视频格式&#xff0c;虽然在一些特定场合下仍有应用&#xff0c;但MP4格式因其广泛的兼容性和较小的文件体积&#xff0c;已成为主流的视频格式。本文将详细介绍六种将AVI转换成MP4的方法&#xff0c;一起来了解下吧。…

安卓手机照片误删? 2024最新恢复办法分享

不小心将安卓手机照片误删了&#xff0c;该怎么办呢&#xff1f;相信不少人都遇到过类似困扰&#xff0c;别担心&#xff0c;下面小编就分享几种华为手机数据恢复办法&#xff0c;助大家快速找回误删照片。 方法一&#xff1a;从「回收站」中恢复照片 安卓手机通常都具备回收站…

17 连接池原理

可以设计一个mysql的连接池&#xff0c;提高效率 提前建立一个连接池&#xff0c;这里面创建线程池&#xff0c;和mysql建立连接&#xff0c;维护一个任务队列。有任务到来时&#xff0c;将任务放入任务队列&#xff0c;任务结构是要执行的sql语句和需要的回调函数&#xff0c…

信息化项目验收测试的必要性,第三方软件测评机构的进行步骤

随着信息化时代的到来&#xff0c;各类软件项目在企业中得到了越来越广泛的应用。为了保障项目的顺利交付&#xff0c;确保软件系统的功能、性能和稳定性&#xff0c;验收测试成为了一个不可或缺的环节。 一、信息化项目验收测试   信息化项目验收测试是对软件项目最终成果进…

py脚本 银行帐号格式化显示4个数字一组

假设你想要将银行帐号以某种特定的格式&#xff08;例如&#xff0c;每 4 位数字加一个空格&#xff09;进行格式化。 示例代码 以下是一个示例 Python 脚本&#xff0c;将银行帐号格式化为每 4 位数字加一个空格的形式&#xff1a; def format_bank_account(account_number…