summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNagi5Yeq <wu@x-nagi.com>2020-05-21 13:32:12 +0800
committerNagi5Yeq <wu@x-nagi.com>2020-05-21 13:32:12 +0800
commit3832be8be4b23fb9e93a3f181e4205eadbdbf4de (patch)
tree0b958eb72400458401be619b04a8a6cf77194255
parent41f6e75e3f26bdcccfcb3910f202452e14653826 (diff)
binary and unary operations
-rw-r--r--CMakeLists.txt2
-rw-r--r--Context.cc10
-rw-r--r--Context.hh7
-rw-r--r--Lexer.hh33
-rw-r--r--Lexer.l16
-rw-r--r--Parser.y1
-rw-r--r--Type.cc331
-rw-r--r--Type.hh167
-rw-r--r--TypeManager.cc150
-rw-r--r--TypeManager.hh24
-rw-r--r--node/BaseNode.hh4
-rw-r--r--node/ExprNode.cc54
-rw-r--r--node/ExprNode.hh43
-rw-r--r--node/LiteralNode.cc51
-rw-r--r--node/LiteralNode.hh35
-rw-r--r--node/Node.hh1
16 files changed, 729 insertions, 200 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index cf4517f..39b38d0 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -11,10 +11,12 @@ set(PCC_SOURCE
Log.cc
main.cc
Type.cc
+ TypeManager.cc
Version.cc)
list(APPEND PCC_SOURCE
node/BaseNode.cc
+ node/ExprNode.cc
node/LiteralNode.cc)
set(PCC_INCLUDE
diff --git a/Context.cc b/Context.cc
index fd4a7a5..64c9d58 100644
--- a/Context.cc
+++ b/Context.cc
@@ -3,11 +3,15 @@
#include "Context.hh"
namespace pcc {
-llvm::LLVMContext GlobalContext;
+// llvm needs a LLVMContext for every thread, but we only have one thread, so we
+// just use this global context.
+llvm::LLVMContext GlobalLLVMContext;
Context::Context(const char* name)
- : builder_(GlobalContext)
- , module_(name, GlobalContext) {}
+ : builder_(GlobalLLVMContext)
+ , module_(name, GlobalLLVMContext) {}
+
+TypeManager* Context::GetTypeManager() { return &TypeManager_; }
llvm::Module* Context::GetModule() { return &module_; }
diff --git a/Context.hh b/Context.hh
index e300a19..2bbcaa4 100644
--- a/Context.hh
+++ b/Context.hh
@@ -4,20 +4,23 @@
#include <llvm/IR/IRBuilder.h>
#include <llvm/IR/Module.h>
+#include "TypeManager.hh"
+
namespace pcc {
-using Value = llvm::Value*;
class Context {
public:
Context(const char* name);
+ TypeManager* GetTypeManager();
llvm::Module* GetModule();
llvm::IRBuilder<>* GetBuilder();
private:
+ TypeManager TypeManager_;
llvm::IRBuilder<> builder_;
llvm::Module module_;
};
-extern llvm::LLVMContext GlobalContext;
+extern llvm::LLVMContext GlobalLLVMContext;
} // namespace pcc
#endif
diff --git a/Lexer.hh b/Lexer.hh
index c6103eb..86e8480 100644
--- a/Lexer.hh
+++ b/Lexer.hh
@@ -55,25 +55,48 @@ char* GetUnescapedChar(char* s, char* end, char* out) {
Parser::symbol_type make_BOOLEAN_LITERAL(bool b, pcc::Context* context,
const Parser::location_type& loc) {
return Parser::make_BOOLEAN_LITERAL(
- std::make_shared<BooleanLiteralNode>(context, b), loc);
+ std::make_shared<BooleanLiteralNode>(
+ context,
+ context->GetTypeManager()->GetBuiltinType(BuiltinType::BOOLEAN), b),
+ loc);
+}
+
+Parser::symbol_type make_CHAR_LITERAL(char c, pcc::Context* context,
+ const Parser::location_type& loc) {
+ return Parser::make_CHAR_LITERAL(
+ std::make_shared<CharLiteralNode>(
+ context,
+ context->GetTypeManager()->GetBuiltinType(BuiltinType::CHAR), c),
+ loc);
}
Parser::symbol_type make_INTEGER_LITERAL(int v, pcc::Context* context,
const Parser::location_type& loc) {
return Parser::make_INTEGER_LITERAL(
- std::make_shared<IntegerLiteralNode>(context, v), loc);
+ std::make_shared<IntegerLiteralNode>(
+ context,
+ context->GetTypeManager()->GetBuiltinType(BuiltinType::INTEGER), v),
+ loc);
}
Parser::symbol_type make_REAL_LITERAL(float v, pcc::Context* context,
const Parser::location_type& loc) {
return Parser::make_REAL_LITERAL(
- std::make_shared<RealLiteralNode>(context, v), loc);
+ std::make_shared<RealLiteralNode>(
+ context,
+ context->GetTypeManager()->GetBuiltinType(BuiltinType::REAL), v),
+ loc);
}
-Parser::symbol_type make_STRING_LITERAL(char* s, pcc::Context* context,
+Parser::symbol_type make_STRING_LITERAL(char* begin, char* end,
+ pcc::Context* context,
const Parser::location_type& loc) {
return Parser::make_STRING_LITERAL(
- std::make_shared<StringLiteralNode>(context, s), loc);
+ std::make_shared<StringLiteralNode>(
+ context,
+ context->GetTypeManager()->GetBuiltinType(BuiltinType::STRING),
+ begin, end),
+ loc);
}
} // namespace Lexer
} // namespace pcc
diff --git a/Lexer.l b/Lexer.l
index b55cb80..6d6204e 100644
--- a/Lexer.l
+++ b/Lexer.l
@@ -41,8 +41,10 @@ trival_char [0-9a-zA-Z_{}[\]#()<>%:;.?*+\-/^&|~!=,\\" \t\n\v\f]
escaped_char \\[\'?\\abfnrtv]
hex_char \\x[0-9a-fA-F]{1,2}
oct_char \\[0-7]{1,3}
+char_value {trival_char}|{escaped_char}|{hex_char}|{oct_char}|\\'
-string '({trival_char}|{escaped_char}|{hex_char}|{oct_char}|\\')*'
+char '{char_value}'
+string '{char_value}+'
identifier [a-z][0-9a-z]*
@@ -117,6 +119,14 @@ white [\t\f\r ]
return pcc::Lexer::make_REAL_LITERAL(number, context, loc);
}
+{char} {
+ char *s, *end, c;
+ s = yytext + 1;
+ end = s + yyleng - 2;
+ pcc::Lexer::GetUnescapedChar(s, end, &c);
+ return pcc::Lexer::make_CHAR_LITERAL(c, context, loc);
+}
+
{string} {
char *s, *end, *p;
s = p = yytext + 1;
@@ -125,8 +135,8 @@ white [\t\f\r ]
s = pcc::Lexer::GetUnescapedChar(s, end, p);
p++;
}
- *p = '\0';
- return pcc::Lexer::make_STRING_LITERAL(yytext + 1, context, loc);
+ *p++ = '\0';
+ return pcc::Lexer::make_STRING_LITERAL(yytext + 1, p, context, loc);
}
{identifier} {
diff --git a/Parser.y b/Parser.y
index bcde931..24b0424 100644
--- a/Parser.y
+++ b/Parser.y
@@ -44,6 +44,7 @@ YY_DECL;
%type <std::string> IDENTIFIER
%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
diff --git a/Type.cc b/Type.cc
index 4e3dd86..aa13f38 100644
--- a/Type.cc
+++ b/Type.cc
@@ -1,154 +1,172 @@
#include <llvm/IR/InstrTypes.h>
+#include "Context.hh"
#include "Type.hh"
namespace pcc {
-Type::Type(const char* name, bool IsBasicType, int width)
- : name_(name)
- , IsBasicType_(IsBasicType)
- , width_(width) {}
+const char* GetOperatorName(BinaryOperator op) {
+ static const char* names[ToUnderlying(BinaryOperator::BINARYOP_NUMBER)] = {
+ "+", "-", "*", "/", "%", "<", "<=", ">",
+ ">=", "=", "<>", "and", "or", "xor", "[]"};
+ return names[ToUnderlying(op)];
+}
+
+const char* GetOperatorName(UnaryOperator op) {
+ static const char* names[ToUnderlying(UnaryOperator::UNARYOP_NUMEBR)] = {
+ "+", "-", "not"};
+ return names[ToUnderlying(op)];
+}
+
+Type::Type(std::string&& name, llvm::Type* LLVMType)
+ : name_(std::move(name))
+ , LLVMType_(LLVMType) {}
+
+const char* Type::GetCommonName() { return name_.c_str(); }
-const char* Type::GetCommonName() { return name_; }
+llvm::Type* Type::GetLLVMType() { return LLVMType_; }
-int Type::CreateBinaryOperation(BinaryOperator op, Value v0, Value v1,
- Context* context) {
+Value Type::NotAllowed(Value v, Context* context) { return nullptr; }
+Value Type::NotAllowed(Value v0, Value v1, Context* context) { return nullptr; }
+
+Value Type::CreateBinaryOperation(BinaryOperator op, Value v0, Value v1,
+ Context* context) {
return NotAllowed(v0, v1, context);
}
-int Type::NotAllowed(Value v0, Value v1, Context* context) { return -1; }
+Value Type::CreateUnaryOperation(UnaryOperator op, Value v, Context* context) {
+ return NotAllowed(v, context);
+}
+
+Value Type::CreateAdd(Value v0, Value v1, Context* context) {
+ return context->GetBuilder()->CreateAdd(v0, v1);
+}
+
+Value Type::CreateSub(Value v0, Value v1, Context* context) {
+ return context->GetBuilder()->CreateSub(v0, v1);
+}
+
+Value Type::CreateMul(Value v0, Value v1, Context* context) {
+ return context->GetBuilder()->CreateMul(v0, v1);
+}
-int Type::CreateAdd(Value v0, Value v1, Context* context) {
- context->GetBuilder()->CreateBinOp(llvm::Instruction::Add, v0, v1);
- return 0;
+Value Type::CreateDiv(Value v0, Value v1, Context* context) {
+ return context->GetBuilder()->CreateSDiv(v0, v1);
}
-int Type::CreateSub(Value v0, Value v1, Context* context) {
- context->GetBuilder()->CreateBinOp(llvm::Instruction::Sub, v0, v1);
- return 0;
+Value Type::CreateMod(Value v0, Value v1, Context* context) {
+ return context->GetBuilder()->CreateSRem(v0, v1);
}
-int Type::CreateMul(Value v0, Value v1, Context* context) {
- context->GetBuilder()->CreateBinOp(llvm::Instruction::Mul, v0, v1);
- return 0;
+Value Type::CreateLt(Value v0, Value v1, Context* context) {
+ return context->GetBuilder()->CreateICmp(llvm::CmpInst::ICMP_SLT, v0, v1);
}
-int Type::CreateDiv(Value v0, Value v1, Context* context) {
- context->GetBuilder()->CreateBinOp(llvm::Instruction::SDiv, v0, v1);
- return 0;
+Value Type::CreateLe(Value v0, Value v1, Context* context) {
+ return context->GetBuilder()->CreateICmp(llvm::CmpInst::ICMP_SLE, v0, v1);
}
-int Type::CreateMod(Value v0, Value v1, Context* context) {
- context->GetBuilder()->CreateBinOp(llvm::Instruction::SRem, v0, v1);
- return 0;
+Value Type::CreateGt(Value v0, Value v1, Context* context) {
+ return context->GetBuilder()->CreateICmp(llvm::CmpInst::ICMP_SGT, v0, v1);
}
-int Type::CreateLt(Value v0, Value v1, Context* context) {
- context->GetBuilder()->CreateICmp(llvm::CmpInst::ICMP_SLT, v0, v1);
- return 0;
+Value Type::CreateGe(Value v0, Value v1, Context* context) {
+ return context->GetBuilder()->CreateICmp(llvm::CmpInst::ICMP_SGE, v0, v1);
}
-int Type::CreateLe(Value v0, Value v1, Context* context) {
- context->GetBuilder()->CreateICmp(llvm::CmpInst::ICMP_SLE, v0, v1);
- return 0;
+Value Type::CreateEq(Value v0, Value v1, Context* context) {
+ return context->GetBuilder()->CreateICmp(llvm::CmpInst::ICMP_EQ, v0, v1);
}
-int Type::CreateGt(Value v0, Value v1, Context* context) {
- context->GetBuilder()->CreateICmp(llvm::CmpInst::ICMP_SGT, v0, v1);
- return 0;
+Value Type::CreateNe(Value v0, Value v1, Context* context) {
+ return context->GetBuilder()->CreateICmp(llvm::CmpInst::ICMP_NE, v0, v1);
}
-int Type::CreateGe(Value v0, Value v1, Context* context) {
- context->GetBuilder()->CreateICmp(llvm::CmpInst::ICMP_SGE, v0, v1);
- return 0;
+Value Type::CreateAnd(Value v0, Value v1, Context* context) {
+ return context->GetBuilder()->CreateAnd(v0, v1);
}
-int Type::CreateEq(Value v0, Value v1, Context* context) {
- context->GetBuilder()->CreateICmp(llvm::CmpInst::ICMP_EQ, v0, v1);
- return 0;
+Value Type::CreateOr(Value v0, Value v1, Context* context) {
+ return context->GetBuilder()->CreateOr(v0, v1);
}
-int Type::CreateNe(Value v0, Value v1, Context* context) {
- context->GetBuilder()->CreateICmp(llvm::CmpInst::ICMP_NE, v0, v1);
- return 0;
+Value Type::CreateXor(Value v0, Value v1, Context* context) {
+ return context->GetBuilder()->CreateXor(v0, v1);
}
-int Type::CreateAnd(Value v0, Value v1, Context* context) {
- context->GetBuilder()->CreateBinOp(llvm::Instruction::And, v0, v1);
- return 0;
+Value Type::CreatePos(Value v, Context* context) { return v; }
+
+Value Type::CreateNeg(Value v, Context* context) {
+ return context->GetBuilder()->CreateNeg(v);
}
-int Type::CreateOr(Value v0, Value v1, Context* context) {
- context->GetBuilder()->CreateBinOp(llvm::Instruction::Or, v0, v1);
- return 0;
+Value Type::CreateNot(Value v, Context* context) {
+ return context->GetBuilder()->CreateNot(v);
}
-int Type::CreateXor(Value v0, Value v1, Context* context) {
- context->GetBuilder()->CreateBinOp(llvm::Instruction::Xor, v0, v1);
- return 0;
+Value Type::CreateFAdd(Value v0, Value v1, Context* context) {
+ return context->GetBuilder()->CreateFAdd(v0, v1);
}
-int Type::CreateFAdd(Value v0, Value v1, Context* context) {
- context->GetBuilder()->CreateBinOp(llvm::Instruction::FAdd, v0, v1);
- return 0;
+Value Type::CreateFSub(Value v0, Value v1, Context* context) {
+ return context->GetBuilder()->CreateFSub(v0, v1);
}
-int Type::CreateFSub(Value v0, Value v1, Context* context) {
- context->GetBuilder()->CreateBinOp(llvm::Instruction::FSub, v0, v1);
- return 0;
+Value Type::CreateFMul(Value v0, Value v1, Context* context) {
+ return context->GetBuilder()->CreateFMul(v0, v1);
}
-int Type::CreateFMul(Value v0, Value v1, Context* context) {
- context->GetBuilder()->CreateBinOp(llvm::Instruction::FMul, v0, v1);
- return 0;
+Value Type::CreateFDiv(Value v0, Value v1, Context* context) {
+ return context->GetBuilder()->CreateFDiv(v0, v1);
}
-int Type::CreateFDiv(Value v0, Value v1, Context* context) {
- context->GetBuilder()->CreateBinOp(llvm::Instruction::FDiv, v0, v1);
- return 0;
+Value Type::CreateFMod(Value v0, Value v1, Context* context) {
+ return context->GetBuilder()->CreateFRem(v0, v1);
}
-int Type::CreateFMod(Value v0, Value v1, Context* context) {
- context->GetBuilder()->CreateBinOp(llvm::Instruction::FRem, v0, v1);
- return 0;
+Value Type::CreateFLt(Value v0, Value v1, Context* context) {
+ return context->GetBuilder()->CreateFCmp(llvm::CmpInst::FCMP_OLT, v0, v1);
}
-int Type::CreateFLt(Value v0, Value v1, Context* context) {
- context->GetBuilder()->CreateFCmp(llvm::CmpInst::FCMP_OLT, v0, v1);
- return 0;
+Value Type::CreateFLe(Value v0, Value v1, Context* context) {
+ return context->GetBuilder()->CreateFCmp(llvm::CmpInst::FCMP_OLE, v0, v1);
}
-int Type::CreateFLe(Value v0, Value v1, Context* context) {
- context->GetBuilder()->CreateFCmp(llvm::CmpInst::FCMP_OLE, v0, v1);
- return 0;
+Value Type::CreateFGt(Value v0, Value v1, Context* context) {
+ return context->GetBuilder()->CreateFCmp(llvm::CmpInst::FCMP_OGT, v0, v1);
}
-int Type::CreateFGt(Value v0, Value v1, Context* context) {
- context->GetBuilder()->CreateFCmp(llvm::CmpInst::FCMP_OGT, v0, v1);
- return 0;
+Value Type::CreateFGe(Value v0, Value v1, Context* context) {
+ return context->GetBuilder()->CreateFCmp(llvm::CmpInst::FCMP_OGE, v0, v1);
}
-int Type::CreateFGe(Value v0, Value v1, Context* context) {
- context->GetBuilder()->CreateFCmp(llvm::CmpInst::FCMP_OGE, v0, v1);
- return 0;
+Value Type::CreateFEq(Value v0, Value v1, Context* context) {
+ return context->GetBuilder()->CreateFCmp(llvm::CmpInst::FCMP_OEQ, v0, v1);
}
-int Type::CreateFEq(Value v0, Value v1, Context* context) {
- context->GetBuilder()->CreateFCmp(llvm::CmpInst::FCMP_OEQ, v0, v1);
- return 0;
+Value Type::CreateFNe(Value v0, Value v1, Context* context) {
+ return context->GetBuilder()->CreateFCmp(llvm::CmpInst::FCMP_ONE, v0, v1);
}
-int Type::CreateFNe(Value v0, Value v1, Context* context) {
- context->GetBuilder()->CreateFCmp(llvm::CmpInst::FCMP_ONE, v0, v1);
- return 0;
+Value Type::CreateFPos(Value v, Context* context) { return v; }
+
+Value Type::CreateFNeg(Value v, Context* context) {
+ return context->GetBuilder()->CreateFNeg(v);
}
+IntegerBaseType::IntegerBaseType(std::string&& name, int width,
+ llvm::Type* LLVMType)
+ : Type(std::move(name), LLVMType)
+ , width_(width) {}
+
+int IntegerBaseType::GetWidth() { return width_; }
+
BooleanType::BooleanType()
- : Type("boolean", true, 1) {}
+ : IntegerBaseType("boolean", 1, llvm::Type::getInt1Ty(GlobalLLVMContext)) {}
-int BooleanType::CreateBinaryOperation(BinaryOperator op, Value v0, Value v1,
- Context* context) {
- static int (pcc::BooleanType::*operations[ToUnderlying(
- BinaryOperator::OPERATOR_NUMBER)])(Value, Value, Context*) = {
+Value BooleanType::CreateBinaryOperation(BinaryOperator op, Value v0, Value v1,
+ Context* context) {
+ static Value (pcc::BooleanType::*operations[ToUnderlying(
+ BinaryOperator::BINARYOP_NUMBER)])(Value, Value, Context*) = {
&BooleanType::NotAllowed, &BooleanType::NotAllowed,
&BooleanType::NotAllowed, &BooleanType::NotAllowed,
&BooleanType::NotAllowed, &BooleanType::NotAllowed,
@@ -161,13 +179,21 @@ int BooleanType::CreateBinaryOperation(BinaryOperator op, Value v0, Value v1,
return (this->*operations[ToUnderlying(op)])(v0, v1, context);
}
+Value BooleanType::CreateUnaryOperation(UnaryOperator op, Value v,
+ Context* context) {
+ if (op == UnaryOperator::NOT) {
+ return CreateNot(v, context);
+ }
+ return NotAllowed(v, context);
+}
+
CharType::CharType()
- : Type("char", true, 8) {}
+ : IntegerBaseType("char", 8, llvm::Type::getInt8Ty(GlobalLLVMContext)) {}
-int CharType::CreateBinaryOperation(BinaryOperator op, Value v0, Value v1,
- Context* context) {
- static int (pcc::CharType::*operations[ToUnderlying(
- BinaryOperator::OPERATOR_NUMBER)])(Value, Value, Context*) = {
+Value CharType::CreateBinaryOperation(BinaryOperator op, Value v0, Value v1,
+ Context* context) {
+ static Value (pcc::CharType::*operations[ToUnderlying(
+ BinaryOperator::BINARYOP_NUMBER)])(Value, Value, Context*) = {
&CharType::CreateAdd, &CharType::CreateSub, &CharType::CreateMul,
&CharType::CreateDiv, &CharType::CreateMod, &CharType::CreateLt,
&CharType::CreateLe, &CharType::CreateGt, &CharType::CreateGe,
@@ -176,13 +202,22 @@ int CharType::CreateBinaryOperation(BinaryOperator op, Value v0, Value v1,
return (this->*operations[ToUnderlying(op)])(v0, v1, context);
}
+Value CharType::CreateUnaryOperation(UnaryOperator op, Value v,
+ Context* context) {
+ static Value (pcc::CharType::*operations[ToUnderlying(
+ UnaryOperator::UNARYOP_NUMEBR)])(Value, Context*) = {
+ &CharType::CreatePos, &CharType::CreateNeg, &CharType::CreateNot};
+ return (this->*operations[ToUnderlying(op)])(v, context);
+}
+
IntegerType::IntegerType()
- : Type("integer", true, 32) {}
+ : IntegerBaseType("integer", 32,
+ llvm::Type::getInt32Ty(GlobalLLVMContext)) {}
-int IntegerType::CreateBinaryOperation(BinaryOperator op, Value v0, Value v1,
- Context* context) {
- static int (pcc::IntegerType::*operations[ToUnderlying(
- BinaryOperator::OPERATOR_NUMBER)])(Value, Value, Context*) = {
+Value IntegerType::CreateBinaryOperation(BinaryOperator op, Value v0, Value v1,
+ Context* context) {
+ static Value (pcc::IntegerType::*operations[ToUnderlying(
+ BinaryOperator::BINARYOP_NUMBER)])(Value, Value, Context*) = {
&IntegerType::CreateAdd, &IntegerType::CreateSub,
&IntegerType::CreateMul, &IntegerType::CreateDiv,
&IntegerType::CreateMod, &IntegerType::CreateLt,
@@ -194,13 +229,22 @@ int IntegerType::CreateBinaryOperation(BinaryOperator op, Value v0, Value v1,
return (this->*operations[ToUnderlying(op)])(v0, v1, context);
}
+Value IntegerType::CreateUnaryOperation(UnaryOperator op, Value v,
+ Context* context) {
+ static Value (pcc::IntegerType::*
+ operations[ToUnderlying(UnaryOperator::UNARYOP_NUMEBR)])(
+ Value, Context*) = {&IntegerType::CreatePos, &IntegerType::CreateNeg,
+ &IntegerType::CreateNot};
+ return (this->*operations[ToUnderlying(op)])(v, context);
+}
+
RealType::RealType()
- : Type("real", true, 32) {}
+ : Type("real", llvm::Type::getFloatTy(GlobalLLVMContext)) {}
-int RealType::CreateBinaryOperation(BinaryOperator op, Value v0, Value v1,
- Context* context) {
- static int (pcc::RealType::*operations[ToUnderlying(
- BinaryOperator::OPERATOR_NUMBER)])(Value, Value, Context*) = {
+Value RealType::CreateBinaryOperation(BinaryOperator op, Value v0, Value v1,
+ Context* context) {
+ static Value (pcc::RealType::*operations[ToUnderlying(
+ BinaryOperator::BINARYOP_NUMBER)])(Value, Value, Context*) = {
&RealType::CreateFAdd, &RealType::CreateFSub, &RealType::CreateFMul,
&RealType::CreateFDiv, &RealType::CreateFMod, &RealType::CreateFLt,
&RealType::CreateFLe, &RealType::CreateFGt, &RealType::CreateFGe,
@@ -209,4 +253,83 @@ int RealType::CreateBinaryOperation(BinaryOperator op, Value v0, Value v1,
return (this->*operations[ToUnderlying(op)])(v0, v1, context);
}
-} // namespace pcc \ No newline at end of file
+Value RealType::CreateUnaryOperation(UnaryOperator op, Value v,
+ Context* context) {
+ static Value (pcc::RealType::*operations[ToUnderlying(
+ UnaryOperator::UNARYOP_NUMEBR)])(Value, Context*) = {
+ &RealType::CreateFPos, &RealType::CreateFNeg, &RealType::NotAllowed};
+ return (this->*operations[ToUnderlying(op)])(v, context);
+}
+
+ArrayType::ArrayType(std::shared_ptr<Type> ElementType, int ElementNumber,
+ std::shared_ptr<Type> IndexType, Value start, Value end,
+ std::string&& name)
+ : Type(std::move(name), llvm::ArrayType::get(ElementType->GetLLVMType(),
+ (uint64_t) ElementNumber))
+ , ElementType_(ElementType)
+ , IndexType_(IndexType)
+ , start_(start)
+ , end_(end) {}
+
+std::shared_ptr<Type> ArrayType::GetElementType() { return ElementType_; }
+std::shared_ptr<Type> ArrayType::GetIndexType() { return IndexType_; }
+
+Value ArrayType::CreateBinaryOperation(BinaryOperator op, Value v0, Value v1,
+ Context* context) {
+ if (op != BinaryOperator::ARRAY_ACCESS) {
+ return NotAllowed(v0, v1, context);
+ }
+ return CreateArrayAccess(v0, v1, context);
+}
+
+Value ArrayType::CreateArrayAccess(Value v0, Value v1, Context* context) {
+ Value indices[2] = {
+ llvm::ConstantInt::get(IndexType_->GetLLVMType(), 0, true),
+ IndexType_->CreateBinaryOperation(BinaryOperator::SUB, v1, start_,
+ context)};
+ return context->GetBuilder()->CreateInBoundsGEP(LLVMType_, v0, indices);
+}
+
+// we use LLVM i8* type to represent void*
+PointerType::PointerType(std::shared_ptr<Type> ElementType,
+ std::shared_ptr<Type> DifferenceType,
+ std::shared_ptr<Type> IndexType, std::string&& name)
+ : Type(std::move(name),
+ llvm::PointerType::get(ElementType->GetLLVMType(), 0))
+ , ElementType_(ElementType)
+ , DifferenceType_(DifferenceType)
+ , IndexType_(IndexType) {}
+
+std::shared_ptr<Type> PointerType::GetElementType() { return ElementType_; }
+std::shared_ptr<Type> PointerType::GetIndexType() { return IndexType_; }
+std::shared_ptr<Type> PointerType::GeDiifferenceType() {
+ return DifferenceType_;
+}
+
+Value PointerType::CreateBinaryOperation(BinaryOperator op, Value v0, Value v1,
+ Context* context) {
+ static Value (pcc::PointerType::*operations[ToUnderlying(
+ BinaryOperator::BINARYOP_NUMBER)])(Value, Value, Context*) = {
+ &PointerType::NotAllowed, &PointerType::CreatePointerSub,
+ &PointerType::NotAllowed, &PointerType::NotAllowed,
+ &PointerType::NotAllowed, &PointerType::CreateLt,
+ &PointerType::CreateLe, &PointerType::CreateGt,
+ &PointerType::CreateGe, &PointerType::CreateEq,
+ &PointerType::CreateNe, &PointerType::NotAllowed,
+ &PointerType::NotAllowed, &PointerType::NotAllowed,
+ &PointerType::NotAllowed};
+ return (this->*operations[ToUnderlying(op)])(v0, v1, context);
+}
+
+Value PointerType::CreatePointerSub(Value v0, Value v1, Context* context) {
+ llvm::IRBuilder<>* builder = context->GetBuilder();
+ llvm::Type* ResultLLVMType = DifferenceType_->GetLLVMType();
+ Value ConvertedV0 = builder->CreatePtrToInt(v0, ResultLLVMType);
+ Value ConvertedV1 = builder->CreatePtrToInt(v1, ResultLLVMType);
+ return builder->CreateSub(ConvertedV0, ConvertedV1);
+}
+
+Value PointerType::CreateArrayAccess(Value v0, Value v1, Context* context) {
+ return context->GetBuilder()->CreateInBoundsGEP(LLVMType_, v0, v1);
+}
+} // namespace pcc
diff --git a/Type.hh b/Type.hh
index 0bc889d..4413058 100644
--- a/Type.hh
+++ b/Type.hh
@@ -3,11 +3,15 @@
#include <memory>
#include <string>
-#include <vector>
-#include "Context.hh"
+#include <llvm/IR/IRBuilder.h>
+#include <llvm/IR/Module.h>
+#include <llvm/IR/Type.h>
namespace pcc {
+using Value = llvm::Value*;
+class Context;
+
enum class BinaryOperator {
ADD,
SUB,
@@ -24,9 +28,14 @@ enum class BinaryOperator {
OR,
XOR,
ARRAY_ACCESS,
- OPERATOR_NUMBER
+ BINARYOP_NUMBER
};
+enum class UnaryOperator { POS, NEG, NOT, UNARYOP_NUMEBR };
+
+const char* GetOperatorName(BinaryOperator op);
+const char* GetOperatorName(UnaryOperator op);
+
template <typename T>
constexpr std::underlying_type_t<T> ToUnderlying(T value) {
return static_cast<std::underlying_type_t<T>>(value);
@@ -34,75 +43,137 @@ constexpr std::underlying_type_t<T> ToUnderlying(T value) {
class Type {
public:
- Type(const char* name, bool IsBasicType, int width);
+ Type(std::string&& name, llvm::Type* LLVMType);
virtual const char* GetCommonName();
+ llvm::Type* GetLLVMType();
+
+ // return nullptr if the operation is not supported
+ virtual Value CreateBinaryOperation(BinaryOperator op, Value v0, Value v1,
+ Context* context);
+ virtual Value CreateUnaryOperation(UnaryOperator op, Value v,
+ Context* context);
+
+ protected:
+ Value NotAllowed(Value v0, Value v1, Context* context);
+ Value NotAllowed(Value v, Context* context);
- // return -1 if the operation is not supported
- virtual int CreateBinaryOperation(BinaryOperator op, Value v0, Value v1,
- Context* context);
+ Value CreateAdd(Value v0, Value v1, Context* context);
+ Value CreateSub(Value v0, Value v1, Context* context);
+ Value CreateMul(Value v0, Value v1, Context* context);
+ Value CreateDiv(Value v0, Value v1, Context* context);
+ Value CreateMod(Value v0, Value v1, Context* context);
+ Value CreateLt(Value v0, Value v1, Context* context);
+ Value CreateLe(Value v0, Value v1, Context* context);
+ Value CreateGt(Value v0, Value v1, Context* context);
+ Value CreateGe(Value v0, Value v1, Context* context);
+ Value CreateEq(Value v0, Value v1, Context* context);
+ Value CreateNe(Value v0, Value v1, Context* context);
+ Value CreateAnd(Value v0, Value v1, Context* context);
+ Value CreateOr(Value v0, Value v1, Context* context);
+ Value CreateXor(Value v0, Value v1, Context* context);
+ Value CreatePos(Value v, Context* context);
+ Value CreateNeg(Value v, Context* context);
+ Value CreateNot(Value v, Context* context);
+
+ Value CreateFAdd(Value v0, Value v1, Context* context);
+ Value CreateFSub(Value v0, Value v1, Context* context);
+ Value CreateFMul(Value v0, Value v1, Context* context);
+ Value CreateFDiv(Value v0, Value v1, Context* context);
+ Value CreateFMod(Value v0, Value v1, Context* context);
+ Value CreateFLt(Value v0, Value v1, Context* context);
+ Value CreateFLe(Value v0, Value v1, Context* context);
+ Value CreateFGt(Value v0, Value v1, Context* context);
+ Value CreateFGe(Value v0, Value v1, Context* context);
+ Value CreateFEq(Value v0, Value v1, Context* context);
+ Value CreateFNe(Value v0, Value v1, Context* context);
+ Value CreateFPos(Value v, Context* context);
+ Value CreateFNeg(Value v, Context* context);
+
+ std::string name_;
+ llvm::Type* LLVMType_;
+};
+
+class IntegerBaseType : public Type {
+ public:
+ IntegerBaseType(std::string&& name, int width, llvm::Type* LLVMType);
+ int GetWidth();
protected:
- int NotAllowed(Value v0, Value v1, Context* context);
-
- int CreateAdd(Value v0, Value v1, Context* context);
- int CreateSub(Value v0, Value v1, Context* context);
- int CreateMul(Value v0, Value v1, Context* context);
- int CreateDiv(Value v0, Value v1, Context* context);
- int CreateMod(Value v0, Value v1, Context* context);
- int CreateLt(Value v0, Value v1, Context* context);
- int CreateLe(Value v0, Value v1, Context* context);
- int CreateGt(Value v0, Value v1, Context* context);
- int CreateGe(Value v0, Value v1, Context* context);
- int CreateEq(Value v0, Value v1, Context* context);
- int CreateNe(Value v0, Value v1, Context* context);
- int CreateAnd(Value v0, Value v1, Context* context);
- int CreateOr(Value v0, Value v1, Context* context);
- int CreateXor(Value v0, Value v1, Context* context);
- int CreateFAdd(Value v0, Value v1, Context* context);
- int CreateFSub(Value v0, Value v1, Context* context);
- int CreateFMul(Value v0, Value v1, Context* context);
- int CreateFDiv(Value v0, Value v1, Context* context);
- int CreateFMod(Value v0, Value v1, Context* context);
- int CreateFLt(Value v0, Value v1, Context* context);
- int CreateFLe(Value v0, Value v1, Context* context);
- int CreateFGt(Value v0, Value v1, Context* context);
- int CreateFGe(Value v0, Value v1, Context* context);
- int CreateFEq(Value v0, Value v1, Context* context);
- int CreateFNe(Value v0, Value v1, Context* context);
- int CreateArrayAccess(Value v0, Value v1, Context* context);
- const char* name_;
- bool IsBasicType_;
int width_;
};
-class BooleanType : public Type {
+class BooleanType : public IntegerBaseType {
public:
BooleanType();
- virtual int CreateBinaryOperation(BinaryOperator op, Value v0, Value v1,
- Context* context) override;
+ virtual Value CreateBinaryOperation(BinaryOperator op, Value v0, Value v1,
+ Context* context) override;
+ virtual Value CreateUnaryOperation(UnaryOperator op, Value v,
+ Context* context) override;
};
-class CharType : public Type {
+class CharType : public IntegerBaseType {
public:
CharType();
- virtual int CreateBinaryOperation(BinaryOperator op, Value v0, Value v1,
- Context* context) override;
+ virtual Value CreateBinaryOperation(BinaryOperator op, Value v0, Value v1,
+ Context* context) override;
+ virtual Value CreateUnaryOperation(UnaryOperator op, Value v,
+ Context* context) override;
};
-class IntegerType : public Type {
+class IntegerType : public IntegerBaseType {
public:
IntegerType();
- virtual int CreateBinaryOperation(BinaryOperator op, Value v0, Value v1,
- Context* context) override;
+ virtual Value CreateBinaryOperation(BinaryOperator op, Value v0, Value v1,
+ Context* context) override;
+ virtual Value CreateUnaryOperation(UnaryOperator op, Value v,
+ Context* context) override;
};
class RealType : public Type {
public:
RealType();
- virtual int CreateBinaryOperation(BinaryOperator op, Value v0, Value v1,
- Context* context) override;
+ virtual Value CreateBinaryOperation(BinaryOperator op, Value v0, Value v1,
+ Context* context) override;
+ virtual Value CreateUnaryOperation(UnaryOperator op, Value v,
+ Context* context) override;
};
+class ArrayType : public Type {
+ public:
+ ArrayType(std::shared_ptr<Type> ElementType, int ElementNumber,
+ std::shared_ptr<Type> IndexType, Value start, Value end,
+ std::string&& name);
+ std::shared_ptr<Type> GetElementType();
+ std::shared_ptr<Type> GetIndexType();
+ virtual Value CreateBinaryOperation(BinaryOperator op, Value v0, Value v1,
+ Context* context) override;
+
+ protected:
+ Value CreateArrayAccess(Value v0, Value v1, Context* context);
+
+ std::shared_ptr<Type> ElementType_;
+ std::shared_ptr<Type> IndexType_;
+ Value start_, end_;
+};
+
+class PointerType : public Type {
+ public:
+ PointerType(std::shared_ptr<Type> ElementType,
+ std::shared_ptr<Type> DifferenceType,
+ std::shared_ptr<Type> IndexType, std::string&& name);
+ std::shared_ptr<Type> GetElementType();
+ std::shared_ptr<Type> GetIndexType();
+ std::shared_ptr<Type> GeDiifferenceType();
+ virtual Value CreateBinaryOperation(BinaryOperator op, Value v0, Value v1,
+ Context* context) override;
+
+ protected:
+ Value CreatePointerSub(Value v0, Value v1, Context* context);
+ Value CreateArrayAccess(Value v0, Value v1, Context* context);
+ std::shared_ptr<Type> ElementType_;
+ std::shared_ptr<Type> DifferenceType_;
+ std::shared_ptr<Type> IndexType_;
+};
} // namespace pcc
#endif // PCC_TYPE_H
diff --git a/TypeManager.cc b/TypeManager.cc
index e69de29..d3599bd 100644
--- a/TypeManager.cc
+++ b/TypeManager.cc
@@ -0,0 +1,150 @@
+#include "TypeManager.hh"
+#include "Context.hh"
+#include "Log.hh"
+
+namespace pcc {
+TypeManager::TypeManager()
+ : builtins_{std::make_shared<BooleanType>(), std::make_shared<CharType>(),
+ std::make_shared<IntegerType>(), std::make_shared<RealType>()} {
+ PointerDifferenceType_ = GetBuiltinType(BuiltinType::INTEGER);
+ PointerIndexType_ = GetBuiltinType(BuiltinType::INTEGER);
+ builtins_.push_back(std::make_shared<PointerType>(
+ GetBuiltinType(BuiltinType::CHAR), PointerDifferenceType_,
+ PointerIndexType_, "string"));
+}
+
+std::shared_ptr<Type> TypeManager::GetBuiltinType(BuiltinType type) {
+ return builtins_[ToUnderlying(type)];
+}
+
+std::pair<std::shared_ptr<Type>, Value>
+ TypeManager::CreateOperation(BinaryOperator op,
+ std::shared_ptr<Type> LeftType,
+ std::shared_ptr<Type> RightType, Value left,
+ Value right, Context* context) {
+ llvm::IRBuilder<>* builder = context->GetBuilder();
+ std::shared_ptr<IntegerBaseType> LeftIntegerBaseType =
+ std::dynamic_pointer_cast<IntegerBaseType>(LeftType);
+ std::shared_ptr<IntegerBaseType> RightIntegerBaseType =
+ std::dynamic_pointer_cast<IntegerBaseType>(RightType);
+ std::shared_ptr<PointerType> LeftPointerType =
+ std::dynamic_pointer_cast<PointerType>(LeftType);
+ std::shared_ptr<ArrayType> LeftArrayType =
+ std::dynamic_pointer_cast<ArrayType>(LeftType);
+
+ // array or pointer access
+ if (op == BinaryOperator::ARRAY_ACCESS) {
+ if (LeftArrayType != nullptr) {
+ if (RightIntegerBaseType == nullptr) {
+ Log(LogLevel::PCC_ERROR,
+ "cannot access the array %s with a non-integer type %s",
+ LeftType->GetCommonName(), RightType->GetCommonName());
+ return {nullptr, nullptr};
+ }
+ std::shared_ptr<Type> LeftIndexType = LeftArrayType->GetIndexType();
+ Value CastedInedx =
+ builder->CreateSExtOrTrunc(right, LeftIndexType->GetLLVMType());
+ return {LeftArrayType->GetElementType(),
+ LeftType->CreateBinaryOperation(op, left, CastedInedx,
+ context)};
+ }
+ if (LeftPointerType != nullptr) {
+ if (RightIntegerBaseType == nullptr) {
+ Log(LogLevel::PCC_ERROR,
+ "cannot access the pointer %s with a non-integer type %s",
+ LeftType->GetCommonName(), RightType->GetCommonName());
+ return {nullptr, nullptr};
+ }
+ Value CastedInedx = builder->CreateSExtOrTrunc(
+ right, PointerIndexType_->GetLLVMType());
+ return {LeftPointerType->GetElementType(),
+ LeftType->CreateBinaryOperation(op, left, CastedInedx,
+ context)};
+ }
+ Log(LogLevel::PCC_ERROR,
+ "the left operand type %s is not array or pointer",
+ LeftType->GetCommonName());
+ return {nullptr, nullptr};
+ }
+
+ // add/sub a pointer with a integer
+ if (op == BinaryOperator::ADD || op == BinaryOperator::SUB) {
+ if (LeftPointerType != nullptr) {
+ if (RightIntegerBaseType != nullptr) {
+ Log(LogLevel::PCC_ERROR,
+ "can not add pointer with non-integer type %s");
+ return {nullptr, nullptr};
+ }
+ Value CastedInedx = builder->CreateSExtOrTrunc(
+ right, PointerIndexType_->GetLLVMType());
+ return {LeftType, builder->CreateInBoundsGEP(
+ LeftType->GetLLVMType(), left, CastedInedx)};
+ }
+ }
+
+ // other operations will require the types of left and right are the same.
+ std::shared_ptr<RealType> LeftRealType =
+ std::dynamic_pointer_cast<RealType>(LeftType);
+ std::shared_ptr<RealType> RightRealType =
+ std::dynamic_pointer_cast<RealType>(RightType);
+ Value ConvertedLeft, ConvertedRight;
+ std::shared_ptr<Type> CommonType;
+ if (LeftType != RightType) {
+ // we can cast the boolean, char, integer and real.
+ if (LeftRealType != nullptr && RightIntegerBaseType != nullptr) {
+ ConvertedLeft = left;
+ ConvertedRight =
+ builder->CreateSIToFP(right, LeftType->GetLLVMType());
+ CommonType = LeftType;
+ } else if (RightRealType != nullptr && LeftIntegerBaseType != nullptr) {
+ ConvertedLeft =
+ builder->CreateSIToFP(left, RightType->GetLLVMType());
+ ConvertedRight = right;
+ CommonType = RightType;
+ } else if (LeftIntegerBaseType != nullptr &&
+ RightIntegerBaseType != nullptr) {
+ CommonType = (LeftIntegerBaseType->GetWidth() >
+ RightIntegerBaseType->GetWidth()
+ ? LeftType
+ : RightType);
+ ConvertedLeft =
+ builder->CreateSExt(left, CommonType->GetLLVMType());
+ ConvertedRight =
+ builder->CreateSExt(right, CommonType->GetLLVMType());
+ } else {
+ Log(LogLevel::PCC_ERROR,
+ "can not apply binary operator on two different type %s and %s",
+ LeftType->GetCommonName(), RightType->GetCommonName());
+ return {nullptr, nullptr};
+ }
+ } else {
+ ConvertedLeft = left;
+ ConvertedRight = right;
+ CommonType = LeftType;
+ }
+ Value result = CommonType->CreateBinaryOperation(op, ConvertedLeft,
+ ConvertedRight, context);
+ if (result == nullptr) {
+ Log(LogLevel::PCC_ERROR,
+ "binary operator %s is not supported on type %s",
+ GetOperatorName(op), CommonType->GetCommonName());
+ }
+ // logical operators return boolean type
+ if (ToUnderlying(op) >= ToUnderlying(BinaryOperator::LT) &&
+ ToUnderlying(op) <= ToUnderlying(BinaryOperator::NE)) {
+ CommonType = builtins_[ToUnderlying(BuiltinType::BOOLEAN)];
+ }
+ return {CommonType, result};
+}
+
+Value TypeManager::CreateOperation(UnaryOperator op, std::shared_ptr<Type> type,
+ Value v, Context* context) {
+ Value result = type->CreateUnaryOperation(op, v, context);
+ if (result == nullptr) {
+ Log(LogLevel::PCC_ERROR,
+ "unary operator %s is not supported on type %s",
+ GetOperatorName(op), type->GetCommonName());
+ }
+ return result;
+}
+} // namespace pcc
diff --git a/TypeManager.hh b/TypeManager.hh
index 248a53a..35a5d78 100644
--- a/TypeManager.hh
+++ b/TypeManager.hh
@@ -1,15 +1,39 @@
#ifndef PCC_TYPEMANAGER_H
#define PCC_TYPEMANAGER_H
+#include <map>
+#include <memory>
+#include <utility>
+#include <vector>
+
#include "Type.hh"
namespace pcc {
+enum class BuiltinType { BOOLEAN, CHAR, INTEGER, REAL, STRING, BUILTIN_NUMBER };
class TypeManager {
+
public:
TypeManager();
+ std::shared_ptr<Type> GetBuiltinType(BuiltinType type);
+
+ // binary operators may change type
+ std::pair<std::shared_ptr<Type>, Value>
+ CreateOperation(BinaryOperator op, std::shared_ptr<Type> LeftType,
+ std::shared_ptr<Type> RightType, Value left,
+ Value right, Context* context);
+
+ // unary operators never change type
+ Value CreateOperation(UnaryOperator op, std::shared_ptr<Type> type, Value v,
+ Context* context);
private:
+ std::vector<std::shared_ptr<Type>> builtins_;
std::vector<std::shared_ptr<Type>> types_;
+
+ // if we are porting to some 64-bit machines, we can change these types to
+ // 64-bit type, in order to make pointers behave correctly
+ std::shared_ptr<Type> PointerDifferenceType_;
+ std::shared_ptr<Type> PointerIndexType_;
};
} // namespace pcc
diff --git a/node/BaseNode.hh b/node/BaseNode.hh
index 4a3746c..ab0b96a 100644
--- a/node/BaseNode.hh
+++ b/node/BaseNode.hh
@@ -1,15 +1,13 @@
#ifndef PCC_BASENODE_H
#define PCC_BASENODE_H
-#include <llvm/IR/Value.h>
-
#include "Context.hh"
namespace pcc {
class BaseNode {
public:
- virtual Value CodeGen() = 0;
BaseNode(Context* context);
+ virtual Value CodeGen() = 0;
protected:
Context* context_;
diff --git a/node/ExprNode.cc b/node/ExprNode.cc
new file mode 100644
index 0000000..8034fb8
--- /dev/null
+++ b/node/ExprNode.cc
@@ -0,0 +1,54 @@
+#include "ExprNode.hh"
+#include "Log.hh"
+#include "TypeManager.hh"
+
+namespace pcc {
+ExprNode::ExprNode(Context* context)
+ : BaseNode(context) {}
+
+std::shared_ptr<Type> ExprNode::GetType() { return type_; }
+
+BinaryExprNode::BinaryExprNode(Context* context, BinaryOperator op,
+ std::shared_ptr<ExprNode> left,
+ std::shared_ptr<ExprNode> right)
+ : ExprNode(context)
+ , op_(op)
+ , left_(left)
+ , right_(right) {}
+
+Value BinaryExprNode::CodeGen() {
+ Value lhs = left_->CodeGen();
+ Value rhs = right_->CodeGen();
+ if (lhs == nullptr || rhs == nullptr) {
+ return nullptr;
+ }
+ std::pair<std::shared_ptr<Type>, Value> result =
+ context_->GetTypeManager()->CreateOperation(
+ op_, left_->GetType(), right_->GetType(), lhs, rhs, context_);
+ if (std::get<1>(result) == nullptr) {
+ Log(LogLevel::PCC_ERROR, "failed to generate a binary expression");
+ return nullptr;
+ }
+ type_ = std::get<0>(result);
+ return std::get<1>(result);
+}
+
+UnaryExprNode::UnaryExprNode(Context* context, UnaryOperator op,
+ std::shared_ptr<ExprNode> value)
+ : ExprNode(context)
+ , op_(op)
+ , value_(value) {}
+
+Value UnaryExprNode::CodeGen() {
+ Value v = value_->CodeGen();
+ if (v == nullptr) {
+ return nullptr;
+ }
+ Value result = context_->GetTypeManager()->CreateOperation(
+ op_, value_->GetType(), v, context_);
+ if (result == nullptr) {
+ Log(LogLevel::PCC_ERROR, "failed to generate a unary operation");
+ }
+ return result;
+}
+} // namespace pcc
diff --git a/node/ExprNode.hh b/node/ExprNode.hh
new file mode 100644
index 0000000..ac62975
--- /dev/null
+++ b/node/ExprNode.hh
@@ -0,0 +1,43 @@
+#ifndef PCC_EXPRNODE_H
+#define PCC_EXPRNODE_H
+
+#include "BaseNode.hh"
+#include "Type.hh"
+
+namespace pcc {
+class ExprNode : public BaseNode {
+ public:
+ ExprNode(Context* context);
+ virtual Value CodeGen() = 0;
+ std::shared_ptr<Type> GetType();
+
+ protected:
+ std::shared_ptr<Type> type_;
+};
+
+class BinaryExprNode : public ExprNode {
+ public:
+ BinaryExprNode(Context* context, BinaryOperator op,
+ std::shared_ptr<ExprNode> left,
+ std::shared_ptr<ExprNode> right);
+ virtual Value CodeGen();
+
+ protected:
+ BinaryOperator op_;
+ std::shared_ptr<ExprNode> left_, right_;
+};
+
+class UnaryExprNode : public ExprNode {
+ public:
+ UnaryExprNode(Context* context, UnaryOperator op,
+ std::shared_ptr<ExprNode> value);
+ virtual Value CodeGen();
+
+ protected:
+ UnaryOperator op_;
+ std::shared_ptr<ExprNode> value_;
+};
+
+} // namespace pcc
+
+#endif // !PCC_EXPRNODE_H
diff --git a/node/LiteralNode.cc b/node/LiteralNode.cc
index fedeb36..19a2419 100644
--- a/node/LiteralNode.cc
+++ b/node/LiteralNode.cc
@@ -2,42 +2,49 @@
#include <llvm/ADT/APInt.h>
#include "Driver.hh"
-#include "Node.hh"
+#include "LiteralNode.hh"
namespace pcc {
template <> Value BooleanLiteralNode::CodeGen() {
- llvm::LLVMContext& context = context_->GetModule()->getContext();
if (value_ == true) {
- return llvm::ConstantInt::getTrue(context);
+ return llvm::ConstantInt::getTrue(GlobalLLVMContext);
} else {
- return llvm::ConstantInt::getFalse(context);
+ return llvm::ConstantInt::getFalse(GlobalLLVMContext);
}
}
+template <> Value CharLiteralNode::CodeGen() {
+ return llvm::ConstantInt::get(type_->GetLLVMType(), value_, true);
+}
+
template <> Value IntegerLiteralNode::CodeGen() {
- llvm::LLVMContext& context = context_->GetModule()->getContext();
- llvm::APInt value(32, (uint64_t) value_, true);
- return llvm::ConstantInt::get(context, value);
+ return llvm::ConstantInt::get(type_->GetLLVMType(), value_, true);
}
template <> Value RealLiteralNode::CodeGen() {
- llvm::LLVMContext& context = context_->GetModule()->getContext();
llvm::APFloat value(value_);
- return llvm::ConstantFP::get(context, value);
+ return llvm::ConstantFP::get(GlobalLLVMContext, value);
+}
+
+StringLiteralNode::StringLiteralNode(Context* context,
+ std::shared_ptr<Type> type, char* begin,
+ char* end)
+ : ExprNode(context)
+ , value_(begin, end) {
+ type_ = type;
}
-template <> Value StringLiteralNode::CodeGen() {
- llvm::Module* module = context_->GetModule();
- llvm::LLVMContext& context = module->getContext();
- llvm::Constant* str = llvm::ConstantDataArray::getString(context, value_);
- llvm::Type* type = str->getType();
- llvm::GlobalVariable* var = new llvm::GlobalVariable(
- *module, type, true, llvm::GlobalVariable::InternalLinkage, str);
- llvm::Constant* zero =
- llvm::Constant::getNullValue(llvm::IntegerType::getInt32Ty(context));
- llvm::Constant* indices[] = {zero, zero};
- llvm::Constant* ptr =
- llvm::ConstantExpr::getGetElementPtr(type, var, indices, true);
- return ptr;
+Value StringLiteralNode::CodeGen() {
+ llvm::IRBuilder<>* builder = context_->GetBuilder();
+ std::shared_ptr<PointerType> pointer =
+ std::static_pointer_cast<PointerType>(type_);
+ llvm::Constant* ConstantString =
+ llvm::ConstantDataArray::get(GlobalLLVMContext, value_);
+ llvm::Constant* GlobalString = new llvm::GlobalVariable(
+ type_->GetLLVMType(), true, llvm::GlobalValue::PrivateLinkage,
+ ConstantString);
+ Value ZeroIndex =
+ llvm::ConstantInt::get(pointer->GetIndexType()->GetLLVMType(), 0, true);
+ return builder->CreateInBoundsGEP(GlobalString, {ZeroIndex, ZeroIndex});
}
} // namespace pcc
diff --git a/node/LiteralNode.hh b/node/LiteralNode.hh
index 7c74f27..b7fcb38 100644
--- a/node/LiteralNode.hh
+++ b/node/LiteralNode.hh
@@ -4,27 +4,42 @@
#include <string>
#include "BaseNode.hh"
+#include "ExprNode.hh"
namespace pcc {
-template <typename Type, typename Construct = Type>
-class LiteralNode : public BaseNode {
+template <typename T> class LiteralNode : public ExprNode {
public:
- LiteralNode(Context* context, Construct value);
- Value CodeGen() override; // type-specific CodeGen() is in the .cc file.
+ LiteralNode(Context* context, std::shared_ptr<Type> type, T value);
+ Value CodeGen() override;
private:
- Type value_;
+ T value_;
};
-template <typename Type, typename Construct>
-LiteralNode<Type, Construct>::LiteralNode(Context* context, Construct value)
- : BaseNode(context)
- , value_(value) {}
+// the implementation of member functions of template classes must be put in
+// header, but we put type-specific CodeGen() in the .cc file.
+template <typename T>
+LiteralNode<T>::LiteralNode(Context* context, std::shared_ptr<Type> type,
+ T value)
+ : ExprNode(context)
+ , value_(value) {
+ type_ = type;
+}
using BooleanLiteralNode = LiteralNode<bool>;
+using CharLiteralNode = LiteralNode<char>;
using IntegerLiteralNode = LiteralNode<int>;
using RealLiteralNode = LiteralNode<float>;
-using StringLiteralNode = LiteralNode<std::string, char*>;
+
+class StringLiteralNode : public ExprNode {
+ public:
+ StringLiteralNode(Context* context, std::shared_ptr<Type> type, char* begin,
+ char* end);
+ Value CodeGen() override;
+
+ private:
+ std::vector<char> value_;
+};
} // namespace pcc
#endif
diff --git a/node/Node.hh b/node/Node.hh
index daf99eb..bb5ce7c 100644
--- a/node/Node.hh
+++ b/node/Node.hh
@@ -2,6 +2,7 @@
#define PCC_NODE_H
#include "BaseNode.hh"
+#include "ExprNode.hh"
#include "LiteralNode.hh"
#endif // !PCC_NODE_H