diff --git a/mkdot.py b/mkdot.py index 2d3d28f9d8a46c4d9659fff75c104b02497ab2bb..ce4cff4bad12de772c7cdc54cbed1db88d3bb948 100644 --- a/mkdot.py +++ b/mkdot.py @@ -7,12 +7,107 @@ except ImportError: header = 'digraph G {\nnode [shape = "record"]\n' footer = '\n}' +def ata(d, nonterminal, attribute): + d.setdefault(nonterminal, []).append(attribute) + +@task +def test_pa(*attribute_files): + """ + Test parse_atts + """ + print parse_atts(attribute_files) + +def parse_atts(attribute_files): + # stages + agsearch, rulenamesearch, nonterminalsearch = 1,2,3 + stage = agsearch + d = {} + for f in attribute_files: + with open(f) as fd: + lines = fd.readlines() + for line in lines: + line = line.partition(';')[0].strip() + if line.startswith('(ag-rule'): ## stage == agsearch and + rule_index = line.index('ag-rule') + if line[rule_index+8:]: + # there is more on this line + bracket_index = line.find('(', rule_index+8) + if bracket_index == -1: + # only the name of the attribute + rulename = line[rule_index:bracket_index].strip() + else: + rulename, nonterminal = [x.strip() for x in line[rule_index+8:].split('(')[0:2]] + ata(d,nonterminal,rulename) + stage = nonterminalsearch + else: + stage = rulenamesearch + elif stage == rulenamesearch: + if '(' in line: + # there is something more on the line + rulename, _, rest = line.partition('(') + nonterminal = rest.strip().split()[0] + ata(d,nonterminal,rulename) + else: + # name is on one line + rulename = line.partition(';')[0].strip() + stage = nonterminalsearch + elif stage == nonterminalsearch: + bracket_index = line.find('(') + if bracket_index > -1 and line[bracket_index+1].isupper(): + nonterminal = line[bracket_index+1:].strip().split()[0] + ata(d,nonterminal,rulename) + return d + +def mk_balanced_atts(attributes, max_length = 25): + result = [] # empty list of lists + sums = [] # empty list of sums + attributes.sort(key=len, reverse=True) + for a in attributes: + # search through result lists + # if one list has enough space (i.e. after insertion, the sum of lengths is <= than max_length) + # if not, create a new chunk + # in each case, update the sums + l = len(a) + for i, chunk in enumerate(result): + if sums[i] + l <= max_length: + # add to this chunk + chunk.append(a) + sums[i] = sums[i] + l + break + else: + # if no chunk fits, create a new one and update sums + result.append([a]) + sums.append(l) + return result + +@task +def test_ba(): + """ + Test mk_balanced_atts + """ + print mk_balanced_atts([str(i) for i in xrange(12)]) + print mk_balanced_atts([str(i) for i in xrange(34)]) + + print mk_balanced_atts(['check-model','to-ilp','ilp-objective','ilp-nego','ilp-binary-vars','clauses-met?','every-container','every-pe','every-res-type','every-comp','every-impl','every-mode','every-sw-clause','every-hw-clause','lookup-property','objective-name','objective-value','get-request','get-root','search-comp','search-pe','target','type']) + @task(default=True) -def convert(f, output=None): - if output is None: - output = f+".dot" +def run(): + """ + Create default grammar dot file + """ + convert('ast.scm', True, 'ilp.scm', 'basic-ag.scm') + +def convert(f, balance_atts, *atts): + """ + Converts the given RAG specification into a dot file + @f: File containing AST rules + @balance_atts: True to break attributes into chunks with similar length + @atts: Files containing AG rules + """ + output = f+".dot" with open(f) as fd: lines = fd.readlines() + d_attributes = parse_atts(atts) with open(output, 'w') as fd: fd.write(header) for line in [l.strip() for l in lines if l.strip().startswith('(ast-rule')]: @@ -26,8 +121,10 @@ def convert(f, output=None): children = rhand.split('-') if rhand.strip() else [] terminals = filter(lambda x: x.islower(), children) nonterminals = filter(lambda x: not x.islower(), children) + attributes = d_attributes.get(lhand, []) + attribute_string = '{ ' + ' } | { '.join([' | '.join(l) for l in mk_balanced_atts(attributes)]) + ' }' if balance_atts else ' | '.join(attributes) # define the node of the left hand side - fd.write('{0} [label = "{{{0} | {1}}}"]\n'.format(lhand, '|'.join(terminals))) + fd.write('{0} [label = "{{{0} | {{ t | {1} }} | {{ a | {2} }} }}"]\n'.format(lhand, ' | '.join(terminals), attribute_string)) # add inheritance if superclass: fd.write('{0} -> {1} [arrowhead = "empty"]\n'.format(lhand, superclass))