Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
WuK committed Feb 21, 2024
1 parent ee536f3 commit 3d2c7d6
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 38 deletions.
3 changes: 1 addition & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
# syntax=docker/dockerfile:1.4
ARG BASE_IMAGE=ubuntu:noble
FROM ${BASE_IMAGE}
WORKDIR /autograder
WORKDIR /opt/SYsU-lang
COPY <<build_install.sh <<run.sh . /opt/SYsU-lang
#!/bin/sh
Expand All @@ -27,7 +26,6 @@ rm -rf /opt/SYsU-lang/optimizer
cp -r /opt/SYsU-lang/submission/*-Source/optimizer /opt/SYsU-lang
rm -rf /opt/SYsU-lang/submission
/opt/SYsU-lang/build_install.sh /opt/SYsU-lang /opt/sysu
mkdir -p /autograder/results
sysu-compiler \\
--unittest=benchmark_generator_and_optimizer_1 \\
"/opt/SYsU-lang/**/*.sysu.c" >/autograder/results/results.json
Expand All @@ -41,6 +39,7 @@ apt-get install -y --no-install-recommends \
apt-get autoremove -y
apt-get clean -y
rm -rf /var/lib/apt/lists/*
mkdir -p /autograder/results
mv /opt/SYsU-lang/run.sh /autograder/run
chmod +x /autograder/run
chmod +x /opt/SYsU-lang/build_install.sh
Expand Down
6 changes: 6 additions & 0 deletions grammar/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,12 @@ flowchart TD;
2. 输出到 json,因为 json 格式非常容易理解,不需要像 [LLVM 官方教程](https://releases.llvm.org/17.0.0/docs/tutorial/MyFirstLanguageFrontend/LangImpl02.html) 一样定义很多节点。
3. 输出到 `llvm::json`,可以让同学们提前上手 LLVM 库的使用,平滑下一个实验的难度。

### Q & A:该选择 Visitor 还是 Listener?

TL;DR: Vistor 更符合任务需求,但是 Listener 仍然更加趁手。

Visitor 有更强的可定制性,但是需要自行实现每个节点到子节点的访问规则;Listener 则适合更轻量的任务,例如只提取某些语法规则的上下文。在本实验中,按道理每个节点都需要被访问,因此 Vistor 更符合任务需求,Listener 的优势没有那么大。然而,根据助教的使用经验,Listener 仍然是一个更常用且好用的选择。

## 评分规则

本实验的评分分为两部分:基础部分和挑战部分。
Expand Down
73 changes: 37 additions & 36 deletions grammar/main.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "CVisitor.h"
#include <algorithm>
#include <antlr4-runtime.h>
#include <any>
#include <llvm/Support/JSON.h>
#include <llvm/Support/MemoryBuffer.h>
#include <llvm/Support/raw_ostream.h>
Expand Down Expand Up @@ -48,27 +49,28 @@ int main(int argc, char **argv) {
return 0;
}
sysu_grammar::CParser parser(&tokens);
#ifndef SYSU_GRAMMAR_USE_LISTENER // 任 君 选 择
struct Visitor : sysu_grammar::CBaseVisitor {
antlrcpp::Any visitCompilationUnit(
sysu_grammar::CParser::CompilationUnitContext *ctx) override {
return visit(ctx->translationUnit());
}
antlrcpp::Any visitTranslationUnit(
#ifndef SYSU_GRAMMAR_NO_USE_LISTENER // 任 君 选 择
struct Listener : sysu_grammar::CBaseListener {
llvm::json::Array stak;
void exitTranslationUnit(
sysu_grammar::CParser::TranslationUnitContext *ctx) override {
llvm::json::Value ret = llvm::json::Object{
{"kind", "TranslationUnitDecl"}, {"inner", llvm::json::Array{}}};
for (auto child : ctx->externalDeclaration()) {
ret.getAsObject()->get("inner")->getAsArray()->push_back(
visit(child).as<llvm::json::Value>());
ret.getAsObject()->get("inner")->getAsArray()->reserve(
ctx->externalDeclaration().size());
for (const auto &child : ctx->externalDeclaration()) {
ret.getAsObject()->get("inner")->getAsArray()->push_back(stak.back());
stak.pop_back();
}
return ret;
std::reverse(ret.getAsObject()->get("inner")->getAsArray()->begin(),
ret.getAsObject()->get("inner")->getAsArray()->end());
stak.push_back(ret);
}
// 请续写 visitExternalDeclaration 及之后的遍历逻辑,将 ParseTree 转换为
// 请续写 exitExternalDeclaration 及之后的遍历逻辑,将 ParseTree 转换为
// json 格式的 AbstractSyntaxTree,简而言之就是把树拍扁
antlrcpp::Any visitExternalDeclaration(
void exitExternalDeclaration(
sysu_grammar::CParser::ExternalDeclarationContext *ctx) override {
return llvm::json::Value(llvm::json::Object{
stak.push_back(llvm::json::Object{
{"kind", "FunctionDecl"},
{"name", "main"},
{"inner",
Expand All @@ -82,32 +84,31 @@ int main(int argc, char **argv) {
}}},
}}}});
}
};
llvm::outs()
<< Visitor().visit(parser.compilationUnit()).as<llvm::json::Value>()
<< "\n";
} listener;
antlr4::tree::ParseTreeWalker::DEFAULT.walk(&listener,
parser.compilationUnit());
llvm::outs() << listener.stak.back() << "\n";
#else
struct Listener : sysu_grammar::CBaseListener {
llvm::json::Array stak;
void exitTranslationUnit(
struct Visitor : sysu_grammar::CBaseVisitor {
antlrcpp::Any visitCompilationUnit(
sysu_grammar::CParser::CompilationUnitContext *ctx) override {
return visit(ctx->translationUnit());
}
antlrcpp::Any visitTranslationUnit(
sysu_grammar::CParser::TranslationUnitContext *ctx) override {
llvm::json::Value ret = llvm::json::Object{
{"kind", "TranslationUnitDecl"}, {"inner", llvm::json::Array{}}};
ret.getAsObject()->get("inner")->getAsArray()->reserve(
ctx->externalDeclaration().size());
for (const auto &child : ctx->externalDeclaration()) {
ret.getAsObject()->get("inner")->getAsArray()->push_back(stak.back());
stak.pop_back();
for (auto child : ctx->externalDeclaration()) {
ret.getAsObject()->get("inner")->getAsArray()->push_back(
std::any_cast<llvm::json::Value>(visit(child)));
}
std::reverse(ret.getAsObject()->get("inner")->getAsArray()->begin(),
ret.getAsObject()->get("inner")->getAsArray()->end());
stak.push_back(ret);
return ret;
}
// 请续写 exitExternalDeclaration 及之后的遍历逻辑,将 ParseTree 转换为
// 请续写 visitExternalDeclaration 及之后的遍历逻辑,将 ParseTree 转换为
// json 格式的 AbstractSyntaxTree,简而言之就是把树拍扁
void exitExternalDeclaration(
antlrcpp::Any visitExternalDeclaration(
sysu_grammar::CParser::ExternalDeclarationContext *ctx) override {
stak.push_back(llvm::json::Object{
return llvm::json::Value(llvm::json::Object{
{"kind", "FunctionDecl"},
{"name", "main"},
{"inner",
Expand All @@ -121,9 +122,9 @@ int main(int argc, char **argv) {
}}},
}}}});
}
} listener;
antlr4::tree::ParseTreeWalker::DEFAULT.walk(&listener,
parser.compilationUnit());
llvm::outs() << listener.stak.back() << "\n";
};
llvm::outs() << std::any_cast<llvm::json::Value>(
Visitor().visit(parser.compilationUnit()))
<< "\n";
#endif
}

0 comments on commit 3d2c7d6

Please sign in to comment.