From 41f6e75e3f26bdcccfcb3910f202452e14653826 Mon Sep 17 00:00:00 2001 From: Nagi5Yeq Date: Fri, 15 May 2020 21:16:26 +0800 Subject: basic support of types --- CMakeLists.txt | 36 +++++--- Context.cc | 4 + Context.hh | 5 +- Driver.cc | 10 +-- Driver.hh | 7 +- Lexer.hh | 19 +++-- Lexer.l | 11 ++- Parser.y | 22 ++--- Type.cc | 212 ++++++++++++++++++++++++++++++++++++++++++++++ Type.hh | 108 ++++++++++++++++++++++++ TypeManager.cc | 0 TypeManager.hh | 16 ++++ getopt.c | 223 ------------------------------------------------- getopt.h | 59 ------------- main.cc | 5 +- node/BaseNode.cc | 4 +- node/BaseNode.hh | 9 +- node/ExpressionNode.hh | 8 ++ node/LiteralNode.cc | 8 +- node/LiteralNode.hh | 7 +- win32/getopt.c | 223 +++++++++++++++++++++++++++++++++++++++++++++++++ win32/getopt.h | 59 +++++++++++++ 22 files changed, 700 insertions(+), 355 deletions(-) create mode 100644 Type.cc create mode 100644 Type.hh create mode 100644 TypeManager.cc create mode 100644 TypeManager.hh delete mode 100644 getopt.c delete mode 100644 getopt.h create mode 100644 node/ExpressionNode.hh create mode 100644 win32/getopt.c create mode 100644 win32/getopt.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 388e050..cf4517f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,36 +5,46 @@ find_package(LLVM REQUIRED CONFIG) include_directories(${LLVM_INCLUDE_DIRS}) add_definitions(${LLVM_DEFINITIONS}) -find_package(BISON REQUIRED) -find_package(FLEX REQUIRED) - set(PCC_SOURCE Context.cc Driver.cc Log.cc main.cc + Type.cc Version.cc) -bison_target(pcc_parser Parser.y ${CMAKE_CURRENT_BINARY_DIR}/Parser.cc) -flex_target(pcc_lexer Lexer.l ${CMAKE_CURRENT_BINARY_DIR}/Lexer.cc) -add_flex_bison_dependency(pcc_lexer pcc_parser) - -add_definitions(-DPCC_OSNAME="${CMAKE_SYSTEM}") - list(APPEND PCC_SOURCE node/BaseNode.cc node/LiteralNode.cc) +set(PCC_INCLUDE + ${CMAKE_SOURCE_DIR} + ${CMAKE_SOURCE_DIR}/node + ${CMAKE_CURRENT_BINARY_DIR}) + +if(WIN32) + add_compile_options(/Zc:__cplusplus) + list(APPEND PCC_SOURCE + win32/getopt.c) + list(APPEND PCC_INCLUDE + ${CMAKE_SOURCE_DIR}/win32) +endif() + +find_package(BISON REQUIRED) +find_package(FLEX REQUIRED) + +bison_target(pcc_parser Parser.y ${CMAKE_CURRENT_BINARY_DIR}/Parser.cc) +flex_target(pcc_lexer Lexer.l ${CMAKE_CURRENT_BINARY_DIR}/Lexer.cc) +add_flex_bison_dependency(pcc_lexer pcc_parser) list(APPEND PCC_SOURCE ${BISON_pcc_parser_OUTPUTS} ${FLEX_pcc_lexer_OUTPUTS}) +add_definitions(-DPCC_OSNAME="${CMAKE_SYSTEM}") + add_executable(pcc ${PCC_SOURCE}) -target_include_directories(pcc PRIVATE - ${CMAKE_SOURCE_DIR} - ${CMAKE_SOURCE_DIR}/node - ${CMAKE_CURRENT_BINARY_DIR}) +target_include_directories(pcc PRIVATE ${PCC_INCLUDE}) llvm_map_components_to_libnames(llvm_libs support core) target_link_libraries(pcc ${llvm_libs}) diff --git a/Context.cc b/Context.cc index ee88544..fd4a7a5 100644 --- a/Context.cc +++ b/Context.cc @@ -8,4 +8,8 @@ llvm::LLVMContext GlobalContext; Context::Context(const char* name) : builder_(GlobalContext) , module_(name, GlobalContext) {} + +llvm::Module* Context::GetModule() { return &module_; } + +llvm::IRBuilder<>* Context::GetBuilder() { return &builder_; } } // namespace pcc diff --git a/Context.hh b/Context.hh index bc66632..e300a19 100644 --- a/Context.hh +++ b/Context.hh @@ -5,15 +5,16 @@ #include namespace pcc { -class Driver; +using Value = llvm::Value*; class Context { public: Context(const char* name); + llvm::Module* GetModule(); + llvm::IRBuilder<>* GetBuilder(); private: llvm::IRBuilder<> builder_; llvm::Module module_; - friend class Driver; }; extern llvm::LLVMContext GlobalContext; diff --git a/Driver.cc b/Driver.cc index 6c3509d..6d557db 100644 --- a/Driver.cc +++ b/Driver.cc @@ -2,8 +2,8 @@ #include "Parser.hh" namespace pcc { -Driver::Driver(Context* context) - : context_(context) {} +Driver::Driver(const char* name) + : context_(name) {} Driver::~Driver() {} @@ -12,12 +12,8 @@ void Driver::Parse(std::string& filename) { if (StartLexer(filename) != 0) { return; } - Parser parser(*this); + Parser parser(*this, &context_); parser.parse(); StopLexer(); } - -llvm::Module* Driver::GetModule() { return &context_->module_; } - -llvm::IRBuilder<>* Driver::GetBuilder() { return &context_->builder_; } } // namespace pcc diff --git a/Driver.hh b/Driver.hh index 5f0d18d..d3e773d 100644 --- a/Driver.hh +++ b/Driver.hh @@ -9,16 +9,15 @@ namespace pcc { class Driver { public: - Driver(Context* context); + Driver(const char* name); ~Driver(); int StartLexer(std::string& filename); void StopLexer(); void Parse(std::string& filename); - llvm::Module* GetModule(); - llvm::IRBuilder<>* GetBuilder(); Location location_; - Context* context_; + private: + Context context_; }; } // namespace pcc diff --git a/Lexer.hh b/Lexer.hh index 35b27cc..c6103eb 100644 --- a/Lexer.hh +++ b/Lexer.hh @@ -6,7 +6,8 @@ #include "Node.hh" #include "Parser.hh" -#define YY_DECL pcc::Parser::symbol_type yylex(pcc::Driver& driver) +#define YY_DECL \ + pcc::Parser::symbol_type yylex(pcc::Driver& driver, pcc::Context* context) YY_DECL; @@ -51,28 +52,28 @@ char* GetUnescapedChar(char* s, char* end, char* out) { } } -Parser::symbol_type make_BOOLEAN_LITERAL(bool b, pcc::Driver& driver, +Parser::symbol_type make_BOOLEAN_LITERAL(bool b, pcc::Context* context, const Parser::location_type& loc) { return Parser::make_BOOLEAN_LITERAL( - std::make_shared(&driver, b), loc); + std::make_shared(context, b), loc); } -Parser::symbol_type make_INTEGER_LITERAL(int v, pcc::Driver& driver, +Parser::symbol_type make_INTEGER_LITERAL(int v, pcc::Context* context, const Parser::location_type& loc) { return Parser::make_INTEGER_LITERAL( - std::make_shared(&driver, v), loc); + std::make_shared(context, v), loc); } -Parser::symbol_type make_REAL_LITERAL(float v, pcc::Driver& driver, +Parser::symbol_type make_REAL_LITERAL(float v, pcc::Context* context, const Parser::location_type& loc) { return Parser::make_REAL_LITERAL( - std::make_shared(&driver, v), loc); + std::make_shared(context, v), loc); } -Parser::symbol_type make_STRING_LITERAL(char* s, pcc::Driver& driver, +Parser::symbol_type make_STRING_LITERAL(char* s, pcc::Context* context, const Parser::location_type& loc) { return Parser::make_STRING_LITERAL( - std::make_shared(&driver, s), loc); + std::make_shared(context, s), loc); } } // namespace Lexer } // namespace pcc diff --git a/Lexer.l b/Lexer.l index 6f43790..b55cb80 100644 --- a/Lexer.l +++ b/Lexer.l @@ -74,7 +74,6 @@ white [\t\f\r ] "/" {return Parser::make_REAL_DIV(loc);} "div" {return Parser::make_DIV(loc);} "mod" {return Parser::make_MOD(loc);} -"**" {return Parser::make_EXP(loc);} "and" {return Parser::make_AND(loc);} "not" {return Parser::make_NOT(loc);} @@ -105,17 +104,17 @@ white [\t\f\r ] "real" {return Parser::make_REAL(loc);} "string" {return Parser::make_STRING(loc);} -"true" {return pcc::Lexer::make_BOOLEAN_LITERAL(true, driver, loc);} -"false" {return pcc::Lexer::make_BOOLEAN_LITERAL(false, driver, loc);} +"true" {return pcc::Lexer::make_BOOLEAN_LITERAL(true, context, loc);} +"false" {return pcc::Lexer::make_BOOLEAN_LITERAL(false, context, loc);} {integer} { int number = std::strtol(yytext, NULL, 0); - return pcc::Lexer::make_INTEGER_LITERAL(number, driver, loc); + return pcc::Lexer::make_INTEGER_LITERAL(number, context, loc); } {real} { float number = std::strtof(yytext, NULL); - return pcc::Lexer::make_REAL_LITERAL(number, driver, loc); + return pcc::Lexer::make_REAL_LITERAL(number, context, loc); } {string} { @@ -127,7 +126,7 @@ white [\t\f\r ] p++; } *p = '\0'; - return pcc::Lexer::make_STRING_LITERAL(yytext + 1, driver, loc); + return pcc::Lexer::make_STRING_LITERAL(yytext + 1, context, loc); } {identifier} { diff --git a/Parser.y b/Parser.y index 993867f..bcde931 100644 --- a/Parser.y +++ b/Parser.y @@ -7,8 +7,9 @@ #include "Location.hh" #include "Node.hh" +#include "Context.hh" -namespace pcc { +namespace pcc{ class Driver; } } @@ -16,11 +17,12 @@ namespace pcc { %locations %param {pcc::Driver& driver} +%param {pcc::Context* context} -%code { -#include "Driver.hh" +%code{ +#define YY_DECL \ + pcc::Parser::symbol_type yylex(pcc::Driver& driver, pcc::Context* context) -#define YY_DECL pcc::Parser::symbol_type yylex(pcc::Driver& driver) YY_DECL; } @@ -36,7 +38,7 @@ YY_DECL; %token PROGRAM IDENTIFIER CONST VAR BEGINS ENDS FUNCTION FILE_END %token IF THEN ELSE WHILE DO %token BOOLEAN CHAR INTEGER REAL STRING -%token ADD SUB MUL REAL_DIV DIV MOD EXP LT LE GT GE EQ NE +%token ADD SUB MUL REAL_DIV DIV MOD LT LE GT GE EQ NE %token AND NOT OR XOR %token INTEGER_LITERAL REAL_LITERAL STRING_LITERAL BOOLEAN_LITERAL CHAR_LITERAL @@ -166,15 +168,11 @@ l2_expression ; l3_expression - : l3_expression l4_operator l4_expression - | l4_expression - -l4_expression : lvalue | function_call | literal | LPARENTHESIS expression RPARENTHESIS - | l5_operator l4_expression + | l4_operator l3_expression ; l1_operator @@ -202,10 +200,6 @@ l3_operator ; l4_operator - : EXP - ; - -l5_operator : NOT | ADD | SUB diff --git a/Type.cc b/Type.cc new file mode 100644 index 0000000..4e3dd86 --- /dev/null +++ b/Type.cc @@ -0,0 +1,212 @@ +#include + +#include "Type.hh" + +namespace pcc { +Type::Type(const char* name, bool IsBasicType, int width) + : name_(name) + , IsBasicType_(IsBasicType) + , width_(width) {} + +const char* Type::GetCommonName() { return name_; } + +int 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; } + +int Type::CreateAdd(Value v0, Value v1, Context* context) { + context->GetBuilder()->CreateBinOp(llvm::Instruction::Add, v0, v1); + return 0; +} + +int Type::CreateSub(Value v0, Value v1, Context* context) { + context->GetBuilder()->CreateBinOp(llvm::Instruction::Sub, v0, v1); + return 0; +} + +int Type::CreateMul(Value v0, Value v1, Context* context) { + context->GetBuilder()->CreateBinOp(llvm::Instruction::Mul, v0, v1); + return 0; +} + +int Type::CreateDiv(Value v0, Value v1, Context* context) { + context->GetBuilder()->CreateBinOp(llvm::Instruction::SDiv, v0, v1); + return 0; +} + +int Type::CreateMod(Value v0, Value v1, Context* context) { + context->GetBuilder()->CreateBinOp(llvm::Instruction::SRem, v0, v1); + return 0; +} + +int Type::CreateLt(Value v0, Value v1, Context* context) { + context->GetBuilder()->CreateICmp(llvm::CmpInst::ICMP_SLT, v0, v1); + return 0; +} + +int Type::CreateLe(Value v0, Value v1, Context* context) { + context->GetBuilder()->CreateICmp(llvm::CmpInst::ICMP_SLE, v0, v1); + return 0; +} + +int Type::CreateGt(Value v0, Value v1, Context* context) { + context->GetBuilder()->CreateICmp(llvm::CmpInst::ICMP_SGT, v0, v1); + return 0; +} + +int Type::CreateGe(Value v0, Value v1, Context* context) { + context->GetBuilder()->CreateICmp(llvm::CmpInst::ICMP_SGE, v0, v1); + return 0; +} + +int Type::CreateEq(Value v0, Value v1, Context* context) { + context->GetBuilder()->CreateICmp(llvm::CmpInst::ICMP_EQ, v0, v1); + return 0; +} + +int Type::CreateNe(Value v0, Value v1, Context* context) { + context->GetBuilder()->CreateICmp(llvm::CmpInst::ICMP_NE, v0, v1); + return 0; +} + +int Type::CreateAnd(Value v0, Value v1, Context* context) { + context->GetBuilder()->CreateBinOp(llvm::Instruction::And, v0, v1); + return 0; +} + +int Type::CreateOr(Value v0, Value v1, Context* context) { + context->GetBuilder()->CreateBinOp(llvm::Instruction::Or, v0, v1); + return 0; +} + +int Type::CreateXor(Value v0, Value v1, Context* context) { + context->GetBuilder()->CreateBinOp(llvm::Instruction::Xor, v0, v1); + return 0; +} + +int Type::CreateFAdd(Value v0, Value v1, Context* context) { + context->GetBuilder()->CreateBinOp(llvm::Instruction::FAdd, v0, v1); + return 0; +} + +int Type::CreateFSub(Value v0, Value v1, Context* context) { + context->GetBuilder()->CreateBinOp(llvm::Instruction::FSub, v0, v1); + return 0; +} + +int Type::CreateFMul(Value v0, Value v1, Context* context) { + context->GetBuilder()->CreateBinOp(llvm::Instruction::FMul, v0, v1); + return 0; +} + +int Type::CreateFDiv(Value v0, Value v1, Context* context) { + context->GetBuilder()->CreateBinOp(llvm::Instruction::FDiv, v0, v1); + return 0; +} + +int Type::CreateFMod(Value v0, Value v1, Context* context) { + context->GetBuilder()->CreateBinOp(llvm::Instruction::FRem, v0, v1); + return 0; +} + +int Type::CreateFLt(Value v0, Value v1, Context* context) { + context->GetBuilder()->CreateFCmp(llvm::CmpInst::FCMP_OLT, v0, v1); + return 0; +} + +int Type::CreateFLe(Value v0, Value v1, Context* context) { + context->GetBuilder()->CreateFCmp(llvm::CmpInst::FCMP_OLE, v0, v1); + return 0; +} + +int Type::CreateFGt(Value v0, Value v1, Context* context) { + context->GetBuilder()->CreateFCmp(llvm::CmpInst::FCMP_OGT, v0, v1); + return 0; +} + +int Type::CreateFGe(Value v0, Value v1, Context* context) { + context->GetBuilder()->CreateFCmp(llvm::CmpInst::FCMP_OGE, v0, v1); + return 0; +} + +int Type::CreateFEq(Value v0, Value v1, Context* context) { + context->GetBuilder()->CreateFCmp(llvm::CmpInst::FCMP_OEQ, v0, v1); + return 0; +} + +int Type::CreateFNe(Value v0, Value v1, Context* context) { + context->GetBuilder()->CreateFCmp(llvm::CmpInst::FCMP_ONE, v0, v1); + return 0; +} + +BooleanType::BooleanType() + : Type("boolean", true, 1) {} + +int BooleanType::CreateBinaryOperation(BinaryOperator op, Value v0, Value v1, + Context* context) { + static int (pcc::BooleanType::*operations[ToUnderlying( + BinaryOperator::OPERATOR_NUMBER)])(Value, Value, Context*) = { + &BooleanType::NotAllowed, &BooleanType::NotAllowed, + &BooleanType::NotAllowed, &BooleanType::NotAllowed, + &BooleanType::NotAllowed, &BooleanType::NotAllowed, + &BooleanType::NotAllowed, &BooleanType::NotAllowed, + &BooleanType::NotAllowed, &BooleanType::CreateEq, + &BooleanType::CreateNe, &BooleanType::CreateAnd, + &BooleanType::CreateOr, &BooleanType::CreateXor, + &BooleanType::NotAllowed, + }; + return (this->*operations[ToUnderlying(op)])(v0, v1, context); +} + +CharType::CharType() + : Type("char", true, 8) {} + +int CharType::CreateBinaryOperation(BinaryOperator op, Value v0, Value v1, + Context* context) { + static int (pcc::CharType::*operations[ToUnderlying( + BinaryOperator::OPERATOR_NUMBER)])(Value, Value, Context*) = { + &CharType::CreateAdd, &CharType::CreateSub, &CharType::CreateMul, + &CharType::CreateDiv, &CharType::CreateMod, &CharType::CreateLt, + &CharType::CreateLe, &CharType::CreateGt, &CharType::CreateGe, + &CharType::CreateEq, &CharType::CreateNe, &CharType::CreateAnd, + &CharType::CreateOr, &CharType::CreateXor, &CharType::NotAllowed}; + return (this->*operations[ToUnderlying(op)])(v0, v1, context); +} + +IntegerType::IntegerType() + : Type("integer", true, 32) {} + +int IntegerType::CreateBinaryOperation(BinaryOperator op, Value v0, Value v1, + Context* context) { + static int (pcc::IntegerType::*operations[ToUnderlying( + BinaryOperator::OPERATOR_NUMBER)])(Value, Value, Context*) = { + &IntegerType::CreateAdd, &IntegerType::CreateSub, + &IntegerType::CreateMul, &IntegerType::CreateDiv, + &IntegerType::CreateMod, &IntegerType::CreateLt, + &IntegerType::CreateLe, &IntegerType::CreateGt, + &IntegerType::CreateGe, &IntegerType::CreateEq, + &IntegerType::CreateNe, &IntegerType::CreateAnd, + &IntegerType::CreateOr, &IntegerType::CreateXor, + &IntegerType::NotAllowed}; + return (this->*operations[ToUnderlying(op)])(v0, v1, context); +} + +RealType::RealType() + : Type("real", true, 32) {} + +int RealType::CreateBinaryOperation(BinaryOperator op, Value v0, Value v1, + Context* context) { + static int (pcc::RealType::*operations[ToUnderlying( + BinaryOperator::OPERATOR_NUMBER)])(Value, Value, Context*) = { + &RealType::CreateFAdd, &RealType::CreateFSub, &RealType::CreateFMul, + &RealType::CreateFDiv, &RealType::CreateFMod, &RealType::CreateFLt, + &RealType::CreateFLe, &RealType::CreateFGt, &RealType::CreateFGe, + &RealType::CreateFEq, &RealType::CreateFNe, &RealType::NotAllowed, + &RealType::NotAllowed, &RealType::NotAllowed, &RealType::NotAllowed}; + return (this->*operations[ToUnderlying(op)])(v0, v1, context); +} + +} // namespace pcc \ No newline at end of file diff --git a/Type.hh b/Type.hh new file mode 100644 index 0000000..0bc889d --- /dev/null +++ b/Type.hh @@ -0,0 +1,108 @@ +#ifndef PCC_TYPE_H +#define PCC_TYPE_H + +#include +#include +#include + +#include "Context.hh" + +namespace pcc { +enum class BinaryOperator { + ADD, + SUB, + MUL, + DIV, + MOD, + LT, + LE, + GT, + GE, + EQ, + NE, + AND, + OR, + XOR, + ARRAY_ACCESS, + OPERATOR_NUMBER +}; + +template +constexpr std::underlying_type_t ToUnderlying(T value) { + return static_cast>(value); +} + +class Type { + public: + Type(const char* name, bool IsBasicType, int width); + virtual const char* GetCommonName(); + + // return -1 if the operation is not supported + virtual int CreateBinaryOperation(BinaryOperator op, Value v0, Value v1, + Context* context); + + 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 { + public: + BooleanType(); + virtual int CreateBinaryOperation(BinaryOperator op, Value v0, Value v1, + Context* context) override; +}; + +class CharType : public Type { + public: + CharType(); + virtual int CreateBinaryOperation(BinaryOperator op, Value v0, Value v1, + Context* context) override; +}; + +class IntegerType : public Type { + public: + IntegerType(); + virtual int CreateBinaryOperation(BinaryOperator op, Value v0, Value v1, + Context* context) override; +}; + +class RealType : public Type { + public: + RealType(); + virtual int CreateBinaryOperation(BinaryOperator op, Value v0, Value v1, + Context* context) override; +}; + +} // namespace pcc + +#endif // PCC_TYPE_H diff --git a/TypeManager.cc b/TypeManager.cc new file mode 100644 index 0000000..e69de29 diff --git a/TypeManager.hh b/TypeManager.hh new file mode 100644 index 0000000..248a53a --- /dev/null +++ b/TypeManager.hh @@ -0,0 +1,16 @@ +#ifndef PCC_TYPEMANAGER_H +#define PCC_TYPEMANAGER_H + +#include "Type.hh" + +namespace pcc { +class TypeManager { + public: + TypeManager(); + + private: + std::vector> types_; +}; +} // namespace pcc + +#endif // !PCC_TYPEMANAGER_H diff --git a/getopt.c b/getopt.c deleted file mode 100644 index b5eebdf..0000000 --- a/getopt.c +++ /dev/null @@ -1,223 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012-2017, Kim Grasman - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Kim Grasman nor the - * names of contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL KIM GRASMAN BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - ******************************************************************************/ - -#include "getopt.h" - -#include -#include - -char* optarg; -int optopt; -/* The variable optind [...] shall be initialized to 1 by the system. */ -int optind = 1; -int opterr; - -static char* optcursor = NULL; - -/* Implemented based on [1] and [2] for optional arguments. - optopt is handled FreeBSD-style, per [3]. - Other GNU and FreeBSD extensions are purely accidental. - -[1] http://pubs.opengroup.org/onlinepubs/000095399/functions/getopt.html -[2] http://www.kernel.org/doc/man-pages/online/pages/man3/getopt.3.html -[3] -http://www.freebsd.org/cgi/man.cgi?query=getopt&sektion=3&manpath=FreeBSD+9.0-RELEASE -*/ -int getopt(int argc, char* const argv[], const char* optstring) { - int optchar = -1; - const char* optdecl = NULL; - - optarg = NULL; - opterr = 0; - optopt = 0; - - /* Unspecified, but we need it to avoid overrunning the argv bounds. */ - if (optind >= argc) goto no_more_optchars; - - /* If, when getopt() is called argv[optind] is a null pointer, getopt() - shall return -1 without changing optind. */ - if (argv[optind] == NULL) goto no_more_optchars; - - /* If, when getopt() is called *argv[optind] is not the character '-', - getopt() shall return -1 without changing optind. */ - if (*argv[optind] != '-') goto no_more_optchars; - - /* If, when getopt() is called argv[optind] points to the string "-", - getopt() shall return -1 without changing optind. */ - if (strcmp(argv[optind], "-") == 0) goto no_more_optchars; - - /* If, when getopt() is called argv[optind] points to the string "--", - getopt() shall return -1 after incrementing optind. */ - if (strcmp(argv[optind], "--") == 0) { - ++optind; - goto no_more_optchars; - } - - if (optcursor == NULL || *optcursor == '\0') optcursor = argv[optind] + 1; - - optchar = *optcursor; - - /* FreeBSD: The variable optopt saves the last known option character - returned by getopt(). */ - optopt = optchar; - - /* The getopt() function shall return the next option character (if one is - found) from argv that matches a character in optstring, if there is - one that matches. */ - optdecl = strchr(optstring, optchar); - if (optdecl) { - /* [I]f a character is followed by a colon, the option takes an - argument. */ - if (optdecl[1] == ':') { - optarg = ++optcursor; - if (*optarg == '\0') { - /* GNU extension: Two colons mean an option takes an - optional arg; if there is text in the current argv-element - (i.e., in the same word as the option name itself, for - example, - "-oarg"), then it is returned in optarg, otherwise optarg is - set to zero. */ - if (optdecl[2] != ':') { - /* If the option was the last character in the string - pointed to by an element of argv, then optarg shall - contain the next element of argv, and optind shall be - incremented by 2. If the resulting value of optind is - greater than argc, this indicates a missing - option-argument, and getopt() shall return an error - indication. - - Otherwise, optarg shall point to the string following the - option character in that element of argv, and optind - shall be incremented by 1. - */ - if (++optind < argc) { - optarg = argv[optind]; - } else { - /* If it detects a missing option-argument, it shall - return the colon character ( ':' ) if the first - character of optstring was a colon, or a - question-mark character ( '?' ) otherwise. - */ - optarg = NULL; - optchar = (optstring[0] == ':') ? ':' : '?'; - } - } else { - optarg = NULL; - } - } - - optcursor = NULL; - } - } else { - /* If getopt() encounters an option character that is not contained in - optstring, it shall return the question-mark ( '?' ) character. */ - optchar = '?'; - } - - if (optcursor == NULL || *++optcursor == '\0') ++optind; - - return optchar; - -no_more_optchars: - optcursor = NULL; - return -1; -} - -/* Implementation based on [1]. - -[1] http://www.kernel.org/doc/man-pages/online/pages/man3/getopt.3.html -*/ -int getopt_long(int argc, char* const argv[], const char* optstring, - const struct option* longopts, int* longindex) { - const struct option* o = longopts; - const struct option* match = NULL; - int num_matches = 0; - size_t argument_name_length = 0; - const char* current_argument = NULL; - int retval = -1; - - optarg = NULL; - optopt = 0; - - if (optind >= argc) return -1; - - if (strlen(argv[optind]) < 3 || strncmp(argv[optind], "--", 2) != 0) - return getopt(argc, argv, optstring); - - /* It's an option; starts with -- and is longer than two chars. */ - current_argument = argv[optind] + 2; - argument_name_length = strcspn(current_argument, "="); - for (; o->name; ++o) { - if (strncmp(o->name, current_argument, argument_name_length) == 0) { - match = o; - ++num_matches; - } - } - - if (num_matches == 1) { - /* If longindex is not NULL, it points to a variable which is set to the - index of the long option relative to longopts. */ - if (longindex) *longindex = (match - longopts); - - /* If flag is NULL, then getopt_long() shall return val. - Otherwise, getopt_long() returns 0, and flag shall point to a - variable which shall be set to val if the option is found, but left - unchanged if the option is not found. */ - if (match->flag) *(match->flag) = match->val; - - retval = match->flag ? 0 : match->val; - - if (match->has_arg != no_argument) { - optarg = strchr(argv[optind], '='); - if (optarg != NULL) ++optarg; - - if (match->has_arg == required_argument) { - /* Only scan the next argv for required arguments. Behavior is - not - specified, but has been observed with Ubuntu and Mac OSX. */ - if (optarg == NULL && ++optind < argc) { - optarg = argv[optind]; - } - - if (optarg == NULL) retval = ':'; - } - } else if (strchr(argv[optind], '=')) { - /* An argument was provided to a non-argument option. - I haven't seen this specified explicitly, but both GNU and - BSD-based implementations show this behavior. - */ - retval = '?'; - } - } else { - /* Unknown option or ambiguous match. */ - retval = '?'; - } - - ++optind; - return retval; -} diff --git a/getopt.h b/getopt.h deleted file mode 100644 index 03f769f..0000000 --- a/getopt.h +++ /dev/null @@ -1,59 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2012-2017, Kim Grasman - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Kim Grasman nor the - * names of contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL KIM GRASMAN BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - ******************************************************************************/ - -#ifndef INCLUDED_GETOPT_PORT_H -#define INCLUDED_GETOPT_PORT_H - -#if defined(__cplusplus) -extern "C" { -#endif - -#define no_argument 1 -#define required_argument 2 -#define optional_argument 3 - -extern char* optarg; -extern int optind, opterr, optopt; - -struct option { - const char* name; - int has_arg; - int* flag; - int val; -}; - -int getopt(int argc, char* const argv[], const char* optstring); - -int getopt_long(int argc, char* const argv[], const char* optstring, - const struct option* longopts, int* longindex); - -#if defined(__cplusplus) -} -#endif - -#endif // INCLUDED_GETOPT_PORT_H diff --git a/main.cc b/main.cc index 25a1b65..e538e45 100644 --- a/main.cc +++ b/main.cc @@ -32,11 +32,10 @@ int main(int argc, char* argv[]) { return 0; } for (int i = optind; i < argc; i++) { - pcc::Context context(argv[i]); - pcc::Driver driver(&context); + pcc::Driver driver(argv[i]); std::string filename(argv[i]); driver.Parse(filename); } - + return 0; } diff --git a/node/BaseNode.cc b/node/BaseNode.cc index de38f55..8fe2c5d 100644 --- a/node/BaseNode.cc +++ b/node/BaseNode.cc @@ -1,6 +1,6 @@ #include "Node.hh" namespace pcc { -BaseNode::BaseNode(Driver* driver) - : driver_(driver) {} +BaseNode::BaseNode(Context* context) + : context_(context) {} } // namespace pcc diff --git a/node/BaseNode.hh b/node/BaseNode.hh index 60e25bd..4a3746c 100644 --- a/node/BaseNode.hh +++ b/node/BaseNode.hh @@ -3,17 +3,16 @@ #include -namespace pcc { -using Value = llvm::Value*; -class Driver; +#include "Context.hh" +namespace pcc { class BaseNode { public: virtual Value CodeGen() = 0; - BaseNode(Driver* driver); + BaseNode(Context* context); protected: - Driver* driver_; + Context* context_; }; } // namespace pcc diff --git a/node/ExpressionNode.hh b/node/ExpressionNode.hh new file mode 100644 index 0000000..ad31835 --- /dev/null +++ b/node/ExpressionNode.hh @@ -0,0 +1,8 @@ +#ifndef PCC_EXPRESSIONNODE_H +#define PCC_EXPRESSIONNODE_H + +#include "BaseNode.hh" + + + +#endif diff --git a/node/LiteralNode.cc b/node/LiteralNode.cc index 1e9c4b7..fedeb36 100644 --- a/node/LiteralNode.cc +++ b/node/LiteralNode.cc @@ -6,7 +6,7 @@ namespace pcc { template <> Value BooleanLiteralNode::CodeGen() { - llvm::LLVMContext& context = driver_->GetModule()->getContext(); + llvm::LLVMContext& context = context_->GetModule()->getContext(); if (value_ == true) { return llvm::ConstantInt::getTrue(context); } else { @@ -15,19 +15,19 @@ template <> Value BooleanLiteralNode::CodeGen() { } template <> Value IntegerLiteralNode::CodeGen() { - llvm::LLVMContext& context = driver_->GetModule()->getContext(); + llvm::LLVMContext& context = context_->GetModule()->getContext(); llvm::APInt value(32, (uint64_t) value_, true); return llvm::ConstantInt::get(context, value); } template <> Value RealLiteralNode::CodeGen() { - llvm::LLVMContext& context = driver_->GetModule()->getContext(); + llvm::LLVMContext& context = context_->GetModule()->getContext(); llvm::APFloat value(value_); return llvm::ConstantFP::get(context, value); } template <> Value StringLiteralNode::CodeGen() { - llvm::Module* module = driver_->GetModule(); + llvm::Module* module = context_->GetModule(); llvm::LLVMContext& context = module->getContext(); llvm::Constant* str = llvm::ConstantDataArray::getString(context, value_); llvm::Type* type = str->getType(); diff --git a/node/LiteralNode.hh b/node/LiteralNode.hh index 1d5c1b8..7c74f27 100644 --- a/node/LiteralNode.hh +++ b/node/LiteralNode.hh @@ -9,7 +9,7 @@ namespace pcc { template class LiteralNode : public BaseNode { public: - LiteralNode(Driver* driver, Construct value); + LiteralNode(Context* context, Construct value); Value CodeGen() override; // type-specific CodeGen() is in the .cc file. private: @@ -17,9 +17,8 @@ class LiteralNode : public BaseNode { }; template -LiteralNode::LiteralNode(Driver* driver, - Construct value) - : BaseNode(driver) +LiteralNode::LiteralNode(Context* context, Construct value) + : BaseNode(context) , value_(value) {} using BooleanLiteralNode = LiteralNode; diff --git a/win32/getopt.c b/win32/getopt.c new file mode 100644 index 0000000..b5eebdf --- /dev/null +++ b/win32/getopt.c @@ -0,0 +1,223 @@ +/******************************************************************************* + * Copyright (c) 2012-2017, Kim Grasman + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Kim Grasman nor the + * names of contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL KIM GRASMAN BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ******************************************************************************/ + +#include "getopt.h" + +#include +#include + +char* optarg; +int optopt; +/* The variable optind [...] shall be initialized to 1 by the system. */ +int optind = 1; +int opterr; + +static char* optcursor = NULL; + +/* Implemented based on [1] and [2] for optional arguments. + optopt is handled FreeBSD-style, per [3]. + Other GNU and FreeBSD extensions are purely accidental. + +[1] http://pubs.opengroup.org/onlinepubs/000095399/functions/getopt.html +[2] http://www.kernel.org/doc/man-pages/online/pages/man3/getopt.3.html +[3] +http://www.freebsd.org/cgi/man.cgi?query=getopt&sektion=3&manpath=FreeBSD+9.0-RELEASE +*/ +int getopt(int argc, char* const argv[], const char* optstring) { + int optchar = -1; + const char* optdecl = NULL; + + optarg = NULL; + opterr = 0; + optopt = 0; + + /* Unspecified, but we need it to avoid overrunning the argv bounds. */ + if (optind >= argc) goto no_more_optchars; + + /* If, when getopt() is called argv[optind] is a null pointer, getopt() + shall return -1 without changing optind. */ + if (argv[optind] == NULL) goto no_more_optchars; + + /* If, when getopt() is called *argv[optind] is not the character '-', + getopt() shall return -1 without changing optind. */ + if (*argv[optind] != '-') goto no_more_optchars; + + /* If, when getopt() is called argv[optind] points to the string "-", + getopt() shall return -1 without changing optind. */ + if (strcmp(argv[optind], "-") == 0) goto no_more_optchars; + + /* If, when getopt() is called argv[optind] points to the string "--", + getopt() shall return -1 after incrementing optind. */ + if (strcmp(argv[optind], "--") == 0) { + ++optind; + goto no_more_optchars; + } + + if (optcursor == NULL || *optcursor == '\0') optcursor = argv[optind] + 1; + + optchar = *optcursor; + + /* FreeBSD: The variable optopt saves the last known option character + returned by getopt(). */ + optopt = optchar; + + /* The getopt() function shall return the next option character (if one is + found) from argv that matches a character in optstring, if there is + one that matches. */ + optdecl = strchr(optstring, optchar); + if (optdecl) { + /* [I]f a character is followed by a colon, the option takes an + argument. */ + if (optdecl[1] == ':') { + optarg = ++optcursor; + if (*optarg == '\0') { + /* GNU extension: Two colons mean an option takes an + optional arg; if there is text in the current argv-element + (i.e., in the same word as the option name itself, for + example, + "-oarg"), then it is returned in optarg, otherwise optarg is + set to zero. */ + if (optdecl[2] != ':') { + /* If the option was the last character in the string + pointed to by an element of argv, then optarg shall + contain the next element of argv, and optind shall be + incremented by 2. If the resulting value of optind is + greater than argc, this indicates a missing + option-argument, and getopt() shall return an error + indication. + + Otherwise, optarg shall point to the string following the + option character in that element of argv, and optind + shall be incremented by 1. + */ + if (++optind < argc) { + optarg = argv[optind]; + } else { + /* If it detects a missing option-argument, it shall + return the colon character ( ':' ) if the first + character of optstring was a colon, or a + question-mark character ( '?' ) otherwise. + */ + optarg = NULL; + optchar = (optstring[0] == ':') ? ':' : '?'; + } + } else { + optarg = NULL; + } + } + + optcursor = NULL; + } + } else { + /* If getopt() encounters an option character that is not contained in + optstring, it shall return the question-mark ( '?' ) character. */ + optchar = '?'; + } + + if (optcursor == NULL || *++optcursor == '\0') ++optind; + + return optchar; + +no_more_optchars: + optcursor = NULL; + return -1; +} + +/* Implementation based on [1]. + +[1] http://www.kernel.org/doc/man-pages/online/pages/man3/getopt.3.html +*/ +int getopt_long(int argc, char* const argv[], const char* optstring, + const struct option* longopts, int* longindex) { + const struct option* o = longopts; + const struct option* match = NULL; + int num_matches = 0; + size_t argument_name_length = 0; + const char* current_argument = NULL; + int retval = -1; + + optarg = NULL; + optopt = 0; + + if (optind >= argc) return -1; + + if (strlen(argv[optind]) < 3 || strncmp(argv[optind], "--", 2) != 0) + return getopt(argc, argv, optstring); + + /* It's an option; starts with -- and is longer than two chars. */ + current_argument = argv[optind] + 2; + argument_name_length = strcspn(current_argument, "="); + for (; o->name; ++o) { + if (strncmp(o->name, current_argument, argument_name_length) == 0) { + match = o; + ++num_matches; + } + } + + if (num_matches == 1) { + /* If longindex is not NULL, it points to a variable which is set to the + index of the long option relative to longopts. */ + if (longindex) *longindex = (match - longopts); + + /* If flag is NULL, then getopt_long() shall return val. + Otherwise, getopt_long() returns 0, and flag shall point to a + variable which shall be set to val if the option is found, but left + unchanged if the option is not found. */ + if (match->flag) *(match->flag) = match->val; + + retval = match->flag ? 0 : match->val; + + if (match->has_arg != no_argument) { + optarg = strchr(argv[optind], '='); + if (optarg != NULL) ++optarg; + + if (match->has_arg == required_argument) { + /* Only scan the next argv for required arguments. Behavior is + not + specified, but has been observed with Ubuntu and Mac OSX. */ + if (optarg == NULL && ++optind < argc) { + optarg = argv[optind]; + } + + if (optarg == NULL) retval = ':'; + } + } else if (strchr(argv[optind], '=')) { + /* An argument was provided to a non-argument option. + I haven't seen this specified explicitly, but both GNU and + BSD-based implementations show this behavior. + */ + retval = '?'; + } + } else { + /* Unknown option or ambiguous match. */ + retval = '?'; + } + + ++optind; + return retval; +} diff --git a/win32/getopt.h b/win32/getopt.h new file mode 100644 index 0000000..03f769f --- /dev/null +++ b/win32/getopt.h @@ -0,0 +1,59 @@ +/******************************************************************************* + * Copyright (c) 2012-2017, Kim Grasman + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Kim Grasman nor the + * names of contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL KIM GRASMAN BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ******************************************************************************/ + +#ifndef INCLUDED_GETOPT_PORT_H +#define INCLUDED_GETOPT_PORT_H + +#if defined(__cplusplus) +extern "C" { +#endif + +#define no_argument 1 +#define required_argument 2 +#define optional_argument 3 + +extern char* optarg; +extern int optind, opterr, optopt; + +struct option { + const char* name; + int has_arg; + int* flag; + int val; +}; + +int getopt(int argc, char* const argv[], const char* optstring); + +int getopt_long(int argc, char* const argv[], const char* optstring, + const struct option* longopts, int* longindex); + +#if defined(__cplusplus) +} +#endif + +#endif // INCLUDED_GETOPT_PORT_H -- cgit