]> git.xonotic.org Git - xonotic/gmqcc.git/commitdiff
handling if/else, shunting yard now leaves unmatched closing paren-tokens on the...
authorWolfgang (Blub) Bumiller <blub@speed.at>
Sat, 11 Aug 2012 09:17:46 +0000 (11:17 +0200)
committerWolfgang (Blub) Bumiller <blub@speed.at>
Sat, 11 Aug 2012 09:17:46 +0000 (11:17 +0200)
lexer.c
parser.c

diff --git a/lexer.c b/lexer.c
index bfa7443f3eb09fa13e1b104e33f67562a84f7b88..fe9eb0f089e35ee67a16a40af3700b7a099dd298 100644 (file)
--- 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"))
index 3d7ab0d02db5854c3b4db6e96c09b87589987e19..94486d62fb38cc648f258f398bae7ad7bb6eb016 100644 (file)
--- 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;
     }