From b566e4bcd0c7cb3c90ad941b37db223134090ded Mon Sep 17 00:00:00 2001 From: Nicolas Schodet Date: Fri, 8 May 2009 23:07:25 +0200 Subject: * tools/dfagen: - added state attributes. - added support for more than one initial state. - added table of transitions with only one default branch. - added state and event template parameter. - added --output-dir. - make template directory relative to config file. - more options checking. - added transition attributes and callback definition. - conserve input file order in output. - added --dump and more option checking. - fixed missing newline. --- tools/dfagen/dfagen/output/__init__.py | 1 + tools/dfagen/dfagen/output/c.py | 160 +++++++++++++++++++----- tools/dfagen/dfagen/output/c/template.c | 2 +- tools/dfagen/dfagen/output/c/template_cb_decl.h | 2 +- tools/dfagen/dfagen/output/c/template_cb_impl.c | 2 +- tools/dfagen/dfagen/output/dot.py | 11 +- 6 files changed, 142 insertions(+), 36 deletions(-) (limited to 'tools/dfagen/dfagen/output') diff --git a/tools/dfagen/dfagen/output/__init__.py b/tools/dfagen/dfagen/output/__init__.py index 567ab745..eadd8c2f 100644 --- a/tools/dfagen/dfagen/output/__init__.py +++ b/tools/dfagen/dfagen/output/__init__.py @@ -2,6 +2,7 @@ from ConfigParser import ConfigParser class UserConfig: def __init__ (self, file): + self.file = file if file: f = open (file, 'r') cp = ConfigParser () diff --git a/tools/dfagen/dfagen/output/c.py b/tools/dfagen/dfagen/output/c.py index 099302f9..5a44d0e3 100644 --- a/tools/dfagen/dfagen/output/c.py +++ b/tools/dfagen/dfagen/output/c.py @@ -1,48 +1,108 @@ import os.path +import re + +class StateData: + """Data associated with a state when enumerating, used with templates.""" + + def __init__ (self, state, prefix): + self.state = state + self.dict = dict ( + state = state.name, + prefix = prefix, + PREFIX = prefix.upper (), + ) + + def __getitem__ (self, key): + # Second argument may be a default value. + key = key.split ('|', 1) + [ '' ] + key, default = key[0], key[1] + val = None + # Get value. + if key in self.dict: + val = self.dict[key] + elif key == '@': + val = self.state.attributes + elif key.startswith ('@'): + if self.state.attributes is not None: + a = dict (p.split ('=') + for p in self.state.attributes.split ()) + try: + val = a[key[1:]] + except KeyError: + pass + else: + raise KeyError, key + # Test for empty value, and return. + if val is None: + val = default + return val + class WriterData: + callback_re = re.compile ('^\w+$') + def __init__ (self, prefix, automaton, user): self.prefix = prefix self.automaton = automaton self.user = user - self.states = self.automaton.states.values () - self.events = self.automaton.events.values () + self.states = self.automaton.iter_states + self.initials = self.automaton.iter_initials + self.events = self.automaton.iter_events self.dict = dict ( prefix = prefix, PREFIX = prefix.upper (), name = automaton.name, comments = automaton.comments, - initial = automaton.initial.name, states = self.list_states, + initials = self.list_initials, events = self.list_events, states_names = self.list_states_names, events_names = self.list_events_names, + initials_nb = str (len (automaton.initials)), branches = self.list_branches, + only_branch_table = self.only_branch_table, transition_table = self.transition_table, states_template = self.states_template, ) + if len (automaton.initials) == 1: + self.dict['initial'] = automaton.initials[0].name + + def list_states_sub (self, iter, template = None): + if template is None: + template = '%(PREFIX)s_STATE_%(state)s' + return ''.join (' ' + + template % StateData (s, self.prefix) + + ',\n' for s in iter ()) + + def list_states (self, template = None): + return self.list_states_sub (self.states, template) - def list_states (self): - return ''.join ([' ' + self.prefix.upper () + '_STATE_' + s.name - + ',\n' for s in self.states]) + def list_initials (self, template = None): + return self.list_states_sub (self.initials, template) - def list_events (self): - return ''.join ([' ' + self.prefix.upper () + '_EVENT_' - + e.name.replace (' ', '_') + ',\n' for e in self.events]) + def list_events (self, template = None): + if template is None: + template = '%(PREFIX)s_EVENT_%(event)s' + return ''.join (' ' + + template % dict ( + PREFIX = self.prefix.upper (), + event = e.name.replace (' ', '_') + ) + + ',\n' for e in self.events ()) def list_states_names (self): - return ''.join ([' "' + s.name + '",\n' for s in self.states]) + return ''.join (' "' + s.name + '",\n' for s in self.states ()) def list_events_names (self): - return ''.join ([' "' + e.name.replace (' ', '_') + '",\n' - for e in self.events]) + return ''.join (' "' + e.name.replace (' ', '_') + '",\n' + for e in self.events ()) def list_branches (self): l = '' - for s in self.states: - for tr in s.transitions.values (): - for br in tr.branches.values (): + for s in self.states (): + for tr in s.iter_transitions (): + for br in tr.iter_branches (): n = dict ( PREFIX = self.prefix.upper (), state = s.name, @@ -55,15 +115,54 @@ class WriterData: + '_BRANCH (%(state)s, %(event)s, %(to)s),\n') % n return l + def only_branch_table (self, template = None, null = None): + if template is None: + template = '%(PREFIX)s_STATE_%(state)s' + if null is None: + null = template + r = '' + for s in self.states (): + r += ' { ' + es = [ ] + for e in self.events (): + to = None + t = None + if e in s.transitions and None in s.transitions[e].branches: + br = s.transitions[e].branches[None] + to = br.to and br.to.name or s.name + t = template + else: + to = 'NB' + t = null + es.append (t % dict ( + PREFIX = self.prefix.upper (), + state = to, + )) + r += ',\n '.join (es) + r += ' },\n' + return r + + def transition_callback (self, state, event): + attr = state.transitions[event].get_attributes () + if attr: + assert len (attr) == 1, ("multiple callbacks for transition on " + + "event %s for state %s" % (event.name, state.name)) + callback = attr[0] + assert self.callback_re.match (callback), ("bad callback name %s" + % callback) + return callback + else: + return (self.prefix + '__' + state.name + '__' + + event.name.replace (' ', '_')) + def transition_table (self): r = '' - for s in self.states: + for s in self.states (): r += ' { ' es = [ ] - for e in self.events: + for e in self.events (): if e in s.transitions: - es.append (self.prefix + '__' + s.name + '__' - + e.name.replace (' ', '_')) + es.append (self.transition_callback (s, e)) else: es.append ('NULL') r += ',\n '.join (es) @@ -75,8 +174,8 @@ class WriterData: tt = t.read () t.close () exp = '' - for s in self.states: - for tr in s.transitions.values (): + for s in self.states (): + for tr in s.iter_transitions (): d = WriterData (self.prefix, self.automaton, self.user) branches_to = '\n'.join ( [(br.name and br.name or '') @@ -84,7 +183,7 @@ class WriterData: + (br.to and br.to.name or s.name) + (br.comments and ('\n ' + br.comments.replace ('\n', '\n ')) or '') - for br in tr.branches.values ()]) + for br in tr.iter_branches ()]) returns = '\n'.join ( [' return ' + self.prefix + '_next' + (br.name and '_branch' or '') @@ -93,7 +192,7 @@ class WriterData: + (br.name and ', ' + br.name.replace (' ', '_') or '') + ');' - for br in tr.branches.values ()]) + for br in tr.iter_branches ()]) d.dict = dict ( prefix = self.prefix, user = self.user, @@ -101,6 +200,7 @@ class WriterData: event = tr.event.name.replace (' ', '_'), branches_to = branches_to, returns = returns, + callback = self.transition_callback (s, tr.event), ) exp += tt % d return exp @@ -131,17 +231,18 @@ class WriterData: class Writer: - def __init__ (self, data, templatedir): + def __init__ (self, data, templatedir, outputdir): data.templatedir = templatedir self.data = data self.templatedir = templatedir + self.outputdir = outputdir def write_template (self, template, output): t = open (os.path.join (self.templatedir, template), 'r') tt = t.read () t.close () exp = tt % self.data - o = open (output, 'w') + o = open (os.path.join (self.outputdir, output), 'w') o.write (exp) o.close () @@ -157,8 +258,11 @@ class Writer: for (t, f) in templates.iteritems (): self.write_template (t, f.replace ('%', self.data.prefix)) -def write (prefix, automaton, user): - w = Writer (WriterData (prefix, automaton, user), 'template-dir' in user - and user['template-dir'] or os.path.splitext (__file__)[0]) +def write (prefix, automaton, user, outputdir): + templatedir = os.path.splitext (__file__)[0] + if 'template-dir' in user: + templatedir = os.path.join (os.path.split (user.file)[0], + user['template-dir']) + w = Writer (WriterData (prefix, automaton, user), templatedir, outputdir) w.write () diff --git a/tools/dfagen/dfagen/output/c/template.c b/tools/dfagen/dfagen/output/c/template.c index a8679046..6beda928 100644 --- a/tools/dfagen/dfagen/output/c/template.c +++ b/tools/dfagen/dfagen/output/c/template.c @@ -8,7 +8,7 @@ #include #include -%(_user.type-decl)s +%(_user.type-decl)s /* %(name)s transition table. */ static const %(prefix)s_transition_t %(prefix)s_transition_table[%(PREFIX)s_STATE_NB][%(PREFIX)s_EVENT_NB] = { diff --git a/tools/dfagen/dfagen/output/c/template_cb_decl.h b/tools/dfagen/dfagen/output/c/template_cb_decl.h index a1e7c0f2..3bb0a35f 100644 --- a/tools/dfagen/dfagen/output/c/template_cb_decl.h +++ b/tools/dfagen/dfagen/output/c/template_cb_decl.h @@ -2,5 +2,5 @@ * %(state)s =%(event)s=> %(*branches_to)s */ %(prefix)s_branch_t -%(prefix)s__%(state)s__%(event)s (%(user.type)s *user); +%(callback)s (%(user.type)s *user); diff --git a/tools/dfagen/dfagen/output/c/template_cb_impl.c b/tools/dfagen/dfagen/output/c/template_cb_impl.c index ffd9720f..e5a4d789 100644 --- a/tools/dfagen/dfagen/output/c/template_cb_impl.c +++ b/tools/dfagen/dfagen/output/c/template_cb_impl.c @@ -2,7 +2,7 @@ * %(state)s =%(event)s=> %(*branches_to)s */ %(prefix)s_branch_t -%(prefix)s__%(state)s__%(event)s (%(user.type)s *user) +%(callback)s (%(user.type)s *user) { %(returns)s } diff --git a/tools/dfagen/dfagen/output/dot.py b/tools/dfagen/dfagen/output/dot.py index d6cc057c..ce9c4db8 100644 --- a/tools/dfagen/dfagen/output/dot.py +++ b/tools/dfagen/dfagen/output/dot.py @@ -1,12 +1,13 @@ +import os.path -def write (prefix, automaton, user): +def write (prefix, automaton, user, outputdir): output = prefix + '.dot' - o = open (output, 'w') + o = open (os.path.join (outputdir, output), 'w') o.write ('digraph %s {' % prefix) - for s in automaton.states.values (): + for s in automaton.iter_states (): o.write (' %s\n' % s.name) - for tr in s.transitions.values (): - for br in tr.branches.values (): + for tr in s.iter_transitions (): + for br in tr.iter_branches (): o.write (' %(state)s -> %(to)s [ label = "%(event)s" ];\n' % dict ( state = s.name, -- cgit v1.2.3