source: buchla-68k/misc/fix-decls.py@ e225e77

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

Added missing includes and declarations.

  • Property mode set to 100755
File size: 5.1 KB
Line 
1#!/usr/bin/env python3
2
3from sys import stdout
4from pycparser import c_ast, c_generator, parse_file
5
6cross_gcc = "/opt/cross-m68k/bin/m68k-none-elf-gcc"
7
8class Visitor(c_ast.NodeVisitor):
9 gen = c_generator.CGenerator()
10
11 def __init__(self):
12 self.path = None
13
14 self.calls = {}
15 self.knows = {}
16
17 self.declares = {}
18 self.in_header = {}
19
20 self.decl = {}
21
22 self.max_decl = {}
23 self.max_head = {}
24
25 self.fix_head = {}
26 self.fix_decl = {}
27
28 def visit_FuncCall(self, node):
29 if node.coord.file != self.path:
30 return
31
32 if type(node.name) is not c_ast.ID:
33 return
34
35 if self.path not in self.calls:
36 self.calls[self.path] = set()
37
38 self.calls[self.path].add(node.name.name)
39 self.generic_visit(node)
40
41 def visit_path(self, path, ast):
42 self.path = path
43 self.visit(ast)
44 self.path = None
45
46 for node in ast.ext:
47 if type(node) is not c_ast.FuncDef:
48 continue
49
50 node.decl.storage = []
51 decl = self.gen.visit(node.decl)
52
53 if node.decl.name in self.decl and \
54 self.decl[node.decl.name] != decl:
55 raise Exception("declaration mismatch: {} vs. {}". \
56 format(self.decl[node.decl.name], decl))
57
58 self.decl[node.decl.name] = decl
59
60 for node in ast.ext:
61 if type(node) is c_ast.Decl and \
62 type(node.type) is c_ast.FuncDecl:
63 decl = node
64
65 elif type(node) is c_ast.FuncDef:
66 decl = node.decl
67
68 else:
69 continue
70
71 if path not in self.knows:
72 self.knows[path] = set()
73
74 self.knows[path].add(decl.name)
75
76 if decl.coord.file != path:
77 continue
78
79 if type(node) is c_ast.Decl:
80 if path not in self.max_decl:
81 self.max_decl[path] = -1;
82
83 if decl.coord.line > self.max_decl[path]:
84 self.max_decl[path] = decl.coord.line
85
86 if path not in self.declares:
87 self.declares[path] = set()
88
89 self.declares[path].add(decl.name)
90
91 if path[-2:] == ".h":
92 if decl.name in self.in_header:
93 raise Exception("duplicate definition of {}".format(decl.name))
94
95 self.in_header[decl.name] = path
96
97 def fix(self):
98 for path, calls in sorted(self.calls.items()):
99 knows = self.knows[path]
100 needs = calls - knows
101
102 for need in sorted(needs):
103 if need in self.in_header:
104 if path not in self.fix_head:
105 self.fix_head[path] = set()
106
107 self.fix_head[path].add(self.in_header[need])
108
109 else:
110 if path not in self.fix_decl:
111 self.fix_decl[path] = set()
112
113 self.fix_decl[path].add(self.decl[need])
114
115 no = 1
116
117 with open(path, "r") as f:
118 for line in f:
119 if len(line) >= 8 and line[:8] == "#include":
120 self.max_head[path] = no
121
122 no += 1
123
124 for path, _ in sorted(self.calls.items()):
125 if path not in self.fix_head and path not in self.fix_decl:
126 continue
127
128 max_head = self.max_head[path] if path in self.max_head else None
129 max_decl = self.max_decl[path] if path in self.max_decl else None
130
131 if max_head is None:
132 max_head = max_decl
133
134 if max_decl is None:
135 max_decl = max_head
136
137 no = 1
138 out = []
139 extern = "extern "
140
141 with open(path, "r") as f:
142 for line in f:
143 out.append(line)
144
145 if "extern\t" in line:
146 extern = "extern\t"
147
148 if no == max_head and path in self.fix_head:
149 out.append("\n")
150
151 for head in sorted(self.fix_head[path]):
152 out.append("#include \"{}\"\n".format(head.split("/")[-1]))
153
154 if no == max_decl and path in self.fix_decl:
155 out.append("\n")
156
157 for decl in sorted(self.fix_decl[path]):
158 out.append(extern + decl + ";\n")
159
160 no += 1
161
162 with open(path, "w") as f:
163 for line in out:
164 f.write(line)
165
166vis = Visitor()
167
168with open("misc/c-files.txt", "r") as f:
169 for path in f:
170 path = path.rstrip()
171
172 if path == "ram/wdfield.c": # breaks pycparser
173 continue
174
175 stdout.write("parsing {} \r".format(path))
176 stdout.flush()
177
178 ast = parse_file(path, use_cpp = True, cpp_path = cross_gcc,
179 cpp_args = ["-E", "-I", "include", "-include", "predef.h"])
180 # ast.show()
181
182 vis.visit_path(path, ast)
183
184 print("")
185
186vis.fix()
Note: See TracBrowser for help on using the repository browser.