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

2024-03-27 05:20

本文主要是介绍编译原理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 初代编译器实验说明和要求的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!


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

相关文章

zookeeper端口说明及介绍

《zookeeper端口说明及介绍》:本文主要介绍zookeeper端口说明,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、zookeeper有三个端口(可以修改)aVNMqvZ二、3个端口的作用三、部署时注意总China编程结一、zookeeper有三个端口(可以

java使用protobuf-maven-plugin的插件编译proto文件详解

《java使用protobuf-maven-plugin的插件编译proto文件详解》:本文主要介绍java使用protobuf-maven-plugin的插件编译proto文件,具有很好的参考价... 目录protobuf文件作为数据传输和存储的协议主要介绍在Java使用maven编译proto文件的插件

Go语言中make和new的区别及说明

《Go语言中make和new的区别及说明》:本文主要介绍Go语言中make和new的区别及说明,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1 概述2 new 函数2.1 功能2.2 语法2.3 初始化案例3 make 函数3.1 功能3.2 语法3.3 初始化

java中新生代和老生代的关系说明

《java中新生代和老生代的关系说明》:本文主要介绍java中新生代和老生代的关系说明,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、内存区域划分新生代老年代二、对象生命周期与晋升流程三、新生代与老年代的协作机制1. 跨代引用处理2. 动态年龄判定3. 空间分

从原理到实战深入理解Java 断言assert

《从原理到实战深入理解Java断言assert》本文深入解析Java断言机制,涵盖语法、工作原理、启用方式及与异常的区别,推荐用于开发阶段的条件检查与状态验证,并强调生产环境应使用参数验证工具类替代... 目录深入理解 Java 断言(assert):从原理到实战引言:为什么需要断言?一、断言基础1.1 语

Visual Studio 2022 编译C++20代码的图文步骤

《VisualStudio2022编译C++20代码的图文步骤》在VisualStudio中启用C++20import功能,需设置语言标准为ISOC++20,开启扫描源查找模块依赖及实验性标... 默认创建Visual Studio桌面控制台项目代码包含C++20的import方法。右键项目的属性:

MySQL之InnoDB存储引擎中的索引用法及说明

《MySQL之InnoDB存储引擎中的索引用法及说明》:本文主要介绍MySQL之InnoDB存储引擎中的索引用法及说明,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐... 目录1、背景2、准备3、正篇【1】存储用户记录的数据页【2】存储目录项记录的数据页【3】聚簇索引【4】二

mysql中的数据目录用法及说明

《mysql中的数据目录用法及说明》:本文主要介绍mysql中的数据目录用法及说明,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1、背景2、版本3、数据目录4、总结1、背景安装mysql之后,在安装目录下会有一个data目录,我们创建的数据库、创建的表、插入的

MySQL中的表连接原理分析

《MySQL中的表连接原理分析》:本文主要介绍MySQL中的表连接原理分析,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1、背景2、环境3、表连接原理【1】驱动表和被驱动表【2】内连接【3】外连接【4编程】嵌套循环连接【5】join buffer4、总结1、背景

深度解析Spring AOP @Aspect 原理、实战与最佳实践教程

《深度解析SpringAOP@Aspect原理、实战与最佳实践教程》文章系统讲解了SpringAOP核心概念、实现方式及原理,涵盖横切关注点分离、代理机制(JDK/CGLIB)、切入点类型、性能... 目录1. @ASPect 核心概念1.1 AOP 编程范式1.2 @Aspect 关键特性2. 完整代码实