]> git.xonotic.org Git - xonotic/gmqcc.git/blobdiff - parser.c
string-literals now do not treat digraphs as digraphs
[xonotic/gmqcc.git] / parser.c
index f11684bb3bb139325a598b8114374db641a0444b..a49deb5e398b8b25496c076d4008805e8c3cc3d2 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -23,6 +23,9 @@ typedef struct {
     ast_value *imm_float_zero;
     ast_value *imm_vector_zero;
 
+    size_t crc_globals;
+    size_t crc_fields;
+
     ast_function *function;
     MEM_VECTOR_MAKE(varentry_t, locals);
     size_t blocklocal;
@@ -861,10 +864,50 @@ static bool parser_sy_pop(parser_t *parser, shunt *sy)
             break;
 
         case opid1('='):
-            if (ast_istype(exprs[0], ast_entfield))
+            if (ast_istype(exprs[0], ast_entfield)) {
+                ast_expression *field = ((ast_entfield*)exprs[0])->field;
                 assignop = type_storep_instr[exprs[0]->expression.vtype];
+                if (!ast_compare_type(field->expression.next, exprs[1])) {
+                    char ty1[1024];
+                    char ty2[1024];
+                    ast_type_to_string(field->expression.next, ty1, sizeof(ty1));
+                    ast_type_to_string(exprs[1], ty2, sizeof(ty2));
+                    if (opts_standard == COMPILER_QCC &&
+                        field->expression.next->expression.vtype == TYPE_FUNCTION &&
+                        exprs[1]->expression.vtype == TYPE_FUNCTION)
+                    {
+                        if (parsewarning(parser, WARN_ASSIGN_FUNCTION_TYPES,
+                                         "invalid types in assignment: cannot assign %s to %s", ty2, ty1))
+                        {
+                            parser->errors++;
+                        }
+                    }
+                    else
+                        parseerror(parser, "invalid types in assignment: cannot assign %s to %s", ty2, ty1);
+                }
+            }
             else
+            {
                 assignop = type_store_instr[exprs[0]->expression.vtype];
+                if (!ast_compare_type(exprs[0], exprs[1])) {
+                    char ty1[1024];
+                    char ty2[1024];
+                    ast_type_to_string(exprs[0], ty1, sizeof(ty1));
+                    ast_type_to_string(exprs[1], ty2, sizeof(ty2));
+                    if (opts_standard == COMPILER_QCC &&
+                        exprs[0]->expression.vtype == TYPE_FUNCTION &&
+                        exprs[1]->expression.vtype == TYPE_FUNCTION)
+                    {
+                        if (parsewarning(parser, WARN_ASSIGN_FUNCTION_TYPES,
+                                         "invalid types in assignment: cannot assign %s to %s", ty2, ty1))
+                        {
+                            parser->errors++;
+                        }
+                    }
+                    else
+                        parseerror(parser, "invalid types in assignment: cannot assign %s to %s", ty2, ty1);
+                }
+            }
             out = (ast_expression*)ast_store_new(ctx, assignop, exprs[0], exprs[1]);
             break;
         case opid2('+','='):
@@ -964,6 +1007,8 @@ static bool parser_close_call(parser_t *parser, shunt *sy)
             MEM_VECTOR_MOVE(params, exprs, call, params);
             ast_delete(params);
         }
+        if (!ast_call_check_types(call))
+            parser->errors++;
     } else {
         parseerror(parser, "invalid function call");
         return false;
@@ -1812,7 +1857,7 @@ static bool parse_block_into(parser_t *parser, ast_block *block, bool warnreturn
             break;
 
         if (!parse_statement(parser, block, &expr)) {
-            parseerror(parser, "parse error");
+            /* parseerror(parser, "parse error"); */
             block = NULL;
             goto cleanup;
         }
@@ -2194,12 +2239,12 @@ static bool parse_function_body(parser_t *parser, ast_value *var)
     parser->function = func;
     if (!parse_block_into(parser, block, true)) {
         ast_block_delete(block);
-        goto enderrfn;
+        goto enderrfn2;
     }
 
     if (!ast_function_blocks_add(func, block)) {
         ast_block_delete(block);
-        goto enderrfn;
+        goto enderrfn2;
     }
 
     parser->function = old;
@@ -2212,6 +2257,8 @@ static bool parse_function_body(parser_t *parser, ast_value *var)
         parseerror(parser, "missing semicolon after function body (mandatory with -std=qcc)");
     return retval;
 
+enderrfn2:
+    parser->functions_count--;
 enderrfn:
     ast_function_delete(func);
     var->constval.vfunc = NULL;
@@ -2284,6 +2331,13 @@ static bool parse_variable(parser_t *parser, ast_block *localblock)
             goto cleanup;
         }
 
+        if (!localblock) {
+            if      (!strcmp(parser_tokval(parser), "end_sys_globals"))
+                parser->crc_globals = parser->globals_count;
+            else if (!strcmp(parser_tokval(parser), "end_sys_fields"))
+                parser->crc_fields = parser->fields_count;
+        }
+
         if (!isfunc) {
             if (!localblock && (olddecl = parser_find_global(parser, parser_tokval(parser)))) {
                 parseerror(parser, "global `%s` already declared here: %s:%i",
@@ -2710,6 +2764,13 @@ static bool parser_global_statement(parser_t *parser)
                 var = fval;
             }
 
+            if (!strcmp(parser_tokval(parser), "end_sys_fields")) {
+                if (parsewarning(parser, WARN_END_SYS_FIELDS, "by convention end_sys_fields should be declared as global, rather than a field")) {
+                    ast_value_delete(var);
+                    return false;
+                }
+            }
+
             /* turn it into a field */
             fld = ast_value_new(ctx, parser_tokval(parser), TYPE_FIELD);
             fld->expression.next = (ast_expression*)var;
@@ -2829,7 +2890,7 @@ bool parser_compile(const char *filename)
                 if (parser->tok == TOKEN_EOF)
                     parseerror(parser, "unexpected eof");
                 else if (!parser->errors)
-                    parseerror(parser, "parse error");
+                    parseerror(parser, "there have been errors, bailing out");
                 lex_close(parser->lex);
                 parser->lex = NULL;
                 return false;
@@ -2882,6 +2943,78 @@ void parser_cleanup()
     mem_d(parser);
 }
 
+static uint16_t progdefs_crc_sum(uint16_t old, const char *str)
+{
+    return util_crc16(old, str, strlen(str));
+}
+
+static void progdefs_crc_file(const char *str)
+{
+    /* write to progdefs.h here */
+}
+
+static uint16_t progdefs_crc_both(uint16_t old, const char *str)
+{
+    old = progdefs_crc_sum(old, str);
+    progdefs_crc_file(str);
+    return old;
+}
+
+static void generate_checksum(parser_t *parser)
+{
+    uint16_t crc = 0xFFFF;
+    size_t i;
+
+       crc = progdefs_crc_both(crc, "\n/* file generated by qcc, do not modify */\n\ntypedef struct\n{");
+       crc = progdefs_crc_sum(crc, "\tint\tpad[28];\n");
+       /*
+       progdefs_crc_file("\tint\tpad;\n");
+       progdefs_crc_file("\tint\tofs_return[3];\n");
+       progdefs_crc_file("\tint\tofs_parm0[3];\n");
+       progdefs_crc_file("\tint\tofs_parm1[3];\n");
+       progdefs_crc_file("\tint\tofs_parm2[3];\n");
+       progdefs_crc_file("\tint\tofs_parm3[3];\n");
+       progdefs_crc_file("\tint\tofs_parm4[3];\n");
+       progdefs_crc_file("\tint\tofs_parm5[3];\n");
+       progdefs_crc_file("\tint\tofs_parm6[3];\n");
+       progdefs_crc_file("\tint\tofs_parm7[3];\n");
+       */
+       for (i = 0; i < parser->crc_globals; ++i) {
+           if (!ast_istype(parser->globals[i].var, ast_value))
+               continue;
+           switch (parser->globals[i].var->expression.vtype) {
+               case TYPE_FLOAT:    crc = progdefs_crc_both(crc, "\tfloat\t"); break;
+               case TYPE_VECTOR:   crc = progdefs_crc_both(crc, "\tvec3_t\t"); break;
+               case TYPE_STRING:   crc = progdefs_crc_both(crc, "\tstring_t\t"); break;
+               case TYPE_FUNCTION: crc = progdefs_crc_both(crc, "\tfunc_t\t"); break;
+               default:
+                   crc = progdefs_crc_both(crc, "\tint\t");
+                   break;
+           }
+           crc = progdefs_crc_both(crc, parser->globals[i].name);
+           crc = progdefs_crc_both(crc, ";\n");
+       }
+       crc = progdefs_crc_both(crc, "} globalvars_t;\n\ntypedef struct\n{\n");
+       for (i = 0; i < parser->crc_fields; ++i) {
+           if (!ast_istype(parser->fields[i].var, ast_value))
+               continue;
+           switch (parser->fields[i].var->expression.next->expression.vtype) {
+               case TYPE_FLOAT:    crc = progdefs_crc_both(crc, "\tfloat\t"); break;
+               case TYPE_VECTOR:   crc = progdefs_crc_both(crc, "\tvec3_t\t"); break;
+               case TYPE_STRING:   crc = progdefs_crc_both(crc, "\tstring_t\t"); break;
+               case TYPE_FUNCTION: crc = progdefs_crc_both(crc, "\tfunc_t\t"); break;
+               default:
+                   crc = progdefs_crc_both(crc, "\tint\t");
+                   break;
+           }
+           crc = progdefs_crc_both(crc, parser->fields[i].name);
+           crc = progdefs_crc_both(crc, ";\n");
+       }
+       crc = progdefs_crc_both(crc, "} entvars_t;\n\n");
+
+       code_crc = crc;
+}
+
 bool parser_finish(const char *output)
 {
     size_t i;
@@ -2928,8 +3061,12 @@ bool parser_finish(const char *output)
                 continue;
             asvalue = (ast_value*)(parser->globals[i].var);
             if (!asvalue->uses && !asvalue->isconst && asvalue->expression.vtype != TYPE_FUNCTION) {
-                retval = retval && !genwarning(ast_ctx(asvalue), WARN_UNUSED_VARIABLE,
-                                               "unused global: `%s`", asvalue->name);
+                if (strcmp(asvalue->name, "end_sys_globals") &&
+                    strcmp(asvalue->name, "end_sys_fields"))
+                {
+                    retval = retval && !genwarning(ast_ctx(asvalue), WARN_UNUSED_VARIABLE,
+                                                   "unused global: `%s`", asvalue->name);
+                }
             }
             if (!ast_global_codegen(asvalue, ir)) {
                 printf("failed to generate global %s\n", parser->globals[i].name);
@@ -2975,6 +3112,8 @@ bool parser_finish(const char *output)
             if (opts_dump)
                 ir_builder_dump(ir, printf);
 
+            generate_checksum(parser);
+
             if (!ir_builder_generate(ir, output)) {
                 printf("*** failed to generate output file\n");
                 ir_builder_delete(ir);