当前位置: 首页 > news >正文

编译原理Lab. 1 初代编译器实验说明和要求

目录

  • Lab. 1 初代编译器实验说明和要求
    • 一、初代编译器功能描述
    • 二、初代编译器文法要求
    • 三、初代编译器测试样例
    • 四、初代编译器提交要求
    • 五、初代编译器实验测试框架说明
  • 代码与思路

Lab. 1 初代编译器实验说明和要求

一、初代编译器功能描述

初代编译器将 C 语言顺序语句序列翻译为等价的汇编程序,所输出的汇编程序符合 x86 汇编语言格式要求,能够被后续的汇编器翻译为可执行程序运行。

二、初代编译器文法要求

初代编译器能够处理的文法如下所示:

关键字int return
标识符:单个英文字母
常量:十进制整型,如 122310
操作符=+-*/()
分隔符;
语句:表达式语句、赋值语句,其中表达式语句包含括号及括号嵌套;

三、初代编译器测试样例

测试用例难度分为两个等级:其中第一个等级每个表达式中操作符优先级相同,且无括号;第二个等级同一个表达式中会有不同优先级,且包含有嵌套的括号。测试用例中,第一个等级测试用例占比 90%,第二个等级的测试用例占比 10%。

所有输入测试样例文件中单词之间均由空格或者回车分隔,输入文件中可能存在多个连续的空格或者回车。

评分依据 return 的值是否符合预期。

等级一输入样例:

int a ;
int b ;
int d ;
a = 1 ;
b = 2 ;
d = a + b ;
return d ;
(预期返回值为 3)

等级一输出样例 x86:

mov DWORD PTR [ebp-4], 0 # int a
mov DWORD PTR [ebp-8], 0 # int b
mov DWORD PTR [ebp-12], 0 # int d
mov DWORD PTR [ebp-4], 1 # a = 1
mov DWORD PTR [ebp-8], 2 # b = 2
mov eax, DWORD PTR [ebp-4] # d = a + b
push eax
mov eax, DWORD PTR [ebp-8]
push eax
pop ebx
pop eax
add eax, ebx
push eax
pop eax
mov DWORD PTR [ebp-12], eax
mov eax, DWORD PTR [ebp-12] # return d

等级二输入样例:

int a ;
int b ;
int c ;
int d ;
a = 1 ;
b = 2 ;
c = 3 ;
d = ( a + b * 2 ) / c – 3 ;
return d ;
(预期返回值为-2)

等级二输出样例 x86:

