]> git.xonotic.org Git - xonotic/gmqcc.git/blobdiff - parser.c
Make COMPILER_QCC default to please the stuborn Quake community.
[xonotic/gmqcc.git] / parser.c
index 71242ac79a81850d57209a2f7234323e478d390f..ea4930f02b79f8d0d4b4f52e4a6e9fdee7d1b94c 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -31,8 +31,8 @@
 /* beginning of locals */
 #define PARSER_HT_LOCALS  2
 
-#define PARSER_HT_SIZE    128
-#define TYPEDEF_HT_SIZE   16
+#define PARSER_HT_SIZE    512
+#define TYPEDEF_HT_SIZE   512
 
 typedef struct parser_s {
     lex_file *lex;
@@ -49,6 +49,7 @@ typedef struct parser_s {
     size_t         translated;
 
     ht ht_imm_string;
+    ht ht_imm_string_dotranslate;
 
     /* must be deleted first, they reference immediates and values */
     ast_value    **accessors;
@@ -104,9 +105,6 @@ typedef struct parser_s {
 
     /* collected information */
     size_t     max_param_count;
-
-    /* code generator */
-    code_t     *code;
 } parser_t;
 
 static ast_expression * const intrinsic_debug_typestring = (ast_expression*)0x1;
@@ -260,17 +258,15 @@ static char *parser_strdup(const char *str)
 
 static ast_value* parser_const_string(parser_t *parser, const char *str, bool dotranslate)
 {
-    size_t hash = util_hthash(parser->ht_imm_string, str);
+    ht ht_string = (dotranslate)
+        ? parser->ht_imm_string_dotranslate
+        : parser->ht_imm_string;
+
     ast_value *out;
-    if ( (out = (ast_value*)util_htgeth(parser->ht_imm_string, str, hash)) ) {
-        if (dotranslate && out->name[0] == '#') {
-            char name[32];
-            util_snprintf(name, sizeof(name), "dotranslate_%lu", (unsigned long)(parser->translated++));
-            ast_value_set_name(out, name);
-            out->expression.flags |= AST_FLAG_INCLUDE_DEF;
-        }
+    size_t     hash = util_hthash(ht_string, str);
+
+    if ((out = (ast_value*)util_htgeth(ht_string, str, hash)))
         return out;
-    }
     /*
     for (i = 0; i < vec_size(parser->imm_string); ++i) {
         if (!strcmp(parser->imm_string[i]->constval.vstring, str))
@@ -284,12 +280,14 @@ static ast_value* parser_const_string(parser_t *parser, const char *str, bool do
         out->expression.flags |= AST_FLAG_INCLUDE_DEF;
     } else
         out = ast_value_new(parser_ctx(parser), "#IMMEDIATE", TYPE_STRING);
+
     out->cvq      = CV_CONST;
     out->hasvalue = true;
     out->isimm    = true;
     out->constval.vstring = parser_strdup(str);
     vec_push(parser->imm_string, out);
-    util_htseth(parser->ht_imm_string, str, hash, out);
+    util_htseth(ht_string, str, hash, out);
+
     return out;
 }
 
@@ -952,7 +950,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy)
             if (exprs[1]->vtype != TYPE_FLOAT) {
                 ast_type_to_string(exprs[0], ty1, sizeof(ty1));
                 ast_type_to_string(exprs[1], ty2, sizeof(ty2));
-                compile_error(ctx, "invalid types used in expression: cannot divide tyeps %s and %s", ty1, ty2);
+                compile_error(ctx, "invalid types used in expression: cannot divide types %s and %s", ty1, ty2);
                 return false;
             }
             if (exprs[0]->vtype == TYPE_FLOAT) {
@@ -983,7 +981,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy)
             {
                 ast_type_to_string(exprs[0], ty1, sizeof(ty1));
                 ast_type_to_string(exprs[1], ty2, sizeof(ty2));
-                compile_error(ctx, "invalid types used in expression: cannot divide tyeps %s and %s", ty1, ty2);
+                compile_error(ctx, "invalid types used in expression: cannot divide types %s and %s", ty1, ty2);
                 return false;
             }
             break;
@@ -1044,20 +1042,20 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy)
              * Further more, the only time it is legal to do XOR otherwise
              * is when both operand are floats. This nicely crafted if
              * statement catches them all.
-             * 
+             *
              * In the event that the first operand is a vector, two
              * possible situations can arise, thus, each element of
              * vector A (operand A) is exclusive-ORed with the corresponding
              * element of vector B (operand B), If B is scalar, the
              * scalar value is first replicated for each element.
-             * 
+             *
              * The QCVM itself lacks a BITXOR instruction. Thus emulating
              * the mathematics of it is required. The following equation
              * is used: (LHS | RHS) & ~(LHS & RHS). However, due to the
              * QCVM also lacking a BITNEG instruction, we need to emulate
              * ~FOO with -1 - FOO, the whole process becoming this nicely
              * crafted expression: (LHS | RHS) & (-1 - (LHS & RHS)).
-             * 
+             *
              * When A is not scalar, this process is repeated for all
              * components of vector A with the value in operand B,
              * only if operand B is scalar. When A is not scalar, and B
@@ -1065,7 +1063,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy)
              * components of the vector A with the components of vector B.
              * Finally when A is scalar and B is scalar, this process is
              * simply used once for A and B being LHS and RHS respectfully.
-             * 
+             *
              * Yes the semantics are a bit strange (no pun intended).
              * But then again BITXOR is strange itself, consdering it's
              * commutative, assocative, and elements of the BITXOR operation
@@ -1101,7 +1099,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy)
                         )
                     );
                     expr->refs = AST_REF_NONE;
-                    
+
                     out = (ast_expression*)
                         ast_binary_new(
                             ctx,
@@ -1154,7 +1152,7 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy)
                     }
                 }
             }
-                
+
             break;
 
         case opid2('<','<'):
@@ -2059,7 +2057,7 @@ static bool parse_sya_operand(parser_t *parser, shunt *sy, bool with_labels)
                         correct = correct_str(&corr, parser->correct_variables[i], parser_tokval(parser));
                         if (strcmp(correct, parser_tokval(parser))) {
                             break;
-                        } else if (correct) {
+                        } else  {
                             mem_d(correct);
                             correct = NULL;
                         }
@@ -2517,7 +2515,8 @@ static ast_expression* process_condition(parser_t *parser, ast_expression *cond,
     }
 
     unary = (ast_unary*)cond;
-    while (ast_istype(cond, ast_unary) && unary->op == INSTR_NOT_F)
+    /* ast_istype dereferences cond, should test here for safety */
+    while (cond && ast_istype(cond, ast_unary) && unary->op == INSTR_NOT_F)
     {
         cond = unary->operand;
         unary->operand = NULL;
@@ -2757,7 +2756,12 @@ static bool parse_dowhile(parser_t *parser, ast_block *block, ast_expression **o
     if (vec_last(parser->breaks) != label || vec_last(parser->continues) != label) {
         parseerror(parser, "internal error: label stack corrupted");
         rv = false;
-        ast_delete(*out);
+        /*
+         * Test for NULL otherwise ast_delete dereferences null pointer
+         * and boom.
+         */
+        if (*out)
+            ast_delete(*out);
         *out = NULL;
     }
     else {
@@ -3625,7 +3629,8 @@ static bool parse_goto(parser_t *parser, ast_expression **out)
         if (!(expression = parse_expression(parser, false, true)) ||
             !(*out = parse_goto_computed(parser, &expression))) {
             parseerror(parser, "invalid goto expression");
-            ast_unref(expression);
+            if(expression)
+                ast_unref(expression);
             return false;
         }
 
@@ -5887,8 +5892,16 @@ skipvar:
 
         if (parser->tok != '{' || var->expression.vtype != TYPE_FUNCTION) {
             if (parser->tok != '=') {
-                parseerror(parser, "missing semicolon or initializer, got: `%s`", parser_tokval(parser));
-                break;
+                if (!strcmp(parser_tokval(parser), "break")) {
+                    if (!parser_next(parser)) {
+                        parseerror(parser, "error parsing break definition");
+                        break;
+                    }
+                    (void)!!parsewarning(parser, WARN_BREAKDEF, "break definition ignored (suggest removing it)");
+                } else {
+                    parseerror(parser, "missing semicolon or initializer, got: `%s`", parser_tokval(parser));
+                    break;
+                }
             }
 
             if (!parser_next(parser)) {
@@ -6204,7 +6217,7 @@ static uint16_t progdefs_crc_both(uint16_t old, const char *str)
     return old;
 }
 
-static void generate_checksum(parser_t *parser)
+static void generate_checksum(parser_t *parser, ir_builder *ir)
 {
     uint16_t   crc = 0xFFFF;
     size_t     i;
@@ -6258,8 +6271,7 @@ static void generate_checksum(parser_t *parser)
         crc = progdefs_crc_both(crc, ";\n");
     }
     crc = progdefs_crc_both(crc, "} entvars_t;\n\n");
-
-    parser->code->crc = crc;
+    ir->code->crc = crc;
 }
 
 parser_t *parser_create()
@@ -6274,11 +6286,6 @@ parser_t *parser_create()
 
     memset(parser, 0, sizeof(*parser));
 
-    if (!(parser->code = code_init())) {
-        mem_d(parser);
-        return NULL;
-    }
-
     for (i = 0; i < operator_count; ++i) {
         if (operators[i].id == opid1('=')) {
             parser->assign_op = operators+i;
@@ -6299,13 +6306,15 @@ parser_t *parser_create()
     parser->aliases = util_htnew(PARSER_HT_SIZE);
 
     parser->ht_imm_string = util_htnew(512);
+    parser->ht_imm_string_dotranslate = util_htnew(512);
 
     /* corrector */
     vec_push(parser->correct_variables, correct_trie_new());
     vec_push(parser->correct_variables_score, NULL);
 
-    empty_ctx.file = "<internal>";
-    empty_ctx.line = 0;
+    empty_ctx.file   = "<internal>";
+    empty_ctx.line   = 0;
+    empty_ctx.column = 0;
     parser->nil = ast_value_new(empty_ctx, "nil", TYPE_NIL);
     parser->nil->cvq = CV_CONST;
     if (OPTS_FLAG(UNTYPED_NIL))
@@ -6415,6 +6424,7 @@ static void parser_remove_ast(parser_t *parser)
     vec_free(parser->functions);
     vec_free(parser->imm_vector);
     vec_free(parser->imm_string);
+    util_htdel(parser->ht_imm_string_dotranslate);
     util_htdel(parser->ht_imm_string);
     vec_free(parser->imm_float);
     vec_free(parser->globals);
@@ -6453,7 +6463,7 @@ static void parser_remove_ast(parser_t *parser)
     ast_value_delete(parser->const_vec[0]);
     ast_value_delete(parser->const_vec[1]);
     ast_value_delete(parser->const_vec[2]);
-    
+
     if (parser->reserved_version)
         ast_value_delete(parser->reserved_version);
 
@@ -6464,8 +6474,6 @@ static void parser_remove_ast(parser_t *parser)
 void parser_cleanup(parser_t *parser)
 {
     parser_remove_ast(parser);
-    code_cleanup(parser->code);
-
     mem_d(parser);
 }
 
@@ -6623,7 +6631,8 @@ bool parser_finish(parser_t *parser, const char *output)
         }
     }
 
-    generate_checksum(parser);
+    generate_checksum(parser, ir);
+
     if (OPTS_OPTION_BOOL(OPTION_DUMP))
         ir_builder_dump(ir, con_out);
     for (i = 0; i < vec_size(parser->functions); ++i) {
@@ -6645,7 +6654,7 @@ bool parser_finish(parser_t *parser, const char *output)
         if (OPTS_OPTION_BOOL(OPTION_DUMPFIN))
             ir_builder_dump(ir, con_out);
 
-        if (!ir_builder_generate(parser->code, ir, output)) {
+        if (!ir_builder_generate(ir, output)) {
             con_out("*** failed to generate output file\n");
             ir_builder_delete(ir);
             return false;