Mercurial > lcfOS
annotate python/ppci/c3/codegenerator.py @ 393:6ae782a085e0
Added init program
author | Windel Bouwman |
---|---|
date | Sat, 17 May 2014 21:17:40 +0200 |
parents | 2ec730e45ea1 |
children | 988f3fb861e4 |
rev | line source |
---|---|
255 | 1 import logging |
354 | 2 import struct |
301 | 3 from .. import ir |
307 | 4 from .. import irutils |
308 | 5 from . import astnodes as ast |
230 | 6 |
228 | 7 |
307 | 8 class SemanticError(Exception): |
308 | 9 """ Error thrown when a semantic issue is observed """ |
307 | 10 def __init__(self, msg, loc): |
308 | 11 super().__init__() |
307 | 12 self.msg = msg |
13 self.loc = loc | |
14 | |
15 | |
16 class CodeGenerator(irutils.Builder): | |
288 | 17 """ |
274 | 18 Generates intermediate (IR) code from a package. The entry function is |
19 'genModule'. The main task of this part is to rewrite complex control | |
20 structures, such as while and for loops into simple conditional | |
21 jump statements. Also complex conditional statements are simplified. | |
22 Such as 'and' and 'or' statements are rewritten in conditional jumps. | |
23 And structured datatypes are rewritten. | |
307 | 24 |
25 Type checking is done in one run with code generation. | |
274 | 26 """ |
307 | 27 def __init__(self, diag): |
261 | 28 self.logger = logging.getLogger('c3cgen') |
307 | 29 self.diag = diag |
261 | 30 |
217 | 31 def gencode(self, pkg): |
308 | 32 """ Generate code for a single module """ |
268 | 33 self.prepare() |
308 | 34 assert type(pkg) is ast.Package |
307 | 35 self.pkg = pkg |
36 self.intType = pkg.scope['int'] | |
37 self.boolType = pkg.scope['bool'] | |
389 | 38 self.pointerSize = 4 |
39 self.logger.debug('Generating ir-code for {}'.format(pkg.name), | |
40 extra={'c3_ast': pkg}) | |
288 | 41 self.varMap = {} # Maps variables to storage locations. |
268 | 42 self.m = ir.Module(pkg.name) |
307 | 43 try: |
389 | 44 for typ in pkg.Types: |
45 self.check_type(typ) | |
362 | 46 # Only generate function if function contains a body: |
389 | 47 real_functions = list(filter( |
48 lambda f: f.body, pkg.innerScope.Functions)) | |
307 | 49 for v in pkg.innerScope.Variables: |
364 | 50 v2 = ir.GlobalVariable(v.name) |
51 self.varMap[v] = v2 | |
363 | 52 if not v.isLocal: |
364 | 53 self.m.add_variable(v2) |
362 | 54 for s in real_functions: |
308 | 55 self.gen_function(s) |
307 | 56 except SemanticError as e: |
57 self.error(e.msg, e.loc) | |
313 | 58 if self.pkg.ok: |
59 return self.m | |
308 | 60 |
61 def error(self, msg, loc=None): | |
62 self.pkg.ok = False | |
63 self.diag.error(msg, loc) | |
307 | 64 |
308 | 65 def gen_function(self, fn): |
268 | 66 # TODO: handle arguments |
363 | 67 f = self.newFunction(fn.name) |
272 | 68 f.return_value = self.newTemp() |
268 | 69 self.setFunction(f) |
269 | 70 l2 = self.newBlock() |
71 self.emit(ir.Jump(l2)) | |
72 self.setBlock(l2) | |
268 | 73 # generate room for locals: |
174 | 74 |
268 | 75 for sym in fn.innerScope: |
389 | 76 self.check_type(sym.typ) |
272 | 77 if sym.isParameter: |
316 | 78 p = ir.Parameter(sym.name) |
79 variable = ir.LocalVariable(sym.name + '_copy') | |
80 f.addParameter(p) | |
81 f.addLocal(variable) | |
82 # Move parameter into local copy: | |
83 self.emit(ir.Move(ir.Mem(variable), p)) | |
274 | 84 elif sym.isLocal: |
308 | 85 variable = ir.LocalVariable(sym.name) |
86 f.addLocal(variable) | |
87 elif isinstance(sym, ast.Variable): | |
88 variable = ir.LocalVariable(sym.name) | |
89 f.addLocal(variable) | |
274 | 90 else: |
275 | 91 raise NotImplementedError('{}'.format(sym)) |
308 | 92 self.varMap[sym] = variable |
268 | 93 |
94 self.genCode(fn.body) | |
272 | 95 self.emit(ir.Move(f.return_value, ir.Const(0))) |
269 | 96 self.emit(ir.Jump(f.epiloog)) |
268 | 97 self.setFunction(None) |
158 | 98 |
217 | 99 def genCode(self, code): |
308 | 100 """ Wrapper around gen_stmt to catch errors """ |
307 | 101 try: |
308 | 102 self.gen_stmt(code) |
307 | 103 except SemanticError as e: |
104 self.error(e.msg, e.loc) | |
105 | |
308 | 106 def gen_stmt(self, code): |
107 """ Generate code for a statement """ | |
108 assert isinstance(code, ast.Statement) | |
268 | 109 self.setLoc(code.loc) |
308 | 110 if type(code) is ast.Compound: |
221 | 111 for s in code.statements: |
112 self.genCode(s) | |
308 | 113 elif type(code) is ast.Empty: |
306 | 114 pass |
308 | 115 elif type(code) is ast.Assignment: |
393 | 116 lval = self.gen_expr_code(code.lval) |
117 rval = self.gen_expr_code(code.rval) | |
389 | 118 if not self.equal_types(code.lval.typ, code.rval.typ): |
119 raise SemanticError('Cannot assign {} to {}' | |
120 .format(code.rval.typ, code.lval.typ), | |
121 code.loc) | |
307 | 122 if not code.lval.lvalue: |
389 | 123 raise SemanticError('No valid lvalue {}'.format(code.lval), |
124 code.lval.loc) | |
268 | 125 self.emit(ir.Move(lval, rval)) |
308 | 126 elif type(code) is ast.ExpressionStatement: |
393 | 127 self.emit(ir.Exp(self.gen_expr_code(code.ex))) |
308 | 128 elif type(code) is ast.If: |
268 | 129 bbtrue = self.newBlock() |
130 bbfalse = self.newBlock() | |
131 te = self.newBlock() | |
308 | 132 self.gen_cond_code(code.condition, bbtrue, bbfalse) |
268 | 133 self.setBlock(bbtrue) |
134 self.genCode(code.truestatement) | |
135 self.emit(ir.Jump(te)) | |
136 self.setBlock(bbfalse) | |
306 | 137 self.genCode(code.falsestatement) |
268 | 138 self.emit(ir.Jump(te)) |
139 self.setBlock(te) | |
308 | 140 elif type(code) is ast.Return: |
393 | 141 re = self.gen_expr_code(code.expr) |
303 | 142 self.emit(ir.Move(self.fn.return_value, re)) |
143 self.emit(ir.Jump(self.fn.epiloog)) | |
144 b = self.newBlock() | |
145 self.setBlock(b) | |
308 | 146 elif type(code) is ast.While: |
268 | 147 bbdo = self.newBlock() |
148 bbtest = self.newBlock() | |
149 te = self.newBlock() | |
150 self.emit(ir.Jump(bbtest)) | |
151 self.setBlock(bbtest) | |
308 | 152 self.gen_cond_code(code.condition, bbdo, te) |
268 | 153 self.setBlock(bbdo) |
228 | 154 self.genCode(code.statement) |
268 | 155 self.emit(ir.Jump(bbtest)) |
156 self.setBlock(te) | |
315 | 157 elif type(code) is ast.For: |
158 bbdo = self.newBlock() | |
159 bbtest = self.newBlock() | |
160 te = self.newBlock() | |
161 self.genCode(code.init) | |
162 self.emit(ir.Jump(bbtest)) | |
163 self.setBlock(bbtest) | |
164 self.gen_cond_code(code.condition, bbdo, te) | |
165 self.setBlock(bbdo) | |
166 self.genCode(code.statement) | |
360 | 167 self.genCode(code.final) |
315 | 168 self.emit(ir.Jump(bbtest)) |
169 self.setBlock(te) | |
393 | 170 elif type(code) is ast.Switch: |
171 raise NotImplementedError('Unknown stmt {}'.format(code)) | |
222 | 172 else: |
268 | 173 raise NotImplementedError('Unknown stmt {}'.format(code)) |
230 | 174 |
308 | 175 def gen_cond_code(self, expr, bbtrue, bbfalse): |
176 """ Generate conditional logic. | |
177 Implement sequential logical operators. """ | |
178 if type(expr) is ast.Binop: | |
268 | 179 if expr.op == 'or': |
180 l2 = self.newBlock() | |
308 | 181 self.gen_cond_code(expr.a, bbtrue, l2) |
389 | 182 if not self.equal_types(expr.a.typ, self.boolType): |
307 | 183 raise SemanticError('Must be boolean', expr.a.loc) |
268 | 184 self.setBlock(l2) |
308 | 185 self.gen_cond_code(expr.b, bbtrue, bbfalse) |
389 | 186 if not self.equal_types(expr.b.typ, self.boolType): |
307 | 187 raise SemanticError('Must be boolean', expr.b.loc) |
268 | 188 elif expr.op == 'and': |
189 l2 = self.newBlock() | |
308 | 190 self.gen_cond_code(expr.a, l2, bbfalse) |
389 | 191 if not self.equal_types(expr.a.typ, self.boolType): |
307 | 192 self.error('Must be boolean', expr.a.loc) |
268 | 193 self.setBlock(l2) |
308 | 194 self.gen_cond_code(expr.b, bbtrue, bbfalse) |
389 | 195 if not self.equal_types(expr.b.typ, self.boolType): |
307 | 196 raise SemanticError('Must be boolean', expr.b.loc) |
305 | 197 elif expr.op in ['==', '>', '<', '!=', '<=', '>=']: |
393 | 198 ta = self.gen_expr_code(expr.a) |
199 tb = self.gen_expr_code(expr.b) | |
389 | 200 if not self.equal_types(expr.a.typ, expr.b.typ): |
307 | 201 raise SemanticError('Types unequal {} != {}' |
389 | 202 .format(expr.a.typ, expr.b.typ), |
203 expr.loc) | |
268 | 204 self.emit(ir.CJump(ta, expr.op, tb, bbtrue, bbfalse)) |
205 else: | |
311 | 206 raise SemanticError('non-bool: {}'.format(expr.op), expr.loc) |
307 | 207 expr.typ = self.boolType |
308 | 208 elif type(expr) is ast.Literal: |
393 | 209 self.gen_expr_code(expr) |
288 | 210 if expr.val: |
268 | 211 self.emit(ir.Jump(bbtrue)) |
288 | 212 else: |
268 | 213 self.emit(ir.Jump(bbfalse)) |
228 | 214 else: |
288 | 215 raise NotImplementedError('Unknown cond {}'.format(expr)) |
354 | 216 |
217 # Check that the condition is a boolean value: | |
389 | 218 if not self.equal_types(expr.typ, self.boolType): |
307 | 219 self.error('Condition must be boolean', expr.loc) |
230 | 220 |
393 | 221 def gen_expr_code(self, expr): |
308 | 222 """ Generate code for an expression. Return the generated ir-value """ |
223 assert isinstance(expr, ast.Expression) | |
224 if type(expr) is ast.Binop: | |
307 | 225 expr.lvalue = False |
226 if expr.op in ['+', '-', '*', '/', '<<', '>>', '|', '&']: | |
393 | 227 ra = self.gen_expr_code(expr.a) |
228 rb = self.gen_expr_code(expr.b) | |
389 | 229 if self.equal_types(expr.a.typ, self.intType) and \ |
230 self.equal_types(expr.b.typ, self.intType): | |
307 | 231 expr.typ = expr.a.typ |
393 | 232 elif self.equal_types(expr.b.typ, self.intType) and \ |
233 type(expr.a.typ) is ast.PointerType: | |
234 # Special case for pointer arithmatic TODO: coerce! | |
235 expr.typ = expr.a.typ | |
307 | 236 else: |
237 raise SemanticError('Can only add integers', expr.loc) | |
238 else: | |
239 raise NotImplementedError("Cannot use equality as expressions") | |
268 | 240 return ir.Binop(ra, expr.op, rb) |
308 | 241 elif type(expr) is ast.Unop: |
307 | 242 if expr.op == '&': |
393 | 243 ra = self.gen_expr_code(expr.a) |
308 | 244 expr.typ = ast.PointerType(expr.a.typ) |
307 | 245 if not expr.a.lvalue: |
246 raise SemanticError('No valid lvalue', expr.a.loc) | |
247 expr.lvalue = False | |
248 assert type(ra) is ir.Mem | |
249 return ra.e | |
250 else: | |
251 raise NotImplementedError('Unknown unop {0}'.format(expr.op)) | |
308 | 252 elif type(expr) is ast.Identifier: |
307 | 253 # Generate code for this identifier. |
254 tg = self.resolveSymbol(expr) | |
255 expr.kind = type(tg) | |
256 expr.typ = tg.typ | |
279 | 257 # This returns the dereferenced variable. |
308 | 258 if isinstance(tg, ast.Variable): |
313 | 259 expr.lvalue = True |
307 | 260 return ir.Mem(self.varMap[tg]) |
313 | 261 elif isinstance(tg, ast.Constant): |
393 | 262 c_val = self.gen_expr_code(tg.value) |
313 | 263 return self.evalConst(c_val) |
280
02385f62f250
Rework from str interface to Instruction interface
Windel Bouwman
parents:
279
diff
changeset
|
264 else: |
308 | 265 raise NotImplementedError(str(tg)) |
266 elif type(expr) is ast.Deref: | |
222 | 267 # dereference pointer type: |
393 | 268 addr = self.gen_expr_code(expr.ptr) |
316 | 269 ptr_typ = self.the_type(expr.ptr.typ) |
307 | 270 expr.lvalue = True |
308 | 271 if type(ptr_typ) is ast.PointerType: |
307 | 272 expr.typ = ptr_typ.ptype |
273 return ir.Mem(addr) | |
274 else: | |
275 raise SemanticError('Cannot deref non-pointer', expr.loc) | |
308 | 276 elif type(expr) is ast.Member: |
393 | 277 base = self.gen_expr_code(expr.base) |
307 | 278 expr.lvalue = expr.base.lvalue |
316 | 279 basetype = self.the_type(expr.base.typ) |
308 | 280 if type(basetype) is ast.StructureType: |
307 | 281 if basetype.hasField(expr.field): |
282 expr.typ = basetype.fieldType(expr.field) | |
283 else: | |
284 raise SemanticError('{} does not contain field {}' | |
389 | 285 .format(basetype, expr.field), |
286 expr.loc) | |
307 | 287 else: |
308 | 288 raise SemanticError('Cannot select {} of non-structure type {}' |
289 .format(expr.field, basetype), expr.loc) | |
307 | 290 |
279 | 291 assert type(base) is ir.Mem, type(base) |
316 | 292 bt = self.the_type(expr.base.typ) |
268 | 293 offset = ir.Const(bt.fieldOffset(expr.field)) |
308 | 294 return ir.Mem(ir.Add(base.e, offset)) |
354 | 295 elif type(expr) is ast.Index: |
296 """ Array indexing """ | |
393 | 297 base = self.gen_expr_code(expr.base) |
298 idx = self.gen_expr_code(expr.i) | |
354 | 299 base_typ = self.the_type(expr.base.typ) |
300 if not isinstance(base_typ, ast.ArrayType): | |
389 | 301 raise SemanticError('Cannot index non-array type {}' |
302 .format(base_typ), | |
303 expr.base.loc) | |
354 | 304 idx_type = self.the_type(expr.i.typ) |
389 | 305 if not self.equal_types(idx_type, self.intType): |
306 raise SemanticError('Index must be int not {}' | |
307 .format(idx_type), expr.i.loc) | |
354 | 308 assert type(base) is ir.Mem |
309 element_type = self.the_type(base_typ.element_type) | |
310 element_size = self.size_of(element_type) | |
311 expr.typ = base_typ.element_type | |
312 expr.lvalue = True | |
313 | |
314 return ir.Mem(ir.Add(base.e, ir.Mul(idx, ir.Const(element_size)))) | |
308 | 315 elif type(expr) is ast.Literal: |
307 | 316 expr.lvalue = False |
389 | 317 typemap = {int: 'int', |
318 float: 'double', | |
319 bool: 'bool', | |
320 str: 'string'} | |
307 | 321 if type(expr.val) in typemap: |
322 expr.typ = self.pkg.scope[typemap[type(expr.val)]] | |
323 else: | |
389 | 324 raise SemanticError('Unknown literal type {}' |
325 .format(expr.val), expr.loc) | |
354 | 326 # Construct correct const value: |
327 if type(expr.val) is str: | |
389 | 328 cval = self.pack_string(expr.val) |
354 | 329 return ir.Addr(ir.Const(cval)) |
330 else: | |
331 return ir.Const(expr.val) | |
308 | 332 elif type(expr) is ast.TypeCast: |
333 return self.gen_type_cast(expr) | |
393 | 334 elif type(expr) is ast.Sizeof: |
335 # The type of this expression is int: | |
336 expr.typ = self.intType | |
337 self.check_type(expr.query_typ) | |
338 type_size = self.size_of(expr.query_typ) | |
339 return ir.Const(type_size) | |
308 | 340 elif type(expr) is ast.FunctionCall: |
341 return self.gen_function_call(expr) | |
225 | 342 else: |
259 | 343 raise NotImplementedError('Unknown expr {}'.format(expr)) |
307 | 344 |
389 | 345 def pack_string(self, txt): |
346 """ Pack a string using 4 bytes length followed by text data """ | |
347 length = struct.pack('<I', len(txt)) | |
348 data = txt.encode('ascii') | |
349 return length + data | |
350 | |
308 | 351 def gen_type_cast(self, expr): |
352 """ Generate code for type casting """ | |
393 | 353 ar = self.gen_expr_code(expr.a) |
316 | 354 from_type = self.the_type(expr.a.typ) |
355 to_type = self.the_type(expr.to_type) | |
389 | 356 if isinstance(from_type, ast.PointerType) and \ |
308 | 357 isinstance(to_type, ast.PointerType): |
358 expr.typ = expr.to_type | |
359 return ar | |
389 | 360 elif self.equal_types(self.intType, from_type) and \ |
361 isinstance(to_type, ast.PointerType): | |
362 expr.typ = expr.to_type | |
363 return ar | |
364 elif self.equal_types(self.intType, to_type) \ | |
364 | 365 and isinstance(from_type, ast.PointerType): |
366 expr.typ = expr.to_type | |
367 return ar | |
354 | 368 elif type(from_type) is ast.BaseType and from_type.name == 'byte' and \ |
369 type(to_type) is ast.BaseType and to_type.name == 'int': | |
370 expr.typ = expr.to_type | |
371 return ar | |
308 | 372 else: |
373 raise SemanticError('Cannot cast {} to {}' | |
374 .format(from_type, to_type), expr.loc) | |
353 | 375 |
308 | 376 def gen_function_call(self, expr): |
377 """ Generate code for a function call """ | |
378 # Evaluate the arguments: | |
393 | 379 args = [self.gen_expr_code(e) for e in expr.args] |
308 | 380 # Check arguments: |
381 tg = self.resolveSymbol(expr.proc) | |
382 if type(tg) is not ast.Function: | |
383 raise SemanticError('cannot call {}'.format(tg)) | |
384 ftyp = tg.typ | |
336
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
334
diff
changeset
|
385 fname = tg.package.name + '_' + tg.name |
308 | 386 ptypes = ftyp.parametertypes |
387 if len(expr.args) != len(ptypes): | |
388 raise SemanticError('{} requires {} arguments, {} given' | |
389 | 389 .format(fname, len(ptypes), len(expr.args)), |
390 expr.loc) | |
308 | 391 for arg, at in zip(expr.args, ptypes): |
389 | 392 if not self.equal_types(arg.typ, at): |
308 | 393 raise SemanticError('Got {}, expected {}' |
389 | 394 .format(arg.typ, at), arg.loc) |
308 | 395 # determine return type: |
396 expr.typ = ftyp.returntype | |
397 return ir.Call(fname, args) | |
398 | |
313 | 399 def evalConst(self, c): |
400 if isinstance(c, ir.Const): | |
401 return c | |
402 else: | |
403 raise SemanticError('Cannot evaluate constant {}'.format(c)) | |
404 | |
307 | 405 def resolveSymbol(self, sym): |
308 | 406 if type(sym) is ast.Member: |
307 | 407 base = self.resolveSymbol(sym.base) |
308 | 408 if type(base) is not ast.Package: |
409 raise SemanticError('Base is not a package', sym.loc) | |
307 | 410 scope = base.innerScope |
411 name = sym.field | |
308 | 412 elif type(sym) is ast.Identifier: |
307 | 413 scope = sym.scope |
414 name = sym.target | |
415 else: | |
416 raise NotImplementedError(str(sym)) | |
417 if name in scope: | |
418 s = scope[name] | |
419 else: | |
420 raise SemanticError('{} undefined'.format(name), sym.loc) | |
308 | 421 assert isinstance(s, ast.Symbol) |
307 | 422 return s |
423 | |
316 | 424 def size_of(self, t): |
425 """ Determine the byte size of a type """ | |
426 t = self.the_type(t) | |
427 if type(t) is ast.BaseType: | |
428 return t.bytesize | |
429 elif type(t) is ast.StructureType: | |
430 return sum(self.size_of(mem.typ) for mem in t.mems) | |
354 | 431 elif type(t) is ast.ArrayType: |
432 return t.size * self.size_of(t.element_type) | |
389 | 433 elif type(t) is ast.PointerType: |
434 return self.pointerSize | |
316 | 435 else: |
436 raise NotImplementedError(str(t)) | |
437 | |
389 | 438 def the_type(self, t, reveil_defined=True): |
439 """ Recurse until a 'real' type is found | |
440 When reveil_defined is True, defined types are resolved to | |
441 their backing types. | |
442 """ | |
308 | 443 if type(t) is ast.DefinedType: |
389 | 444 if reveil_defined: |
445 t = self.the_type(t.typ) | |
308 | 446 elif type(t) in [ast.Identifier, ast.Member]: |
389 | 447 t = self.the_type(self.resolveSymbol(t), reveil_defined) |
308 | 448 elif isinstance(t, ast.Type): |
307 | 449 pass |
450 else: | |
451 raise NotImplementedError(str(t)) | |
308 | 452 assert isinstance(t, ast.Type) |
307 | 453 return t |
454 | |
389 | 455 def equal_types(self, a, b, byname=False): |
456 """ Compare types a and b for structural equavalence. | |
457 if byname is True stop on defined types. | |
458 """ | |
307 | 459 # Recurse into named types: |
389 | 460 a = self.the_type(a, not byname) |
461 b = self.the_type(b, not byname) | |
307 | 462 |
389 | 463 # Check types for sanity: |
464 self.check_type(a) | |
465 self.check_type(b) | |
466 | |
467 # Do structural equivalence check: | |
307 | 468 if type(a) is type(b): |
308 | 469 if type(a) is ast.BaseType: |
307 | 470 return a.name == b.name |
308 | 471 elif type(a) is ast.PointerType: |
389 | 472 # If a pointed type is detected, stop structural |
473 # equivalence: | |
474 return self.equal_types(a.ptype, b.ptype, byname=True) | |
308 | 475 elif type(a) is ast.StructureType: |
307 | 476 if len(a.mems) != len(b.mems): |
477 return False | |
389 | 478 return all(self.equal_types(am.typ, bm.typ) for am, bm in |
307 | 479 zip(a.mems, b.mems)) |
354 | 480 elif type(a) is ast.ArrayType: |
389 | 481 return self.equal_types(a.element_type, b.element_type) |
482 elif type(a) is ast.DefinedType: | |
483 # Try by name in case of defined types: | |
484 return a.name == b.name | |
307 | 485 else: |
486 raise NotImplementedError('{} not implemented'.format(type(a))) | |
487 return False | |
389 | 488 |
489 def check_type(self, t, first=True, byname=False): | |
490 """ Determine struct offsets and check for recursiveness by using | |
491 mark and sweep algorithm. | |
492 The calling function could call this function with first set | |
493 to clear the marks. | |
494 """ | |
495 | |
496 # Reset the mark and sweep: | |
497 if first: | |
498 self.got_types = set() | |
499 | |
500 # Resolve the type: | |
501 t = self.the_type(t, not byname) | |
502 | |
503 # Check for recursion: | |
504 if t in self.got_types: | |
505 raise SemanticError('Recursive data type {}'.format(t), None) | |
506 | |
507 if type(t) is ast.BaseType: | |
508 pass | |
509 elif type(t) is ast.PointerType: | |
510 # If a pointed type is detected, stop structural | |
511 # equivalence: | |
512 self.check_type(t.ptype, first=False, byname=True) | |
513 elif type(t) is ast.StructureType: | |
514 self.got_types.add(t) | |
515 # Setup offsets of fields. Is this the right place?: | |
516 offset = 0 | |
517 for struct_member in t.mems: | |
518 self.check_type(struct_member.typ, first=False) | |
519 struct_member.offset = offset | |
520 offset = offset + self.size_of(struct_member.typ) | |
521 elif type(t) is ast.ArrayType: | |
522 self.check_type(t.element_type, first=False) | |
523 elif type(t) is ast.DefinedType: | |
524 pass | |
525 else: | |
526 raise NotImplementedError('{} not implemented'.format(type(t))) |