Skip to content
Snippets Groups Projects
Commit d9d091ca authored by benjamin.franksen's avatar benjamin.franksen
Browse files

snc: issue warning if a state is not reachable from the first

parent 47ff8794
No related branches found
No related tags found
No related merge requests found
......@@ -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.
*/
......
......@@ -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 */
};
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment