[PATCH] libosmocore[master]: contrib/fsm-to-dot.py: some tweaks that help with osmo-bsc's...

Neels Hofmeyr gerrit-no-reply at lists.osmocom.org
Mon Oct 23 02:24:34 UTC 2017


Review at  https://gerrit.osmocom.org/4377

contrib/fsm-to-dot.py: some tweaks that help with osmo-bsc's new FSMs

Combine the C source file name and the string name into the fsm's internal name
token, and use it in most places instead of the plain struct name: osmo-bsc's
new FSMs have identical struct names in each static c context.

Output in a file name that includes all of these more detailed name tokens.

Also parse '(1 << EVENT)' as event names.

Note that besides this patch, there are also some tweaks to the osmo-bsc patch
that improve the fsm-to-dot experience...
- call fsm-to-dot for single files to avoid name conflicts, or rename each
  struct as a unique name.
- Add comments for the event name a callback is intended for, so that not all
  transitions are interpreted as TEARDOWN (because it is invoked in common
  error handling, which causes the script to interpret it as the causing
  event). (or change the event-checking if into a switch that names the valid
  event and has a default case for all others.)

Change-Id: Ib60df7fd19efc99ba9fe797f14c0e3239c4bea20
---
M contrib/fsm-to-dot.py
1 file changed, 40 insertions(+), 13 deletions(-)


  git pull ssh://gerrit.osmocom.org:29418/libosmocore refs/changes/77/4377/1

