From a693258d77ff7993b4b227853f97ff7af4b3644b Mon Sep 17 00:00:00 2001 From: augustin64 Date: Fri, 1 Dec 2023 14:27:48 +0100 Subject: [PATCH] Parser: Add while & for --- src/include/types.h | 4 +++ src/parser.cpp | 78 +++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 79 insertions(+), 3 deletions(-) diff --git a/src/include/types.h b/src/include/types.h index 8e4db0c..aa27909 100644 --- a/src/include/types.h +++ b/src/include/types.h @@ -36,6 +36,8 @@ Statement -> | { Prog } | If (Expr) Instruction | If (Expr) Instruction Else Instruction + | While (Expr) Instruction + | For (Expr | ExprStatement; Expr; Expr) Instruction ExprStatement -> | Type ParIdentifier = Expr // AssignedDeclaration @@ -114,6 +116,8 @@ enum class NodeType { RDecr, // -> ParIdentifier-- If, // -> If (Expr) Instruction IfElse, // -> If (Expr) Instruction Else Instruction + For, // -> For (Expr) Instruction + While, // -> While (Expr/ ExprStatement; Expr; Expr) Instruction Bloc, // -> { Prog } Lt, // -> Sum < Comp Gt, // -> Sum > Comp diff --git a/src/parser.cpp b/src/parser.cpp index 3e26f58..512f4dc 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -16,7 +16,7 @@ CodePosition null_pos = { const char* _node_names[] = { "Prog", "Epsilon", "AssignedDeclaration", "Declaration", "Plus", "Minus", "Mult", "Div", "Mod", "UnaryMinus", "UnaryPlus", "Neg", "Assignment", "LIncr", "RIncr", "LDecr", "RDecr", "If", "IfElse", - "Bloc", "Lt", "Gt", "Leq", "Geq", "Eq", "Neq", "Land", "Lor" + "For", "While", "Bloc", "Lt", "Gt", "Leq", "Geq", "Eq", "Neq", "Land", "Lor" }; void _debug_print_tree(const Node& node, int depth, const string& prefix) { if (holds_alternative(node)) { @@ -168,13 +168,26 @@ ParseReturn parse_instruction(vector tokens) { } ParseReturn parse_statement(vector tokens) { - if (tokens.size() < 2) // 'If' / 'For' '(' at least + if (tokens.size() < 2) throw ParseException(); switch (tokens.back().type) { + case TokenType::While: case TokenType::If: { CodePosition pos = tokens.back().pos; + NodeType type; + switch (tokens.back().type) { + case TokenType::If: + type = NodeType::If; + break; + case TokenType::While: + type = NodeType::While; + break; + default: + break; // Impossible + } + tokens.pop_back(); if (tokens.back().type != TokenType::LParenthese) // Opening ( throw SyntaxError("Missing '('", tokens.back().pos); @@ -215,7 +228,7 @@ ParseReturn parse_statement(vector tokens) { if (tokens.size() == 0 || tokens.back().type != TokenType::Else) { //* -> If (Expr) Instruction InnerNode node = { - .type=NodeType::If, + .type=type, .children={expr, instruction1}, .pos=pos }; @@ -240,6 +253,65 @@ ParseReturn parse_statement(vector tokens) { .tokens=tokens }; } + case TokenType::For: { + CodePosition pos = tokens.back().pos; + tokens.pop_back(); + + if (tokens.back().type != TokenType::LParenthese) // Opening ( + throw SyntaxError("Missing '('", tokens.back().pos); + tokens.pop_back(); + + ParseReturn ret1; + try { + ret1 = parse_expr_statement(tokens); + } catch (const ParseException& pex) { + ret1 = parse_expr(tokens); + } + + int nb_tok = ret1.tokens.size(); // First ; + if (nb_tok == 0 || ret1.tokens.back().type != TokenType::Semicolon) + throw SyntaxError( + "Expected ';'", + nb_tok == 0 ? tokens.back().pos : ret1.tokens.back().pos + ); + tokens = ret1.tokens; + tokens.pop_back(); + + ParseReturn ret2 = parse_expr(tokens); + + nb_tok = ret2.tokens.size(); // Second ; + if (nb_tok == 0 || ret2.tokens.back().type != TokenType::Semicolon) + throw SyntaxError( + "Expected ';'", + nb_tok == 0 ? tokens.back().pos : ret2.tokens.back().pos + ); + tokens = ret2.tokens; + tokens.pop_back(); + + ParseReturn ret3 = parse_expr(tokens); + + nb_tok = ret3.tokens.size(); // Closing ) + if (nb_tok == 0 || ret3.tokens.back().type != TokenType::RParenthese) + throw SyntaxError( + "Missing ')'", + nb_tok == 0 ? tokens.back().pos : ret3.tokens.back().pos + ); + tokens = ret3.tokens; + tokens.pop_back(); + + ParseReturn ret_instruction = parse_instruction(tokens); + tokens = ret_instruction.tokens; + + InnerNode node = { + .type=NodeType::For, + .children={ret1.node, ret2.node, ret3.node, ret_instruction.node}, + .pos=pos + }; + return { + .node=node, + .tokens=tokens + }; + } case TokenType::LCurlyBracket: { CodePosition pos = tokens.back().pos; tokens.pop_back();