用例 2 的期待输出: (你的输出中不必输出#行的内容)
# int a ;
mov DWORD PTR [ebp-4], 0
# int b ;
mov DWORD PTR [ebp-8], 0
# int c ;
mov DWORD PTR [ebp-12], 0 
# int d ;
mov DWORD PTR [ebp-16], 0
# a = 1 ;
mov DWORD PTR [ebp-4], 1
# b = 2 ;
mov DWORD PTR [ebp-8], 2
# c = 3 ;
mov DWORD PTR [ebp-12], 3
# d = ( a + b * 2 ) / c - 3
mov eax, DWORD PTR [ebp-4]
push eax
mov eax, DWORD PTR [ebp-8]
push eax
mov eax, 2
push eax
pop ebx
pop eax
imul eax, ebx
push eax
pop ebx
pop eax
add eax, ebx
push eax
mov eax, DWORD PTR [ebp-12]
push eax
pop ebx
pop eax
cdq
idiv ebx
push eax
mov eax, 3
push eax
pop ebx
pop eax
sub eax, ebx
push eax
pop eax
mov DWORD PTR [ebp-16], eax
# return d
mov eax, DWORD PTR [ebp-16]

四、初代编译器提交要求

实现语言:C++(语言标准 c++14)

编译环境:g++ -11

测试环境:gcc -11

提交内容:单个 cpp 源文件,文件名称为 compilerlab1.cpp

输入输出:实现的编译器有一个命令行参数,用于指明输入文件路径,编译器从该路径读取源码,并向 stdout 输出编译结果。

注:g++用于编译你提交的编译器实验源码,gcc 用于将你的编译器实验输出的 x86 汇编码编译成可执行文件,用于测试。

五、初代编译器实验测试框架说明

为了方便测试,实验提供了一个测试框架,用于测试你的编译器实验。

x86 汇编的测试框架:

.intel_syntax noprefix # 使用 Intel 语法
.global main # 声明 main 函数为全局符号,这使得链接器能够识别程序
的入口点。
.extern printf # 声明外部函数 printf,表示该函数在其他地方定义,通
常是 C 标准库中。
.data # 开始数据段,用于定义程序中的初始化数据。
format_str:.asciz "%d\n" # 定义一个用于 printf 的格式字符串,输出整数并换行。
.text # 开始代码段,包含程序的实际指令。
main:push ebp # 将基指针寄存器 ebp 的当前值压入堆栈,保存上一个函
数栈帧的基指针mov ebp, esp # 将栈指针 esp 的值复制到基指针 ebp ,设置新的栈帧
基指针sub esp, 0x100 # 从栈指针 esp 减去 256 字节,为局部变量分配栈空间
##################################################
##
## 你的编译器实验输出的 x86 汇编码将被插入到这里
##
################################################### 打印 d (当前 eax 的值)push eax # 将结果 (eax 的值) 作为 printf 的参数push offset format_str # 将格式字符串的地址作为 printf 的参数call printf # 调用 printf 函数add esp, 8 # 清理栈# 恢复 eax 的值并退出 mainpop eaxleaveret

你的编译器实验输出的 x86 汇编码将会被插入到上述框架中。

为了便于评测,本实验框架将会自动调用 C 库的 printf 函数,输出你的编译器实验输出的 x86 汇编码中的返回值(即 eax 的内容)。

代码与思路

考虑到代码会查重,以及隔壁3月16号大哥的惨案,我不会给出具体的代码。(至少要过半年我才会补上代码)

请同学们自己完成代码。

我会给出一些实验注意事项,该部分主要阐述本人在做该实验时踩过的坑,为大家提供一部分参考。

  1. 注意按照平台要求的命令行输入输出,否则提交无效
  2. 关于测试用例8:需要处理可能出现的回车,可能出现一条语句中间被回车截断,如
int a ;
a 
= 
1
;			// 一条语句 a = 1 ; 被拆成了多行输入
return a
;
// 还可能会出现同一行多条语句,例如:
int b ; int c ; b = 1 ; c = 2 ;

请注意以上情况。

  1. 关于测试用例3和7:注意处理直接赋变量的值的语句,如
int a ;
int b ;
a = 1 ;			// 对于这一句,直接把1存入a即可,即 mov DWORD PTR [ebp-4], 1 
b = a ;			// 对于这一句,容易写成把a的值直接mov到b中;然而这样做是错的,要先从a取出放到eax,再从eax取出放到b
return b ;

这里再贴两组用例供大家测试。

输入用例 3: (试试直接赋值,顺便试试大写字母)

int a ;
int A ;
int B ;
a = 1 ;
A = a ;
B = A / a ;
return B ;

用例 3 的期待输出: (你的输出不必像我这里特意搞空行)

mov DWORD PTR [ebp-4], 0mov DWORD PTR [ebp-8], 0mov DWORD PTR [ebp-12], 0mov DWORD PTR [ebp-4], 1mov eax, DWORD PTR [ebp-4]
mov DWORD PTR [ebp-8], eaxmov eax, DWORD PTR [ebp-8]
push eax
mov eax, DWORD PTR [ebp-4]
push eax
pop ebx
pop eax
cdq
idiv ebx
push eax
pop eax
mov DWORD PTR [ebp-12], eaxmov eax, DWORD PTR [ebp-12]

输入用例 4: (莫名其妙的换行)

int
p
; int q ; p =
1 
; 
q
= p 
+
p ; return 
q 
;

用例 4 的期待输出: (你的输出不必像我这里特意搞空行)

mov DWORD PTR [ebp-4], 0mov DWORD PTR [ebp-8], 0mov DWORD PTR [ebp-4], 1mov eax, DWORD PTR [ebp-4]
push eax
mov eax, DWORD PTR [ebp-4]
push eax
pop ebx
pop eax
add eax, ebx
push eax
pop eax
mov DWORD PTR [ebp-8], eaxmov eax, DWORD PTR [ebp-8]

以上。

someday,我会把我的代码补充进来,顺便在git上再发一份

但不是现在:)


发布后的一小时后补充

我忘记写思路了2333

你可以直接 if

  • 如果遇到了 int,就输出 mov DWORD PTR [ebp-%d], 0
  • 如果遇到了 =,就说明是等式,可能是赋值,或可能是算式
  • 如果遇到了 return,就输出 mov eax, DWORD PTR [ebp-%d],并结束程序

对于遇到了 =

  • 右边只有一个数字
  • 右边只有一个字母
  • 如果不是前两者,说明是算式

如果是算式:

  • 用我们以前学过的和栈有关的知识去做
  • 下面是我的处理手段
    • 定义两个栈:op 用来存储符号,v 用来存储值
    • 如果是数字
    • 如果是字母
    • 如果既不是数字也不是字母,那就说明是符号:
      • 如果是 (
      • 如果是 )
      • 如果是 */
      • 如果是 +-
      • 当然,你也可以先转换成前缀表或者后缀表达式,再用相应的方法处理,自己去百度吧

你也可以使用正则表达式

如果这些方法都不合你的胃口,那你问问身边的人,方法真的很多。

我就点到为止吧,剩下的靠你们自己了(笔芯)。

祝大家早日AC

如果有什么思路上的问题或者编译上的问题总之跟这个实验有关的都可以问,我要是有空会回答的。

相关文章:

编译原理Lab. 1 初代编译器实验说明和要求

目录 Lab. 1 初代编译器实验说明和要求一、初代编译器功能描述二、初代编译器文法要求三、初代编译器测试样例四、初代编译器提交要求五、初代编译器实验测试框架说明 代码与思路 Lab. 1 初代编译器实验说明和要求 一、初代编译器功能描述 初代编译器将 C 语言顺序语句序列翻…...

python判断工作日,节假日

一、概述 需要判断一个日期是否为工作日,节假日。 找到一个现成的插件,蛮好用的。 插件介绍 https://pypi.org/project/chinesecalendar/ 判断某年某月某一天是不是工作日/节假日。 支持 2004年 至 2020年,包括 2020年 的春节延长。 兼容…...

练习4-权重衰减(李沐函数简要解析)

环境:练习1的环境 代码详解 0.导入库 import torch from torch import nn from d2l import torch as d2l1.初始化数据 这里初始化出train_iter test_iter 可以查一下之前的获取Fashion数据集后的数据格式与此对应 n_train, n_test, num_inputs, batch_size 20, 100, 200, …...

websocket 中 request-line 中的URI编码问题

首先,request-line组成如下: Request-Line Method SP Request-URI SP HTTP-Version CRLF 在 rfc6455 规范的 5.1.2 Request-URI 中,有这样的描述: The Request-URI is transmitted in the format specified in section 3.2.1. …...

为何ChatGPT日耗电超50万度?

看新闻说,ChatGPT每天的耗电量是50万度,国内每个家庭日均的耗电量不到10度,ChatGPT耗电相当于国内5万个家庭用量。 网上流传,英伟达创始人黄仁勋说:“AI的尽头是光伏和储能”,大佬的眼光就是毒辣&#xff…...

__init__.py 的作用

在 Python 中,包含一个名为 __ init __.py 的文件的目录被称为一个包(package)。 __ init __.py 文件的作用有以下几点: 指示包含该文件的目录是一个 Python 包:当 Python 导入一个包时,会查找该包所在目录…...

Redis到底是多线程还是单线程?

Redis6.0之前:是单线程模式。 Redis6.0之后:Redis的IO线程是多线程,worker线程是单线程。 Redis6.0之前:单线程 Redis6.0之后:Redis的IO线程是多线程,worker线程是单线程。...

JAVA 100道题(18)

18.实现一个除法运算的方法,能够处理被除数为零的情况,并抛出异常。 在Java中,你可以创建一个除法运算的方法,该方法接受两个整数作为参数,分别代表被除数和除数。如果被除数为零,你可以抛出一个自定义的异…...

【C++】每日一题 137 只出现一次的数字

给你一个整数数组 nums &#xff0c;除某个元素仅出现 一次 外&#xff0c;其余每个元素都恰出现 三次 。请你找出并返回那个只出现了一次的元素。 你必须设计并实现线性时间复杂度的算法且使用常数级空间来解决此问题。 #include <vector>int singleNumber(std::vecto…...

