跳转至

Week 1 - Introduction

RoadMap

Lab 课大致安排:

  • 有多个 Projects,最终任务是写一个类C语言的编译器,我们会将这个大任务拆成多个 Projects,并提供 Hints。
  • 每个 Project 之间是串联在一起的。即你在上个 Project 写的代码会在下一个 Project 中用到。

    所以,请保持你代码的良好结构。

  • 每个 Project 都具有相同的结构:

    • 我们提供的 Framework
    • 你需要自行完成的 Implementation
  • 每个 Project 都将由自动评测脚本进行评测,所以千万不要改 Framework 的接口!

搭建环境

参考 环境配置

什么是 ANTLR

ChatGPT said:

ANTLR(ANother Tool for Language Recognition)是一个功能强大的 语法解析器生成工具,常用于构建编译器、解释器、DSL(领域特定语言)、代码分析工具等。它的主要作用是将 文法规则 转换成可以在目标语言(如 Java、C#, Python, JavaScript 等)中运行的 词法分析器(Lexer)语法分析器(Parser)

什么是文法规则

具体而言,我们可以可以把 文法规则 想象成 语言的“说明书”造句的规矩

在自然语言里,我们有语法,比如:

  • 主语 + 谓语 + 宾语

  • “我 吃 苹果” ✅

同样,编程语言数据格式 也有自己的规则,用来规定哪些符号组合是合法的。

抽象的来说,文法规则通常用来描述:

  • 词汇层次:最小的语法单元,比如数字、单词、符号。

  • 结构层次:这些词汇如何组合成更大的结构,比如“表达式”“语句”“程序”。

换句话说:

  • 文法规则是一组形式化的 生产规则,规定了“从哪些符号出发,能一步步生成一个完整的合法句子”。

  • 这些规则通常用 递归 方式定义,可以无限扩展。

Project Zero

Project Zero is released!

ANTLR 配置

首先,从 https://github.com/sqlab-sustech/CS323-Compilers-2025F-Projects/ clone 代码,并切换到 project0-fake1 分支:

$ git clone https://github.com/sqlab-sustech/CS323-Compilers-2025F-Projects/
$ cd CS323-Compilers-2025F-Projects
$ git checkout project0-fake1

随后,在 IDEA 中打开这个文件夹,你应该看到如下目录结构:

alt text

设置 Java SDK 版本为 21。

使用 Makefile 编译 ANTLR 语法文件

我们之前说,ANTLR 是一套 语法解析器生成工具,它可以针对某个给定的语法文件(形式语言学的上下文中,语法和文法绝大多数情况下指的是同一回事,两个术语可以互换使用),生成一些可以处理该语法的代码。

项目根目录中有一个 Calc1.g4 文件,它是一个 ANTLR 的语法文件,在项目根目录下执行 make,我们可以注意到在 src/main/java 下面多了 generated.Calc1 这个包,里面有若干 .java 文件。这些代码就是 ANTLR 工具针对 Calc1.g4 这个语法生成的代码。

alt text

再执行 make clean 我们会发现 generated/ 目录被删除了。

安装 IDEA 的 ANTLR 插件

打开 Settings,找到 Plugin,在 Marketplace 里搜索 ANTLR v4,安装开发者为 "Terence Parr" 的那个插件。

alt text

Calc1.g4 文件上点右键,在菜单栏中点 "Configure ANTLR",打开配置框,并按照如下配置:

alt text

Calc1.g4 文件上点右键,在菜单栏中点 "Generate ANTLR Recognizer",我们会注意到在 src/main/java/generated/Calc1 下面出现了同样的文件。

调用 ANTLR 生成的解析器

Main.java 覆盖为如下内容,如果遇到了依赖问题,使用 Maven 解决依赖问题。

import generated.Calc1.Calc1Lexer;
import generated.Calc1.Calc1Parser;
import org.antlr.v4.runtime.*;
import org.antlr.v4.runtime.tree.*;

public class Main {
    public static void main(String[] args) {
        // 把要解析的字符串喂给 ANTLR
        CharStream input = CharStreams.fromString("1 + 2");
        // 词法分析器
        Calc1Lexer lexer = new Calc1Lexer(input);
        // Token 流
        CommonTokenStream tokens = new CommonTokenStream(lexer);
        // 语法分析器
        Calc1Parser parser = new Calc1Parser(tokens);
        // 从规则 'expression' 开始解析
        ParseTree tree = parser.expr();
        // 把树打印出来看看
        System.out.println(tree.toStringTree(parser));
    }
}

然后,运行该 Main 类,Console 会输出:

line 1:5 no viable alternative at input '<EOF>'
(expr (expr (factor 1)) + (expr (factor 2)))

这就表示 ANTLR 构建的解析器成功把 1 + 2 拆成了一棵语法树,至于第一句报错是什么意思,我们会在后续 Lexer 中讲解。

暂时看不懂树长什么样没关系,后面我们会慢慢讲到它背后的含义。