From: Wolfgang (Blub) Bumiller Date: Sat, 11 Aug 2012 09:17:46 +0000 (+0200) Subject: handling if/else, shunting yard now leaves unmatched closing paren-tokens on the... X-Git-Tag: 0.1-rc1~354 X-Git-Url: https://git.rm.cloudns.org/?a=commitdiff_plain;h=ce082551d8538fea703968d23d68b805ee530132;p=xonotic%2Fgmqcc.git handling if/else, shunting yard now leaves unmatched closing paren-tokens on the parser for this purpose --- diff --git a/lexer.c b/lexer.c index bfa7443..fe9eb0f 100644 --- a/lexer.c +++ b/lexer.c @@ -623,6 +623,8 @@ int lex_do(lex_file *lex) } else if (!strcmp(v, "for") || !strcmp(v, "while") || !strcmp(v, "do") || + !strcmp(v, "if") || + !strcmp(v, "else") || !strcmp(v, "var") || !strcmp(v, "return") || !strcmp(v, "const")) diff --git a/parser.c b/parser.c index 3d7ab0d..94486d6 100644 --- a/parser.c +++ b/parser.c @@ -572,6 +572,11 @@ static ast_expression* parser_expression(parser_t *parser) shunt sy; bool wantop = false; + /* count the parens because an if starts with one, so the + * end of a condition is an unmatched closing paren + */ + int parens = 0; + MEM_VECTOR_INIT(&sy, out); MEM_VECTOR_INIT(&sy, ops); @@ -630,6 +635,7 @@ static ast_expression* parser_expression(parser_t *parser) } } else if (parser->tok == '(') { + ++parens; nextwant = false; /* not expecting an operator next */ if (!shunt_ops_add(&sy, syparen(parser_ctx(parser), 1, 0))) { parseerror(parser, "out of memory"); @@ -637,6 +643,9 @@ static ast_expression* parser_expression(parser_t *parser) } } else if (parser->tok == ')') { + --parens; + if (parens < 0) + break; /* allowed for function calls */ if (!parser_close_paren(parser, &sy, true)) goto onerr; @@ -650,6 +659,7 @@ static ast_expression* parser_expression(parser_t *parser) parser->lex->flags.noops = !wantop; } else { if (parser->tok == '(') { + ++parens; /* we expected an operator, this is the function-call operator */ if (!shunt_ops_add(&sy, syparen(parser_ctx(parser), 'f', sy.out_count-1))) { parseerror(parser, "out of memory"); @@ -657,6 +667,9 @@ static ast_expression* parser_expression(parser_t *parser) } } else if (parser->tok == ')') { + --parens; + if (parens < 0) + break; /* we do expect an operator next */ /* closing an opening paren */ if (!parser_close_paren(parser, &sy, false)) @@ -713,7 +726,7 @@ static ast_expression* parser_expression(parser_t *parser) break; } } - if (!parser_next(parser)) { + if (parens >= 0 && !parser_next(parser)) { parseerror(parser, "Unexpected end of file"); goto onerr; } @@ -742,6 +755,7 @@ onerr: static bool parser_variable(parser_t *parser, ast_block *localblock); static ast_block* parser_parse_block(parser_t *parser); +static ast_expression* parser_parse_statement_or_block(parser_t *parser); static bool parser_parse_statement(parser_t *parser, ast_block *block, ast_expression **out) { if (parser->tok == TOKEN_TYPENAME) @@ -793,6 +807,65 @@ static bool parser_parse_statement(parser_t *parser, ast_block *block, ast_expre } return true; } + else if (!strcmp(parser_tokval(parser), "if")) + { + ast_ifthen *ifthen; + ast_expression *cond, *ontrue, *onfalse = NULL; + + lex_ctx ctx = parser_ctx(parser); + + /* skip the 'if' and check for opening paren */ + if (!parser_next(parser) || parser->tok != '(') { + parseerror(parser, "expected 'if' condition in parenthesis"); + return false; + } + /* parse into the expression */ + if (!parser_next(parser)) { + parseerror(parser, "expected 'if' condition after opening paren"); + return false; + } + /* parse the condition */ + cond = parser_expression(parser); + if (!cond) + return false; + /* closing paren */ + if (parser->tok != ')') { + parseerror(parser, "expected closing paren after 'if' condition"); + ast_delete(cond); + return false; + } + /* parse into the 'then' branch */ + if (!parser_next(parser)) { + parseerror(parser, "expected statement for on-true branch of 'if'"); + ast_delete(cond); + return false; + } + ontrue = parser_parse_statement_or_block(parser); + if (!ontrue) { + ast_delete(cond); + return false; + } + /* check for an else */ + if (!strcmp(parser_tokval(parser), "else")) { + /* parse into the 'else' branch */ + if (!parser_next(parser)) { + parseerror(parser, "expected on-false branch after 'else'"); + ast_delete(ontrue); + ast_delete(cond); + return false; + } + onfalse = parser_parse_statement_or_block(parser); + if (!onfalse) { + ast_delete(ontrue); + ast_delete(cond); + return false; + } + } + + ifthen = ast_ifthen_new(ctx, cond, ontrue, onfalse); + *out = (ast_expression*)ifthen; + return true; + } parseerror(parser, "Unexpected keyword"); return false; }