X-Git-Url: https://git.xonotic.org/?p=xonotic%2Fgmqcc.git;a=blobdiff_plain;f=parser.c;h=422930d0d8d1ca7612caee58af4e41ac92f2665a;hp=5129962c768c216f8a1e16d15e78b4a8e4026d8c;hb=5cfd97c344b5a3d90409cd0ba04b410b2cdd25b8;hpb=a985a5cab14ff367bcbde95f613a438e835ead4c diff --git a/parser.c b/parser.c index 5129962..422930d 100644 --- a/parser.c +++ b/parser.c @@ -26,14 +26,13 @@ #include "gmqcc.h" #include "lexer.h" -#define PARSER_HT_FIELDS 0 -#define PARSER_HT_GLOBALS 1 /* beginning of locals */ #define PARSER_HT_LOCALS 2 #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; @@ -77,8 +76,6 @@ typedef struct { size_t *_blocktypedefs; lex_ctx *_block_ctx; - size_t errors; - /* we store the '=' operator info */ const oper_info *assign_op; @@ -92,7 +89,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; @@ -104,7 +101,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); @@ -114,34 +111,31 @@ static ast_expression* parse_expression(parser_t *parser, bool stopatcomma); static void parseerror(parser_t *parser, const char *fmt, ...) { - va_list ap; - - parser->errors++; - - 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_list ap; + va_start(ap, fmt); + vcompile_error(parser->lex->tok.ctx, fmt, 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; } /********************************************************************** @@ -236,7 +230,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; } @@ -298,12 +292,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) @@ -330,7 +324,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; @@ -892,23 +886,28 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) parseerror(parser, "invalid types for logical operation with -fperl-logic: %s and %s", ty1, ty2); return false; } - if (OPTS_FLAG(CORRECT_LOGIC)) { - /* non-floats need to be NOTed */ - for (i = 0; i < 2; ++i) { - if (exprs[i]->expression.vtype != TYPE_FLOAT) { - if (type_not_instr[exprs[i]->expression.vtype] == AINSTR_END) { - ast_type_to_string(exprs[0], ty1, sizeof(ty1)); - ast_type_to_string(exprs[1], ty2, sizeof(ty2)); - parseerror(parser, "invalid types for logical operation with -fcorrect-logic: %s and %s", ty1, ty2); - return false; - } - out = (ast_expression*)ast_unary_new(ctx, type_not_instr[exprs[i]->expression.vtype], exprs[i]); - if (!out) - break; - exprs[i] = out; out = NULL; + for (i = 0; i < 2; ++i) { + if (OPTS_FLAG(CORRECT_LOGIC) && exprs[i]->expression.vtype == TYPE_VECTOR) { + out = (ast_expression*)ast_unary_new(ctx, INSTR_NOT_V, exprs[i]); + if (!out) break; + out = (ast_expression*)ast_unary_new(ctx, INSTR_NOT_F, out); + if (!out) break; + exprs[i] = out; out = NULL; + if (OPTS_FLAG(PERL_LOGIC)) { + /* here we want to keep the right expressions' type */ + break; } - if (OPTS_FLAG(PERL_LOGIC)) + } + else if (OPTS_FLAG(FALSE_EMPTY_STRINGS) && exprs[i]->expression.vtype == TYPE_STRING) { + out = (ast_expression*)ast_unary_new(ctx, INSTR_NOT_S, exprs[i]); + if (!out) break; + out = (ast_expression*)ast_unary_new(ctx, INSTR_NOT_F, out); + if (!out) break; + exprs[i] = out; out = NULL; + if (OPTS_FLAG(PERL_LOGIC)) { + /* here we want to keep the right expressions' type */ break; + } } } out = (ast_expression*)ast_binary_new(ctx, generated_op, exprs[0], exprs[1]); @@ -988,11 +987,8 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) 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++; - } + (void)!parsewarning(parser, WARN_ASSIGN_FUNCTION_TYPES, + "invalid types in assignment: cannot assign %s to %s", ty2, ty1); } else parseerror(parser, "invalid types in assignment: cannot assign %s to %s", ty2, ty1); @@ -1022,11 +1018,8 @@ static bool parser_sy_apply_operator(parser_t *parser, shunt *sy) 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++; - } + (void)!parsewarning(parser, WARN_ASSIGN_FUNCTION_TYPES, + "invalid types in assignment: cannot assign %s to %s", ty2, ty1); } else parseerror(parser, "invalid types in assignment: cannot assign %s to %s", ty2, ty1); @@ -1302,8 +1295,7 @@ static bool parser_close_call(parser_t *parser, shunt *sy) params->exprs = NULL; ast_delete(params); } - if (!ast_call_check_types(call)) - parser->errors++; + (void)!ast_call_check_types(call); } else { parseerror(parser, "invalid function call"); return false; @@ -1476,7 +1468,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")); @@ -1553,7 +1545,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)); } @@ -1566,7 +1558,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)); } @@ -1579,7 +1571,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")); } @@ -1592,7 +1584,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, @@ -1869,10 +1861,8 @@ static bool parser_leaveblock(parser_t *parser) ast_value *v = (ast_value*)e; vec_pop(parser->_locals); if (ast_istype(e, ast_value) && !v->uses) { - if (compile_warning(ast_ctx(v), WARN_UNUSED_VARIABLE, "unused variable: `%s`", v->name)) { - parser->errors++; + if (compile_warning(ast_ctx(v), WARN_UNUSED_VARIABLE, "unused variable: `%s`", v->name)) rv = false; - } } } @@ -1900,7 +1890,8 @@ static ast_expression* process_condition(parser_t *parser, ast_expression *cond, ast_unary *unary; ast_expression *prev; - if (OPTS_FLAG(FALSE_EMPTY_STRINGS) && cond->expression.vtype == TYPE_STRING) { + if (OPTS_FLAG(FALSE_EMPTY_STRINGS) && cond->expression.vtype == TYPE_STRING) + { prev = cond; cond = (ast_expression*)ast_unary_new(ast_ctx(cond), INSTR_NOT_S, cond); if (!cond) { @@ -1910,14 +1901,15 @@ static ast_expression* process_condition(parser_t *parser, ast_expression *cond, } ifnot = !ifnot; } - else if (OPTS_FLAG(CORRECT_LOGIC)) { - /* everything must use a NOT_ */ - unary = (ast_unary*)cond; - if (!ast_istype(cond, ast_unary) || unary->op < INSTR_NOT_F || unary->op > INSTR_NOT_FNC) + else if (OPTS_FLAG(CORRECT_LOGIC) && cond->expression.vtype == TYPE_VECTOR) + { + /* vector types need to be cast to true booleans */ + ast_binary *bin = (ast_binary*)cond; + if (!OPTS_FLAG(PERL_LOGIC) || !ast_istype(cond, ast_binary) || !(bin->op == INSTR_AND || bin->op == INSTR_OR)) { - /* use the right NOT_ */ + /* in perl-logic, AND and OR take care of the -fcorrect-logic */ prev = cond; - cond = (ast_expression*)ast_unary_new(ast_ctx(cond), type_not_instr[cond->expression.vtype], cond); + cond = (ast_expression*)ast_unary_new(ast_ctx(cond), INSTR_NOT_V, cond); if (!cond) { ast_unref(prev); parseerror(parser, "internal error: failed to process condition"); @@ -1929,7 +1921,6 @@ 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) - /*&& unary->operand->expression.vtype != TYPE_STRING) */ { cond = unary->operand; unary->operand = NULL; @@ -2194,7 +2185,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 != ';') @@ -2255,9 +2246,11 @@ static bool parse_for(parser_t *parser, ast_block *block, ast_expression **out) if (!parse_statement_or_block(parser, &ontrue)) goto onerr; - cond = process_condition(parser, cond, &ifnot); - if (!cond) - goto onerr; + if (cond) { + cond = process_condition(parser, cond, &ifnot); + if (!cond) + goto onerr; + } aloop = ast_loop_new(ctx, initexpr, cond, ifnot, NULL, false, increment, ontrue); *out = (ast_expression*)aloop; @@ -2337,15 +2330,57 @@ 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_NONE; for (;;) { - if (!strcmp(parser_tokval(parser), "const")) + 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; + } + } + else if (!strcmp(parser_tokval(parser), "noref")) { + 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")) had_var = true; @@ -2353,9 +2388,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 (!strcmp(parser_tokval(parser), "noreturn")) - had_noreturn = 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 @@ -2369,8 +2402,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"); @@ -2387,7 +2421,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); @@ -2439,19 +2473,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; } @@ -2464,11 +2498,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); @@ -2497,6 +2526,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 != ':') { @@ -2666,7 +2700,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; @@ -2686,15 +2720,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) { @@ -2923,7 +2957,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; @@ -3660,9 +3694,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; } } @@ -3950,7 +3984,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; @@ -3967,6 +4001,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) { @@ -4213,16 +4250,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; @@ -4364,7 +4440,6 @@ skipvar: } else if (parser->tok == '{' || parser->tok == '[') { - size_t i; if (localblock) { parseerror(parser, "cannot declare functions within functions"); break; @@ -4484,23 +4559,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) { @@ -4557,56 +4633,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; @@ -4652,7 +4728,7 @@ bool parser_compile() if (!parser_global_statement(parser)) { if (parser->tok == TOKEN_EOF) parseerror(parser, "unexpected eof"); - else if (!parser->errors) + else if (compile_errors) parseerror(parser, "there have been errors, bailing out"); lex_close(parser->lex); parser->lex = NULL; @@ -4669,7 +4745,7 @@ bool parser_compile() lex_close(parser->lex); parser->lex = NULL; - return !parser->errors; + return !compile_errors; } bool parser_compile_file(const char *filename) @@ -4682,7 +4758,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) { @@ -4692,16 +4768,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; @@ -4764,133 +4830,138 @@ bool parser_finish(const char *output) ir_builder *ir; bool retval = true; - if (!parser->errors) - { - ir = ir_builder_new("gmqcc_out"); - if (!ir) { - con_out("failed to allocate builder\n"); + if (compile_errors) { + con_out("*** there were compile errors\n"); + return false; + } + + ir = ir_builder_new("gmqcc_out"); + if (!ir) { + con_out("failed to allocate builder\n"); + return false; + } + + for (i = 0; i < vec_size(parser->fields); ++i) { + ast_value *field; + bool hasvalue; + if (!ast_istype(parser->fields[i], ast_value)) + continue; + field = (ast_value*)parser->fields[i]; + hasvalue = field->hasvalue; + field->hasvalue = false; + if (!ast_global_codegen((ast_value*)field, ir, true)) { + con_out("failed to generate field %s\n", field->name); + ir_builder_delete(ir); return false; } - - for (i = 0; i < vec_size(parser->fields); ++i) { - ast_value *field; - bool hasvalue; - if (!ast_istype(parser->fields[i], ast_value)) - continue; - field = (ast_value*)parser->fields[i]; - hasvalue = field->hasvalue; - field->hasvalue = false; - if (!ast_global_codegen((ast_value*)field, ir, true)) { - con_out("failed to generate field %s\n", field->name); - ir_builder_delete(ir); - return false; - } - if (hasvalue) { - ir_value *ifld; - ast_expression *subtype; - field->hasvalue = true; - subtype = field->expression.next; - ifld = ir_builder_create_field(ir, field->name, subtype->expression.vtype); - if (subtype->expression.vtype == TYPE_FIELD) - ifld->fieldtype = subtype->expression.next->expression.vtype; - else if (subtype->expression.vtype == TYPE_FUNCTION) - ifld->outtype = subtype->expression.next->expression.vtype; - (void)!ir_value_set_field(field->ir_v, ifld); - } - } - for (i = 0; i < vec_size(parser->globals); ++i) { - ast_value *asvalue; - if (!ast_istype(parser->globals[i], ast_value)) - continue; - asvalue = (ast_value*)(parser->globals[i]); - if (!asvalue->uses && !asvalue->hasvalue && asvalue->expression.vtype != TYPE_FUNCTION) { - retval = retval && !genwarning(ast_ctx(asvalue), WARN_UNUSED_VARIABLE, - "unused global: `%s`", asvalue->name); - } - if (!ast_global_codegen(asvalue, ir, false)) { - con_out("failed to generate global %s\n", asvalue->name); - ir_builder_delete(ir); - return false; - } + if (hasvalue) { + ir_value *ifld; + ast_expression *subtype; + field->hasvalue = true; + subtype = field->expression.next; + ifld = ir_builder_create_field(ir, field->name, subtype->expression.vtype); + if (subtype->expression.vtype == TYPE_FIELD) + ifld->fieldtype = subtype->expression.next->expression.vtype; + else if (subtype->expression.vtype == TYPE_FUNCTION) + ifld->outtype = subtype->expression.next->expression.vtype; + (void)!ir_value_set_field(field->ir_v, ifld); } - for (i = 0; i < vec_size(parser->imm_float); ++i) { - if (!ast_global_codegen(parser->imm_float[i], ir, false)) { - con_out("failed to generate global %s\n", parser->imm_float[i]->name); - ir_builder_delete(ir); - return false; - } + } + for (i = 0; i < vec_size(parser->globals); ++i) { + ast_value *asvalue; + if (!ast_istype(parser->globals[i], ast_value)) + continue; + asvalue = (ast_value*)(parser->globals[i]); + if (!asvalue->uses && !asvalue->hasvalue && asvalue->expression.vtype != TYPE_FUNCTION) { + retval = retval && !genwarning(ast_ctx(asvalue), WARN_UNUSED_VARIABLE, + "unused global: `%s`", asvalue->name); + } + if (!ast_global_codegen(asvalue, ir, false)) { + con_out("failed to generate global %s\n", asvalue->name); + ir_builder_delete(ir); + return false; } - for (i = 0; i < vec_size(parser->imm_string); ++i) { - if (!ast_global_codegen(parser->imm_string[i], ir, false)) { - con_out("failed to generate global %s\n", parser->imm_string[i]->name); - ir_builder_delete(ir); - return false; - } + } + for (i = 0; i < vec_size(parser->imm_float); ++i) { + if (!ast_global_codegen(parser->imm_float[i], ir, false)) { + con_out("failed to generate global %s\n", parser->imm_float[i]->name); + ir_builder_delete(ir); + return false; } - for (i = 0; i < vec_size(parser->imm_vector); ++i) { - if (!ast_global_codegen(parser->imm_vector[i], ir, false)) { - con_out("failed to generate global %s\n", parser->imm_vector[i]->name); - ir_builder_delete(ir); - return false; - } + } + for (i = 0; i < vec_size(parser->imm_string); ++i) { + if (!ast_global_codegen(parser->imm_string[i], ir, false)) { + con_out("failed to generate global %s\n", parser->imm_string[i]->name); + ir_builder_delete(ir); + return false; } - for (i = 0; i < vec_size(parser->globals); ++i) { - ast_value *asvalue; - if (!ast_istype(parser->globals[i], ast_value)) - continue; - asvalue = (ast_value*)(parser->globals[i]); - if (!ast_generate_accessors(asvalue, ir)) { - ir_builder_delete(ir); - return false; - } + } + for (i = 0; i < vec_size(parser->imm_vector); ++i) { + if (!ast_global_codegen(parser->imm_vector[i], ir, false)) { + con_out("failed to generate global %s\n", parser->imm_vector[i]->name); + ir_builder_delete(ir); + return false; + } + } + for (i = 0; i < vec_size(parser->globals); ++i) { + ast_value *asvalue; + if (!ast_istype(parser->globals[i], ast_value)) + continue; + asvalue = (ast_value*)(parser->globals[i]); + if (!ast_generate_accessors(asvalue, ir)) { + ir_builder_delete(ir); + return false; } - for (i = 0; i < vec_size(parser->fields); ++i) { - ast_value *asvalue; - asvalue = (ast_value*)(parser->fields[i]->expression.next); + } + for (i = 0; i < vec_size(parser->fields); ++i) { + ast_value *asvalue; + asvalue = (ast_value*)(parser->fields[i]->expression.next); - if (!ast_istype((ast_expression*)asvalue, ast_value)) - continue; - if (asvalue->expression.vtype != TYPE_ARRAY) - continue; - if (!ast_generate_accessors(asvalue, ir)) { - ir_builder_delete(ir); - return false; - } + if (!ast_istype((ast_expression*)asvalue, ast_value)) + continue; + if (asvalue->expression.vtype != TYPE_ARRAY) + continue; + if (!ast_generate_accessors(asvalue, ir)) { + ir_builder_delete(ir); + return false; } - for (i = 0; i < vec_size(parser->functions); ++i) { - if (!ast_function_codegen(parser->functions[i], ir)) { - con_out("failed to generate function %s\n", parser->functions[i]->name); - ir_builder_delete(ir); - return false; - } + } + for (i = 0; i < vec_size(parser->functions); ++i) { + if (!ast_function_codegen(parser->functions[i], ir)) { + con_out("failed to generate function %s\n", parser->functions[i]->name); + ir_builder_delete(ir); + return false; } - if (opts.dump) - ir_builder_dump(ir, con_out); - for (i = 0; i < vec_size(parser->functions); ++i) { - if (!ir_function_finalize(parser->functions[i]->ir_func)) { - con_out("failed to finalize function %s\n", parser->functions[i]->name); - ir_builder_delete(ir); - return false; - } + } + if (opts.dump) + ir_builder_dump(ir, con_out); + for (i = 0; i < vec_size(parser->functions); ++i) { + if (!ir_function_finalize(parser->functions[i]->ir_func)) { + con_out("failed to finalize function %s\n", parser->functions[i]->name); + ir_builder_delete(ir); + return false; } + } - if (retval) { - if (opts.dumpfin) - ir_builder_dump(ir, con_out); + if (compile_Werrors) { + con_out("*** there were warnings treated as errors\n"); + compile_show_werrors(); + retval = false; + } - generate_checksum(parser); + if (retval) { + if (opts.dumpfin) + ir_builder_dump(ir, con_out); - if (!ir_builder_generate(ir, output)) { - con_out("*** failed to generate output file\n"); - ir_builder_delete(ir); - return false; - } - } + generate_checksum(parser); - ir_builder_delete(ir); - return retval; + if (!ir_builder_generate(ir, output)) { + con_out("*** failed to generate output file\n"); + ir_builder_delete(ir); + return false; + } } - con_out("*** there were compile errors\n"); - return false; + ir_builder_delete(ir); + return retval; }