Add functions parsing
This commit is contained in:
parent
0759050fef
commit
91b398dbe9
@ -264,6 +264,8 @@ AnalysisResult analyze(Node &ast, Memory &memory) {
|
|||||||
analyze(node.children[0], memory);
|
analyze(node.children[0], memory);
|
||||||
return analyze(node.children[1], memory);
|
return analyze(node.children[1], memory);
|
||||||
}
|
}
|
||||||
|
default:
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
throw exception();
|
throw exception();
|
||||||
|
@ -16,6 +16,7 @@ string UserError::get_message(void) const {
|
|||||||
case ErrorType::InvalidSyntax: return "Invalid syntax";
|
case ErrorType::InvalidSyntax: return "Invalid syntax";
|
||||||
case ErrorType::ExceptedLParen: return "Expected '(";
|
case ErrorType::ExceptedLParen: return "Expected '(";
|
||||||
case ErrorType::ExpectedRParen: return "Expected ')'";
|
case ErrorType::ExpectedRParen: return "Expected ')'";
|
||||||
|
case ErrorType::ExpectedLCurlyBracket: return "Expected '{'";
|
||||||
case ErrorType::ExpectedRCurlyBracket: return "Expected '}'";
|
case ErrorType::ExpectedRCurlyBracket: return "Expected '}'";
|
||||||
case ErrorType::ExpectedSemicolon: return "Expected ';'";
|
case ErrorType::ExpectedSemicolon: return "Expected ';'";
|
||||||
case ErrorType::DependentDeclaration: return "A dependant statement may not be a declaration";
|
case ErrorType::DependentDeclaration: return "A dependant statement may not be a declaration";
|
||||||
|
@ -22,6 +22,7 @@ enum class ErrorType {
|
|||||||
InvalidSyntax,
|
InvalidSyntax,
|
||||||
ExceptedLParen,
|
ExceptedLParen,
|
||||||
ExpectedRParen,
|
ExpectedRParen,
|
||||||
|
ExpectedLCurlyBracket,
|
||||||
ExpectedRCurlyBracket,
|
ExpectedRCurlyBracket,
|
||||||
ExpectedSemicolon,
|
ExpectedSemicolon,
|
||||||
DependentDeclaration,
|
DependentDeclaration,
|
||||||
|
@ -78,6 +78,13 @@ ParseReturn parse_val(vector<Token> tokens);
|
|||||||
*/
|
*/
|
||||||
ParseReturn parse_par_identifier(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
|
* Prints a tree for debugging it
|
||||||
*/
|
*/
|
||||||
|
@ -63,11 +63,16 @@ Statement ->
|
|||||||
| For (Expr | ExprStatement; Expr; Expr) Instruction
|
| For (Expr | ExprStatement; Expr; Expr) Instruction
|
||||||
| Continue ;
|
| Continue ;
|
||||||
| Break ;
|
| Break ;
|
||||||
|
| Return ; | Return Expr ;
|
||||||
|
| Type ParIdentifier ( Args ) ;
|
||||||
|
| Type ParIdentifier ( Args ) { Prog }
|
||||||
|
|
||||||
ExprStatement ->
|
ExprStatement ->
|
||||||
| Type ParIdentifier = Expr // AssignedDeclaration
|
| Type ParIdentifier = Expr // AssignedDeclaration
|
||||||
| Type ParIdentifier // Declaration
|
| Type ParIdentifier // Declaration
|
||||||
|
|
||||||
|
Args -> Type ParIdentifier, Args | Type ParIdentifier | void
|
||||||
|
|
||||||
|
|
||||||
Expr -> Comp, Expr | Comp
|
Expr -> Comp, Expr | Comp
|
||||||
|
|
||||||
@ -111,6 +116,7 @@ Val ->
|
|||||||
| ParIdentifier // This makes the grammar ambiguous but simpler to parse
|
| ParIdentifier // This makes the grammar ambiguous but simpler to parse
|
||||||
|
|
||||||
| (Expr)
|
| (Expr)
|
||||||
|
| ParIdentifier ( Expr ) // FunctionCall
|
||||||
|
|
||||||
ParIdentifier ->
|
ParIdentifier ->
|
||||||
| Identifier
|
| Identifier
|
||||||
@ -152,7 +158,12 @@ enum class NodeType {
|
|||||||
Neq, // -> Sum != Comp
|
Neq, // -> Sum != Comp
|
||||||
Land, // -> Sum && Comp
|
Land, // -> Sum && Comp
|
||||||
Lor, // -> 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;
|
struct InnerNode;
|
||||||
|
171
src/parser.cpp
171
src/parser.cpp
@ -17,7 +17,8 @@ CodePosition null_pos = {
|
|||||||
const char* _debug_ast_node_names[] = {
|
const char* _debug_ast_node_names[] = {
|
||||||
"Prog", "Epsilon", "AssignedDeclaration", "Declaration", "Plus", "Minus", "Mult", "Div", "Mod",
|
"Prog", "Epsilon", "AssignedDeclaration", "Declaration", "Plus", "Minus", "Mult", "Div", "Mod",
|
||||||
"UnaryMinus", "UnaryPlus", "Neg", "Assignment", "LIncr", "RIncr", "LDecr", "RDecr", "If", "IfElse",
|
"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) {
|
void _debug_print_tree(const Node& node, int depth, const string& prefix) {
|
||||||
if (holds_alternative<InnerNode>(node)) {
|
if (holds_alternative<InnerNode>(node)) {
|
||||||
@ -177,6 +178,32 @@ ParseReturn parse_statement(vector<Token> tokens) {
|
|||||||
.tokens=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::While:
|
||||||
case TokenType::If: {
|
case TokenType::If: {
|
||||||
CodePosition pos = tokens.back().pos;
|
CodePosition pos = tokens.back().pos;
|
||||||
@ -374,7 +401,79 @@ ParseReturn parse_statement(vector<Token> tokens) {
|
|||||||
.node=node,
|
.node=node,
|
||||||
.tokens=tokens
|
.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:
|
default:
|
||||||
throw ParseException();
|
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) {
|
ParseReturn parse_comp(vector<Token> tokens) {
|
||||||
if (tokens.size() == 0)
|
if (tokens.size() == 0)
|
||||||
throw ParseException();
|
throw ParseException();
|
||||||
@ -769,6 +914,30 @@ ParseReturn parse_val(vector<Token> tokens) {
|
|||||||
.tokens=ret.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)
|
case TokenType::Equal: { //* Val -> ParIdentifier = (Expr)
|
||||||
ret.tokens.pop_back();
|
ret.tokens.pop_back();
|
||||||
ParseReturn ret_expr = parse_expr(ret.tokens);
|
ParseReturn ret_expr = parse_expr(ret.tokens);
|
||||||
|
Loading…
Reference in New Issue
Block a user