Franck Pommereau

untested C to Python-simulator translator

...@@ -47,6 +47,12 @@ class CAni (object) : ...@@ -47,6 +47,12 @@ class CAni (object) :
47 @RET.setter 47 @RET.setter
48 def RET (self, val) : 48 def RET (self, val) :
49 dict.__setitem__(self._env, "RET", val) 49 dict.__setitem__(self._env, "RET", val)
50 + @property
51 + def CASE (self) :
52 + return self._env.get("CASE", None)
53 + @CASE.setter
54 + def CASE (self, val) :
55 + dict.__setitem__(self._env, "CASE", val)
50 def exec (self, code) : 56 def exec (self, code) :
51 self._env.exec(code) 57 self._env.exec(code)
52 def eval (self, code) : 58 def eval (self, code) :
......
...@@ -46,6 +46,9 @@ class _CODE (CAni) : ...@@ -46,6 +46,9 @@ class _CODE (CAni) :
46 for key, val in self.items() : 46 for key, val in self.items() :
47 if isinstance(val, _CODE) : 47 if isinstance(val, _CODE) :
48 sub[key] = val.source() 48 sub[key] = val.source()
49 + elif isinstance(val, (list, tuple)) :
50 + sub[key] = "".join(v.source() if isinstance(v, _CODE) else str(v)
51 + for v in val)
49 else : 52 else :
50 sub[key] = val 53 sub[key] = val
51 return self.src.format(**sub) 54 return self.src.format(**sub)
...@@ -64,8 +67,29 @@ class _CODE (CAni) : ...@@ -64,8 +67,29 @@ class _CODE (CAni) :
64 else : 67 else :
65 return tex 68 return tex
66 69
70 +class RAW (_CODE) :
71 + _fields = []
72 + @autorepr
73 + def __init__ (self, src) :
74 + super().__init__(src=src)
75 + def __call__ (self) :
76 + pass
77 +
78 +class WS (RAW) :
79 + _fields = []
80 + def tex (self) :
81 + return self.src
82 +
67 class BLOCK (_CODE) : 83 class BLOCK (_CODE) :
68 _fields = ["*body"] 84 _fields = ["*body"]
85 + def __init__ (self, *l, **k) :
86 + super().__init__(*l, **k)
87 + self.body = list(self.body)
88 + def __repr__ (self) :
89 + return "{}({}{}{})".format(self.__class__.__name__,
90 + ", ".join(repr(b) for b in self.body),
91 + ", " if self.body and self.src else "",
92 + "src={}".format(self.src) if self.src else "")
69 def __call__ (self) : 93 def __call__ (self) :
70 self._at.add(self.IP) 94 self._at.add(self.IP)
71 for code in self.body : 95 for code in self.body :
...@@ -74,6 +98,15 @@ class BLOCK (_CODE) : ...@@ -74,6 +98,15 @@ class BLOCK (_CODE) :
74 return "".join(b.source() for b in self.body) 98 return "".join(b.source() for b in self.body)
75 def tex (self) : 99 def tex (self) :
76 return "".join(b.tex() for b in self.body) 100 return "".join(b.tex() for b in self.body)
101 + def append (self, code) :
102 + if not self.body :
103 + self.body.append(code)
104 + elif isinstance(self.body[-1], RAW) and isinstance(code, RAW) :
105 + self.body[-1] = RAW(self.body[-1].src + code.src)
106 + elif isinstance(code, RAW) and not code.src :
107 + pass
108 + else :
109 + self.body.append(code)
77 110
78 class STMT (_CODE) : 111 class STMT (_CODE) :
79 _fields = ["*steps"] 112 _fields = ["*steps"]
...@@ -113,24 +146,6 @@ class ENV (_CODE) : ...@@ -113,24 +146,6 @@ class ENV (_CODE) :
113 def source (self) : 146 def source (self) :
114 return "" 147 return ""
115 148
116 -class WS (_CODE) :
117 - _fields = []
118 - @autorepr
119 - def __init__ (self, src) :
120 - super().__init__(src=src)
121 - def __call__ (self) :
122 - pass
123 - def tex (self) :
124 - return self.src
125 -
126 -class RAW (_CODE) :
127 - _fields = []
128 - @autorepr
129 - def __init__ (self, src) :
130 - super().__init__(src=src)
131 - def __call__ (self) :
132 - pass
133 -
134 class XDECL (_CODE) : 149 class XDECL (_CODE) :
135 _fields = ["*names"] 150 _fields = ["*names"]
136 def __call__ (self) : 151 def __call__ (self) :
...@@ -169,6 +184,9 @@ class BreakLoop (Exception) : ...@@ -169,6 +184,9 @@ class BreakLoop (Exception) :
169 pass 184 pass
170 185
171 class BREAK (_CODE) : 186 class BREAK (_CODE) :
187 + def __init__ (self) :
188 + super().__init__()
189 + self.src = "break"
172 def __call__ (self) : 190 def __call__ (self) :
173 self._at.add(self.IP) 191 self._at.add(self.IP)
174 self.IP += 1 192 self.IP += 1
...@@ -243,3 +261,26 @@ class FUNC (_CODE) : ...@@ -243,3 +261,26 @@ class FUNC (_CODE) :
243 self.body() 261 self.body()
244 except FunctionReturn as exc : 262 except FunctionReturn as exc :
245 self._env["RET"] = exc.RET 263 self._env["RET"] = exc.RET
264 +
265 +class SWITCH (_CODE) :
266 + _fields = ["cond", "*cases"]
267 + def __call__ (self) :
268 + self.cond()
269 + cond = self.RET
270 + try :
271 + for case in self.cases :
272 + self.CASE = cond
273 + case()
274 + except BreakLoop :
275 + pass
276 +
277 +class CASE (_CODE) :
278 + _fields = ["value", "body"]
279 + def __call__ (self) :
280 + self.value()
281 + if self.RET == self.CASE :
282 + self.body()
283 +
284 +class DEFAULT (BLOCK) :
285 + def source (self) :
286 + return self.src.format(body=super().source())
......
File mode changed
1 +import re, sys, itertools
2 +import pycparser, colorama
3 +
4 +from .. import flow
5 +
6 +def escape (text) :
7 + return text.replace("{", "{{").replace("}", "}}")
8 +
9 +class String (str):
10 + def __new__(cls, content):
11 + self = super().__new__(cls, content)
12 + self._n = {0: 0}
13 + for n, match in enumerate(re.finditer("\n", self)) :
14 + self._n[n+1] = match.end()
15 + return self
16 + def last (self) :
17 + l = len(self._n) - 1
18 + return Coord(l, len(self) - self._n[l] + 1)
19 + def __call__ (self, coord) :
20 + return self._n[coord.line-1] + coord.column-1
21 + def __getitem__ (self, idx) :
22 + if isinstance(idx, Span) :
23 + a = self(idx.start)
24 + b = self(idx.stop)
25 + return super().__getitem__(slice(a,b))
26 + elif isinstance(idx, Coord) :
27 + return super().__getitem__(self(idx))
28 + elif isinstance(idx, slice) :
29 + if isinstance(idx.start, Coord) :
30 + a = self(idx.start)
31 + else :
32 + a = idx.start
33 + if isinstance(idx.stop, Coord) :
34 + b = self(idx.stop)
35 + else :
36 + b = idx.stop
37 + return super().__getitem__(slice(a,b))
38 + else :
39 + return super().__getitem__(idx)
40 + def index (self, sub, start=None, end=None) :
41 + if isinstance(start, Coord) :
42 + start = self(start)
43 + if isinstance(end, Coord) :
44 + end = self(end)
45 + return super().index(sub, start, end) - (start or 0)
46 + def rindex (self, sub, start=None, end=None) :
47 + if isinstance(start, Coord) :
48 + start = self(start)
49 + if isinstance(end, Coord) :
50 + end = self(end)
51 + return super().rindex(sub, start, end) - (end or 0)
52 + def sub (self, within, pairs) :
53 + parts = []
54 + last = within.start
55 + for span, text in pairs :
56 + parts.append(escape(self[last:span.start]))
57 + parts.append(text)
58 + last = span.stop
59 + parts.append(escape(self[last:within.stop]))
60 + return "".join(parts)
61 +
62 +class Coord (object) :
63 + def __init__ (self, l, c=None) :
64 + if c is None :
65 + self.line, self.column = l.line, l.column
66 + else :
67 + self.line, self.column = l or 1, c or 1
68 + def __eq__ (self, other) :
69 + return self.line == other.line and self.column == other.column
70 + def __lt__ (self, other) :
71 + return (self.line < other.line
72 + or (self.line == other.line and self.column < other.column))
73 + def __add__ (self, other) :
74 + return self.__class__(self.line, self.column + other)
75 + def __str__ (self) :
76 + return f"{self.line}:{self.column}"
77 +
78 +class Span (object) :
79 + def __init__ (self, start, stop) :
80 + self.start = Coord(start)
81 + self.stop = Coord(stop)
82 + def add (self, other) :
83 + if isinstance(other, Span) :
84 + if other.start is not None and other.start < self.start :
85 + self.start = other.start
86 + if other.stop is not None and other.stop > self.stop :
87 + self.stop = other.stop
88 + elif isinstance(other, Coord) :
89 + if other < self.start :
90 + self.start = other
91 + elif other > self.stop :
92 + self.stop = other
93 + elif isinstance(other, int) :
94 + if other > 0 :
95 + self.stop += other
96 + elif other < 0 :
97 + self.start += other
98 + else :
99 + raise TypeError(repr(other))
100 + def __str__ (self) :
101 + return f"{self.start}/{self.stop}"
102 +
103 +class SpanDict (dict) :
104 + def __init__ (self, ast, src) :
105 + super().__init__()
106 + self.src = String(src)
107 + self.do(ast)
108 + def do (self, node) :
109 + self.generic_do(node)
110 + name = node.__class__.__name__
111 + handler = getattr(self, "do_" + name, None)
112 + if handler is not None :
113 + handler(node)
114 + def generic_do (self, node) :
115 + coord = getattr(node, "coord", None)
116 + if coord is not None :
117 + span = self[node] = Span(Coord(coord), Coord(coord))
118 + else :
119 + span = self[node] = Span(Coord(sys.maxsize, sys.maxsize), Coord(1, 1))
120 + for _, child in node.children() :
121 + self.do(child)
122 + span.add(self[child])
123 + def do_ID (self, node) :
124 + self[node].add(len(node.name))
125 + def do_Constant (self, node) :
126 + self[node].add(len(node.value))
127 + def do_Break (self, node) :
128 + self[node].add(5)
129 + def do_Typedef (self, node) :
130 + if not self.src[self[node].start:self[node].stop].startswith("typedef") :
131 + self[node].start += self.src.rindex("typedef", 0, self[node].start)
132 + def do_TypeDecl (self, node) :
133 + self[node].add(len(node.declname))
134 + def do_Struct (self, node) :
135 + self[node].add(self.src.index("}", self[node].stop) + 1)
136 + def do_ArrayRef (self, node) :
137 + self[node].add(self.src.index("]", self[node].stop) + 1)
138 + def do_FuncCall (self, node) :
139 + self[node].add(self.src.index(")", self[node].stop) + 1)
140 + def do_FuncDecl (self, node) :
141 + self[node].add(self.src.index(")", self[node].stop) + 1)
142 + def do_FuncDef (self, node) :
143 + self[node.body].add(self.src.index("}", self[node.body].stop) + 1)
144 + self[node].add(self[node.body])
145 + self[node.body].start = self[node.decl].stop + 1
146 + while self.src[self[node.body].start] in " \t" :
147 + self[node.body].start += 1
148 + def do_UnaryOp (self, node) :
149 + if node.op in ("p++", "p--") :
150 + self[node].add(self.src.index(node.op[1:], self[node].stop)
151 + + len(node.op[1:]))
152 + def do_DoWhile (self, node) :
153 + self[node].add(self.src.index(")", self[node].stop) + 1)
154 + self[node].start += self.src.index("do", self[node].start)
155 + self[node.stmt].start = self[node].start + 2
156 + while self.src[self[node.stmt].start] in " \t" :
157 + self[node.stmt].start += 1
158 + if self.src[self[node.stmt].start] == "{" :
159 + self[node.stmt].add(self.src.index("}", self[node.stmt].stop) + 1)
160 + self[node].add(self[node.stmt])
161 + def do_If (self, node) :
162 + self[node].start += self.src.index("if", self[node].start)
163 + self[node.iftrue].start = (self[node.cond].stop
164 + + self.src.index(")", self[node.cond].stop) + 1)
165 + while self.src[self[node.iftrue].start] in " \t" :
166 + self[node.iftrue].start += 1
167 + if self.src[self[node.iftrue].start] == "{" :
168 + self[node.iftrue].add(self.src.index("}", self[node.iftrue].stop) + 1)
169 + self[node].add(self[node.iftrue])
170 + def do_While (self, node) :
171 + self[node].start += self.src.index("while", self[node].start)
172 + self[node.stmt].start = (self[node.cond].stop
173 + + self.src.index(")", self[node.cond].stop) + 1)
174 + while self.src[self[node.stmt].start] in " \t" :
175 + self[node.stmt].start += 1
176 + if self.src[self[node.stmt].start] == "{" :
177 + self[node.stmt].add(self.src.index("}", self[node.stmt].stop) + 1)
178 + self[node].add(self[node.stmt])
179 + def do_BinaryOp (self, node) :
180 + if ")" in self.src[self[node.left].stop:self[node.right].start] :
181 + while self.src[self[node].start] != "(" :
182 + self[node].start += -1
183 + def do_FileAST (self, node) :
184 + self[node] = Span(Coord(1,1), self.src.last())
185 + def do_Switch (self, node) :
186 + self[node].start += self.src.index("switch", self[node].start)
187 + self[node.stmt].start = (self[node.cond].stop
188 + + self.src.index(")", self[node.cond].stop) + 1)
189 + while self.src[self[node.stmt].start] in " \t" :
190 + self[node.stmt].start += 1
191 + if self.src[self[node.stmt].start] == "{" :
192 + self[node.stmt].add(self.src.index("}", self[node.stmt].stop) + 1)
193 + self[node].add(self[node.stmt])
194 +
195 +class SpanTree (object) :
196 + def __init__ (self, ast, span) :
197 + self.span = span[ast]
198 + self._ast = ast
199 + self._span = span
200 + for name in itertools.chain(getattr(ast, "attr_names", []),
201 + ast.__slots__) :
202 + attr = getattr(ast, name, None)
203 + if isinstance(attr, (list, tuple)) :
204 + setattr(self, name, type(attr)(self.__class__(v, span)
205 + if isinstance(v, pycparser.c_ast.Node)
206 + else v for v in attr))
207 + self.nodetype = ast.__class__.__name__
208 + def __repr__ (self) :
209 + return f"<ast.{self.nodetype} at {self.span}>"
210 + def __getattr__ (self, name) :
211 + ret = getattr(self._ast, name)
212 + if isinstance(ret, pycparser.c_ast.Node) :
213 + return self.__class__(ret, self._span)
214 + else :
215 + return ret
216 + def children (self) :
217 + for name, child in self._ast.children() :
218 + yield name, self.__class__(child, self._span)
219 + def dump (self, indent=" ", source=False) :
220 + print(f"{colorama.Style.BRIGHT}{self.nodetype}{colorama.Style.RESET_ALL} at"
221 + f" {colorama.Fore.YELLOW}{self.span}{colorama.Style.RESET_ALL}")
222 + for name in getattr(self, "attr_names", []) :
223 + attr = getattr(self, name, None)
224 + if not attr :
225 + continue
226 + attr_type = type(attr).__name__
227 + print(f"{indent}{colorama.Fore.BLUE}{name}{colorama.Style.RESET_ALL}"
228 + f" = {attr!r}"
229 + f" {colorama.Fore.WHITE}<{attr_type}>{colorama.Style.RESET_ALL}")
230 + if source :
231 + print(f"{indent}{colorama.Fore.GREEN}source{colorama.Style.RESET_ALL}"
232 + f" = {self.source!r}")
233 + for name, child in self.children() :
234 + print(f"{indent}{colorama.Fore.RED}{name}:{colorama.Style.RESET_ALL} ",
235 + end="")
236 + child.dump(indent + " ", source)
237 + @property
238 + def source (self) :
239 + return self._span.src[self.span]
240 + def get_source (self, start, stop) :
241 + return escape(self._span.src[start:stop])
242 + def sub_source (self, *pairs) :
243 + return self._span.src.sub(self.span, zip(pairs[::2], pairs[1::2]))
244 +
245 +_skip = ["/\\*(?ms:.*?)\\*/",
246 + "//.*",
247 + "#define .*",
248 + "#include .*"]
249 +_skip_re = re.compile("|".join(f"({e})" for e in _skip), re.M)
250 +_skip_clean = re.compile("[^\n]")
251 +
252 +def parse (source, path="<str>") :
253 + _src = []
254 + _cpp = []
255 + pos = 0
256 + for match in _skip_re.finditer(source) :
257 + _src.append(source[pos:match.start()])
258 + _cpp.append(match[0])
259 + pos = match.end()
260 + cppsrc = "".join(s + _skip_clean.sub(" ", c)
261 + for s, c in zip(_src, _cpp)) + source[pos:]
262 + parser = pycparser.CParser()
263 + ast = parser.parse(cppsrc, path)
264 + return SpanTree(ast, SpanDict(ast, source))
265 +
266 +class Translator (object) :
267 + def __init__ (self) :
268 + self.typedef = {}
269 + self.funcdef = {}
270 + def __call__ (self, node) :
271 + handler = getattr(self, "do_" + node.nodetype, self.generic_do)
272 + return handler(node)
273 + def generic_do (self, node) :
274 + block = flow.BLOCK()
275 + last = node.span.start
276 + for _, child in node.children() :
277 + if child.span.start > last :
278 + block.append(flow.RAW(node.get_source(last, child.span.start)))
279 + block.append(self(child))
280 + last = child.span.stop
281 + if last < node.span.stop :
282 + block.append(flow.RAW(node.get_source(last, node.span.stop)))
283 + return block
284 + def do_Typedef (self, node) :
285 + self.typedef[node.name] = node
286 + return flow.RAW(node.source)
287 + def do_FuncDef (self, node) :
288 + self.funcdef[node.decl.name] = node
289 + return flow.FUNC(self(node.body),
290 + src=node.sub_source(node.body.span, "{body}"))
291 + def do_Assignment (self, node) :
292 + src = node.source
293 + return flow.STMT(f"FIXME {src}", src=src)
294 + def do_FuncCall (self, node) :
295 + src = node.source
296 + return flow.STMT(f"FIXME {src}", src=src)
297 + def do_Decl (self, node) :
298 + src = node.source
299 + if node.init :
300 + return flow.DECL(node.name,
301 + flow.EXPR(f"FIXME {src}", src=src),
302 + animate=False,
303 + src=node.sub_source(node.init.span, "{init}"))
304 + else :
305 + return flow.DECL(node.name, animate=False, src=src)
306 + def do_If (self, node) :
307 + cond = node.cond.source
308 + if node.iffalse is None :
309 + return flow.IF(flow.EXPR(f"FIXME {cond}", src=cond),
310 + self(node.iftrue),
311 + src=node.sub_source(node.iftrue.span, "{then}"))
312 + else :
313 + return flow.IF(flow.EXPR(f"FIXME {cond}", src=cond),
314 + self(node.iftrue),
315 + self(node.iffalse),
316 + src=node.sub_source(node.iftrue.span, "{then}",
317 + node.iffalse.span, "{otherwise}"))
318 + def do_For (self, node) :
319 + init = node.init.source
320 + cond = node.cond.source
321 + step = node.next.source
322 + return flow.FOR(flow.STMT(f"FIXME {init}", src=init),
323 + flow.EXPR(f"FIXME {cond}", src=cond),
324 + flow.STMT(f"FIXME {step}", src=step),
325 + self(node.stmt),
326 + src=node.sub_source(node.init.span, "{init}",
327 + node.cond.span, "{cond}",
328 + node.next.span, "{step}",
329 + node.stmt.span, "{body}"))
330 + def do_While (self, node) :
331 + cond = node.cond.source
332 + return flow.WHILE(flow.EXPR(f"FIXME {cond}", src=cond),
333 + self(node.stmt),
334 + src=node.sub_source(node.cond.span, "{cond}",
335 + node.stmt.span, "{body}"))
336 + def do_DoWhile (self, node) :
337 + cond = node.cond.source
338 + return flow.DO(self(node.stmt),
339 + flow.EXPR(f"FIXME {cond}", src=cond),
340 + src=node.sub_source(node.stmt.span, "{body}",
341 + node.cond.span, "{cond}"))
342 + def do_Switch (self, node) :
343 + cond = node.cond.source
344 + block = flow.BLOCK()
345 + last = node.stmt.span.start
346 + for _, child in node.stmt.children() :
347 + if child.span.start > last :
348 + block.append(flow.RAW(node.get_source(last, child.span.start)))
349 + block.append(self(child))
350 + last = child.span.stop
351 + if last < node.span.stop :
352 + block.append(flow.RAW(node.get_source(last, node.span.stop)))
353 + return flow.SWITCH(flow.EXPR(f"FIXME {cond}", src=cond),
354 + *block.body,
355 + src=node.sub_source(node.cond.span, "{cond}",
356 + node.stmt.span, "{cases}"))
357 + def do_Case (self, node) :
358 + value = node.expr.source
359 + block = flow.BLOCK()
360 + last = None
361 + for child in node.stmts :
362 + if last is not None and child.span.start > last :
363 + block.append(flow.RAW(node.get_source(last, child.span.start)))
364 + block.append(self(child))
365 + last = child.span.stop
366 + if last < node.span.stop :
367 + block.append(flow.RAW(node.get_source(last, node.span.stop)))
368 + return flow.CASE(flow.EXPR(f"FIXME {value}", src=value),
369 + block,
370 + src=node.sub_source(node.expr.span, "{value}",
371 + Span(node.stmts[0].span.start,
372 + node.stmts[-1].span.stop), "{body}"))
373 + def do_Default (self, node) :
374 + default = flow.DEFAULT(src=node.sub_source(Span(node.stmts[0].span.start,
375 + node.stmts[-1].span.stop),
376 + "{body}"))
377 + last = None
378 + for child in node.stmts :
379 + if last is not None and child.span.start > last :
380 + default.append(flow.RAW(node.get_source(last, child.span.start)))
381 + default.append(self(child))
382 + last = child.span.stop
383 + if last < node.span.stop :
384 + default.append(flow.RAW(node.get_source(last, node.span.stop)))
385 + return default
386 + def do_Break (self, node) :
387 + return flow.BREAK()