RAG进阶笔记:RAG进阶

1 查询/索引部分 1.1 层次索引 创建两个索引——一个由摘要组成&#xff0c;另一个由文档块组成分两步进行搜索&#xff1a;首先通过摘要过滤出相关文档&#xff0c;接着只在这个相关群体内进行搜索 1.2 假设性问题 让LLM为每个块生成一个假设性问题&#xff0c;并将这些问…...

《论文阅读》带边界调整的联合约束学习用于情感原因对提取 ACL 2023

《论文阅读》带边界调整的联合约束学习用于情感原因对提取 前言简介Clause EncoderJoint Constrained LearningBoundary Adjusting损失函数前言 亲身阅读感受分享,细节画图解释,再也不用担心看不懂论文啦~ 无抄袭,无复制,纯手工敲击键盘~ 今天为大家带来的是《Joint Cons…...

【微服务】接口幂等性常用解决方案

一、前言 在微服务开发中&#xff0c;接口幂等性问题是一个常见却容易被忽视的问题&#xff0c;同时对于微服务架构设计来讲&#xff0c;好的幂等性设计方案可以让程序更好的应对一些高并发场景下的数据一致性问题。 二、幂等性介绍 2.1 什么是幂等性 通常我们说的幂等性&…...

RocketMQ学习笔记:零拷贝

这是本人学习的总结&#xff0c;主要学习资料如下 马士兵教育rocketMq官方文档 目录 1、零拷贝技术1.1、什么是零拷贝1.2、mmap()1.3、Java中的零拷贝 1、零拷贝技术 1.1、什么是零拷贝 使用传统的IO&#xff0c;从硬盘读取数据然后发送到网络需要经过四个步骤。 通过DMA复…...

3.26日总结

1.Fliptile Sample Input 4 4 1 0 0 1 0 1 1 0 0 1 1 0 1 0 0 1 Sample Output 0 0 0 0 1 0 0 1 1 0 0 1 0 0 0 0 题意&#xff1a;在题目输入的矩阵&#xff0c;在这个矩阵的基础上&#xff0c;通过最少基础反转&#xff0c;可以将矩阵元素全部变为0&#xff0c;如果不能达…...

应用日志集成到ElasticSearch

1、阿里云sls平台集成日志 阿里sls集成日志步骤 2、filebeat 收集到指定es 安装docker容器 Docker安装 拉取镜像&#xff1a; docker pull elastic/filebeat:7.5.1启动&#xff1a; docker run -d --namefilebeat elastic/filebeat:7.5.1拷贝容器中的数据文件到宿主机&a…...

MySQL多表联查函数

1 多表联查 1.1 表之间的关系 表和表的关系有: 一对一 老公 --> 老婆 , 人 ---> 身份证/户口本 一对多 皇帝 --> 妻妾 , 人 ---> 房/车 多对多 订单 --> 商品 1.2 合并结果集 合并结果集,是将多表查询的结果纵向合并 语法: select field1,field2 from t1 un…...

JAVAEE—实现多线程版本的定时器

文章目录 什么是定时器定时器的概念定时器的简单应用和介绍代码示例 定时器的代码解析定时器在执行任务的时候是创建了一个线程去执行吗&#xff1f;为什么叫做扫描线程呢&#xff1f;执行完任务之后代码就暂停了不自动结束吗&#xff1f; 手撕定时器demo相对时间与绝对时间Myt…...

KY228 找位置(用Java实现)

描述 对给定的一个字符串&#xff0c;找出有重复的字符&#xff0c;并给出其位置&#xff0c;如&#xff1a;abcaaAB12ab12 输出&#xff1a;a&#xff0c;1&#xff1b;a&#xff0c;4&#xff1b;a&#xff0c;5&#xff1b;a&#xff0c;10&#xff0c;b&#xff0c;2&…...

物联网边缘网关有哪些优势?-天拓四方

随着物联网技术的快速发展&#xff0c;越来越多的设备接入网络&#xff0c;数据交互日益频繁&#xff0c;对数据处理和传输的要求也越来越高。在这样的背景下&#xff0c;物联网边缘网关应运而生&#xff0c;以其低延迟、减少带宽消耗、提高数据质量和安全性等优势&#xff0c;…...

【C++】6-2 交换函数2 分数 10

6-2 交换函数2 分数 10 全屏浏览 切换布局 作者 刘利 单位 惠州学院 根据题目需求&#xff0c;编写一个交换函数Swap。 裁判测试程序样例&#xff1a; #include <iostream> using namespace std; class pen{private:string brand;string color;double price;publi…...

XML Group端口详解

在XML数据映射过程中&#xff0c;经常需要对数据进行分组聚合操作。例如&#xff0c;当处理包含多个物料明细的XML文件时&#xff0c;可能需要将相同物料号的明细归为一组&#xff0c;或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码&#xff0c;增加了开…...

应用升级/灾备测试时使用guarantee 闪回点迅速回退

1.场景 应用要升级,当升级失败时,数据库回退到升级前. 要测试系统,测试完成后,数据库要回退到测试前。 相对于RMAN恢复需要很长时间&#xff0c; 数据库闪回只需要几分钟。 2.技术实现 数据库设置 2个db_recovery参数 创建guarantee闪回点&#xff0c;不需要开启数据库闪回。…...

进程地址空间(比特课总结)

一、进程地址空间 1. 环境变量 1 &#xff09;⽤户级环境变量与系统级环境变量 全局属性&#xff1a;环境变量具有全局属性&#xff0c;会被⼦进程继承。例如当bash启动⼦进程时&#xff0c;环 境变量会⾃动传递给⼦进程。 本地变量限制&#xff1a;本地变量只在当前进程(ba…...

模型参数、模型存储精度、参数与显存

模型参数量衡量单位 M&#xff1a;百万&#xff08;Million&#xff09; B&#xff1a;十亿&#xff08;Billion&#xff09; 1 B 1000 M 1B 1000M 1B1000M 参数存储精度 模型参数是固定的&#xff0c;但是一个参数所表示多少字节不一定&#xff0c;需要看这个参数以什么…...

线程同步:确保多线程程序的安全与高效!

全文目录&#xff1a; 开篇语前序前言第一部分&#xff1a;线程同步的概念与问题1.1 线程同步的概念1.2 线程同步的问题1.3 线程同步的解决方案 第二部分&#xff1a;synchronized关键字的使用2.1 使用 synchronized修饰方法2.2 使用 synchronized修饰代码块 第三部分&#xff…...

Swift 协议扩展精进之路:解决 CoreData 托管实体子类的类型不匹配问题(下)

概述 在 Swift 开发语言中&#xff0c;各位秃头小码农们可以充分利用语法本身所带来的便利去劈荆斩棘。我们还可以恣意利用泛型、协议关联类型和协议扩展来进一步简化和优化我们复杂的代码需求。 不过&#xff0c;在涉及到多个子类派生于基类进行多态模拟的场景下&#xff0c;…...

BCS 2025|百度副总裁陈洋:智能体在安全领域的应用实践

6月5日&#xff0c;2025全球数字经济大会数字安全主论坛暨北京网络安全大会在国家会议中心隆重开幕。百度副总裁陈洋受邀出席&#xff0c;并作《智能体在安全领域的应用实践》主题演讲&#xff0c;分享了在智能体在安全领域的突破性实践。他指出&#xff0c;百度通过将安全能力…...

大模型多显卡多服务器并行计算方法与实践指南

一、分布式训练概述 大规模语言模型的训练通常需要分布式计算技术,以解决单机资源不足的问题。分布式训练主要分为两种模式: 数据并行:将数据分片到不同设备,每个设备拥有完整的模型副本 模型并行:将模型分割到不同设备,每个设备处理部分模型计算 现代大模型训练通常结合…...

Spring AI与Spring Modulith核心技术解析

Spring AI核心架构解析 Spring AI&#xff08;https://spring.io/projects/spring-ai&#xff09;作为Spring生态中的AI集成框架&#xff0c;其核心设计理念是通过模块化架构降低AI应用的开发复杂度。与Python生态中的LangChain/LlamaIndex等工具类似&#xff0c;但特别为多语…...

Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信

文章目录 Linux C语言网络编程详细入门教程&#xff1a;如何一步步实现TCP服务端与客户端通信前言一、网络通信基础概念二、服务端与客户端的完整流程图解三、每一步的详细讲解和代码示例1. 创建Socket&#xff08;服务端和客户端都要&#xff09;2. 绑定本地地址和端口&#x…...