]> de.git.xonotic.org Git - xonotic/gmqcc.git/blobdiff - parser.c
manpage: -Wreserved-names, -funtyped-nil, -fpermissive
[xonotic/gmqcc.git] / parser.c
index 23a3ed6fc7bae059e7ac69dc696a70b936f2ba7d..a47c6ad3b978d78a0a91b1b598e913f654a94c5f 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -51,6 +51,7 @@ typedef struct {
     ast_value *imm_float_zero;
     ast_value *imm_float_one;
     ast_value *imm_vector_zero;
+    ast_value *nil;
 
     size_t crc_globals;
     size_t crc_fields;
@@ -62,7 +63,8 @@ typedef struct {
      */
     ast_label  **labels;
     ast_goto   **gotos;
-    const char **loops;
+    const char **breaks;
+    const char **continues;
 
     /* A list of hashtables for each scope */
     ht *variables;
@@ -758,10 +760,11 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy)
             break;
         case opid1('*'):
             if (exprs[0]->expression.vtype != exprs[1]->expression.vtype &&
-                exprs[0]->expression.vtype != TYPE_VECTOR &&
-                exprs[0]->expression.vtype != TYPE_FLOAT &&
-                exprs[1]->expression.vtype != TYPE_VECTOR &&
-                exprs[1]->expression.vtype != TYPE_FLOAT)
+                !(exprs[0]->expression.vtype == TYPE_VECTOR &&
+                  exprs[1]->expression.vtype == TYPE_FLOAT) &&
+                !(exprs[1]->expression.vtype == TYPE_VECTOR &&
+                  exprs[0]->expression.vtype == TYPE_FLOAT)
+                )
             {
                 parseerror(parser, "invalid types used in expression: cannot multiply types %s and %s",
                            type_name[exprs[1]->expression.vtype],
@@ -1012,7 +1015,9 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy)
                     ast_type_to_string(exprs[1], ty2, sizeof(ty2));
                     parseerror(parser, "invalid types in assignment: cannot assign %s to %s", ty2, ty1);
                 }
