diff --git a/src/analysis.cpp b/src/analysis.cpp index e92fd39..1871c3d 100644 --- a/src/analysis.cpp +++ b/src/analysis.cpp @@ -264,6 +264,8 @@ AnalysisResult analyze(Node &ast, Memory &memory) { analyze(node.children[0], memory); return analyze(node.children[1], memory); } + default: + return {}; } } throw exception(); diff --git a/src/errors.cpp b/src/errors.cpp index 160dd7c..b1ffbc1 100644 --- a/src/errors.cpp +++ b/src/errors.cpp @@ -16,6 +16,7 @@ string UserError::get_message(void) const { case ErrorType::InvalidSyntax: return "Invalid syntax"; case ErrorType::ExceptedLParen: return "Expected '("; case ErrorType::ExpectedRParen: return "Expected ')'"; + case ErrorType::ExpectedLCurlyBracket: return "Expected '{'"; case ErrorType::ExpectedRCurlyBracket: return "Expected '}'"; case ErrorType::ExpectedSemicolon: return "Expected ';'"; case ErrorType::DependentDeclaration: return "A dependant statement may not be a declaration"; diff --git a/src/include/errors.h b/src/include/errors.h index 7d05ffc..df1dd26 100644 --- a/src/include/errors.h +++ b/src/include/errors.h @@ -22,6 +22,7 @@ enum class ErrorType { InvalidSyntax, ExceptedLParen, ExpectedRParen, + ExpectedLCurlyBracket, ExpectedRCurlyBracket, ExpectedSemicolon, DependentDeclaration, diff --git a/src/include/parser.h b/src/include/parser.h index fb10586..38b2cbf 100644 --- a/src/include/parser.h +++ b/src/include/parser.h @@ -78,6 +78,13 @@ ParseReturn parse_val(vector tokens); */ ParseReturn parse_par_identifier(vector tokens); +/** + * Parse the arguments of a function + * Type1 Identifier1, Type2 Identifier2 + * and returns it as a node with Declaration as children +*/ +ParseReturn parse_args(vector tokens); + /** * Prints a tree for debugging it */ diff --git a/src/include/types.h b/src/include/types.h index f65476f..84a934c 100644 --- a/src/include/types.h +++ b/src/include/types.h @@ -63,11 +63,16 @@ Statement -> | For (Expr | ExprStatement; Expr; Expr) Instruction | Continue ; | Break ; + | Return ; | Return Expr ; + | Type ParIdentifier ( Args ) ; + | Type ParIdentifier ( Args ) { Prog } -ExprStatement -> +ExprStatement -> | Type ParIdentifier = Expr // AssignedDeclaration | Type ParIdentifier // Declaration +Args -> Type ParIdentifier, Args | Type ParIdentifier | void + Expr -> Comp, Expr | Comp @@ -111,6 +116,7 @@ Val -> | ParIdentifier // This makes the grammar ambiguous but simpler to parse | (Expr) + | ParIdentifier ( Expr ) // FunctionCall ParIdentifier -> | Identifier @@ -152,7 +158,12 @@ enum class NodeType { Neq, // -> Sum != Comp Land, // -> Sum && Comp Lor, // -> Sum || Comp - Comma // -> Comp, Expr + Comma, // -> Comp, Expr + FunctionPrototype, // -> Type ParIdentifier ( Args ) ; + FunctionDeclaration, // -> Type ParIdentifier ( Args ) { Prog } + FunctionCall, // -> ParIdentifier ( Expr ) + FunctionArgs, // -> Type ParIdentifier, Args | Type ParIdentifier | void + Return, // -> Return ; | Return Expr ; }; struct InnerNode; diff --git a/src/parser.cpp b/src/parser.cpp index 2def335..ea14877 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -17,7 +17,8 @@ CodePosition null_pos = { const char* _debug_ast_node_names[] = { "Prog", "Epsilon", "AssignedDeclaration", "Declaration", "Plus", "Minus", "Mult", "Div", "Mod", "UnaryMinus", "UnaryPlus", "Neg", "Assignment", "LIncr", "RIncr", "LDecr", "RDecr", "If", "IfElse", - "For", "While", "Bloc", "Lt", "Gt", "Leq", "Geq", "Eq", "Neq", "Land", "Lor", "Comma" + "For", "While", "Bloc", "Lt", "Gt", "Leq", "Geq", "Eq", "Neq", "Land", "Lor", "Comma", + "FunctionPrototype", "FunctionDeclaration", "FunctionCall", "FunctionArgs", "Return" }; void _debug_print_tree(const Node& node, int depth, const string& prefix) { if (holds_alternative(node)) { @@ -177,6 +178,32 @@ ParseReturn parse_statement(vector tokens) { .tokens=tokens }; } + case TokenType::Return: { + CodePosition pos = tokens.back().pos; + tokens.pop_back(); + + vector children; + if (tokens.back().type != TokenType::Semicolon) { + ParseReturn ret = parse_expr(tokens); + tokens = ret.tokens; + + if (tokens.back().type != TokenType::Semicolon) + throw SyntaxError(ErrorType::ExpectedSemicolon, tokens.back().pos); + + children = {ret.node}; + } + + tokens.pop_back(); + InnerNode node = { + .type=NodeType::Return, + .children=children, + .pos=pos + }; + return { + .node=node, + .tokens=tokens + }; + } case TokenType::While: case TokenType::If: { CodePosition pos = tokens.back().pos; @@ -374,7 +401,79 @@ ParseReturn parse_statement(vector tokens) { .node=node, .tokens=tokens }; + } + case TokenType::Identifier: { + //* Type + Token type = tokens.back(); + tokens.pop_back(); + //* ParIdentifier + ParseReturn ret = parse_par_identifier(tokens); + tokens = ret.tokens; + + if (!holds_alternative(ret.node)) + throw ParseException(); // The parsing is incorrect + + Token identifier = get(ret.node); + + // LPar + if (tokens.size() < 1 || tokens.back().type != TokenType::LParenthese) + throw ParseException(); + + tokens.pop_back(); + + //* Args + ParseReturn args_ret = parse_args(tokens); + + // RPar + if (args_ret.tokens.size() < 1 || args_ret.tokens.back().type != TokenType::RParenthese) + throw SyntaxError(ErrorType::ExpectedRParen, tokens.back().pos, {}); + + tokens = args_ret.tokens; + tokens.pop_back(); + + if (tokens.size() < 1) + throw SyntaxError(ErrorType::ExpectedSemicolon, identifier.pos, {}); + + + if (tokens.back().type == TokenType::Semicolon) { //* -> Type ParIdentifier ( Args ) ; + tokens.pop_back(); + + InnerNode node = { + .type=NodeType::FunctionPrototype, + .children={type, identifier, args_ret.node}, + .pos=identifier.pos + }; + return { + .node=node, + .tokens=tokens + }; + } + + //* LCurly + if (tokens.size() < 1 || tokens.back().type != TokenType::LCurlyBracket) + throw SyntaxError(ErrorType::ExpectedLCurlyBracket, identifier.pos, {}); + + tokens.pop_back(); + + ParseReturn ret_prog = parse_prog(tokens); + tokens = ret_prog.tokens; + + //* RCurly + if (tokens.size() < 1 || tokens.back().type != TokenType::RCurlyBracket) + throw SyntaxError(ErrorType::ExpectedRCurlyBracket, identifier.pos, {}); + + tokens.pop_back(); + + InnerNode node = { + .type=NodeType::FunctionDeclaration, + .children={type, identifier, args_ret.node, ret_prog.node}, + .pos=identifier.pos + }; + return { + .node=node, + .tokens=tokens + }; } default: throw ParseException(); @@ -467,6 +566,52 @@ ParseReturn parse_expr(vector tokens) { }; } +ParseReturn parse_args(vector tokens) { + vector nodes; + CodePosition pos = tokens.back().pos; + + while (tokens.size() != 0 && tokens.back().type != TokenType::RParenthese) { + if (tokens.back().type != TokenType::Identifier) + throw ParseException(); + + Token type = tokens.back(); + tokens.pop_back(); + + // TODO: if type is void, return + + ParseReturn ret = parse_par_identifier(tokens); + tokens = ret.tokens; + + if (!holds_alternative(ret.node)) + throw ParseException(); // The parsing is incorrect + + Token identifier = get(ret.node); + + InnerNode node = { + .type=NodeType::Declaration, + .children={type, identifier}, + .pos=identifier.pos + }; + nodes.push_back(node); + + if (tokens.back().type == TokenType::Comma) { + tokens.pop_back(); + } else { + break; + } + } + + InnerNode node = { + .type=NodeType::FunctionArgs, + .children=nodes, + .pos=pos + }; + return { + .node=node, + .tokens=tokens + }; +} + ParseReturn parse_comp(vector tokens) { if (tokens.size() == 0) throw ParseException(); @@ -769,6 +914,30 @@ ParseReturn parse_val(vector tokens) { .tokens=ret.tokens }; } + case TokenType::LParenthese: { + ret.tokens.pop_back(); + + ParseReturn ret_expr = parse_expr(ret.tokens); + + if (ret_expr.tokens.size() < 1 || ret_expr.tokens.back().type != TokenType::RParenthese) + throw SyntaxError( + ErrorType::ExpectedRParen, + ret_expr.tokens.size() < 1 ? ret.tokens.back().pos : ret_expr.tokens.back().pos, + {} + ); + + ret_expr.tokens.pop_back(); + + InnerNode node = { + .type = NodeType::FunctionCall, + .children = { ret.node, ret_expr.node }, + .pos=get_node_pos(ret.node) + }; + return { + .node=node, + .tokens=ret_expr.tokens + }; + } case TokenType::Equal: { //* Val -> ParIdentifier = (Expr) ret.tokens.pop_back(); ParseReturn ret_expr = parse_expr(ret.tokens);