代码之家  ›  专栏  ›  技术社区  ›  wim

如何在抽象语法树之前编辑解析树?

  •  0
  • wim  · 技术社区  · 6 年前

    parser 模块,因为有时 ast.parse 丢失了太多的信息(例如,它会吃掉空白、注释、额外的paren等—与源代码格式化程序相关的详细信息)

    >>> parser.expr('(*x,)').tolist()
    [258,
     [332,
      [306,
       [310,
        [311,
         [312,
          [313,
           [316,
            [317,
             [318,
              [319,
               [320,
                [321,
                 [322,
                  [323,
                   [324,
                    [325,
                     [7, '('],
                     [326,
                      [315,
                       [16, '*'],
                       [316,
                        [317,
                         [318,
                          [319,
                           [320, [321, [322, [323, [324, [325, [1, 'x']]]]]]]]]]]],
                      [12, ',']],
                     [8, ')']]]]]]]]]]]]]]]]],
     [4, ''],
     [0, '']]
    

    是什么 all those numbers grammar ? 您应该如何解释这个解析树的结构和嵌套?有没有一种方法可以用缩进和符号名称代替代码打印出来?

    0 回复  |  直到 6 年前
        1
  •  2
  •   rici    6 年前

    你在标题中问了一个问题,在正文中问了一些不同的问题。这个答案主要是针对身体的问题,因为我不知道你在寻求什么样的前转换。

    我怀疑你这个名义上的问题的答案要复杂得多。这个 parse 例如,模块也不保留格式或注释(尽管如果有请求,它会标识标记的行号/列号,您可以从中派生非注释行的水平格式)。如果你想写一个彩色查看器,你需要使用 tokenize 解析 ast 标记化 .

    它们要么标识非终结符(语法生成),要么标识终结符(标记)。这两个类别的数字范围不重叠,因此没有混淆。

    您应该如何解释这个解析树的结构和嵌套?

    eval_input file_input ,取决于你是否打过电话 parser.expr parser.suite ). 终端节点以终端索引号开头,后跟令牌的文本表示形式,如果请求,后跟位置信息。非终端节点以非终端索引号开头,后跟子节点。(显然总是至少有一个子节点;Python语法没有可为null的非终结符。)

    阿斯特 模块DOE是单位生产链的浓缩。

    有没有一种方法可以用缩进和符号名称代替代码打印出来?

    当然:

    import parse
    import pprint
    import symbol
    import token
    
    def symbolic(root):
      if root[0] in token.tok_name:
        return [token.tok_name[root[0]], *root[1:]]
      elif root[0] in symbol.sym_name:
        return [symbol.sym_name[root[0]], *map(symbolic, root[1:])]
      else:
        # Not optimal since it doesn't symbolise children, if any.
        # But it should never happen, anyway.
        return root
    
    >>> pprint(symbolic(parser.expr("a if True else b").tolist()))
    ['eval_input',
     ['testlist',
      ['test',
       ['or_test',
        ['and_test',
         ['not_test',
          ['comparison',
           ['expr',
            ['xor_expr',
             ['and_expr',
              ['shift_expr',
               ['arith_expr',
                ['term',
                 ['factor',
                  ['power', ['atom_expr', ['atom', ['NAME', 'a']]]]]]]]]]]]]]],
       ['NAME', 'if'],
       ['or_test',
        ['and_test',
         ['not_test',
          ['comparison',
           ['expr',
            ['xor_expr',
             ['and_expr',
              ['shift_expr',
               ['arith_expr',
                ['term',
                 ['factor',
                  ['power', ['atom_expr', ['atom', ['NAME', 'True']]]]]]]]]]]]]]],
       ['NAME', 'else'],
       ['test',
        ['or_test',
         ['and_test',
          ['not_test',
           ['comparison',
            ['expr',
             ['xor_expr',
              ['and_expr',
               ['shift_expr',
                ['arith_expr',
                 ['term',
                  ['factor',
                   ['power', ['atom_expr', ['atom', ['NAME', 'b']]]]]]]]]]]]]]]]]],
     ['NEWLINE', ''],
     ['ENDMARKER', '']]
    

    test 在上述输出的第三行中,对应于语法生成

    test: or_test ['if' or_test 'else' test]
    

    文件输入

     >>> pprint(symbolic(parser.suite("import sys").tolist()))
    ['file_input',
     ['stmt',
      ['simple_stmt',
       ['small_stmt',
        ['import_stmt',
         ['import_name',
          ['NAME', 'import'],
          ['dotted_as_names',
           ['dotted_as_name', ['dotted_name', ['NAME', 'sys']]]]]]],
       ['NEWLINE', '']]],
     ['NEWLINE', ''],
     ['ENDMARKER', '']]