From 0e4e81d94f0ad27b9f5d3f105495c45ef0aae8f4 Mon Sep 17 00:00:00 2001 From: "Wolfgang (Blub) Bumiller" Date: Tue, 4 Dec 2012 12:12:45 +0100 Subject: [PATCH] Parsing the 'noref' keyword; this also gets rid of some code duplication --- gmqcc.h | 2 + parser.c | 171 ++++++++++++++++++++++++------------------------------- 2 files changed, 77 insertions(+), 96 deletions(-) diff --git a/gmqcc.h b/gmqcc.h index c7d034e..34367b8 100644 --- a/gmqcc.h +++ b/gmqcc.h @@ -341,6 +341,8 @@ enum { #define CV_NONE 0 #define CV_CONST 1 #define CV_VAR -1 +/* magic number to help parsing */ +#define CV_WRONG 0x8000 extern const char *type_name [TYPE_COUNT]; extern size_t type_sizeof [TYPE_COUNT]; diff --git a/parser.c b/parser.c index 5f2f7da..8001ffa 100644 --- a/parser.c +++ b/parser.c @@ -102,7 +102,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); +static bool parse_variable(parser_t *parser, ast_block *localblock, bool nofields, int qualifier, ast_value *cached_typedef, bool noref); 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); @@ -2031,7 +2031,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)) + if (!parse_variable(parser, block, true, CV_VAR, typevar, false)) goto onerr; } else if (parser->tok != ';') @@ -2168,6 +2168,46 @@ static bool parse_break_continue(parser_t *parser, ast_block *block, ast_express return true; } +/* 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 had_const = false; + bool had_var = false; + bool had_noref = false; + + for (;;) { + if (!strcmp(parser_tokval(parser), "const")) + had_const = true; + else if (!strcmp(parser_tokval(parser), "var")) + had_var = true; + else if (with_local && !strcmp(parser_tokval(parser), "local")) + had_var = true; + else if (!strcmp(parser_tokval(parser), "noref")) + had_noref = true; + else if (!had_const && !had_var && !had_noref) { + return false; + } + else + break; + if (!parser_next(parser)) + goto onerr; + } + if (had_const) + *cvq = CV_CONST; + else if (had_var) + *cvq = CV_VAR; + else + *cvq = CV_NONE; + *noref = had_noref; + return true; +onerr: + parseerror(parser, "parse error after variable qualifier"); + *cvq = CV_WRONG; + return true; +} + static bool parse_switch(parser_t *parser, ast_block *block, ast_expression **out) { ast_expression *operand; @@ -2176,6 +2216,9 @@ static bool parse_switch(parser_t *parser, ast_block *block, ast_expression **ou ast_switch *switchnode; ast_switch_case swcase; + int cvq; + bool noref; + lex_ctx ctx = parser_ctx(parser); (void)block; /* not touching */ @@ -2226,40 +2269,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)) { + if (!parse_variable(parser, block, false, CV_NONE, typevar, false)) { ast_delete(switchnode); return false; } continue; } - if (!strcmp(parser_tokval(parser), "var") || - !strcmp(parser_tokval(parser), "local")) + if (parse_var_qualifiers(parser, true, &cvq, &noref)) { - if (!parser_next(parser)) { - parseerror(parser, "expected variable declaration"); + if (cvq == CV_WRONG) { ast_delete(switchnode); return false; } - if (!parse_variable(parser, block, false, CV_VAR, NULL)) { - ast_delete(switchnode); - return false; - } - continue; - } - if (!strcmp(parser_tokval(parser), "const")) { - if (!parser_next(parser)) { - parseerror(parser, "expected variable declaration"); - ast_delete(switchnode); - return false; - } - if (!strcmp(parser_tokval(parser), "var")) { - if (!parser_next(parser)) { - parseerror(parser, "expected variable declaration"); - ast_delete(switchnode); - return false; - } - } - if (!parse_variable(parser, block, false, CV_CONST, NULL)) { + if (!parse_variable(parser, block, false, cvq, NULL, noref)) { ast_delete(switchnode); return false; } @@ -2472,8 +2494,10 @@ static bool parse_pragma(parser_t *parser) static bool parse_statement(parser_t *parser, ast_block *block, ast_expression **out, bool allow_cases) { - int cvq; + bool noref; + int cvq = CV_NONE; ast_value *typevar = NULL; + *out = NULL; if (parser->tok == TOKEN_IDENT) @@ -2490,43 +2514,19 @@ 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)) + if (!parse_variable(parser, block, false, CV_NONE, typevar, false)) return false; - *out = NULL; return true; } - else if (parser->tok == TOKEN_IDENT && !strcmp(parser_tokval(parser), "var")) + else if (parse_var_qualifiers(parser, !!block, &cvq, &noref)) { - goto ident_var; + if (cvq == CV_WRONG) + return false; + return parse_variable(parser, block, true, cvq, NULL, noref); } else if (parser->tok == TOKEN_KEYWORD) { - if (!strcmp(parser_tokval(parser), "local") || - !strcmp(parser_tokval(parser), "const") || - !strcmp(parser_tokval(parser), "var")) - { -ident_var: - if (parser_tokval(parser)[0] == 'c') - cvq = CV_CONST; - else if (parser_tokval(parser)[0] == 'v') - cvq = CV_VAR; - else - cvq = CV_NONE; - - if (!block) { - parseerror(parser, "cannot declare a local variable here"); - return false; - } - if (!parser_next(parser)) { - parseerror(parser, "expected variable declaration"); - return false; - } - if (!parse_variable(parser, block, true, cvq, NULL)) - return false; - *out = NULL; - return true; - } - else if (!strcmp(parser_tokval(parser), "__builtin_debug_printtype")) + if (!strcmp(parser_tokval(parser), "__builtin_debug_printtype")) { char ty[1024]; ast_value *tdef; @@ -3761,7 +3761,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) +static bool parse_variable(parser_t *parser, ast_block *localblock, bool nofields, int qualifier, ast_value *cached_typedef, bool noref) { ast_value *var; ast_value *proto; @@ -3825,6 +3825,9 @@ static bool parse_variable(parser_t *parser, ast_block *localblock, bool nofield } var->cvq = qualifier; + /* in a noref section we simply bump the usecount */ + if (noref || parser->noref) + var->uses++; /* Part 1: * check for validity: (end_sys_..., multiple-definitions, prototypes, ...) @@ -3835,10 +3838,12 @@ static bool parse_variable(parser_t *parser, ast_block *localblock, bool nofield /* Deal with end_sys_ vars */ was_end = false; if (!strcmp(var->name, "end_sys_globals")) { + var->uses++; parser->crc_globals = vec_size(parser->globals); was_end = true; } else if (!strcmp(var->name, "end_sys_fields")) { + var->uses++; parser->crc_fields = vec_size(parser->fields); was_end = true; } @@ -4287,48 +4292,26 @@ cleanup: static bool parser_global_statement(parser_t *parser) { + int cvq = CV_WRONG; + bool noref = 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); + return parse_variable(parser, NULL, false, CV_NONE, istype, false); } - else if (parser->tok == TOKEN_IDENT && !strcmp(parser_tokval(parser), "var")) + else if (parse_var_qualifiers(parser, false, &cvq, &noref)) { - if (!strcmp(parser_tokval(parser), "var")) { - if (!parser_next(parser)) { - parseerror(parser, "expected variable declaration after 'var'"); - return false; - } - if (parser->tok == TOKEN_KEYWORD && !strcmp(parser_tokval(parser), "const")) { - (void)!parsewarning(parser, WARN_CONST_VAR, "ignoring `const` after 'var' qualifier"); - if (!parser_next(parser)) { - parseerror(parser, "expected variable declaration after 'const var'"); - return false; - } - } - return parse_variable(parser, NULL, true, CV_VAR, NULL); - } + if (cvq == CV_WRONG) + return false; + return parse_variable(parser, NULL, true, cvq, NULL, noref); } else if (parser->tok == TOKEN_KEYWORD) { - if (!strcmp(parser_tokval(parser), "const")) { - if (!parser_next(parser)) { - parseerror(parser, "expected variable declaration after 'const'"); - return false; - } - if (parser->tok == TOKEN_IDENT && !strcmp(parser_tokval(parser), "var")) { - (void)!parsewarning(parser, WARN_CONST_VAR, "ignoring `var` after const qualifier"); - if (!parser_next(parser)) { - parseerror(parser, "expected variable declaration after 'const var'"); - return false; - } - } - return parse_variable(parser, NULL, true, CV_CONST, NULL); - } - else if (!strcmp(parser_tokval(parser), "typedef")) { + if (!strcmp(parser_tokval(parser), "typedef")) { if (!parser_next(parser)) { parseerror(parser, "expected type definition after 'typedef'"); return false; @@ -4628,12 +4611,8 @@ bool parser_finish(const char *output) continue; asvalue = (ast_value*)(parser->globals[i]); if (!asvalue->uses && !asvalue->hasvalue && asvalue->expression.vtype != TYPE_FUNCTION) { - 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); - } + 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);