source: buchla-68k/misc/fix-proto.py@ dfe4288

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

Prototype fix framework.

  • Property mode set to 100755
File size: 5.1 KB
Line 
1#!/usr/bin/env python3
2
3from sys import stdout
4from os import unlink
5from pickle import load
6from pycparser import c_ast, parse_file, c_generator
7from re import subn, escape
8
9cross_gcc = "/opt/cross-m68k/bin/m68k-none-elf-gcc"
10
11class Visitor(c_ast.NodeVisitor):
12 def reset(self):
13 self.path = None
14 self.orig = None
15 self.align = None
16
17 self.func_def = False
18 self.prev_line = 0
19 self.this_line = None
20 self.subs = []
21 self.sub_def = False
22
23 def __init__(self):
24 with open("proto.dat", "rb") as f:
25 proto = load(f)
26
27 self.proto = {}
28
29 for p in proto:
30 self.proto[p.name] = p
31
32 self.gen = c_generator.CGenerator()
33 self.reset()
34
35 def visit_Decl(self, node):
36 if node.coord.file != self.path:
37 return
38
39 sub_def = self.func_def
40 self.func_def = False
41
42 if type(node.type) is not c_ast.FuncDecl:
43 return
44
45 if node.coord.line <= self.prev_line:
46 return
47
48 if self.this_line is None:
49 self.this_line = node.coord.line
50
51 if node.coord.line != self.this_line:
52 return
53
54 self.sub_def = sub_def
55
56 self.generic_visit(node)
57 self.subs.append(node)
58
59 def visit_FuncDef(self, node):
60 if node.coord.file != self.path:
61 return
62
63 self.func_def = True
64 self.generic_visit(node)
65
66 def get_ast(self):
67 with open(self.path, "w") as f:
68 f.write(self.orig)
69
70 ast = parse_file(self.path, use_cpp = True, cpp_path = cross_gcc,
71 cpp_args = ["-E", "-I", "include", "-include", "predef.h"])
72 # ast.show()
73
74 unlink(self.path)
75 return ast
76
77 def make_old_new(self, sub):
78 old = self.gen.visit(sub).replace("*" + sub.name, "* " + sub.name)
79
80 old_type = sub.type
81 sub.type = self.proto[sub.name].type
82
83 new = self.gen.visit(sub)
84 sub.type = old_type
85
86 print("{} -> {}".format(old, new))
87 return (old, new)
88
89 def replace_dec(self):
90 print("--- {}:{}:".format(self.path, self.this_line))
91
92 lines = self.orig.split("\n")
93 out = lines[:self.this_line - 1]
94
95 for sub in self.subs:
96 (_, new) = self.make_old_new(sub)
97
98 if self.align:
99 news_spa = new.split(" ")
100 news_tab = []
101
102 while news_spa[0] in ["extern", "char", "short", "int",
103 "unsigned", "long", "struct", "void"]:
104 is_struct = news_spa[0] == "struct"
105
106 news_tab.append(news_spa[0])
107 news_spa = news_spa[1:]
108
109 if is_struct:
110 news_tab.append(news_spa[0])
111 news_spa = news_spa[1:]
112
113 new_spa = " ".join(news_spa)
114 new_tab = "\t".join(news_tab)
115 new = new_tab + "\t" + new_spa
116
117 out.append(new + ";")
118
119 out += lines[self.this_line:]
120 self.orig = "\n".join(out)
121
122 self.this_line += len(self.subs) - 1
123
124 def replace_def(self):
125 print("--- {}:{}:".format(self.path, self.this_line))
126
127 def make_re(olds, strip = None):
128 escs = [escape(x) for x in olds if x != strip]
129 re = "[\t\n ]*".join(escs) + "[^{/]*\n{"
130 # print("re {}".format(re))
131 return re
132
133 for sub in self.subs:
134 (old, new) = self.make_old_new(sub)
135
136 olds = old.split(" ")
137 new += "\n{"
138
139 (new_orig, n) = subn(make_re(olds), new, self.orig)
140
141 if n == 0 and "int" in olds:
142 (new_orig, n) = subn(make_re(olds, "int"), new, self.orig)
143
144 if n != 1:
145 raise Exception("error while replacing definition")
146
147 self.orig = new_orig
148
149 def fix(self, path, orig):
150 self.path = path
151 self.orig = orig
152 self.align = "extern\t" in orig or \
153 "char\t" in orig or \
154 "short\t" in orig or \
155 "int\t" in orig or \
156 "long\t" in orig
157
158 while True:
159 self.visit(self.get_ast())
160
161 if self.this_line is None:
162 break
163
164 if self.sub_def:
165 self.replace_def()
166 else:
167 self.replace_dec()
168
169 self.prev_line = self.this_line
170 self.this_line = None
171 self.subs = []
172 self.sub_def = False
173
174 fixed = self.orig
175 self.reset()
176 return fixed
177
178vis = Visitor()
179
180with open("misc/c-files.txt", "r") as f:
181 for path in f:
182 path = path.rstrip()
183
184 if path == "ram/wdfield.c": # breaks pycparser
185 continue
186
187 stdout.write("fixing {} \r".format(path))
188 stdout.flush()
189
190 with open(path, "r") as f:
191 orig = f.read()
192
193 segs = path.split("/")
194 path_ = "/".join(segs[:-1] + ["_" + segs[-1]])
195
196 fixed = vis.fix(path_, orig)
197
198 with open(path, "w") as f:
199 f.write(fixed)
200
201 print("")
Note: See TracBrowser for help on using the repository browser.