add list of gprs which need to access GPR functions (code-rewrite)
[soc.git] / src / soc / decoder / power_pseudo.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 import sys
12 from pprint import pprint
13 from copy import copy
14 from ply import lex, yacc
15 import astor
16
17 from soc.decoder.power_fieldsn import create_sigdecode
18
19
20 # I use the Python AST
21 #from compiler import ast
22 import ast
23
24 # Helper function
25 def Assign(left, right):
26 names = []
27 if isinstance(left, ast.Name):
28 # Single assignment on left
29 return ast.Assign([ast.Name(left.id, ast.Store())], right)
30 elif isinstance(left, ast.Tuple):
31 # List of things - make sure they are Name nodes
32 names = []
33 for child in left.getChildren():
34 if not isinstance(child, ast.Name):
35 raise SyntaxError("that assignment not supported")
36 names.append(child.name)
37 ass_list = [ast.AssName(name, 'OP_ASSIGN') for name in names]
38 return ast.Assign([ast.AssTuple(ass_list)], right)
39 else:
40 raise SyntaxError("Can't do that yet")
41
42
43 ## I implemented INDENT / DEDENT generation as a post-processing filter
44
45 # The original lex token stream contains WS and NEWLINE characters.
46 # WS will only occur before any other tokens on a line.
47
48 # I have three filters. One tags tokens by adding two attributes.
49 # "must_indent" is True if the token must be indented from the
50 # previous code. The other is "at_line_start" which is True for WS
51 # and the first non-WS/non-NEWLINE on a line. It flags the check so
52 # see if the new line has changed indication level.
53
54 # Python's syntax has three INDENT states
55 # 0) no colon hence no need to indent
56 # 1) "if 1: go()" - simple statements have a COLON but no need for an indent
57 # 2) "if 1:\n go()" - complex statements have a COLON NEWLINE and must indent
58 NO_INDENT = 0
59 MAY_INDENT = 1
60 MUST_INDENT = 2
61
62 # turn into python-like colon syntax from pseudo-code syntax
63 def python_colonify(lexer, tokens):
64
65 forwhile_seen = False
66 for token in tokens:
67 #print ("track colon token", token, token.type)
68
69 if token.type == 'THEN':
70 # turn then into colon
71 token.type = "COLON"
72 yield token
73 elif token.type == 'ELSE':
74 yield token
75 token = copy(token)
76 token.type = "COLON"
77 yield token
78 elif token.type in ['WHILE', 'FOR']:
79 forwhile_seen = True
80 yield token
81 elif token.type == 'NEWLINE':
82 if forwhile_seen:
83 ctok = copy(token)
84 ctok.type = "COLON"
85 yield ctok
86 forwhile_seen = False
87 yield token
88 else:
89 yield token
90
91
92 # only care about whitespace at the start of a line
93 def track_tokens_filter(lexer, tokens):
94 oldignore = lexer.lexignore
95 lexer.at_line_start = at_line_start = True
96 indent = NO_INDENT
97 saw_colon = False
98 for token in tokens:
99 #print ("track token", token, token.type)
100 token.at_line_start = at_line_start
101
102 if token.type == "COLON":
103 at_line_start = False
104 indent = MAY_INDENT
105 token.must_indent = False
106
107 elif token.type == "NEWLINE":
108 at_line_start = True
109 if indent == MAY_INDENT:
110 indent = MUST_INDENT
111 token.must_indent = False
112
113 elif token.type == "WS":
114 assert token.at_line_start == True
115 at_line_start = True
116 token.must_indent = False
117
118 else:
119 # A real token; only indent after COLON NEWLINE
120 if indent == MUST_INDENT:
121 token.must_indent = True
122 else:
123 token.must_indent = False
124 at_line_start = False
125 indent = NO_INDENT
126
127 # really bad hack that changes ignore lexer state.
128 # when "must indent" is seen (basically "real tokens" seen)
129 # then ignore whitespace.
130 if token.must_indent:
131 lexer.lexignore = ('ignore', ' ')
132 else:
133 lexer.lexignore = oldignore
134
135 token.indent = indent
136 yield token
137 lexer.at_line_start = at_line_start
138
139 def _new_token(type, lineno):
140 tok = lex.LexToken()
141 tok.type = type
142 tok.value = None
143 tok.lineno = lineno
144 tok.lexpos = -1
145 return tok
146
147 # Synthesize a DEDENT tag
148 def DEDENT(lineno):
149 return _new_token("DEDENT", lineno)
150
151 # Synthesize an INDENT tag
152 def INDENT(lineno):
153 return _new_token("INDENT", lineno)
154
155
156 # Track the indentation level and emit the right INDENT / DEDENT events.
157 def indentation_filter(tokens):
158 # A stack of indentation levels; will never pop item 0
159 levels = [0]
160 token = None
161 depth = 0
162 prev_was_ws = False
163 for token in tokens:
164 if 1:
165 print ("Process", depth, token.indent, token,)
166 if token.at_line_start:
167 print ("at_line_start",)
168 if token.must_indent:
169 print ("must_indent",)
170 print
171
172 # WS only occurs at the start of the line
173 # There may be WS followed by NEWLINE so
174 # only track the depth here. Don't indent/dedent
175 # until there's something real.
176 if token.type == "WS":
177 assert depth == 0
178 depth = len(token.value)
179 prev_was_ws = True
180 # WS tokens are never passed to the parser
181 continue
182
183 if token.type == "NEWLINE":
184 depth = 0
185 if prev_was_ws or token.at_line_start:
186 # ignore blank lines
187 continue
188 # pass the other cases on through
189 yield token
190 continue
191
192 # then it must be a real token (not WS, not NEWLINE)
193 # which can affect the indentation level
194
195 prev_was_ws = False
196 if token.must_indent:
197 # The current depth must be larger than the previous level
198 if not (depth > levels[-1]):
199 raise IndentationError("expected an indented block")
200
201 levels.append(depth)
202 yield INDENT(token.lineno)
203
204 elif token.at_line_start:
205 # Must be on the same level or one of the previous levels
206 if depth == levels[-1]:
207 # At the same level
208 pass
209 elif depth > levels[-1]:
210 raise IndentationError("indentation increase but not in new block")
211 else:
212 # Back up; but only if it matches a previous level
213 try:
214 i = levels.index(depth)
215 except ValueError:
216 raise IndentationError("inconsistent indentation")
217 for _ in range(i+1, len(levels)):
218 yield DEDENT(token.lineno)
219 levels.pop()
220
221 yield token
222
223 ### Finished processing ###
224
225 # Must dedent any remaining levels
226 if len(levels) > 1:
227 assert token is not None
228 for _ in range(1, len(levels)):
229 yield DEDENT(token.lineno)
230
231
232 # The top-level filter adds an ENDMARKER, if requested.
233 # Python's grammar uses it.
234 def filter(lexer, add_endmarker = True):
235 token = None
236 tokens = iter(lexer.token, None)
237 tokens = python_colonify(lexer, tokens)
238 tokens = track_tokens_filter(lexer, tokens)
239 for token in indentation_filter(tokens):
240 yield token
241
242 if add_endmarker:
243 lineno = 1
244 if token is not None:
245 lineno = token.lineno
246 yield _new_token("ENDMARKER", lineno)
247
248 ## No using Python's approach because Ply supports precedence
249
250 # comparison: expr (comp_op expr)*
251 # arith_expr: term (('+'|'-') term)*
252 # term: factor (('*'|'/'|'%'|'//') factor)*
253 # factor: ('+'|'-'|'~') factor | power
254 # comp_op: '<'|'>'|'=='|'>='|'<='|'<>'|'!='|'in'|'not' 'in'|'is'|'is' 'not'
255
256 def make_lt_compare(arg):
257 (left, right) = arg
258 return ast.Compare(left, [ast.Lt()], [right])
259 def make_gt_compare(arg):
260 (left, right) = arg
261 return ast.Compare(left, [ast.Gt()], [right])
262 def make_eq_compare(arg):
263 (left, right) = arg
264 return ast.Compare(left, [ast.Eq()], [right])
265
266
267 binary_ops = {
268 "+": ast.Add(),
269 "-": ast.Sub(),
270 "*": ast.Mult(),
271 "/": ast.Div(),
272 "<": make_lt_compare,
273 ">": make_gt_compare,
274 "=": make_eq_compare,
275 }
276 unary_ops = {
277 "+": ast.Add,
278 "-": ast.Sub,
279 }
280 precedence = (
281 ("left", "EQ", "GT", "LT"),
282 ("left", "PLUS", "MINUS"),
283 ("left", "MULT", "DIV"),
284 )
285
286 def check_concat(node): # checks if the comparison is already a concat
287 print (node)
288 if not isinstance(node, ast.Call):
289 return [node]
290 if node[0].id != 'concat':
291 return node
292 return node[1]
293 ##### Lexer ######
294 #import lex
295 import decimal
296
297 class PowerLexer:
298 tokens = (
299 'DEF',
300 'IF',
301 'THEN',
302 'ELSE',
303 'FOR',
304 'TO',
305 'DO',
306 'WHILE',
307 'BREAK',
308 'NAME',
309 'NUMBER', # Python decimals
310 'BINARY', # Python binary
311 'STRING', # single quoted strings only; syntax of raw strings
312 'LPAR',
313 'RPAR',
314 'LBRACK',
315 'RBRACK',
316 'COLON',
317 'EQ',
318 'ASSIGN',
319 'LT',
320 'GT',
321 'PLUS',
322 'MINUS',
323 'MULT',
324 'DIV',
325 'APPEND',
326 'RETURN',
327 'WS',
328 'NEWLINE',
329 'COMMA',
330 'SEMICOLON',
331 'INDENT',
332 'DEDENT',
333 'ENDMARKER',
334 )
335
336 # Build the lexer
337 def build(self,**kwargs):
338 self.lexer = lex.lex(module=self, **kwargs)
339
340 def t_BINARY(self, t):
341 r"""0b[01]+"""
342 t.value = int(t.value, 2)
343 return t
344
345 #t_NUMBER = r'\d+'
346 # taken from decmial.py but without the leading sign
347 def t_NUMBER(self, t):
348 r"""(\d+(\.\d*)?|\.\d+)([eE][-+]? \d+)?"""
349 t.value = int(t.value)
350 return t
351
352 def t_STRING(self, t):
353 r"'([^\\']+|\\'|\\\\)*'" # I think this is right ...
354 t.value=t.value[1:-1].decode("string-escape") # .swapcase() # for fun
355 return t
356
357 t_COLON = r':'
358 t_EQ = r'='
359 t_ASSIGN = r'<-'
360 t_LT = r'<'
361 t_GT = r'>'
362 t_PLUS = r'\+'
363 t_MINUS = r'-'
364 t_MULT = r'\*'
365 t_DIV = r'/'
366 t_COMMA = r','
367 t_SEMICOLON = r';'
368 t_APPEND = r'\|\|'
369
370 # Ply nicely documented how to do this.
371
372 RESERVED = {
373 "def": "DEF",
374 "if": "IF",
375 "then": "THEN",
376 "else": "ELSE",
377 "leave": "BREAK",
378 "for": "FOR",
379 "to": "TO",
380 "while": "WHILE",
381 "do": "DO",
382 "return": "RETURN",
383 }
384
385 def t_NAME(self, t):
386 r'[a-zA-Z_][a-zA-Z0-9_]*'
387 t.type = self.RESERVED.get(t.value, "NAME")
388 return t
389
390 # Putting this before t_WS let it consume lines with only comments in
391 # them so the latter code never sees the WS part. Not consuming the
392 # newline. Needed for "if 1: #comment"
393 def t_comment(self, t):
394 r"[ ]*\043[^\n]*" # \043 is '#'
395 pass
396
397
398 # Whitespace
399 def t_WS(self, t):
400 r'[ ]+'
401 if t.lexer.at_line_start and t.lexer.paren_count == 0 and \
402 t.lexer.brack_count == 0:
403 return t
404
405 # Don't generate newline tokens when inside of parenthesis, eg
406 # a = (1,
407 # 2, 3)
408 def t_newline(self, t):
409 r'\n+'
410 t.lexer.lineno += len(t.value)
411 t.type = "NEWLINE"
412 if t.lexer.paren_count == 0 and t.lexer.brack_count == 0:
413 return t
414
415 def t_LBRACK(self, t):
416 r'\['
417 t.lexer.brack_count += 1
418 return t
419
420 def t_RBRACK(self, t):
421 r'\]'
422 # check for underflow? should be the job of the parser
423 t.lexer.brack_count -= 1
424 return t
425
426 def t_LPAR(self, t):
427 r'\('
428 t.lexer.paren_count += 1
429 return t
430
431 def t_RPAR(self, t):
432 r'\)'
433 # check for underflow? should be the job of the parser
434 t.lexer.paren_count -= 1
435 return t
436
437 #t_ignore = " "
438
439 def t_error(self, t):
440 raise SyntaxError("Unknown symbol %r" % (t.value[0],))
441 print ("Skipping", repr(t.value[0]))
442 t.lexer.skip(1)
443
444 # Combine Ply and my filters into a new lexer
445
446 class IndentLexer(PowerLexer):
447 def __init__(self, debug=0, optimize=0, lextab='lextab', reflags=0):
448 self.build(debug=debug, optimize=optimize,
449 lextab=lextab, reflags=reflags)
450 self.token_stream = None
451 def input(self, s, add_endmarker=True):
452 self.lexer.paren_count = 0
453 self.lexer.brack_count = 0
454 self.lexer.input(s)
455 self.token_stream = filter(self.lexer, add_endmarker)
456
457 def token(self):
458 try:
459 return next(self.token_stream)
460 except StopIteration:
461 return None
462
463
464 ########## Parser (tokens -> AST) ######
465
466 # also part of Ply
467 #import yacc
468
469 class PowerParser:
470
471 def __init__(self):
472 self.gprs = {}
473 for rname in ['RA', 'RB', 'RC', 'RT']:
474 self.gprs[rname] = None
475
476 # The grammar comments come from Python's Grammar/Grammar file
477
478 ## NB: compound_stmt in single_input is followed by extra NEWLINE!
479 # file_input: (NEWLINE | stmt)* ENDMARKER
480
481 def p_file_input_end(self, p):
482 """file_input_end : file_input ENDMARKER"""
483 print ("end", p[1])
484 p[0] = p[1]
485
486 def p_file_input(self, p):
487 """file_input : file_input NEWLINE
488 | file_input stmt
489 | NEWLINE
490 | stmt"""
491 if isinstance(p[len(p)-1], str):
492 if len(p) == 3:
493 p[0] = p[1]
494 else:
495 p[0] = [] # p == 2 --> only a blank line
496 else:
497 if len(p) == 3:
498 p[0] = p[1] + p[2]
499 else:
500 p[0] = p[1]
501
502
503 # funcdef: [decorators] 'def' NAME parameters ':' suite
504 # ignoring decorators
505 def p_funcdef(self, p):
506 "funcdef : DEF NAME parameters COLON suite"
507 p[0] = ast.Function(None, p[2], list(p[3]), (), 0, None, p[5])
508
509 # parameters: '(' [varargslist] ')'
510 def p_parameters(self, p):
511 """parameters : LPAR RPAR
512 | LPAR varargslist RPAR"""
513 if len(p) == 3:
514 p[0] = []
515 else:
516 p[0] = p[2]
517
518
519 # varargslist: (fpdef ['=' test] ',')* ('*' NAME [',' '**' NAME] | '**' NAME) |
520 # highly simplified
521 def p_varargslist(self, p):
522 """varargslist : varargslist COMMA NAME
523 | NAME"""
524 if len(p) == 4:
525 p[0] = p[1] + p[3]
526 else:
527 p[0] = [p[1]]
528
529 # stmt: simple_stmt | compound_stmt
530 def p_stmt_simple(self, p):
531 """stmt : simple_stmt"""
532 # simple_stmt is a list
533 p[0] = p[1]
534
535 def p_stmt_compound(self, p):
536 """stmt : compound_stmt"""
537 p[0] = [p[1]]
538
539 # simple_stmt: small_stmt (';' small_stmt)* [';'] NEWLINE
540 def p_simple_stmt(self, p):
541 """simple_stmt : small_stmts NEWLINE
542 | small_stmts SEMICOLON NEWLINE"""
543 p[0] = p[1]
544
545 def p_small_stmts(self, p):
546 """small_stmts : small_stmts SEMICOLON small_stmt
547 | small_stmt"""
548 if len(p) == 4:
549 p[0] = p[1] + [p[3]]
550 else:
551 p[0] = [p[1]]
552
553 # small_stmt: expr_stmt | print_stmt | del_stmt | pass_stmt | flow_stmt |
554 # import_stmt | global_stmt | exec_stmt | assert_stmt
555 def p_small_stmt(self, p):
556 """small_stmt : flow_stmt
557 | break_stmt
558 | expr_stmt"""
559 p[0] = p[1]
560
561 # expr_stmt: testlist (augassign (yield_expr|testlist) |
562 # ('=' (yield_expr|testlist))*)
563 # augassign: ('+=' | '-=' | '*=' | '/=' | '%=' | '&=' | '|=' | '^=' |
564 # '<<=' | '>>=' | '**=' | '//=')
565 def p_expr_stmt(self, p):
566 """expr_stmt : testlist ASSIGN testlist
567 | testlist """
568 if len(p) == 2:
569 # a list of expressions
570 #p[0] = ast.Discard(p[1])
571 p[0] = p[1]
572 else:
573 p[0] = Assign(p[1], p[3])
574
575 def p_flow_stmt(self, p):
576 "flow_stmt : return_stmt"
577 p[0] = p[1]
578
579 # return_stmt: 'return' [testlist]
580 def p_return_stmt(self, p):
581 "return_stmt : RETURN testlist"
582 p[0] = ast.Return(p[2])
583
584
585 def p_compound_stmt(self, p):
586 """compound_stmt : if_stmt
587 | while_stmt
588 | for_stmt
589 | funcdef
590 """
591 p[0] = p[1]
592
593 def p_break_stmt(self, p):
594 """break_stmt : BREAK
595 """
596 p[0] = ast.Break()
597
598 def p_for_stmt(self, p):
599 """for_stmt : FOR test EQ test TO test COLON suite
600 """
601 p[0] = ast.While(p[2], p[4], [])
602 # auto-add-one (sigh) due to python range
603 start = p[4]
604 end = ast.BinOp(p[6], ast.Add(), ast.Constant(1))
605 it = ast.Call(ast.Name("range"), [start, end], [])
606 p[0] = ast.For(p[2], it, p[8], [])
607
608 def p_while_stmt(self, p):
609 """while_stmt : DO WHILE test COLON suite ELSE COLON suite
610 | DO WHILE test COLON suite
611 """
612 if len(p) == 6:
613 p[0] = ast.While(p[3], p[5], [])
614 else:
615 p[0] = ast.While(p[3], p[5], p[8])
616
617 def p_if_stmt(self, p):
618 """if_stmt : IF test COLON suite ELSE COLON suite
619 | IF test COLON suite
620 """
621 if len(p) == 5:
622 p[0] = ast.If(p[2], p[4], [])
623 else:
624 p[0] = ast.If(p[2], p[4], p[7])
625
626 def p_suite(self, p):
627 """suite : simple_stmt
628 | NEWLINE INDENT stmts DEDENT"""
629 if len(p) == 2:
630 p[0] = p[1]
631 else:
632 p[0] = p[3]
633
634
635 def p_stmts(self, p):
636 """stmts : stmts stmt
637 | stmt"""
638 if len(p) == 3:
639 p[0] = p[1] + p[2]
640 else:
641 p[0] = p[1]
642
643 def p_comparison(self, p):
644 """comparison : comparison PLUS comparison
645 | comparison MINUS comparison
646 | comparison MULT comparison
647 | comparison DIV comparison
648 | comparison LT comparison
649 | comparison EQ comparison
650 | comparison GT comparison
651 | PLUS comparison
652 | MINUS comparison
653 | comparison APPEND comparison
654 | power"""
655 if len(p) == 4:
656 print (list(p))
657 if p[2] == '||':
658 l = check_concat(p[1]) + check_concat(p[3])
659 p[0] = ast.Call(ast.Name("concat"), l, [])
660 elif p[2] in ['<', '>', '=']:
661 p[0] = binary_ops[p[2]]((p[1],p[3]))
662 else:
663 p[0] = ast.BinOp(p[1], binary_ops[p[2]], p[3])
664 elif len(p) == 3:
665 p[0] = unary_ops[p[1]](p[2])
666 else:
667 p[0] = p[1]
668
669 # power: atom trailer* ['**' factor]
670 # trailers enables function calls (and subscripts).
671 # I only allow one level of calls
672 # so this is 'trailer'
673 def p_power(self, p):
674 """power : atom
675 | atom trailer"""
676 if len(p) == 2:
677 p[0] = p[1]
678 else:
679 if p[2][0] == "CALL":
680 #p[0] = ast.Expr(ast.Call(p[1], p[2][1], []))
681 p[0] = ast.Call(p[1], p[2][1], [])
682 #if p[1].id == 'print':
683 # p[0] = ast.Printnl(ast.Tuple(p[2][1]), None, None)
684 #else:
685 # p[0] = ast.CallFunc(p[1], p[2][1], None, None)
686 else:
687 print (p[2][1])
688 #raise AssertionError("not implemented %s" % p[2][0])
689 subs = p[2][1]
690 if len(subs) == 1:
691 idx = subs[0]
692 else:
693 idx = ast.Slice(subs[0], subs[1], None)
694 p[0] = ast.Subscript(p[1], idx)
695
696 def p_atom_name(self, p):
697 """atom : NAME"""
698 p[0] = ast.Name(p[1], ctx=ast.Load())
699
700 def p_atom_number(self, p):
701 """atom : BINARY
702 | NUMBER
703 | STRING"""
704 p[0] = ast.Constant(p[1])
705
706 #'[' [listmaker] ']' |
707
708 def p_atom_listmaker(self, p):
709 """atom : LBRACK listmaker RBRACK"""
710 p[0] = p[2]
711
712 def p_listmaker(self, p):
713 """listmaker : test COMMA listmaker
714 | test
715 """
716 if len(p) == 2:
717 p[0] = ast.List([p[1]])
718 else:
719 p[0] = ast.List([p[1]] + p[3].nodes)
720
721 def p_atom_tuple(self, p):
722 """atom : LPAR testlist RPAR"""
723 p[0] = p[2]
724
725 # trailer: '(' [arglist] ')' | '[' subscriptlist ']' | '.' NAME
726 def p_trailer(self, p):
727 """trailer : trailer_arglist
728 | trailer_subscript
729 """
730 p[0] = p[1]
731
732 def p_trailer_arglist(self, p):
733 "trailer_arglist : LPAR arglist RPAR"
734 p[0] = ("CALL", p[2])
735
736 def p_trailer_subscript(self, p):
737 "trailer_subscript : LBRACK subscript RBRACK"
738 p[0] = ("SUBS", p[2])
739
740 #subscript: '.' '.' '.' | test | [test] ':' [test]
741
742 def p_subscript(self, p):
743 """subscript : test COLON test
744 | test
745 """
746 if len(p) == 4:
747 p[0] = [p[1], p[3]]
748 else:
749 p[0] = [p[1]]
750
751
752 # testlist: test (',' test)* [',']
753 # Contains shift/reduce error
754 def p_testlist(self, p):
755 """testlist : testlist_multi COMMA
756 | testlist_multi """
757 if len(p) == 2:
758 p[0] = p[1]
759 else:
760 # May need to promote singleton to tuple
761 if isinstance(p[1], list):
762 p[0] = p[1]
763 else:
764 p[0] = [p[1]]
765 # Convert into a tuple?
766 if isinstance(p[0], list):
767 p[0] = ast.Tuple(p[0])
768
769 def p_testlist_multi(self, p):
770 """testlist_multi : testlist_multi COMMA test
771 | test"""
772 if len(p) == 2:
773 # singleton
774 p[0] = p[1]
775 else:
776 if isinstance(p[1], list):
777 p[0] = p[1] + [p[3]]
778 else:
779 # singleton -> tuple
780 p[0] = [p[1], p[3]]
781
782
783 # test: or_test ['if' or_test 'else' test] | lambdef
784 # as I don't support 'and', 'or', and 'not' this works down to 'comparison'
785 def p_test(self, p):
786 "test : comparison"
787 p[0] = p[1]
788
789
790
791 # arglist: (argument ',')* (argument [',']| '*' test [',' '**' test] | '**' test)
792 # XXX INCOMPLETE: this doesn't allow the trailing comma
793 def p_arglist(self, p):
794 """arglist : arglist COMMA argument
795 | argument"""
796 if len(p) == 4:
797 p[0] = p[1] + [p[3]]
798 else:
799 p[0] = [p[1]]
800
801 # argument: test [gen_for] | test '=' test # Really [keyword '='] test
802 def p_argument(self, p):
803 "argument : test"
804 p[0] = p[1]
805
806 def p_error(self, p):
807 #print "Error!", repr(p)
808 raise SyntaxError(p)
809
810
811 class GardenSnakeParser(PowerParser):
812 def __init__(self, lexer = None):
813 if lexer is None:
814 lexer = IndentLexer(debug=1)
815 self.lexer = lexer
816 self.tokens = lexer.tokens
817 self.parser = yacc.yacc(module=self, start="file_input_end",
818 debug=False, write_tables=False)
819
820 self.sd = create_sigdecode()
821
822 def parse(self, code):
823 self.lexer.input(code)
824 result = self.parser.parse(lexer = self.lexer, debug=False)
825 return ast.Module(result)
826
827
828 ###### Code generation ######
829
830 #from compiler import misc, syntax, pycodegen
831
832 class GardenSnakeCompiler(object):
833 def __init__(self):
834 self.parser = GardenSnakeParser()
835 def compile(self, code, mode="exec", filename="<string>"):
836 tree = self.parser.parse(code)
837 print ("snake")
838 pprint(tree)
839 return tree
840 #misc.set_filename(filename, tree)
841 return compile(tree, mode="exec", filename="<string>")
842 #syntax.check(tree)
843 gen = pycodegen.ModuleCodeGenerator(tree)
844 code = gen.getCode()
845 return code
846
847 ####### Test code #######
848
849 from soc.decoder.power_fieldsn import create_sigdecode
850
851 bpermd = r"""
852 perm <- [0] * 8
853 if index < 64:
854 index <- (RS)[8*i:8*i+7]
855 RA <- [0]*56 || perm[0:7]
856 print (RA)
857 """
858
859 bpermd = r"""
860 if index < 64 then index <- 0
861 else index <- 5
862 do while index < 5
863 index <- 0
864 leave
865 for i = 0 to 7
866 index <- 0
867 """
868
869 _bpermd = r"""
870 for i = 0 to 7
871 index <- (RS)[8*i:8*i+7]
872 if index < 64 then
873 permi <- (RB)[index]
874 else
875 permi <- 0
876 RA <- [0]*56|| perm[0:7]
877 """
878
879 cnttzd = """
880 n <- 0
881 do while n < 64
882 if (RS)[63-n] = 0b1 then
883 leave
884 n <- n + 1
885 RA <- EXTZ64(n)
886 """
887
888 code = cnttzd
889 #code = bpermd
890
891 lexer = IndentLexer(debug=1)
892 # Give the lexer some input
893 print ("code")
894 print (code)
895 lexer.input(code)
896
897 # Tokenize
898 while True:
899 tok = lexer.token()
900 if not tok:
901 break # No more input
902 print(tok)
903
904 #sys.exit(0)
905
906 sd = create_sigdecode()
907 print ("forms", sd.df.forms)
908 for f in sd.df.FormX:
909 print (f)
910
911 gsc = GardenSnakeCompiler()
912 _compile = gsc.compile
913
914 tree = _compile(code, mode="single", filename="string")
915 import ast
916 tree = ast.fix_missing_locations(tree)
917 print ( ast.dump(tree) )
918
919 print ("astor dump")
920 print (astor.dump_tree(tree))
921 print ("to source")
922 source = astor.to_source(tree)
923 print (source)
924
925 #sys.exit(0)
926
927 # Set up the GardenSnake run-time environment
928 def print_(*args):
929 print ("args", args)
930 print ("-->", " ".join(map(str,args)))
931
932 def listconcat(l1, l2):
933 return l1 + l2
934
935 d = {}
936 d["print"] = print_
937 d["concat"] = listconcat
938
939 form = 'X'
940 getform = getattr(gsc.parser.sd.df, "Form%s" % form)
941 print (getform)
942 for k, f in sd.df.instrs[form].items():
943 d[k] = getattr(getform, k)
944
945 compiled_code = compile(source, mode="exec", filename="<string>")
946
947 exec (compiled_code, d)
948 print ("Done")
949