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

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

Align FILE and PFS.

  • 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 "FILE", "PFS"]:
105 is_struct = news_spa[0] == "struct"
106
107 news_tab.append(news_spa[0])
108 news_spa = news_spa[1:]
109
110 if is_struct:
111 news_tab.append(news_spa[0])
112 news_spa = news_spa[1:]
113
114 new_spa = " ".join(news_spa)
115 new_tab = "\t".join(news_tab)
116 new = new_tab + "\t" + new_spa
117
118 out.append(new + ";")
119
120 out += lines[self.this_line:]
121 self.orig = "\n".join(out)
122
123 self.this_line += len(self.subs) - 1
124
125 def replace_def(self):
126 print("--- {}:{}:".format(self.path, self.this_line))
127
128 def make_re(olds, strip = None):
129 escs = [escape(x) for x in olds if x != strip]
130 re = "[\t\n ]*".join(escs) + "[^{/]*\n{"
131 # print("re {}".format(re))
132 return re
133
134 for sub in self.subs:
135 (old, new) = self.make_old_new(sub)
136
137 olds = old.split(" ")
138 new += "\n{"
139
140 (new_orig, n) = subn(make_re(olds), new, self.orig)
141
142 if n == 0 and "int" in olds:
143 (new_orig, n) = subn(make_re(olds, "int"), new, self.orig)
144
145 if n != 1:
146 raise Exception("error while replacing definition")
147
148 self.orig = new_orig
149
150 def fix(self, path, orig):
151 self.path = path
152 self.orig = orig
153 self.align = "extern\t" in orig or \
154 "char\t" in orig or \
155 "short\t" in orig or \
156 "int\t" in orig or \
157 "long\t" in orig
158
159 while True:
160 self.visit(self.get_ast())
161
162 if self.this_line is None:
163 break
164
165 if self.sub_def:
166 self.replace_def()
167 else:
168 self.replace_dec()
169
170 self.prev_line = self.this_line
171 self.this_line = None
172 self.subs = []
173 self.sub_def = False
174
175 fixed = self.orig
176 self.reset()
177 return fixed
178
179vis = Visitor()
180
181with open("misc/c-files.txt", "r") as f:
182 for path in f:
183 path = path.rstrip()
184
185 if path == "ram/wdfield.c": # breaks pycparser
186 continue
187
188 stdout.write("fixing {} \r".format(path))
189 stdout.flush()
190
191 with open(path, "r") as f:
192 orig = f.read()
193
194 segs = path.split("/")
195 path_ = "/".join(segs[:-1] + ["_" + segs[-1]])
196
197 fixed = vis.fix(path_, orig)
198
199 with open(path, "w") as f:
200 f.write(fixed)
201
202 print("")
Note: See TracBrowser for help on using the repository browser.