started state machine extraction tool

This commit is contained in:
matthias.ringwald 2011-06-25 18:17:42 +00:00
parent fc3ea481fb
commit 588b0e6cca
3 changed files with 189 additions and 0 deletions

View File

@ -0,0 +1,31 @@
Project title: "Annotation-based state machine definition for doubly nested switch-case implementations"
- goals: testability, documentation
- assumptions: fixed code stucture
- input: some code (.c)
- output: graphviz state machine ...
- documentation: BTstack Wiki page
- implementation: Python
- problems:
- implicit event like "can send packet now", =? deal with guards?
- "inverse handler" for "global" events
Example:
{
// @STATEMACHINE(multiplexer)
switch (multiplexer->state) { // detect state variable, count {
case W4_MULTIPLEXER: // implicit state
switch (event) { // events start here
case L2CAP_OPEN: // implicit event
// @ACTION(action description)
multiplexer->state = OTHER_STATE;
break; // break || return -> end case block
}
break;
case OTHER_STATE:
break;
}
}
}

104
docs/extract.py Executable file
View File

@ -0,0 +1,104 @@
#!/usr/bin/env python
import re
class Transition(object):
def __init__ (self, fromState, toState, event, guard, action):
self.fromState = fromState
self.toState = toState
self.event = event
self.guard = guard
self.action = action
statemachineName = ""
stateVariable = ""
numBraces = 0
fromState = ""
toState = ""
onEvent = ""
action = ""
def parseLine(line):
global statemachineName
global numBraces
global stateVariable
global fromState
global toState
global onEvent
global action
# looks for annotations
ann = re.compile("(@\w*)\s*(\((.*)\))?")
anns = ann.findall(line)
if anns:
if "@STATEMACHINE" in anns[0]:
# print "statemachine, name:", anns[0][2]
statemachineName = anns[0][2]
numBraces = 0
stateVariable = ""
if "@ACTION" in anns[0]:
action = anns[0][2]
# look for switch
switch = re.compile("(switch)\s*\(\s*(.*)\s*\)")
switches = switch.findall(line)
if (switches):
if numBraces == 0:
stateVariable = switches[0][1]
# print "switch on state opened", numBraces, stateVariable
# if numBraces == 1:
# print "switch on event opened", numBraces
# count curly braces when inside statemachine
if statemachineName:
for c in line:
before = numBraces
if '{' in c:
numBraces = numBraces + 1
if '}' in c:
numBraces = numBraces - 1
# look for case
case = re.compile("(case)\s*(.*):")
cases = case.findall(line)
if cases:
if numBraces == 1:
# print "from state: " + cases[0][1]
fromState = cases[0][1]
if numBraces == 2:
# print "on event: " + cases[0][1]
onEvent = cases[0][1]
toState = ""
action = ""
# look for break or return
brk = re.compile("(break)")
breaks = brk.findall(line)
rtrn = re.compile("(return)")
returns = rtrn.findall(line)
if numBraces > 1:
if breaks or returns:
if not toState:
toState = fromState
# print "to state:", toState
print fromState + "->" + toState + " [label=\"" + onEvent + "/" + action + "\"];"
# look for state transition
if stateVariable:
stateTransition = re.compile( stateVariable + "\s*=\s*(.*);")
transition = stateTransition.findall(line)
if transition:
toState = transition[0]
def parseFile(filename):
f = open (filename, "r")
for line in f:
parseLine(line)
f.close()
print "digraph fsm { "
print "size = \"8.5\""
parseFile("/Projects/iPhone/btstack/src/l2cap.c")
print "}"

54
docs/lamp.c Normal file
View File

@ -0,0 +1,54 @@
#include <stdio.h>
typedef enum {
LAMP_OFF = 1,
LAMP_ON
} state_t;
typedef enum {
TOGGLE_ON = 1,
TOGGLE_OFF
} event_t;
state_t state;
void statemachine(event_t ev){
printf("State: %u, event: %u\n", state, ev);
// @STATEMACHINE(lamp)
switch(state){
case LAMP_OFF:
switch(ev){
case TOGGLE_ON:
// @ACTION(Turning lamp on)
printf("Turning lamp on\n");
state = LAMP_ON;
break;
case TOGGLE_OFF:
// @ACTION(Ignoring toggle off)
printf("Ignoring toggle off\n");
break;
}
break;
case LAMP_ON:
switch(ev){
case TOGGLE_ON:
// @ACTION(Ignoring toggle on)
printf("Ignoring toggle on\n");
break;
case TOGGLE_OFF:
// @ACTION(Turning lamp off)
printf("Turning lamp off\n");
state = LAMP_OFF;
break;
}
}
}
int main(void){
state = LAMP_OFF;
statemachine( TOGGLE_ON );
statemachine( TOGGLE_ON );
statemachine( TOGGLE_OFF );
}