X-Git-Url: https://git.xonotic.org/?p=xonotic%2Fgmqcc.git;a=blobdiff_plain;f=parser.c;h=eac983ee3b643259f3ffb92b482febae4ffea749;hp=27c694d406955059e8400eb121c4dfb223734186;hb=7a36a8bdd8f7d6a17b0fde0e5b3f6da5dd80b0a3;hpb=9167de1631b078c44ac5d03e135d291ffb0a965a diff --git a/parser.c b/parser.c index 27c694d..eac983e 100644 --- a/parser.c +++ b/parser.c @@ -21,8 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -#include -#include +#include #include #include "gmqcc.h" @@ -39,6 +38,8 @@ typedef struct parser_s { lex_file *lex; int tok; + bool ast_cleaned; + ast_expression **globals; ast_expression **fields; ast_function **functions; @@ -266,6 +267,7 @@ static ast_value* parser_const_string(parser_t *parser, const char *str, bool do 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; } return out; } @@ -279,6 +281,7 @@ static ast_value* parser_const_string(parser_t *parser, const char *str, bool do char name[32]; util_snprintf(name, sizeof(name), "dotranslate_%lu", (unsigned long)(parser->translated++)); out = ast_value_new(parser_ctx(parser), name, TYPE_STRING); + out->expression.flags |= AST_FLAG_INCLUDE_DEF; } else out = ast_value_new(parser_ctx(parser), "#IMMEDIATE", TYPE_STRING); out->cvq = CV_CONST; @@ -2955,6 +2958,11 @@ static bool parse_return(parser_t *parser, ast_block *block, ast_expression **ou return false; } + if (parser->tok != ';') + parseerror(parser, "missing semicolon after return assignment"); + else if (!parser_next(parser)) + parseerror(parser, "parse error after return assignment"); + *out = var; return true; } @@ -4786,6 +4794,7 @@ static ast_value *parse_parameter_list(parser_t *parser, ast_value *var) /* for the sake of less code we parse-in in this function */ if (!parser_next(parser)) { + ast_delete(var); parseerror(parser, "expected parameter list"); return NULL; } @@ -5053,6 +5062,7 @@ static ast_value *parse_typename(parser_t *parser, ast_value **storebase, ast_va /* parse on */ if (!parser_next(parser)) { ast_delete(var); + mem_d(name); parseerror(parser, "error after variable or field declaration"); return NULL; } @@ -5062,8 +5072,10 @@ static ast_value *parse_typename(parser_t *parser, ast_value **storebase, ast_va if (parser->tok == '[') { wasarray = true; var = parse_arraysize(parser, var); - if (!var) + if (!var) { + if (name) mem_d(name); return NULL; + } } /* This is the point where we can turn it into a field */ @@ -5082,8 +5094,7 @@ static ast_value *parse_typename(parser_t *parser, ast_value **storebase, ast_va while (parser->tok == '(') { var = parse_parameter_list(parser, var); if (!var) { - if (name) - mem_d((void*)name); + if (name) mem_d(name); return NULL; } } @@ -5092,11 +5103,12 @@ static ast_value *parse_typename(parser_t *parser, ast_value **storebase, ast_va if (name) { if (!ast_value_set_name(var, name)) { ast_delete(var); + mem_d(name); parseerror(parser, "internal error: failed to set name"); return NULL; } /* free the name, ast_value_set_name duplicates */ - mem_d((void*)name); + mem_d(name); } return var; @@ -5180,6 +5192,43 @@ static bool parser_check_qualifiers(parser_t *parser, const ast_value *var, cons return true; } +static bool parse_array(parser_t *parser, ast_value *array) +{ + if (!parser_next(parser)) { + parseerror(parser, "parse error in array initializer"); + return false; + } + while (parser->tok != '}') { + ast_value *v = (ast_value*)parse_expression_leave(parser, true, false, false); + if (!v) + return false; + if (!ast_istype(v, ast_value) || !v->hasvalue || v->cvq != CV_CONST) { + ast_unref(v); + parseerror(parser, "initializing element must be a compile time constant"); + return false; + } + vec_push(array->initlist, v->constval); + ast_unref(v); + if (parser->tok == '}') + break; + if (parser->tok != ',' || !parser_next(parser)) { + parseerror(parser, "expected comma or '}' in element list"); + return false; + } + } + if (!parser_next(parser) || parser->tok != ';') { + parseerror(parser, "expected semicolon after initializer, got %s"); + return false; + } + /* + if (!parser_next(parser)) { + parseerror(parser, "parse error after initializer"); + return false; + } + */ + return true; +} + static bool parse_variable(parser_t *parser, ast_block *localblock, bool nofields, int qualifier, ast_value *cached_typedef, bool noref, bool is_static, uint32_t qflags, char *vstring) { ast_value *var; @@ -5791,11 +5840,9 @@ skipvar: parseerror(parser, "TODO: initializers for local arrays"); break; } - /* -static ast_expression* parse_expression_leave(parser_t *parser, bool stopatcomma, bool truthvalue, bool with_labels); -*/ - parseerror(parser, "TODO: initializing global arrays is not supported yet!"); - break; + + if (!parse_array(parser, var)) + break; } else if (var->expression.vtype == TYPE_FUNCTION && (parser->tok == '{' || parser->tok == '[')) { @@ -6178,9 +6225,12 @@ bool parser_compile_string(parser_t *parser, const char *name, const char *str, return parser_compile(parser); } -void parser_cleanup(parser_t *parser) +static void parser_remove_ast(parser_t *parser) { size_t i; + if (parser->ast_cleaned) + return; + parser->ast_cleaned = true; for (i = 0; i < vec_size(parser->accessors); ++i) { ast_delete(parser->accessors[i]->constval.vfunc); parser->accessors[i]->constval.vfunc = NULL; @@ -6249,9 +6299,12 @@ void parser_cleanup(parser_t *parser) ast_value_delete(parser->const_vec[2]); util_htdel(parser->aliases); - intrin_intrinsics_destroy(parser); +} +void parser_cleanup(parser_t *parser) +{ + parser_remove_ast(parser); code_cleanup(parser->code); mem_d(parser); @@ -6410,6 +6463,8 @@ bool parser_finish(parser_t *parser, const char *output) return false; } } + + generate_checksum(parser); if (OPTS_OPTION_BOOL(OPTION_DUMP)) ir_builder_dump(ir, con_out); for (i = 0; i < vec_size(parser->functions); ++i) { @@ -6419,6 +6474,7 @@ bool parser_finish(parser_t *parser, const char *output) return false; } } + parser_remove_ast(parser); if (compile_Werrors) { con_out("*** there were warnings treated as errors\n"); @@ -6430,15 +6486,12 @@ bool parser_finish(parser_t *parser, const char *output) if (OPTS_OPTION_BOOL(OPTION_DUMPFIN)) ir_builder_dump(ir, con_out); - generate_checksum(parser); - if (!ir_builder_generate(parser->code, ir, output)) { con_out("*** failed to generate output file\n"); ir_builder_delete(ir); return false; } } - ir_builder_delete(ir); return retval; }