Commit 5e3c0318 authored by 王宇航's avatar 王宇航

Lab2 publish

parent ad086fc0
cmake_minimum_required( VERSION 3.8 )
project(CMINUSF)
set(CMAKE_C_FLAGS "${CMAKE_CXX_FLAGS} -std=c99")
SET(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -O0 -Wall -g2 -ggdb")
SET(CMAKE_CXX_FLAGS_RELEASE "$ENV{CXXFLAGS} -O3 -Wall")
SET(CMAKE_CXX_FLAGS_ASAN "${CMAKE_CXX_FLAGS_DEBUG} -fsanitize=undefined -fsanitize=address")
set(default_build_type "Debug")
if(NOT(CMAKE_BUILD_TYPE_SHADOW STREQUAL CMAKE_BUILD_TYPE))
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
message(STATUS "Setting build type to '${default_build_type}'")
set(CMAKE_BUILD_TYPE "${default_build_type}" CACHE STRING "Choose the type of build." FORCE)
else()
message(STATUS "Building in ${CMAKE_BUILD_TYPE} mode")
endif()
set(CMAKE_BUILD_TYPE_SHADOW ${CMAKE_BUILD_TYPE} CACHE STRING "used to detect changes in build type" FORCE)
endif()
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
find_package(FLEX REQUIRED)
find_package(BISON REQUIRED)
find_package(LLVM REQUIRED CONFIG)
message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}")
message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}")
llvm_map_components_to_libnames(
llvm_libs
support
core
)
INCLUDE_DIRECTORIES(
include
include/cminusfc
include/common
include/lightir
${LLVM_INCLUDE_DIRS}
)
add_definitions(${LLVM_DEFINITIONS})
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR})
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR})
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR})
include_directories(${PROJECT_SOURCE_DIR})
include_directories(${PROJECT_BINARY_DIR})
add_subdirectory(src)
add_subdirectory(tests)
This is 2025 compiler.
\ No newline at end of file
# 简介
本仓库为 USTC 编译原理和技术 2025 的课程实验仓库。在本学期的编译实验中,你们将构建一个从词法分析器开始到后端代码生成的JIANMU编译器。
你们需要 fork 此 repo 到自己的仓库下,随后在自己的仓库中完成实验。
## 测试脚本使用方法
eval_lab2.sh:
没有参数,直接运行即可,结果会生成在 eval_result 下
\ No newline at end of file
#pragma once
#include "BasicBlock.hpp"
#include "Constant.hpp"
#include "Function.hpp"
#include "IRBuilder.hpp"
#include "Module.hpp"
#include "Type.hpp"
#include "ast.hpp"
#include <map>
#include <memory>
class Scope {
public:
// enter a new scope
void enter() { inner.emplace_back(); }
// exit a scope
void exit() { inner.pop_back(); }
bool in_global() { return inner.size() == 1; }
// push a name to scope
// return true if successful
// return false if this name already exits
bool push(const std::string& name, Value *val) {
auto result = inner[inner.size() - 1].insert({name, val});
return result.second;
}
Value *find(const std::string& name) {
for (auto s = inner.rbegin(); s != inner.rend(); s++) {
auto iter = s->find(name);
if (iter != s->end()) {
return iter->second;
}
}
// Name not found: handled here?
assert(false && "Name not found in scope");
return nullptr;
}
private:
std::vector<std::map<std::string, Value *>> inner;
};
class CminusfBuilder : public ASTVisitor {
public:
CminusfBuilder() {
module = std::make_unique<Module>();
builder = std::make_unique<IRBuilder>(nullptr, module.get());
auto *TyVoid = module->get_void_type();
auto *TyInt32 = module->get_int32_type();
auto *TyFloat = module->get_float_type();
auto *input_type = FunctionType::get(TyInt32, {});
auto *input_fun = Function::create(input_type, "input", module.get());
std::vector<Type *> output_params;
output_params.push_back(TyInt32);
auto *output_type = FunctionType::get(TyVoid, output_params);
auto *output_fun = Function::create(output_type, "output", module.get());
std::vector<Type *> output_float_params;
output_float_params.push_back(TyFloat);
auto *output_float_type = FunctionType::get(TyVoid, output_float_params);
auto *output_float_fun =
Function::create(output_float_type, "outputFloat", module.get());
auto *neg_idx_except_type = FunctionType::get(TyVoid, {});
auto *neg_idx_except_fun = Function::create(
neg_idx_except_type, "neg_idx_except", module.get());
scope.enter();
scope.push("input", input_fun);
scope.push("output", output_fun);
scope.push("outputFloat", output_float_fun);
scope.push("neg_idx_except", neg_idx_except_fun);
}
std::unique_ptr<Module> getModule() { return std::move(module); }
private:
virtual Value *visit(ASTProgram &) override final;
virtual Value *visit(ASTNum &) override final;
virtual Value *visit(ASTVarDeclaration &) override final;
virtual Value *visit(ASTFunDeclaration &) override final;
virtual Value *visit(ASTParam &) override final;
virtual Value *visit(ASTCompoundStmt &) override final;
virtual Value *visit(ASTExpressionStmt &) override final;
virtual Value *visit(ASTSelectionStmt &) override final;
virtual Value *visit(ASTIterationStmt &) override final;
virtual Value *visit(ASTReturnStmt &) override final;
virtual Value *visit(ASTAssignExpression &) override final;
virtual Value *visit(ASTSimpleExpression &) override final;
virtual Value *visit(ASTAdditiveExpression &) override final;
virtual Value *visit(ASTVar &) override final;
virtual Value *visit(ASTTerm &) override final;
virtual Value *visit(ASTCall &) override final;
std::unique_ptr<IRBuilder> builder;
Scope scope;
std::unique_ptr<Module> module;
struct {
// function that is being built
Function *func = nullptr;
// TODO: you should add more fields to store state
} context;
};
#pragma once
#include <cstdarg>
extern "C" {
#include "syntax_tree.h"
extern syntax_tree *parse(const char *input);
}
#include "User.hpp"
#include <memory>
#include <string>
#include <vector>
enum CminusType { TYPE_INT, TYPE_FLOAT, TYPE_VOID };
enum RelOp {
// <=
OP_LE,
// <
OP_LT,
// >
OP_GT,
// >=
OP_GE,
// ==
OP_EQ,
// !=
OP_NEQ
};
enum AddOp {
// +
OP_PLUS,
// -
OP_MINUS
};
enum MulOp {
// *
OP_MUL,
// /
OP_DIV
};
class AST;
struct ASTNode;
struct ASTProgram;
struct ASTDeclaration;
struct ASTNum;
struct ASTVarDeclaration;
struct ASTFunDeclaration;
struct ASTParam;
struct ASTCompoundStmt;
struct ASTStatement;
struct ASTExpressionStmt;
struct ASTSelectionStmt;
struct ASTIterationStmt;
struct ASTReturnStmt;
struct ASTFactor;
struct ASTExpression;
struct ASTVar;
struct ASTAssignExpression;
struct ASTSimpleExpression;
struct ASTAdditiveExpression;
struct ASTTerm;
struct ASTCall;
class ASTVisitor;
class AST {
public:
AST() = delete;
AST(syntax_tree *);
AST(AST &&tree) {
root = tree.root;
tree.root = nullptr;
};
ASTProgram *get_root() { return root.get(); }
void run_visitor(ASTVisitor &visitor);
private:
ASTNode *transform_node_iter(syntax_tree_node *);
std::shared_ptr<ASTProgram> root = nullptr;
};
struct ASTNode {
virtual Value* accept(ASTVisitor &) = 0;
virtual ~ASTNode() = default;
};
struct ASTProgram : ASTNode {
virtual Value* accept(ASTVisitor &) override final;
virtual ~ASTProgram() = default;
std::vector<std::shared_ptr<ASTDeclaration>> declarations;
};
struct ASTDeclaration : ASTNode {
virtual ~ASTDeclaration() = default;
CminusType type;
std::string id;
};
struct ASTFactor : ASTNode {
virtual ~ASTFactor() = default;
};
struct ASTNum : ASTFactor {
virtual Value* accept(ASTVisitor &) override final;
CminusType type;
union {
int i_val;
float f_val;
};
};
struct ASTVarDeclaration : ASTDeclaration {
virtual Value* accept(ASTVisitor &) override final;
std::shared_ptr<ASTNum> num;
};
struct ASTFunDeclaration : ASTDeclaration {
virtual Value* accept(ASTVisitor &) override final;
std::vector<std::shared_ptr<ASTParam>> params;
std::shared_ptr<ASTCompoundStmt> compound_stmt;
};
struct ASTParam : ASTNode {
virtual Value* accept(ASTVisitor &) override final;
CminusType type;
std::string id;
// true if it is array param
bool isarray;
};
struct ASTStatement : ASTNode {
virtual ~ASTStatement() = default;
};
struct ASTCompoundStmt : ASTStatement {
virtual Value* accept(ASTVisitor &) override final;
std::vector<std::shared_ptr<ASTVarDeclaration>> local_declarations;
std::vector<std::shared_ptr<ASTStatement>> statement_list;
};
struct ASTExpressionStmt : ASTStatement {
virtual Value* accept(ASTVisitor &) override final;
std::shared_ptr<ASTExpression> expression;
};
struct ASTSelectionStmt : ASTStatement {
virtual Value* accept(ASTVisitor &) override final;
std::shared_ptr<ASTExpression> expression;
std::shared_ptr<ASTStatement> if_statement;
// should be nullptr if no else structure exists
std::shared_ptr<ASTStatement> else_statement;
};
struct ASTIterationStmt : ASTStatement {
virtual Value* accept(ASTVisitor &) override final;
std::shared_ptr<ASTExpression> expression;
std::shared_ptr<ASTStatement> statement;
};
struct ASTReturnStmt : ASTStatement {
virtual Value* accept(ASTVisitor &) override final;
// should be nullptr if return void
std::shared_ptr<ASTExpression> expression;
};
struct ASTExpression : ASTFactor {};
struct ASTAssignExpression : ASTExpression {
virtual Value* accept(ASTVisitor &) override final;
std::shared_ptr<ASTVar> var;
std::shared_ptr<ASTExpression> expression;
};
struct ASTSimpleExpression : ASTExpression {
virtual Value* accept(ASTVisitor &) override final;
std::shared_ptr<ASTAdditiveExpression> additive_expression_l;
std::shared_ptr<ASTAdditiveExpression> additive_expression_r;
RelOp op;
};
struct ASTVar : ASTFactor {
virtual Value* accept(ASTVisitor &) override final;
std::string id;
// nullptr if var is of int type
std::shared_ptr<ASTExpression> expression;
};
struct ASTAdditiveExpression : ASTNode {
virtual Value* accept(ASTVisitor &) override final;
std::shared_ptr<ASTAdditiveExpression> additive_expression;
AddOp op;
std::shared_ptr<ASTTerm> term;
};
struct ASTTerm : ASTNode {
virtual Value* accept(ASTVisitor &) override final;
std::shared_ptr<ASTTerm> term;
MulOp op;
std::shared_ptr<ASTFactor> factor;
};
struct ASTCall : ASTFactor {
virtual Value* accept(ASTVisitor &) override final;
std::string id;
std::vector<std::shared_ptr<ASTExpression>> args;
};
class ASTVisitor {
public:
virtual Value* visit(ASTProgram &) = 0;
virtual Value* visit(ASTNum &) = 0;
virtual Value* visit(ASTVarDeclaration &) = 0;
virtual Value* visit(ASTFunDeclaration &) = 0;
virtual Value* visit(ASTParam &) = 0;
virtual Value* visit(ASTCompoundStmt &) = 0;
virtual Value* visit(ASTExpressionStmt &) = 0;
virtual Value* visit(ASTSelectionStmt &) = 0;
virtual Value* visit(ASTIterationStmt &) = 0;
virtual Value* visit(ASTReturnStmt &) = 0;
virtual Value* visit(ASTAssignExpression &) = 0;
virtual Value* visit(ASTSimpleExpression &) = 0;
virtual Value* visit(ASTAdditiveExpression &) = 0;
virtual Value* visit(ASTVar &) = 0;
virtual Value* visit(ASTTerm &) = 0;
virtual Value* visit(ASTCall &) = 0;
};
class ASTPrinter : public ASTVisitor {
public:
virtual Value* visit(ASTProgram &) override final;
virtual Value* visit(ASTNum &) override final;
virtual Value* visit(ASTVarDeclaration &) override final;
virtual Value* visit(ASTFunDeclaration &) override final;
virtual Value* visit(ASTParam &) override final;
virtual Value* visit(ASTCompoundStmt &) override final;
virtual Value* visit(ASTExpressionStmt &) override final;
virtual Value* visit(ASTSelectionStmt &) override final;
virtual Value* visit(ASTIterationStmt &) override final;
virtual Value* visit(ASTReturnStmt &) override final;
virtual Value* visit(ASTAssignExpression &) override final;
virtual Value* visit(ASTSimpleExpression &) override final;
virtual Value* visit(ASTAdditiveExpression &) override final;
virtual Value* visit(ASTVar &) override final;
virtual Value* visit(ASTTerm &) override final;
virtual Value* visit(ASTCall &) override final;
void add_depth() { depth += 2; }
void remove_depth() { depth -= 2; }
private:
int depth = 0;
};
#ifndef LOGGING_HPP
#define LOGGING_HPP
#include <cstdlib>
#include <iostream>
#include <sstream>
enum LogLevel { DEBUG = 0, INFO, WARNING, ERROR };
struct LocationInfo {
LocationInfo(std::string file, int line, const char *func)
: file_(file), line_(line), func_(func) {}
~LocationInfo() = default;
std::string file_;
int line_;
const char *func_;
};
class LogStream;
class LogWriter;
class LogWriter {
public:
LogWriter(LocationInfo location, LogLevel loglevel)
: location_(location), log_level_(loglevel) {
char *logv = std::getenv("LOGV");
if (logv) {
std::string string_logv = logv;
env_log_level = std::stoi(logv);
} else {
env_log_level = 4;
}
};
void operator<(const LogStream &stream);
private:
void output_log(const std::ostringstream &g);
LocationInfo location_;
LogLevel log_level_;
int env_log_level;
};
class LogStream {
public:
template <typename T> LogStream &operator<<(const T &val) noexcept {
sstream_ << val;
return *this;
}
friend class LogWriter;
private:
std::stringstream sstream_{};
};
std::string level2string(LogLevel level);
std::string get_short_name(const char *file_path);
#define __FILESHORTNAME__ get_short_name(__FILE__)
#define LOG_IF(level) \
LogWriter(LocationInfo(__FILESHORTNAME__, __LINE__, __FUNCTION__), \
level) < LogStream()
#define LOG(level) LOG_##level
#define LOG_DEBUG LOG_IF(DEBUG)
#define LOG_INFO LOG_IF(INFO)
#define LOG_WARNING LOG_IF(WARNING)
#define LOG_ERROR LOG_IF(ERROR)
#endif
#ifndef __SYNTAXTREE_H__
#define __SYNTAXTREE_H__
#include <stdio.h>
#define SYNTAX_TREE_NODE_NAME_MAX 30
struct _syntax_tree_node {
struct _syntax_tree_node *parent;
struct _syntax_tree_node *children[10];
int children_num;
char name[SYNTAX_TREE_NODE_NAME_MAX];
};
typedef struct _syntax_tree_node syntax_tree_node;
syntax_tree_node *new_anon_syntax_tree_node();
syntax_tree_node *new_syntax_tree_node(const char *name);
int syntax_tree_add_child(syntax_tree_node *parent, syntax_tree_node *child);
void del_syntax_tree_node(syntax_tree_node *node, int recursive);
struct _syntax_tree {
syntax_tree_node *root;
};
typedef struct _syntax_tree syntax_tree;
syntax_tree *new_syntax_tree();
void del_syntax_tree(syntax_tree *tree);
void print_syntax_tree(FILE *fout, syntax_tree *tree);
#endif /* SyntaxTree.h */
#pragma once
#include "Instruction.hpp"
#include "Value.hpp"
#include <list>
#include <llvm/ADT/ilist.h>
#include <llvm/ADT/ilist_node.h>
#include <set>
#include <string>
class Function;
class Instruction;
class Module;
class BasicBlock : public Value, public llvm::ilist_node<BasicBlock> {
public:
~BasicBlock() = default;
static BasicBlock *create(Module *m, const std::string &name,
Function *parent) {
auto prefix = name.empty() ? "" : "label_";
return new BasicBlock(m, prefix + name, parent);
}
/****************api about cfg****************/
std::list<BasicBlock *> &get_pre_basic_blocks() { return pre_bbs_; }
std::list<BasicBlock *> &get_succ_basic_blocks() { return succ_bbs_; }
void add_pre_basic_block(BasicBlock *bb) { pre_bbs_.push_back(bb); }
void add_succ_basic_block(BasicBlock *bb) { succ_bbs_.push_back(bb); }
void remove_pre_basic_block(BasicBlock *bb) { pre_bbs_.remove(bb); }
void remove_succ_basic_block(BasicBlock *bb) { succ_bbs_.remove(bb); }
// If the Block is terminated by ret/br
bool is_terminated() const;
// Get terminator, only accept valid case use
Instruction *get_terminator();
/****************api about Instruction****************/
void add_instruction(Instruction *instr);
void add_instr_begin(Instruction *instr) { instr_list_.push_front(instr); }
void erase_instr(Instruction *instr) { instr_list_.erase(instr); }
void remove_instr(Instruction *instr) { instr_list_.remove(instr); }
llvm::ilist<Instruction> &get_instructions() { return instr_list_; }
bool empty() const { return instr_list_.empty(); }
int get_num_of_instr() const { return instr_list_.size(); }
/****************api about accessing parent****************/
Function *get_parent() { return parent_; }
Module *get_module();
void erase_from_parent();
virtual std::string print() override;
private:
BasicBlock(const BasicBlock &) = delete;
explicit BasicBlock(Module *m, const std::string &name, Function *parent);
std::list<BasicBlock *> pre_bbs_;
std::list<BasicBlock *> succ_bbs_;
llvm::ilist<Instruction> instr_list_;
Function *parent_;
};
#pragma once
#include "Type.hpp"
#include "User.hpp"
#include "Value.hpp"
class Constant : public User {
private:
// int value;
public:
Constant(Type *ty, const std::string &name = "") : User(ty, name) {}
~Constant() = default;
};
class ConstantInt : public Constant {
private:
int value_;
ConstantInt(Type *ty, int val) : Constant(ty, ""), value_(val) {}
public:
int get_value() { return value_; }
static ConstantInt *get(int val, Module *m);
static ConstantInt *get(bool val, Module *m);
virtual std::string print() override;
};
class ConstantArray : public Constant {
private:
std::vector<Constant *> const_array;
ConstantArray(ArrayType *ty, const std::vector<Constant *> &val);
public:
~ConstantArray() = default;
Constant *get_element_value(int index);
unsigned get_size_of_array() { return const_array.size(); }
static ConstantArray *get(ArrayType *ty,
const std::vector<Constant *> &val);
virtual std::string print() override;
};
class ConstantZero : public Constant {
private:
ConstantZero(Type *ty) : Constant(ty, "") {}
public:
static ConstantZero *get(Type *ty, Module *m);
virtual std::string print() override;
};
class ConstantFP : public Constant {
private:
float val_;
ConstantFP(Type *ty, float val) : Constant(ty, ""), val_(val) {}
public:
static ConstantFP *get(float val, Module *m);
float get_value() { return val_; }
virtual std::string print() override;
};
#pragma once
#include "BasicBlock.hpp"
#include "Type.hpp"
#include "User.hpp"
#include <cassert>
#include <cstddef>
#include <iterator>
#include <list>
#include <llvm/ADT/ilist.h>
#include <llvm/ADT/ilist_node.h>
#include <map>
#include <memory>
class Module;
class Argument;
class Type;
class FunctionType;
class Function : public Value, public llvm::ilist_node<Function> {
public:
Function(const Function &) = delete;
Function(FunctionType *ty, const std::string &name, Module *parent);
~Function() = default;
static Function *create(FunctionType *ty, const std::string &name,
Module *parent);
FunctionType *get_function_type() const;
Type *get_return_type() const;
void add_basic_block(BasicBlock *bb);
unsigned get_num_of_args() const;
unsigned get_num_basic_blocks() const;
Module *get_parent() const;
void remove(BasicBlock *bb);
BasicBlock *get_entry_block() { return &*basic_blocks_.begin(); }
llvm::ilist<BasicBlock> &get_basic_blocks() { return basic_blocks_; }
std::list<Argument> &get_args() { return arguments_; }
bool is_declaration() { return basic_blocks_.empty(); }
void set_instr_name();
std::string print();
private:
llvm::ilist<BasicBlock> basic_blocks_;
std::list<Argument> arguments_;
Module *parent_;
unsigned seq_cnt_; // print use
};
// Argument of Function, does not contain actual value
class Argument : public Value {
public:
Argument(const Argument &) = delete;
explicit Argument(Type *ty, const std::string &name = "",
Function *f = nullptr, unsigned arg_no = 0)
: Value(ty, name), parent_(f), arg_no_(arg_no) {}
virtual ~Argument() {}
inline const Function *get_parent() const { return parent_; }
inline Function *get_parent() { return parent_; }
/// For example in "void foo(int a, float b)" a is 0 and b is 1.
unsigned get_arg_no() const {
assert(parent_ && "can't get number of unparented arg");
return arg_no_;
}
virtual std::string print() override;
private:
Function *parent_;
unsigned arg_no_; // argument No.
};
#pragma once
#include "Constant.hpp"
#include "User.hpp"
#include <llvm/ADT/ilist_node.h>
class Module;
class GlobalVariable : public User, public llvm::ilist_node<GlobalVariable> {
private:
bool is_const_;
Constant *init_val_;
GlobalVariable(std::string name, Module *m, Type *ty, bool is_const,
Constant *init = nullptr);
public:
GlobalVariable(const GlobalVariable &) = delete;
static GlobalVariable *create(std::string name, Module *m, Type *ty,
bool is_const, Constant *init);
virtual ~GlobalVariable() = default;
Constant *get_init() { return init_val_; }
bool is_const() { return is_const_; }
std::string print();
};
#pragma once
#include "BasicBlock.hpp"
#include "Function.hpp"
#include "Instruction.hpp"
#include "Value.hpp"
class IRBuilder {
private:
BasicBlock *BB_;
Module *m_;
public:
IRBuilder(BasicBlock *bb, Module *m) : BB_(bb), m_(m){};
~IRBuilder() = default;
Module *get_module() { return m_; }
BasicBlock *get_insert_block() { return this->BB_; }
void set_insert_point(BasicBlock *bb) {
this->BB_ = bb;
} // 在某个基本块中插入指令
IBinaryInst *create_iadd(Value *lhs, Value *rhs) {
return IBinaryInst::create_add(lhs, rhs, this->BB_);
} // 创建加法指令(以及其他算术指令)
IBinaryInst *create_isub(Value *lhs, Value *rhs) {
return IBinaryInst::create_sub(lhs, rhs, this->BB_);
}
IBinaryInst *create_imul(Value *lhs, Value *rhs) {
return IBinaryInst::create_mul(lhs, rhs, this->BB_);
}
IBinaryInst *create_isdiv(Value *lhs, Value *rhs) {
return IBinaryInst::create_sdiv(lhs, rhs, this->BB_);
}
ICmpInst *create_icmp_eq(Value *lhs, Value *rhs) {
return ICmpInst::create_eq(lhs, rhs, this->BB_);
}
ICmpInst *create_icmp_ne(Value *lhs, Value *rhs) {
return ICmpInst::create_ne(lhs, rhs, this->BB_);
}
ICmpInst *create_icmp_gt(Value *lhs, Value *rhs) {
return ICmpInst::create_gt(lhs, rhs, this->BB_);
}
ICmpInst *create_icmp_ge(Value *lhs, Value *rhs) {
return ICmpInst::create_ge(lhs, rhs, this->BB_);
}
ICmpInst *create_icmp_lt(Value *lhs, Value *rhs) {
return ICmpInst::create_lt(lhs, rhs, this->BB_);
}
ICmpInst *create_icmp_le(Value *lhs, Value *rhs) {
return ICmpInst::create_le(lhs, rhs, this->BB_);
}
CallInst *create_call(Value *func, std::vector<Value *> args) {
return CallInst::create_call(static_cast<Function *>(func), args,
this->BB_);
}
BranchInst *create_br(BasicBlock *if_true) {
return BranchInst::create_br(if_true, this->BB_);
}
BranchInst *create_cond_br(Value *cond, BasicBlock *if_true,
BasicBlock *if_false) {
return BranchInst::create_cond_br(cond, if_true, if_false, this->BB_);
}
ReturnInst *create_ret(Value *val) {
return ReturnInst::create_ret(val, this->BB_);
}
ReturnInst *create_void_ret() {
return ReturnInst::create_void_ret(this->BB_);
}
GetElementPtrInst *create_gep(Value *ptr, std::vector<Value *> idxs) {
return GetElementPtrInst::create_gep(ptr, idxs, this->BB_);
}
StoreInst *create_store(Value *val, Value *ptr) {
return StoreInst::create_store(val, ptr, this->BB_);
}
LoadInst *create_load(Value *ptr) {
assert(ptr->get_type()->is_pointer_type() &&
"ptr must be pointer type");
return LoadInst::create_load(ptr, this->BB_);
}
AllocaInst *create_alloca(Type *ty) {
return AllocaInst::create_alloca(ty, this->BB_);
}
ZextInst *create_zext(Value *val, Type *ty) {
return ZextInst::create_zext(val, ty, this->BB_);
}
SiToFpInst *create_sitofp(Value *val, Type *ty) {
return SiToFpInst::create_sitofp(val, this->BB_);
}
FpToSiInst *create_fptosi(Value *val, Type *ty) {
return FpToSiInst::create_fptosi(val, ty, this->BB_);
}
FCmpInst *create_fcmp_ne(Value *lhs, Value *rhs) {
return FCmpInst::create_fne(lhs, rhs, this->BB_);
}
FCmpInst *create_fcmp_lt(Value *lhs, Value *rhs) {
return FCmpInst::create_flt(lhs, rhs, this->BB_);
}
FCmpInst *create_fcmp_le(Value *lhs, Value *rhs) {
return FCmpInst::create_fle(lhs, rhs, this->BB_);
}
FCmpInst *create_fcmp_ge(Value *lhs, Value *rhs) {
return FCmpInst::create_fge(lhs, rhs, this->BB_);
}
FCmpInst *create_fcmp_gt(Value *lhs, Value *rhs) {
return FCmpInst::create_fgt(lhs, rhs, this->BB_);
}
FCmpInst *create_fcmp_eq(Value *lhs, Value *rhs) {
return FCmpInst::create_feq(lhs, rhs, this->BB_);
}
FBinaryInst *create_fadd(Value *lhs, Value *rhs) {
return FBinaryInst::create_fadd(lhs, rhs, this->BB_);
}
FBinaryInst *create_fsub(Value *lhs, Value *rhs) {
return FBinaryInst::create_fsub(lhs, rhs, this->BB_);
}
FBinaryInst *create_fmul(Value *lhs, Value *rhs) {
return FBinaryInst::create_fmul(lhs, rhs, this->BB_);
}
FBinaryInst *create_fdiv(Value *lhs, Value *rhs) {
return FBinaryInst::create_fdiv(lhs, rhs, this->BB_);
}
};
#pragma once
#include "BasicBlock.hpp"
#include "Constant.hpp"
#include "Function.hpp"
#include "GlobalVariable.hpp"
#include "Instruction.hpp"
#include "Module.hpp"
#include "Type.hpp"
#include "User.hpp"
#include "Value.hpp"
std::string print_as_op(Value *v, bool print_ty);
std::string print_instr_op_name(Instruction::OpID);
This diff is collapsed.
#pragma once
#include "Function.hpp"
#include "GlobalVariable.hpp"
#include "Instruction.hpp"
#include "Type.hpp"
#include "Value.hpp"
#include <list>
#include <llvm/ADT/ilist.h>
#include <llvm/ADT/ilist_node.h>
#include <map>
#include <memory>
#include <string>
class GlobalVariable;
class Function;
class Module {
public:
Module();
~Module() = default;
Type *get_void_type();
Type *get_label_type();
IntegerType *get_int1_type();
IntegerType *get_int32_type();
PointerType *get_int32_ptr_type();
FloatType *get_float_type();
PointerType *get_float_ptr_type();
PointerType *get_pointer_type(Type *contained);
ArrayType *get_array_type(Type *contained, unsigned num_elements);
FunctionType *get_function_type(Type *retty, std::vector<Type *> &args);
void add_function(Function *f);
llvm::ilist<Function> &get_functions();
void add_global_variable(GlobalVariable *g);
llvm::ilist<GlobalVariable> &get_global_variable();
void set_print_name();
std::string print();
private:
// The global variables in the module
llvm::ilist<GlobalVariable> global_list_;
// The functions in the module
llvm::ilist<Function> function_list_;
std::unique_ptr<IntegerType> int1_ty_;
std::unique_ptr<IntegerType> int32_ty_;
std::unique_ptr<Type> label_ty_;
std::unique_ptr<Type> void_ty_;
std::unique_ptr<FloatType> float32_ty_;
std::map<Type *, std::unique_ptr<PointerType>> pointer_map_;
std::map<std::pair<Type *, int>, std::unique_ptr<ArrayType>> array_map_;
std::map<std::pair<Type *, std::vector<Type *>>,
std::unique_ptr<FunctionType>>
function_map_;
};
#pragma once
#include <iostream>
#include <vector>
class Module;
class IntegerType;
class FunctionType;
class ArrayType;
class PointerType;
class FloatType;
class Type {
public:
enum TypeID {
VoidTyID, // Void
LabelTyID, // Labels, e.g., BasicBlock
IntegerTyID, // Integers, include 32 bits and 1 bit
FunctionTyID, // Functions
ArrayTyID, // Arrays
PointerTyID, // Pointer
FloatTyID // float
};
explicit Type(TypeID tid, Module *m);
~Type() = default;
TypeID get_type_id() const { return tid_; }
bool is_void_type() const { return get_type_id() == VoidTyID; }
bool is_label_type() const { return get_type_id() == LabelTyID; }
bool is_integer_type() const { return get_type_id() == IntegerTyID; }
bool is_function_type() const { return get_type_id() == FunctionTyID; }
bool is_array_type() const { return get_type_id() == ArrayTyID; }
bool is_pointer_type() const { return get_type_id() == PointerTyID; }
bool is_float_type() const { return get_type_id() == FloatTyID; }
bool is_int32_type() const;
bool is_int1_type() const;
// Return related data member if is the required type, else throw error
Type *get_pointer_element_type() const;
Type *get_array_element_type() const;
Module *get_module() const { return m_; }
unsigned get_size() const;
std::string print() const;
private:
TypeID tid_;
Module *m_;
};
class IntegerType : public Type {
public:
explicit IntegerType(unsigned num_bits, Module *m);
unsigned get_num_bits() const;
private:
unsigned num_bits_;
};
class FunctionType : public Type {
public:
FunctionType(Type *result, std::vector<Type *> params);
static bool is_valid_return_type(Type *ty);
static bool is_valid_argument_type(Type *ty);
static FunctionType *get(Type *result, std::vector<Type *> params);
unsigned get_num_of_args() const;
Type *get_param_type(unsigned i) const;
std::vector<Type *>::iterator param_begin() { return args_.begin(); }
std::vector<Type *>::iterator param_end() { return args_.end(); }
Type *get_return_type() const;
private:
Type *result_;
std::vector<Type *> args_;
};
class ArrayType : public Type {
public:
ArrayType(Type *contained, unsigned num_elements);
static bool is_valid_element_type(Type *ty);
static ArrayType *get(Type *contained, unsigned num_elements);
Type *get_element_type() const { return contained_; }
unsigned get_num_of_elements() const { return num_elements_; }
private:
Type *contained_; // The element type of the array.
unsigned num_elements_; // Number of elements in the array.
};
class PointerType : public Type {
public:
PointerType(Type *contained);
Type *get_element_type() const { return contained_; }
static PointerType *get(Type *contained);
private:
Type *contained_; // The element type of the ptr.
};
class FloatType : public Type {
public:
FloatType(Module *m);
static FloatType *get(Module *m);
private:
};
#pragma once
#include "Value.hpp"
#include <vector>
class User : public Value {
public:
User(Type *ty, const std::string &name = "") : Value(ty, name){};
virtual ~User() { remove_all_operands(); }
const std::vector<Value *> &get_operands() const { return operands_; }
unsigned get_num_operand() const { return operands_.size(); }
// start from 0
Value *get_operand(unsigned i) const { return operands_.at(i); };
// start from 0
void set_operand(unsigned i, Value *v);
void add_operand(Value *v);
void remove_all_operands();
void remove_operand(unsigned i);
private:
std::vector<Value *> operands_; // operands of this value
};
/* For example: op = func(a, b)
* for a: Use(op, 0)
* for b: Use(op, 1)
*/
struct Use {
User *val_; // used by whom
unsigned arg_no_; // the no. of operand
Use(User *val, unsigned no) : val_(val), arg_no_(no) {}
bool operator==(const Use &other) const {
return val_ == other.val_ and arg_no_ == other.arg_no_;
}
};
#pragma once
#include <functional>
#include <iostream>
#include <list>
#include <string>
#include <cassert>
class Type;
class Value;
class User;
struct Use;
class Value {
public:
explicit Value(Type *ty, const std::string &name = "")
: type_(ty), name_(name){};
virtual ~Value() { replace_all_use_with(nullptr); }
std::string get_name() const { return name_; };
Type *get_type() const { return type_; }
const std::list<Use> &get_use_list() const { return use_list_; }
bool set_name(std::string name);
void add_use(User *user, unsigned arg_no);
void remove_use(User *user, unsigned arg_no);
void replace_all_use_with(Value *new_val);
void replace_use_with_if(Value *new_val, std::function<bool(Use *)> pred);
virtual std::string print() = 0;
template<typename T>
T *as()
{
static_assert(std::is_base_of<Value, T>::value, "T must be a subclass of Value");
const auto ptr = dynamic_cast<T*>(this);
assert(ptr && "dynamic_cast failed");
return ptr;
}
template<typename T>
[[nodiscard]] const T* as() const {
static_assert(std::is_base_of<Value, T>::value, "T must be a subclass of Value");
const auto ptr = dynamic_cast<const T*>(this);
assert(ptr);
return ptr;
}
// is 接口
template <typename T>
[[nodiscard]] bool is() const {
static_assert(std::is_base_of<Value, T>::value, "T must be a subclass of Value");
return dynamic_cast<const T*>(this);
}
private:
Type *type_;
std::list<Use> use_list_; // who use this value
std::string name_; // should we put name field here ?
};
add_subdirectory(parser)
add_subdirectory(common)
add_subdirectory(logging)
add_subdirectory(cminusfc)
add_subdirectory(lightir)
add_subdirectory(io)
\ No newline at end of file
add_executable(
cminusfc
main.cpp
cminusf_builder.cpp
)
target_link_libraries(
cminusfc
IR_lib
common
syntax
stdc++fs
)
install(
TARGETS cminusfc
RUNTIME DESTINATION bin
)
#include "cminusf_builder.hpp"
#define CONST_FP(num) ConstantFP::get((float)num, module.get())
#define CONST_INT(num) ConstantInt::get(num, module.get())
// types
Type *VOID_T;
Type *INT1_T;
Type *INT32_T;
Type *INT32PTR_T;
Type *FLOAT_T;
Type *FLOATPTR_T;
/*
* use CMinusfBuilder::Scope to construct scopes
* scope.enter: enter a new scope
* scope.exit: exit current scope
* scope.push: add a new binding to current scope
* scope.find: find and return the value bound to the name
*/
Value* CminusfBuilder::visit(ASTProgram &node) {
VOID_T = module->get_void_type();
INT1_T = module->get_int1_type();
INT32_T = module->get_int32_type();
INT32PTR_T = module->get_int32_ptr_type();
FLOAT_T = module->get_float_type();
FLOATPTR_T = module->get_float_ptr_type();
Value *ret_val = nullptr;
for (auto &decl : node.declarations) {
ret_val = decl->accept(*this);
}
return ret_val;
}
Value* CminusfBuilder::visit(ASTNum &node) {
// TODO: This function is empty now.
// Add some code here.
return nullptr;
}
Value* CminusfBuilder::visit(ASTVarDeclaration &node) {
// TODO: This function is empty now.
// Add some code here.
return nullptr;
}
Value* CminusfBuilder::visit(ASTFunDeclaration &node) {
FunctionType *fun_type;
Type *ret_type;
std::vector<Type *> param_types;
if (node.type == TYPE_INT)
ret_type = INT32_T;
else if (node.type == TYPE_FLOAT)
ret_type = FLOAT_T;
else
ret_type = VOID_T;
for (auto &param : node.params) {
// TODO: Please accomplish param_types.
}
fun_type = FunctionType::get(ret_type, param_types);
auto func = Function::create(fun_type, node.id, module.get());
scope.push(node.id, func);
context.func = func;
auto funBB = BasicBlock::create(module.get(), "entry", func);
builder->set_insert_point(funBB);
scope.enter();
std::vector<Value *> args;
for (auto &arg : func->get_args()) {
args.push_back(&arg);
}
for (unsigned int i = 0; i < node.params.size(); ++i) {
// TODO: You need to deal with params and store them in the scope.
}
node.compound_stmt->accept(*this);
if (not builder->get_insert_block()->is_terminated())
{
if (context.func->get_return_type()->is_void_type())
builder->create_void_ret();
else if (context.func->get_return_type()->is_float_type())
builder->create_ret(CONST_FP(0.));
else
builder->create_ret(CONST_INT(0));
}
scope.exit();
return nullptr;
}
Value* CminusfBuilder::visit(ASTParam &node) {
// TODO: This function is empty now.
// Add some code here.
return nullptr;
}
Value* CminusfBuilder::visit(ASTCompoundStmt &node) {
// TODO: This function is not complete.
// You may need to add some code here
// to deal with complex statements.
for (auto &decl : node.local_declarations) {
decl->accept(*this);
}
for (auto &stmt : node.statement_list) {
stmt->accept(*this);
if (builder->get_insert_block()->is_terminated())
break;
}
return nullptr;
}
Value* CminusfBuilder::visit(ASTExpressionStmt &node) {
// TODO: This function is empty now.
// Add some code here.
return nullptr;
}
Value* CminusfBuilder::visit(ASTSelectionStmt &node) {
// TODO: This function is empty now.
// Add some code here.
return nullptr;
}
Value* CminusfBuilder::visit(ASTIterationStmt &node) {
// TODO: This function is empty now.
// Add some code here.
return nullptr;
}
Value* CminusfBuilder::visit(ASTReturnStmt &node) {
if (node.expression == nullptr) {
builder->create_void_ret();
return nullptr;
} else {
// TODO: The given code is incomplete.
// You need to solve other return cases (e.g. return an integer).
}
return nullptr;
}
Value* CminusfBuilder::visit(ASTVar &node) {
// TODO: This function is empty now.
// Add some code here.
return nullptr;
}
Value* CminusfBuilder::visit(ASTAssignExpression &node) {
// TODO: This function is empty now.
// Add some code here.
return nullptr;
}
Value* CminusfBuilder::visit(ASTSimpleExpression &node) {
// TODO: This function is empty now.
// Add some code here.
return nullptr;
}
Value* CminusfBuilder::visit(ASTAdditiveExpression &node) {
// TODO: This function is empty now.
// Add some code here.
return nullptr;
}
Value* CminusfBuilder::visit(ASTTerm &node) {
// TODO: This function is empty now.
// Add some code here.
return nullptr;
}
Value* CminusfBuilder::visit(ASTCall &node) {
// TODO: This function is empty now.
// Add some code here.
return nullptr;
}
#include "Module.hpp"
#include "ast.hpp"
#include "cminusf_builder.hpp"
#include <filesystem>
#include <fstream>
#include <iostream>
#include <string>
using std::string;
using std::operator""s;
struct Config {
string exe_name; // compiler exe name
std::filesystem::path input_file;
std::filesystem::path output_file;
bool emitast{false};
bool emitllvm{false};
Config(int argc, char **argv) : argc(argc), argv(argv) {
parse_cmd_line();
check();
}
private:
int argc{-1};
char **argv{nullptr};
void parse_cmd_line();
void check();
// print helper infomation and exit
void print_help() const;
void print_err(const string &msg) const;
};
int main(int argc, char **argv) {
Config config(argc, argv);
auto syntax_tree = parse(config.input_file.c_str());
auto ast = AST(syntax_tree);
if (config.emitast) { // if emit ast (lab1), print ast and return
ASTPrinter printer;
ast.run_visitor(printer);
} else {
std::unique_ptr<Module> m;
CminusfBuilder builder;
ast.run_visitor(builder);
m = builder.getModule();
std::ofstream output_stream(config.output_file);
if (config.emitllvm) {
auto abs_path = std::filesystem::canonical(config.input_file);
output_stream << "; ModuleID = 'cminus'\n";
output_stream << "source_filename = " << abs_path << "\n\n";
output_stream << m->print();
}
// TODO: lab3 lab4 (IR optimization or codegen)
}
return 0;
}
void Config::parse_cmd_line() {
exe_name = argv[0];
for (int i = 1; i < argc; ++i) {
if (argv[i] == "-h"s || argv[i] == "--help"s) {
print_help();
} else if (argv[i] == "-o"s) {
if (output_file.empty() && i + 1 < argc) {
output_file = argv[i + 1];
i += 1;
} else {
print_err("bad output file");
}
} else if (argv[i] == "-emit-ast"s) {
emitast = true;
} else if (argv[i] == "-emit-llvm"s) {
emitllvm = true;
} else {
if (input_file.empty()) {
input_file = argv[i];
} else {
string err =
"unrecognized command-line option \'"s + argv[i] + "\'"s;
print_err(err);
}
}
}
}
void Config::check() {
if (input_file.empty()) {
print_err("no input file");
}
if (input_file.extension() != ".cminus") {
print_err("file format not recognized");
}
if (output_file.empty()) {
output_file = input_file.stem();
}
}
void Config::print_help() const {
std::cout << "Usage: " << exe_name
<< " [-h|--help] [-o <target-file>] [-mem2reg] [-emit-llvm] [-S] "
"<input-file>"
<< std::endl;
exit(0);
}
void Config::print_err(const string &msg) const {
std::cout << exe_name << ": " << msg << std::endl;
exit(-1);
}
add_library(common STATIC
syntax_tree.c
ast.cpp
logging.cpp
)
target_link_libraries(common)
This diff is collapsed.
#include "logging.hpp"
void LogWriter::operator<(const LogStream &stream) {
std::ostringstream msg;
msg << stream.sstream_.rdbuf();
output_log(msg);
}
void LogWriter::output_log(const std::ostringstream &msg) {
if (log_level_ >= env_log_level)
std::cout << "[" << level2string(log_level_) << "] "
<< "(" << location_.file_ << ":" << location_.line_ << "L "
<< location_.func_ << ")" << msg.str() << std::endl;
}
std::string level2string(LogLevel level) {
switch (level) {
case DEBUG:
return "DEBUG";
case INFO:
return "INFO";
case WARNING:
return "WARNING";
case ERROR:
return "ERROR";
default:
return "";
}
}
std::string get_short_name(const char *file_path) {
std::string short_file_path = file_path;
int index = short_file_path.find_last_of('/');
return short_file_path.substr(index + 1);
}
#include <stdlib.h>
#include <string.h>
#include "syntax_tree.h"
syntax_tree_node *new_syntax_tree_node(const char *name) {
syntax_tree_node *new_node =
(syntax_tree_node *)malloc(sizeof(syntax_tree_node));
if (name)
strncpy(new_node->name, name, SYNTAX_TREE_NODE_NAME_MAX);
else
new_node->name[0] = '\0';
new_node->children_num = 0;
return new_node;
}
int syntax_tree_add_child(syntax_tree_node *parent, syntax_tree_node *child) {
if (!parent || !child)
return -1;
parent->children[parent->children_num++] = child;
return parent->children_num;
}
void del_syntax_tree_node(syntax_tree_node *node, int recursive) {
if (!node)
return;
int i;
if (recursive) {
for (i = 0; i < node->children_num; i++) {
del_syntax_tree_node(node->children[i], 1);
}
}
free(node);
}
syntax_tree *new_syntax_tree() {
return (syntax_tree *)malloc(sizeof(syntax_tree));
}
void del_syntax_tree(syntax_tree *tree) {
if (!tree)
return;
if (tree->root) {
del_syntax_tree_node(tree->root, 1);
}
free(tree);
}
void print_syntax_tree_node(FILE *fout, syntax_tree_node *node, int level) {
// assume fout valid now
// check if "node" empty pointer
if (!node)
return;
// print myself
int i;
for (i = 0; i < level; i++) {
fprintf(fout, "| ");
}
fprintf(fout, ">--%s %s\n", (node->children_num ? "+" : "*"), node->name);
for (i = 0; i < node->children_num; i++) {
print_syntax_tree_node(fout, node->children[i], level + 1);
}
}
void print_syntax_tree(FILE *fout, syntax_tree *tree) {
if (!fout)
return;
print_syntax_tree_node(fout, tree->root, 0);
}
add_library(cminus_io io.c)
install(
TARGETS cminus_io
ARCHIVE DESTINATION lib
)
#include <stdio.h>
#include <stdlib.h>
int input() {
int a;
scanf("%d", &a);
return a;
}
void output(int a) { printf("%d\n", a); }
void outputFloat(float a) { printf("%f\n", a); }
void neg_idx_except() {
printf("negative index exception\n");
exit(0);
}
int input();
void output(int a);
void outputFloat(float a);
void neg_idx_except();
#include "BasicBlock.hpp"
#include "Function.hpp"
#include "IRprinter.hpp"
#include "Module.hpp"
#include <cassert>
BasicBlock::BasicBlock(Module *m, const std::string &name = "",
Function *parent = nullptr)
: Value(m->get_label_type(), name), parent_(parent) {
assert(parent && "currently parent should not be nullptr");
parent_->add_basic_block(this);
}
Module *BasicBlock::get_module() { return get_parent()->get_parent(); }
void BasicBlock::erase_from_parent() { this->get_parent()->remove(this); }
bool BasicBlock::is_terminated() const {
if (instr_list_.empty()) {
return false;
}
switch (instr_list_.back().get_instr_type()) {
case Instruction::ret:
case Instruction::br:
return true;
default:
return false;
}
}
Instruction *BasicBlock::get_terminator() {
assert(is_terminated() &&
"Trying to get terminator from an bb which is not terminated");
return &instr_list_.back();
}
void BasicBlock::add_instruction(Instruction *instr) {
assert(not is_terminated() && "Inserting instruction to terminated bb");
instr_list_.push_back(instr);
}
std::string BasicBlock::print() {
std::string bb_ir;
bb_ir += this->get_name();
bb_ir += ":";
// print prebb
if (!this->get_pre_basic_blocks().empty()) {
bb_ir += " ; preds = ";
}
for (auto bb : this->get_pre_basic_blocks()) {
if (bb != *this->get_pre_basic_blocks().begin()) {
bb_ir += ", ";
}
bb_ir += print_as_op(bb, false);
}
// print prebb
if (!this->get_parent()) {
bb_ir += "\n";
bb_ir += "; Error: Block without parent!";
}
bb_ir += "\n";
for (auto &instr : this->get_instructions()) {
bb_ir += " ";
bb_ir += instr.print();
bb_ir += "\n";
}
return bb_ir;
}
add_library(
IR_lib STATIC
Type.cpp
User.cpp
Value.cpp
BasicBlock.cpp
Constant.cpp
Function.cpp
GlobalVariable.cpp
Instruction.cpp
Module.cpp
IRprinter.cpp
)
target_link_libraries(
IR_lib
LLVMSupport
)
#include "Constant.hpp"
#include "Module.hpp"
#include <iostream>
#include <memory>
#include <sstream>
#include <unordered_map>
struct pair_hash {
template <typename T>
std::size_t operator()(const std::pair<T, Module *> val) const {
auto lhs = std::hash<T>()(val.first);
auto rhs =
std::hash<uintptr_t>()(reinterpret_cast<uintptr_t>(val.second));
return lhs ^ rhs;
}
};
static std::unordered_map<std::pair<int, Module *>,
std::unique_ptr<ConstantInt>, pair_hash>
cached_int;
static std::unordered_map<std::pair<bool, Module *>,
std::unique_ptr<ConstantInt>, pair_hash>
cached_bool;
static std::unordered_map<std::pair<float, Module *>,
std::unique_ptr<ConstantFP>, pair_hash>
cached_float;
static std::unordered_map<Type *, std::unique_ptr<ConstantZero>> cached_zero;
ConstantInt *ConstantInt::get(int val, Module *m) {
if (cached_int.find(std::make_pair(val, m)) != cached_int.end())
return cached_int[std::make_pair(val, m)].get();
return (cached_int[std::make_pair(val, m)] = std::unique_ptr<ConstantInt>(
new ConstantInt(m->get_int32_type(), val)))
.get();
}
ConstantInt *ConstantInt::get(bool val, Module *m) {
if (cached_bool.find(std::make_pair(val, m)) != cached_bool.end())
return cached_bool[std::make_pair(val, m)].get();
return (cached_bool[std::make_pair(val, m)] = std::unique_ptr<ConstantInt>(
new ConstantInt(m->get_int1_type(), val ? 1 : 0)))
.get();
}
std::string ConstantInt::print() {
std::string const_ir;
Type *ty = this->get_type();
if (ty->is_integer_type() &&
static_cast<IntegerType *>(ty)->get_num_bits() == 1) {
// int1
const_ir += (this->get_value() == 0) ? "false" : "true";
} else {
// int32
const_ir += std::to_string(this->get_value());
}
return const_ir;
}
ConstantArray::ConstantArray(ArrayType *ty, const std::vector<Constant *> &val)
: Constant(ty, "") {
for (unsigned i = 0; i < val.size(); i++)
set_operand(i, val[i]);
this->const_array.assign(val.begin(), val.end());
}
Constant *ConstantArray::get_element_value(int index) {
return this->const_array[index];
}
ConstantArray *ConstantArray::get(ArrayType *ty,
const std::vector<Constant *> &val) {
return new ConstantArray(ty, val);
}
std::string ConstantArray::print() {
std::string const_ir;
const_ir += this->get_type()->print();
const_ir += " ";
const_ir += "[";
for (unsigned i = 0; i < this->get_size_of_array(); i++) {
Constant *element = get_element_value(i);
if (!dynamic_cast<ConstantArray *>(get_element_value(i))) {
const_ir += element->get_type()->print();
}
const_ir += element->print();
if (i < this->get_size_of_array()) {
const_ir += ", ";
}
}
const_ir += "]";
return const_ir;
}
ConstantFP *ConstantFP::get(float val, Module *m) {
if (cached_float.find(std::make_pair(val, m)) != cached_float.end())
return cached_float[std::make_pair(val, m)].get();
return (cached_float[std::make_pair(val, m)] = std::unique_ptr<ConstantFP>(
new ConstantFP(m->get_float_type(), val)))
.get();
}
std::string ConstantFP::print() {
std::stringstream fp_ir_ss;
std::string fp_ir;
double val = this->get_value();
fp_ir_ss << "0x" << std::hex << *(uint64_t *)&val << std::endl;
fp_ir_ss >> fp_ir;
return fp_ir;
}
ConstantZero *ConstantZero::get(Type *ty, Module *m) {
if (not cached_zero[ty])
cached_zero[ty] = std::unique_ptr<ConstantZero>(new ConstantZero(ty));
return cached_zero[ty].get();
}
std::string ConstantZero::print() { return "zeroinitializer"; }
#include "Function.hpp"
#include "IRprinter.hpp"
#include "Module.hpp"
Function::Function(FunctionType *ty, const std::string &name, Module *parent)
: Value(ty, name), parent_(parent), seq_cnt_(0) {
// num_args_ = ty->getNumParams();
parent->add_function(this);
// build args
for (unsigned i = 0; i < get_num_of_args(); i++) {
arguments_.emplace_back(ty->get_param_type(i), "", this, i);
}
}
Function *Function::create(FunctionType *ty, const std::string &name,
Module *parent) {
return new Function(ty, name, parent);
}
FunctionType *Function::get_function_type() const {
return static_cast<FunctionType *>(get_type());
}
Type *Function::get_return_type() const {
return get_function_type()->get_return_type();
}
unsigned Function::get_num_of_args() const {
return get_function_type()->get_num_of_args();
}
unsigned Function::get_num_basic_blocks() const { return basic_blocks_.size(); }
Module *Function::get_parent() const { return parent_; }
void Function::remove(BasicBlock *bb) {
basic_blocks_.remove(bb);
for (auto pre : bb->get_pre_basic_blocks()) {
pre->remove_succ_basic_block(bb);
}
for (auto succ : bb->get_succ_basic_blocks()) {
succ->remove_pre_basic_block(bb);
}
}
void Function::add_basic_block(BasicBlock *bb) { basic_blocks_.push_back(bb); }
void Function::set_instr_name() {
std::map<Value *, int> seq;
for (auto &arg : this->get_args()) {
if (seq.find(&arg) == seq.end()) {
auto seq_num = seq.size() + seq_cnt_;
if (arg.set_name("arg" + std::to_string(seq_num))) {
seq.insert({&arg, seq_num});
}
}
}
for (auto &bb1 : basic_blocks_) {
auto bb = &bb1;
if (seq.find(bb) == seq.end()) {
auto seq_num = seq.size() + seq_cnt_;
if (bb->set_name("label" + std::to_string(seq_num))) {
seq.insert({bb, seq_num});
}
}
for (auto &instr : bb->get_instructions()) {
if (!instr.is_void() && seq.find(&instr) == seq.end()) {
auto seq_num = seq.size() + seq_cnt_;
if (instr.set_name("op" + std::to_string(seq_num))) {
seq.insert({&instr, seq_num});
}
}
}
}
seq_cnt_ += seq.size();
}
std::string Function::print() {
set_instr_name();
std::string func_ir;
if (this->is_declaration()) {
func_ir += "declare ";
} else {
func_ir += "define ";
}
func_ir += this->get_return_type()->print();
func_ir += " ";
func_ir += print_as_op(this, false);
func_ir += "(";
// print arg
if (this->is_declaration()) {
for (unsigned i = 0; i < this->get_num_of_args(); i++) {
if (i)
func_ir += ", ";
func_ir += static_cast<FunctionType *>(this->get_type())
->get_param_type(i)
->print();
}
} else {
for (auto &arg : get_args()) {
if (&arg != &*get_args().begin())
func_ir += ", ";
func_ir += arg.print();
}
}
func_ir += ")";
// print bb
if (this->is_declaration()) {
func_ir += "\n";
} else {
func_ir += " {";
func_ir += "\n";
for (auto &bb1 : this->get_basic_blocks()) {
auto bb = &bb1;
func_ir += bb->print();
}
func_ir += "}";
}
return func_ir;
}
std::string Argument::print() {
std::string arg_ir;
arg_ir += this->get_type()->print();
arg_ir += " %";
arg_ir += this->get_name();
return arg_ir;
}
#include "GlobalVariable.hpp"
#include "IRprinter.hpp"
GlobalVariable::GlobalVariable(std::string name, Module *m, Type *ty,
bool is_const, Constant *init)
: User(ty, name), is_const_(is_const), init_val_(init) {
m->add_global_variable(this);
if (init) {
this->add_operand(init);
}
} // global操作数为initval
GlobalVariable *GlobalVariable::create(std::string name, Module *m, Type *ty,
bool is_const,
Constant *init = nullptr) {
return new GlobalVariable(name, m, PointerType::get(ty), is_const, init);
}
std::string GlobalVariable::print() {
std::string global_val_ir;
global_val_ir += print_as_op(this, false);
global_val_ir += " = ";
global_val_ir += (this->is_const() ? "constant " : "global ");
global_val_ir += this->get_type()->get_pointer_element_type()->print();
global_val_ir += " ";
global_val_ir += this->get_init()->print();
return global_val_ir;
}
#include "IRprinter.hpp"
#include "Instruction.hpp"
#include <cassert>
#include <type_traits>
std::string print_as_op(Value *v, bool print_ty) {
std::string op_ir;
if (print_ty) {
op_ir += v->get_type()->print();
op_ir += " ";
}
if (dynamic_cast<GlobalVariable *>(v)) {
op_ir += "@" + v->get_name();
} else if (dynamic_cast<Function *>(v)) {
op_ir += "@" + v->get_name();
} else if (dynamic_cast<Constant *>(v)) {
op_ir += v->print();
} else {
op_ir += "%" + v->get_name();
}
return op_ir;
}
std::string print_instr_op_name(Instruction::OpID id) {
switch (id) {
case Instruction::ret:
return "ret";
case Instruction::br:
return "br";
case Instruction::add:
return "add";
case Instruction::sub:
return "sub";
case Instruction::mul:
return "mul";
case Instruction::sdiv:
return "sdiv";
case Instruction::fadd:
return "fadd";
case Instruction::fsub:
return "fsub";
case Instruction::fmul:
return "fmul";
case Instruction::fdiv:
return "fdiv";
case Instruction::alloca:
return "alloca";
case Instruction::load:
return "load";
case Instruction::store:
return "store";
case Instruction::ge:
return "sge";
case Instruction::gt:
return "sgt";
case Instruction::le:
return "sle";
case Instruction::lt:
return "slt";
case Instruction::eq:
return "eq";
case Instruction::ne:
return "ne";
case Instruction::fge:
return "uge";
case Instruction::fgt:
return "ugt";
case Instruction::fle:
return "ule";
case Instruction::flt:
return "ult";
case Instruction::feq:
return "ueq";
case Instruction::fne:
return "une";
case Instruction::phi:
return "phi";
case Instruction::call:
return "call";
case Instruction::getelementptr:
return "getelementptr";
case Instruction::zext:
return "zext";
case Instruction::fptosi:
return "fptosi";
case Instruction::sitofp:
return "sitofp";
}
assert(false && "Must be bug");
}
template <class BinInst> std::string print_binary_inst(const BinInst &inst) {
std::string instr_ir;
instr_ir += "%";
instr_ir += inst.get_name();
instr_ir += " = ";
instr_ir += inst.get_instr_op_name();
instr_ir += " ";
instr_ir += inst.get_operand(0)->get_type()->print();
instr_ir += " ";
instr_ir += print_as_op(inst.get_operand(0), false);
instr_ir += ", ";
if (inst.get_operand(0)->get_type() == inst.get_operand(1)->get_type()) {
instr_ir += print_as_op(inst.get_operand(1), false);
} else {
instr_ir += print_as_op(inst.get_operand(1), true);
}
return instr_ir;
}
std::string IBinaryInst::print() { return print_binary_inst(*this); }
std::string FBinaryInst::print() { return print_binary_inst(*this); }
template <class CMP> std::string print_cmp_inst(const CMP &inst) {
std::string cmp_type;
if (inst.is_cmp())
cmp_type = "icmp";
else if (inst.is_fcmp())
cmp_type = "fcmp";
else
assert(false && "Unexpected case");
std::string instr_ir;
instr_ir += "%";
instr_ir += inst.get_name();
instr_ir += " = " + cmp_type + " ";
instr_ir += inst.get_instr_op_name();
instr_ir += " ";
instr_ir += inst.get_operand(0)->get_type()->print();
instr_ir += " ";
instr_ir += print_as_op(inst.get_operand(0), false);
instr_ir += ", ";
if (inst.get_operand(0)->get_type() == inst.get_operand(1)->get_type()) {
instr_ir += print_as_op(inst.get_operand(1), false);
} else {
instr_ir += print_as_op(inst.get_operand(1), true);
}
return instr_ir;
}
std::string ICmpInst::print() { return print_cmp_inst(*this); }
std::string FCmpInst::print() { return print_cmp_inst(*this); }
std::string CallInst::print() {
std::string instr_ir;
if (!this->is_void()) {
instr_ir += "%";
instr_ir += this->get_name();
instr_ir += " = ";
}
instr_ir += get_instr_op_name();
instr_ir += " ";
instr_ir += this->get_function_type()->get_return_type()->print();
instr_ir += " ";
assert(dynamic_cast<Function *>(this->get_operand(0)) &&
"Wrong call operand function");
instr_ir += print_as_op(this->get_operand(0), false);
instr_ir += "(";
for (unsigned i = 1; i < this->get_num_operand(); i++) {
if (i > 1)
instr_ir += ", ";
instr_ir += this->get_operand(i)->get_type()->print();
instr_ir += " ";
instr_ir += print_as_op(this->get_operand(i), false);
}
instr_ir += ")";
return instr_ir;
}
std::string BranchInst::print() {
std::string instr_ir;
instr_ir += get_instr_op_name();
instr_ir += " ";
instr_ir += print_as_op(this->get_operand(0), true);
if (is_cond_br()) {
instr_ir += ", ";
instr_ir += print_as_op(this->get_operand(1), true);
instr_ir += ", ";
instr_ir += print_as_op(this->get_operand(2), true);
}
return instr_ir;
}
std::string ReturnInst::print() {
std::string instr_ir;
instr_ir += get_instr_op_name();
instr_ir += " ";
if (!is_void_ret()) {
instr_ir += this->get_operand(0)->get_type()->print();
instr_ir += " ";
instr_ir += print_as_op(this->get_operand(0), false);
} else {
instr_ir += "void";
}
return instr_ir;
}
std::string GetElementPtrInst::print() {
std::string instr_ir;
instr_ir += "%";
instr_ir += this->get_name();
instr_ir += " = ";
instr_ir += get_instr_op_name();
instr_ir += " ";
assert(this->get_operand(0)->get_type()->is_pointer_type());
instr_ir +=
this->get_operand(0)->get_type()->get_pointer_element_type()->print();
instr_ir += ", ";
for (unsigned i = 0; i < this->get_num_operand(); i++) {
if (i > 0)
instr_ir += ", ";
instr_ir += this->get_operand(i)->get_type()->print();
instr_ir += " ";
instr_ir += print_as_op(this->get_operand(i), false);
}
return instr_ir;
}
std::string StoreInst::print() {
std::string instr_ir;
instr_ir += get_instr_op_name();
instr_ir += " ";
instr_ir += this->get_operand(0)->get_type()->print();
instr_ir += " ";
instr_ir += print_as_op(this->get_operand(0), false);
instr_ir += ", ";
instr_ir += print_as_op(this->get_operand(1), true);
return instr_ir;
}
std::string LoadInst::print() {
std::string instr_ir;
instr_ir += "%";
instr_ir += this->get_name();
instr_ir += " = ";
instr_ir += get_instr_op_name();
instr_ir += " ";
assert(this->get_operand(0)->get_type()->is_pointer_type());
instr_ir +=
this->get_operand(0)->get_type()->get_pointer_element_type()->print();
instr_ir += ",";
instr_ir += " ";
instr_ir += print_as_op(this->get_operand(0), true);
return instr_ir;
}
std::string AllocaInst::print() {
std::string instr_ir;
instr_ir += "%";
instr_ir += this->get_name();
instr_ir += " = ";
instr_ir += get_instr_op_name();
instr_ir += " ";
instr_ir += get_alloca_type()->print();
return instr_ir;
}
std::string ZextInst::print() {
std::string instr_ir;
instr_ir += "%";
instr_ir += this->get_name();
instr_ir += " = ";
instr_ir += get_instr_op_name();
instr_ir += " ";
instr_ir += this->get_operand(0)->get_type()->print();
instr_ir += " ";
instr_ir += print_as_op(this->get_operand(0), false);
instr_ir += " to ";
instr_ir += this->get_dest_type()->print();
return instr_ir;
}
std::string FpToSiInst::print() {
std::string instr_ir;
instr_ir += "%";
instr_ir += this->get_name();
instr_ir += " = ";
instr_ir += get_instr_op_name();
instr_ir += " ";
instr_ir += this->get_operand(0)->get_type()->print();
instr_ir += " ";
instr_ir += print_as_op(this->get_operand(0), false);
instr_ir += " to ";
instr_ir += this->get_dest_type()->print();
return instr_ir;
}
std::string SiToFpInst::print() {
std::string instr_ir;
instr_ir += "%";
instr_ir += this->get_name();
instr_ir += " = ";
instr_ir += get_instr_op_name();
instr_ir += " ";
instr_ir += this->get_operand(0)->get_type()->print();
instr_ir += " ";
instr_ir += print_as_op(this->get_operand(0), false);
instr_ir += " to ";
instr_ir += this->get_dest_type()->print();
return instr_ir;
}
std::string PhiInst::print() {
std::string instr_ir;
instr_ir += "%";
instr_ir += this->get_name();
instr_ir += " = ";
instr_ir += get_instr_op_name();
instr_ir += " ";
instr_ir += this->get_operand(0)->get_type()->print();
instr_ir += " ";
for (unsigned i = 0; i < this->get_num_operand() / 2; i++) {
if (i > 0)
instr_ir += ", ";
instr_ir += "[ ";
instr_ir += print_as_op(this->get_operand(2 * i), false);
instr_ir += ", ";
instr_ir += print_as_op(this->get_operand(2 * i + 1), false);
instr_ir += " ]";
}
if (this->get_num_operand() / 2 <
this->get_parent()->get_pre_basic_blocks().size()) {
for (auto pre_bb : this->get_parent()->get_pre_basic_blocks()) {
if (std::find(this->get_operands().begin(),
this->get_operands().end(),
static_cast<Value *>(pre_bb)) ==
this->get_operands().end()) {
// find a pre_bb is not in phi
instr_ir += ", [ undef, " + print_as_op(pre_bb, false) + " ]";
}
}
}
return instr_ir;
}
This diff is collapsed.
#include "Module.hpp"
#include "Function.hpp"
#include "GlobalVariable.hpp"
#include <memory>
#include <string>
Module::Module() {
void_ty_ = std::make_unique<Type>(Type::VoidTyID, this);
label_ty_ = std::make_unique<Type>(Type::LabelTyID, this);
int1_ty_ = std::make_unique<IntegerType>(1, this);
int32_ty_ = std::make_unique<IntegerType>(32, this);
float32_ty_ = std::make_unique<FloatType>(this);
}
Type *Module::get_void_type() { return void_ty_.get(); }
Type *Module::get_label_type() { return label_ty_.get(); }
IntegerType *Module::get_int1_type() { return int1_ty_.get(); }
IntegerType *Module::get_int32_type() { return int32_ty_.get(); }
FloatType *Module::get_float_type() { return float32_ty_.get(); }
PointerType *Module::get_int32_ptr_type() {
return get_pointer_type(int32_ty_.get());
}
PointerType *Module::get_float_ptr_type() {
return get_pointer_type(float32_ty_.get());
}
PointerType *Module::get_pointer_type(Type *contained) {
if (pointer_map_.find(contained) == pointer_map_.end()) {
pointer_map_[contained] = std::make_unique<PointerType>(contained);
}
return pointer_map_[contained].get();
}
ArrayType *Module::get_array_type(Type *contained, unsigned num_elements) {
if (array_map_.find({contained, num_elements}) == array_map_.end()) {
array_map_[{contained, num_elements}] =
std::make_unique<ArrayType>(contained, num_elements);
}
return array_map_[{contained, num_elements}].get();
}
FunctionType *Module::get_function_type(Type *retty,
std::vector<Type *> &args) {
if (not function_map_.count({retty, args})) {
function_map_[{retty, args}] =
std::make_unique<FunctionType>(retty, args);
}
return function_map_[{retty, args}].get();
}
void Module::add_function(Function *f) { function_list_.push_back(f); }
llvm::ilist<Function> &Module::get_functions() { return function_list_; }
void Module::add_global_variable(GlobalVariable *g) {
global_list_.push_back(g);
}
llvm::ilist<GlobalVariable> &Module::get_global_variable() {
return global_list_;
}
void Module::set_print_name() {
for (auto &func : this->get_functions()) {
func.set_instr_name();
}
return;
}
std::string Module::print() {
set_print_name();
std::string module_ir;
for (auto &global_val : this->global_list_) {
module_ir += global_val.print();
module_ir += "\n";
}
for (auto &func : this->function_list_) {
module_ir += func.print();
module_ir += "\n";
}
return module_ir;
}
#include "Type.hpp"
#include "Module.hpp"
#include <array>
#include <cassert>
#include <stdexcept>
Type::Type(TypeID tid, Module *m) {
tid_ = tid;
m_ = m;
}
bool Type::is_int1_type() const {
return is_integer_type() and
static_cast<const IntegerType *>(this)->get_num_bits() == 1;
}
bool Type::is_int32_type() const {
return is_integer_type() and
static_cast<const IntegerType *>(this)->get_num_bits() == 32;
}
Type *Type::get_pointer_element_type() const {
if (this->is_pointer_type())
return static_cast<const PointerType *>(this)->get_element_type();
assert(false and "get_pointer_element_type() called on non-pointer type");
}
Type *Type::get_array_element_type() const {
if (this->is_array_type())
return static_cast<const ArrayType *>(this)->get_element_type();
assert(false and "get_array_element_type() called on non-array type");
}
unsigned Type::get_size() const {
switch (get_type_id()) {
case IntegerTyID: {
if (is_int1_type())
return 1;
else if (is_int32_type())
return 4;
else
assert(false && "Type::get_size(): unexpected int type bits");
}
case ArrayTyID: {
auto array_type = static_cast<const ArrayType *>(this);
auto element_size = array_type->get_element_type()->get_size();
auto num_elements = array_type->get_num_of_elements();
return element_size * num_elements;
}
case PointerTyID:
return 8;
case FloatTyID:
return 4;
case VoidTyID:
case LabelTyID:
case FunctionTyID:
assert(false && "bad use on get_size()");
}
assert(false && "unreachable");
}
std::string Type::print() const {
std::string type_ir;
switch (this->get_type_id()) {
case VoidTyID:
type_ir += "void";
break;
case LabelTyID:
type_ir += "label";
break;
case IntegerTyID:
type_ir += "i";
type_ir += std::to_string(
static_cast<const IntegerType *>(this)->get_num_bits());
break;
case FunctionTyID:
type_ir +=
static_cast<const FunctionType *>(this)->get_return_type()->print();
type_ir += " (";
for (unsigned i = 0;
i < static_cast<const FunctionType *>(this)->get_num_of_args();
i++) {
if (i)
type_ir += ", ";
type_ir += static_cast<const FunctionType *>(this)
->get_param_type(i)
->print();
}
type_ir += ")";
break;
case PointerTyID:
type_ir += this->get_pointer_element_type()->print();
type_ir += "*";
break;
case ArrayTyID:
type_ir += "[";
type_ir += std::to_string(
static_cast<const ArrayType *>(this)->get_num_of_elements());
type_ir += " x ";
type_ir +=
static_cast<const ArrayType *>(this)->get_element_type()->print();
type_ir += "]";
break;
case FloatTyID:
type_ir += "float";
break;
default:
break;
}
return type_ir;
}
IntegerType::IntegerType(unsigned num_bits, Module *m)
: Type(Type::IntegerTyID, m), num_bits_(num_bits) {}
unsigned IntegerType::get_num_bits() const { return num_bits_; }
FunctionType::FunctionType(Type *result, std::vector<Type *> params)
: Type(Type::FunctionTyID, nullptr) {
assert(is_valid_return_type(result) && "Invalid return type for function!");
result_ = result;
for (auto p : params) {
assert(is_valid_argument_type(p) &&
"Not a valid type for function argument!");
args_.push_back(p);
}
}
bool FunctionType::is_valid_return_type(Type *ty) {
return ty->is_integer_type() || ty->is_void_type() || ty->is_float_type();
}
bool FunctionType::is_valid_argument_type(Type *ty) {
return ty->is_integer_type() || ty->is_pointer_type() ||
ty->is_float_type();
}
FunctionType *FunctionType::get(Type *result, std::vector<Type *> params) {
return result->get_module()->get_function_type(result, params);
}
unsigned FunctionType::get_num_of_args() const { return args_.size(); }
Type *FunctionType::get_param_type(unsigned i) const { return args_[i]; }
Type *FunctionType::get_return_type() const { return result_; }
ArrayType::ArrayType(Type *contained, unsigned num_elements)
: Type(Type::ArrayTyID, contained->get_module()),
num_elements_(num_elements) {
assert(is_valid_element_type(contained) &&
"Not a valid type for array element!");
contained_ = contained;
}
bool ArrayType::is_valid_element_type(Type *ty) {
return ty->is_integer_type() || ty->is_array_type() || ty->is_float_type();
}
ArrayType *ArrayType::get(Type *contained, unsigned num_elements) {
return contained->get_module()->get_array_type(contained, num_elements);
}
PointerType::PointerType(Type *contained)
: Type(Type::PointerTyID, contained->get_module()), contained_(contained) {
static const std::array allowed_elem_type = {
Type::IntegerTyID, Type::FloatTyID, Type::ArrayTyID, Type::PointerTyID};
auto elem_type_id = contained->get_type_id();
assert(std::find(allowed_elem_type.begin(), allowed_elem_type.end(),
elem_type_id) != allowed_elem_type.end() &&
"Not allowed type for pointer");
}
PointerType *PointerType::get(Type *contained) {
return contained->get_module()->get_pointer_type(contained);
}
FloatType::FloatType(Module *m) : Type(Type::FloatTyID, m) {}
FloatType *FloatType::get(Module *m) { return m->get_float_type(); }
#include "User.hpp"
#include <cassert>
void User::set_operand(unsigned i, Value *v) {
assert(i < operands_.size() && "set_operand out of index");
if (operands_[i]) { // old operand
operands_[i]->remove_use(this, i);
}
if (v) { // new operand
v->add_use(this, i);
}
operands_[i] = v;
}
void User::add_operand(Value *v) {
assert(v != nullptr && "bad use: add_operand(nullptr)");
v->add_use(this, operands_.size());
operands_.push_back(v);
}
void User::remove_all_operands() {
for (unsigned i = 0; i != operands_.size(); ++i) {
if (operands_[i]) {
operands_[i]->remove_use(this, i);
}
}
operands_.clear();
}
void User::remove_operand(unsigned idx) {
assert(idx < operands_.size() && "remove_operand out of index");
// influence on other operands
for (unsigned i = idx + 1; i < operands_.size(); ++i) {
operands_[i]->remove_use(this, i);
operands_[i]->add_use(this, i - 1);
}
// remove the designated operand
operands_[idx]->remove_use(this, idx);
operands_.erase(operands_.begin() + idx);
}
#include "Value.hpp"
#include "Type.hpp"
#include "User.hpp"
#include <cassert>
bool Value::set_name(std::string name) {
if (name_ == "") {
name_ = name;
return true;
}
return false;
}
void Value::add_use(User *user, unsigned arg_no) {
use_list_.emplace_back(user, arg_no);
};
void Value::remove_use(User *user, unsigned arg_no) {
auto target_use = Use(user, arg_no);
use_list_.remove_if([&](const Use &use) { return use == target_use; });
}
void Value::replace_all_use_with(Value *new_val) {
if (this == new_val)
return;
while (use_list_.size()) {
auto use = use_list_.begin();
use->val_->set_operand(use->arg_no_, new_val);
}
}
void Value::replace_use_with_if(Value *new_val,
std::function<bool(Use *)> should_replace) {
if (this == new_val)
return;
for (auto iter = use_list_.begin(); iter != use_list_.end();) {
auto use = *iter++;
if (not should_replace(&use))
continue;
use.val_->set_operand(use.arg_no_, new_val);
}
}
add_executable(test_ast test_ast.cpp)
add_executable(test_logging test_logging.cpp)
target_link_libraries(test_ast syntax common)
target_link_libraries(test_logging common)
install(
TARGETS test_logging
RUNTIME DESTINATION bin
)
install(
TARGETS test_ast
RUNTIME DESTINATION bin
)
#include "ast.hpp"
#include <iostream>
int main(int argc, char **argv) {
if (argc != 2) {
std::cout << "usage: " << argv[0] << " <cminus_file>" << std::endl;
} else {
auto s = parse(argv[1]);
auto a = AST(s);
auto printer = ASTPrinter();
a.run_visitor(printer);
}
return 0;
}
#include "logging.hpp"
// 引入头文件
int main() {
LOG(DEBUG) << "This is DEBUG log item.";
// 使用关键字LOG,括号中填入要输出的日志等级
// 紧接着就是<<以及日志的具体信息,这一步就跟使用std::cout一样
LOG(INFO) << "This is INFO log item";
LOG(WARNING) << "This is WARNING log item";
LOG(ERROR) << "This is ERROR log item";
return 0;
}
\ No newline at end of file
flex_target(lex lexical_analyzer.l ${CMAKE_CURRENT_BINARY_DIR}/lexical_analyzer.c)
bison_target(syntax syntax_analyzer.y
${CMAKE_CURRENT_BINARY_DIR}/syntax_analyzer.c
DEFINES_FILE ${PROJECT_BINARY_DIR}/syntax_analyzer.h)
add_flex_bison_dependency(lex syntax)
add_library(syntax STATIC
${BISON_syntax_OUTPUTS}
${FLEX_lex_OUTPUTS}
)
include_directories(${PROJECT_BINARY_DIR})
add_executable(parser parser.c)
target_link_libraries(parser syntax common)
add_executable(lexer lexer.c)
target_link_libraries(lexer syntax common)
install(
TARGETS parser
RUNTIME DESTINATION bin
)
install(
TARGETS lexer
RUNTIME DESTINATION bin
)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syntax_analyzer.h>
///
extern int lines;
extern int pos_start;
extern int pos_end;
///
extern FILE *yyin;
extern char *yytext;
extern int yylex();
// Mac-only hack.
YYSTYPE yylval;
///
int main(int argc, const char **argv) {
if (argc != 2) {
printf("usage: lexer input_file\n");
return 0;
}
const char *input_file = argv[1];
yyin = fopen(input_file, "r");
if (!yyin) {
fprintf(stderr, "cannot open file: %s\n", input_file);
return 1;
}
int token;
printf("%5s\t%10s\t%s\t%s\n", "Token", "Text", "Line",
"Column (Start,End)");
while ((token = yylex())) {
printf("%-5d\t%10s\t%d\t(%d,%d)\n", token, yytext, lines, pos_start,
pos_end);
}
return 0;
}
%option noyywrap
%{
/*****************声明和选项设置 begin*****************/
#include <stdio.h>
#include <stdlib.h>
#include "syntax_tree.h"
#include "syntax_analyzer.h"
int lines=1;
int pos_start=1;
int pos_end=1;
void pass_node(char *text){
yylval.node = new_syntax_tree_node(text);
}
/*****************声明和选项设置 end*****************/
%}
%x COMMENT
%%
/* to do for students */
/* two cases for you, pass_node will send flex's token to bison */
\+ {pos_start = pos_end; pos_end += 1; pass_node(yytext); return ADD;}
\- {pos_start = pos_end; pos_end += 1; pass_node(yytext); return SUB;}
\* {pos_start = pos_end; pos_end += 1; pass_node(yytext); return MUL;}
\/ {pos_start = pos_end; pos_end += 1; pass_node(yytext); return DIV;}
\< {pos_start = pos_end; pos_end += 1; pass_node(yytext); return LT;}
\<= {pos_start = pos_end; pos_end += 2; pass_node(yytext); return LTE;}
\> {pos_start = pos_end; pos_end += 1; pass_node(yytext); return GT;}
\>= {pos_start = pos_end; pos_end += 2; pass_node(yytext); return GTE;}
== {pos_start = pos_end; pos_end += 2; pass_node(yytext); return EQ;}
!= {pos_start = pos_end; pos_end += 2; pass_node(yytext); return NEQ;}
= {pos_start = pos_end; pos_end += 1; pass_node(yytext); return ASSIGN;}
; {pos_start = pos_end; pos_end += 1; pass_node(yytext); return SEMICOLON;}
, {pos_start = pos_end; pos_end += 1; pass_node(yytext); return COMMA;}
/* TODO: phase1. 请在这里补充其他的词法规则 */
. { pos_start = pos_end; pos_end++; return ERROR; }
/****请在此补全所有flex的模式与动作 end******/
%%
#include "syntax_tree.h"
extern syntax_tree *parse(const char *);
int main(int argc, char *argv[]) {
syntax_tree *tree = NULL;
const char *input = NULL;
if (argc == 2) {
input = argv[1];
} else if (argc >= 3) {
printf("usage: %s <cminus_file>\n", argv[0]);
return 1;
}
// Call the syntax analyzer.
tree = parse(input);
print_syntax_tree(stdout, tree);
del_syntax_tree(tree);
return 0;
}
%{
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include "syntax_tree.h"
// external functions from lex
extern int yylex();
extern int yyparse();
extern int yyrestart();
extern FILE * yyin;
// external variables from lexical_analyzer module
extern int lines;
extern char * yytext;
extern int pos_end;
extern int pos_start;
// Global syntax tree
syntax_tree *gt;
// Error reporting
void yyerror(const char *s);
// Helper functions written for you with love
syntax_tree_node *node(const char *node_name, int children_num, ...);
%}
/* Complete this definition.
Hint: See pass_node(), node(), and syntax_tree.h.
Use forward declaring. */
%union {
struct _syntax_tree_node * node;
char * name;
}
/* Your tokens here. */
%token <node> ERROR
%token <node> ADD
%token <node> SUB
%token <node> MUL
%token <node> DIV
%token <node> LT
%token <node> LTE
%token <node> GT
%token <node> GTE
%token <node> EQ
%token <node> NEQ
%token <node> ASSIGN
%token <node> SEMICOLON
%token <node> COMMA
%token <node> LPARENTHESE
%token <node> RPARENTHESE
%token <node> LBRACKET
%token <node> RBRACKET
%token <node> LBRACE
%token <node> RBRACE
%token <node> ELSE
%token <node> IF
%token <node> INT
%token <node> RETURN
%token <node> VOID
%token <node> WHILE
%token <node> IDENTIFIER
%token <node> INTEGER
%token <node> FLOAT // 这个token 对应float 关键字
%token <node> FLOATPOINT // 这个token 对应 浮点数值, 如果分不清的同学可以参考type-specifier的文法和对应产生式规则
//%token <node> EOL
//%token <node> BLANK
//%token <node> COMMENT
%type <node> program declaration-list declaration var-declaration type-specifier fun-declaration params param-list param compound-stmt local-declarations statement-list statement expression-stmt selection-stmt iteration-stmt return-stmt expression var simple-expression relop additive-expression addop term mulop factor integer float call args arg-list
/* compulsory starting symbol */
%start program
%%
/* Your rules here. TA has completed many */
program : declaration-list {$$ = node( "program", 1, $1); gt->root = $$;}
;
declaration-list : declaration-list declaration {$$ = node( "declaration-list", 2, $1, $2);}
| declaration {$$ = node( "declaration-list", 1, $1);}
;
declaration : var-declaration {$$ = node( "declaration", 1, $1);}
| fun-declaration {$$ = node( "declaration", 1, $1);}
;
var-declaration : type-specifier IDENTIFIER SEMICOLON {$$ = node( "var-declaration", 3, $1, $2, $3);}
| type-specifier IDENTIFIER LBRACKET INTEGER RBRACKET SEMICOLON {$$ = node( "var-declaration", 6, $1, $2, $3, $4, $5, $6);}
;
type-specifier : INT {$$ = node( "type-specifier", 1, $1);}
| FLOAT { $$ = node( "type-specifier", 1, $1); }
| VOID {$$ = node( "type-specifier", 1, $1);}
;
fun-declaration : type-specifier IDENTIFIER LPARENTHESE params RPARENTHESE compound-stmt {$$ = node( "fun-declaration", 6, $1, $2, $3, $4, $5, $6);}
;
params : param-list {$$ = node( "params", 1, $1);}
| VOID {$$ = node( "params", 1, $1);}
;
param-list : param-list COMMA param {$$ = node( "param-list", 3, $1, $2, $3);}
| param {$$ = node( "param-list", 1, $1);}
;
param : type-specifier IDENTIFIER {$$ = node( "param", 2, $1, $2);}
| type-specifier IDENTIFIER LBRACKET RBRACKET {$$ = node( "param", 4, $1, $2, $3, $4);}
;
compound-stmt : LBRACE local-declarations statement-list RBRACE {$$ = node( "compound-stmt", 4, $1, $2, $3, $4);}
;
local-declarations : local-declarations var-declaration {$$ = node( "local-declarations", 2, $1, $2);}
| {$$ = node( "local-declarations",0);}
;
statement-list : statement-list statement {$$ = node( "statement-list", 2, $1, $2);}
| {$$ = node( "statement-list",0);}
;
// TODO: phase1. 补充其他的文法产生式逻辑
%%
/// The error reporting function.
void yyerror(const char * s)
{
// TO STUDENTS: This is just an example.
// You can customize it as you like.
fprintf(stderr, "error at line %d column %d: %s\n", lines, pos_start, s);
}
/// Parse input from file `input_path`, and prints the parsing results
/// to stdout. If input_path is NULL, read from stdin.
///
/// This function initializes essential states before running yyparse().
syntax_tree *parse(const char *input_path)
{
if (input_path != NULL) {
if (!(yyin = fopen(input_path, "r"))) {
fprintf(stderr, "[ERR] Open input file %s failed.\n", input_path);
exit(1);
}
} else {
yyin = stdin;
}
lines = pos_start = pos_end = 1;
gt = new_syntax_tree();
yyrestart(yyin);
yyparse();
return gt;
}
/// A helper function to quickly construct a tree node.
///
/// e.g. $$ = node("program", 1, $1);
syntax_tree_node *node(const char *name, int children_num, ...)
{
syntax_tree_node *p = new_syntax_tree_node(name);
syntax_tree_node *child;
// 这里表示 epsilon结点是通过 children_num == 0 来判断的
if (children_num == 0) {
child = new_syntax_tree_node("epsilon");
syntax_tree_add_child(p, child);
} else {
va_list ap;
va_start(ap, children_num);
for (int i = 0; i < children_num; ++i) {
child = va_arg(ap, syntax_tree_node *);
syntax_tree_add_child(p, child);
}
va_end(ap);
}
return p;
}
#!/bin/sh
rm -rf output_student/*
rm -rf output_student_ast/*
#!/bin/bash
# DO NOT MODIFY!
# If you need customized behavior, please create your own script.
function run_tests() {
local TESTCASE_DIR=$1
local OUTPUT_DIR=$2
local OUTPUT_STD_DIR=$3
local score=0
local total=0
mkdir -p "$OUTPUT_DIR"
# 对每个 .cminus 文件生成 syntax_tree 文件
for testcase in "$TESTCASE_DIR"/*.cminus; do
filename="$(basename "$testcase")"
echo "[info] Analyzing $filename"
# 生成学生的 syntax_tree 文件
"$BUILD_DIR"/parser "$testcase" > "$OUTPUT_DIR/${filename%.cminus}.syntax_tree"
# 比较当前文件的输出与标准输出
if [[ ${2:-no} != "no" ]]; then
echo "[info] Comparing $filename..."
# 如果是详细模式
if [[ ${2:-no} == "verbose" ]]; then
diff "$OUTPUT_DIR/${filename%.cminus}.syntax_tree" "$OUTPUT_STD_DIR/${filename%.cminus}.syntax_tree"
else
diff -q "$OUTPUT_DIR/${filename%.cminus}.syntax_tree" "$OUTPUT_STD_DIR/${filename%.cminus}.syntax_tree"
fi
# 检查 diff 的返回值
if [ $? -eq 0 ]; then
echo "[info] $filename is correct!"
let score=score+1 # 正确时得分+1
else
echo "[info] $filename differs from the expected output."
fi
fi
let total=total+1 # 总文件数+1
rm -f "$CUR_DIR/${filename%.cminus}"
done
# 输出当前测试集的得分
echo "[info] Score for $TESTCASE_DIR: $score/$total"
return $score
}
# 检查命令行参数是否足够
if [[ $# -lt 1 ]]; then
echo "usage: ./eval_phase1.sh <input> [<summary>]"
echo " <input> can be one of 'easy', 'normal', 'hard', 'testcases_general', or '-all'."
echo " <summary> can be one of 'no', 'yes', and 'verbose'. the default value is 'no'"
exit 1
fi
CUR_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)"
BUILD_DIR="$CUR_DIR/../../build"
# 检查是否使用了 -all 选项
if [[ $1 == "-all" ]]; then
TOTAL_SCORE=0
TOTAL_FILES=0
# 定义四个测试集
TESTCASES=("easy" "normal" "hard" "testcases_general")
for TESTCASE in "${TESTCASES[@]}"; do
if [[ $TESTCASE == "testcases_general" ]]; then
TESTCASE_DIR="$CUR_DIR/../$TESTCASE"
else
TESTCASE_DIR="$CUR_DIR/input/$TESTCASE"
fi
OUTPUT_DIR="$CUR_DIR/output_student/$TESTCASE"
OUTPUT_STD_DIR="$CUR_DIR/output_standard/$TESTCASE"
# 计算有效文件数
VALID_FILES=$(find "$TESTCASE_DIR" -maxdepth 1 -name '*.cminus' | wc -l)
echo "[info] Found $VALID_FILES valid files in $TESTCASE_DIR"
run_tests "$TESTCASE_DIR" "$OUTPUT_DIR" "$OUTPUT_STD_DIR" $2
CURRENT_SCORE=$?
let TOTAL_SCORE+=CURRENT_SCORE
TOTAL_FILES=$(($TOTAL_FILES + $VALID_FILES))
done
# 输出总分
echo "[info] Total score for all testcases: $TOTAL_SCORE/$TOTAL_FILES"
else
# 单个测试集处理
TESTCASE="$1"
if [[ $TESTCASE == "easy" || $TESTCASE == "normal" || $TESTCASE == "hard" ]]; then
TESTCASE_DIR="$CUR_DIR/input/$TESTCASE"
elif [[ $TESTCASE == "testcases_general" ]]; then
TESTCASE_DIR="$CUR_DIR/../$TESTCASE"
fi
OUTPUT_DIR="$CUR_DIR/output_student/$TESTCASE"
OUTPUT_STD_DIR="$CUR_DIR/output_standard/$TESTCASE"
# 运行单个测试集
run_tests "$TESTCASE_DIR" "$OUTPUT_DIR" "$OUTPUT_STD_DIR" $2
fi
\ No newline at end of file
#!/bin/bash
# DO NOT MODIFY!
# If you need customized behavior, please create your own script.
function run_tests() {
local TESTCASE_DIR=$1
local OUTPUT_DIR=$2
local OUTPUT_STD_DIR=$3
local score=0
local total=0
mkdir -p "$OUTPUT_DIR"
# 对每个 .cminus 文件生成 ast 文件
for testcase in "$TESTCASE_DIR"/*.cminus; do
filename="$(basename "$testcase")"
# 检查文件名是否以 FAIL 开头,跳过该文件
if [[ "$filename" == FAIL* ]]; then
echo "[info] Skipping $filename (starts with FAIL)"
continue
fi
echo "[info] Analyzing $filename"
# 生成学生的 AST 文件
"$BUILD_DIR"/cminusfc -emit-ast "$testcase" > "$OUTPUT_DIR/${filename%.cminus}.ast"
# 比较当前文件的输出与标准输出
if [[ ${2:-no} != "no" ]]; then
echo "[info] Comparing $filename..."
# 如果是详细模式
if [[ ${2:-no} == "verbose" ]]; then
diff "$OUTPUT_DIR/${filename%.cminus}.ast" "$OUTPUT_STD_DIR/${filename%.cminus}.ast"
else
diff -q "$OUTPUT_DIR/${filename%.cminus}.ast" "$OUTPUT_STD_DIR/${filename%.cminus}.ast"
fi
# 检查 diff 的返回值
if [ $? -eq 0 ]; then
echo "[info] $filename is correct!"
let score=score+1 # 正确时得分+1
else
echo "[info] $filename differs from the expected output."
fi
fi
let total=total+1 # 总文件数+1
rm -f "$CUR_DIR/${filename%.cminus}"
done
# 输出当前测试集的得分
echo "[info] Score for $TESTCASE_DIR: $score/$total"
return $score
}
# 检查命令行参数是否足够
if [[ $# -lt 1 ]]; then
echo "usage: ./eval_phase2.sh <input> [<summary>]"
echo " <input> can be one of 'easy', 'normal', 'hard', 'testcases_general', or '-all'."
echo " <summary> can be one of 'no', 'yes', and 'verbose'. the default value is 'no'"
exit 1
fi
CUR_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)"
BUILD_DIR="$CUR_DIR/../../build"
# 检查是否使用了 -all 选项
if [[ $1 == "-all" ]]; then
TOTAL_SCORE=0
TOTAL_FILES=0
# 定义四个测试集
TESTCASES=("easy" "normal" "hard" "testcases_general")
for TESTCASE in "${TESTCASES[@]}"; do
if [[ $TESTCASE == "testcases_general" ]]; then
TESTCASE_DIR="$CUR_DIR/../$TESTCASE"
else
TESTCASE_DIR="$CUR_DIR/input/$TESTCASE"
fi
OUTPUT_DIR="$CUR_DIR/output_student_ast/$TESTCASE"
OUTPUT_STD_DIR="$CUR_DIR/output_standard_ast/$TESTCASE"
# 计算有效文件数,跳过以 FAIL 开头的文件
VALID_FILES=$(find "$TESTCASE_DIR" -maxdepth 1 -name '*.cminus' ! -name 'FAIL*' | wc -l)
echo "[info] Found $VALID_FILES valid files in $TESTCASE_DIR"
# 运行测试集并跳过以 FAIL 开头的文件
run_tests "$TESTCASE_DIR" "$OUTPUT_DIR" "$OUTPUT_STD_DIR" $2
CURRENT_SCORE=$?
let TOTAL_SCORE+=CURRENT_SCORE
TOTAL_FILES=$(($TOTAL_FILES + $VALID_FILES))
done
# 输出总分
echo "[info] Total score for all testcases: $TOTAL_SCORE/$TOTAL_FILES"
else
# 单个测试集处理
TESTCASE="$1"
if [[ $TESTCASE == "easy" || $TESTCASE == "normal" || $TESTCASE == "hard" ]]; then
TESTCASE_DIR="$CUR_DIR/input/$TESTCASE"
elif [[ $TESTCASE == "testcases_general" ]]; then
TESTCASE_DIR="$CUR_DIR/../$TESTCASE"
fi
OUTPUT_DIR="$CUR_DIR/output_student_ast/$TESTCASE"
OUTPUT_STD_DIR="$CUR_DIR/output_standard_ast/$TESTCASE"
# 运行单个测试集
run_tests "$TESTCASE_DIR" "$OUTPUT_DIR" "$OUTPUT_STD_DIR" $2
fi
\ No newline at end of file
/* unclosed comment
\ No newline at end of file
// cminus dont support comment like that
int main(void){
return 0;
}
\ No newline at end of file
/* unclosed function */
int main(void)
{
\ No newline at end of file
int a1;
int f1(void) {}
int f2(void) {}
/*Basic num part*/
int main(void){
a = 0;
x = 0.0;
x = 1.;
x = .1;
a = 1+1;
a = a-1;
x = x*1;
x = a/x;
return 0;
}
\ No newline at end of file
int a;
int f(void) {}
int g(void) {}
/*
I konw it's weird, even stupid, to code C like this. w(゚Д゚)w
HOWEVER, we have to use some tricky cases to test your answer.
*/
float GVAR;
void NeverEverDeclareLikeThis;
int GARRAY[2333];
void MyFuncA(int floatNum, float intNum, void voidNums[]){
int IKnowYouAreVoid;
return MyFuncB(IKnowYouAreVoid);
}
float MyFuncB(void){
int IAmVoid[0];
return MyFuncA(.0, 0, IAmVoid);
}
int main(void){
int a; int b; int c;
a = b = c = (85 == 84 + 0.4);
if(a = b){
GARRAY[ ( MyFuncB() ) ] = GARRAY[c = 1.*.1 == 1.1];
}else if (MyFuncC(NotDeclared)){
}else;
return 0.;
}
\ No newline at end of file
/* associativity and precedence */
int main(void)
{
a = b = c = 1 + 1 / 2 * 1 * (1 + 1 + 1 - 1 / 1) + 3 + 4 * 3;
}
int gcd (int u, int v) { /* calculate the gcd of u and v */
if (v == 0) return u;
else return gcd(v, u - u / v * v); /* v,u-u/v*v is equals to u mod v*/
}
int main(void) {
int x; int y; int temp;
x = 72;
y = 18;
if (x<y) {
temp = x;
x = y;
y = temp;
}
gcd(x,y);
return 0;
}
void move(int x, int y)
{
putint(x); putch(32); putint(y); putch(44); putch(32);
}
void hanoi(int n, int one, int two, int three)
{
if (n == 1)
move(one, three);
else {
hanoi(n - 1, one, three, two);
move(one, three);
hanoi(n - 1, two, one, three);
}
}
int main(void )
{
int n;
n = getint();
while (n > 0) {
hanoi(getint(), 1, 2, 3);
putch(10);
n = n - 1;
}
return 0;
}
/* else should be bound to the closest if */
int main(void)
{
if (1) {} else if (2) {} else {}
return 0;
}
/* this is the sample program in C- in the book "Compiler Construction" */
/* A program to perform selection sort on a 10 element array. */
int x[10];
int minloc ( int a[], int low, int high )
{ int i; int x; int k;
k = low;
x = a[low];
i = low + 1;
while (i < high)
{ if (a[i] < x)
{ x = a[i];
k = i; }
i = i + 1;
}
return k;
}
void sort( int a[], int low, int high)
{ int i; int k;
i = low;
while ( i < high-1)
{ int t;
k = minloc(a, i, high);
t = a[k];
a[k] = a[i];
a[i] = t;
i = i + 1;
}
}
void main(void)
{ int i;
i = 0;
while ( i < 10)
{ x[i] = input();
i = i + 1; }
sort(x, 0, 10);
i = 0;
while (i < 10)
{ output(x[i]);
i = i + 1; }
}
int main(void){
int a;
a = 1;
int b;
return 0;
}
\ No newline at end of file
int main(void) {
int array[1];
array[1] = 0;
return 0;
}
float foo(float a, float b[]) {
return 1;
}
int main(void) {
return 0;
}
/*Basic selection part*/
int main(void){
int a; int b;
a = 1;
b = 1;
if(a != b){
if(a == b);
else{
a = b;
}
}
return 0;
}
\ No newline at end of file
int main(void) {
int i; float j;
void v;
return 0;
}
/*
int main() {
int arr[100];
int i;
int sum;
i = 0;
sum = 0;
while (getint()) {
arr[i] = getint();
i = i + 1;
}*/
int main(void) {
int arr[100];
int i;
int sum;
i = 0;
sum = 0;
while (getint()) {
arr[i] = getint();
i = i + 1;
}
while (i) {
i = i - 1;
sum = sum + arr[i];
}
return sum - 79;
}
This diff is collapsed.
>--+ program
| >--+ declaration-list
| | >--+ declaration-list
| | | >--+ declaration-list
| | | | >--+ declaration
| | | | | >--+ var-declaration
| | | | | | >--+ type-specifier
| | | | | | | >--* int
| | | | | | >--* a
| | | | | | >--* ;
| | | >--+ declaration
| | | | >--+ fun-declaration
| | | | | >--+ type-specifier
| | | | | | >--* int
| | | | | >--* f
| | | | | >--* (
| | | | | >--+ params
| | | | | | >--* void
| | | | | >--* )
| | | | | >--+ compound-stmt
| | | | | | >--* {
| | | | | | >--+ local-declarations
| | | | | | | >--* epsilon
| | | | | | >--+ statement-list
| | | | | | | >--* epsilon
| | | | | | >--* }
| | >--+ declaration
| | | >--+ fun-declaration
| | | | >--+ type-specifier
| | | | | >--* int
| | | | >--* g
| | | | >--* (
| | | | >--+ params
| | | | | >--* void
| | | | >--* )
| | | | >--+ compound-stmt
| | | | | >--* {
| | | | | >--+ local-declarations
| | | | | | >--* epsilon
| | | | | >--+ statement-list
| | | | | | >--* epsilon
| | | | | >--* }
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
>--+ program
| >--+ declaration-list
| | >--+ declaration
| | | >--+ fun-declaration
| | | | >--+ type-specifier
| | | | | >--* int
| | | | >--* main
| | | | >--* (
| | | | >--+ params
| | | | | >--* void
| | | | >--* )
| | | | >--+ compound-stmt
| | | | | >--* {
| | | | | >--+ local-declarations
| | | | | | >--* epsilon
| | | | | >--+ statement-list
| | | | | | >--+ statement-list
| | | | | | | >--+ statement-list
| | | | | | | | >--* epsilon
| | | | | | | >--+ statement
| | | | | | | | >--+ selection-stmt
| | | | | | | | | >--* if
| | | | | | | | | >--* (
| | | | | | | | | >--+ expression
| | | | | | | | | | >--+ simple-expression
| | | | | | | | | | | >--+ additive-expression
| | | | | | | | | | | | >--+ term
| | | | | | | | | | | | | >--+ factor
| | | | | | | | | | | | | | >--+ integer
| | | | | | | | | | | | | | | >--* 1
| | | | | | | | | >--* )
| | | | | | | | | >--+ statement
| | | | | | | | | | >--+ compound-stmt
| | | | | | | | | | | >--* {
| | | | | | | | | | | >--+ local-declarations
| | | | | | | | | | | | >--* epsilon
| | | | | | | | | | | >--+ statement-list
| | | | | | | | | | | | >--* epsilon
| | | | | | | | | | | >--* }
| | | | | | | | | >--* else
| | | | | | | | | >--+ statement
| | | | | | | | | | >--+ selection-stmt
| | | | | | | | | | | >--* if
| | | | | | | | | | | >--* (
| | | | | | | | | | | >--+ expression
| | | | | | | | | | | | >--+ simple-expression
| | | | | | | | | | | | | >--+ additive-expression
| | | | | | | | | | | | | | >--+ term
| | | | | | | | | | | | | | | >--+ factor
| | | | | | | | | | | | | | | | >--+ integer
| | | | | | | | | | | | | | | | | >--* 2
| | | | | | | | | | | >--* )
| | | | | | | | | | | >--+ statement
| | | | | | | | | | | | >--+ compound-stmt
| | | | | | | | | | | | | >--* {
| | | | | | | | | | | | | >--+ local-declarations
| | | | | | | | | | | | | | >--* epsilon
| | | | | | | | | | | | | >--+ statement-list
| | | | | | | | | | | | | | >--* epsilon
| | | | | | | | | | | | | >--* }
| | | | | | | | | | | >--* else
| | | | | | | | | | | >--+ statement
| | | | | | | | | | | | >--+ compound-stmt
| | | | | | | | | | | | | >--* {
| | | | | | | | | | | | | >--+ local-declarations
| | | | | | | | | | | | | | >--* epsilon
| | | | | | | | | | | | | >--+ statement-list
| | | | | | | | | | | | | | >--* epsilon
| | | | | | | | | | | | | >--* }
| | | | | | >--+ statement
| | | | | | | >--+ return-stmt
| | | | | | | | >--* return
| | | | | | | | >--+ expression
| | | | | | | | | >--+ simple-expression
| | | | | | | | | | >--+ additive-expression
| | | | | | | | | | | >--+ term
| | | | | | | | | | | | >--+ factor
| | | | | | | | | | | | | >--+ integer
| | | | | | | | | | | | | | >--* 0
| | | | | | | | >--* ;
| | | | | >--* }
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment