]> git.xonotic.org Git - xonotic/gmqcc.git/blobdiff - parser.c
Fixing uninitialized warnings in parser.c
[xonotic/gmqcc.git] / parser.c
index a941f032e17d0fa08ec880e16080491ce93fc6f7..a11c70955878c248adbef9c0bd7b48307abaafd2 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -32,6 +32,7 @@
 #define PARSER_HT_SIZE    1024
 #define TYPEDEF_HT_SIZE   16
 
+enum parser_pot { POT_PAREN, POT_TERNARY1, POT_TERNARY2 };
 typedef struct {
     lex_file *lex;
     int      tok;
@@ -90,7 +91,7 @@ typedef struct {
      * If we reach a 'comma' operator in a ternary without a paren,
      * we shall trigger -Wternary-precedence.
      */
-    enum { POT_PAREN, POT_TERNARY1, POT_TERNARY2 } *pot;
+    enum parser_pot *pot;
 
     /* pragma flags */
     bool noref;
@@ -102,7 +103,7 @@ static void parser_enterblock(parser_t *parser);
 static bool parser_leaveblock(parser_t *parser);
 static void parser_addlocal(parser_t *parser, const char *name, ast_expression *e);
 static bool parse_typedef(parser_t *parser);
-static bool parse_variable(parser_t *parser, ast_block *localblock, bool nofields, int qualifier, ast_value *cached_typedef, bool noref, bool noreturn);
+static bool parse_variable(parser_t *parser, ast_block *localblock, bool nofields, int qualifier, ast_value *cached_typedef, bool noref, bool noreturn, bool is_static);
 static ast_block* parse_block(parser_t *parser);
 static bool parse_block_into(parser_t *parser, ast_block *block);
 static bool parse_statement_or_block(parser_t *parser, ast_expression **out);
@@ -112,34 +113,34 @@ static ast_expression* parse_expression(parser_t *parser, bool stopatcomma);
 
 static void parseerror(parser_t *parser, const char *fmt, ...)
 {
-       va_list ap;
+    va_list ap;
 
-       parser->errors++;
+    parser->errors++;
 
-       va_start(ap, fmt);
+    va_start(ap, fmt);
     con_vprintmsg(LVL_ERROR, parser->lex->tok.ctx.file, parser->lex->tok.ctx.line, "parse error", fmt, ap);
-       va_end(ap);
+    va_end(ap);
 }
 
 /* returns true if it counts as an error */
 static bool GMQCC_WARN parsewarning(parser_t *parser, int warntype, const char *fmt, ...)
 {
     bool    r;
-       va_list ap;
-       va_start(ap, fmt);
-       r = vcompile_warning(parser->lex->tok.ctx, warntype, fmt, ap);
-       va_end(ap);
-       return r;
+    va_list ap;
+    va_start(ap, fmt);
+    r = vcompile_warning(parser->lex->tok.ctx, warntype, fmt, ap);
+    va_end(ap);
+    return r;
 }
 
 static bool GMQCC_WARN genwarning(lex_ctx ctx, int warntype, const char *fmt, ...)
 {
     bool    r;
-       va_list ap;
-       va_start(ap, fmt);
-       r = vcompile_warning(ctx, warntype, fmt, ap);
-       va_end(ap);
-       return r;
+    va_list ap;
+    va_start(ap, fmt);
+    r = vcompile_warning(ctx, warntype, fmt, ap);
+    va_end(ap);
+    return r;
 }
 
 /**********************************************************************
@@ -234,7 +235,7 @@ static char *parser_strdup(const char *str)
 {
     if (str && !*str) {
         /* actually dup empty strings */
-        char *out = mem_a(1);
+        char *out = (char*)mem_a(1);
         *out = 0;
         return out;
     }
@@ -296,12 +297,12 @@ static ast_value* parser_const_vector_0(parser_t *parser)
 
 static ast_expression* parser_find_field(parser_t *parser, const char *name)
 {
-    return util_htget(parser->htfields, name);
+    return ( ast_expression*)util_htget(parser->htfields, name);
 }
 
 static ast_expression* parser_find_global(parser_t *parser, const char *name)
 {
-    return util_htget(parser->htglobals, name);
+    return (ast_expression*)util_htget(parser->htglobals, name);
 }
 
 static ast_expression* parser_find_param(parser_t *parser, const char *name)
@@ -328,7 +329,7 @@ static ast_expression* parser_find_local(parser_t *parser, const char *name, siz
     *isparam = false;
     for (i = vec_size(parser->variables); i > upto;) {
         --i;
-        if ( (e = util_htgeth(parser->variables[i], name, hash)) )
+        if ( (e = (ast_expression*)util_htgeth(parser->variables[i], name, hash)) )
             return e;
     }
     *isparam = true;
@@ -1479,7 +1480,7 @@ static ast_expression* parse_expression_leave(parser_t *parser, bool stopatcomma
             val = parser_const_string(parser, parser_tokval(parser), true);
             wantop = true;
             if (!val)
-                return false;
+                return NULL;
             vec_push(sy.out, syexp(parser_ctx(parser), (ast_expression*)val));
             DEBUGSHUNTDO(con_out("push string\n"));
 
@@ -1556,7 +1557,7 @@ static ast_expression* parse_expression_leave(parser_t *parser, bool stopatcomma
             wantop = true;
             val = parser_const_float(parser, (parser_token(parser)->constval.f));
             if (!val)
-                return false;
+                return NULL;
             vec_push(sy.out, syexp(parser_ctx(parser), (ast_expression*)val));
             DEBUGSHUNTDO(con_out("push %g\n", parser_token(parser)->constval.f));
         }
@@ -1569,7 +1570,7 @@ static ast_expression* parse_expression_leave(parser_t *parser, bool stopatcomma
             wantop = true;
             val = parser_const_float(parser, (double)(parser_token(parser)->constval.i));
             if (!val)
-                return false;
+                return NULL;
             vec_push(sy.out, syexp(parser_ctx(parser), (ast_expression*)val));
             DEBUGSHUNTDO(con_out("push %i\n", parser_token(parser)->constval.i));
         }
@@ -1582,7 +1583,7 @@ static ast_expression* parse_expression_leave(parser_t *parser, bool stopatcomma
             wantop = true;
             val = parser_const_string(parser, parser_tokval(parser), false);
             if (!val)
-                return false;
+                return NULL;
             vec_push(sy.out, syexp(parser_ctx(parser), (ast_expression*)val));
             DEBUGSHUNTDO(con_out("push string\n"));
         }
@@ -1595,7 +1596,7 @@ static ast_expression* parse_expression_leave(parser_t *parser, bool stopatcomma
             wantop = true;
             val = parser_const_vector(parser, parser_token(parser)->constval.v);
             if (!val)
-                return false;
+                return NULL;
             vec_push(sy.out, syexp(parser_ctx(parser), (ast_expression*)val));
             DEBUGSHUNTDO(con_out("push '%g %g %g'\n",
                                 parser_token(parser)->constval.v.x,
@@ -2198,7 +2199,7 @@ static bool parse_for(parser_t *parser, ast_block *block, ast_expression **out)
                              "current standard does not allow variable declarations in for-loop initializers"))
                 goto onerr;
         }
-        if (!parse_variable(parser, block, true, CV_VAR, typevar, false, false))
+        if (!parse_variable(parser, block, true, CV_VAR, typevar, false, false, false))
             goto onerr;
     }
     else if (parser->tok != ';')
@@ -2343,25 +2344,30 @@ static bool parse_break_continue(parser_t *parser, ast_block *block, ast_express
 /* returns true when it was a variable qualifier, false otherwise!
  * on error, cvq is set to CV_WRONG
  */
-static bool parse_var_qualifiers(parser_t *parser, bool with_local, int *cvq, bool *noref, bool *noreturn)
+static bool parse_var_qualifiers(parser_t *parser, bool with_local, int *cvq, bool *noref, bool *noreturn, bool *is_static)
 {
-    bool had_const = false;
-    bool had_var   = false;
-    bool had_noref = false;
+    bool had_const    = false;
+    bool had_var      = false;
+    bool had_noref    = false;
     bool had_noreturn = false;
+    bool had_attrib   = false;
+    bool had_static   = false;
 
-    *cvq = CV_WRONG;
+    *cvq = CV_NONE;
     for (;;) {
         if (parser->tok == TOKEN_ATTRIBUTE_OPEN) {
+            had_attrib = true;
             /* parse an attribute */
             if (!parser_next(parser)) {
                 parseerror(parser, "expected attribute after `[[`");
+                *cvq = CV_WRONG;
                 return false;
             }
             if (!strcmp(parser_tokval(parser), "noreturn")) {
                 had_noreturn = true;
                 if (!parser_next(parser) || parser->tok != TOKEN_ATTRIBUTE_CLOSE) {
                     parseerror(parser, "`noreturn` attribute has no parameters, expected `]]`");
+                    *cvq = CV_WRONG;
                     return false;
                 }
             }
@@ -2369,20 +2375,25 @@ static bool parse_var_qualifiers(parser_t *parser, bool with_local, int *cvq, bo
                 had_noref = true;
                 if (!parser_next(parser) || parser->tok != TOKEN_ATTRIBUTE_CLOSE) {
                     parseerror(parser, "`noref` attribute has no parameters, expected `]]`");
+                    *cvq = CV_WRONG;
                     return false;
                 }
             }
             else
             {
                 /* Skip tokens until we hit a ]] */
+                (void)!parsewarning(parser, WARN_UNKNOWN_ATTRIBUTE, "unknown attribute starting with `%s`", parser_tokval(parser));
                 while (parser->tok != TOKEN_ATTRIBUTE_CLOSE) {
                     if (!parser_next(parser)) {
                         parseerror(parser, "error inside attribute");
+                        *cvq = CV_WRONG;
                         return false;
                     }
                 }
             }
         }
+        else if (!strcmp(parser_tokval(parser), "static"))
+            had_static = true;
         else if (!strcmp(parser_tokval(parser), "const"))
             had_const = true;
         else if (!strcmp(parser_tokval(parser), "var"))
@@ -2391,7 +2402,7 @@ static bool parse_var_qualifiers(parser_t *parser, bool with_local, int *cvq, bo
             had_var = true;
         else if (!strcmp(parser_tokval(parser), "noref"))
             had_noref = true;
-        else if (!had_const && !had_var && !had_noref && !had_noreturn) {
+        else if (!had_const && !had_var && !had_noref && !had_noreturn && !had_attrib && !had_static) {
             return false;
         }
         else
@@ -2405,8 +2416,9 @@ static bool parse_var_qualifiers(parser_t *parser, bool with_local, int *cvq, bo
         *cvq = CV_VAR;
     else
         *cvq = CV_NONE;
-    *noref    = had_noref;
-    *noreturn = had_noreturn;
+    *noref     = had_noref;
+    *noreturn  = had_noreturn;
+    *is_static = had_static;
     return true;
 onerr:
     parseerror(parser, "parse error after variable qualifier");
@@ -2423,7 +2435,7 @@ static bool parse_switch(parser_t *parser, ast_block *block, ast_expression **ou
     ast_switch_case swcase;
 
     int  cvq;
-    bool noref, noreturn;
+    bool noref, noreturn, is_static;
 
     lex_ctx ctx = parser_ctx(parser);
 
@@ -2475,19 +2487,19 @@ static bool parse_switch(parser_t *parser, ast_block *block, ast_expression **ou
         if (parser->tok == TOKEN_IDENT)
             typevar = parser_find_typedef(parser, parser_tokval(parser), 0);
         if (typevar || parser->tok == TOKEN_TYPENAME) {
-            if (!parse_variable(parser, block, false, CV_NONE, typevar, false, false)) {
+            if (!parse_variable(parser, block, false, CV_NONE, typevar, false, false, false)) {
                 ast_delete(switchnode);
                 return false;
             }
             continue;
         }
-        if (parse_var_qualifiers(parser, true, &cvq, &noref, &noreturn))
+        if (parse_var_qualifiers(parser, true, &cvq, &noref, &noreturn, &is_static))
         {
             if (cvq == CV_WRONG) {
                 ast_delete(switchnode);
                 return false;
             }
-            if (!parse_variable(parser, block, false, cvq, NULL, noref, noreturn)) {
+            if (!parse_variable(parser, block, false, cvq, NULL, noref, noreturn, is_static)) {
                 ast_delete(switchnode);
                 return false;
             }
@@ -2500,11 +2512,6 @@ static bool parse_switch(parser_t *parser, ast_block *block, ast_expression **ou
     while (parser->tok != '}') {
         ast_block *caseblock;
 
-        if (parser->tok != TOKEN_KEYWORD) {
-            ast_delete(switchnode);
-            parseerror(parser, "expected 'case' or 'default'");
-            return false;
-        }
         if (!strcmp(parser_tokval(parser), "case")) {
             if (!parser_next(parser)) {
                 ast_delete(switchnode);
@@ -2533,6 +2540,11 @@ static bool parse_switch(parser_t *parser, ast_block *block, ast_expression **ou
                 return false;
             }
         }
+        else {
+            ast_delete(switchnode);
+            parseerror(parser, "expected 'case' or 'default'");
+            return false;
+        }
 
         /* Now the colon and body */
         if (parser->tok != ':') {
@@ -2702,7 +2714,7 @@ static bool parse_pragma(parser_t *parser)
 
 static bool parse_statement(parser_t *parser, ast_block *block, ast_expression **out, bool allow_cases)
 {
-    bool       noref, noreturn;
+    bool       noref, noreturn, is_static;
     int        cvq = CV_NONE;
     ast_value *typevar = NULL;
 
@@ -2722,15 +2734,15 @@ static bool parse_statement(parser_t *parser, ast_block *block, ast_expression *
             if (parsewarning(parser, WARN_EXTENSIONS, "missing 'local' keyword when declaring a local variable"))
                 return false;
         }
-        if (!parse_variable(parser, block, false, CV_NONE, typevar, false, false))
+        if (!parse_variable(parser, block, false, CV_NONE, typevar, false, false, false))
             return false;
         return true;
     }
-    else if (parse_var_qualifiers(parser, !!block, &cvq, &noref, &noreturn))
+    else if (parse_var_qualifiers(parser, !!block, &cvq, &noref, &noreturn, &is_static))
     {
         if (cvq == CV_WRONG)
             return false;
-        return parse_variable(parser, block, true, cvq, NULL, noref, noreturn);
+        return parse_variable(parser, block, true, cvq, NULL, noref, noreturn, is_static);
     }
     else if (parser->tok == TOKEN_KEYWORD)
     {
@@ -2959,7 +2971,7 @@ static bool create_vector_members(ast_value *var, ast_member **me)
     size_t len = strlen(var->name);
 
     for (i = 0; i < 3; ++i) {
-        char *name = mem_a(len+3);
+        char *name = (char*)mem_a(len+3);
         memcpy(name, var->name, len);
         name[len+0] = '_';
         name[len+1] = 'x'+i;
@@ -3696,9 +3708,9 @@ static ast_value *parse_parameter_list(parser_t *parser, ast_value *var)
                 goto on_error;
             vec_push(params, param);
             if (param->expression.vtype >= TYPE_VARIANT) {
-                char typename[1024];
-                ast_type_to_string((ast_expression*)param, typename, sizeof(typename));
-                parseerror(parser, "type not supported as part of a parameter list: %s", typename);
+                char tname[1024]; /* typename is reserved in C++ */
+                ast_type_to_string((ast_expression*)param, tname, sizeof(tname));
+                parseerror(parser, "type not supported as part of a parameter list: %s", tname);
                 goto on_error;
             }
         }
@@ -3986,7 +3998,7 @@ static bool parse_typedef(parser_t *parser)
     return true;
 }
 
-static bool parse_variable(parser_t *parser, ast_block *localblock, bool nofields, int qualifier, ast_value *cached_typedef, bool noref, bool noreturn)
+static bool parse_variable(parser_t *parser, ast_block *localblock, bool nofields, int qualifier, ast_value *cached_typedef, bool noref, bool noreturn, bool is_static)
 {
     ast_value *var;
     ast_value *proto;
@@ -4003,6 +4015,9 @@ static bool parse_variable(parser_t *parser, ast_block *localblock, bool nofield
 
     ast_member *me[3];
 
+    if (!localblock && is_static)
+        parseerror(parser, "`static` qualifier is not supported in global scope");
+
     /* get the first complete variable */
     var = parse_typename(parser, &basetype, cached_typedef);
     if (!var) {
@@ -4249,16 +4264,55 @@ static bool parse_variable(parser_t *parser, ast_block *localblock, bool nofield
                     }
                 }
             } else {
-                vec_push(localblock->locals, var);
-                parser_addlocal(parser, var->name, (ast_expression*)var);
-                if (isvector) {
-                    for (i = 0; i < 3; ++i) {
-                        parser_addlocal(parser, me[i]->name, (ast_expression*)me[i]);
-                        ast_block_collect(localblock, (ast_expression*)me[i]);
+                if (is_static) {
+                    /* a static adds itself to be generated like any other global
+                     * but is added to the local namespace instead
+                     */
+                    char   *defname = NULL;
+                    size_t  prefix_len, ln;
+
+                    ln = strlen(parser->function->name);
+                    vec_append(defname, ln, parser->function->name);
+
+                    vec_append(defname, 2, "::");
+                    /* remember the length up to here */
+                    prefix_len = vec_size(defname);
+
+                    /* Add it to the local scope */
+                    util_htset(vec_last(parser->variables), var->name, (void*)var);
+                    /* now rename the global */
+                    ln = strlen(var->name);
+                    vec_append(defname, ln, var->name);
+                    ast_value_set_name(var, defname);
+
+                    /* push it to the to-be-generated globals */
+                    vec_push(parser->globals, (ast_expression*)var);
+
+                    /* same game for the vector members */
+                    if (isvector) {
+                        for (i = 0; i < 3; ++i) {
+                            util_htset(vec_last(parser->variables), me[i]->name, (void*)(me[i]));
+
+                            vec_shrinkto(defname, prefix_len);
+                            ln = strlen(me[i]->name);
+                            vec_append(defname, ln, me[i]->name);
+                            ast_member_set_name(me[i], defname);
+
+                            vec_push(parser->globals, (ast_expression*)me[i]);
+                        }
+                    }
+                    vec_free(defname);
+                } else {
+                    vec_push(localblock->locals, var);
+                    parser_addlocal(parser, var->name, (ast_expression*)var);
+                    if (isvector) {
+                        for (i = 0; i < 3; ++i) {
+                            parser_addlocal(parser, me[i]->name, (ast_expression*)me[i]);
+                            ast_block_collect(localblock, (ast_expression*)me[i]);
+                        }
                     }
                 }
             }
-
         }
         me[0] = me[1] = me[2] = NULL;
         cleanvar = false;
@@ -4519,23 +4573,24 @@ cleanup:
 
 static bool parser_global_statement(parser_t *parser)
 {
-    int        cvq      = CV_WRONG;
-    bool       noref    = false;
-    bool       noreturn = false;
-    ast_value *istype   = NULL;
+    int        cvq       = CV_WRONG;
+    bool       noref     = false;
+    bool       noreturn  = false;
+    bool       is_static = false;
+    ast_value *istype    = NULL;
 
     if (parser->tok == TOKEN_IDENT)
         istype = parser_find_typedef(parser, parser_tokval(parser), 0);
 
     if (istype || parser->tok == TOKEN_TYPENAME || parser->tok == '.')
     {
-        return parse_variable(parser, NULL, false, CV_NONE, istype, false, false);
+        return parse_variable(parser, NULL, false, CV_NONE, istype, false, false, false);
     }
-    else if (parse_var_qualifiers(parser, false, &cvq, &noref, &noreturn))
+    else if (parse_var_qualifiers(parser, false, &cvq, &noref, &noreturn, &is_static))
     {
         if (cvq == CV_WRONG)
             return false;
-        return parse_variable(parser, NULL, true, cvq, NULL, noref, noreturn);
+        return parse_variable(parser, NULL, true, cvq, NULL, noref, noreturn, is_static);
     }
     else if (parser->tok == TOKEN_KEYWORD)
     {
@@ -4592,56 +4647,56 @@ static void generate_checksum(parser_t *parser)
     size_t     i;
     ast_value *value;
 
-       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], ast_value))
-               continue;
-           value = (ast_value*)(parser->globals[i]);
-           switch (value->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, value->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], ast_value))
-               continue;
-           value = (ast_value*)(parser->fields[i]);
-           switch (value->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, value->name);
-           crc = progdefs_crc_both(crc, ";\n");
-       }
-       crc = progdefs_crc_both(crc, "} entvars_t;\n\n");
-
-       code_crc = crc;
+    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], ast_value))
+            continue;
+        value = (ast_value*)(parser->globals[i]);
+        switch (value->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, value->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], ast_value))
+            continue;
+        value = (ast_value*)(parser->fields[i]);
+        switch (value->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, value->name);
+        crc = progdefs_crc_both(crc, ";\n");
+    }
+    crc = progdefs_crc_both(crc, "} entvars_t;\n\n");
+
+    code_crc = crc;
 }
 
 static parser_t *parser;
@@ -4717,7 +4772,7 @@ bool parser_compile_file(const char *filename)
     return parser_compile();
 }
 
-bool parser_compile_string_len(const char *name, const char *str, size_t len)
+bool parser_compile_string(const char *name, const char *str, size_t len)
 {
     parser->lex = lex_open_string(str, len, name);
     if (!parser->lex) {
@@ -4727,16 +4782,6 @@ bool parser_compile_string_len(const char *name, const char *str, size_t len)
     return parser_compile();
 }
 
-bool parser_compile_string(const char *name, const char *str)
-{
-    parser->lex = lex_open_string(str, strlen(str), name);
-    if (!parser->lex) {
-        con_err("failed to create lexer for string \"%s\"\n", name);
-        return false;
-    }
-    return parser_compile();
-}
-
 void parser_cleanup()
 {
     size_t i;