diff --git a/src/snc/analysis.c b/src/snc/analysis.c index 34cf14611108eb4cc9a5b425141dd60a3c4f1cb6..7c41527c3ad3a5403df6393448a8741084be7a73 100644 --- a/src/snc/analysis.c +++ b/src/snc/analysis.c @@ -25,7 +25,6 @@ in the file LICENSE that is included with this distribution. static const int impossible = 0; -static void analyse_funcdefs(Expr *prog); static void analyse_definitions(Program *p); static void analyse_option(Options *options, Expr *defn); static void analyse_state_option(StateOptions *options, Expr *defn); @@ -78,7 +77,6 @@ Program *analyse_program(Expr *prog, Options options) report("created symbol table, channel list, and syncq list\n"); #endif - analyse_funcdefs(p->prog); analyse_definitions(p); p->num_ss = connect_states(p->sym_table, prog); connect_variables(p->sym_table, prog); @@ -89,103 +87,72 @@ Program *analyse_program(Expr *prog, Options options) return p; } -static void analyse_funcdefs(Expr *prog) +static void analyse_funcdef(Expr *defn) { - Expr *f; + Expr *d = defn->funcdef_decl; + Var *var = d->extra.e_decl; + struct function_type *fun_type; + Expr *p; + Token t; - assert(prog->type == D_PROG); - foreach(f, prog->prog_funcdefs) + assert(defn->type == D_FUNCDEF); + fun_type = &var->type->val.function; + if (var->type->tag != T_FUNCTION) { - Expr *d = f->funcdef_decl; - Var *var = d->extra.e_decl; - struct function_type *fun_type = &var->type->val.function; - Expr *p; - Token t; + error_at_expr(d, "not a function type\n"); + return; + } - assert(f->type == D_FUNCDEF); - if (var->type->tag != T_FUNCTION) + p = fun_type->param_decls; + assert(p); /* invariant enforced by syntax */ + if (p->extra.e_decl->type->tag == T_VOID) + { + /* no other params should be there */ + if (p->next) { - error_at_expr(d, "not a function type\n"); - continue; + error_at_expr(p->next, "void must be the only parameter\n"); } - - p = fun_type->param_decls; - assert(p); /* invariant enforced by syntax */ - if (p->extra.e_decl->type->tag == T_VOID) + if (p->extra.e_decl->name) { - /* no other params should be there */ - if (p->next) - { - error_at_expr(p->next, "void must be the only parameter\n"); - } - if (p->extra.e_decl->name) - { - error_at_expr(p, "void parameter should not have a name\n"); - } - /* void means empty parameter list */ - fun_type->param_decls = 0; + error_at_expr(p, "void parameter should not have a name\n"); } - foreach(p, fun_type->param_decls) + /* void means empty parameter list */ + fun_type->param_decls = 0; + } + foreach(p, fun_type->param_decls) + { + /* check parameter has a name */ + if (!p->extra.e_decl->name) { - /* check parameter has a name */ - if (!p->extra.e_decl->name) - { - error_at_expr(p, "function parameter must have a name\n"); - } + error_at_expr(p, "function parameter must have a name\n"); } - /* prepend "SEQ_VARS *const _seq_vars" to parameter list */ - t.str = NM_VARS_ARG; - t.line = d->line_num; - t.file = d->src_file; - p = decl_add_base_type( - decl_create(t), - /* HACK! act as if "SEQ_VARS *const" were an identifier */ - mk_foreign_type(F_TYPENAME, "SEQ_VARS *const") - ); - fun_type->param_decls = link_expr(p, fun_type->param_decls); - /* prepend "SS_ID _seq_ss" to parameter list*/ - t.str = NM_SS; - t.line = d->line_num; - t.file = d->src_file; - p = decl_add_base_type( - decl_create(t), - mk_foreign_type(F_TYPENAME, "SS_ID") - ); - fun_type->param_decls = link_expr(p, fun_type->param_decls); - prog->prog_defns = link_expr(prog->prog_defns, d); } + /* prepend "SEQ_VARS *const _seq_vars" to parameter list */ + t.str = NM_VARS_ARG; + t.line = d->line_num; + t.file = d->src_file; + p = decl_add_base_type( + decl_create(t), + /* HACK! act as if "SEQ_VARS *const" were an identifier */ + mk_foreign_type(F_TYPENAME, "SEQ_VARS *const") + ); + fun_type->param_decls = link_expr(p, fun_type->param_decls); + /* prepend "SS_ID _seq_ss" to parameter list*/ + t.str = NM_SS; + t.line = d->line_num; + t.file = d->src_file; + p = decl_add_base_type( + decl_create(t), + mk_foreign_type(F_TYPENAME, "SS_ID") + ); + fun_type->param_decls = link_expr(p, fun_type->param_decls); } -static int analyse_defn(Expr *scope, Expr *parent_scope, void *parg) +static void analyse_defns(Expr *defn_list, Expr *scope, Program *p) { - Program *p = (Program *)parg; - Expr *defn_list; - VarList **pvar_list; Expr *defn; - assert(scope); /* precondition */ - -#ifdef DEBUG - report("analyse_defn: scope=(%s:%s)\n", - expr_type_name(scope), scope->value); -#endif - assert(is_scope(scope)); /* precondition */ - assert(!parent_scope || is_scope(parent_scope)); /* precondition */ - - defn_list = defn_list_from_scope(scope); - pvar_list = pvar_list_from_scope(scope); - - /* NOTE: We always need to allocate a var_list, even if there are no - definitions on this level, so later on (see connect_variables below) - we can traverse in the other direction to find the nearest enclosing - scope. */ - if (!*pvar_list) - { - *pvar_list = new(VarList); - (*pvar_list)->parent_scope = parent_scope; - } - foreach (defn, defn_list) { switch (defn->type) @@ -203,6 +170,10 @@ static int analyse_defn(Expr *scope, Expr *parent_scope, void *parg) case D_DECL: analyse_declaration(p->sym_table, scope, defn); break; + case D_FUNCDEF: + analyse_funcdef(defn); + analyse_declaration(p->sym_table, scope, defn->funcdef_decl); + break; case D_ASSIGN: analyse_assign(p->sym_table, p->chan_list, scope, defn); break; @@ -221,6 +192,43 @@ static int analyse_defn(Expr *scope, Expr *parent_scope, void *parg) assert(impossible); } } +} + +static int analyse_scope(Expr *scope, Expr *parent_scope, void *parg) +{ + Program *p = (Program *)parg; + Expr *defn_list; + VarList **pvar_list; + + assert(scope); /* precondition */ + +#ifdef DEBUG + report("analyse_defn: scope=(%s:%s)\n", + expr_type_name(scope), scope->value); +#endif + + assert(is_scope(scope)); /* precondition */ + assert(!parent_scope || is_scope(parent_scope)); /* precondition */ + + defn_list = defn_list_from_scope(scope); + pvar_list = pvar_list_from_scope(scope); + + /* NOTE: We always need to allocate a var_list, even if there are no + definitions on this level, so later on (see connect_variables below) + we can traverse in the other direction to find the nearest enclosing + scope. */ + if (!*pvar_list) + { + *pvar_list = new(VarList); + (*pvar_list)->parent_scope = parent_scope; + } + + analyse_defns(defn_list, scope, p); + if (scope->type == D_PROG) + { + analyse_defns(scope->prog_xdefns, scope, p); + } + return TRUE; /* always descend into children */ } @@ -276,7 +284,7 @@ static void analyse_definitions(Program *p) report("**begin** analyse definitions\n"); #endif - traverse_expr_tree(p->prog, scope_mask, ~has_sub_scope_mask, 0, analyse_defn, p); + traverse_expr_tree(p->prog, scope_mask, ~has_sub_scope_mask, 0, analyse_scope, p); #ifdef DEBUG report("**end** analyse definitions\n"); diff --git a/src/snc/analysis.h b/src/snc/analysis.h index 6aa52879c7533e7abea15cd6ddba5412a0a00491..d111f1d957b0357beaee5eec8c2383d4bf35bd0c 100644 --- a/src/snc/analysis.h +++ b/src/snc/analysis.h @@ -39,7 +39,7 @@ void traverse_expr_tree( ); VarList **pvar_list_from_scope(Expr *scope); -#define var_list_from_scope(scope) *pvar_list_from_scope(scope) +#define var_list_from_scope(scope) (*pvar_list_from_scope(scope)) Expr *defn_list_from_scope(Expr *scope); Program *analyse_program(Expr *ep, Options options); diff --git a/src/snc/gen_code.c b/src/snc/gen_code.c index 19ea8d0b5ce21d97776546a57393680e02b7d8cc..5d1a09afda5004b202e7615b9c76c4a57ec3e7d6 100644 --- a/src/snc/gen_code.c +++ b/src/snc/gen_code.c @@ -22,9 +22,10 @@ in the file LICENSE that is included with this distribution. #include "gen_code.h" static void gen_main(char *prog_name); -static void gen_user_var(Program *p); -static void gen_global_c_code(Expr *global_c_list); +static void gen_user_var(Expr *prog, uint opt_reent); +static void gen_extra_c_code(Expr *extra_defns); static void gen_init_reg(char *prog_name); +static void gen_func_decls(Expr *prog); static int assert_var_declared(Expr *ep, Expr *scope, void *parg) { @@ -73,7 +74,7 @@ void generate_code(Program *p, const char *header_name) else { /* Generate global, state set, and state variable declarations */ - gen_user_var(p); + gen_user_var(p->prog, p->options.reent); } /* The usual C header file humdrum */ @@ -97,18 +98,21 @@ void generate_code(Program *p, const char *header_name) if (!p->options.reent) { /* Generate global, state set, and state variable declarations */ - gen_user_var(p); + gen_user_var(p->prog, p->options.reent); } + /* Generate code for function definitions */ + gen_func_decls(p->prog); + + /* Output extra C code */ + gen_extra_c_code(p->prog->prog_xdefns); + /* Generate code for each state set */ gen_ss_code(p->prog, p->options); /* Generate tables */ gen_tables(p); - /* Output global C code */ - gen_global_c_code(p->prog->prog_ccode); - /* Generate main function */ if (p->options.main) gen_main(p->name); @@ -128,6 +132,26 @@ void gen_var_decl(Var *vp) gen_type(vp->type, "", vp->name); } +static void gen_func_decls(Expr *prog) +{ + Var *vp; + + assert(prog->type == D_PROG); + gen_code("\n/* Function declarations */\n"); + + /* function declarations are always global and static */ + foreach (vp, var_list_from_scope(prog)->first) + { + if (vp->decl && vp->type->tag == T_FUNCTION) + { + gen_line_marker(vp->decl); + gen_code("static "); + gen_var_decl(vp); + gen_code(";\n"); + } + } +} + /* Generate the UserVar struct containing all program variables with 'infinite' (global) lifetime. These are: variables declared at the top-level, inside a state set, and inside a state. Note that state @@ -135,12 +159,11 @@ void gen_var_decl(Var *vp) where they are declared, but still have global lifetime. To avoid name collisions, generate a nested struct for each state set, and for each state in a state set. */ -static void gen_user_var(Program *p) +static void gen_user_var(Expr *prog, uint opt_reent) { - int opt_reent = p->options.reent; Var *vp; Expr *sp, *ssp; - int num_globals = 0; + uint num_globals = 0; uint num_decls = 0; gen_code("\n/* Variable declarations */\n"); @@ -150,7 +173,7 @@ static void gen_user_var(Program *p) gen_code("struct %s {\n", NM_VARS); } /* Convert internal type to `C' type */ - foreach (vp, p->prog->extra.e_prog->first) + foreach (vp, var_list_from_scope(prog)->first) { if (vp->decl && vp->type->tag != T_NONE && vp->type->tag != T_EVFLAG && vp->type->tag != T_FUNCTION) @@ -168,7 +191,7 @@ static void gen_user_var(Program *p) { indent(1); gen_code("char _seq_dummy;\n"); } - foreach (ssp, p->prog->prog_statesets) + foreach (ssp, prog->prog_statesets) { int level = opt_reent; int ss_empty = !ssp->extra.e_ss->var_list->first; @@ -221,17 +244,6 @@ static void gen_user_var(Program *p) } gen_code("};\n"); } - /* function declarations are always global and static */ - foreach (vp, p->prog->extra.e_prog->first) - { - if (vp->decl && vp->type->tag == T_FUNCTION) - { - gen_line_marker(vp->decl); - gen_code("static "); - gen_var_decl(vp); - gen_code(";\n"); - } - } gen_code("\n"); } @@ -259,19 +271,21 @@ void gen_defn_c_code(Expr *scope, int level) } } -/* Generate global C code following state sets */ -static void gen_global_c_code(Expr *global_c_list) +/* Generate extra C code following state sets */ +static void gen_extra_c_code(Expr *extra_defns) { Expr *ep; - if (global_c_list != 0) + if (extra_defns != 0) { - gen_code("\n/* Global C code */\n"); - foreach (ep, global_c_list) + gen_code("\n/* Extra escaped C code */\n"); + foreach (ep, extra_defns) { - assert(ep->type == T_TEXT); - gen_line_marker(ep); - gen_code("%s\n", ep->value); + if (ep->type == T_TEXT) + { + gen_line_marker(ep); + gen_code("%s\n", ep->value); + } } } } diff --git a/src/snc/gen_ss_code.c b/src/snc/gen_ss_code.c index 41be7815635f29b9b8f3af0f928c860251f41f48..a6b096facc535c4e4f6a555a99f30e6a20c8f516 100644 --- a/src/snc/gen_ss_code.c +++ b/src/snc/gen_ss_code.c @@ -138,8 +138,14 @@ void gen_ss_code(Expr *prog, Options options) if (prog->prog_exit) gen_prog_entex_func(prog, "exit", NM_EXIT, gen_prog_exit_body); + gen_code("\n/****** Global function definitions ******/\n"); + /* Generate function definitions */ - foreach(fp, prog->prog_funcdefs) + foreach(fp, prog->prog_defns) + { + gen_funcdef(fp); + } + foreach(fp, prog->prog_xdefns) { gen_funcdef(fp); } @@ -908,12 +914,15 @@ static void gen_prog_exit_body(Expr *prog) static void gen_funcdef(Expr *fp) { - Var *vp = fp->funcdef_decl->extra.e_decl; - - assert(fp->type == D_FUNCDEF); - gen_line_marker(vp->decl); - gen_code("static "); - gen_var_decl(vp); - gen_code("\n"); - gen_block(fp->funcdef_block, C_FUNC, 0); + if (fp->type == D_FUNCDEF) + { + Var *vp = fp->funcdef_decl->extra.e_decl; + + gen_code("\n"); + gen_line_marker(vp->decl); + gen_code("static "); + gen_var_decl(vp); + gen_code("\n"); + gen_block(fp->funcdef_block, C_FUNC, 0); + } } diff --git a/src/snc/snl.lem b/src/snc/snl.lem index f22d9f88248bbf7325b08d8e142f6fcd8ceff7d7..05cde3f5d26c913c67b27607f5692ea9714ef932 100644 --- a/src/snc/snl.lem +++ b/src/snc/snl.lem @@ -88,14 +88,13 @@ in the file LICENSE that is included with this distribution. program ::= PROGRAM NAME(n) program_param(pp) - global_defns(ds) + initial_defns(ds) entry(en) state_sets(ss) exit(ex) - functions(fs) - c_codes(cc). + final_defns(fs). { - *presult = expr(D_PROG, n, pp, ds, en, ss, ex, fs, cc); + *presult = expr(D_PROG, n, pp, ds, en, ss, ex, fs); } program_param(p) ::= LPAREN string(x) RPAREN. { p = x; } @@ -103,18 +102,27 @@ program_param(p) ::= . { p = 0; } // Definitions -global_defns(p) ::= global_defns(xs) global_defn(x). { +initial_defns(p) ::= initial_defns(xs) initial_defn(x). { p = link_expr(xs, x); } -global_defns(p) ::= . { p = 0; } +initial_defns(p) ::= . { p = 0; } + +initial_defn(p) ::= assign(x). { p = x; } +initial_defn(p) ::= monitor(x). { p = x; } +initial_defn(p) ::= sync(x). { p = x; } +initial_defn(p) ::= syncq(x). { p = x; } +initial_defn(p) ::= declaration(x). { p = x; } +initial_defn(p) ::= option(x). { p = x; } +initial_defn(p) ::= c_code(x). { p = x; } +initial_defn(p) ::= funcdef(x). { p = x; } + +final_defns(p) ::= final_defns(xs) final_defn(x). { + p = link_expr(xs, x); +} +final_defns(p) ::= . { p = 0; } -global_defn(p) ::= assign(x). { p = x; } -global_defn(p) ::= monitor(x). { p = x; } -global_defn(p) ::= sync(x). { p = x; } -global_defn(p) ::= syncq(x). { p = x; } -global_defn(p) ::= declaration(x). { p = x; } -global_defn(p) ::= option(x). { p = x; } -global_defn(p) ::= c_code(x). { p = x; } +final_defn(p) ::= c_code(x). { p = x; } +final_defn(p) ::= funcdef(x). { p = x; } assign(p) ::= connect variable(v) to string(t) SEMICOLON. { p = expr(D_ASSIGN, v, 0, t); @@ -474,18 +482,12 @@ string(p) ::= STRCON(t). { p = expr(E_STRING, t); } member(p) ::= NAME(t). { p = expr(E_MEMBER, t); } -// Functions +// Function Definitions -functions(p) ::= . { p = 0; } -functions(p) ::= functions(fs) function(f). { p = link_expr(fs, f); } - -function(p) ::= basetype(t) declarator(d) block(b). { +funcdef(p) ::= basetype(t) declarator(d) block(b). { p = expr(D_FUNCDEF, token_from_expr(d), decl_add_base_type(d, t), b); } // Literal (C) code -c_codes(p) ::= c_codes(xs) c_code(x). { p = link_expr(xs, x); } -c_codes(p) ::= . { p = 0; } - c_code(p) ::= CCODE(t). { p = expr(T_TEXT, t); } diff --git a/src/snc/types.h b/src/snc/types.h index d9738e022ebd2deefa3005c79278010811f99d18..3eef333edff2a3c4e9f50d93c02b088b4b71fdae 100644 --- a/src/snc/types.h +++ b/src/snc/types.h @@ -274,7 +274,7 @@ enum expr_type /* description [child expressions...] */ D_FUNCDEF, /* function definition [decl,block] */ D_MONITOR, /* monitor statement [subscr] */ D_OPTION, /* option definition [] */ - D_PROG, /* whole program [param,defns,entry,statesets,exit,funcdefs,ccode] */ + D_PROG, /* whole program [param,defns,entry,statesets,exit,xdefns] */ D_SS, /* state set statement [defns,states] */ D_STATE, /* state statement [defns,entry,whens,exit] */ D_SYNC, /* sync statement [subscr,evflag] */ @@ -348,8 +348,7 @@ STATIC_ASSERT(NUM_EXPR_TYPES <= 8*sizeof(TypeMask)); #define prog_entry children[2] #define prog_statesets children[3] #define prog_exit children[4] -#define prog_funcdefs children[5] -#define prog_ccode children[6] +#define prog_xdefns children[5] #define return_expr children[0] #define select_left children[0] #define select_right children[1] @@ -394,7 +393,7 @@ expr_type_info[] { "D_FUNCDEF", 2 }, { "D_MONITOR", 1 }, { "D_OPTION", 0 }, - { "D_PROG", 7 }, + { "D_PROG", 6 }, { "D_SS", 2 }, { "D_STATE", 4 }, { "D_SYNC", 2 },