From d9d091caa2d32561b664dbcbe28bda949032dced Mon Sep 17 00:00:00 2001 From: "benjamin.franksen" <benjamin.franksen@helmholtz-berlin.de> Date: Tue, 8 May 2012 10:10:05 +0000 Subject: [PATCH] snc: issue warning if a state is not reachable from the first --- src/snc/analysis.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++ src/snc/types.h | 1 + 2 files changed, 69 insertions(+) diff --git a/src/snc/analysis.c b/src/snc/analysis.c index c0f57352..6f54258e 100644 --- a/src/snc/analysis.c +++ b/src/snc/analysis.c @@ -40,6 +40,7 @@ static SyncQ *new_sync_queue(SyncQList *syncq_list, uint size); static void connect_variables(SymTable st, Expr *scope); static void connect_state_change_stmts(SymTable st, Expr *scope); static uint connect_states(SymTable st, Expr *ss_list); +static void check_states_reachable_from_first(Expr *ss); static void add_var(SymTable st, Var *vp, Expr *scope); static Var *find_var(SymTable st, char *name, Expr *scope); static uint assign_ef_bits(Expr *scope); @@ -47,6 +48,7 @@ static uint assign_ef_bits(Expr *scope); Program *analyse_program(Expr *prog, Options options) { Program *p = new(Program); + Expr *ss; assert(prog); /* precondition */ #ifdef DEBUG @@ -78,6 +80,8 @@ Program *analyse_program(Expr *prog, Options options) p->num_ss = connect_states(p->sym_table, prog); connect_variables(p->sym_table, prog); connect_state_change_stmts(p->sym_table, prog); + foreach(ss, prog->prog_statesets) + check_states_reachable_from_first(ss); p->num_event_flags = assign_ef_bits(p->prog); return p; } @@ -1352,6 +1356,70 @@ static void connect_state_change_stmts(SymTable st, Expr *scope) expr_mask, 0, iter_connect_state_change_stmts, &csc_arg); } +static void mark_states_reachable_from(Expr *sp); + +static int iter_mark_states_reachable(Expr *ep, Expr *scope, void *parg) +{ + Expr *target_state = 0; + + assert(ep->type == S_CHANGE || ep->type == D_WHEN); + switch (ep->type ) { + case S_CHANGE: + target_state = ep->extra.e_change; + break; + case D_WHEN: + target_state = ep->extra.e_when->next_state; + break; + } + if (target_state && !target_state->extra.e_state->is_target) + { + target_state->extra.e_state->is_target = 1; + mark_states_reachable_from(target_state); + } + return (ep->type == D_WHEN); +} + +static void mark_states_reachable_from(Expr *sp) +{ + assert(sp); + assert(sp->type == D_STATE); + + traverse_expr_tree( + sp, /* start expression */ + (1<<S_CHANGE)|(1<<D_WHEN), /* when to call iteratee */ + expr_mask, /* when to stop descending */ + sp, /* current scope, 0 at top-level */ + iter_mark_states_reachable, /* function to call */ + 0 /* argument to pass to function */ + ); +} + +static void check_states_reachable_from_first(Expr *ssp) +{ + Expr *sp; + + assert(ssp); + assert(ssp->type == D_SS); + + sp = ssp->ss_states; + assert(sp); + assert(sp->type == D_STATE); + assert(sp->extra.e_state->index == 0); + + sp->extra.e_state->is_target = 1; + mark_states_reachable_from(sp); + + foreach (sp, ssp->ss_states) + { + if (!sp->extra.e_state->is_target) + { + warning_at_expr(sp, "state '%s' in state set '%s' cannot " + "be reached from start state\n", + sp->value, ssp->value); + } + } +} + /* Assign event bits to event flags and associate pv channels with * event flags. Return number of event flags found. */ diff --git a/src/snc/types.h b/src/snc/types.h index 0b63a1ab..3ccdb585 100644 --- a/src/snc/types.h +++ b/src/snc/types.h @@ -95,6 +95,7 @@ struct when /* extra data for when clauses */ struct state /* extra data for state clauses */ { int index; /* index in array of seqState structs */ + uint is_target; /* is this state a target state? */ StateOptions options; /* state options */ VarList *var_list; /* list of 'local' variables */ }; -- GitLab