mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2025-02-25 05:01:24 +00:00
[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:
parent
c8158f9ebe
commit
36cf1f948e
10 changed files with 179 additions and 119 deletions
|
@ -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);
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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 = $<symtab>2;
|
||||
current_storage = sc_global;//FIXME
|
||||
current_func = nullptr;
|
||||
|
|
|
@ -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>$ = (funcstate_t) {
|
||||
.symtab = current_symtab,
|
||||
specifier_t spec = qc_set_symbol ($<spec>0, $1);
|
||||
auto fs = (funcstate_t) {
|
||||
.function = current_func,
|
||||
};
|
||||
specifier_t spec = qc_set_symbol ($<spec>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;
|
||||
$<funcstate>$ = fs;
|
||||
}
|
||||
compound_statement_ns
|
||||
{
|
||||
build_code_function ($1, $3, $6, ctx);
|
||||
current_symtab = $<funcstate>5.symtab;
|
||||
current_func = $<funcstate>5.function;
|
||||
auto fs = $<funcstate>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 ($<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;
|
||||
$<symbol>$ = function_symbol (spec);
|
||||
spec.sym = function_symbol (spec);
|
||||
$<spec>$ = spec;
|
||||
}
|
||||
save_storage
|
||||
save_storage[storage]
|
||||
{
|
||||
$<funcstate>$ = (funcstate_t) {
|
||||
.symtab = current_symtab,
|
||||
.function = current_func,
|
||||
};
|
||||
current_func = begin_function ($<symbol>2, 0, current_symtab, 0,
|
||||
$<spec>-1.storage);
|
||||
auto spec = $<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 ($<symbol>2, $1, $5, ctx);
|
||||
current_symtab = $<funcstate>4.symtab;
|
||||
current_func = $<funcstate>4.function;
|
||||
restore_storage ($3);
|
||||
auto spec = $<spec>2;
|
||||
auto funcstate = $<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 ($<op>1) {
|
||||
sym = $<symbol>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 = $<symtab>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 = $<symbol>4;
|
||||
symtab_t *ivar_scope;
|
||||
|
||||
$<funcstate>$ = (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>$ = (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 ($<symbol>4, $3, $7, ctx);
|
||||
current_symtab = $<funcstate>6.symtab;
|
||||
current_func = $<funcstate>6.function;
|
||||
auto fs = $<funcstate>6;
|
||||
auto fsym = $<symbol>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);
|
||||
}
|
||||
|
|
|
@ -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 ';'
|
||||
{
|
||||
$<spec>$.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>$ = 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 = $<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 = $<spec>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);
|
||||
}
|
||||
;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue