diff --git a/sayaka/Makefile b/sayaka/Makefile index e8fa15a..aec276c 100644 --- a/sayaka/Makefile +++ b/sayaka/Makefile @@ -1,8 +1,8 @@ CC = g++ CFLAGS = -c -g -std=c++11 -fexceptions LDFLAGS = -g -rdynamic -LLVM_COMPILER_FLAGS = $(shell llvm-config --libs core jit native --cxxflags) -LLVM_LINKER_FLAGS = $(shell llvm-config --libs core jit native --ldflags) +LLVM_COMPILER_FLAGS = $(shell llvm-config --cxxflags) +LLVM_LINKER_FLAGS = $(shell llvm-config --ldflags --libs core jit native) EXECUTABLE = sayaka SRC_DIR = src BIN_DIR = bin @@ -13,14 +13,11 @@ OBJS = $(subst $(SRC_DIR),$(BIN_DIR),$(subst .cpp,.o,$(SOURCES))) all: $(BIN_DIR) $(PARSER_SOURCE) $(LEXER_SOURCE) $(BIN_DIR)/$(EXECUTABLE) -debug: all - gdb $(BIN_DIR)/$(EXECUTABLE) - -valgrind: all - valgrind --leak-check=yes $(BIN_DIR)/$(EXECUTABLE) - $(BIN_DIR)/$(EXECUTABLE): $(OBJS) - $(CC) $(OBJS) -o $(BIN_DIR)/$(EXECUTABLE) $(LLVM_LINKER_FLAGS) $(LDFLAGS) + $(CC) $(OBJS) -o $@ $(LLVM_LINKER_FLAGS) $(LDFLAGS) + +$(BIN_DIR)/%.o: $(SRC_DIR)/%.cpp + $(CC) $(LLVM_COMPILER_FLAGS) $(CFLAGS) $< -o $@ $(LEXER_SOURCE): $(SRC_DIR)/lexer.l flex --outfile=$@ --header-file=$(SRC_DIR)/lexer.h $(SRC_DIR)/lexer.l @@ -28,8 +25,11 @@ $(LEXER_SOURCE): $(SRC_DIR)/lexer.l $(PARSER_SOURCE): $(SRC_DIR)/parser.y bison --defines=$(SRC_DIR)/parser.h --output=$@ --verbose --report-file=$(BIN_DIR)/parser.log $(SRC_DIR)/parser.y -$(BIN_DIR)/%.o: $(SRC_DIR)/%.cpp - $(CC) $(LLVM_COMPILER_FLAGS) $(CFLAGS) $< -o $@ +debug: all + gdb $(BIN_DIR)/$(EXECUTABLE) + +valgrind: all + valgrind --leak-check=yes $(BIN_DIR)/$(EXECUTABLE) $(BIN_DIR): mkdir -p $(BIN_DIR) @@ -39,4 +39,4 @@ clean: rm -f $(LEXER_SOURCE) $(SRC_DIR)/lexer.h $(PARSER_SOURCE) $(SRC_DIR)/parser.h playground: $(BIN_DIR) - $(CC) $(SRC_DIR)/playground.cpp -o $(BIN_DIR)/playground.o + $(CC) $(SRC_DIR)/playground.cpp -o $(BIN_DIR)/playground.o $(shell llvm-config --libs core jit native --cxxflags --ldflags) diff --git a/sayaka/src/ast_node.h b/sayaka/src/ast_node.h index 9816dfd..6973673 100644 --- a/sayaka/src/ast_node.h +++ b/sayaka/src/ast_node.h @@ -2,37 +2,12 @@ #define __AST_NODE_H_ #include +#include +#include #include #include "ast_type.h" #include "code_gen_context.h" -union tagUNumberValue { - int8_t b; - uint8_t ub; - int16_t s; - uint16_t us; - int32_t i; - uint32_t ui; - int64_t l; - uint64_t ul; - float f; - double d; -}; - - -enum tagENumberType { - eBYTE = 0, - eUBYTE = 1, - eSHORT = (1 << 1), - eUSHORT = (1 << 1) | 1, - eINT = (1 << 2), - eUINT = (1 << 2) | 1, - eLONG = (1 << 3), - eULONG = (1 << 3) | 1, - eFLOAT = (1 << 4), - eDOUBLE = (1 << 5), -}; - enum tagEBinaryOperationType { eMULTIPLY, eADD, @@ -41,8 +16,6 @@ enum tagEBinaryOperationType { ePOW, }; -typedef union tagUNumberValue UNumberValue; -typedef enum tagENumberType ENumberType; typedef enum tagEBinaryOperationType EBinaryOperationType; class ASTNode { @@ -67,7 +40,6 @@ class ASTNodeIdentifier : public ASTNode { class ASTNodePrimitive : public ASTNode { public: - UNumberValue val; std::string str; ASTNodePrimitive(std::string); @@ -150,4 +122,29 @@ class ASTNodeFunction : public ASTNode { virtual ASTNodeFunction* pass_types(CodeGenContext*, ASTType*) override; }; +class ASTNodeFunctionPrototype : public ASTNode { +public: + std::string return_type; + std::string function_name; + std::vector>* args; + + ASTNodeFunctionPrototype(std::string, std::string, std::vector>*); + + virtual ~ASTNodeFunctionPrototype(); + virtual llvm::Value* gen_code(CodeGenContext*) override; + virtual ASTNodeFunctionPrototype* pass_types(CodeGenContext*, ASTType*) override; +}; + +class ASTNodeFunctionCall : public ASTNode { +public: + std::string function_name; + std::vector* args; + + ASTNodeFunctionCall(std::string, std::vector*); + + virtual ~ASTNodeFunctionCall(); + virtual llvm::Value* gen_code(CodeGenContext*) override; + virtual ASTNodeFunctionCall* pass_types(CodeGenContext*, ASTType*) override; +}; + #endif /* __AST_NODE_H_ */ diff --git a/sayaka/src/ast_node_functioncall.cpp b/sayaka/src/ast_node_functioncall.cpp new file mode 100644 index 0000000..ff6f06e --- /dev/null +++ b/sayaka/src/ast_node_functioncall.cpp @@ -0,0 +1,33 @@ +#include "ast_node.h" + +ASTNodeFunctionCall::ASTNodeFunctionCall(std::string function_name, std::vector* args) { + this->function_name = function_name; + this->args = args; +} + +ASTNodeFunctionCall::~ASTNodeFunctionCall() { + for (std::vector::iterator it = this->args->begin(); it != this->args->end(); it++) { + delete *it; + } + delete this->args; +} + +ASTNodeFunctionCall* ASTNodeFunctionCall::pass_types(CodeGenContext* code_gen_context, ASTType* type) { + this->type = code_gen_context->ast_types_resolver.double_ty(); + for (std::vector::iterator it = this->args->begin(); it != this->args->end(); it++) { + *it = (*it)->pass_types(code_gen_context, type); + } + return this; +} + +llvm::Value* ASTNodeFunctionCall::gen_code(CodeGenContext* code_gen_context) { + llvm::Function* callee = code_gen_context->module->getFunction(this->function_name); + if (callee == NULL) { + throw std::runtime_error("Unknown function called"); + } + std::vector argsv; + for (std::vector::iterator it = this->args->begin(); it != this->args->end(); it++) { + argsv.push_back((*it)->gen_code(code_gen_context)); + } + return code_gen_context->builder.CreateCall(callee, argsv, "calltmp"); +} diff --git a/sayaka/src/ast_node_functionprototype.cpp b/sayaka/src/ast_node_functionprototype.cpp new file mode 100644 index 0000000..5554152 --- /dev/null +++ b/sayaka/src/ast_node_functionprototype.cpp @@ -0,0 +1,27 @@ +#include "ast_node.h" + +ASTNodeFunctionPrototype::ASTNodeFunctionPrototype(std::string return_type, std::string function_name, std::vector>* args) { + this->return_type = return_type; + this->function_name = function_name; + this->args = args; +} + +ASTNodeFunctionPrototype::~ASTNodeFunctionPrototype() { + delete this->args; +} + +ASTNodeFunctionPrototype* ASTNodeFunctionPrototype::pass_types(CodeGenContext* code_gen_context, ASTType* type) { + this->type = code_gen_context->ast_types_resolver.int_ty(); + return this; +} + +llvm::Value* ASTNodeFunctionPrototype::gen_code(CodeGenContext* code_gen_context) { + std::vector args_types_list; + for (std::vector>::iterator it = this->args->begin(); it != this->args->end(); it++) { + args_types_list.push_back(code_gen_context->ast_types_resolver.get(std::get<0>(*it))->llvm_type); + } + llvm::FunctionType* ft = llvm::FunctionType::get(code_gen_context->ast_types_resolver.get(this->return_type)->llvm_type, args_types_list, false); + llvm::Function* fn = llvm::Function::Create(ft, llvm::Function::ExternalLinkage, this->function_name, code_gen_context->module); + return llvm::ConstantInt::get(code_gen_context->ast_types_resolver.int_ty()->llvm_type, 0, true); +} + diff --git a/sayaka/src/lexer.l b/sayaka/src/lexer.l index cdb1648..465d16c 100644 --- a/sayaka/src/lexer.l +++ b/sayaka/src/lexer.l @@ -29,6 +29,7 @@ SUBTRACT "-" DIVIDE "/" POW "*\\*" EQUALS "=" +COMMA "," IDENTIFIER [a-z_][a-zA-Z0-9_]* TYPE_NAME [A-Z][a-zA-Z0-9_]* @@ -53,6 +54,7 @@ WS [ \r\n\t]+ {RBRACKET} { return TOKEN_RBRACKET; } {SEMICOLON} { return TOKEN_SEMICOLON; } {EQUALS} { return TOKEN_EQUALS; } +{COMMA} { return TOKEN_COMMA; } {NUMBER} { SAVE_TOKEN; return TOKEN_NUMBER; } {IDENTIFIER} { SAVE_TOKEN; return TOKEN_IDENTIFIER; } diff --git a/sayaka/src/main.cpp b/sayaka/src/main.cpp index 800c5c6..1d7434a 100644 --- a/sayaka/src/main.cpp +++ b/sayaka/src/main.cpp @@ -11,6 +11,12 @@ namespace boost { } #endif // BOOST_NO_EXCEPTIONS +extern "C" { + int32_t test_fn(int32_t x) { + return x * 2; + } +} + int main(int argc, char* argv[]) { Compiler compiler; compiler.llvm_initialize(); diff --git a/sayaka/src/parser.y b/sayaka/src/parser.y index a191271..6d85a19 100644 --- a/sayaka/src/parser.y +++ b/sayaka/src/parser.y @@ -15,6 +15,9 @@ void yyerror(YYLTYPE* llocp, ASTNode**, yyscan_t scanner, const char *s) { %code requires { +#include +#include + class ASTNode; class ASTNodeBlock; class ASTNodeIdentifier; @@ -38,6 +41,8 @@ typedef void* yyscan_t; ASTNode* node; ASTNodeBlock* block; ASTNodeIdentifier* identifier; + std::vector>* typed_args_list; + std::vector* args_list; std::string* str; } @@ -48,11 +53,14 @@ typedef void* yyscan_t; %token TOKEN_LPAREN TOKEN_RPAREN TOKEN_SEMICOLON TOKEN_EQUALS TOKEN_LBRACE TOKEN_RBRACE TOKEN_LBRACKET TOKEN_RBRACKET %token TOKEN_ADD TOKEN_MULTIPLY TOKEN_DIVIDE TOKEN_SUBTRACT TOKEN_POW +%token TOKEN_COMMA %token TOKEN_NUMBER TOKEN_IDENTIFIER TOKEN_TYPE_NAME -%type program expr number binary_operator_expr assignment_expr variable_declaration_expr cast_expr +%type program expr number binary_operator_expr assignment_expr variable_declaration_expr cast_expr function_call_expr function_prototype_expr %type stmts %type identifier +%type typed_args_list +%type args_list %start program @@ -77,6 +85,8 @@ expr | variable_declaration_expr { $$ = $1; } | assignment_expr { $$ = $1; } | cast_expr { $$ = $1; } + | function_prototype_expr { $$ = $1; } + | function_call_expr { $$ = $1; } | binary_operator_expr { $$ = $1; } ; @@ -120,3 +130,43 @@ binary_operator_expr | expr TOKEN_MULTIPLY expr { $$ = new ASTNodeBinaryOperator(eMULTIPLY, $1, $3); } | expr TOKEN_POW expr { $$ = new ASTNodeBinaryOperator(ePOW, $1, $3); } ; + +function_prototype_expr + : TOKEN_TYPE_NAME TOKEN_IDENTIFIER TOKEN_LPAREN typed_args_list TOKEN_RPAREN { + $$ = new ASTNodeFunctionPrototype(*$1, *$2, $4); + delete $1; + delete $2; + } + ; + + +typed_args_list + : TOKEN_TYPE_NAME TOKEN_IDENTIFIER { + $$ = new std::vector>(); + $$->push_back(std::make_tuple(*$1, *$2)); + delete $1; + delete $2; + } + | typed_args_list TOKEN_COMMA TOKEN_TYPE_NAME TOKEN_IDENTIFIER { + $$->push_back(std::make_tuple(*$3, *$4)); + delete $3; + delete $4; + } + ; + +args_list + : expr { + $$ = new std::vector(); + $$->push_back($1); + } + | args_list TOKEN_COMMA expr { + $$->push_back($3); + } + ; + +function_call_expr + : TOKEN_IDENTIFIER TOKEN_LPAREN args_list TOKEN_RPAREN { + $$ = new ASTNodeFunctionCall(*$1, $3); + delete $1; + } + ; diff --git a/sayaka/src/playground.cpp b/sayaka/src/playground.cpp index aee052c..6add888 100644 --- a/sayaka/src/playground.cpp +++ b/sayaka/src/playground.cpp @@ -2,6 +2,8 @@ #include #include #include +#include +#include void test_map_nonexisting_key() { std::cout << "Testing map non-existing key" << std::endl; @@ -57,11 +59,17 @@ void test_virtual_destructors() { std::cout << "---" << std::endl; } +void test_llvm_memory() { + llvm::InitializeNativeTarget(); + llvm::llvm_shutdown(); +} + int main() { test_map_nonexisting_key(); test_pointer_size(); test_string_concat(); test_string_stream(); test_virtual_destructors(); + test_llvm_memory(); return 0; }