diff --git a/tools/qfcc/include/function.h b/tools/qfcc/include/function.h index 24f87cd19..38e624d24 100644 --- a/tools/qfcc/include/function.h +++ b/tools/qfcc/include/function.h @@ -212,14 +212,12 @@ function_t *make_function (symbol_t *sym, const char *nice_name, enum storage_class_e storage); symbol_t *function_symbol (specifier_t spec); const expr_t *find_function (const expr_t *fexpr, const expr_t *params); -function_t *begin_function (symbol_t *sym, const char *nicename, - symtab_t *parent, int far, - enum storage_class_e storage); -function_t *build_code_function (symbol_t *fsym, const expr_t *state_expr, - expr_t *statements, rua_ctx_t *ctx); -function_t *build_builtin_function (symbol_t *sym, const char *ext_name, - const expr_t *bi_val, int far, - enum storage_class_e storage); +function_t *begin_function (specifier_t spec, const char *nicename, + symtab_t *parent); +void build_code_function (specifier_t spec, const expr_t *state_expr, + expr_t *statements, rua_ctx_t *ctx); +void build_builtin_function (specifier_t spec, const char *ext_name, + const expr_t *bi_val); void build_intrinsic_function (specifier_t spec, const expr_t *intrinsic); void emit_function (function_t *f, expr_t *e); void clear_functions (void); diff --git a/tools/qfcc/include/rua-lang.h b/tools/qfcc/include/rua-lang.h index de3fbb92b..630c43eb1 100644 --- a/tools/qfcc/include/rua-lang.h +++ b/tools/qfcc/include/rua-lang.h @@ -84,6 +84,7 @@ typedef struct rua_tok_s { typedef struct { symtab_t *symtab; function_t *function; + specifier_t spec; } funcstate_t; typedef union rua_val_s { diff --git a/tools/qfcc/include/specifier.h b/tools/qfcc/include/specifier.h index bcc0ce8a9..95f99f047 100644 --- a/tools/qfcc/include/specifier.h +++ b/tools/qfcc/include/specifier.h @@ -81,6 +81,7 @@ typedef struct specifier_s { bool is_generic:1; bool is_generic_block:1; bool is_function:1;//FIXME do proper void(*)() -> ev_func + bool is_far:1; }; unsigned spec_bits; }; diff --git a/tools/qfcc/include/symtab.h b/tools/qfcc/include/symtab.h index 1f31be573..921ad65db 100644 --- a/tools/qfcc/include/symtab.h +++ b/tools/qfcc/include/symtab.h @@ -107,6 +107,7 @@ typedef enum { stab_enum, stab_label, stab_block, + stab_bypass, ///< symbols are added to parent } stab_type_e; typedef struct symtab_s { diff --git a/tools/qfcc/source/function.c b/tools/qfcc/source/function.c index 8a1474197..48f9c167f 100644 --- a/tools/qfcc/source/function.c +++ b/tools/qfcc/source/function.c @@ -1010,11 +1010,19 @@ value_too_large (const type_t *val_type) static void check_function (symbol_t *fsym) { + function_t *func = fsym->metafunc->func; param_t *params = fsym->params; param_t *p; int i; auto ret_type = fsym->type->func.ret_type; + if (!func) { + internal_error (0, "function %s not defined", fsym->name); + } + if (!is_func (func->type)) { + internal_error (0, "function type %s not a funciton", fsym->name); + } + if (!ret_type || !type_size (ret_type)) { error (0, "return type is an incomplete type"); return; @@ -1048,15 +1056,6 @@ build_scope (symbol_t *fsym, symtab_t *parent) symtab_t *parameters; symtab_t *locals; - if (!func) { - internal_error (0, "function %s not defined", fsym->name); - } - if (!is_func (func->type)) { - internal_error (0, "function type %s not a funciton", fsym->name); - } - - check_function (fsym); - func->label_scope = new_symtab (0, stab_label); parameters = new_symtab (parent, stab_param); @@ -1122,9 +1121,9 @@ add_function (function_t *f) } function_t * -begin_function (symbol_t *sym, const char *nicename, symtab_t *parent, - int far, storage_class_t storage) +begin_function (specifier_t spec, const char *nicename, symtab_t *parent) { + auto sym = spec.sym; if (sym->sy_type != sy_func) { error (0, "%s is not a function", sym->name); sym = new_symbol_type (sym->name, &type_func); @@ -1143,9 +1142,9 @@ begin_function (symbol_t *sym, const char *nicename, symtab_t *parent, }); } - defspace_t *space = far ? pr.far_data : sym->table->space; + defspace_t *space = spec.is_far ? pr.far_data : sym->table->space; - func = make_function (sym, nicename, space, storage); + func = make_function (sym, nicename, space, spec.storage); if (!func->def->external) { func->def->initialized = 1; func->def->constant = 1; @@ -1163,6 +1162,8 @@ begin_function (symbol_t *sym, const char *nicename, symtab_t *parent, func->line_info = lineno - pr.linenos; } + check_function (sym); + build_scope (sym, parent); return func; } @@ -1177,58 +1178,60 @@ build_function (symbol_t *fsym) } } -function_t * -build_code_function (symbol_t *fsym, const expr_t *state_expr, +void +build_code_function (specifier_t spec, const expr_t *state_expr, expr_t *statements, rua_ctx_t *ctx) { + auto fsym = spec.sym; if (ctx) { statements = (expr_t *) expr_process (statements, ctx); } - if (fsym->sy_type != sy_func) // probably in error recovery - return 0; + if (fsym->sy_type != sy_func) { // probably in error recovery + return; + } build_function (fsym); if (state_expr) { prepend_expr (statements, state_expr); } function_t *func = fsym->metafunc->func; current_target.build_code (func, statements); - - return fsym->metafunc->func; } -function_t * -build_builtin_function (symbol_t *sym, const char *ext_name, - const expr_t *bi_val, int far, storage_class_t storage) +void +build_builtin_function (specifier_t spec, const char *ext_name, + const expr_t *bi_val) { + auto sym = spec.sym; int bi; if (sym->sy_type != sy_func) { error (bi_val, "%s is not a function", sym->name); - return 0; + return; } if (!is_int_val (bi_val) && !(type_default != &type_int && is_float_val (bi_val))) { error (bi_val, "invalid constant for = #"); - return 0; + return; } if (sym->metafunc->meta_type == mf_generic) { - return 0; + return; } function_t *func = sym->metafunc->func; if (func && func->def && func->def->initialized) { error (bi_val, "%s redefined", sym->name); - return 0; + return; } - defspace_t *space = far ? pr.far_data : sym->table->space; - func = make_function (sym, nullptr, space, storage); + defspace_t *space = spec.is_far ? pr.far_data : sym->table->space; + func = make_function (sym, nullptr, space, spec.storage); if (ext_name) { func->s_name = ReuseString (ext_name); } - if (func->def->external) - return 0; + if (func->def->external) { + return; + } func->def->initialized = 1; func->def->constant = 1; @@ -1245,17 +1248,18 @@ build_builtin_function (symbol_t *sym, const char *ext_name, } if (bi < 0) { error (bi_val, "builtin functions must be positive or 0"); - return 0; + return; } func->builtin = bi; reloc_def_func (func, func->def); build_function (sym); + check_function (sym); + // for debug info build_scope (sym, current_symtab); func->parameters->space->size = 0; func->locals->space = func->parameters->space; - return func; } void @@ -1315,8 +1319,12 @@ emit_ctor (void) return; } - auto ctor_sym = new_symbol_type (".ctor", &type_func); - ctor_sym = function_symbol ((specifier_t) { .sym = ctor_sym }); - current_func = begin_function (ctor_sym, 0, current_symtab, 1, sc_static); - build_code_function (ctor_sym, 0, pr.ctor_exprs, nullptr); + auto spec = (specifier_t) { + .sym = new_symbol_type (".ctor", &type_func), + .storage = sc_static, + .is_far = true, + }; + spec.sym = function_symbol (spec); + current_func = begin_function (spec, nullptr, current_symtab); + build_code_function (spec, 0, pr.ctor_exprs, nullptr); } diff --git a/tools/qfcc/source/glsl-builtins.c b/tools/qfcc/source/glsl-builtins.c index 7e1dc21e7..87028c31b 100644 --- a/tools/qfcc/source/glsl-builtins.c +++ b/tools/qfcc/source/glsl-builtins.c @@ -437,9 +437,11 @@ SRC_LINE "genUType clamp(genUType x, genUType minVal, genUType maxVal);" "\n" "genUType clamp(genUType x, uint minVal, uint maxVal);" "\n" "genFType mix(genFType x, genFType y, genFType a) = " GLSL(46) ";" "\n" -"genFType mix(genFType x, genFType y, float a) = " GLSL(46) ";" "\n" +"genFType mix(genFType x, genFType y, float a)" "\n" +"{ return mix (x, y, (genFType) a); }" "\n" "genDType mix(genDType x, genDType y, genDType a) = " GLSL(46) ";" "\n" -"genDType mix(genDType x, genDType y, double a) = " GLSL(46) ";" "\n" +"genDType mix(genDType x, genDType y, double a)" "\n" +"{ return mix (x, y, (genDType) a); }" "\n" "genFType mix(genFType x, genFType y, genBType a) = " SPV(169) ";" "\n" "genDType mix(genDType x, genDType y, genBType a) = " SPV(169) ";" "\n" "genIType mix(genIType x, genIType y, genBType a) = " SPV(169) ";" "\n" diff --git a/tools/qfcc/source/glsl-parse.y b/tools/qfcc/source/glsl-parse.y index ce49fdf4b..32ccd1238 100644 --- a/tools/qfcc/source/glsl-parse.y +++ b/tools/qfcc/source/glsl-parse.y @@ -332,19 +332,16 @@ function_definition auto spec = $1; spec.sym->params = spec.params; spec.is_overload = true; - auto sym = function_symbol (spec); - current_func = begin_function (sym, nullptr, current_symtab, - false, spec.storage); + spec.sym = function_symbol (spec); + current_func = begin_function (spec, nullptr, current_symtab); current_symtab = current_func->locals; current_storage = sc_local; - spec.sym = sym; $1 = spec; } compound_statement_no_new_scope { auto spec = $1; - auto sym = spec.sym; - build_code_function (sym, nullptr, (expr_t *) $3, ctx); + build_code_function (spec, nullptr, (expr_t *) $3, ctx); current_symtab = $2; current_storage = sc_global;//FIXME current_func = nullptr; diff --git a/tools/qfcc/source/qc-parse.y b/tools/qfcc/source/qc-parse.y index 27b6c44e9..44606b544 100644 --- a/tools/qfcc/source/qc-parse.y +++ b/tools/qfcc/source/qc-parse.y @@ -257,8 +257,12 @@ static expr_t *local_expr; static void end_generic_scope (void) { - generic_scope = false; + if (generic_symtab != current_symtab || !generic_symtab->parent) { + internal_error (0, "scope stack tangled?"); + } + current_symtab = generic_symtab->parent; generic_symtab = nullptr; + generic_scope = false; } static void @@ -662,6 +666,23 @@ decl_expr (specifier_t spec, const expr_t *init, rua_ctx_t *ctx) return append_decl (decl, sym, init); } +static symtab_t * +pop_scope (symtab_t *current) +{ + auto parent = current->parent; + if (!parent) { + internal_error (0, "scope stack underflow"); + } + if (parent->type == stab_bypass) { + if (!parent->parent) { + internal_error (0, "bypass scope with no parent"); + } + // reconnect the current scope to the parent of the bypassed scope + current->parent = parent->parent; + } + return parent; +} + %} %expect 2 @@ -681,7 +702,7 @@ program external_def_list : /* empty */ { - if (!generic_block) { + if (!current_symtab) { current_symtab = pr.symtab; } } @@ -832,8 +853,8 @@ qc_nocode_func const expr_t *bi_val = expr_process ($4, ctx); spec.is_overload |= ctx->language->always_overload; - symbol_t *sym = function_symbol (spec); - build_builtin_function (sym, nullptr, bi_val, 0, spec.storage); + spec.sym = function_symbol (spec); + build_builtin_function (spec, nullptr, bi_val); } | identifier '=' intrinsic { @@ -858,24 +879,24 @@ qc_code_func : identifier '=' optional_state_expr save_storage { - $$ = (funcstate_t) { - .symtab = current_symtab, + specifier_t spec = qc_set_symbol ($0, $1); + auto fs = (funcstate_t) { .function = current_func, }; - specifier_t spec = qc_set_symbol ($0, $1); spec.is_overload |= ctx->language->always_overload; - symbol_t *sym = function_symbol (spec); - current_func = begin_function (sym, 0, current_symtab, 0, - spec.storage); + spec.sym = function_symbol (spec); + current_func = begin_function (spec, nullptr, current_symtab); current_symtab = current_func->locals; current_storage = sc_local; - $1 = sym; + fs.spec = spec; + $$ = fs; } compound_statement_ns { - build_code_function ($1, $3, $6, ctx); - current_symtab = $5.symtab; - current_func = $5.function; + auto fs = $5; + build_code_function (fs.spec, $3, $6, ctx); + current_symtab = pop_scope (current_func->parameters); + current_func = fs.function; restore_storage ($4); } ; @@ -1171,29 +1192,34 @@ save_storage ; function_body - : method_optional_state_expr + : method_optional_state_expr[state] { - specifier_t spec = default_type ($0, $0.sym); + specifier_t spec = $0; + if (!spec.is_generic) { + spec = default_type (spec, spec.sym); + } spec.is_overload |= ctx->language->always_overload; - $$ = function_symbol (spec); + spec.sym = function_symbol (spec); + $$ = spec; } - save_storage + save_storage[storage] { $$ = (funcstate_t) { - .symtab = current_symtab, .function = current_func, }; - current_func = begin_function ($2, 0, current_symtab, 0, - $-1.storage); + auto spec = $2; + current_func = begin_function (spec, nullptr, current_symtab); current_symtab = current_func->locals; current_storage = sc_local; } - compound_statement_ns + compound_statement_ns[body] { - build_code_function ($2, $1, $5, ctx); - current_symtab = $4.symtab; - current_func = $4.function; - restore_storage ($3); + auto spec = $2; + auto funcstate = $4; + build_code_function (spec, $state, $body, ctx); + current_symtab = pop_scope (current_func->parameters); + current_func = funcstate.function; + restore_storage ($storage); } | '=' '#' expr ';' { @@ -1201,8 +1227,8 @@ function_body const expr_t *bi_val = expr_process ($3, ctx); spec.is_overload |= ctx->language->always_overload; - symbol_t *sym = function_symbol (spec); - build_builtin_function (sym, nullptr, bi_val, 0, spec.storage); + spec.sym = function_symbol (spec); + build_builtin_function (spec, nullptr, bi_val); } | '=' intrinsic { @@ -1232,6 +1258,9 @@ storage_class } else { generic_scope = true; } + generic_symtab->type = stab_bypass; + generic_symtab->parent = current_symtab; + current_symtab = generic_symtab; } | ATTRIBUTE '(' attribute_list ')' { @@ -1380,7 +1409,7 @@ optional_enum_list enum_list : '{' enum_init enumerator_list optional_comma '}' { - current_symtab = current_symtab->parent; + current_symtab = pop_scope (current_symtab); $$ = finish_enum ($3); } ; @@ -1467,7 +1496,7 @@ struct_list { symbol_t *sym; symtab_t *symtab = current_symtab; - current_symtab = symtab->parent; + current_symtab = pop_scope (symtab); if ($1) { sym = $2; @@ -1841,7 +1870,7 @@ end_scope : /* empty */ { if (!options.traditional) { - current_symtab = current_symtab->parent; + current_symtab = pop_scope (current_symtab); } } ; @@ -1980,7 +2009,7 @@ statement } compound_statement { - current_symtab = current_symtab->parent; + current_symtab = pop_scope (current_symtab); $$ = $9; } | ALGEBRA '(' TYPE_SPEC ')' @@ -1990,7 +2019,7 @@ statement } compound_statement { - current_symtab = current_symtab->parent; + current_symtab = pop_scope (current_symtab); $$ = $6; } | ALGEBRA '(' TYPE_NAME ')' @@ -2000,7 +2029,7 @@ statement } compound_statement { - current_symtab = current_symtab->parent; + current_symtab = pop_scope (current_symtab); $$ = $6; } | comma_expr ';' @@ -2523,7 +2552,7 @@ ivar_decl_list { symtab_t *tab = $1; $$ = current_symtab; - current_symtab = tab->parent; + current_symtab = pop_scope (tab); tab->parent = 0; tab = $$->parent; // preserve the ivars inheritance chain @@ -2615,14 +2644,18 @@ methoddef symbol_t *sym = $4; symtab_t *ivar_scope; - $$ = (funcstate_t) { - .symtab = current_symtab, - .function = current_func, + auto spec = (specifier_t) { + .sym = sym, + .storage = sc_static, + .is_far = true, }; ivar_scope = class_ivar_scope (current_class, current_symtab); - current_func = begin_function (sym, nicename, ivar_scope, 1, - sc_static); + $$ = (funcstate_t) { + .symtab = ivar_scope, + .function = current_func, + }; + current_func = begin_function (spec, nicename, ivar_scope); class_finish_ivar_scope (current_class, ivar_scope, current_func->locals); method->func = sym->metafunc->func; @@ -2632,22 +2665,29 @@ methoddef } compound_statement_ns { - build_code_function ($4, $3, $7, ctx); - current_symtab = $6.symtab; - current_func = $6.function; + auto fs = $6; + auto fsym = $4; + fs.spec.sym = fsym; + build_code_function (fs.spec, $3, $7, ctx); + current_symtab = pop_scope (fs.symtab); + current_func = fs.function; restore_storage ($5); } | ci methoddecl '=' '#' const ';' { - symbol_t *sym; method_t *method = $2; const expr_t *bi_val = expr_process ($5, ctx); method->instance = $1; method = class_find_method (current_class, method); - sym = method_symbol (current_class, method); - build_builtin_function (sym, nullptr, bi_val, 1, sc_static); - method->func = sym->metafunc->func; + + auto spec = (specifier_t) { + .sym = method_symbol (current_class, method), + .storage = sc_static, + .is_far = true, + }; + build_builtin_function (spec, nullptr, bi_val); + method->func = spec.sym->metafunc->func; method->def = method->func->def; } ; @@ -3127,9 +3167,6 @@ qc_keyword_or_id (QC_YYSTYPE *lval, const char *token, rua_ctx_t *ctx) } symbol_t *sym = nullptr; - if (generic_symtab) { - sym = symtab_lookup (generic_symtab, token); - } if (!sym) { sym = symtab_lookup (current_symtab, token); } diff --git a/tools/qfcc/source/qp-parse.y b/tools/qfcc/source/qp-parse.y index 0b091d773..a988b2902 100644 --- a/tools/qfcc/source/qp-parse.y +++ b/tools/qfcc/source/qp-parse.y @@ -161,14 +161,17 @@ build_dotmain (symbol_t *program, rua_ctx_t *ctx) exitcode = new_symbol_expr (symtab_lookup (current_symtab, "ExitCode")); - current_func = begin_function (dotmain, 0, current_symtab, 0, - current_storage); + auto spec = (specifier_t) { + .sym = dotmain, + .storage = current_storage, + }; + current_func = begin_function (spec, nullptr, current_symtab); code = new_block_expr (0); code->block.scope = current_func->locals; auto call = new_call_expr (new_symbol_expr (program), nullptr, nullptr); append_expr (code, call); append_expr (code, new_return_expr (exitcode)); - build_code_function (dotmain, 0, code, ctx); + build_code_function (spec, 0, code, ctx); } static const expr_t * @@ -281,10 +284,13 @@ program symtab_removesymbol (current_symtab, $1); symtab_addsymbol (current_symtab, $1); - current_func = begin_function ($1, 0, current_symtab, 0, - current_storage); + auto spec = (specifier_t) { + .sym = $1, + .storage = current_storage, + }; + current_func = begin_function (spec, nullptr, current_symtab); current_symtab = current_func->locals; - build_code_function ($1, 0, $4, ctx); + build_code_function (spec, 0, $4, ctx); current_symtab = st; build_dotmain ($1, ctx); @@ -367,25 +373,25 @@ subprogram_declarations subprogram_declaration : subprogram_head ';' { - $$.storage = current_storage; auto sym = $1; // always an sy_xvalue with callable symbol in lvalue and // actual function symbol in rvalue auto csym = (symbol_t *) sym->xvalue.lvalue; auto fsym = (symbol_t *) sym->xvalue.rvalue; - current_func = begin_function (fsym, sym->name, current_symtab, 0, - current_storage); + auto spec = (specifier_t) { + .sym = fsym, + .storage = current_storage, + }; + current_func = begin_function (spec, sym->name, current_symtab); current_symtab = current_func->locals; current_storage = sc_local; // null for procedures, valid symbol expression for functions csym->xvalue.lvalue = function_return (current_func); + $$ = spec; } declarations compound_statement ';' { - auto sym = $1; - // always an sy_xvalue with callable symbol in lvalue and - // actual function symbol in rvalue - auto fsym = (symbol_t *) sym->xvalue.rvalue; + auto spec = $3; auto statements = $5; if (!statements) { statements = new_block_expr (0); @@ -393,17 +399,20 @@ subprogram_declaration } auto ret_expr = new_return_expr (function_return (current_func)); append_expr (statements, ret_expr); - build_code_function (fsym, 0, statements, ctx); + build_code_function (spec, 0, statements, ctx); current_symtab = current_func->parameters->parent; - current_storage = $3.storage; + current_storage = spec.storage; } | subprogram_head ASSIGNOP '#' VALUE ';' { auto sym = $1; // always an sy_xvalue with callable symbol in lvalue and // actual function symbol in rvalue - auto fsym = (symbol_t *) sym->xvalue.rvalue; - build_builtin_function (fsym, sym->name, $4, 0, current_storage); + auto spec = (specifier_t) { + .sym = (symbol_t *) sym->xvalue.rvalue, + .storage = current_storage, + }; + build_builtin_function (spec, sym->name, $4); } ; diff --git a/tools/qfcc/source/symtab.c b/tools/qfcc/source/symtab.c index 78cd81409..ba93224fe 100644 --- a/tools/qfcc/source/symtab.c +++ b/tools/qfcc/source/symtab.c @@ -152,6 +152,12 @@ symtab_addsymbol (symtab_t *symtab, symbol_t *symbol) if (symbol->table) internal_error (0, "symbol '%s' is already in another symbol table", symbol->name); + if (symtab->type == stab_bypass) { + if (!symtab->parent) { + internal_error (0, "bypass symbol table with no parent"); + } + symtab = symtab->parent; + } if ((s = Hash_Find (symtab->tab, symbol->name))) return s; Hash_Add (symtab->tab, symbol);