Add functions parsing

This commit is contained in:
augustin64 2023-12-27 18:43:56 +01:00
parent 0759050fef
commit 91b398dbe9
6 changed files with 194 additions and 3 deletions

View File

@ -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();

View File

@ -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";

View File

@ -22,6 +22,7 @@ enum class ErrorType {
InvalidSyntax,
ExceptedLParen,
ExpectedRParen,
ExpectedLCurlyBracket,
ExpectedRCurlyBracket,
ExpectedSemicolon,
DependentDeclaration,

View File

@ -78,6 +78,13 @@ ParseReturn parse_val(vector<Token> tokens);
*/
ParseReturn parse_par_identifier(vector<Token> 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<Token> tokens);
/**
* Prints a tree for debugging it
*/

View File

@ -63,11 +63,16 @@ Statement ->
| For (Expr | ExprStatement; Expr; Expr) Instruction
| Continue ;
| Break ;
| Return ; | Return Expr ;
| Type ParIdentifier ( Args ) ;
| Type ParIdentifier ( Args ) { Prog }
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;

View File

@ -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<InnerNode>(node)) {
@ -177,6 +178,32 @@ ParseReturn parse_statement(vector<Token> tokens) {
.tokens=tokens
};
}
case TokenType::Return: {
CodePosition pos = tokens.back().pos;
tokens.pop_back();
vector<Node> 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<Token> 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<Token>(ret.node))
throw ParseException(); // The parsing is incorrect
Token identifier = get<Token>(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<Token> tokens) {
};
}
ParseReturn parse_args(vector<Token> tokens) {
vector<Node> 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<Token>(ret.node))
throw ParseException(); // The parsing is incorrect
Token identifier = get<Token>(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<Token> tokens) {
if (tokens.size() == 0)
throw ParseException();
@ -769,6 +914,30 @@ ParseReturn parse_val(vector<Token> 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);