From d80958f987790f533f5048c2e0e8a1cd5fd9f5a1 Mon Sep 17 00:00:00 2001 From: Nagi5Yeq Date: Thu, 14 May 2020 02:05:13 +0800 Subject: use template to make literal nodes --- CMakeLists.txt | 2 +- Lexer.hh | 59 ++++++++++++++++++++++++++++++++++++++++ Lexer.l | 77 +++++++++++------------------------------------------ Parser.y | 20 +++++++------- Version.cc | 13 ++++++--- node/BaseNode.cc | 2 +- node/LiteralNode.cc | 29 +++++++++++++++++--- node/LiteralNode.hh | 20 +++++++++++--- node/Node.hh | 1 - 9 files changed, 135 insertions(+), 88 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a7ab1cf..388e050 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,5 +36,5 @@ target_include_directories(pcc PRIVATE ${CMAKE_SOURCE_DIR}/node ${CMAKE_CURRENT_BINARY_DIR}) -llvm_map_components_to_libnames(llvm_libs support core irreader all) +llvm_map_components_to_libnames(llvm_libs support core) target_link_libraries(pcc ${llvm_libs}) diff --git a/Lexer.hh b/Lexer.hh index 1558d14..35b27cc 100644 --- a/Lexer.hh +++ b/Lexer.hh @@ -1,6 +1,8 @@ #ifndef PCC_LEXER_H #define PCC_LEXER_H +#include + #include "Node.hh" #include "Parser.hh" @@ -10,6 +12,63 @@ YY_DECL; namespace pcc { namespace Lexer { +char* GetUnescapedChar(char* s, char* end, char* out) { + static std::map escape_map = { + {'\'', '\''}, {'?', '\?'}, {'\\', '\\'}, {'a', '\a'}, {'b', '\b'}, + {'f', '\f'}, {'n', '\n'}, {'r', '\r'}, {'t', '\t'}, {'v', '\v'}}; + if (s[0] != '\\') { + *out = s[0]; + return s + 1; + } else if (s[1] == 'x') { + char c[3], *cend; + c[0] = s[2]; + if (end - s > 3) { + c[1] = s[3]; + c[2] = '\0'; + } else { + c[1] = '\0'; + } + *out = (char) std::strtol(c, &cend, 16); + return s + 2 + (cend - c); + } else if (s[1] >= '0' && s[1] <= '7') { + char c[4], *cend; + c[0] = s[1]; + if (end - s > 4) { + c[1] = s[2]; + c[2] = s[3]; + c[3] = '\0'; + } else if (end - s > 3) { + c[1] = s[2]; + c[2] = '\0'; + } else { + c[1] = '\0'; + } + *out = (char) std::strtol(c, &cend, 8); + return s + 1 + (cend - c); + } else { + *out = escape_map[s[1]]; + return s + 2; + } +} + +Parser::symbol_type make_BOOLEAN_LITERAL(bool b, pcc::Driver& driver, + const Parser::location_type& loc) { + return Parser::make_BOOLEAN_LITERAL( + std::make_shared(&driver, b), loc); +} + +Parser::symbol_type make_INTEGER_LITERAL(int v, pcc::Driver& driver, + const Parser::location_type& loc) { + return Parser::make_INTEGER_LITERAL( + std::make_shared(&driver, v), loc); +} + +Parser::symbol_type make_REAL_LITERAL(float v, pcc::Driver& driver, + const Parser::location_type& loc) { + return Parser::make_REAL_LITERAL( + std::make_shared(&driver, v), loc); +} + Parser::symbol_type make_STRING_LITERAL(char* s, pcc::Driver& driver, const Parser::location_type& loc) { return Parser::make_STRING_LITERAL( diff --git a/Lexer.l b/Lexer.l index cd1b634..6f43790 100644 --- a/Lexer.l +++ b/Lexer.l @@ -37,12 +37,12 @@ real_noexp [0-9]*\.[0-9]* real [+-]?({real_exp}|{real_noexp}) -char [0-9a-zA-Z_{}[\]#()<>%:;.?*+\-/^&|~!=,\\" \t\n\v\f] +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} -string '({char}|{escaped_char}|{hex_char}|{oct_char}|\\')*' +string '({trival_char}|{escaped_char}|{hex_char}|{oct_char}|\\')*' identifier [a-z][0-9a-z]* @@ -104,77 +104,30 @@ white [\t\f\r ] "char" {return Parser::make_CHAR(loc);} "real" {return Parser::make_REAL(loc);} "string" {return Parser::make_STRING(loc);} -"true" {return Parser::make_TRUE(loc);} -"false" {return Parser::make_FALSE(loc);} + +"true" {return pcc::Lexer::make_BOOLEAN_LITERAL(true, driver, loc);} +"false" {return pcc::Lexer::make_BOOLEAN_LITERAL(false, driver, loc);} {integer} { int number = std::strtol(yytext, NULL, 0); - return pcc::Parser::make_INTEGER_LITERAL(number, loc); + return pcc::Lexer::make_INTEGER_LITERAL(number, driver, loc); } {real} { float number = std::strtof(yytext, NULL); - return pcc::Parser::make_REAL_LITERAL(number, loc); + return pcc::Lexer::make_REAL_LITERAL(number, driver, loc); } {string} { - static std::map escape_map={ - {'\'','\''}, - {'?','\?'}, - {'\\','\\'}, - {'a','\a'}, - {'b','\b'}, - {'f','\f'}, - {'n','\n'}, - {'r','\r'}, - {'t','\t'}, - {'v','\v'} - }; - char *str = new char[yyleng]; - char *p = str; - int i = 1; - while(i='0' && yytext[i+1]<='7'){ - char c[4], *cend; - c[0]=yytext[i+1]; - if(i+3 #include "Location.hh" +#include "Node.hh" namespace pcc { class Driver; - class StringLiteralNode; } } @@ -19,7 +19,6 @@ namespace pcc { %code { #include "Driver.hh" -#include "Node.hh" #define YY_DECL pcc::Parser::symbol_type yylex(pcc::Driver& driver) YY_DECL; @@ -36,15 +35,15 @@ YY_DECL; %token COLON SEMICOLON COMMA DOT ASSIGN LBRACKET RBRACKET LPARENTHESIS RPARENTHESIS %token PROGRAM IDENTIFIER CONST VAR BEGINS ENDS FUNCTION FILE_END %token IF THEN ELSE WHILE DO -%token INTEGER BOOLEAN CHAR REAL STRING +%token BOOLEAN CHAR INTEGER REAL STRING %token ADD SUB MUL REAL_DIV DIV MOD EXP LT LE GT GE EQ NE -%token AND NOT OR XOR TRUE FALSE -%token INTEGER_LITERAL REAL_LITERAL STRING_LITERAL - -%type INTEGER_LITERAL -%type REAL_LITERAL -%type IDENTIFIER +%token AND NOT OR XOR +%token INTEGER_LITERAL REAL_LITERAL STRING_LITERAL BOOLEAN_LITERAL CHAR_LITERAL +%type IDENTIFIER +%type > BOOLEAN_LITERAL +%type > INTEGER_LITERAL +%type > REAL_LITERAL %type > STRING_LITERAL %% @@ -229,8 +228,7 @@ arguments ; literal - : TRUE - | FALSE + : BOOLEAN_LITERAL | INTEGER_LITERAL | REAL_LITERAL | STRING_LITERAL diff --git a/Version.cc b/Version.cc index 9b8be86..2a58401 100644 --- a/Version.cc +++ b/Version.cc @@ -1,3 +1,5 @@ +#include + #include "Version.hh" namespace pcc { @@ -5,15 +7,18 @@ namespace pcc { PCC_NORETURN void ShowVersion() { std::cerr << PCC_NAME " version " PCC_VERSION_STRING "\n" - << "Copyright (C) 2020 Hanjie Wu \n" - "Platform: " PCC_OSNAME "\n" - "Built on " __DATE__ " " __TIME__ "\n\n" + << "Copyright (C) 2020 Hanjie Wu \n\n" "This program is free software; you can redistribute it and/or " "modify\n" "it under the terms of the GNU General Public License as published " "by\n" "the Free Software Foundation; either version 2 of the License, or\n" - "(at your option) any later version." + "(at your option) any later version.\n\n" + "Configurations:\n" + " LLVM Version: " LLVM_VERSION_STRING "\n" + " Host Platform: " PCC_OSNAME "\n" + " Defaule Target: " LLVM_DEFAULT_TARGET_TRIPLE "\n" + " Built on: " __DATE__ " " __TIME__ << std::endl; std::exit(0); } diff --git a/node/BaseNode.cc b/node/BaseNode.cc index 98ebb82..de38f55 100644 --- a/node/BaseNode.cc +++ b/node/BaseNode.cc @@ -1,4 +1,4 @@ -#include "BaseNode.hh" +#include "Node.hh" namespace pcc { BaseNode::BaseNode(Driver* driver) diff --git a/node/LiteralNode.cc b/node/LiteralNode.cc index dd84ff9..1e9c4b7 100644 --- a/node/LiteralNode.cc +++ b/node/LiteralNode.cc @@ -1,11 +1,32 @@ +#include +#include + +#include "Driver.hh" #include "Node.hh" namespace pcc { -StringLiteralNode::StringLiteralNode(Driver* driver, char* value) - : BaseNode(driver) - , value_(value) {} +template <> Value BooleanLiteralNode::CodeGen() { + llvm::LLVMContext& context = driver_->GetModule()->getContext(); + if (value_ == true) { + return llvm::ConstantInt::getTrue(context); + } else { + return llvm::ConstantInt::getFalse(context); + } +} + +template <> Value IntegerLiteralNode::CodeGen() { + llvm::LLVMContext& context = driver_->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::APFloat value(value_); + return llvm::ConstantFP::get(context, value); +} -Value StringLiteralNode::CodeGen() { +template <> Value StringLiteralNode::CodeGen() { llvm::Module* module = driver_->GetModule(); llvm::LLVMContext& context = module->getContext(); llvm::Constant* str = llvm::ConstantDataArray::getString(context, value_); diff --git a/node/LiteralNode.hh b/node/LiteralNode.hh index 4f9a61a..1d5c1b8 100644 --- a/node/LiteralNode.hh +++ b/node/LiteralNode.hh @@ -6,14 +6,26 @@ #include "BaseNode.hh" namespace pcc { -class StringLiteralNode : public BaseNode { +template +class LiteralNode : public BaseNode { public: - StringLiteralNode(Driver* driver, char* value); - Value CodeGen() override; + LiteralNode(Driver* driver, Construct value); + Value CodeGen() override; // type-specific CodeGen() is in the .cc file. private: - std::string value_; + Type value_; }; + +template +LiteralNode::LiteralNode(Driver* driver, + Construct value) + : BaseNode(driver) + , value_(value) {} + +using BooleanLiteralNode = LiteralNode; +using IntegerLiteralNode = LiteralNode; +using RealLiteralNode = LiteralNode; +using StringLiteralNode = LiteralNode; } // namespace pcc #endif diff --git a/node/Node.hh b/node/Node.hh index 3a02689..daf99eb 100644 --- a/node/Node.hh +++ b/node/Node.hh @@ -1,7 +1,6 @@ #ifndef PCC_NODE_H #define PCC_NODE_H -#include "Driver.hh" #include "BaseNode.hh" #include "LiteralNode.hh" -- cgit