mirror of
https://github.com/DarkPlacesEngine/gmqcc.git
synced 2025-01-18 22:31: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") ||
|
} else if (!strcmp(v, "for") ||
|
||||||
!strcmp(v, "while") ||
|
!strcmp(v, "while") ||
|
||||||
!strcmp(v, "do") ||
|
!strcmp(v, "do") ||
|
||||||
|
!strcmp(v, "if") ||
|
||||||
|
!strcmp(v, "else") ||
|
||||||
!strcmp(v, "var") ||
|
!strcmp(v, "var") ||
|
||||||
!strcmp(v, "return") ||
|
!strcmp(v, "return") ||
|
||||||
!strcmp(v, "const"))
|
!strcmp(v, "const"))
|
||||||
|
|
75
parser.c
75
parser.c
|
@ -572,6 +572,11 @@ static ast_expression* parser_expression(parser_t *parser)
|
||||||
shunt sy;
|
shunt sy;
|
||||||
bool wantop = false;
|
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, out);
|
||||||
MEM_VECTOR_INIT(&sy, ops);
|
MEM_VECTOR_INIT(&sy, ops);
|
||||||
|
|
||||||
|
@ -630,6 +635,7 @@ static ast_expression* parser_expression(parser_t *parser)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (parser->tok == '(') {
|
else if (parser->tok == '(') {
|
||||||
|
++parens;
|
||||||
nextwant = false; /* not expecting an operator next */
|
nextwant = false; /* not expecting an operator next */
|
||||||
if (!shunt_ops_add(&sy, syparen(parser_ctx(parser), 1, 0))) {
|
if (!shunt_ops_add(&sy, syparen(parser_ctx(parser), 1, 0))) {
|
||||||
parseerror(parser, "out of memory");
|
parseerror(parser, "out of memory");
|
||||||
|
@ -637,6 +643,9 @@ static ast_expression* parser_expression(parser_t *parser)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (parser->tok == ')') {
|
else if (parser->tok == ')') {
|
||||||
|
--parens;
|
||||||
|
if (parens < 0)
|
||||||
|
break;
|
||||||
/* allowed for function calls */
|
/* allowed for function calls */
|
||||||
if (!parser_close_paren(parser, &sy, true))
|
if (!parser_close_paren(parser, &sy, true))
|
||||||
goto onerr;
|
goto onerr;
|
||||||
|
@ -650,6 +659,7 @@ static ast_expression* parser_expression(parser_t *parser)
|
||||||
parser->lex->flags.noops = !wantop;
|
parser->lex->flags.noops = !wantop;
|
||||||
} else {
|
} else {
|
||||||
if (parser->tok == '(') {
|
if (parser->tok == '(') {
|
||||||
|
++parens;
|
||||||
/* we expected an operator, this is the function-call operator */
|
/* we expected an operator, this is the function-call operator */
|
||||||
if (!shunt_ops_add(&sy, syparen(parser_ctx(parser), 'f', sy.out_count-1))) {
|
if (!shunt_ops_add(&sy, syparen(parser_ctx(parser), 'f', sy.out_count-1))) {
|
||||||
parseerror(parser, "out of memory");
|
parseerror(parser, "out of memory");
|
||||||
|
@ -657,6 +667,9 @@ static ast_expression* parser_expression(parser_t *parser)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (parser->tok == ')') {
|
else if (parser->tok == ')') {
|
||||||
|
--parens;
|
||||||
|
if (parens < 0)
|
||||||
|
break;
|
||||||
/* we do expect an operator next */
|
/* we do expect an operator next */
|
||||||
/* closing an opening paren */
|
/* closing an opening paren */
|
||||||
if (!parser_close_paren(parser, &sy, false))
|
if (!parser_close_paren(parser, &sy, false))
|
||||||
|
@ -713,7 +726,7 @@ static ast_expression* parser_expression(parser_t *parser)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!parser_next(parser)) {
|
if (parens >= 0 && !parser_next(parser)) {
|
||||||
parseerror(parser, "Unexpected end of file");
|
parseerror(parser, "Unexpected end of file");
|
||||||
goto onerr;
|
goto onerr;
|
||||||
}
|
}
|
||||||
|
@ -742,6 +755,7 @@ onerr:
|
||||||
|
|
||||||
static bool parser_variable(parser_t *parser, ast_block *localblock);
|
static bool parser_variable(parser_t *parser, ast_block *localblock);
|
||||||
static ast_block* parser_parse_block(parser_t *parser);
|
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)
|
static bool parser_parse_statement(parser_t *parser, ast_block *block, ast_expression **out)
|
||||||
{
|
{
|
||||||
if (parser->tok == TOKEN_TYPENAME)
|
if (parser->tok == TOKEN_TYPENAME)
|
||||||
|
@ -793,6 +807,65 @@ static bool parser_parse_statement(parser_t *parser, ast_block *block, ast_expre
|
||||||
}
|
}
|
||||||
return true;
|
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");
|
parseerror(parser, "Unexpected keyword");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue