[qfcc] Add bypass scopes

Because the symbol tables for generic functions are ephemeral (as such),
they need to be easily removed from the scope chain, it's easiest if
definitions are never added to them (instead, they get added to the
parent symbol table). This keeps handling of function declarations or
definitions and their parameter scopes simple as the function gets put
in the global scope still, and the parameter scope simply gets
reconnected to the global scope (really, the generic scope's parent)
when the parameter scope is popped within a generic scope.
This commit is contained in:
Bill Currie 2024-12-11 03:06:50 +09:00
parent c8158f9ebe
commit 36cf1f948e
10 changed files with 179 additions and 119 deletions

View file

@ -212,14 +212,12 @@ function_t *make_function (symbol_t *sym, const char *nice_name,
enum storage_class_e storage); enum storage_class_e storage);
symbol_t *function_symbol (specifier_t spec); symbol_t *function_symbol (specifier_t spec);
const expr_t *find_function (const expr_t *fexpr, const expr_t *params); const expr_t *find_function (const expr_t *fexpr, const expr_t *params);
function_t *begin_function (symbol_t *sym, const char *nicename, function_t *begin_function (specifier_t spec, const char *nicename,
symtab_t *parent, int far, symtab_t *parent);
enum storage_class_e storage); void build_code_function (specifier_t spec, const expr_t *state_expr,
function_t *build_code_function (symbol_t *fsym, const expr_t *state_expr, expr_t *statements, rua_ctx_t *ctx);
expr_t *statements, rua_ctx_t *ctx); void build_builtin_function (specifier_t spec, const char *ext_name,
function_t *build_builtin_function (symbol_t *sym, const char *ext_name, const expr_t *bi_val);
const expr_t *bi_val, int far,
enum storage_class_e storage);
void build_intrinsic_function (specifier_t spec, const expr_t *intrinsic); void build_intrinsic_function (specifier_t spec, const expr_t *intrinsic);
void emit_function (function_t *f, expr_t *e); void emit_function (function_t *f, expr_t *e);
void clear_functions (void); void clear_functions (void);

View file

@ -84,6 +84,7 @@ typedef struct rua_tok_s {
typedef struct { typedef struct {
symtab_t *symtab; symtab_t *symtab;
function_t *function; function_t *function;
specifier_t spec;
} funcstate_t; } funcstate_t;
typedef union rua_val_s { typedef union rua_val_s {

View file

@ -81,6 +81,7 @@ typedef struct specifier_s {
bool is_generic:1; bool is_generic:1;
bool is_generic_block:1; bool is_generic_block:1;
bool is_function:1;//FIXME do proper void(*)() -> ev_func bool is_function:1;//FIXME do proper void(*)() -> ev_func
bool is_far:1;
}; };
unsigned spec_bits; unsigned spec_bits;
}; };

View file

