diff --git a/REFERENCE.html b/REFERENCE.html index e5405abd..45b6cff0 100644 --- a/REFERENCE.html +++ b/REFERENCE.html @@ -1397,7 +1397,7 @@
前端的主要任务是将源代码转换为抽象语法树(Abstract Syntax Tree, AST),为中端和后端生成中间表示和目标代码提供基础。在这个过程中,前端会经历词法分析、语法分析、语义分析等多个步骤。
词法分析的任务是将源代码转换为一系列的符号(token),每个符号代表源代码中的一个最小单位,如关键词、标识符、操作符等。词法分析器会忽略空格、注释等非必要信息,并在此过程中进行基本的错误检测(如非法字符)。
-下面我们以Antlr框架为例,介绍如何进行词法分析和语法分析。你也可以使用其他工具如 Flex & Bison, lex & yacc等。
-Antlr 是一个功能强大的解析器生成器,能够根据给定的语法规则自动生成词法分析器和语法分析器。Antlr 支持多种语言,包括 Java、Python 和 C++。通过定义语法文件(.g4 文件),Antlr 能够帮助我们生成解析源代码所需的词法分析和语法分析工具。
+下面我们以 Antlr 框架为例,介绍如何进行词法分析和语法分析。你也可以使用其他工具如 Flex & Bison, lex & yacc 等。
+Antlr (Another Tool for Language Recognition) 是一个功能强大的解析器生成器,能够根据给定的语法规则自动生成词法分析器和语法分析器。Antlr 支持多种语言,包括 Java、Python 和 C++。通过定义语法文件(.g4 文件),Antlr 能够帮助我们生成解析源代码所需的词法分析和语法分析工具。
在这个项目中,我们推荐使用 Antlr 来处理 MiniDecaf 的词法分析和语法分析部分。
ANTLR 工具需要 JVM 才能执行;另一方面,为了方便使用 grun,你需要一个能够编译 java 源文件的环境。因此,你需要一个完整的 Java Development Kit。
-直接使用包管理器安装
+直接使用包管理器安装:
sudo apt install openjdk-19-jdk
-你需要从 ANTLR Download 下载 antlr-4.13.2-complete.jar
(截至文档写作时此为最新版)。
然后,你需要将该jar包的路径加入到环境变量 CLASSPATH
中,注意将下面/path/to/your/
改为你的路径
然后,你需要将该 jar 包的路径加入到环境变量 CLASSPATH
中,注意将下面 /path/to/your/
改为你的路径:
export CLASSPATH=".:/path/to/your/antlr-4.13.2-complete.jar:$CLASSPATH"
-最好将它加到
+bashrc
中(对于bash),以避免每次打开终端时需要重新配置。最好将它加到
~/.bashrc
中(对于 bash),以避免每次打开终端时需要重新配置。
在命令行中输入
java org.antlr.v4.Tool
-你应该可以看见ANTLR Parser Generator Version 4.13.2
以及一些帮助信息,这说明可以正确使用antlr了.
你应该可以看见 ANTLR Parser Generator Version 4.13.2
以及一些帮助信息,这说明可以正确使用 Antlr 了。
可以定义别名 antlr4
表示 ANTLR 工具,即
alias antlr4='java org.antlr.v4.Tool'
-这样,你可以直接使用 antlr4 your.g4
来为your.g4 生成解析器源码。
ANTLR 的运行时库中还提供了一个灵活的测试工具 TestRig
,它可以显示解析器如何匹配输入的许多相关信息。TestRig
使用Java的反射机制来调用编译过的解析器。为了方便用户使用,ANTLR 提供了一个 grun
工具来使用 TestRig
。
这样,你可以直接使用 antlr4 your.g4
来为 your.g4 生成解析器源码。
ANTLR 的运行时库中还提供了一个灵活的测试工具 TestRig
,它可以显示解析器如何匹配输入的许多相关信息。TestRig
使用 Java 的反射机制来调用编译过的解析器。为了方便用户使用,ANTLR 提供了一个 grun
工具来使用 TestRig
。
grun
本质上是一个别名,可以定义如下:
alias grun='java org.antlr.v4.runtime.misc.TestRig'
或
alias grun='java org.antlr.v4.gui.TestRig'
-同样的,你可以将这些别名命令加入到.bashrc
,以节省你配置和使用的时间。
同样的,你可以将这些别名命令加入到 ~/.bashrc
,以节省你配置和使用的时间。
ANTLR 运行时库是解析器生成的代码在运行时所依赖的代码。对于 C++,你可以从 ANTLR4 runtime Cpp的 GitHub 仓库下载预编译的库或者自己编译安装。但是官方的CMAKE脚本会从官方 git 仓库下载 ANTLR C++ 运行时并构建它,你在编译过程中很可能会因为网络等问题而失败,如果难以解决,可以直接clone ANTLR 运行时库的 C++ 源代码到你的代码仓库里,并为你的整个项目编写一个CMAKE文件(强烈建议)。处于方便考虑,我在这里给出一个可能的项目结构与CMAKE文件实例.
+ANTLR 运行时库是解析器生成的代码在运行时所依赖的代码。对于 C++,你可以从 ANTLR4 runtime Cpp的 GitHub 仓库下载预编译的库或者自己编译安装。但是官方的 CMAKE 脚本会从官方 git 仓库下载 ANTLR C++ 运行时并构建它,你在编译过程中很可能会因为网络等问题而失败,如果难以解决,可以直接 clone ANTLR 运行时库的 C++ 源代码到你的代码仓库里,并为你的整个项目编写一个 CMAKE 文件(强烈建议)。出于方便考虑,我在这里给出一个可能的项目结构与CMAKE文件实例.
项目结构
example-tree/
├── 3rd_party/
-│ └── antlr4-runtime/ # 第三方库ANTLR运行时目录(在源码的src目录下)
-│ ├── CMakeLists.txt # antlr4-runtime的CMake配置文件,需要你手动添加一个
+│ └── antlr4-runtime/ # 第三方库 ANTLR 运行时目录(在源码的 src 目录下)
+│ ├── CMakeLists.txt # antlr4-runtime 的 CMake 配置文件,需要你手动添加一个
│ └── antlr4-runtime.h
│ └── antlr4-common.h
│ └── ...
-├── CMakeLists.txt # 根目录下的CMake配置文件
+├── CMakeLists.txt # 根目录下的 CMake 配置文件
└── src/ # 源代码目录
├── frontend/ # 前端代码目录
│ ├── lexer/ # 词法分析相关代码
- │ │ └── *.cpp # 词法分析器源文件
- │ │ └── *.h # 词法分析器头文件
+ │ │ └── *.cpp # 词法分析器源文件
+ │ │ └── *.h # 词法分析器头文件
│ ├── parser/ # 语法分析相关代码
- │ │ └── *.cpp # 语法分析器源文件
- │ │ └── *.h # 语法分析器头文件
+ │ │ └── *.cpp # 语法分析器源文件
+ │ │ └── *.h # 语法分析器头文件
│ └── ast/ # 抽象语法树相关代码
- │ ├── *.cpp # AST源文件
- │ ├── *.h # AST头文件
- ├── backend/ # 后端代码目录
- ├── midend/ # 中间代码目录
+ │ ├── *.cpp # AST 源文件
+ │ ├── *.h # AST 头文件
+ ├── backend/ # 后端代码目录
+ ├── midend/ # 中间代码目录
└── main.cpp # 程序入口文件
对应的CMakeLists.txt
# 指定CMake的最小版本要求
+对应的 CMakeLists.txt
+# 指定 CMake 的最小版本要求
cmake_minimum_required(VERSION 3.10)
-# 设置项目名称和使用的语言(CXX代表C++)
+# 设置项目名称和使用的语言(CXX 代表 C++)
project(my_compiler CXX)
-# 设置C++标准为C++17
+# 设置 C++ 标准为 C++17
set(CMAKE_CXX_STANDARD 17)
-# 设置C++编译器标志,这里没有额外添加,使用默认
+# 设置 C++ 编译器标志,这里没有额外添加,使用默认
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
-# 设置调试模式下的编译器标志,开启DEBUG宏
+# 设置调试模式下的编译器标志,开启 DEBUG 宏
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DDEBUG")
-# 使用GLOB_RECURSE模式递归查找src目录下所有的.cpp文件
+# 使用 GLOB_RECURSE 模式递归查找 src 目录下所有的 .cpp 文件
file(GLOB_RECURSE SRC "src/*.cpp")
-# 添加项目的src目录到头文件搜索路径
+# 添加项目的 src 目录到头文件搜索路径
include_directories(src)
-# 添加第三方库目录antlr4-runtime到头文件搜索路径
+# 添加第三方库目录 antlr4-runtime 到头文件搜索路径
include_directories(3rd_party/antlr4-runtime)
-# 添加antlr4-runtime子目录作为子项目进行构建
+# 添加 antlr4-runtime 子目录作为子项目进行构建
add_subdirectory(3rd_party/antlr4-runtime)
-# 创建名为my_compiler的可执行文件,将所有源文件编译链接到这个可执行文件中
+# 创建名为 my_compiler 的可执行文件,将所有源文件编译链接到这个可执行文件中
add_executable(my_compiler ${SRC})
-# 将antlr4_runtime库与my_compiler可执行文件链接
+# 将 antlr4_runtime 库与 my_compiler 可执行文件链接
target_link_libraries(my_compiler antlr4_runtime)
-为antlr4-runtime添加一个相应的CMakeLists.txt
+为 antlr4-runtime 添加一个相应的 CMakeLists.txt
# 3rd_party/antlr4-runtime/CMakeLists.txt
@@ -1438,11 +1438,8 @@ 1. 安
add_library(antlr4_runtime STATIC ${ANTLR4_SRC})
-<somepath>
是你指定的安装目录,你也可以不指定<DESTDIR>
,直接安装到系统。终于,在上一部分中,我们完成了项目的环境准备工作,可以着手开始编写代码了。在这一节中,我们会开始编写一个简单的C语言子集simpleC
的文法文件simpleC.g4
,并利用它生成一个parse tree
.最终把一个简单的c语言程序test.c
转换为一个parse tree
终于,在上一部分中,我们完成了项目的环境准备工作,可以着手开始编写代码了。在这一节中,我们会开始编写一个简单的 C 语言子集 simpleC
的文法文件 simpleC.g4
,并利用它生成一个 parse tree。最终把一个简单的 C 语言程序 test.c
转换为一个 parse tree。
test.c
int main(){
@@ -1474,22 +1471,19 @@ 1.编写simpleC.g4
-
-todo:如何编写一个ANTLR文法文件.
-
-
.g4
文件是 ANTLR (Another Tool for Language Recognition) 使用的文法文件,用于定义语言的语法规则。它使用基于上下文的语法规则来描述语言的结构。一个典型的 .g4
文件包含以下几个部分:
+1. 编写simpleC.g4
+.g4
文件是 ANTLR 使用的文法文件,用于定义语言的语法规则。它使用基于上下文的语法规则来描述语言的结构。一个典型的 .g4
文件包含以下几个部分:
-- 语法定义:声明语法的名称,这是识别语法文件的关键字。这个语法名称必须要和包含这个语法的文件名完全相同(甚至包括大小写,因为ANTLR是对大小写敏感的)
+- 语法定义:声明语法的名称,这是识别语法文件的关键字。这个语法名称必须要和包含这个语法的文件名完全相同(甚至包括大小写,因为 ANTLR 是对大小写敏感的)
- 规则:定义语言中各种结构的模式。
- 词法规则:定义词法单元(如关键字、标识符、符号等)。
- 忽略规则:通常用来忽略空格、换行等空白字符。
- 操作:在规则中嵌入的代码,用于在解析过程中执行特定的动作。
-示例 .g4
文件结构
+示例 .g4
文件结构
// 文件名: SimpleC.g4
-grammar SimpleC; //语法定义
+grammar SimpleC; // 语法定义
// 程序的起始规则
program: funcDeclaration ;
@@ -1507,13 +1501,13 @@ 示例 <
;
// 表达式的规则
-expression: expression PLUS expression # AddExpr
- | expression MINUS expression # SubExpr
- | expression MUL expression # MulExpr
- | expression DIV expression # DivExpr
- | '(' expression ')' # ParenExpr
- | INT # IntExpr
- | ID # ID
+expression: expression PLUS expression // AddExpr
+ | expression MINUS expression // SubExpr
+ | expression MUL expression // MulExpr
+ | expression DIV expression // DivExpr
+ | '(' expression ')' // ParenExpr
+ | INT // IntExpr
+ | ID // ID
;
// 类型的规则(这里只支持 int 类型)
@@ -1541,15 +1535,15 @@ 示例 <
DIV: '/' ;
通过编写 .g4
文件,我们能够为 ANTLR 提供足够的信息来构建一个能够理解和处理特定语言的解析器。这种形式的文法定义是编译器设计和语言工具开发的基础。
-2.使用文法文件生成lexer&parser
-在确认环境配置无误后,我们可以使用ANTLR+文法文件生成所需的lexer&parser,只需要执行
+2. 使用文法文件生成 lexer & parser
+在确认环境配置无误后,我们可以使用 ANTLR 和文法文件生成所需的 lexer & parser,只需要执行
antlr4 -Dlanguage=Cpp -no-listener -visitor -o src/frontend/lexer_parser simpleC.g4
--no-listener
和-visitor
选项分别用于停止生成listener
(默认是激活的)和激活visitor
模式。如果你还不知道visitor
是什么,不用担心,我们稍后会看到。
--o 选项用于设置输出目录。我们将在src/frontend/lexer_parser
目录中输出生成的代码。
-3.使用lexer&parser
+-no-listener
和 -visitor
选项分别用于禁止生成 listener(默认是激活的)和激活 visitor 模式。如果你还不知道 visitor 是什么,不用担心,我们稍后会看到。
+-o 选项用于设置输出目录。我们将在 src/frontend/lexer_parser
目录中输出生成的代码。
+3. 使用 lexer & parser
现在我们可以看到如何在 C++ 程序中使用我们生成的解析器。
-//src/main.cpp
+// src/main.cpp
#include "antlr4-runtime.h"
#include "frontend/lexer/SimpleCBaseVisitor.h"
#include "frontend/lexer/SimpleCLexer.h"
@@ -1583,16 +1577,16 @@ 3.使用lexer&parser
- 我们将输入转换为 ANTLR 格式
- 我们创建一个在该输入上工作的词法分析器
-- 我们使用词法分析器产生一个token流
+- 我们使用词法分析器产生一个 token 流
- 我们创建一个在令牌流上工作的解析器
- 然后,21 行使用解析器的一个方法,该方法对应于语法规则中的一个,以获得规则匹配的第一个节点。在我们的例子中,只有一个节点
program
,这是因为我们定义规则的方式。然而,原则上那可以是任意的,每次你调用相应的方法,你都会得到一个相应的结果。
-现在,使用cmake构建运行我们自己实现的编译器。你将会看到一个parse tree
+现在,使用 cmake 构建并运行我们自己实现的编译器,你将会看到 test.c
对应的 parse tree 被输出到终端中。
./my_compiler test.c
-总得来说,我们现在利用ANTLR实现了词法分析器分析输入(即字符)并产生token,然后解析器分析token以产生parser tree
。这样,我们就把一个看似被复杂地组织起来的文本转化成了一个“树”,有了“树”之后我们就可以各种花式遍历这个树并对这个树的每个节点进行一些操作,如何遍历呢?我们用到了Visitor
模式。
-第三部分:ast的生成
-Visitor模式代码的编写方法
+总的来说,我们现在利用 ANTLR 实现了词法分析器分析输入(即字符)并产生 token,然后解析器分析 token 以产生 parser tree。这样,我们就把一个看似被复杂地组织起来的文本转化成了一个“树”,有了“树”之后我们就可以各种花式遍历这个树并对这个树的每个节点进行一些操作,如何遍历呢?我们用到了 visitor 模式。
+第三部分:AST 的生成
+Visitor 模式代码的编写方法
在编写编译器时,我们通常使用 Visitor 模式来遍历和处理 AST。Visitor 模式提供了一种解耦的方式来在不同的节点上执行操作。通过定义 Visitor 类,我们可以根据 AST 的不同节点执行特定的逻辑操作。
在 Antlr 中,Visitor 类会根据语法文件中的每个语法规则生成对应的函数,例如:
public class MiniDecafVisitor extends MiniDecafBaseVisitor<Void> {
@@ -1604,7 +1598,7 @@ 第四部分 语义分析
+第四部分:语义分析
符号解析(namer)
类型检查(typer)
前端参考资料
@@ -1674,7 +1668,7 @@ No results matching "
var gitbook = gitbook || [];
gitbook.push(function() {
- gitbook.page.hasChanged({"page":{"title":"前端设计","level":"11.2","depth":1,"next":{"title":"中端设计","level":"11.3","depth":1,"path":"docs/contest/midend/midend.md","ref":"docs/contest/midend/midend.md","articles":[{"title":"静态单赋值","level":"11.3.1","depth":2,"path":"docs/contest/midend/ssa.md","ref":"docs/contest/midend/ssa.md","articles":[]},{"title":"常量传播","level":"11.3.2","depth":2,"path":"docs/contest/midend/cp.md","ref":"docs/contest/midend/cp.md","articles":[]},{"title":"死代码消除","level":"11.3.3","depth":2,"path":"docs/contest/midend/dce.md","ref":"docs/contest/midend/dce.md","articles":[]}]},"previous":{"title":"大实验简介","level":"11.1","depth":1,"path":"docs/contest/intro.md","ref":"docs/contest/intro.md","articles":[]},"dir":"ltr"},"config":{"gitbook":"*","theme":"default","variables":{},"plugins":["hide-element","chapter-fold","katex","alerts","emphasize","mermaid-gb3","codeblock-label","code","search-pro","click-reveal","expandable-chapters-interactive","localized-footer","intopic-toc"],"pluginsConfig":{"chapter-fold":{},"emphasize":{},"intopic-toc":{"isCollapsed":true,"isScrollspyActive":true,"label":"In this article","maxDepth":6,"mode":"nested","selector":".markdown-section h1, .markdown-section h2, .markdown-section h3, .markdown-section h4, .markdown-section h5, .markdown-section h6","visible":true},"codeblock-label":{},"search-pro":{},"search":{},"localized-footer":{"filename":"gitalk.html","hline":"true"},"lunr":{"maxIndexSize":1000000,"ignoreSpecialCharacters":false},"code":{"copyButtons":true},"hide-element":{},"katex":{},"fontsettings":{"theme":"white","family":"sans","size":1},"click-reveal":{},"highlight":{},"mermaid-gb3":{},"expandable-chapters-interactive":{},"alerts":{},"sharing":{"facebook":true,"twitter":true,"google":false,"weibo":false,"instapaper":false,"vk":false,"all":["facebook","google","twitter","weibo","instapaper"]},"theme-default":{"styles":{"website":"styles/website.css","pdf":"styles/pdf.css","epub":"styles/epub.css","mobi":"styles/mobi.css","ebook":"styles/ebook.css","print":"styles/print.css"},"showLevel":false}},"structure":{"langs":"LANGS.md","readme":"README.md","glossary":"GLOSSARY.md","summary":"SUMMARY.md"},"pdf":{"pageNumbers":true,"fontSize":12,"fontFamily":"Arial","paperSize":"a4","chapterMark":"pagebreak","pageBreaksBefore":"/","margin":{"right":62,"left":62,"top":56,"bottom":56}},"styles":{"website":"styles/website.css","pdf":"styles/pdf.css","epub":"styles/epub.css","mobi":"styles/mobi.css","ebook":"styles/ebook.css","print":"styles/print.css"}},"file":{"path":"docs/contest/frontend.md","mtime":"2024-09-11T04:46:33.093Z","type":"markdown"},"gitbook":{"version":"3.2.3","time":"2024-09-11T04:47:17.025Z"},"basePath":"../..","book":{"language":""}});
+ gitbook.page.hasChanged({"page":{"title":"前端设计","level":"11.2","depth":1,"next":{"title":"中端设计","level":"11.3","depth":1,"path":"docs/contest/midend/midend.md","ref":"docs/contest/midend/midend.md","articles":[{"title":"静态单赋值","level":"11.3.1","depth":2,"path":"docs/contest/midend/ssa.md","ref":"docs/contest/midend/ssa.md","articles":[]},{"title":"常量传播","level":"11.3.2","depth":2,"path":"docs/contest/midend/cp.md","ref":"docs/contest/midend/cp.md","articles":[]},{"title":"死代码消除","level":"11.3.3","depth":2,"path":"docs/contest/midend/dce.md","ref":"docs/contest/midend/dce.md","articles":[]}]},"previous":{"title":"大实验简介","level":"11.1","depth":1,"path":"docs/contest/intro.md","ref":"docs/contest/intro.md","articles":[]},"dir":"ltr"},"config":{"gitbook":"*","theme":"default","variables":{},"plugins":["hide-element","chapter-fold","katex","alerts","emphasize","mermaid-gb3","codeblock-label","code","search-pro","click-reveal","expandable-chapters-interactive","localized-footer","intopic-toc"],"pluginsConfig":{"chapter-fold":{},"emphasize":{},"intopic-toc":{"isCollapsed":true,"isScrollspyActive":true,"label":"In this article","maxDepth":6,"mode":"nested","selector":".markdown-section h1, .markdown-section h2, .markdown-section h3, .markdown-section h4, .markdown-section h5, .markdown-section h6","visible":true},"codeblock-label":{},"search-pro":{},"search":{},"localized-footer":{"filename":"gitalk.html","hline":"true"},"lunr":{"maxIndexSize":1000000,"ignoreSpecialCharacters":false},"code":{"copyButtons":true},"hide-element":{},"katex":{},"fontsettings":{"theme":"white","family":"sans","size":1},"click-reveal":{},"highlight":{},"mermaid-gb3":{},"expandable-chapters-interactive":{},"alerts":{},"sharing":{"facebook":true,"twitter":true,"google":false,"weibo":false,"instapaper":false,"vk":false,"all":["facebook","google","twitter","weibo","instapaper"]},"theme-default":{"styles":{"website":"styles/website.css","pdf":"styles/pdf.css","epub":"styles/epub.css","mobi":"styles/mobi.css","ebook":"styles/ebook.css","print":"styles/print.css"},"showLevel":false}},"structure":{"langs":"LANGS.md","readme":"README.md","glossary":"GLOSSARY.md","summary":"SUMMARY.md"},"pdf":{"pageNumbers":true,"fontSize":12,"fontFamily":"Arial","paperSize":"a4","chapterMark":"pagebreak","pageBreaksBefore":"/","margin":{"right":62,"left":62,"top":56,"bottom":56}},"styles":{"website":"styles/website.css","pdf":"styles/pdf.css","epub":"styles/epub.css","mobi":"styles/mobi.css","ebook":"styles/ebook.css","print":"styles/print.css"}},"file":{"path":"docs/contest/frontend.md","mtime":"2024-09-13T08:36:21.372Z","type":"markdown"},"gitbook":{"version":"3.2.3","time":"2024-09-13T08:37:08.626Z"},"basePath":"../..","book":{"language":""}});
});
diff --git a/docs/contest/intro.html b/docs/contest/intro.html
index 50787109..11c3b8ce 100644
--- a/docs/contest/intro.html
+++ b/docs/contest/intro.html
@@ -1336,10 +1336,10 @@ 介绍
参加大实验的同学应该需要自己从头设计一个符合 minidecaf 规范 的编译器,包括前端、中端和后端。
有两个原因我们要求同学们从头设计一个编译器:
-- 为了简化课程实验,我们的基础实验框架在设计时并未考虑大实验的需求(例如:IR的类型系统简易、没有区分基本块),在现有框架的基础上重构实现编译优化反而在一定程度上限制了编译器的优化能力。
+- 为了简化课程实验,我们的基础实验框架在设计时并未考虑大实验的需求(例如:IR 的类型系统简易、没有区分基本块),在现有框架的基础上重构实现编译优化反而在一定程度上限制了编译器的优化能力。
- 大实验设计的其中一个目标是鼓励同学们参加系统能力设计大赛,比赛有查重要求,如果同学们使用相同的框架开始参加大实验并参与后续比赛,可能存在代码被判定为重复的问题。
-大实验在2024年相对于2023年有一些变化,主要体现在:
+大实验在 2024 年相对于 2023 年有一些变化,主要体现在:
- 增加了实验文档
- 语法要求从 Sysy 语法改为了 MiniDecaf,主要差别在于
const
标志符号、数组初始化等语法上的区别,难度有所降低
@@ -1347,9 +1347,9 @@ 介绍
大实验的语法规范与 step12 的规范是一致的。不过有一点需要注意:
-- 我们要求实现函数声明,即一个函数可以只有声明没有定义,主要是用于评测性能,比如读入数据和打印结果,我们将会把你的代码和一个外部库进行链接编译。这意味着,你需要实现标准的riscv调用约定。
+- 我们要求实现函数声明,即一个函数可以只有声明没有定义,主要是用于评测性能,比如读入数据和打印结果,我们将会把你的代码和一个外部库进行链接编译。这意味着,你需要实现标准的 RiscV 调用约定。
-你可以选择 C++,Rust 实现你的编译器,你的编译器生成的目标代码可以是 riscv 或者 arm 架构的,这与比赛要求一致。如果你们想用其他语言实现,请告知助教。
+你可以选择 C++,Rust 实现你的编译器,你的编译器生成的目标代码可以是 RISC-V 或者 ARM 架构的,这与比赛要求一致。如果你想用其他语言实现,请告知助教。
大实验为组队实验,4人一组(可以更少,但是评分标准保持不变)。没有特殊情况时,同组同分。
注意:大实验工作量较大,并不推荐所有同学都参加。
编译器的构成
@@ -1362,7 +1362,7 @@ 编译զ
可以通过后续的文档了解每个部分的更多细节。
编写前端、设计IR、完成中间代码生成 (两周)
+编写前端、设计 IR、完成中间代码生成 (两周)
utils/tac
)。中间代码生成:将AST转换为IR,你可以参考基础实验框架的中间代码生成部分(frontend/tacgen
)。
utils/tac
)。中间代码生成:将 AST 转换为 IR,你可以参考基础实验框架的中间代码生成部分(frontend/tacgen
)。
此阶段分工建议:两位同学负责前端,两位同学负责中间表示设计和中间代码生成。
第一次进度检查:第六周周六(10.19)
第二次进度检查(中期检查):第八周周六(11.2)
第三次进度检查:第十二周周六(11.23)
第四次进度检查(期末检查):第十六周周末(12.29)
成绩占比 90%,剩余 10% 为书面作业和日常成绩。
其中这90%构成为:
30% 性能测试,将根据你的编译器的性能进行评分。
性能评分方案:
-附加测试中performance
部分测试样例,以gcc打开-O2
优化的性能的 60% 为满分,按照比例折算。如果一个程序gcc编译后运行时间为 12s ,如果你的程序执行时间为 20s 即为满分。
performance
部分测试样例,以 gcc 打开-O2
优化的性能的 60% 为满分,按照比例折算。如果一个程序 gcc 编译后运行时间为 12s ,如果你的程序执行时间为 20s 即为满分。
你的单个测试点的得分为:
-min{100, 100 * GCC编译程序运行时间 * 1.25/你的程序运行时间}
+min{100, 100 * GCC编译程序运行时间 * 1.67 / 你的程序运行时间}
所有测试点取算数平均值,最后结果 * 30% 作为你的最终性能测试成绩。
-评测将会在我们提供的服务器上进行,通过QEMU模拟RISC-V或者ARM架构的CPU运行你的程序。经过测试QEMU与真实硬件的性能相对差值是比较恒定的(如比较gcc-O1
与-O2
)。
+评测将会在我们提供的服务器上进行,通过 QEMU 模拟 RISC-V 或者 ARM 架构的 CPU 运行你的程序。经过测试 QEMU与 真实硬件的性能相对差值是比较恒定的(如比较 gcc -O1
与-O2
)。
实验评测仓库在这里。
你也可以选择参加期末考,那么你的成绩将会是评分方案一、二取最高的一个。
选项二 仅完成竞赛第一阶段(达到课程基础实验的要求)
实验部分占比与基础实验一致,你不需要完成思考题,但是需要简单介绍你的编译器是怎么完成每一个 step 的。根据通过测试样例情况评分。