Skip to content

Commit 87247dc

Browse files
committed
[lab2] Added the version used in 2017 fall
1 parent 36cb25c commit 87247dc

10 files changed

+487
-0
lines changed

c1interpreter/.gitignore

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
.vscode
2+
build
3+
src/grammar/*
4+
!src/grammar/*.g4
5+
!src/grammar/*.sh
6+
!src/grammar/*.ps1

c1interpreter/CMakeLists.txt

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
CMAKE_MINIMUM_REQUIRED(VERSION 3.5)
2+
3+
add_definitions(-DFULL_IMPL)
4+
5+
SET (CMAKE_CXX_STANDARD 14)
6+
7+
find_package(c1recognizer)
8+
include_directories(${C1RECOGNIZER_INCLUDE_DIRS})
9+
link_directories(${C1RECOGNIZER_LIBRARY_DIRS})
10+
11+
# Import LLVM
12+
find_package(LLVM REQUIRED CONFIG)
13+
message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}")
14+
message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}")
15+
llvm_map_components_to_libnames(llvm_libs core mcjit native)
16+
17+
include_directories(${LLVM_INCLUDE_DIRS})
18+
add_definitions(${LLVM_DEFINITIONS})
19+
20+
include_directories(dependency/c1recognizer/include)
21+
add_executable(c1i
22+
src/main.cpp
23+
src/assembly_builder.cpp
24+
src/runtime.cpp
25+
src/runtime/io.c
26+
src/assembly_builder.h
27+
src/runtime.h
28+
src/runtime/io.h)
29+
target_link_libraries(c1i ${C1RECOGNIZER_LIBS} ${llvm_libs})

c1interpreter/README.md

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# C1 Language Interpreter (Reference Version)
2+
3+
## Introduction
4+
5+
Two parts are included:
6+
7+
1. `assembly_builder`: Build assembly from AST, with LLVM `IRBuilder`.
8+
1. `jit_driver`: Execute assembly with the help of Just-In-Time compiling. Currently all in `main.cpp`.
9+
10+
As a CLI tool, `c1i` is capable of compiling C1 code into LLVM IR, print it and execute it.
11+
12+
## Build
13+
14+
Use CMake for building this project. `c1recognizer` and LLVM installations are required.
+63
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
2+
#include "assembly_builder.h"
3+
4+
#include <vector>
5+
6+
using namespace llvm;
7+
using namespace c1_recognizer::syntax_tree;
8+
9+
void assembly_builder::visit(assembly &node)
10+
{
11+
}
12+
13+
void assembly_builder::visit(func_def_syntax &node)
14+
{
15+
}
16+
17+
void assembly_builder::visit(cond_syntax &node)
18+
{
19+
}
20+
21+
void assembly_builder::visit(binop_expr_syntax &node)
22+
{
23+
}
24+
25+
void assembly_builder::visit(unaryop_expr_syntax &node)
26+
{
27+
}
28+
29+
void assembly_builder::visit(lval_syntax &node)
30+
{
31+
}
32+
33+
void assembly_builder::visit(literal_syntax &node)
34+
{
35+
}
36+
37+
void assembly_builder::visit(var_def_stmt_syntax &node)
38+
{
39+
}
40+
41+
void assembly_builder::visit(assign_stmt_syntax &node)
42+
{
43+
}
44+
45+
void assembly_builder::visit(func_call_stmt_syntax &node)
46+
{
47+
}
48+
49+
void assembly_builder::visit(block_syntax &node)
50+
{
51+
}
52+
53+
void assembly_builder::visit(if_stmt_syntax &node)
54+
{
55+
}
56+
57+
void assembly_builder::visit(while_stmt_syntax &node)
58+
{
59+
}
60+
61+
void assembly_builder::visit(empty_stmt_syntax &node)
62+
{
63+
}

c1interpreter/src/assembly_builder.h

+130
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
2+
#ifndef _C1_ASSEMBLY_BUILDER_H_
3+
#define _C1_ASSEMBLY_BUILDER_H_
4+
5+
#include <deque>
6+
#include <unordered_map>
7+
#include <string>
8+
#include <tuple>
9+
10+
#include <llvm/IR/BasicBlock.h>
11+
#include <llvm/IR/Constants.h>
12+
#include <llvm/IR/DerivedTypes.h>
13+
#include <llvm/IR/Function.h>
14+
#include <llvm/IR/IRBuilder.h>
15+
#include <llvm/IR/LLVMContext.h>
16+
#include <llvm/IR/Module.h>
17+
#include <llvm/IR/Type.h>
18+
#include <llvm/IR/Verifier.h>
19+
20+
#include <c1recognizer/error_reporter.h>
21+
#include <c1recognizer/syntax_tree.h>
22+
23+
#include "runtime.h"
24+
25+
class assembly_builder : public c1_recognizer::syntax_tree::syntax_tree_visitor
26+
{
27+
virtual void visit(c1_recognizer::syntax_tree::assembly &node) override;
28+
virtual void visit(c1_recognizer::syntax_tree::func_def_syntax &node) override;
29+
virtual void visit(c1_recognizer::syntax_tree::cond_syntax &node) override;
30+
virtual void visit(c1_recognizer::syntax_tree::binop_expr_syntax &node) override;
31+
virtual void visit(c1_recognizer::syntax_tree::unaryop_expr_syntax &node) override;
32+
virtual void visit(c1_recognizer::syntax_tree::lval_syntax &node) override;
33+
virtual void visit(c1_recognizer::syntax_tree::literal_syntax &node) override;
34+
virtual void visit(c1_recognizer::syntax_tree::var_def_stmt_syntax &node) override;
35+
virtual void visit(c1_recognizer::syntax_tree::assign_stmt_syntax &node) override;
36+
virtual void visit(c1_recognizer::syntax_tree::func_call_stmt_syntax &node) override;
37+
virtual void visit(c1_recognizer::syntax_tree::block_syntax &node) override;
38+
virtual void visit(c1_recognizer::syntax_tree::if_stmt_syntax &node) override;
39+
virtual void visit(c1_recognizer::syntax_tree::while_stmt_syntax &node) override;
40+
virtual void visit(c1_recognizer::syntax_tree::empty_stmt_syntax &node) override;
41+
42+
llvm::LLVMContext &context;
43+
llvm::IRBuilder<> builder;
44+
std::unique_ptr<llvm::Module> module;
45+
std::unique_ptr<runtime_info> runtime;
46+
47+
llvm::Value *value_result;
48+
int const_result;
49+
50+
llvm::Function *current_function;
51+
int bb_count;
52+
53+
bool lval_as_rval;
54+
bool in_global;
55+
bool constexpr_expected;
56+
57+
c1_recognizer::error_reporter &err;
58+
bool error_flag;
59+
60+
public:
61+
assembly_builder(llvm::LLVMContext &ctx, c1_recognizer::error_reporter &error_stream)
62+
: context(ctx), builder(ctx), err(error_stream) {}
63+
64+
void build(std::string name, std::shared_ptr<c1_recognizer::syntax_tree::syntax_tree_node> tree)
65+
{
66+
// Initialize environment.
67+
module = std::make_unique<llvm::Module>(name, context);
68+
runtime = std::make_unique<runtime_info>(module.get());
69+
70+
enter_scope();
71+
for (auto t : runtime->get_language_symbols())
72+
{
73+
llvm::GlobalValue *val;
74+
std::string name;
75+
bool is_function;
76+
bool is_const;
77+
bool is_array;
78+
std::tie(name, val, is_function, is_const, is_array) = t;
79+
if (is_function)
80+
functions[name] = static_cast<llvm::Function *>(val);
81+
else
82+
declare_variable(name, val, is_const, is_array);
83+
}
84+
85+
lval_as_rval = true;
86+
in_global = true;
87+
constexpr_expected = false;
88+
error_flag = false;
89+
// Start building by starting iterate over the syntax tree.
90+
tree->accept(*this);
91+
// Finish by clear IRBuilder's insertion point and moving away built module.
92+
builder.ClearInsertionPoint();
93+
exit_scope();
94+
if (error_flag)
95+
{
96+
module.release();
97+
runtime.release();
98+
}
99+
}
100+
101+
std::unique_ptr<llvm::Module> get_module() { return std::move(module); }
102+
std::unique_ptr<runtime_info> get_runtime_info() { return std::move(runtime); }
103+
104+
private:
105+
void enter_scope() { variables.emplace_front(); }
106+
107+
void exit_scope() { variables.pop_front(); }
108+
109+
std::tuple<llvm::Value *, bool, bool> lookup_variable(std::string name)
110+
{
111+
for (auto m : variables)
112+
if (m.count(name))
113+
return m[name];
114+
return std::make_tuple((llvm::Value *)nullptr, false, false);
115+
}
116+
117+
bool declare_variable(std::string name, llvm::Value *var_ptr, bool is_const, bool is_array)
118+
{
119+
if (variables.front().count(name))
120+
return false;
121+
variables.front()[name] = std::make_tuple(var_ptr, is_const, is_array);
122+
return true;
123+
}
124+
125+
std::deque<std::unordered_map<std::string, std::tuple<llvm::Value *, bool, bool>>> variables;
126+
127+
std::unordered_map<std::string, llvm::Function *> functions;
128+
};
129+
130+
#endif

c1interpreter/src/main.cpp

+114
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
#include <iostream>
2+
#include <fstream>
3+
#include <string>
4+
#include <stdexcept>
5+
6+
#include <llvm/ExecutionEngine/MCJIT.h>
7+
#include <llvm/ExecutionEngine/GenericValue.h>
8+
#include <llvm/Support/DynamicLibrary.h>
9+
#include <llvm/Support/TargetSelect.h>
10+
11+
#include <c1recognizer/recognizer.h>
12+
13+
#include "assembly_builder.h"
14+
15+
using namespace llvm;
16+
using namespace std;
17+
using namespace c1_recognizer;
18+
using namespace syntax_tree;
19+
using namespace std::literals::string_literals;
20+
21+
int main(int argc, char **argv)
22+
{
23+
char *in_file = nullptr;
24+
bool emit_llvm = false;
25+
for (int i = 1; i < argc; ++i)
26+
if ("-emit-llvm"s == argv[i])
27+
emit_llvm = true;
28+
else if ("-h"s == argv[i] || "--help"s == argv[i])
29+
{
30+
cout << "Usage: c1i [-emit-llvm] <input-c1-source>." << endl;
31+
return 0;
32+
}
33+
else if (argv[i][0] == '-')
34+
{
35+
cerr << "Unknown option '" << argv[i] << "'." << endl;
36+
return 1;
37+
}
38+
else
39+
{
40+
if (!in_file)
41+
in_file = argv[i];
42+
else
43+
{
44+
cerr << "Multiple input file specified. Compiling multiple sources is not supported in C1." << endl;
45+
return 1;
46+
}
47+
}
48+
49+
if (!in_file)
50+
{
51+
cerr << "Input file expected." << endl;
52+
return 1;
53+
}
54+
55+
ifstream in_stream(in_file);
56+
recognizer c1r(in_stream);
57+
58+
error_reporter err(cerr);
59+
if (!c1r.execute(err))
60+
{
61+
cerr << "Parsing failed. Exiting." << endl;
62+
return 2;
63+
}
64+
65+
auto ast = c1r.get_syntax_tree();
66+
67+
string name = in_file;
68+
name = name.substr(name.find_last_of("/\\") + 1);
69+
70+
LLVMContext llvm_ctx;
71+
assembly_builder builder(llvm_ctx, err);
72+
builder.build(name, ast);
73+
auto module = builder.get_module();
74+
auto runtime = builder.get_runtime_info();
75+
76+
if (!module)
77+
{
78+
cerr << "Semantic failed. Exiting." << endl;
79+
return 3;
80+
}
81+
82+
if (emit_llvm)
83+
module->print(outs(), nullptr);
84+
else
85+
{
86+
auto entry_func = module->getFunction("main");
87+
if (!entry_func)
88+
{
89+
cerr << "No 'main' function presented. Exiting." << endl;
90+
return 4;
91+
}
92+
93+
InitializeNativeTarget();
94+
InitializeNativeTargetAsmPrinter();
95+
InitializeNativeTargetAsmParser();
96+
97+
for (auto t : runtime->get_runtime_symbols())
98+
sys::DynamicLibrary::AddSymbol(get<0>(t), get<1>(t));
99+
100+
string error_info;
101+
unique_ptr<ExecutionEngine> engine(EngineBuilder(move(module))
102+
.setEngineKind(EngineKind::JIT)
103+
.setErrorStr(&error_info)
104+
.create());
105+
if (!engine)
106+
{
107+
cerr << "EngineBuilder failed: " << error_info << endl;
108+
return 4;
109+
}
110+
engine->runFunction(entry_func, {});
111+
}
112+
113+
return 0;
114+
}

0 commit comments

Comments
 (0)