1#!/usr/bin/env python3 2# 3# Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) 4# 5# SPDX-License-Identifier: BSD-2-Clause 6# 7 8from __future__ import print_function 9import sys 10import six 11from functools import reduce 12 13# We assume length tp > 0 14 15 16def parse_type(tps): 17 def helper(tps): 18 tp = tps[0] 19 rest = tps[1:] 20 21 if tp == 'Word': 22 return ('Word', rest[0]), rest[1:] 23 24 elif tp == 'Ptr': 25 tp2, rest = helper(rest) 26 return ('Ptr', tp2), rest 27 28 elif tp == 'Unit': 29 return ('Unit',), rest 30 31 elif tp == 'Array': 32 tp2, rest = helper(rest) 33 # arrays are Array ... sz 34 return ('Array', tp2, rest[0]), rest[1:] 35 36 else: 37 return ('Base', tp), rest 38 39 return helper(tps)[0] 40 41 42def splitBy(f, xs): 43 def fold(acc, v): 44 if f(v): 45 acc[0].append(acc[1]) 46 return (acc[0], []) 47 else: 48 acc[1].append(v) 49 return acc 50 51 return (reduce(fold, xs, ([], [])))[0] 52 53 54def handle_one_struct(s): 55 def hdl_fld(f): 56 fl, tp = f.split(':') 57 return (fl.lstrip(), parse_type(tp.split(' '))) 58 59 name = s[0] 60 return (name, map(hdl_fld, s[1:])) 61 62 63def dict_from_list(ls): 64 a = {} 65 for k, v in ls: 66 a[k] = v 67 68 return a 69 70 71def is_base(x): 72 return (x[0] == 'Base') 73 74 75def base_name(x): 76 return x[1] 77 78 79def paths_to_type(mp, f, start): 80 # This assumes that membership is a DAG which is the case in C 81 82 def handle_one(fld): 83 name, tp = fld 84 if f(tp): 85 return [([start + '.' + name], tp)] 86 elif is_base(tp): 87 res = paths_to_type(mp, f, base_name(tp)) 88 # prepend paths by name (why no Cons in python? grrr) 89 map(lambda x: (x[0].insert(0, name)), res) 90 return res 91 else: 92 return [] 93 94 # init case 95 start_tp = ('Base', start) 96 if f(start_tp): 97 return [([], start_tp)] 98 else: 99 res = map(handle_one, mp[start]) 100 return (reduce(lambda x, y: x + y, res)) 101 102 103def build_types(file): 104 in_file = open(file, 'r') 105 106 lines = map(lambda x: x.rstrip(), in_file.readlines()) 107 108 in_file.close() 109 110 grps = splitBy(lambda x: x == '', lines) 111 112 # the order information will be important if we want _CL for all types 113 sts = dict_from_list(map(handle_one_struct, grps)) 114 115 return sts 116 117 118def print_graph(filename, out_file): 119 mp = build_types(filename) 120 121 print('digraph types {', file=out_file) 122 for k, flds in six.iteritems(mp): 123 for fld, tp in flds: 124 # if is_base(tp): 125 print('\t "%s" -> "%s" [label="%s"]' % (k, base_name(tp), fld), 126 file=out_file) 127 print('}', file=out_file) 128 129# Toplevel 130 131 132if __name__ == '__main__': 133 print_graph('umm_types.txt', sys.stdout) 134