@ -107,6 +107,7 @@ typedef enum {
stab_enum, stab_enum,
stab_label, stab_label,
stab_block, stab_block,
stab_bypass, ///< symbols are added to parent
} stab_type_e; } stab_type_e;
typedef struct symtab_s { typedef struct symtab_s {

View file

@ -1010,11 +1010,19 @@ value_too_large (const type_t *val_type)
static void static void
check_function (symbol_t *fsym) check_function (symbol_t *fsym)
{ {
function_t *func = fsym->metafunc->func;
param_t *params = fsym->params; param_t *params = fsym->params;
param_t *p; param_t *p;
int i; int i;
auto ret_type = fsym->type->func.ret_type; 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)) { if (!ret_type || !type_size (ret_type)) {
error (0, "return type is an incomplete type"); error (0, "return type is an incomplete type");
return; return;
@ -1048,15 +1056,6 @@ build_scope (symbol_t *fsym, symtab_t *parent)
symtab_t *parameters; symtab_t *parameters;
symtab_t *locals; 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); func->label_scope = new_symtab (0, stab_label);
parameters = new_symtab (parent, stab_param); parameters = new_symtab (parent, stab_param);
@ -1122,9 +1121,9 @@ add_function (function_t *f)
} }
function_t * function_t *
begin_function (symbol_t *sym, const char *nicename, symtab_t *parent, begin_function (specifier_t spec, const char *nicename, symtab_t *parent)
int far, storage_class_t storage)
{ {
auto sym = spec.sym;
if (sym->sy_type != sy_func) { if (sym->sy_type != sy_func) {
error (0, "%s is not a function", sym->name); error (0, "%s is not a function", sym->name);
sym = new_symbol_type (sym->name, &type_func); 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) { if (!func->def->external) {
func->def->initialized = 1; func->def->initialized = 1;
func->def->constant = 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; func->line_info = lineno - pr.linenos;
} }
check_function (sym);
build_scope (sym, parent); build_scope (sym, parent);
return func; return func;
} }
@ -1177,58 +1178,60 @@ build_function (symbol_t *fsym)
} }
} }
function_t * void
build_code_function (symbol_t *fsym, const expr_t *state_expr, build_code_function (specifier_t spec, const expr_t *state_expr,
expr_t *statements, rua_ctx_t *ctx) expr_t *statements, rua_ctx_t *ctx)
{ {
auto fsym = spec.sym;
if (ctx) { if (ctx) {
statements = (expr_t *) expr_process (statements, ctx); statements = (expr_t *) expr_process (statements, ctx);
} }
if (fsym->sy_type != sy_func) // probably in error recovery if (fsym->sy_type != sy_func) { // probably in error recovery
return 0; return;
}
build_function (fsym); build_function (fsym);
if (state_expr) { if (state_expr) {
prepend_expr (statements, state_expr); prepend_expr (statements, state_expr);
} }
function_t *func = fsym->metafunc->func; function_t *func = fsym->metafunc->func;
current_target.build_code (func, statements); current_target.build_code (func, statements);
return fsym->metafunc->func;
} }
function_t * void
build_builtin_function (symbol_t *sym, const char *ext_name, build_builtin_function (specifier_t spec, const char *ext_name,
const expr_t *bi_val, int far, storage_class_t storage) const expr_t *bi_val)
{ {
auto sym = spec.sym;
int bi; int bi;
if (sym->sy_type != sy_func) { if (sym->sy_type != sy_func) {
error (bi_val, "%s is not a function", sym->name); error (bi_val, "%s is not a function", sym->name);
return 0; return;
} }
if (!is_int_val (bi_val) if (!is_int_val (bi_val)
&& !(type_default != &type_int && is_float_val (bi_val))) { && !(type_default != &type_int && is_float_val (bi_val))) {
error (bi_val, "invalid constant for = #"); error (bi_val, "invalid constant for = #");
return 0; return;
} }
if (sym->metafunc->meta_type == mf_generic) { if (sym->metafunc->meta_type == mf_generic) {
return 0; return;
} }
function_t *func = sym->metafunc->func; function_t *func = sym->metafunc->func;
if (func && func->def && func->def->initialized) { if (func && func->def && func->def->initialized) {
error (bi_val, "%s redefined", sym->name); error (bi_val, "%s redefined", sym->name);
return 0; return;
} }
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, nullptr, space, storage); func = make_function (sym, nullptr, space, spec.storage);
if (ext_name) { if (ext_name) {
func->s_name = ReuseString (ext_name); func->s_name = ReuseString (ext_name);
} }
if (func->def->external) if (func->def->external) {
return 0; return;
}
func->def->initialized = 1; func->def->initialized = 1;
func->def->constant = 1; func->def->constant = 1;
@ -1245,17 +1248,18 @@ build_builtin_function (symbol_t *sym, const char *ext_name,
} }
if (bi < 0) { if (bi < 0) {
error (bi_val, "builtin functions must be positive or 0"); error (bi_val, "builtin functions must be positive or 0");
return 0; return;
} }
func->builtin = bi; func->builtin = bi;
reloc_def_func (func, func->def); reloc_def_func (func, func->def);
build_function (sym); build_function (sym);
check_function (sym);
// for debug info // for debug info
build_scope (sym, current_symtab); build_scope (sym, current_symtab);
func->parameters->space->size = 0; func->parameters->space->size = 0;
func->locals->space = func->parameters->space; func->locals->space = func->parameters->space;
return func;
} }
void void
@ -1315,8 +1319,12 @@ emit_ctor (void)
return; return;
} }
auto ctor_sym = new_symbol_type (".ctor", &type_func); auto spec = (specifier_t) {
ctor_sym = function_symbol ((specifier_t) { .sym = ctor_sym }); .sym = new_symbol_type (".ctor", &type_func),
current_func = begin_function (ctor_sym, 0, current_symtab, 1, sc_static); .storage = sc_static,
build_code_function (ctor_sym, 0, pr.ctor_exprs, nullptr); .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);
} }

View file

@ -437,9 +437,11 @@ SRC_LINE
"genUType clamp(genUType x, genUType minVal, genUType maxVal);" "\n" "genUType clamp(genUType x, genUType minVal, genUType maxVal);" "\n"
"genUType clamp(genUType x, uint minVal, uint 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, 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, 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" "genFType mix(genFType x, genFType y, genBType a) = " SPV(169) ";" "\n"
"genDType mix(genDType x, genDType 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" "genIType mix(genIType x, genIType y, genBType a) = " SPV(169) ";" "\n"

View file

@ -332,19 +332,16 @@ function_definition
auto spec = $1; auto spec = $1;
spec.sym->params = spec.params; spec.sym->params = spec.params;
spec.is_overload = true; spec.is_overload = true;
auto sym = function_symbol (spec); spec.sym = function_symbol (spec);
current_func = begin_function (sym, nullptr, current_symtab, current_func = begin_function (spec, nullptr, current_symtab);
false, spec.storage);
current_symtab = current_func->locals; current_symtab = current_func->locals;
current_storage = sc_local; current_storage = sc_local;
spec.sym = sym;
$1 = spec; $1 = spec;
} }
compound_statement_no_new_scope compound_statement_no_new_scope
{ {
auto spec = $1; auto spec = $1;
auto sym = spec.sym; build_code_function (spec, nullptr, (expr_t *) $3, ctx);
build_code_function (sym, nullptr, (expr_t *) $3, ctx);
current_symtab = $<symtab>2; current_symtab = $<symtab>2;
current_storage = sc_global;//FIXME current_storage = sc_global;//FIXME
current_func = nullptr; current_func = nullptr;

View file

@ -257,8 +257,12 @@ static expr_t *local_expr;
static void static void
end_generic_scope (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_symtab = nullptr;
generic_scope = false;
} }
static void 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); 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 %expect 2
@ -681,7 +702,7 @@ program
external_def_list external_def_list
: /* empty */ : /* empty */
{ {
if (!generic_block) { if (!current_symtab) {
current_symtab = pr.symtab; current_symtab = pr.symtab;
} }
} }
@ -832,8 +853,8 @@ qc_nocode_func
const expr_t *bi_val = expr_process ($4, ctx); const expr_t *bi_val = expr_process ($4, ctx);
spec.is_overload |= ctx->language->always_overload; spec.is_overload |= ctx->language->always_overload;
symbol_t *sym = function_symbol (spec); spec.sym = function_symbol (spec);
build_builtin_function (sym, nullptr, bi_val, 0, spec.storage); build_builtin_function (spec, nullptr, bi_val);
} }
| identifier '=' intrinsic | identifier '=' intrinsic
{ {
@ -858,24 +879,24 @@ qc_code_func
: identifier '=' optional_state_expr : identifier '=' optional_state_expr
save_storage save_storage
{ {
$<funcstate>$ = (funcstate_t) { specifier_t spec = qc_set_symbol ($<spec>0, $1);
.symtab = current_symtab, auto fs = (funcstate_t) {
.function = current_func, .function = current_func,
}; };
specifier_t spec = qc_set_symbol ($<spec>0, $1);
spec.is_overload |= ctx->language->always_overload; spec.is_overload |= ctx->language->always_overload;
symbol_t *sym = function_symbol (spec); spec.sym = function_symbol (spec);
current_func = begin_function (sym, 0, current_symtab, 0, current_func = begin_function (spec, nullptr, current_symtab);
spec.storage);
current_symtab = current_func->locals; current_symtab = current_func->locals;
current_storage = sc_local; current_storage = sc_local;
$1 = sym; fs.spec = spec;
$<funcstate>$ = fs;
} }
compound_statement_ns compound_statement_ns
{ {
build_code_function ($1, $3, $6, ctx); auto fs = $<funcstate>5;
current_symtab = $<funcstate>5.symtab; build_code_function (fs.spec, $3, $6, ctx);
current_func = $<funcstate>5.function; current_symtab = pop_scope (current_func->parameters);
current_func = fs.function;
restore_storage ($4); restore_storage ($4);
} }
; ;
@ -1171,29 +1192,34 @@ save_storage
; ;
function_body function_body
: method_optional_state_expr : method_optional_state_expr[state]
{ {
specifier_t spec = default_type ($<spec>0, $<spec>0.sym); specifier_t spec = $<spec>0;
if (!spec.is_generic) {
spec = default_type (spec, spec.sym);
}
spec.is_overload |= ctx->language->always_overload; spec.is_overload |= ctx->language->always_overload;
$<symbol>$ = function_symbol (spec); spec.sym = function_symbol (spec);
$<spec>$ = spec;
} }
save_storage save_storage[storage]
{ {
$<funcstate>$ = (funcstate_t) { $<funcstate>$ = (funcstate_t) {
.symtab = current_symtab,
.function = current_func, .function = current_func,
}; };
current_func = begin_function ($<symbol>2, 0, current_symtab, 0, auto spec = $<spec>2;
$<spec>-1.storage); current_func = begin_function (spec, nullptr, current_symtab);
current_symtab = current_func->locals; current_symtab = current_func->locals;
current_storage = sc_local; current_storage = sc_local;
} }
compound_statement_ns compound_statement_ns[body]
{ {
build_code_function ($<symbol>2, $1, $5, ctx); auto spec = $<spec>2;
current_symtab = $<funcstate>4.symtab; auto funcstate = $<funcstate>4;
current_func = $<funcstate>4.function; build_code_function (spec, $state, $body, ctx);
restore_storage ($3); current_symtab = pop_scope (current_func->parameters);
current_func = funcstate.function;
restore_storage ($storage);
} }
| '=' '#' expr ';' | '=' '#' expr ';'
{ {
@ -1201,8 +1227,8 @@ function_body
const expr_t *bi_val = expr_process ($3, ctx); const expr_t *bi_val = expr_process ($3, ctx);
spec.is_overload |= ctx->language->always_overload; spec.is_overload |= ctx->language->always_overload;
symbol_t *sym = function_symbol (spec); spec.sym = function_symbol (spec);
build_builtin_function (sym, nullptr, bi_val, 0, spec.storage); build_builtin_function (spec, nullptr, bi_val);
} }
| '=' intrinsic | '=' intrinsic
{ {
@ -1232,6 +1258,9 @@ storage_class
} else { } else {
generic_scope = true; generic_scope = true;
} }
generic_symtab->type = stab_bypass;
generic_symtab->parent = current_symtab;
current_symtab = generic_symtab;
} }
| ATTRIBUTE '(' attribute_list ')' | ATTRIBUTE '(' attribute_list ')'
{ {
@ -1380,7 +1409,7 @@ optional_enum_list
enum_list enum_list
: '{' enum_init enumerator_list optional_comma '}' : '{' enum_init enumerator_list optional_comma '}'
{ {
current_symtab = current_symtab->parent; current_symtab = pop_scope (current_symtab);
$$ = finish_enum ($3); $$ = finish_enum ($3);
} }
; ;
@ -1467,7 +1496,7 @@ struct_list
{ {
symbol_t *sym; symbol_t *sym;
symtab_t *symtab = current_symtab; symtab_t *symtab = current_symtab;
current_symtab = symtab->parent; current_symtab = pop_scope (symtab);
if ($<op>1) { if ($<op>1) {
sym = $<symbol>2; sym = $<symbol>2;
@ -1841,7 +1870,7 @@ end_scope
: /* empty */ : /* empty */
{ {
if (!options.traditional) { if (!options.traditional) {
current_symtab = current_symtab->parent; current_symtab = pop_scope (current_symtab);
} }
} }
; ;
@ -1980,7 +2009,7 @@ statement
} }
compound_statement compound_statement
{ {
current_symtab = current_symtab->parent; current_symtab = pop_scope (current_symtab);
$$ = $9; $$ = $9;
} }
| ALGEBRA '(' TYPE_SPEC ')' | ALGEBRA '(' TYPE_SPEC ')'
@ -1990,7 +2019,7 @@ statement
} }
compound_statement compound_statement
{ {
current_symtab = current_symtab->parent; current_symtab = pop_scope (current_symtab);
$$ = $6; $$ = $6;
} }
| ALGEBRA '(' TYPE_NAME ')' | ALGEBRA '(' TYPE_NAME ')'
@ -2000,7 +2029,7 @@ statement
} }
compound_statement compound_statement
{ {
current_symtab = current_symtab->parent; current_symtab = pop_scope (current_symtab);
$$ = $6; $$ = $6;
} }
| comma_expr ';' | comma_expr ';'
@ -2523,7 +2552,7 @@ ivar_decl_list
{ {
symtab_t *tab = $<symtab>1; symtab_t *tab = $<symtab>1;
$$ = current_symtab; $$ = current_symtab;
current_symtab = tab->parent; current_symtab = pop_scope (tab);
tab->parent = 0; tab->parent = 0;
tab = $$->parent; // preserve the ivars inheritance chain tab = $$->parent; // preserve the ivars inheritance chain
@ -2615,14 +2644,18 @@ methoddef
symbol_t *sym = $<symbol>4; symbol_t *sym = $<symbol>4;
symtab_t *ivar_scope; symtab_t *ivar_scope;
$<funcstate>$ = (funcstate_t) { auto spec = (specifier_t) {
.symtab = current_symtab, .sym = sym,
.function = current_func, .storage = sc_static,
.is_far = true,
}; };
ivar_scope = class_ivar_scope (current_class, current_symtab); ivar_scope = class_ivar_scope (current_class, current_symtab);
current_func = begin_function (sym, nicename, ivar_scope, 1, $<funcstate>$ = (funcstate_t) {
sc_static); .symtab = ivar_scope,
.function = current_func,
};
current_func = begin_function (spec, nicename, ivar_scope);
class_finish_ivar_scope (current_class, ivar_scope, class_finish_ivar_scope (current_class, ivar_scope,
current_func->locals); current_func->locals);
method->func = sym->metafunc->func; method->func = sym->metafunc->func;
@ -2632,22 +2665,29 @@ methoddef
} }
compound_statement_ns compound_statement_ns
{ {
build_code_function ($<symbol>4, $3, $7, ctx); auto fs = $<funcstate>6;
current_symtab = $<funcstate>6.symtab; auto fsym = $<symbol>4;
current_func = $<funcstate>6.function; 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); restore_storage ($5);
} }
| ci methoddecl '=' '#' const ';' | ci methoddecl '=' '#' const ';'
{ {
symbol_t *sym;
method_t *method = $2; method_t *method = $2;
const expr_t *bi_val = expr_process ($5, ctx); const expr_t *bi_val = expr_process ($5, ctx);
method->instance = $1; method->instance = $1;
method = class_find_method (current_class, method); method = class_find_method (current_class, method);
sym = method_symbol (current_class, method);
build_builtin_function (sym, nullptr, bi_val, 1, sc_static); auto spec = (specifier_t) {
method->func = sym->metafunc->func; .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; 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; symbol_t *sym = nullptr;
if (generic_symtab) {
sym = symtab_lookup (generic_symtab, token);
}
if (!sym) { if (!sym) {
sym = symtab_lookup (current_symtab, token); sym = symtab_lookup (current_symtab, token);
} }

View file

@ -161,14 +161,17 @@ build_dotmain (symbol_t *program, rua_ctx_t *ctx)
exitcode = new_symbol_expr (symtab_lookup (current_symtab, "ExitCode")); exitcode = new_symbol_expr (symtab_lookup (current_symtab, "ExitCode"));
current_func = begin_function (dotmain, 0, current_symtab, 0, auto spec = (specifier_t) {
current_storage); .sym = dotmain,
.storage = current_storage,
};
current_func = begin_function (spec, nullptr, current_symtab);
code = new_block_expr (0); code = new_block_expr (0);
code->block.scope = current_func->locals; code->block.scope = current_func->locals;
auto call = new_call_expr (new_symbol_expr (program), nullptr, nullptr); auto call = new_call_expr (new_symbol_expr (program), nullptr, nullptr);
append_expr (code, call); append_expr (code, call);
append_expr (code, new_return_expr (exitcode)); 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 * static const expr_t *
@ -281,10 +284,13 @@ program
symtab_removesymbol (current_symtab, $1); symtab_removesymbol (current_symtab, $1);
symtab_addsymbol (current_symtab, $1); symtab_addsymbol (current_symtab, $1);
current_func = begin_function ($1, 0, current_symtab, 0, auto spec = (specifier_t) {
current_storage); .sym = $1,
.storage = current_storage,
};
current_func = begin_function (spec, nullptr, current_symtab);
current_symtab = current_func->locals; current_symtab = current_func->locals;
build_code_function ($1, 0, $4, ctx); build_code_function (spec, 0, $4, ctx);
current_symtab = st; current_symtab = st;
build_dotmain ($1, ctx); build_dotmain ($1, ctx);
@ -367,25 +373,25 @@ subprogram_declarations
subprogram_declaration subprogram_declaration
: subprogram_head ';' : subprogram_head ';'
{ {
$<spec>$.storage = current_storage;
auto sym = $1; auto sym = $1;
// always an sy_xvalue with callable symbol in lvalue and // always an sy_xvalue with callable symbol in lvalue and
// actual function symbol in rvalue // actual function symbol in rvalue
auto csym = (symbol_t *) sym->xvalue.lvalue; auto csym = (symbol_t *) sym->xvalue.lvalue;
auto fsym = (symbol_t *) sym->xvalue.rvalue; auto fsym = (symbol_t *) sym->xvalue.rvalue;
current_func = begin_function (fsym, sym->name, current_symtab, 0, auto spec = (specifier_t) {
current_storage); .sym = fsym,
.storage = current_storage,
};
current_func = begin_function (spec, sym->name, current_symtab);
current_symtab = current_func->locals; current_symtab = current_func->locals;
current_storage = sc_local; current_storage = sc_local;
// null for procedures, valid symbol expression for functions // null for procedures, valid symbol expression for functions
csym->xvalue.lvalue = function_return (current_func); csym->xvalue.lvalue = function_return (current_func);
$<spec>$ = spec;
} }
declarations compound_statement ';' declarations compound_statement ';'
{ {
auto sym = $1; auto spec = $<spec>3;
// always an sy_xvalue with callable symbol in lvalue and
// actual function symbol in rvalue
auto fsym = (symbol_t *) sym->xvalue.rvalue;
auto statements = $5; auto statements = $5;
if (!statements) { if (!statements) {
statements = new_block_expr (0); statements = new_block_expr (0);
@ -393,17 +399,20 @@ subprogram_declaration
} }
auto ret_expr = new_return_expr (function_return (current_func)); auto ret_expr = new_return_expr (function_return (current_func));
append_expr (statements, ret_expr); 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_symtab = current_func->parameters->parent;
current_storage = $<spec>3.storage; current_storage = spec.storage;
} }
| subprogram_head ASSIGNOP '#' VALUE ';' | subprogram_head ASSIGNOP '#' VALUE ';'
{ {
auto sym = $1; auto sym = $1;
// always an sy_xvalue with callable symbol in lvalue and // always an sy_xvalue with callable symbol in lvalue and
// actual function symbol in rvalue // actual function symbol in rvalue
auto fsym = (symbol_t *) sym->xvalue.rvalue; auto spec = (specifier_t) {
build_builtin_function (fsym, sym->name, $4, 0, current_storage); .sym = (symbol_t *) sym->xvalue.rvalue,
.storage = current_storage,
};
build_builtin_function (spec, sym->name, $4);
} }
; ;

View file

@ -152,6 +152,12 @@ symtab_addsymbol (symtab_t *symtab, symbol_t *symbol)
if (symbol->table) if (symbol->table)
internal_error (0, "symbol '%s' is already in another symbol table", internal_error (0, "symbol '%s' is already in another symbol table",
symbol->name); 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))) if ((s = Hash_Find (symtab->tab, symbol->name)))
return s; return s;
Hash_Add (symtab->tab, symbol); Hash_Add (symtab->tab, symbol);