parse26.py 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535
  1. # Copyright (c) 2017-2024 Rocky Bernstein
  2. """
  3. spark grammar differences over Python2 for Python 2.6.
  4. """
  5. from spark_parser import DEFAULT_DEBUG as PARSER_DEFAULT_DEBUG
  6. from uncompyle6.parser import PythonParserSingle
  7. from uncompyle6.parsers.parse2 import Python2Parser
  8. from uncompyle6.parsers.reducecheck import (
  9. except_handler,
  10. ifelsestmt2,
  11. ifstmt2,
  12. tryelsestmt,
  13. tryexcept,
  14. )
  15. class Python26Parser(Python2Parser):
  16. def __init__(self, debug_parser=PARSER_DEFAULT_DEBUG):
  17. super(Python26Parser, self).__init__(debug_parser)
  18. self.customized = {}
  19. def p_try_except26(self, args):
  20. """
  21. except_stmt ::= except_cond3 except_suite
  22. except_cond1 ::= DUP_TOP expr COMPARE_OP
  23. JUMP_IF_FALSE POP_TOP POP_TOP POP_TOP POP_TOP
  24. except_cond3 ::= DUP_TOP expr COMPARE_OP
  25. JUMP_IF_FALSE POP_TOP POP_TOP store POP_TOP
  26. except_handler ::= JUMP_FORWARD COME_FROM except_stmts
  27. come_froms_pop END_FINALLY come_froms
  28. except_handler ::= JUMP_FORWARD COME_FROM except_stmts
  29. END_FINALLY
  30. except_handler ::= JUMP_FORWARD COME_FROM except_stmts
  31. POP_TOP END_FINALLY
  32. come_froms
  33. except_handler ::= jmp_abs COME_FROM except_stmts
  34. POP_TOP END_FINALLY
  35. except_handler ::= jmp_abs COME_FROM except_stmts
  36. END_FINALLY JUMP_FORWARD
  37. # Sometimes we don't put in COME_FROM to the next statement
  38. # like we do in 2.7. Perhaps we should?
  39. try_except ::= SETUP_EXCEPT suite_stmts_opt POP_BLOCK
  40. except_handler
  41. tryelsestmt ::= SETUP_EXCEPT suite_stmts_opt POP_BLOCK
  42. except_handler else_suite come_froms
  43. tryelsestmtl ::= SETUP_EXCEPT suite_stmts_opt POP_BLOCK
  44. except_handler else_suitel
  45. tryelsestmtc ::= SETUP_EXCEPT suite_stmts_opt POP_BLOCK
  46. except_handler else_suitec
  47. _ifstmts_jump ::= c_stmts_opt JUMP_FORWARD COME_FROM POP_TOP
  48. except_suite ::= c_stmts_opt JUMP_FORWARD come_from_pop
  49. except_suite ::= c_stmts_opt jf_pop
  50. except_suite ::= c_stmts_opt jmp_abs come_from_pop
  51. # This is what happens after a jump where
  52. # we start a new block. For reasons that I don't fully
  53. # understand, there is also a value on the top of the stack.
  54. come_from_pop ::= COME_FROM POP_TOP
  55. come_froms_pop ::= come_froms POP_TOP
  56. """
  57. # In contrast to Python 2.7, Python 2.6 has a lot of
  58. # POP_TOP's which come right after various jumps.
  59. # The COME_FROM instructions our scanner adds, here it is to assist
  60. # distinguishing the extraneous POP_TOPs from those that start
  61. # after one of these jumps
  62. def p_jumps26(self, args):
  63. """
  64. # There are the equivalents of Python 2.7+'s
  65. # POP_JUMP_IF_TRUE and POP_JUMP_IF_FALSE
  66. jmp_true ::= JUMP_IF_TRUE POP_TOP
  67. jmp_false ::= JUMP_IF_FALSE POP_TOP
  68. jb_pop ::= JUMP_BACK POP_TOP
  69. jf_pop ::= JUMP_FORWARD POP_TOP
  70. jb_cont ::= JUMP_BACK
  71. jb_cont ::= CONTINUE
  72. jb_cf_pop ::= come_from_opt JUMP_BACK _come_froms POP_TOP
  73. ja_cf_pop ::= JUMP_ABSOLUTE come_froms POP_TOP
  74. jf_cf_pop ::= JUMP_FORWARD come_froms POP_TOP
  75. # The first optional COME_FROM when it appears is really
  76. # COME_FROM_LOOP, but in <= 2.6 we don't distinguish
  77. # this
  78. cf_jb_cf_pop ::= _come_froms JUMP_BACK come_froms POP_TOP
  79. pb_come_from ::= POP_BLOCK COME_FROM
  80. jb_pb_come_from ::= JUMP_BACK pb_come_from
  81. _ifstmts_jump ::= c_stmts_opt JUMP_FORWARD COME_FROM POP_TOP
  82. _ifstmts_jump ::= c_stmts_opt JUMP_FORWARD come_froms POP_TOP COME_FROM
  83. # This is what happens after a jump where
  84. # we start a new block. For reasons that I don't fully
  85. # understand, there is also a value on the top of the stack.
  86. come_froms_pop ::= come_froms POP_TOP
  87. """
  88. def p_stmt26(self, args):
  89. """
  90. stmt ::= ifelsestmtr
  91. # We use filler as a placeholder to keep nonterminal positions
  92. # the same across different grammars so that the same semantic actions
  93. # can be used
  94. filler ::=
  95. assert ::= assert_expr jmp_true LOAD_ASSERT RAISE_VARARGS_1 come_froms_pop
  96. assert2 ::= assert_expr jmp_true LOAD_ASSERT expr RAISE_VARARGS_2 come_froms_pop
  97. break ::= BREAK_LOOP JUMP_BACK
  98. # Semantic actions want else_suitel to be at index 3
  99. ifelsestmtl ::= testexpr c_stmts_opt cf_jb_cf_pop else_suitel
  100. ifelsestmtc ::= testexpr c_stmts_opt ja_cf_pop else_suitec
  101. ifelsestmt ::= testexpr stmts_opt ja_cf_pop else_suite
  102. stmts_opt ::= stmts
  103. stmts_opt ::=
  104. # The last except of a "try: ... except" can do this...
  105. except_suite ::= stmts_opt COME_FROM JUMP_ABSOLUTE POP_TOP
  106. # Semantic actions want suite_stmts_opt to be at index 3
  107. with ::= expr setupwith SETUP_FINALLY suite_stmts_opt
  108. POP_BLOCK LOAD_CONST COME_FROM WITH_CLEANUP END_FINALLY
  109. # Semantic actions want store to be at index 2
  110. with_as ::= expr setupwithas store suite_stmts_opt
  111. POP_BLOCK LOAD_CONST COME_FROM WITH_CLEANUP END_FINALLY
  112. # This is truly weird. 2.7 does this (not including POP_TOP) with
  113. # opcode SETUP_WITH
  114. setupwith ::= DUP_TOP LOAD_ATTR ROT_TWO LOAD_ATTR CALL_FUNCTION_0 POP_TOP
  115. setupwithas ::= DUP_TOP LOAD_ATTR ROT_TWO LOAD_ATTR CALL_FUNCTION_0 setup_finally
  116. setup_finally ::= STORE_FAST SETUP_FINALLY LOAD_FAST DELETE_FAST
  117. setup_finally ::= STORE_NAME SETUP_FINALLY LOAD_NAME DELETE_NAME
  118. while1stmt ::= SETUP_LOOP l_stmts_opt come_from_opt JUMP_BACK _come_froms
  119. # Sometimes JUMP_BACK is misclassified as CONTINUE.
  120. # workaround until we have better control flow in place
  121. while1stmt ::= SETUP_LOOP l_stmts_opt CONTINUE _come_froms
  122. whilestmt ::= SETUP_LOOP testexpr l_stmts_opt jb_pop POP_BLOCK _come_froms
  123. whilestmt ::= SETUP_LOOP testexpr l_stmts_opt jb_cf_pop pb_come_from
  124. whilestmt ::= SETUP_LOOP testexpr l_stmts_opt jb_cf_pop POP_BLOCK
  125. whilestmt ::= SETUP_LOOP testexpr returns POP_BLOCK COME_FROM
  126. # In the "whilestmt" below, there isn't a COME_FROM when the
  127. # "while" is the last thing in the module or function.
  128. whilestmt ::= SETUP_LOOP testexpr returns POP_TOP POP_BLOCK
  129. whileelsestmt ::= SETUP_LOOP testexpr l_stmts_opt jb_pop POP_BLOCK
  130. else_suitel COME_FROM
  131. while1elsestmt ::= SETUP_LOOP l_stmts JUMP_BACK else_suitel COME_FROM
  132. return ::= return_expr RETURN_END_IF POP_TOP
  133. return ::= return_expr RETURN_VALUE POP_TOP
  134. return_if_stmt ::= return_expr RETURN_END_IF POP_TOP
  135. iflaststmtl ::= testexpr c_stmts_opt jb_cf_pop
  136. iflaststmt ::= testexpr c_stmts_opt JUMP_ABSOLUTE come_from_pop
  137. lastc_stmt ::= iflaststmt come_froms
  138. ifstmt ::= testexpr_then _ifstmts_jump
  139. # Semantic actions want the else to be at position 3
  140. ifelsestmt ::= testexpr_then c_stmts_opt jf_cf_pop else_suite come_froms
  141. ifelsestmt ::= testexpr_then c_stmts_opt filler else_suitel come_froms POP_TOP
  142. ifelsestmt ::= testexpr c_stmts_opt jf_cf_pop else_suite
  143. # We have no jumps to jumps, so no "come_froms" but a single "COME_FROM"
  144. ifelsestmt ::= testexpr c_stmts_opt jf_cf_pop else_suite COME_FROM
  145. # Semantic actions want else_suitel to be at index 3
  146. ifelsestmtl ::= testexpr_then c_stmts_opt jb_cf_pop else_suitel
  147. ifelsestmtc ::= testexpr_then c_stmts_opt ja_cf_pop else_suitec
  148. iflaststmt ::= testexpr_then c_stmts_opt JUMP_ABSOLUTE come_froms POP_TOP
  149. iflaststmt ::= testexpr c_stmts_opt JUMP_ABSOLUTE come_froms POP_TOP
  150. # "if"/"else" statement that ends in a RETURN
  151. ifelsestmtr ::= testexpr_then return_if_stmts returns
  152. testexpr_then ::= testtrue_then
  153. testexpr_then ::= testfalse_then
  154. testtrue_then ::= expr jmp_true_then
  155. testfalse_then ::= expr jmp_false_then
  156. jmp_false_then ::= JUMP_IF_FALSE THEN POP_TOP
  157. jmp_true_then ::= JUMP_IF_TRUE THEN POP_TOP
  158. # In the "while1stmt" below, there sometimes isn't a
  159. # "COME_FROM" when the "while1" is the last thing in the
  160. # module or function.
  161. while1stmt ::= SETUP_LOOP returns come_from_opt
  162. for_block ::= returns _come_froms
  163. """
  164. def p_comp26(self, args):
  165. """
  166. list_for ::= expr for_iter store list_iter JUMP_BACK come_froms POP_TOP
  167. # The JUMP FORWARD below jumps to the JUMP BACK. It seems to happen
  168. # in rare cases that may have to with length of code
  169. # FIXME: we can add a reduction check for this
  170. list_for ::= expr for_iter store list_iter JUMP_FORWARD come_froms POP_TOP
  171. COME_FROM JUMP_BACK
  172. list_for ::= expr for_iter store list_iter jb_cont
  173. # This is for a really funky:
  174. # [ x for x in range(10) if x % 2 if x % 3 ]
  175. # the JUMP_ABSOLUTE is to the instruction after the last POP_TOP
  176. # we have a reduction check for this
  177. list_for ::= expr for_iter store list_iter JUMP_ABSOLUTE come_froms
  178. POP_TOP jb_pop
  179. list_iter ::= list_if JUMP_BACK
  180. list_iter ::= list_if JUMP_BACK COME_FROM POP_TOP
  181. list_comp ::= BUILD_LIST_0 DUP_TOP
  182. store list_iter delete
  183. list_comp ::= BUILD_LIST_0 DUP_TOP
  184. store list_iter JUMP_BACK delete
  185. lc_body ::= LOAD_NAME expr LIST_APPEND
  186. lc_body ::= LOAD_FAST expr LIST_APPEND
  187. comp_for ::= SETUP_LOOP expr for_iter store comp_iter jb_pb_come_from
  188. comp_iter ::= comp_if_not
  189. comp_if_not ::= expr jmp_true comp_iter
  190. comp_body ::= gen_comp_body
  191. for_block ::= l_stmts_opt _come_froms POP_TOP JUMP_BACK
  192. # Make sure we keep indices the same as 2.7
  193. setup_loop_lf ::= SETUP_LOOP LOAD_FAST
  194. genexpr_func ::= setup_loop_lf FOR_ITER store comp_iter jb_pb_come_from
  195. genexpr_func ::= setup_loop_lf FOR_ITER store comp_iter JUMP_BACK come_from_pop
  196. jb_pb_come_from
  197. # This is for a really funky:
  198. # (x for x in range(10) if x % 2 if x % 3 )
  199. # the JUMP_ABSOLUTE is to the instruction after the last POP_TOP.
  200. # Add a reduction check for this?
  201. genexpr_func ::= setup_loop_lf FOR_ITER store comp_iter JUMP_ABSOLUTE come_froms
  202. POP_TOP jb_pop jb_pb_come_from
  203. genexpr_func ::= setup_loop_lf FOR_ITER store comp_iter JUMP_BACK come_froms
  204. POP_TOP jb_pb_come_from
  205. generator_exp ::= LOAD_GENEXPR MAKE_FUNCTION_0 expr GET_ITER CALL_FUNCTION_1 COME_FROM
  206. list_if ::= expr jmp_false_then list_iter
  207. """
  208. def p_ret26(self, args):
  209. """
  210. ret_and ::= expr jmp_false return_expr_or_cond COME_FROM
  211. ret_or ::= expr jmp_true return_expr_or_cond COME_FROM
  212. if_exp_ret ::= expr jmp_false_then expr RETURN_END_IF POP_TOP return_expr_or_cond
  213. if_exp_ret ::= expr jmp_false_then expr return_expr_or_cond
  214. return_if_stmt ::= return_expr RETURN_END_IF POP_TOP
  215. return ::= return_expr RETURN_VALUE POP_TOP
  216. # FIXME: split into Python 2.5
  217. ret_or ::= expr jmp_true return_expr_or_cond come_froms
  218. """
  219. def p_except26(self, args):
  220. """
  221. except_suite ::= c_stmts_opt jmp_abs POP_TOP
  222. """
  223. def p_misc26(self, args):
  224. """
  225. dict ::= BUILD_MAP kvlist
  226. kvlist ::= kvlist kv3
  227. # Note: preserve positions 0 2 and 4 for semantic actions
  228. if_exp_not ::= expr jmp_true expr jf_cf_pop expr COME_FROM
  229. if_exp ::= expr jmp_false expr jf_cf_pop expr come_from_opt
  230. if_exp ::= expr jmp_false expr ja_cf_pop expr
  231. expr ::= if_exp_not
  232. and ::= expr JUMP_IF_FALSE POP_TOP expr JUMP_IF_FALSE POP_TOP
  233. # A "compare_chained" is two comparisons like x <= y <= z
  234. compare_chained ::= expr compared_chained_middle ROT_TWO
  235. COME_FROM POP_TOP _come_froms
  236. compared_chained_middle ::= expr DUP_TOP ROT_THREE COMPARE_OP
  237. jmp_false compared_chained_middle _come_froms
  238. compared_chained_middle ::= expr DUP_TOP ROT_THREE COMPARE_OP
  239. jmp_false compare_chained_right _come_froms
  240. compared_chained_middle ::= expr DUP_TOP ROT_THREE COMPARE_OP
  241. jmp_false_then compared_chained_middle _come_froms
  242. compared_chained_middle ::= expr DUP_TOP ROT_THREE COMPARE_OP
  243. jmp_false_then compare_chained_right _come_froms
  244. compare_chained_right ::= expr COMPARE_OP return_expr_lambda
  245. compare_chained_right ::= expr COMPARE_OP RETURN_END_IF_LAMBDA
  246. compare_chained_right ::= expr COMPARE_OP RETURN_END_IF COME_FROM
  247. return_if_lambda ::= RETURN_END_IF_LAMBDA POP_TOP
  248. stmt ::= if_exp_lambda
  249. stmt ::= if_exp_not_lambda
  250. if_exp_lambda ::= expr jmp_false_then expr return_if_lambda
  251. return_stmt_lambda LAMBDA_MARKER
  252. if_exp_not_lambda ::=
  253. expr jmp_true_then expr return_if_lambda
  254. return_stmt_lambda LAMBDA_MARKER
  255. # if_exp_true are for conditions which always evaluate true
  256. # There is dead or non-optional remnants of the condition code though,
  257. # and we use that to match on to reconstruct the source more accurately
  258. expr ::= if_exp_true
  259. if_exp_true ::= expr jf_pop expr COME_FROM
  260. # This comes from
  261. # 0 or max(5, 3) if 0 else 3
  262. # where there seems to be an additional COME_FROM at the
  263. # end. Not sure if this is appropriately named or
  264. # is the best way to handle
  265. expr ::= if_exp_false
  266. if_exp_false ::= if_exp COME_FROM
  267. """
  268. def customize_grammar_rules(self, tokens, customize):
  269. self.remove_rules(
  270. """
  271. with_as ::= expr SETUP_WITH store suite_stmts_opt
  272. POP_BLOCK LOAD_CONST COME_FROM_WITH
  273. WITH_CLEANUP END_FINALLY
  274. """
  275. )
  276. super(Python26Parser, self).customize_grammar_rules(tokens, customize)
  277. self.reduce_check_table = {
  278. "except_handler": except_handler,
  279. "ifstmt": ifstmt2,
  280. "ifelsestmt": ifelsestmt2,
  281. "tryelsestmt": tryelsestmt,
  282. "try_except": tryexcept,
  283. "tryelsestmtl": tryelsestmt,
  284. }
  285. self.check_reduce["and"] = "AST"
  286. self.check_reduce["assert_expr_and"] = "AST"
  287. self.check_reduce["except_handler"] = "tokens"
  288. self.check_reduce["ifstmt"] = "AST"
  289. self.check_reduce["ifelsestmt"] = "AST"
  290. self.check_reduce["forelselaststmtl"] = "tokens"
  291. self.check_reduce["forelsestmt"] = "tokens"
  292. self.check_reduce["list_for"] = "AST"
  293. self.check_reduce["try_except"] = "AST"
  294. self.check_reduce["tryelsestmt"] = "AST"
  295. self.check_reduce["tryelsestmtl"] = "AST"
  296. def reduce_is_invalid(self, rule, ast, tokens, first, last):
  297. invalid = super(Python26Parser, self).reduce_is_invalid(
  298. rule, ast, tokens, first, last
  299. )
  300. lhs = rule[0]
  301. if invalid or tokens is None:
  302. return invalid
  303. if rule in (
  304. ("and", ("expr", "jmp_false", "expr", "\\e_come_from_opt")),
  305. ("and", ("expr", "jmp_false", "expr", "come_from_opt")),
  306. ("assert_expr_and", ("assert_expr", "jmp_false", "expr")),
  307. ):
  308. # FIXME: workaround profiling bug
  309. if ast[1] is None:
  310. return False
  311. # For now, we won't let the 2nd 'expr' be an "if_exp_not"
  312. # However in < 2.6 where we don't have if/else expression it *can*
  313. # be.
  314. if self.version >= (2, 6) and ast[2][0] == "if_exp_not":
  315. return True
  316. test_index = last
  317. while tokens[test_index].kind == "COME_FROM":
  318. test_index += 1
  319. if tokens[test_index].kind.startswith("JUMP_IF"):
  320. return False
  321. # Test that jmp_false jumps to the end of "and"
  322. # or that it jumps to the same place as the end of "and"
  323. jmp_false = ast[1][0]
  324. jmp_target = jmp_false.offset + jmp_false.attr + 3
  325. return not (
  326. jmp_target == tokens[test_index].offset
  327. or tokens[last].pattr == jmp_false.pattr
  328. )
  329. elif lhs in ("forelselaststmtl", "forelsestmt"):
  330. # print("XXX", first, last)
  331. # for t in range(first, last):
  332. # print(tokens[t])
  333. # print("=" * 30)
  334. # If the SETUP_LOOP jumps to the tokens[last] then
  335. # this is a "for" not a "for else".
  336. # However, in Python 2.2 and before there is a SET_LINENO
  337. # instruction which might have gotten removed. So we need
  338. # to account for that. bytecode-1.4/anydbm.pyc exhibits
  339. # this behavior.
  340. # Also we need to use the setup_loop instruction (not opcode)
  341. # since the operand can be a relative offset rather than
  342. # an absolute offset.
  343. setup_inst = self.insts[self.offset2inst_index[tokens[first].offset]]
  344. last = min(len(tokens) - 1, last)
  345. if self.version <= (2, 2) and tokens[last] == "COME_FROM":
  346. last += 1
  347. return tokens[last - 1].off2int() > setup_inst.argval
  348. elif rule == ("ifstmt", ("testexpr", "_ifstmts_jump")):
  349. for i in range(last - 1, last - 4, -1):
  350. t = tokens[i]
  351. if t == "JUMP_FORWARD":
  352. return t.attr > tokens[min(last, len(tokens) - 1)].off2int()
  353. elif t not in ("POP_TOP", "COME_FROM"):
  354. break
  355. pass
  356. pass
  357. elif rule == (
  358. "list_for",
  359. (
  360. "expr",
  361. "for_iter",
  362. "store",
  363. "list_iter",
  364. "JUMP_ABSOLUTE",
  365. "come_froms",
  366. "POP_TOP",
  367. "jb_pop",
  368. ),
  369. ):
  370. # The JUMP_ABSOLUTE has to be to the last POP_TOP or this is invalid
  371. ja_attr = ast[4].attr
  372. return tokens[last].offset != ja_attr
  373. elif lhs == "try_except":
  374. # We need to distinguish "try_except" from "tryelsestmt"; we do that
  375. # by looking for a jump before the END_FINALLY to the "else" clause of
  376. # "try else".
  377. #
  378. # If we have:
  379. # <insn>
  380. # POP_TOP
  381. # END_FINALLY
  382. # COME_FROM
  383. # then <insn> has to be either a a jump of some sort (JUMP_FORWARD, BREAK_LOOP, JUMP_BACK, or RETURN_VALUE).
  384. # Furthermore, if it is JUMP_FORWARD, then it has to be a JUMP_FORWARD to right after
  385. # COME_FROM
  386. if last == len(tokens):
  387. last -= 1
  388. if tokens[last] != "COME_FROM" and tokens[last - 1] == "COME_FROM":
  389. last -= 1
  390. if (
  391. tokens[last] == "COME_FROM"
  392. and tokens[last - 1] == "END_FINALLY"
  393. and tokens[last - 2] == "POP_TOP"
  394. ):
  395. # A jump of 2 is a jump around POP_TOP, END_FINALLY which
  396. # would indicate try/else rather than try
  397. return tokens[last - 3].kind not in frozenset(
  398. ("JUMP_FORWARD", "JUMP_BACK", "BREAK_LOOP", "RETURN_VALUE")
  399. ) or (tokens[last - 3] == "JUMP_FORWARD" and tokens[last - 3].attr != 2)
  400. return False
  401. class Python26ParserSingle(Python2Parser, PythonParserSingle):
  402. pass
  403. if __name__ == "__main__":
  404. # Check grammar
  405. p = Python26Parser()
  406. p.check_grammar()
  407. from xdis.version_info import IS_PYPY, PYTHON_VERSION_TRIPLE
  408. if PYTHON_VERSION_TRIPLE[:2] == (2, 6):
  409. lhs, rhs, tokens, right_recursive, dup_rhs = p.check_sets()
  410. from uncompyle6.scanner import get_scanner
  411. s = get_scanner(PYTHON_VERSION_TRIPLE, IS_PYPY)
  412. opcode_set = set(s.opc.opname).union(
  413. set(
  414. """JUMP_BACK CONTINUE RETURN_END_IF COME_FROM
  415. LOAD_GENEXPR LOAD_ASSERT LOAD_SETCOMP LOAD_DICTCOMP
  416. LAMBDA_MARKER RETURN_LAST
  417. """.split()
  418. )
  419. )
  420. remain_tokens = set(tokens) - opcode_set
  421. import re
  422. remain_tokens = set([re.sub(r"_\d+$", "", t) for t in remain_tokens])
  423. remain_tokens = set([re.sub("_CONT$", "", t) for t in remain_tokens])
  424. remain_tokens = set(remain_tokens) - opcode_set
  425. print(remain_tokens)
  426. # print(sorted(p.rule2name.items()))