diff --git a/contrib/fsm-to-dot.py b/contrib/fsm-to-dot.py
index 3549d1e..06d2df1 100755
--- a/contrib/fsm-to-dot.py
+++ b/contrib/fsm-to-dot.py
@@ -5,7 +5,7 @@
 
 Usage:
   ./fsm-to-dot.py ~/openbsc/openbsc/src/libvlr/*.c
-  for f in *.dot ; do dot -Tpng $f > $f.png; done
+  for f in *.dot ; do dot -Tpng "$f" > "$f.png"; done
   # dot comes from 'apt-get install graphviz'
 
 Looks for osmo_fsm finite state machine definitions and madly parses .c files
@@ -13,7 +13,7 @@
 No proper C parsing is done here (pycparser sucked, unfortunately).
 '''
 
-import sys, re
+import sys, re, os
 
 def err(msg):
   sys.stderr.write(msg + '\n')
@@ -63,8 +63,13 @@
     return ld
 
 re_state_start = re.compile(r'\[([A-Z_][A-Z_0-9]*)\]')
-re_event = re.compile(r'S\(([A-Z_][A-Z_0-9]*)\)')
+re_event_alternatives = [
+    re.compile(r'\(1 *<< *([A-Z_][A-Z_0-9]*)\)'),
+    re.compile(r'S\(([A-Z_][A-Z_0-9]*)\)'),
+  ]
 re_action = re.compile(r'.action *= *([a-z_][a-z_0-9]*)')
+
+re_insane_dot_name_chars = re.compile('[^a-zA-Z_]')
 
 def state_starts(line):
   m = re_state_start.search(line)
@@ -79,7 +84,10 @@
   return line.find('out_state_mask') >= 0
 
 def states_or_events(line):
-  return re_event.findall(line)
+  results = []
+  for one_re in re_event_alternatives:
+    results.extend(one_re.findall(line))
+  return results
 
 def parse_action(line):
   a = re_action.findall(line)
@@ -224,13 +232,15 @@
     return 'State(name=%r,short_name=%r,out=%d)' % (state.name, state.short_name, len(state.out_edges))
 
 class Fsm:
-  def __init__(fsm, struct_name, states_struct_name, from_file=None):
+  def __init__(fsm, struct_name, string_name, states_struct_name, from_file=None):
     fsm.states = []
     fsm.struct_name = struct_name
+    fsm.string_name = string_name
     fsm.states_struct_name = states_struct_name
     fsm.from_file = from_file
     fsm.action_funcs = set()
     fsm.event_names = set()
+    fsm.dot_name = fsm.all_names_sanitized()
 
   def parse_states(fsm, src):
     state = None
@@ -462,8 +472,8 @@
           edge_action = caller
           if calling_state.action == edge_action:
             edge_action = None
-          calling_fsm.add_special_state(calling_fsm.states, fsm.struct_name,
-            calling_state, kind=KIND_FSM, edge_action=edge_action, label=label)
+          calling_fsm.add_special_state(calling_fsm.states, fsm.dot_name,
+            calling_state, kind=KIND_FSM, edge_action=edge_action, label=' '.join(fsm.all_names()))
 
           label = None
           if calling_state.kind == KIND_STATE:
@@ -471,13 +481,13 @@
           edge_action = caller
           if state.action == edge_action:
             edge_action = None
-          fsm.add_special_state(fsm.states, calling_fsm.struct_name, None,
+          fsm.add_special_state(fsm.states, calling_fsm.dot_name, None,
             state, kind=KIND_FSM, edge_action=edge_action,
             label=label)
 
           # meta overview
-          meta_called_fsm = fsm_meta.have_state(fsm.struct_name, KIND_FSM)
-          meta_calling_fsm = fsm_meta.have_state(calling_fsm.struct_name, KIND_FSM)
+          meta_called_fsm = fsm_meta.have_state(fsm.dot_name, KIND_FSM)
+          meta_calling_fsm = fsm_meta.have_state(calling_fsm.dot_name, KIND_FSM)
           meta_calling_fsm.add_out_edge(Edge(meta_called_fsm))
 
 
@@ -519,8 +529,23 @@
 
     return '\n'.join(out)
 
+  def all_names(fsm):
+    n = []
+    if fsm.from_file:
+      n.append(os.path.basename(fsm.from_file.path))
+    if fsm.struct_name:
+      n.append(fsm.struct_name)
+    if fsm.string_name:
+      n.append(fsm.string_name)
+    return n
+
+  def all_names_sanitized(fsm, sep='_'):
+    n = sep.join(fsm.all_names())
+    n = re_insane_dot_name_chars.sub('_', n)
+    return n
+
   def write_dot_file(fsm):
-    dot_path = '%s.dot' % fsm.struct_name
+    dot_path = '%s.dot' % ('_'.join(fsm.all_names()))
     f = open(dot_path, 'w')
     f.write(fsm.to_dot())
     f.close()
@@ -528,6 +553,7 @@
 
 
 re_fsm = re.compile(r'struct osmo_fsm ([a-z_][a-z_0-9]*) =')
+re_fsm_string_name = re.compile(r'\bname = "([^"]*)"')
 re_fsm_states_struct_name = re.compile(r'\bstates = ([a-z_][a-z_0-9]*)\W*,')
 re_fsm_states = re.compile(r'struct osmo_fsm_state ([a-z_][a-z_0-9]*)\[\] =')
 re_func = re.compile(r'(\b[a-z_][a-z_0-9]*\b)\([^)]*\)\W*^{', re.MULTILINE)
@@ -575,8 +601,9 @@
     for m in re_fsm.finditer(c_file.src):
       struct_name = m.group(1)
       struct_def = c_file.extract_block('{', '}', m.start())
+      string_name = (re_fsm_string_name.findall(struct_def) or [None])[0]
       states_struct_name = re_fsm_states_struct_name.findall(struct_def)[0]
-      fsm = Fsm(struct_name, states_struct_name, c_file)
+      fsm = Fsm(struct_name, string_name, states_struct_name, c_file)
       fsms.append(fsm)
     return fsms
 
@@ -694,7 +721,7 @@
   fsm.find_event_edges(c_files)
   fsm.add_fsm_alloc(c_files)
 
-fsm_meta = Fsm("meta", "meta")
+fsm_meta = Fsm("meta", None, "meta")
 for fsm in fsms:
   fsm.add_cross_fsm_links(fsms, c_files, fsm_meta)
 

-- 
To view, visit https://gerrit.osmocom.org/4377
To unsubscribe, visit https://gerrit.osmocom.org/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: Ib60df7fd19efc99ba9fe797f14c0e3239c4bea20
Gerrit-PatchSet: 1
Gerrit-Project: libosmocore
Gerrit-Branch: master
Gerrit-Owner: Neels Hofmeyr <nhofmeyr at sysmocom.de>


More information about the gerrit-log mailing list