From 3832be8be4b23fb9e93a3f181e4205eadbdbf4de Mon Sep 17 00:00:00 2001 From: Nagi5Yeq Date: Thu, 21 May 2020 13:32:12 +0800 Subject: binary and unary operations --- CMakeLists.txt | 2 + Context.cc | 10 +- Context.hh | 7 +- Lexer.hh | 33 +++++- Lexer.l | 16 ++- Parser.y | 1 + Type.cc | 331 +++++++++++++++++++++++++++++++++++----------------- Type.hh | 167 ++++++++++++++++++-------- TypeManager.cc | 150 ++++++++++++++++++++++++ TypeManager.hh | 24 ++++ node/BaseNode.hh | 4 +- node/ExprNode.cc | 54 +++++++++ node/ExprNode.hh | 43 +++++++ node/LiteralNode.cc | 51 ++++---- node/LiteralNode.hh | 35 ++++-- node/Node.hh | 1 + 16 files changed, 729 insertions(+), 200 deletions(-) create mode 100644 node/ExprNode.cc create mode 100644 node/ExprNode.hh 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 #include +#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(context, b), loc); + std::make_shared( + 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( + 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(context, v), loc); + std::make_shared( + 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(context, v), loc); + std::make_shared( + 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(context, s), loc); + std::make_shared( + 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 IDENTIFIER %type > BOOLEAN_LITERAL +%type > CHAR_LITERAL %type > INTEGER_LITERAL %type > REAL_LITERAL %type > 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 +#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 ElementType, int ElementNumber, + std::shared_ptr 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 ArrayType::GetElementType() { return ElementType_; } +std::shared_ptr 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 ElementType, + std::shared_ptr DifferenceType, + std::shared_ptr IndexType, std::string&& name) + : Type(std::move(name), + llvm::PointerType::get(ElementType->GetLLVMType(), 0)) + , ElementType_(ElementType) + , DifferenceType_(DifferenceType) + , IndexType_(IndexType) {} + +std::shared_ptr PointerType::GetElementType() { return ElementType_; } +std::shared_ptr PointerType::GetIndexType() { return IndexType_; } +std::shared_ptr 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 #include -#include -#include "Context.hh" +#include +#include +#include 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 constexpr std::underlying_type_t ToUnderlying(T value) { return static_cast>(value); @@ -34,75 +43,137 @@ constexpr std::underlying_type_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 ElementType, int ElementNumber, + std::shared_ptr IndexType, Value start, Value end, + std::string&& name); + std::shared_ptr GetElementType(); + std::shared_ptr 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 ElementType_; + std::shared_ptr IndexType_; + Value start_, end_; +}; + +class PointerType : public Type { + public: + PointerType(std::shared_ptr ElementType, + std::shared_ptr DifferenceType, + std::shared_ptr IndexType, std::string&& name); + std::shared_ptr GetElementType(); + std::shared_ptr GetIndexType(); + std::shared_ptr 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 ElementType_; + std::shared_ptr DifferenceType_; + std::shared_ptr 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(), std::make_shared(), + std::make_shared(), std::make_shared()} { + PointerDifferenceType_ = GetBuiltinType(BuiltinType::INTEGER); + PointerIndexType_ = GetBuiltinType(BuiltinType::INTEGER); + builtins_.push_back(std::make_shared( + GetBuiltinType(BuiltinType::CHAR), PointerDifferenceType_, + PointerIndexType_, "string")); +} + +std::shared_ptr TypeManager::GetBuiltinType(BuiltinType type) { + return builtins_[ToUnderlying(type)]; +} + +std::pair, Value> + TypeManager::CreateOperation(BinaryOperator op, + std::shared_ptr LeftType, + std::shared_ptr RightType, Value left, + Value right, Context* context) { + llvm::IRBuilder<>* builder = context->GetBuilder(); + std::shared_ptr LeftIntegerBaseType = + std::dynamic_pointer_cast(LeftType); + std::shared_ptr RightIntegerBaseType = + std::dynamic_pointer_cast(RightType); + std::shared_ptr LeftPointerType = + std::dynamic_pointer_cast(LeftType); + std::shared_ptr LeftArrayType = + std::dynamic_pointer_cast(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 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 LeftRealType = + std::dynamic_pointer_cast(LeftType); + std::shared_ptr RightRealType = + std::dynamic_pointer_cast(RightType); + Value ConvertedLeft, ConvertedRight; + std::shared_ptr 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, + 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 +#include +#include +#include + #include "Type.hh" namespace pcc { +enum class BuiltinType { BOOLEAN, CHAR, INTEGER, REAL, STRING, BUILTIN_NUMBER }; class TypeManager { + public: TypeManager(); + std::shared_ptr GetBuiltinType(BuiltinType type); + + // binary operators may change type + std::pair, Value> + CreateOperation(BinaryOperator op, std::shared_ptr LeftType, + std::shared_ptr RightType, Value left, + Value right, Context* context); + + // unary operators never change type + Value CreateOperation(UnaryOperator op, std::shared_ptr type, Value v, + Context* context); private: + std::vector> builtins_; std::vector> 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 PointerDifferenceType_; + std::shared_ptr 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 - #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 ExprNode::GetType() { return type_; } + +BinaryExprNode::BinaryExprNode(Context* context, BinaryOperator op, + std::shared_ptr left, + std::shared_ptr 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, 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 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 GetType(); + + protected: + std::shared_ptr type_; +}; + +class BinaryExprNode : public ExprNode { + public: + BinaryExprNode(Context* context, BinaryOperator op, + std::shared_ptr left, + std::shared_ptr right); + virtual Value CodeGen(); + + protected: + BinaryOperator op_; + std::shared_ptr left_, right_; +}; + +class UnaryExprNode : public ExprNode { + public: + UnaryExprNode(Context* context, UnaryOperator op, + std::shared_ptr value); + virtual Value CodeGen(); + + protected: + UnaryOperator op_; + std::shared_ptr 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 #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, 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 pointer = + std::static_pointer_cast(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 #include "BaseNode.hh" +#include "ExprNode.hh" namespace pcc { -template -class LiteralNode : public BaseNode { +template 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, T value); + Value CodeGen() override; private: - Type value_; + T value_; }; -template -LiteralNode::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 +LiteralNode::LiteralNode(Context* context, std::shared_ptr type, + T value) + : ExprNode(context) + , value_(value) { + type_ = type; +} using BooleanLiteralNode = LiteralNode; +using CharLiteralNode = LiteralNode; using IntegerLiteralNode = LiteralNode; using RealLiteralNode = LiteralNode; -using StringLiteralNode = LiteralNode; + +class StringLiteralNode : public ExprNode { + public: + StringLiteralNode(Context* context, std::shared_ptr type, char* begin, + char* end); + Value CodeGen() override; + + private: + std::vector 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 -- cgit