mirror of
https://github.com/DarkPlacesEngine/gmqcc.git
synced 2025-01-18 14:21:36 +00:00
handling if/else, shunting yard now leaves unmatched closing paren-tokens on the parser for this purpose
This commit is contained in:
parent
3e4f490a59
commit
ce082551d8
2 changed files with 76 additions and 1 deletions
2
lexer.c
2
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"))
|
||||
|
|
75
parser.c
75
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;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue