From f098f91455af5d992a075b9b3b9941c6428d20f8 Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Mon, 20 May 2019 11:12:53 -0700 Subject: [PATCH] Make parser create trees --- main.cpp | 29 ++-------------------- parser.y | 74 ++++++++++++++++++++++++++++++------------------------- scanner.l | 4 +-- tree.hpp | 34 ++++++++++++++++++++++--- 4 files changed, 75 insertions(+), 66 deletions(-) diff --git a/main.cpp b/main.cpp index 2c78b1f..3e2ab16 100644 --- a/main.cpp +++ b/main.cpp @@ -1,39 +1,14 @@ #include #include +#include "tree.hpp" #include "parser.hpp" extern int yylex(); -extern std::string* target_program; -extern std::set symbols; +extern stmt_ptr target_program; int main() { if (!yylex()) { - // Write initial C++ stuff. - std::cout << "#include " << std::endl; - std::cout << "int main() {" << std::endl; - - // Write declaractions for all variables. - std::set::iterator it; - for (it = symbols.begin(); it != symbols.end(); it++) { - std::cout << "double " << *it << ";" << std::endl; - } - - // Write the program itself. - std::cout << std::endl << "/* Begin program */" << std::endl << std::endl; - std::cout << *target_program << std::endl; - std::cout << "/* End program */" << std::endl << std::endl; - - // Write print statements for all symbols. - for (it = symbols.begin(); it != symbols.end(); it++) { - std::cout << "std::cout << \"" << *it << ": \" << " << *it << " << std::endl;" << std::endl; - } - - // Write terminating brace. - std::cout << "}" << std::endl; - delete target_program; - target_program = NULL; - } } diff --git a/parser.y b/parser.y index 3b71c7f..a902a6f 100644 --- a/parser.y +++ b/parser.y @@ -2,6 +2,7 @@ #include #include +#include "tree.hpp" #include "parser.hpp" extern int yylex(); @@ -12,8 +13,7 @@ std::string* translate_boolean_str(std::string* boolean_str); * Here, target_program is a string that will hold the target program being * generated, and symbols is a simple symbol table. */ -std::string* target_program; -std::set symbols; +stmt_ptr target_program; %} /* Enable location tracking. */ @@ -23,7 +23,11 @@ std::set symbols; * All program constructs will be represented as strings, specifically as * their corresponding C/C++ translation. */ -%define api.value.type { std::string* } +%union { + expr_ptr ex; + stmt_ptr st; + std::string* str; +} /* * Because the lexer can generate more than one token at a time (i.e. DEDENT @@ -56,6 +60,10 @@ std::set symbols; %left EQ NEQ GT GTE LT LTE %right NOT +%type IDENTIFIER FLOAT INTEGER BOOLEAN +%type program statements statement if_statement while_statement break_statement block elif_blocks else_block +%type assign_statement primary_expression negated_expression expression condition + /* This is our goal/start symbol. */ %start program @@ -73,78 +81,78 @@ program ; statements - : statement { $$ = $1; } - | statements statement { $$ = new std::string(*$1 + *$2); delete $1; delete $2; } + : statement { $$ = new stmt_block(); ((stmt_block*)$$)->children.push_back($1); } + | statements statement { $$ = $1; ((stmt_block*)$$)->children.push_back($2); } ; statement - : assign_statement { $$ = $1; } + : assign_statement { $$ = new stmt_expr($1); } | if_statement { $$ = $1; } | while_statement { $$ = $1; } | break_statement { $$ = $1; } ; primary_expression - : IDENTIFIER { $$ = $1; } - | FLOAT { $$ = $1; } - | INTEGER { $$ = $1; } - | BOOLEAN { $$ = translate_boolean_str($1); delete $1; } - | LPAREN expression RPAREN { $$ = new std::string("(" + *$2 + ")"); delete $2; } + : IDENTIFIER { $$ = new expr_id(*$1); delete $1; } + | FLOAT { $$ = new expr_float(std::stod(*$1)); delete $1; } + | INTEGER { $$ = new expr_int(std::stoi(*$1)); delete $1; } + | BOOLEAN { $$ = new expr_int(*$1 == "True"); delete $1; } + | LPAREN expression RPAREN { $$ = $2; } ; negated_expression - : NOT primary_expression { $$ = new std::string("!" + *$2); delete $2; } + : NOT primary_expression { $$ = new expr_unop(unop::lnot, $2); } ; expression : primary_expression { $$ = $1; } | negated_expression { $$ = $1; } - | expression PLUS expression { $$ = new std::string(*$1 + " + " + *$3); delete $1; delete $3; } - | expression MINUS expression { $$ = new std::string(*$1 + " - " + *$3); delete $1; delete $3; } - | expression TIMES expression { $$ = new std::string(*$1 + " * " + *$3); delete $1; delete $3; } - | expression DIVIDEDBY expression { $$ = new std::string(*$1 + " / " + *$3); delete $1; delete $3; } - | expression EQ expression { $$ = new std::string(*$1 + " == " + *$3); delete $1; delete $3; } - | expression NEQ expression { $$ = new std::string(*$1 + " != " + *$3); delete $1; delete $3; } - | expression GT expression { $$ = new std::string(*$1 + " > " + *$3); delete $1; delete $3; } - | expression GTE expression { $$ = new std::string(*$1 + " >= " + *$3); delete $1; delete $3; } - | expression LT expression { $$ = new std::string(*$1 + " < " + *$3); delete $1; delete $3; } - | expression LTE expression { $$ = new std::string(*$1 + " <= " + *$3); delete $1; delete $3; } + | expression PLUS expression { $$ = new expr_binop(binop::plus, $1, $3); } + | expression MINUS expression { $$ = new expr_binop(binop::minus, $1, $3); } + | expression TIMES expression { $$ = new expr_binop(binop::times, $1, $3); } + | expression DIVIDEDBY expression { $$ = new expr_binop(binop::divide, $1, $3); } + | expression EQ expression { $$ = new expr_binop(binop::eq, $1, $3); } + | expression NEQ expression { $$ = new expr_binop(binop::neq, $1, $3); } + | expression GT expression { $$ = new expr_binop(binop::gt, $1, $3); } + | expression GTE expression { $$ = new expr_binop(binop::gte, $1, $3); } + | expression LT expression { $$ = new expr_binop(binop::lt, $1, $3); } + | expression LTE expression { $$ = new expr_binop(binop::lte, $1, $3); } ; assign_statement - : IDENTIFIER ASSIGN expression NEWLINE { symbols.insert(*$1); $$ = new std::string(*$1 + " = " + *$3 + ";\n"); delete $1; delete $3; } + : IDENTIFIER ASSIGN expression NEWLINE { $$ = new expr_assign(*$1, $3); delete $1; } ; block - : INDENT statements DEDENT { $$ = new std::string("{\n" + *$2 + "}"); delete $2; } + : INDENT statements DEDENT { $$ = $2; } ; condition : expression { $$ = $1; } - | condition AND condition { $$ = new std::string(*$1 + " && " + *$3); delete $1; delete $3; } - | condition OR condition { $$ = new std::string(*$1 + " || " + *$3); delete $1; delete $3; } + | condition AND condition { $$ = new expr_binop(binop::land, $1, $3); } + | condition OR condition { $$ = new expr_binop(binop::lor, $1, $3); } ; if_statement - : IF condition COLON NEWLINE block elif_blocks else_block { $$ = new std::string("if (" + *$2 + ") " + *$5 + *$6 + *$7 + "\n"); delete $2; delete $5; delete $6; delete $7; } + : IF condition COLON NEWLINE block elif_blocks else_block { $$ = new stmt_if($2, $6, $7); delete $6; } ; elif_blocks - : %empty { $$ = new std::string(""); } - | elif_blocks ELIF condition COLON NEWLINE block { $$ = new std::string(*$1 + " else if (" + *$3 + ") " + *$6); delete $1; delete $3; delete $6; } + : %empty { $$ = nullptr; } + | elif_blocks ELIF condition COLON NEWLINE block { $$ = new stmt_if($3, $6); delete $6; } ; else_block - : %empty { $$ = new std::string(""); } - | ELSE COLON NEWLINE block { $$ = new std::string(" else " + *$4); delete $4; } + : %empty { $$ = nullptr; } + | ELSE COLON NEWLINE block { $$ = $4; } while_statement - : WHILE condition COLON NEWLINE block { $$ = new std::string("while (" + *$2 + ") " + *$5 + "\n"); delete $2; delete $5; } + : WHILE condition COLON NEWLINE block { $$ = new stmt_while($2, $5); } ; break_statement - : BREAK NEWLINE { $$ = new std::string("break;\n"); } + : BREAK NEWLINE { $$ = new stmt_break(); } ; %% diff --git a/scanner.l b/scanner.l index d4467d6..de849b3 100644 --- a/scanner.l +++ b/scanner.l @@ -7,6 +7,7 @@ #include #include +#include "tree.hpp" #include "parser.hpp" /* @@ -44,8 +45,7 @@ std::stack _indent_stack; YYLTYPE loc; #define PUSH_TOKEN(token, text) do { \ - yylval = text ? new std::string(text) : NULL; \ - loc.first_line = loc.last_line = yylineno; \ + yylval.str = text ? new std::string(text) : NULL; \ int status = yypush_parse(pstate, token, &yylval, &loc); \ if (status != YYPUSH_MORE) { \ yypstate_delete(pstate); \ diff --git a/tree.hpp b/tree.hpp index 03d445f..b1a291b 100644 --- a/tree.hpp +++ b/tree.hpp @@ -25,7 +25,26 @@ struct expr { virtual ~expr() = default; }; -typedef std::unique_ptr expr_ptr; +typedef expr* expr_ptr; + +struct expr_id : expr { + std::string id; + + expr_id(std::string i) : + id(std::move(i)) {} +}; + +struct expr_int : expr { + int val; + + expr_int(int i) : val(i) {} +}; + +struct expr_float : expr { + double val; + + expr_float(double f) : val(f) {} +}; struct expr_binop : expr { binop op; @@ -61,7 +80,7 @@ struct stmt { virtual ~stmt() = default; }; -typedef std::unique_ptr stmt_ptr; +typedef stmt* stmt_ptr; struct stmt_block : stmt { std::vector children; @@ -80,14 +99,21 @@ struct stmt_while : stmt { expr_ptr cond; stmt_ptr body; - stmt_while(expr_ptr c, stmt_ptr b) - : cond(std::move(c)), body(std::move(b)) {} + stmt_while(expr_ptr c, stmt_ptr b) : + cond(std::move(c)), body(std::move(b)) {} }; struct stmt_break : stmt { }; +struct stmt_expr : stmt { + expr_ptr child; + + stmt_expr(expr_ptr c) : + child(std::move(c)) {} +}; + template stmt_ptr make_stmt(Ts&& ... ts) { return stmt_ptr(new T(std::move(ts)...));