Parser: Add while & for

This commit is contained in:
augustin64 2023-12-01 14:27:48 +01:00
parent 5925582de8
commit a693258d77
2 changed files with 79 additions and 3 deletions

View File

@ -36,6 +36,8 @@ Statement ->
| { Prog } | { Prog }
| If (Expr) Instruction | If (Expr) Instruction
| If (Expr) Instruction Else Instruction | If (Expr) Instruction Else Instruction
| While (Expr) Instruction
| For (Expr | ExprStatement; Expr; Expr) Instruction
ExprStatement -> ExprStatement ->
| Type ParIdentifier = Expr // AssignedDeclaration | Type ParIdentifier = Expr // AssignedDeclaration
@ -114,6 +116,8 @@ enum class NodeType {
RDecr, // -> ParIdentifier-- RDecr, // -> ParIdentifier--
If, // -> If (Expr) Instruction If, // -> If (Expr) Instruction
IfElse, // -> If (Expr) Instruction Else Instruction IfElse, // -> If (Expr) Instruction Else Instruction
For, // -> For (Expr) Instruction
While, // -> While (Expr/ ExprStatement; Expr; Expr) Instruction
Bloc, // -> { Prog } Bloc, // -> { Prog }
Lt, // -> Sum < Comp Lt, // -> Sum < Comp
Gt, // -> Sum > Comp Gt, // -> Sum > Comp

View File

@ -16,7 +16,7 @@ CodePosition null_pos = {
const char* _node_names[] = { const char* _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",
"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) { void _debug_print_tree(const Node& node, int depth, const string& prefix) {
if (holds_alternative<InnerNode>(node)) { if (holds_alternative<InnerNode>(node)) {
@ -168,13 +168,26 @@ ParseReturn parse_instruction(vector<Token> tokens) {
} }
ParseReturn parse_statement(vector<Token> tokens) { ParseReturn parse_statement(vector<Token> tokens) {
if (tokens.size() < 2) // 'If' / 'For' '(' at least if (tokens.size() < 2)
throw ParseException(); throw ParseException();
switch (tokens.back().type) { switch (tokens.back().type) {
case TokenType::While:
case TokenType::If: { case TokenType::If: {
CodePosition pos = tokens.back().pos; 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(); tokens.pop_back();
if (tokens.back().type != TokenType::LParenthese) // Opening ( if (tokens.back().type != TokenType::LParenthese) // Opening (
throw SyntaxError("Missing '('", tokens.back().pos); throw SyntaxError("Missing '('", tokens.back().pos);
@ -215,7 +228,7 @@ ParseReturn parse_statement(vector<Token> tokens) {
if (tokens.size() == 0 || tokens.back().type != TokenType::Else) { //* -> If (Expr) Instruction if (tokens.size() == 0 || tokens.back().type != TokenType::Else) { //* -> If (Expr) Instruction
InnerNode node = { InnerNode node = {
.type=NodeType::If, .type=type,
.children={expr, instruction1}, .children={expr, instruction1},
.pos=pos .pos=pos
}; };
@ -240,6 +253,65 @@ ParseReturn parse_statement(vector<Token> tokens) {
.tokens=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: { case TokenType::LCurlyBracket: {
CodePosition pos = tokens.back().pos; CodePosition pos = tokens.back().pos;
tokens.pop_back(); tokens.pop_back();