source: buchla-68k/misc/gen-x.py@ bc1afe0

Last change on this file since bc1afe0 was 2340de6, checked in by Thomas Lopatic <thomas@…>, 7 years ago

Keep macros in external declarations.

  • Property mode set to 100755
File size: 6.5 KB
Line 
1#!/usr/bin/env python3
2
3from sys import stdout
4from pycparser import c_ast, parse_file, c_generator
5from re import escape, subn, search
6
7cross_gcc = "/opt/cross-m68k/bin/m68k-none-elf-gcc"
8
9class InclVis(c_ast.NodeVisitor):
10 def __init__(self, path):
11 self.path = path
12 self.typs = set()
13
14 def visit_Typedef(self, node):
15 if node.coord.file == self.path:
16 self.typs.add(node.name)
17
18 self.generic_visit(node)
19
20 def visit_Struct(self, node):
21 if node.coord.file == self.path and \
22 node.name is not None and node.decls is not None:
23 self.typs.add(node.name)
24
25 self.generic_visit(node)
26
27 def get_typs(self):
28 return self.typs
29
30typ_map = {
31 "void": None
32}
33
34with open("misc/c-files.txt", "r") as f:
35 for path in f:
36 path = path.rstrip()
37
38 if len(path) < 8 or path[:8] != "include/":
39 continue
40
41 stdout.write("parsing {} \r".format(path))
42 stdout.flush()
43
44 ast = parse_file(path, use_cpp = True, cpp_path = cross_gcc,
45 cpp_args = ["-E", "-I", "include"])
46 # ast.show()
47
48 vis = InclVis(path)
49 vis.visit(ast)
50
51 for typ in vis.get_typs():
52 if typ in typ_map:
53 raise Exception("redefinition of {}".format(typ))
54
55 typ_map[typ] = path[8:]
56
57class DeclVis(c_ast.NodeVisitor):
58 def __init__(self, typ_map):
59 self.typ_map = typ_map
60 self.typs = set()
61
62 def visit_IdentifierType(self, node):
63 if node.names[0] not in self.typ_map:
64 raise Exception("unknown type {} in {}:{}". \
65 format(node.names[0], node.coord.file, node.coord.line))
66
67 self.typs.add(node.names[0])
68 self.generic_visit(node)
69
70 def visit_Struct(self, node):
71 if node.name not in self.typ_map:
72 raise Exception("unknown struct {} in {}:{}". \
73 format(node.name, node.coord.file, node.coord.line))
74
75 self.typs.add(node.name)
76 self.generic_visit(node)
77
78 def get_typs(self):
79 return self.typs
80
81def fix(text, path):
82 with open(path, "r") as f:
83 cont = f.read()
84
85 (pat, n) = subn(r"\[[0-9]+\]", "[@]", text[7:])
86
87 if n == 0:
88 return text
89
90 rex = escape(pat). \
91 replace("\@", "([0-9A-Z_]+)"). \
92 replace("\ ", "[\t\n ]+")
93
94 m = search(rex, cont)
95
96 if not m:
97 raise Exception("error while matching {}".format(re))
98
99 pats = pat.split("@")
100 vals = m.groups()
101
102 if len(pats) != len(vals) + 1:
103 raise Exception("length mismatch: {} vs. {}". \
104 format(len(pats), len(vals)))
105
106 out = pats[0]
107 pats = pats[1:]
108
109 while len(pats) > 0:
110 out += vals[0] + pats[0]
111 vals = vals[1:]
112 pats = pats[1:]
113
114 return "extern " + out
115
116gen = c_generator.CGenerator()
117
118with open("misc/c-files.txt", "r") as f:
119 for path in f:
120 path = path.rstrip()
121
122 if len(path) >= 8 and path[:8] == "include/":
123 continue
124
125 if path == "ram/wdfield.c": # breaks pycparser
126 continue
127
128 stdout.write("reading {} \r".format(path))
129 stdout.flush()
130
131 ast = parse_file(path, use_cpp = True, cpp_path = cross_gcc,
132 cpp_args = ["-E", "-I", "include"])
133 # ast.show()
134
135 incs = set()
136 funs = {}
137 vars = {}
138
139 for node in ast.ext:
140 if type(node) is c_ast.Decl and \
141 (type(node.type) is c_ast.TypeDecl or \
142 type(node.type) is c_ast.PtrDecl or \
143 type(node.type) is c_ast.ArrayDecl):
144 decl = node
145 dest = vars
146
147 elif type(node) is c_ast.FuncDef:
148 decl = node.decl
149 dest = funs
150
151 else:
152 continue
153
154 if "extern" in decl.storage or \
155 "static" in decl.storage:
156 continue
157
158 vis = DeclVis(typ_map)
159 vis.visit(decl)
160
161 for typ in vis.get_typs():
162 if typ_map[typ] is not None:
163 incs.add(typ_map[typ])
164
165 decl.storage = ["extern"]
166 decl.init = None
167
168 text = gen.visit(decl)
169 text = fix(text, decl.coord.file)
170
171 toks = text.split(" ")
172 alig = ""
173
174 alig += toks[0] + "\t"
175 toks = toks[1:]
176
177 if toks[0] == "struct":
178 if len(toks[1]) > 7:
179 raise Exception("identifier too long: {}".format(toks[1]))
180
181 alig += toks[0] + "\t" + toks[1] + "\t"
182 toks = toks[2:]
183
184 else:
185 alig += toks[0] + ("\t\t" if len(toks[0]) < 8 else "\t")
186 toks = toks[1:]
187
188 dest[decl.name] = alig + " ".join(toks) + ";"
189
190 if len(vars) == 0 and len(funs) == 0:
191 continue
192
193 file = path.split("/")[-1]
194 glob = []
195
196 glob.append("/*")
197 glob.append(" =============================================================================")
198 glob.append("\t" + file + " -- external declarations")
199 glob.append(" =============================================================================")
200 glob.append("*/")
201 glob.append("")
202
203 glob.append("#pragma once")
204 glob.append("")
205
206 if len(incs) > 0:
207 for inc in sorted(incs):
208 glob.append("#include \"{}\"".format(inc))
209
210 glob.append("")
211
212 if len(vars) > 0:
213 glob.append("/*")
214 glob.append(" =============================================================================")
215 glob.append("\texternal variables")
216 glob.append(" =============================================================================")
217 glob.append("*/")
218 glob.append("")
219
220 for _, out in sorted(vars.items()):
221 glob.append(out)
222
223 glob.append("")
224
225 if len(funs) > 0:
226 glob.append("/*")
227 glob.append(" =============================================================================")
228 glob.append("\texternal functions")
229 glob.append(" =============================================================================")
230 glob.append("*/")
231 glob.append("")
232
233 for _, out in sorted(funs.items()):
234 glob.append(out)
235
236 glob.append("")
237
238 with open(path[:-2] + ".x", "w") as f:
239 f.write("\n".join(glob))
240
241 print("")
Note: See TracBrowser for help on using the repository browser.