596830ed3b950c11366e72f16ba69ce07b067ac6
5 import openpower
.oppc
.pc_ast
as pc_ast
8 class SyntaxError2(Exception):
10 Class used to raise a syntax error but get ply to stop eating errors
11 since it catches and discards SyntaxError after setting a flag.
14 def __init__(self
, *args
, cls
=SyntaxError):
15 super().__init
__(*args
)
19 return repr(self
.cls(*self
.args
))
22 return str(self
.cls(*self
.args
))
24 def raise_syntax_error(self
):
25 raise self
.cls(*self
.args
) from self
28 def raise_syntax_error(msg
,
29 filename
, lineno
, lexpos
, data
,
31 line_start
= data
.rfind('\n', 0, lexpos
) + 1
32 line_end
= data
.find('\n', line_start
)
33 col
= (lexpos
- line_start
) + 1
35 raise SyntaxError2(str(msg
),
36 (filename
, lineno
, col
, data
[line_start
:line_end
]),
67 REGS
.update(map(lambda reg
: (reg
, pc_ast
.GPR
), pc_ast
.GPR
))
68 REGS
.update(map(lambda reg
: (reg
, pc_ast
.FPR
), pc_ast
.FPR
))
69 REGS
.update(map(lambda reg
: (reg
, pc_ast
.CR3
), pc_ast
.CR3
))
70 REGS
.update(map(lambda reg
: (reg
, pc_ast
.CR5
), pc_ast
.CR5
))
71 REGS
.update(map(lambda reg
: (reg
, pc_ast
.XER
), pc_ast
.XER
))
73 def __init__(self
, lexer
, debug
=False, optimize
=False, write_tables
=True):
74 ignore
= lambda token
: token
in ("WS", "THEN")
75 self
.tokens
= tuple(itertools
.filterfalse(ignore
, lexer
.tokens
))
78 self
.__parser
= yacc
.yacc(
80 start
="file_input_end",
83 write_tables
=write_tables
,
86 return super().__init
__()
89 ("left", "EQ", "NE", "GT", "LT", "LE", "GE", "LTU", "GTU"),
93 ("left", "LSHIFT", "RSHIFT"),
94 ("left", "PLUS", "MINUS"),
95 ("left", "MULT", "DIV", "MOD"),
99 def p_file_input_end(self
, p
):
101 file_input_end : file_input ENDMARKER
105 def p_file_input(self
, p
):
107 file_input : file_input NEWLINE
112 if isinstance(p
[len(p
)-1], pc_ast
.Linebreak
):
116 p
[0] = pc_ast
.Scope()
120 if not isinstance(stmt
, pc_ast
.Scope
):
121 stmt
= pc_ast
.Scope([stmt
])
122 p
[0] = pc_ast
.Scope(p
[1] + stmt
)
126 # funcdef: [decorators] 'def' NAME parameters ':' suite
127 # ignoring decorators
128 def p_funcdef(self
, p
):
130 funcdef : DEF NAME parameters COLON suite
132 raise NotImplementedError()
134 # parameters: '(' [varargslist] ')'
135 def p_parameters(self
, p
):
137 parameters : LPAR RPAR
138 | LPAR varargslist RPAR
140 raise NotImplementedError()
142 # varargslist: (fpdef ['=' test] ',')* ('*' NAME [',' '**' NAME] |
146 def p_varargslist(self
, p
):
148 varargslist : varargslist COMMA NAME
151 raise NotImplementedError()
153 # stmt: simple_stmt | compound_stmt
154 def p_stmt_simple(self
, p
):
158 # simple_stmt is a list
161 def p_stmt_compound(self
, p
):
165 p
[0] = pc_ast
.Scope([p
[1]])
167 # simple_stmt: small_stmt (';' small_stmt)* [';'] NEWLINE
168 def p_simple_stmt(self
, p
):
170 simple_stmt : small_stmts NEWLINE
171 | small_stmts SEMICOLON NEWLINE
175 def p_small_stmts(self
, p
):
177 small_stmts : small_stmts SEMICOLON small_stmt
181 p
[0] = pc_ast
.Scope(p
[1] + (p
[3],))
183 p
[0] = pc_ast
.Scope([p
[1]])
185 # small_stmt: expr_stmt | print_stmt | del_stmt | pass_stmt | flow_stmt |
186 # import_stmt | global_stmt | exec_stmt | assert_stmt
187 def p_small_stmt(self
, p
):
189 small_stmt : flow_stmt
195 # expr_stmt: testlist (augassign (yield_expr|testlist) |
196 # ('=' (yield_expr|testlist))*)
197 # augassign: ('+=' | '-=' | '*=' | '/=' | '%=' | '&=' | '|=' | '^=' |
198 # '<<=' | '>>=' | '**=' | '//=')
199 def p_expr_stmt(self
, p
):
201 expr_stmt : testlist ASSIGNEA testlist
202 | testlist ASSIGN testlist
208 (lvalue
, rvalue
) = (p
[1], p
[3])
209 if isinstance(p
[2], pc_ast
.AssignOp
):
212 cls
= pc_ast
.AssignIEA
213 if (isinstance(lvalue
, pc_ast
.Symbol
) and
214 (str(lvalue
) in self
.__class
__.REGS
)):
215 lvalue
= self
.__class
__.REGS
[str(lvalue
)](lvalue
)
216 p
[0] = cls(lvalue
=lvalue
, rvalue
=rvalue
)
218 def p_flow_stmt(self
, p
):
219 "flow_stmt : return_stmt"
222 # return_stmt: 'return' [testlist]
223 def p_return_stmt(self
, p
):
224 "return_stmt : RETURN testlist"
225 p
[0] = pc_ast
.Return(p
[2])
227 def p_compound_stmt(self
, p
):
229 compound_stmt : if_stmt
237 def p_break_stmt(self
, p
):
243 def p_for_stmt(self
, p
):
245 for_stmt : FOR atom EQ comparison TO comparison COLON suite
246 | DO atom EQ comparison TO comparison COLON suite
248 p
[0] = pc_ast
.ForExpr(subject
=p
[2], start
=p
[4], end
=p
[6], body
=p
[8])
250 def p_while_stmt(self
, p
):
252 while_stmt : DO WHILE test COLON suite ELSE COLON suite
253 | DO WHILE test COLON suite
256 p
[0] = pc_ast
.WhileExpr(test
=p
[3], body
=p
[5], orelse
=p
[8])
258 p
[0] = pc_ast
.WhileExpr(test
=p
[3], body
=p
[5], orelse
=pc_ast
.Scope())
260 def p_switch_smt(self
, p
):
262 switch_stmt : SWITCH LPAR atom RPAR COLON NEWLINE INDENT cases DEDENT
264 p
[0] = pc_ast
.SwitchExpr(subject
=p
[3], cases
=p
[8])
266 def p_cases(self
, p
):
268 cases : switch_list switch_default
272 p
[0] = pc_ast
.Cases(p
[1] + (p
[2],))
274 p
[0] = pc_ast
.Cases([p
[1]])
276 def p_switch_list(self
, p
):
278 switch_list : switch_case switch_list
282 p
[0] = pc_ast
.Sequence((p
[1],) + p
[2])
284 p
[0] = pc_ast
.Sequence([p
[1]])
286 def p_switch_case(self
, p
):
288 switch_case : CASE LPAR labels RPAR COLON suite
290 p
[0] = pc_ast
.Case(labels
=p
[3], body
=p
[6])
292 def p_switch_default(self
, p
):
294 switch_default : DEFAULT COLON suite
296 p
[0] = pc_ast
.Case(body
=p
[3],
297 labels
=pc_ast
.Labels([pc_ast
.DefaultLabel()]))
299 def p_labels(self
, p
):
301 labels : atom COMMA labels
304 if not isinstance(p
[1], pc_ast
.IntLiteral
):
305 raise_syntax_error(str(p
),
306 self
.filename
, p
.lineno
, p
.lexpos
,
308 label
= pc_ast
.Label(str(p
[1]))
310 p
[0] = pc_ast
.Labels((label
,) + p
[3])
312 p
[0] = pc_ast
.Labels([label
])
314 def p_if_stmt(self
, p
):
316 if_stmt : IF test COLON suite ELSE COLON if_stmt
317 | IF test COLON suite ELSE COLON suite
318 | IF test COLON suite
320 (test
, body
) = (p
[2], p
[4])
324 orelse
= pc_ast
.Scope()
325 if not isinstance(body
, pc_ast
.Scope
):
326 body
= pc_ast
.Scope([body
])
327 if not isinstance(orelse
, pc_ast
.Scope
):
328 orelse
= pc_ast
.Scope([orelse
])
329 p
[0] = pc_ast
.IfExpr(test
=test
,
330 body
=body
, orelse
=orelse
)
332 def p_suite(self
, p
):
335 | NEWLINE INDENT stmts DEDENT
342 def p_stmts(self
, p
):
348 p
[0] = pc_ast
.Scope(p
[1] + p
[2])
352 def p_comparison(self
, p
):
354 comparison : comparison PLUS comparison
355 | comparison MINUS comparison
356 | comparison MULT comparison
357 | comparison LSHIFT comparison
358 | comparison RSHIFT comparison
359 | comparison DIV comparison
360 | comparison MOD comparison
361 | comparison EQ comparison
362 | comparison NE comparison
363 | comparison LE comparison
364 | comparison GE comparison
365 | comparison LTU comparison
366 | comparison GTU comparison
367 | comparison LT comparison
368 | comparison GT comparison
369 | comparison BITOR comparison
370 | comparison BITXOR comparison
371 | comparison BITAND comparison
375 | comparison APPEND comparison
379 def reg0(left
, op
, right
):
380 if (isinstance(left
, pc_ast
.Symbol
) and
381 isinstance(op
, pc_ast
.BitOr
) and
382 (isinstance(right
, pc_ast
.DecLiteral
) and (str(right
) == "0")) and
383 (str(left
) in frozenset(pc_ast
.GPRZero
))):
384 return pc_ast
.GPRZero(str(left
))
387 def repeat(left
, op
, right
):
388 if (isinstance(left
, pc_ast
.Sequence
) and
390 isinstance(op
, pc_ast
.Mul
)):
391 return pc_ast
.RepeatExpr(subject
=left
[0], times
=right
)
394 (left
, op
, right
) = p
[1:]
395 for hook
in (reg0
, repeat
):
396 p
[0] = hook(left
, op
, right
)
400 p
[0] = pc_ast
.BinaryExpr(left
=left
, op
=op
, right
=right
)
404 p
[0] = pc_ast
.UnaryExpr(op
=op
, value
=value
)
408 # power: atom trailer* ['**' factor]
409 # trailers enables function calls (and subscripts).
410 # so this is 'trailerlist'
411 def p_power(self
, p
):
419 attribute_or_subscript
= (
422 pc_ast
.RangeSubscript
,
424 if isinstance(p
[2], attribute_or_subscript
):
426 while isinstance(node
.subject
, attribute_or_subscript
):
428 if isinstance(node
.subject
, pc_ast
.Arguments
):
429 node
.subject
= pc_ast
.Call(name
=p
[1], args
=node
.subject
)
433 elif isinstance(p
[2], pc_ast
.Arguments
):
434 p
[0] = pc_ast
.Call(name
=p
[1], args
=p
[2])
436 raise NotImplementedError()
438 def p_atom_name(self
, p
):
444 def p_atom_number(self
, p
):
453 # '[' [listmaker] ']' |
454 def p_atom_listmaker(self
, p
):
456 atom : LBRACK listmaker RBRACK
460 def p_listmaker(self
, p
):
462 listmaker : test COMMA listmaker
466 p
[0] = pc_ast
.Sequence([p
[1]])
468 p
[0] = pc_ast
.Sequence((p
[0],) + p
[1])
470 def p_atom_tuple(self
, p
):
472 atom : LPAR testlist RPAR
475 if (isinstance(value
, pc_ast
.Symbol
) and
476 (str(value
) in self
.__class
__.REGS
)):
477 value
= self
.__class
__.REGS
[str(value
)](value
)
480 def p_trailerlist(self
, p
):
482 trailerlist : trailer trailerlist
488 attribute_or_subscript
= (
491 pc_ast
.RangeSubscript
,
493 if isinstance(p
[2], attribute_or_subscript
):
495 while isinstance(node
.subject
, attribute_or_subscript
):
500 p
[0] = pc_ast
.Sequence(p
[1] + (p
[2],))
502 # trailer: '(' [arglist] ')' | '[' subscriptlist ']' | '.' NAME
503 def p_trailer(self
, p
):
505 trailer : trailer_arglist
511 def p_trailer_arglist(self
, p
):
513 trailer_arglist : LPAR arglist RPAR
517 p
[0] = pc_ast
.Arguments()
521 def p_trailer_subscript(self
, p
):
523 trailer_subscript : LBRACK subscript RBRACK
527 def p_trailer_attr(self
, p
):
529 trailer_attr : PERIOD NAME
531 p
[0] = pc_ast
.Attribute(name
=p
[2])
533 # subscript: '.' '.' '.' | test | [test] ':' [test]
534 def p_subscript(self
, p
):
535 """subscript : test COLON test
539 p
[0] = pc_ast
.RangeSubscript(start
=p
[1], end
=p
[3])
541 p
[0] = pc_ast
.Subscript(index
=p
[1])
543 # testlist: test (',' test)* [',']
544 # Contains shift/reduce error
545 def p_testlist(self
, p
):
547 testlist : testlist_multi COMMA
553 if isinstance(p
[1], pc_ast
.Sequence
):
556 p
[0] = pc_ast
.Sequence([p
[1]])
558 def p_testlist_multi(self
, p
):
560 testlist_multi : testlist_multi COMMA test
566 if isinstance(p
[1], pc_ast
.Sequence
):
567 p
[0] = pc_ast
.Sequence(p
[1] + (p
[3],))
569 p
[0] = pc_ast
.Sequence([p
[1], p
[3]])
571 # test: or_test ['if' or_test 'else' test] | lambdef
572 # as I don't support 'and', 'or', and 'not' this works down to 'comparison'
576 | comparison QMARK test COLON test
581 p
[0] = pc_ast
.IfExpr(test
=p
[1],
582 body
=pc_ast
.Scope([p
[3]]),
583 orelse
=pc_ast
.Scope([p
[5]]))
585 # arglist: (argument ',')* (argument [',']| '*' test [',' '**' test]
587 # XXX INCOMPLETE: this doesn't allow the trailing comma
588 def p_arglist(self
, p
):
590 arglist : arglist COMMA argument
594 p
[0] = pc_ast
.Arguments(p
[1] + (p
[3],))
596 p
[0] = pc_ast
.Arguments([p
[1]])
598 # argument: test [gen_for] | test '=' test # Really [keyword '='] test
599 def p_argument(self
, p
):
605 def p_error(self
, p
):
606 raise_syntax_error(str(p
.value
),
607 self
.filename
, p
.lineno
, p
.lexpos
,
610 def parse(self
, code
, filename
=None, debug
=False):
611 self
.filename
= filename
612 self
.input_text
= code
613 return self
.__parser
.parse(lexer
=self
.__lexer
, debug
=debug
, input=code
)