get first revision setvl operational in ISACaller
[soc.git] / src / soc / decoder / pseudo / parser.py
1 # Based on GardenSnake - a parser generator demonstration program
2 # GardenSnake was released into the Public Domain by Andrew Dalke.
3
4 # Portions of this work are derived from Python's Grammar definition
5 # and may be covered under the Python copyright and license
6 #
7 # Andrew Dalke / Dalke Scientific Software, LLC
8 # 30 August 2006 / Cape Town, South Africa
9
10 # Modifications for inclusion in PLY distribution
11 from pprint import pprint
12 from ply import lex, yacc
13 import astor
14 from copy import deepcopy
15
16 from soc.decoder.power_decoder import create_pdecode
17 from soc.decoder.pseudo.lexer import IndentLexer
18 from soc.decoder.orderedset import OrderedSet
19
20 # I use the Python AST
21 #from compiler import ast
22 import ast
23
24 # Helper function
25
26
27 def Assign(autoassign, assignname, left, right, iea_mode):
28 names = []
29 print("Assign", assignname, left, right)
30 if isinstance(left, ast.Name):
31 # Single assignment on left
32 # XXX when doing IntClass, which will have an "eq" function,
33 # this is how to access it
34 # eq = ast.Attribute(left, "eq") # get eq fn
35 # return ast.Call(eq, [right], []) # now call left.eq(right)
36 return ast.Assign([ast.Name(left.id, ast.Store())], right)
37 elif isinstance(left, ast.Tuple):
38 # List of things - make sure they are Name nodes
39 names = []
40 for child in left.getChildren():
41 if not isinstance(child, ast.Name):
42 raise SyntaxError("that assignment not supported")
43 names.append(child.name)
44 ass_list = [ast.AssName(name, 'OP_ASSIGN') for name in names]
45 return ast.Assign([ast.AssTuple(ass_list)], right)
46 elif isinstance(left, ast.Subscript):
47 ls = left.slice
48 # XXX changing meaning of "undefined" to a function
49 #if (isinstance(ls, ast.Slice) and isinstance(right, ast.Name) and
50 # right.id == 'undefined'):
51 # # undefined needs to be copied the exact same slice
52 # right = ast.Subscript(right, ls, ast.Load())
53 # return ast.Assign([left], right)
54 res = ast.Assign([left], right)
55 if autoassign and isinstance(ls, ast.Slice):
56 # hack to create a variable pre-declared based on a slice.
57 # dividend[0:32] = (RA)[0:32] will create
58 # dividend = [0] * 32
59 # dividend[0:32] = (RA)[0:32]
60 # the declaration makes the slice-assignment "work"
61 lower, upper, step = ls.lower, ls.upper, ls.step
62 print("lower, upper, step", repr(lower), repr(upper), step)
63 if not isinstance(lower, ast.Constant) or \
64 not isinstance(upper, ast.Constant):
65 return res
66 qty = ast.Num(upper.value-lower.value)
67 keywords = [ast.keyword(arg='repeat', value=qty)]
68 l = [ast.Num(0)]
69 right = ast.Call(ast.Name("concat", ast.Load()), l, keywords)
70 declare = ast.Assign([ast.Name(assignname, ast.Store())], right)
71 return [declare, res]
72 return res
73 # XXX HMMM probably not needed...
74 ls = left.slice
75 if isinstance(ls, ast.Slice):
76 lower, upper, step = ls.lower, ls.upper, ls.step
77 print("slice assign", lower, upper, step)
78 if step is None:
79 ls = (lower, upper, None)
80 else:
81 ls = (lower, upper, step)
82 ls = ast.Tuple(ls)
83 return ast.Call(ast.Name("selectassign", ast.Load()),
84 [left.value, ls, right], [])
85 else:
86 print("Assign fail")
87 raise SyntaxError("Can't do that yet")
88
89
90 # I implemented INDENT / DEDENT generation as a post-processing filter
91
92 # The original lex token stream contains WS and NEWLINE characters.
93 # WS will only occur before any other tokens on a line.
94
95 # I have three filters. One tags tokens by adding two attributes.
96 # "must_indent" is True if the token must be indented from the
97 # previous code. The other is "at_line_start" which is True for WS
98 # and the first non-WS/non-NEWLINE on a line. It flags the check so
99 # see if the new line has changed indication level.
100
101
102 # No using Python's approach because Ply supports precedence
103
104 # comparison: expr (comp_op expr)*
105 # arith_expr: term (('+'|'-') term)*
106 # term: factor (('*'|'/'|'%'|'//') factor)*
107 # factor: ('+'|'-'|'~') factor | power
108 # comp_op: '<'|'>'|'=='|'>='|'<='|'<>'|'!='|'in'|'not' 'in'|'is'|'is' 'not'
109
110 def make_le_compare(arg):
111 (left, right) = arg
112 return ast.Call(ast.Name("le", ast.Load()), (left, right), [])
113
114
115 def make_ge_compare(arg):
116 (left, right) = arg
117 return ast.Call(ast.Name("ge", ast.Load()), (left, right), [])
118
119
120 def make_lt_compare(arg):
121 (left, right) = arg
122 return ast.Call(ast.Name("lt", ast.Load()), (left, right), [])
123
124
125 def make_gt_compare(arg):
126 (left, right) = arg
127 return ast.Call(ast.Name("gt", ast.Load()), (left, right), [])
128
129
130 def make_eq_compare(arg):
131 (left, right) = arg
132 return ast.Call(ast.Name("eq", ast.Load()), (left, right), [])
133
134
135 def make_ne_compare(arg):
136 (left, right) = arg
137 return ast.Call(ast.Name("ne", ast.Load()), (left, right), [])
138
139
140 binary_ops = {
141 "^": ast.BitXor(),
142 "&": ast.BitAnd(),
143 "|": ast.BitOr(),
144 "+": ast.Add(),
145 "-": ast.Sub(),
146 "*": ast.Mult(),
147 "/": ast.FloorDiv(),
148 "%": ast.Mod(),
149 "<=": make_le_compare,
150 ">=": make_ge_compare,
151 "<": make_lt_compare,
152 ">": make_gt_compare,
153 "=": make_eq_compare,
154 "!=": make_ne_compare,
155 }
156 unary_ops = {
157 "+": ast.UAdd(),
158 "-": ast.USub(),
159 "¬": ast.Invert(),
160 }
161
162
163 def check_concat(node): # checks if the comparison is already a concat
164 print("check concat", node)
165 if not isinstance(node, ast.Call):
166 return [node]
167 print("func", node.func.id)
168 if node.func.id != 'concat':
169 return [node]
170 if node.keywords: # a repeated list-constant, don't optimise
171 return [node]
172 return node.args
173
174
175 # identify SelectableInt pattern [something] * N
176 # must return concat(something, repeat=N)
177 def identify_sint_mul_pattern(p):
178 if p[2] != '*': # multiply
179 return False
180 if not isinstance(p[3], ast.Constant): # rhs = Num
181 return False
182 if not isinstance(p[1], ast.List): # lhs is a list
183 return False
184 l = p[1].elts
185 if len(l) != 1: # lhs is a list of length 1
186 return False
187 return True # yippee!
188
189
190 def apply_trailer(atom, trailer):
191 if trailer[0] == "TLIST":
192 # assume depth of one
193 atom = apply_trailer(atom, trailer[1])
194 trailer = trailer[2]
195 if trailer[0] == "CALL":
196 #p[0] = ast.Expr(ast.Call(p[1], p[2][1], []))
197 return ast.Call(atom, trailer[1], [])
198 # if p[1].id == 'print':
199 # p[0] = ast.Printnl(ast.Tuple(p[2][1]), None, None)
200 # else:
201 # p[0] = ast.CallFunc(p[1], p[2][1], None, None)
202 else:
203 print("subscript atom", trailer[1])
204 #raise AssertionError("not implemented %s" % p[2][0])
205 subs = trailer[1]
206 if len(subs) == 1:
207 idx = subs[0]
208 else:
209 idx = ast.Slice(subs[0], subs[1], None)
210 # if isinstance(atom, ast.Name) and atom.id == 'CR':
211 # atom.id = 'CR' # bad hack
212 #print ("apply_trailer Subscript", atom.id, idx)
213 return ast.Subscript(atom, idx, ast.Load())
214
215 ########## Parser (tokens -> AST) ######
216
217 # also part of Ply
218 #import yacc
219
220 # https://www.mathcs.emory.edu/~valerie/courses/fall10/155/resources/op_precedence.html
221 # python operator precedence
222 # Highest precedence at top, lowest at bottom.
223 # Operators in the same box evaluate left to right.
224 #
225 # Operator Description
226 # () Parentheses (grouping)
227 # f(args...) Function call
228 # x[index:index] Slicing
229 # x[index] Subscription
230 # x.attribute Attribute reference
231 # ** Exponentiation
232 # ~x Bitwise not
233 # +x, -x Positive, negative
234 # *, /, % mul, div, remainder
235 # +, - Addition, subtraction
236 # <<, >> Bitwise shifts
237 # & Bitwise AND
238 # ^ Bitwise XOR
239 # | Bitwise OR
240 # in, not in, is, is not, <, <=, >, >=, <>, !=, == comp, membership, ident
241 # not x Boolean NOT
242 # and Boolean AND
243 # or Boolean OR
244 # lambda Lambda expression
245
246
247 class PowerParser:
248
249 precedence = (
250 ("left", "EQ", "NE", "GT", "LT", "LE", "GE", "LTU", "GTU"),
251 ("left", "BITOR"),
252 ("left", "BITXOR"),
253 ("left", "BITAND"),
254 ("left", "PLUS", "MINUS"),
255 ("left", "MULT", "DIV", "MOD"),
256 ("left", "INVERT"),
257 )
258
259 def __init__(self, form, include_carry_in_write=False):
260 self.include_ca_in_write = include_carry_in_write
261 self.gprs = {}
262 form = self.sd.sigforms[form]
263 print(form)
264 formkeys = form._asdict().keys()
265 self.declared_vars = set()
266 for rname in ['RA', 'RB', 'RC', 'RT', 'RS']:
267 self.gprs[rname] = None
268 self.declared_vars.add(rname)
269 self.available_op_fields = set()
270 for k in formkeys:
271 if k not in self.gprs:
272 if k == 'SPR': # sigh, lower-case to not conflict
273 k = k.lower()
274 self.available_op_fields.add(k)
275 self.op_fields = OrderedSet()
276 self.read_regs = OrderedSet()
277 self.uninit_regs = OrderedSet()
278 self.write_regs = OrderedSet()
279 self.special_regs = OrderedSet() # see p_atom_name
280
281 # The grammar comments come from Python's Grammar/Grammar file
282
283 # NB: compound_stmt in single_input is followed by extra NEWLINE!
284 # file_input: (NEWLINE | stmt)* ENDMARKER
285
286 def p_file_input_end(self, p):
287 """file_input_end : file_input ENDMARKER"""
288 print("end", p[1])
289 p[0] = p[1]
290
291 def p_file_input(self, p):
292 """file_input : file_input NEWLINE
293 | file_input stmt
294 | NEWLINE
295 | stmt"""
296 if isinstance(p[len(p)-1], str):
297 if len(p) == 3:
298 p[0] = p[1]
299 else:
300 p[0] = [] # p == 2 --> only a blank line
301 else:
302 if len(p) == 3:
303 p[0] = p[1] + p[2]
304 else:
305 p[0] = p[1]
306
307 # funcdef: [decorators] 'def' NAME parameters ':' suite
308 # ignoring decorators
309
310 def p_funcdef(self, p):
311 "funcdef : DEF NAME parameters COLON suite"
312 p[0] = ast.FunctionDef(p[2], p[3], p[5], ())
313
314 # parameters: '(' [varargslist] ')'
315 def p_parameters(self, p):
316 """parameters : LPAR RPAR
317 | LPAR varargslist RPAR"""
318 if len(p) == 3:
319 args = []
320 else:
321 args = p[2]
322 p[0] = ast.arguments(args=args, vararg=None, kwarg=None, defaults=[])
323
324 # varargslist: (fpdef ['=' test] ',')* ('*' NAME [',' '**' NAME] |
325 # '**' NAME) |
326 # highly simplified
327
328 def p_varargslist(self, p):
329 """varargslist : varargslist COMMA NAME
330 | NAME"""
331 if len(p) == 4:
332 p[0] = p[1] + p[3]
333 else:
334 p[0] = [p[1]]
335
336 # stmt: simple_stmt | compound_stmt
337 def p_stmt_simple(self, p):
338 """stmt : simple_stmt"""
339 # simple_stmt is a list
340 p[0] = p[1]
341
342 def p_stmt_compound(self, p):
343 """stmt : compound_stmt"""
344 p[0] = [p[1]]
345
346 # simple_stmt: small_stmt (';' small_stmt)* [';'] NEWLINE
347 def p_simple_stmt(self, p):
348 """simple_stmt : small_stmts NEWLINE
349 | small_stmts SEMICOLON NEWLINE"""
350 p[0] = p[1]
351
352 def p_small_stmts(self, p):
353 """small_stmts : small_stmts SEMICOLON small_stmt
354 | small_stmt"""
355 if len(p) == 4:
356 p[0] = p[1] + [p[3]]
357 elif isinstance(p[1], list):
358 p[0] = p[1]
359 else:
360 p[0] = [p[1]]
361
362 # small_stmt: expr_stmt | print_stmt | del_stmt | pass_stmt | flow_stmt |
363 # import_stmt | global_stmt | exec_stmt | assert_stmt
364 def p_small_stmt(self, p):
365 """small_stmt : flow_stmt
366 | break_stmt
367 | expr_stmt"""
368 if isinstance(p[1], ast.Call):
369 p[0] = ast.Expr(p[1])
370 elif isinstance(p[1], ast.Name) and p[1].id == 'TRAP':
371 # TRAP needs to actually be a function
372 name = ast.Name("self", ast.Load())
373 name = ast.Attribute(name, "TRAP", ast.Load())
374 p[0] = ast.Call(name, [], [])
375 else:
376 p[0] = p[1]
377
378 # expr_stmt: testlist (augassign (yield_expr|testlist) |
379 # ('=' (yield_expr|testlist))*)
380 # augassign: ('+=' | '-=' | '*=' | '/=' | '%=' | '&=' | '|=' | '^=' |
381 # '<<=' | '>>=' | '**=' | '//=')
382 def p_expr_stmt(self, p):
383 """expr_stmt : testlist ASSIGNEA testlist
384 | testlist ASSIGN testlist
385 | testlist """
386 print("expr_stmt", p)
387 if len(p) == 2:
388 # a list of expressions
389 #p[0] = ast.Discard(p[1])
390 p[0] = p[1]
391 else:
392 iea_mode = p[2] == '<-iea'
393 name = None
394 autoassign = False
395 if isinstance(p[1], ast.Name):
396 name = p[1].id
397 elif isinstance(p[1], ast.Subscript):
398 if isinstance(p[1].value, ast.Name):
399 name = p[1].value.id
400 if name in self.gprs:
401 # add to list of uninitialised
402 self.uninit_regs.add(name)
403 autoassign = (name not in self.declared_vars and
404 name not in self.special_regs)
405 elif isinstance(p[1], ast.Call) and p[1].func.id in ['GPR', 'SPR']:
406 print(astor.dump_tree(p[1]))
407 # replace GPR(x) with GPR[x]
408 idx = p[1].args[0]
409 p[1] = ast.Subscript(p[1].func, idx, ast.Load())
410 elif isinstance(p[1], ast.Call) and p[1].func.id == 'MEM':
411 print("mem assign")
412 print(astor.dump_tree(p[1]))
413 p[1].func.id = "memassign" # change function name to set
414 p[1].args.append(p[3])
415 p[0] = p[1]
416 print("mem rewrite")
417 print(astor.dump_tree(p[0]))
418 return
419 else:
420 print("help, help")
421 print(astor.dump_tree(p[1]))
422 print("expr assign", name, p[1])
423 if name and name in self.gprs:
424 self.write_regs.add(name) # add to list of regs to write
425 p[0] = Assign(autoassign, name, p[1], p[3], iea_mode)
426 if name:
427 self.declared_vars.add(name)
428
429 def p_flow_stmt(self, p):
430 "flow_stmt : return_stmt"
431 p[0] = p[1]
432
433 # return_stmt: 'return' [testlist]
434 def p_return_stmt(self, p):
435 "return_stmt : RETURN testlist"
436 p[0] = ast.Return(p[2])
437
438 def p_compound_stmt(self, p):
439 """compound_stmt : if_stmt
440 | while_stmt
441 | switch_stmt
442 | for_stmt
443 | funcdef
444 """
445 p[0] = p[1]
446
447 def p_break_stmt(self, p):
448 """break_stmt : BREAK
449 """
450 p[0] = ast.Break()
451
452 def p_for_stmt(self, p):
453 """for_stmt : FOR atom EQ test TO test COLON suite
454 | DO atom EQ test TO test COLON suite
455 """
456 start = p[4]
457 end = p[6]
458 if start.value > end.value: # start greater than end, must go -ve
459 # auto-subtract-one (sigh) due to python range
460 end = ast.BinOp(p[6], ast.Add(), ast.Constant(-1))
461 arange = [start, end, ast.Constant(-1)]
462 else:
463 # auto-add-one (sigh) due to python range
464 end = ast.BinOp(p[6], ast.Add(), ast.Constant(1))
465 arange = [start, end]
466 it = ast.Call(ast.Name("range", ast.Load()), arange, [])
467 p[0] = ast.For(p[2], it, p[8], [])
468
469 def p_while_stmt(self, p):
470 """while_stmt : DO WHILE test COLON suite ELSE COLON suite
471 | DO WHILE test COLON suite
472 """
473 if len(p) == 6:
474 p[0] = ast.While(p[3], p[5], [])
475 else:
476 p[0] = ast.While(p[3], p[5], p[8])
477
478 def p_switch_smt(self, p):
479 """switch_stmt : SWITCH LPAR atom RPAR COLON NEWLINE INDENT switches DEDENT
480 """
481 switchon = p[3]
482 print("switch stmt")
483 print(astor.dump_tree(p[1]))
484
485 cases = []
486 current_cases = [] # for deferral
487 for (case, suite) in p[8]:
488 print("for", case, suite)
489 if suite is None:
490 for c in case:
491 current_cases.append(ast.Num(c))
492 continue
493 if case == 'default': # last
494 break
495 for c in case:
496 current_cases.append(ast.Num(c))
497 print("cases", current_cases)
498 compare = ast.Compare(switchon, [ast.In()],
499 [ast.List(current_cases, ast.Load())])
500 current_cases = []
501 cases.append((compare, suite))
502
503 print("ended", case, current_cases)
504 if case == 'default':
505 if current_cases:
506 compare = ast.Compare(switchon, [ast.In()],
507 [ast.List(current_cases, ast.Load())])
508 cases.append((compare, suite))
509 cases.append((None, suite))
510
511 cases.reverse()
512 res = []
513 for compare, suite in cases:
514 print("after rev", compare, suite)
515 if compare is None:
516 assert len(res) == 0, "last case should be default"
517 res = suite
518 else:
519 if not isinstance(res, list):
520 res = [res]
521 res = ast.If(compare, suite, res)
522 p[0] = res
523
524 def p_switches(self, p):
525 """switches : switch_list switch_default
526 | switch_default
527 """
528 if len(p) == 3:
529 p[0] = p[1] + [p[2]]
530 else:
531 p[0] = [p[1]]
532
533 def p_switch_list(self, p):
534 """switch_list : switch_case switch_list
535 | switch_case
536 """
537 if len(p) == 3:
538 p[0] = [p[1]] + p[2]
539 else:
540 p[0] = [p[1]]
541
542 def p_switch_case(self, p):
543 """switch_case : CASE LPAR atomlist RPAR COLON suite
544 """
545 # XXX bad hack
546 if isinstance(p[6][0], ast.Name) and p[6][0].id == 'fallthrough':
547 p[6] = None
548 p[0] = (p[3], p[6])
549
550 def p_switch_default(self, p):
551 """switch_default : DEFAULT COLON suite
552 """
553 p[0] = ('default', p[3])
554
555 def p_atomlist(self, p):
556 """atomlist : atom COMMA atomlist
557 | atom
558 """
559 assert isinstance(p[1], ast.Constant), "case must be numbers"
560 if len(p) == 4:
561 p[0] = [p[1].value] + p[3]
562 else:
563 p[0] = [p[1].value]
564
565 def p_if_stmt(self, p):
566 """if_stmt : IF test COLON suite ELSE COLON if_stmt
567 | IF test COLON suite ELSE COLON suite
568 | IF test COLON suite
569 """
570 if len(p) == 8 and isinstance(p[7], ast.If):
571 p[0] = ast.If(p[2], p[4], [p[7]])
572 elif len(p) == 5:
573 p[0] = ast.If(p[2], p[4], [])
574 else:
575 p[0] = ast.If(p[2], p[4], p[7])
576
577 def p_suite(self, p):
578 """suite : simple_stmt
579 | NEWLINE INDENT stmts DEDENT"""
580 if len(p) == 2:
581 p[0] = p[1]
582 else:
583 p[0] = p[3]
584
585 def p_stmts(self, p):
586 """stmts : stmts stmt
587 | stmt"""
588 if len(p) == 3:
589 p[0] = p[1] + p[2]
590 else:
591 p[0] = p[1]
592
593 def p_comparison(self, p):
594 """comparison : comparison PLUS comparison
595 | comparison MINUS comparison
596 | comparison MULT comparison
597 | comparison DIV comparison
598 | comparison MOD comparison
599 | comparison EQ comparison
600 | comparison NE comparison
601 | comparison LE comparison
602 | comparison GE comparison
603 | comparison LTU comparison
604 | comparison GTU comparison
605 | comparison LT comparison
606 | comparison GT comparison
607 | comparison BITOR comparison
608 | comparison BITXOR comparison
609 | comparison BITAND comparison
610 | PLUS comparison
611 | comparison MINUS
612 | INVERT comparison
613 | comparison APPEND comparison
614 | power"""
615 if len(p) == 4:
616 print(list(p))
617 if p[2] == '<u':
618 p[0] = ast.Call(ast.Name("ltu", ast.Load()), (p[1], p[3]), [])
619 elif p[2] == '>u':
620 p[0] = ast.Call(ast.Name("gtu", ast.Load()), (p[1], p[3]), [])
621 elif p[2] == '||':
622 l = check_concat(p[1]) + check_concat(p[3])
623 p[0] = ast.Call(ast.Name("concat", ast.Load()), l, [])
624 elif p[2] in ['/', '%']:
625 # bad hack: if % or / used anywhere other than div/mod ops,
626 # do % or /. however if the argument names are "dividend"
627 # we must call the special trunc_divs and trunc_rems functions
628 l, r = p[1], p[3]
629 # actual call will be "dividend / divisor" - just check
630 # LHS name
631 # XXX DISABLE BAD HACK (False)
632 if False and isinstance(l, ast.Name) and l.id == 'dividend':
633 if p[2] == '/':
634 fn = 'trunc_divs'
635 else:
636 fn = 'trunc_rems'
637 # return "function trunc_xxx(l, r)"
638 p[0] = ast.Call(ast.Name(fn, ast.Load()), (l, r), [])
639 else:
640 # return "l {binop} r"
641 p[0] = ast.BinOp(p[1], binary_ops[p[2]], p[3])
642 elif p[2] in ['<', '>', '=', '<=', '>=', '!=']:
643 p[0] = binary_ops[p[2]]((p[1], p[3]))
644 elif identify_sint_mul_pattern(p):
645 keywords = [ast.keyword(arg='repeat', value=p[3])]
646 l = p[1].elts
647 p[0] = ast.Call(ast.Name("concat", ast.Load()), l, keywords)
648 else:
649 p[0] = ast.BinOp(p[1], binary_ops[p[2]], p[3])
650 elif len(p) == 3:
651 if isinstance(p[2], str) and p[2] == '-':
652 p[0] = ast.UnaryOp(unary_ops[p[2]], p[1])
653 else:
654 p[0] = ast.UnaryOp(unary_ops[p[1]], p[2])
655 else:
656 p[0] = p[1]
657
658 # power: atom trailer* ['**' factor]
659 # trailers enables function calls (and subscripts).
660 # so this is 'trailerlist'
661 def p_power(self, p):
662 """power : atom
663 | atom trailerlist"""
664 if len(p) == 2:
665 print("power dump atom notrailer")
666 print(astor.dump_tree(p[1]))
667 p[0] = p[1]
668 else:
669 print("power dump atom")
670 print(astor.dump_tree(p[1]))
671 print("power dump trailerlist")
672 print(astor.dump_tree(p[2]))
673 p[0] = apply_trailer(p[1], p[2])
674 if isinstance(p[1], ast.Name):
675 name = p[1].id
676 if name in ['RA', 'RS', 'RB', 'RC', 'RT']:
677 self.read_regs.add(name)
678
679 def p_atom_name(self, p):
680 """atom : NAME"""
681 name = p[1]
682 if name in self.available_op_fields:
683 self.op_fields.add(name)
684 if name == 'overflow':
685 self.write_regs.add(name)
686 if self.include_ca_in_write:
687 if name in ['CA', 'CA32']:
688 self.write_regs.add(name)
689 if name in ['CR', 'LR', 'CTR', 'TAR', 'FPSCR', 'MSR', 'SVSTATE']:
690 self.special_regs.add(name)
691 self.write_regs.add(name) # and add to list to write
692 p[0] = ast.Name(id=name, ctx=ast.Load())
693
694 def p_atom_number(self, p):
695 """atom : BINARY
696 | NUMBER
697 | HEX
698 | STRING"""
699 p[0] = ast.Constant(p[1])
700
701 # '[' [listmaker] ']' |
702
703 def p_atom_listmaker(self, p):
704 """atom : LBRACK listmaker RBRACK"""
705 p[0] = p[2]
706
707 def p_listmaker(self, p):
708 """listmaker : test COMMA listmaker
709 | test
710 """
711 if len(p) == 2:
712 p[0] = ast.List([p[1]], ast.Load())
713 else:
714 p[0] = ast.List([p[1]] + p[3].nodes, ast.Load())
715
716 def p_atom_tuple(self, p):
717 """atom : LPAR testlist RPAR"""
718 print("tuple", p[2])
719 print("astor dump")
720 print(astor.dump_tree(p[2]))
721
722 if isinstance(p[2], ast.Name):
723 name = p[2].id
724 print("tuple name", name)
725 if name in self.gprs:
726 self.read_regs.add(name) # add to list of regs to read
727 #p[0] = ast.Subscript(ast.Name("GPR", ast.Load()), ast.Str(p[2].id))
728 # return
729 p[0] = p[2]
730 elif isinstance(p[2], ast.BinOp):
731 if isinstance(p[2].left, ast.Name) and \
732 isinstance(p[2].right, ast.Constant) and \
733 p[2].right.value == 0 and \
734 p[2].left.id in self.gprs:
735 rid = p[2].left.id
736 self.read_regs.add(rid) # add to list of regs to read
737 # create special call to GPR.getz
738 gprz = ast.Name("GPR", ast.Load())
739 # get testzero function
740 gprz = ast.Attribute(gprz, "getz", ast.Load())
741 # *sigh* see class GPR. we need index itself not reg value
742 ridx = ast.Name("_%s" % rid, ast.Load())
743 p[0] = ast.Call(gprz, [ridx], [])
744 print("tree", astor.dump_tree(p[0]))
745 else:
746 p[0] = p[2]
747 else:
748 p[0] = p[2]
749
750 def p_trailerlist(self, p):
751 """trailerlist : trailer trailerlist
752 | trailer
753 """
754 if len(p) == 2:
755 p[0] = p[1]
756 else:
757 p[0] = ("TLIST", p[1], p[2])
758
759 # trailer: '(' [arglist] ')' | '[' subscriptlist ']' | '.' NAME
760 def p_trailer(self, p):
761 """trailer : trailer_arglist
762 | trailer_subscript
763 """
764 p[0] = p[1]
765
766 def p_trailer_arglist(self, p):
767 "trailer_arglist : LPAR arglist RPAR"
768 p[0] = ("CALL", p[2])
769
770 def p_trailer_subscript(self, p):
771 "trailer_subscript : LBRACK subscript RBRACK"
772 p[0] = ("SUBS", p[2])
773
774 # subscript: '.' '.' '.' | test | [test] ':' [test]
775
776 def p_subscript(self, p):
777 """subscript : test COLON test
778 | test
779 """
780 if len(p) == 4:
781 # add one to end
782 if isinstance(p[3], ast.Constant):
783 end = ast.Constant(p[3].value+1)
784 else:
785 end = ast.BinOp(p[3], ast.Add(), ast.Constant(1))
786 p[0] = [p[1], end]
787 else:
788 p[0] = [p[1]]
789
790 # testlist: test (',' test)* [',']
791 # Contains shift/reduce error
792
793 def p_testlist(self, p):
794 """testlist : testlist_multi COMMA
795 | testlist_multi """
796 if len(p) == 2:
797 p[0] = p[1]
798 else:
799 # May need to promote singleton to tuple
800 if isinstance(p[1], list):
801 p[0] = p[1]
802 else:
803 p[0] = [p[1]]
804 # Convert into a tuple?
805 if isinstance(p[0], list):
806 p[0] = ast.Tuple(p[0])
807
808 def p_testlist_multi(self, p):
809 """testlist_multi : testlist_multi COMMA test
810 | test"""
811 if len(p) == 2:
812 # singleton
813 p[0] = p[1]
814 else:
815 if isinstance(p[1], list):
816 p[0] = p[1] + [p[3]]
817 else:
818 # singleton -> tuple
819 p[0] = [p[1], p[3]]
820
821 # test: or_test ['if' or_test 'else' test] | lambdef
822 # as I don't support 'and', 'or', and 'not' this works down to 'comparison'
823
824 def p_test(self, p):
825 "test : comparison"
826 p[0] = p[1]
827
828 # arglist: (argument ',')* (argument [',']| '*' test [',' '**' test]
829 # | '**' test)
830 # XXX INCOMPLETE: this doesn't allow the trailing comma
831
832 def p_arglist(self, p):
833 """arglist : arglist COMMA argument
834 | argument"""
835 if len(p) == 4:
836 p[0] = p[1] + [p[3]]
837 else:
838 p[0] = [p[1]]
839
840 # argument: test [gen_for] | test '=' test # Really [keyword '='] test
841 def p_argument(self, p):
842 "argument : test"
843 p[0] = p[1]
844
845 def p_error(self, p):
846 # print "Error!", repr(p)
847 raise SyntaxError(p)
848
849
850 class GardenSnakeParser(PowerParser):
851 def __init__(self, lexer=None, debug=False, form=None, incl_carry=False):
852 self.sd = create_pdecode()
853 PowerParser.__init__(self, form, incl_carry)
854 self.debug = debug
855 if lexer is None:
856 lexer = IndentLexer(debug=0)
857 self.lexer = lexer
858 self.tokens = lexer.tokens
859 self.parser = yacc.yacc(module=self, start="file_input_end",
860 debug=debug, write_tables=False)
861
862 def parse(self, code):
863 # self.lexer.input(code)
864 result = self.parser.parse(code, lexer=self.lexer, debug=self.debug)
865 return ast.Module(result)
866
867
868 ###### Code generation ######
869
870 #from compiler import misc, syntax, pycodegen
871
872 _CACHED_PARSERS = {}
873 _CACHE_PARSERS = True
874
875
876 class GardenSnakeCompiler(object):
877 def __init__(self, debug=False, form=None, incl_carry=False):
878 if _CACHE_PARSERS:
879 try:
880 parser = _CACHED_PARSERS[debug, form, incl_carry]
881 except KeyError:
882 parser = GardenSnakeParser(debug=debug, form=form,
883 incl_carry=incl_carry)
884 _CACHED_PARSERS[debug, form, incl_carry] = parser
885
886 self.parser = deepcopy(parser)
887 else:
888 self.parser = GardenSnakeParser(debug=debug, form=form,
889 incl_carry=incl_carry)
890
891 def compile(self, code, mode="exec", filename="<string>"):
892 tree = self.parser.parse(code)
893 print("snake")
894 pprint(tree)
895 return tree
896 #misc.set_filename(filename, tree)
897 return compile(tree, mode="exec", filename="<string>")
898 # syntax.check(tree)
899 gen = pycodegen.ModuleCodeGenerator(tree)
900 code = gen.getCode()
901 return code