diff options
| -rw-r--r-- | CMakeLists.txt | 6 | ||||
| -rw-r--r-- | Context.cc | 12 | ||||
| -rw-r--r-- | Context.hh | 9 | ||||
| -rw-r--r-- | Parser.y | 124 | ||||
| -rw-r--r-- | VariableList.cc | 31 | ||||
| -rw-r--r-- | VariableList.hh | 28 | ||||
| -rw-r--r-- | node/BaseNode.hh | 12 | ||||
| -rw-r--r-- | node/DeclNode.cc | 23 | ||||
| -rw-r--r-- | node/DeclNode.hh | 26 | ||||
| -rw-r--r-- | node/ExpressionNode.hh | 8 | ||||
| -rw-r--r-- | node/FunctionNode.cc | 69 | ||||
| -rw-r--r-- | node/FunctionNode.hh | 30 | ||||
| -rw-r--r-- | node/Node.hh | 3 | ||||
| -rw-r--r-- | node/StatementNode.cc | 11 | ||||
| -rw-r--r-- | node/StatementNode.hh | 12 |
15 files changed, 343 insertions, 61 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 39b38d0..b486bc5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,12 +12,16 @@ set(PCC_SOURCE main.cc Type.cc TypeManager.cc + VariableList.cc Version.cc) list(APPEND PCC_SOURCE node/BaseNode.cc + node/DeclNode.cc node/ExprNode.cc - node/LiteralNode.cc) + node/FunctionNode.cc + node/LiteralNode.cc + node/StatementNode.cc) set(PCC_INCLUDE ${CMAKE_SOURCE_DIR} @@ -9,11 +9,21 @@ llvm::LLVMContext GlobalLLVMContext; Context::Context(const char* name) : builder_(GlobalLLVMContext) - , module_(name, GlobalLLVMContext) {} + , module_(name, GlobalLLVMContext) { + scopes_.push(&globals_); +} TypeManager* Context::GetTypeManager() { return &TypeManager_; } +VariableList Context::GetGlobals() { return &globals_; } + llvm::Module* Context::GetModule() { return &module_; } llvm::IRBuilder<>* Context::GetBuilder() { return &builder_; } + +VariableList* Context::GetCurrentScope() { return scopes_.top(); } + +void Context::PushScope(VariableList* scope) { scopes_.push(scope); } + +void Context::PopScope() { scopes_.pop(); } } // namespace pcc @@ -1,21 +1,30 @@ #ifndef PCC_CONTEXT_H #define PCC_CONTEXT_H +#include <stack> + #include <llvm/IR/IRBuilder.h> #include <llvm/IR/Module.h> #include "TypeManager.hh" +#include "VariableList.hh" namespace pcc { class Context { public: Context(const char* name); TypeManager* GetTypeManager(); + VariableList GetGlobals(); llvm::Module* GetModule(); llvm::IRBuilder<>* GetBuilder(); + VariableList* GetCurrentScope(); + void PushScope(VariableList* scope); + void PopScope(); private: TypeManager TypeManager_; + VariableList globals_; + std::stack<VariableList*> scopes_; llvm::IRBuilder<> builder_; llvm::Module module_; }; @@ -17,11 +17,11 @@ namespace pcc{ %locations %param {pcc::Driver& driver} -%param {pcc::Context* context} +%param {pcc::Context* ctx} %code{ #define YY_DECL \ - pcc::Parser::symbol_type yylex(pcc::Driver& driver, pcc::Context* context) + pcc::Parser::symbol_type yylex(pcc::Driver& driver, pcc::Context* ctx) YY_DECL; } @@ -43,31 +43,47 @@ YY_DECL; %token INTEGER_LITERAL REAL_LITERAL STRING_LITERAL BOOLEAN_LITERAL CHAR_LITERAL %type <std::string> IDENTIFIER +%type <std::shared_ptr<pcc::Type>> type +%type <std::list<Declaration>> var_decls +%type <std::pair<std::list<std::string>, std::shared_ptr<pcc::Type>>> var_decl +%type <std::list<std::string>> vars + %type <std::shared_ptr<pcc::BooleanLiteralNode>> BOOLEAN_LITERAL %type <std::shared_ptr<pcc::CharLiteralNode>> CHAR_LITERAL %type <std::shared_ptr<pcc::IntegerLiteralNode>> INTEGER_LITERAL %type <std::shared_ptr<pcc::RealLiteralNode>> REAL_LITERAL %type <std::shared_ptr<pcc::StringLiteralNode>> STRING_LITERAL +%type <std::shared_ptr<pcc::ExprNode>> literal + +%type <std::shared_ptr<pcc::ExprNode>> expression l1_expression l2_expression l3_expression +%type <pcc::BinaryOperator> l1_operator l2_operator l3_operator +%type <pcc::UnaryOperator> l4_operator + +%type <std::shared_ptr<pcc::StatementListNode>> statements statement_block + +%type <std::shared_ptr<pcc::FunctionNode>> function +%type <std::list<std::shared_ptr<pcc::BaseNode>>> local_decls +%type <std::shared_ptr<pcc::BaseNode>> local_decl %% /* ==================[global part]================== */ program - : program_header decls functions + : program_header global_decls functions ; program_header : PROGRAM IDENTIFIER SEMICOLON ; -decls - : decls decl SEMICOLON +global_decls + : global_decls global_decl SEMICOLON | ; -decl - : VAR var_decls SEMICOLON +global_decl + : VAR var_decls ; functions @@ -78,34 +94,41 @@ functions /* ==================[var part]================== */ var_decls - : var_decls SEMICOLON var_decl - | var_decl + : var_decls SEMICOLON var_decl {$$=$1; auto NewChilds=std::get<0>($3); for(auto& name: NewChilds){$$.push_back({name, std::get<1>($3)});}} + | var_decl {auto NewChilds=std::get<0>($1); for(auto& name: NewChilds){$$.push_back({name, std::get<1>($1)});}} ; var_decl - : vars COLON type + : vars COLON type {$$={$1,$3};} ; vars - : vars COMMA IDENTIFIER - | IDENTIFIER + : vars COMMA IDENTIFIER {$$=$1; $$.push_back($3);} + | IDENTIFIER {$$.push_back($1);} + ; type - : INTEGER - | REAL - | BOOLEAN - | CHAR - | STRING + : BOOLEAN {$$=ctx->GetTypeManager()->GetBuiltinType(pcc::BuiltinType::BOOLEAN);} + | CHAR {$$=ctx->GetTypeManager()->GetBuiltinType(pcc::BuiltinType::CHAR);} + | INTEGER {$$=ctx->GetTypeManager()->GetBuiltinType(pcc::BuiltinType::INTEGER);} + | REAL {$$=ctx->GetTypeManager()->GetBuiltinType(pcc::BuiltinType::REAL);} + | STRING {$$=ctx->GetTypeManager()->GetBuiltinType(pcc::BuiltinType::STRING);} ; /* ==================[function part]================== */ function - : function_header decls statement_block + : FUNCTION IDENTIFIER LPARENTHESIS var_decls RPARENTHESIS COLON type SEMICOLON + local_decls statement_block ; -function_header - : FUNCTION IDENTIFIER LPARENTHESIS var_decls RPARENTHESIS COLON type SEMICOLON +local_decls + : local_decls local_decl {$$=$1; $$.push_back($2);} + | + ; + +local_decl + : VAR var_decls {$$=std::make_shared<pcc::VarDeclNode>(ctx, nullptr, $2);} ; /* ==================[statements part]================== */ @@ -154,56 +177,55 @@ assign_statement /* ==================[expression part]================== */ expression - : l1_expression l1_operator expression - | l1_expression + : l1_expression l1_operator expression {$$=std::make_shared<pcc::BinaryExprNode>(ctx,$2,$1,$3);} + | l1_expression {$$=$1;} ; l1_expression - : l1_expression l2_operator l2_expression - | l2_expression + : l1_expression l2_operator l2_expression {$$=std::make_shared<pcc::BinaryExprNode>(ctx,$2,$1,$3);} + | l2_expression {$$=$1;} ; l2_expression - : l2_expression l3_operator l3_expression - | l3_expression + : l2_expression l3_operator l3_expression {$$=std::make_shared<pcc::BinaryExprNode>(ctx,$2,$1,$3);} + | l3_expression {$$=$1;} ; l3_expression : lvalue | function_call - | literal - | LPARENTHESIS expression RPARENTHESIS - | l4_operator l3_expression + | literal {$$=$1;} + | LPARENTHESIS expression RPARENTHESIS {$$=$2;} + | l4_operator l3_expression {$$=std::make_shared<pcc::UnaryExprNode>(ctx,$1,$2);} ; l1_operator - : LT - | LE - | GT - | GE - | EQ - | NE + : LT {$$=pcc::BinaryOperator::LT;} + | LE {$$=pcc::BinaryOperator::LE;} + | GT {$$=pcc::BinaryOperator::GT;} + | GE {$$=pcc::BinaryOperator::GE;} + | EQ {$$=pcc::BinaryOperator::EQ;} + | NE {$$=pcc::BinaryOperator::NE;} ; l2_operator - : ADD - | SUB - | OR - | XOR + : ADD {$$=pcc::BinaryOperator::ADD;} + | SUB {$$=pcc::BinaryOperator::SUB;} + | OR {$$=pcc::BinaryOperator::OR;} + | XOR {$$=pcc::BinaryOperator::XOR;} ; l3_operator - : MUL - | REAL_DIV - | DIV - | MOD - | AND + : MUL {$$=pcc::BinaryOperator::MUL;} + | DIV {$$=pcc::BinaryOperator::DIV;} + | MOD {$$=pcc::BinaryOperator::MOD;} + | AND {$$=pcc::BinaryOperator::AND;} ; l4_operator - : NOT - | ADD - | SUB + : NOT {$$=pcc::UnaryOperator::NOT;} + | ADD {$$=pcc::UnaryOperator::POS;} + | SUB {$$=pcc::UnaryOperator::NEG;} ; lvalue @@ -223,10 +245,10 @@ arguments ; literal - : BOOLEAN_LITERAL - | INTEGER_LITERAL - | REAL_LITERAL - | STRING_LITERAL + : BOOLEAN_LITERAL {$$=$1;} + | INTEGER_LITERAL {$$=$1;} + | REAL_LITERAL {$$=$1;} + | STRING_LITERAL {$$=$1;} ; %% diff --git a/VariableList.cc b/VariableList.cc new file mode 100644 index 0000000..5bf0373 --- /dev/null +++ b/VariableList.cc @@ -0,0 +1,31 @@ +#include "VariableList.hh" +#include "Log.hh" + +namespace pcc { +VariableList::VariableList(VariableList* parent) + : parent_(parent) {} + +Variable VariableList::Find(const std::string& name) { + bool found = false; + VariableList* level = this; + decltype(variables_)::iterator result; + while (level != nullptr) { + result = level->variables_.find(name); + if (result != level->variables_.end()) { + found = true; + break; + } else { + level = level->parent_; + } + } + if (found == false) { + Log(LogLevel::PCC_ERROR, "unknown identifier %s", name.c_str()); + return {nullptr, nullptr}; + } + return std::get<1>(*result); +} + +void VariableList::Add(std::string name, Variable variable) { + variables_.insert({name, variable}); +} +} // namespace pcc diff --git a/VariableList.hh b/VariableList.hh new file mode 100644 index 0000000..cf622ee --- /dev/null +++ b/VariableList.hh @@ -0,0 +1,28 @@ +#ifndef PCC_VARIABLELIST_HH +#define PCC_VARIABLELIST_HH + +#include <memory> +#include <string> +#include <unordered_map> + +#include "Type.hh" + +namespace pcc { +// type and value +using Variable = std::pair<std::shared_ptr<Type>, Value>; +// name and type +using Declaration = std::pair<std::string, std::shared_ptr<Type>>; + +class VariableList { + public: + VariableList(VariableList* parent = nullptr); + Variable Find(const std::string& name); + void Add(std::string name, Variable variable); + + protected: + std::unordered_map<std::string, Variable> variables_; + VariableList* parent_; +}; +} // namespace pcc + +#endif // !PCC_VARIABLELIST_HH diff --git a/node/BaseNode.hh b/node/BaseNode.hh index ab0b96a..bec9ebd 100644 --- a/node/BaseNode.hh +++ b/node/BaseNode.hh @@ -1,6 +1,8 @@ #ifndef PCC_BASENODE_H #define PCC_BASENODE_H +#include <vector> + #include "Context.hh" namespace pcc { @@ -12,6 +14,16 @@ class BaseNode { protected: Context* context_; }; + +template <typename T, class Base = BaseNode> class ListNode : public Base { + public: + ListNode(Context* context) + : Base(context) {} + virtual Value CodeGen(); + + private: + std::vector<T> childs_; +}; } // namespace pcc #endif diff --git a/node/DeclNode.cc b/node/DeclNode.cc new file mode 100644 index 0000000..63dc848 --- /dev/null +++ b/node/DeclNode.cc @@ -0,0 +1,23 @@ +#include "DeclNode.hh" + +#include <llvm/IR/IRBuilder.h> + +namespace pcc { +VarDeclNode::VarDeclNode(Context* context, VariableList* scope, + std::list<Declaration> decls) + : BaseNode(context) + , scope_(scope) + , decls_(decls) {} + +void VarDeclNode::SetScope(VariableList* scope) { scope_ = scope; } + +Value VarDeclNode::CodeGen() { + llvm::IRBuilder<>* builder = context_->GetBuilder(); + for (auto& decl : decls_) { + Value value = builder->CreateAlloca(std::get<1>(decl)->GetLLVMType()); + scope_->Add(std::get<0>(decl), {std::get<1>(decl), value}); + } + return nullptr; +} + +} // namespace pcc diff --git a/node/DeclNode.hh b/node/DeclNode.hh new file mode 100644 index 0000000..8360426 --- /dev/null +++ b/node/DeclNode.hh @@ -0,0 +1,26 @@ +#ifndef PCC_DECLNODE_HH +#define PCC_DECLNODE_HH + +#include <list> + +#include "BaseNode.hh" + +namespace pcc { +class VarDeclNode : public BaseNode { + public: + VarDeclNode(Context* context, VariableList* scope, + std::list<Declaration> decls); + + // the scope of variable is an inherited attribute, but we don't have a good + // way to set inherited attribute during the construction of AST, so we call + // this in parent's constructor + void SetScope(VariableList* scope); + virtual Value CodeGen() override; + + protected: + std::list<Declaration> decls_; + VariableList* scope_; +}; +} // namespace pcc + +#endif // !PCC_DECLNODE_HH diff --git a/node/ExpressionNode.hh b/node/ExpressionNode.hh deleted file mode 100644 index ad31835..0000000 --- a/node/ExpressionNode.hh +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef PCC_EXPRESSIONNODE_H -#define PCC_EXPRESSIONNODE_H - -#include "BaseNode.hh" - - - -#endif diff --git a/node/FunctionNode.cc b/node/FunctionNode.cc new file mode 100644 index 0000000..3346db0 --- /dev/null +++ b/node/FunctionNode.cc @@ -0,0 +1,69 @@ +#include <memory> +#include <vector> + +#include <llvm/IR/IRBuilder.h> + +#include "DeclNode.hh" +#include "FunctionNode.hh" + +namespace pcc { +FunctionNode::FunctionNode( + Context* context, std::string name, std::list<Declaration> arguments, + std::list<std::shared_ptr<BaseNode>> LocalDeclarations, + std::shared_ptr<Type> type, std::shared_ptr<StatementListNode> body) + : BaseNode(context) + , name_(name) + , arguments_(arguments) + , LocalDeclarations_(LocalDeclarations) + , type_(type) + , locals_(context->GetGlobals()) + , body_(body) { + for (auto& decl : LocalDeclarations_) { + std::shared_ptr<VarDeclNode> VarDecl = + std::dynamic_pointer_cast<VarDeclNode>(decl); + if (VarDecl != nullptr) { + // set the inherited attribute + VarDecl->SetScope(&locals_); + } + } +} + +Value FunctionNode::CodeGen() { + llvm::Module* module = context_->GetModule(); + llvm::IRBuilder<>* builder = context_->GetBuilder(); + std::vector<llvm::Type*> params(arguments_.size()); + std::transform(arguments_.cbegin(), arguments_.cend(), params.begin(), + [](const Declaration& decl) { + return std::get<1>(decl)->GetLLVMType(); + }); + llvm::Type* type = + llvm::FunctionType::get(type_->GetLLVMType(), params, false); + llvm::FunctionCallee f = module->getOrInsertFunction(name_, type); + llvm::Function* function = llvm::cast<llvm::Function>(f.getCallee()); + function->setCallingConv(llvm::CallingConv::C); + llvm::BasicBlock* block = + llvm::BasicBlock::Create(GlobalLLVMContext, name_, function); + builder->SetInsertPoint(block); + // alloc arguments + llvm::Function::arg_iterator ArgIt; + for (auto& arg : arguments_) { + Value ArgValue = builder->CreateAlloca(std::get<1>(arg)->GetLLVMType()); + builder->CreateStore(ArgIt++, ArgValue); + locals_.Add(std::get<0>(arg), {std::get<1>(arg), ArgValue}); + } + // alloc local variables + for (auto& decl : LocalDeclarations_) { + decl->CodeGen(); + } + // create a variable with the same name as the function for return value + Value rv = builder->CreateAlloca(type_->GetLLVMType()); + locals_.Add(name_, {type_, rv}); + // push the function scope variables + context_->PushScope(&locals_); + body_->CodeGen(); + builder->CreateRet(rv); + context_->PopScope(); + return nullptr; +} + +} // namespace pcc diff --git a/node/FunctionNode.hh b/node/FunctionNode.hh new file mode 100644 index 0000000..281f5da --- /dev/null +++ b/node/FunctionNode.hh @@ -0,0 +1,30 @@ +#ifndef PCC_FUNCTIONNODE_H +#define PCC_FUNCTIONNODE_H + +#include <list> + +#include "BaseNode.hh" +#include "StatementNode.hh" +#include "VariableList.hh" + +namespace pcc { +class FunctionNode : public BaseNode { + public: + FunctionNode(Context* context, std::string name, + std::list<Declaration> arguments, + std::list<std::shared_ptr<BaseNode>> LocalDeclarations, + std::shared_ptr<Type> type, + std::shared_ptr<StatementListNode> body); + virtual Value CodeGen() override; + + protected: + std::string name_; + std::list<Declaration> arguments_; + std::list<std::shared_ptr<BaseNode>> LocalDeclarations_; + std::shared_ptr<Type> type_; + VariableList locals_; + std::shared_ptr<StatementListNode> body_; +}; +} // namespace pcc + +#endif diff --git a/node/Node.hh b/node/Node.hh index bb5ce7c..c75126c 100644 --- a/node/Node.hh +++ b/node/Node.hh @@ -2,7 +2,10 @@ #define PCC_NODE_H #include "BaseNode.hh" +#include "DeclNode.hh" #include "ExprNode.hh" #include "LiteralNode.hh" +#include "StatementNode.hh" +#include "FunctionNode.hh" #endif // !PCC_NODE_H diff --git a/node/StatementNode.cc b/node/StatementNode.cc new file mode 100644 index 0000000..b373b70 --- /dev/null +++ b/node/StatementNode.cc @@ -0,0 +1,11 @@ +#include "StatementNode.hh" + +namespace pcc { +template <> Value StatementListNode::CodeGen() { + Value result = nullptr; + for (auto& child : childs_) { + result = child->CodeGen(); + } + return result; +} +} // namespace pcc diff --git a/node/StatementNode.hh b/node/StatementNode.hh new file mode 100644 index 0000000..595298b --- /dev/null +++ b/node/StatementNode.hh @@ -0,0 +1,12 @@ +#ifndef PCC_STATEMENTNODE_HH +#define PCC_STATEMENTNODE_HH + +#include <memory> + +#include "BaseNode.hh" + +namespace pcc { +using StatementListNode = ListNode<std::shared_ptr<BaseNode>>; +} // namespace pcc + +#endif |
