summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt6
-rw-r--r--Context.cc12
-rw-r--r--Context.hh9
-rw-r--r--Parser.y124
-rw-r--r--VariableList.cc31
-rw-r--r--VariableList.hh28
-rw-r--r--node/BaseNode.hh12
-rw-r--r--node/DeclNode.cc23
-rw-r--r--node/DeclNode.hh26
-rw-r--r--node/ExpressionNode.hh8
-rw-r--r--node/FunctionNode.cc69
-rw-r--r--node/FunctionNode.hh30
-rw-r--r--node/Node.hh3
-rw-r--r--node/StatementNode.cc11
-rw-r--r--node/StatementNode.hh12
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}
diff --git a/Context.cc b/Context.cc
index 64c9d58..d009835 100644
--- a/Context.cc
+++ b/Context.cc
@@ -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
diff --git a/Context.hh b/Context.hh
index 2bbcaa4..9a30721 100644
--- a/Context.hh
+++ b/Context.hh
@@ -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_;
};
diff --git a/Parser.y b/Parser.y
index 24b0424..c322dd3 100644
--- a/Parser.y
+++ b/Parser.y
@@ -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