slicc: support for transitions with a wildcard next state

This patches adds support for transitions of the form:

transition(START, EVENTS, *) { ACTIONS }

This allows a machine to collapse states that differ only in the next state
transition to collapse into one, and can help shorten/simplfy some protocols
significantly.

When * is encountered as an end state of a transition, the next state is
determined by calling the machine-specific getNextState function. The next
state is determined before any actions of the transition execute, and
therefore the next state calculation cannot depend on any of the transition
actions.
This commit is contained in:
David Hashe 2015-07-20 09:15:18 -05:00
parent 6a288d9de3
commit ee0d414fa8
4 changed files with 40 additions and 5 deletions

View file

@ -278,7 +278,7 @@ class SLICC(Grammar):
p[0] = ast.OutPortDeclAST(self, p[3], p[5], p[7], p[8])
def p_decl__trans0(self, p):
"decl : TRANS '(' idents ',' idents ',' ident ')' idents"
"decl : TRANS '(' idents ',' idents ',' ident_or_star ')' idents"
p[0] = ast.TransitionDeclAST(self, [], p[3], p[5], p[7], p[9])
def p_decl__trans1(self, p):
@ -286,7 +286,7 @@ class SLICC(Grammar):
p[0] = ast.TransitionDeclAST(self, [], p[3], p[5], None, p[7])
def p_decl__trans2(self, p):
"decl : TRANS '(' idents ',' idents ',' ident ')' idents idents"
"decl : TRANS '(' idents ',' idents ',' ident_or_star ')' idents idents"
p[0] = ast.TransitionDeclAST(self, p[9], p[3], p[5], p[7], p[10])
def p_decl__trans3(self, p):
@ -506,6 +506,11 @@ class SLICC(Grammar):
"ident : IDENT"
p[0] = p[1]
def p_ident_or_star(self, p):
"""ident_or_star : ident
| STAR"""
p[0] = p[1]
# Pair and pair lists
def p_pairs__list(self, p):
"pairs : ',' pairsx"

View file

@ -30,5 +30,13 @@ from slicc.symbols.Symbol import Symbol
class State(Symbol):
def __repr__(self):
return "[State: %s]" % self.ident
def isWildcard(self):
return False
class WildcardState(State):
def __repr__(self):
return "[State: *]"
def isWildcard(self):
return True
__all__ = [ "State" ]

View file

@ -1310,8 +1310,17 @@ ${ident}_Controller::doTransitionWorker(${ident}_Event event,
case = self.symtab.codeFormatter()
# Only set next_state if it changes
if trans.state != trans.nextState:
ns_ident = trans.nextState.ident
case('next_state = ${ident}_State_${ns_ident};')
if trans.nextState.isWildcard():
# When * is encountered as an end state of a transition,
# the next state is determined by calling the
# machine-specific getNextState function. The next state
# is determined before any actions of the transition
# execute, and therefore the next state calculation cannot
# depend on any of the transitionactions.
case('next_state = getNextState(addr);')
else:
ns_ident = trans.nextState.ident
case('next_state = ${ident}_State_${ns_ident};')
actions = trans.actions
request_types = trans.request_types

View file

@ -26,6 +26,7 @@
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from slicc.symbols.Symbol import Symbol
from slicc.symbols.State import WildcardState
class Transition(Symbol):
def __init__(self, table, machine, state, event, nextState, actions,
@ -35,7 +36,19 @@ class Transition(Symbol):
self.state = machine.states[state]
self.event = machine.events[event]
self.nextState = machine.states[nextState]
if nextState == '*':
# check to make sure there is a getNextState function declared
found = False
for func in machine.functions:
if func.c_ident == 'getNextState':
found = True
break
if found == False:
fatal("Machine uses a wildcard transition without getNextState defined")
self.nextState = WildcardState(machine.symtab,
'*', location)
else:
self.nextState = machine.states[nextState]
self.actions = [ machine.actions[a] for a in actions ]
self.request_types = [ machine.request_types[s] for s in request_types ]
self.resources = {}