-                else if (!ast_compare_type(exprs[0], exprs[1])) {
+                else if (exprs[1]->expression.vtype != TYPE_NIL &&
+                         !ast_compare_type(exprs[0], exprs[1]))
+                {
                     ast_type_to_string(exprs[0], ty1, sizeof(ty1));
                     ast_type_to_string(exprs[1], ty2, sizeof(ty2));
                     if (OPTS_FLAG(ASSIGN_FUNCTION_TYPES) &&
@@ -1664,7 +1669,7 @@ static ast_expression* parse_expression_leave(parser_t *parser, bool stopatcomma
             const oper_info *olast = NULL;
             size_t o;
             for (o = 0; o < operator_count; ++o) {
-                if ((!(operators[o].flags & OP_PREFIX) == wantop) &&
+                if (((!(operators[o].flags & OP_PREFIX) == !!wantop)) &&
                     /* !(operators[o].flags & OP_SUFFIX) && / * remove this */
                     !strcmp(parser_tokval(parser), operators[o].op))
                 {
@@ -2054,19 +2059,22 @@ static bool parse_while(parser_t *parser, ast_block *block, ast_expression **out
         return false;
     }
 
-    vec_push(parser->loops, label);
+    vec_push(parser->breaks, label);
+    vec_push(parser->continues, label);
 
     rv = parse_while_go(parser, block, out);
     if (label)
         mem_d(label);
-    if (vec_last(parser->loops) != label) {
+    if (vec_last(parser->breaks) != label || vec_last(parser->continues) != label) {
         parseerror(parser, "internal error: label stack corrupted");
         rv = false;
         ast_delete(*out);
         *out = NULL;
     }
-    else
-        vec_pop(parser->loops);
+    else {
+        vec_pop(parser->breaks);
+        vec_pop(parser->continues);
+    }
     return rv;
 }
 
@@ -2081,11 +2089,6 @@ static bool parse_while_go(parser_t *parser, ast_block *block, ast_expression **
 
     (void)block; /* not touching */
 
-    /* skip the 'while' and check for opening paren */
-    if (!parser_next(parser) || parser->tok != '(') {
-        parseerror(parser, "expected 'while' condition in parenthesis");
-        return false;
-    }
     /* parse into the expression */
     if (!parser_next(parser)) {
         parseerror(parser, "expected 'while' condition after opening paren");
@@ -2152,19 +2155,22 @@ static bool parse_dowhile(parser_t *parser, ast_block *block, ast_expression **o
         }
     }
 
-    vec_push(parser->loops, label);
+    vec_push(parser->breaks, label);
+    vec_push(parser->continues, label);
 
     rv = parse_dowhile_go(parser, block, out);
     if (label)
         mem_d(label);
-    if (vec_last(parser->loops) != label) {
+    if (vec_last(parser->breaks) != label || vec_last(parser->continues) != label) {
         parseerror(parser, "internal error: label stack corrupted");
         rv = false;
         ast_delete(*out);
         *out = NULL;
     }
-    else
-        vec_pop(parser->loops);
+    else {
+        vec_pop(parser->breaks);
+        vec_pop(parser->continues);
+    }
     return rv;
 }
 
@@ -2274,19 +2280,22 @@ static bool parse_for(parser_t *parser, ast_block *block, ast_expression **out)
         return false;
     }
 
-    vec_push(parser->loops, label);
+    vec_push(parser->breaks, label);
+    vec_push(parser->continues, label);
 
     rv = parse_for_go(parser, block, out);
     if (label)
         mem_d(label);
-    if (vec_last(parser->loops) != label) {
+    if (vec_last(parser->breaks) != label || vec_last(parser->continues) != label) {
         parseerror(parser, "internal error: label stack corrupted");
         rv = false;
         ast_delete(*out);
         *out = NULL;
     }
-    else
-        vec_pop(parser->loops);
+    else {
+        vec_pop(parser->breaks);
+        vec_pop(parser->continues);
+    }
     return rv;
 }
 static bool parse_for_go(parser_t *parser, ast_block *block, ast_expression **out)
@@ -2449,9 +2458,10 @@ static bool parse_return(parser_t *parser, ast_block *block, ast_expression **ou
 
 static bool parse_break_continue(parser_t *parser, ast_block *block, ast_expression **out, bool is_continue)
 {
-    size_t i;
+    size_t       i;
     unsigned int levels = 0;
-    lex_ctx ctx = parser_ctx(parser);
+    lex_ctx      ctx = parser_ctx(parser);
+    const char **loops = (is_continue ? parser->continues : parser->breaks);
 
     (void)block; /* not touching */
     if (!parser_next(parser)) {
@@ -2462,9 +2472,9 @@ static bool parse_break_continue(parser_t *parser, ast_block *block, ast_express
     if (parser->tok == TOKEN_IDENT) {
         if (!OPTS_FLAG(LOOP_LABELS))
             parseerror(parser, "labeled loops not activated, try using -floop-labels");
-        i = vec_size(parser->loops);
+        i = vec_size(loops);
         while (i--) {
-            if (parser->loops[i] && !strcmp(parser->loops[i], parser_tokval(parser)))
+            if (loops[i] && !strcmp(loops[i], parser_tokval(parser)))
                 break;
             if (!i) {
                 parseerror(parser, "no such loop to %s: `%s`",
@@ -2577,7 +2587,59 @@ onerr:
     return true;
 }
 
+static bool parse_switch_go(parser_t *parser, ast_block *block, ast_expression **out);
 static bool parse_switch(parser_t *parser, ast_block *block, ast_expression **out)
+{
+    bool rv;
+    char *label = NULL;
+
+    /* skip the 'while' and get the body */
+    if (!parser_next(parser)) {
+        if (OPTS_FLAG(LOOP_LABELS))
+            parseerror(parser, "expected loop label or 'switch' operand in parenthesis");
+        else
+            parseerror(parser, "expected 'switch' operand in parenthesis");
+        return false;
+    }
+
+    if (parser->tok == ':') {
+        if (!OPTS_FLAG(LOOP_LABELS))
+            parseerror(parser, "labeled loops not activated, try using -floop-labels");
+        if (!parser_next(parser) || parser->tok != TOKEN_IDENT) {
+            parseerror(parser, "expected loop label");
+            return false;
+        }
+        label = util_strdup(parser_tokval(parser));
+        if (!parser_next(parser)) {
+            mem_d(label);
+            parseerror(parser, "expected 'switch' operand in parenthesis");
+            return false;
+        }
+    }
+
+    if (parser->tok != '(') {
+        parseerror(parser, "expected 'switch' operand in parenthesis");
+        return false;
+    }
+
+    vec_push(parser->breaks, label);
+
+    rv = parse_switch_go(parser, block, out);
+    if (label)
+        mem_d(label);
+    if (vec_last(parser->breaks) != label) {
+        parseerror(parser, "internal error: label stack corrupted");
+        rv = false;
+        ast_delete(*out);
+        *out = NULL;
+    }
+    else {
+        vec_pop(parser->breaks);
+    }
+    return rv;
+}
+
+static bool parse_switch_go(parser_t *parser, ast_block *block, ast_expression **out)
 {
     ast_expression *operand;
     ast_value      *opval;
@@ -2593,12 +2655,6 @@ static bool parse_switch(parser_t *parser, ast_block *block, ast_expression **ou
     (void)block; /* not touching */
     (void)opval;
 
-    /* parse over the opening paren */
-    if (!parser_next(parser) || parser->tok != '(') {
-        parseerror(parser, "expected switch operand in parenthesis");
-        return false;
-    }
-
     /* parse into the expression */
     if (!parser_next(parser)) {
         parseerror(parser, "expected switch operand");
@@ -4227,6 +4283,13 @@ static bool parse_variable(parser_t *parser, ast_block *localblock, bool nofield
          * Also: if there was a prototype, `var` will be deleted and set to `proto` which
          * is then filled with the previous definition and the parameter-names replaced.
          */
+        if (!strcmp(var->name, "nil")) {
+            if (OPTS_FLAG(UNTYPED_NIL)) {
+                if (!localblock || !OPTS_FLAG(PERMISSIVE))
+                    parseerror(parser, "name `nil` not allowed (try -fpermissive)");
+            } else
+                (void)!parsewarning(parser, WARN_RESERVED_NAMES, "variable name `nil` is reserved");
+        }
         if (!localblock) {
             /* Deal with end_sys_ vars */
             was_end = false;
@@ -4854,6 +4917,7 @@ static parser_t *parser;
 
 bool parser_init()
 {
+    lex_ctx empty_ctx;
     size_t i;
 
     parser = (parser_t*)mem_a(sizeof(parser_t));
@@ -4878,6 +4942,12 @@ bool parser_init()
     vec_push(parser->variables, parser->htglobals = util_htnew(PARSER_HT_SIZE));
     vec_push(parser->typedefs, util_htnew(TYPEDEF_HT_SIZE));
     vec_push(parser->_blocktypedefs, 0);
+
+    empty_ctx.file = "<internal>";
+    empty_ctx.line = 0;
+    parser->nil = ast_value_new(empty_ctx, "nil", TYPE_NIL);
+    if (OPTS_FLAG(UNTYPED_NIL))
+        util_htset(parser->htglobals, "nil", (void*)parser->nil);
     return true;
 }
 
@@ -4985,6 +5055,8 @@ void parser_cleanup()
 
     vec_free(parser->labels);
     vec_free(parser->gotos);
+    vec_free(parser->breaks);
+    vec_free(parser->continues);
 
     mem_d(parser);
 }