代码之家  ›  专栏  ›  技术社区  ›  Gaslight Deceive Subvert

lambda演算的Python解析器

  •  0
  • Gaslight Deceive Subvert  · 技术社区  · 7 年前

    为了好玩,我想为非类型化Lambda演算编写一个解析器。这个 最简单的方法可能是编写一个手写解析器,但我想知道 翻译语言语法描述的Python库 到解析器中。以下是该语言的BNF定义:

    <term> ::= <var>
            |  <term> <term>
            |  λ <var> <term>
    

    为了简单起见,我省略了一些规则。应用程序助理 x y z (x y) z

    什么Python库可以接受上述语法描述,或者 模棱两可且左递归,因此实现起来并不繁琐),以及 生成解析器?我想看看如何使用代码,所以请 不要只回答“我能行”。请写代码沿着 以下行:

    >>> G = """syntax description here..."""
    >>> parser = build.the_parser(G)
    >>> parser.parse("λ x. (y z)")
    Abs('x', App(Id('x', Id('y'))))
    

    最后一行是生成的抽象语法树可能是什么。防抱死制动系统 表示抽象(lambda),App表示应用程序,Id表示

    0 回复  |  直到 7 年前
        1
  •  1
  •   Bart Kiers    7 年前

    这个ANTLR4语法的作用是:

    grammar T;
    
    program
     : term EOF
     ;
    
    term
     : Lambda Id '.' term
     | '(' term ')'
     | term term
     | Id
     ;
    
    Lambda
     : '\u03BB'
     ;
    
    Id
     : [a-z] [a-zA-Z0-9]*
     ;
    
    Spaces
     : [ \t\r\n] -> skip
     ;
    

    将上述内容放入名为 T.g4 . 下载 ANTLR4 jar 放入同一文件夹并执行以下操作:

    java -cp antlr-4.7.2-complete.jar org.antlr.v4.Tool -Dlanguage=Python3 T.g4
    

    现在运行:

    from antlr4 import *
    from playground.TLexer import TLexer
    from playground.TParser import TParser
    
    
    tests = [
      'λ x. (y z)', 
      'x y z w'
    ]
    
    for test in tests:
        lexer = TLexer(InputStream(test))
        parser = TParser(CommonTokenStream(lexer))
        tree = parser.program()
        print("{}".format(tree.toStringTree(recog=parser)))
    

    (program (term λ x . (term ( (term (term y) (term z)) ))) <EOF>)
    (program (term (term (term (term x) (term y)) (term z)) (term w)) <EOF>)
    
        2
  •  0
  •   Josh Voigts    7 年前

    这里有一个替代方法,可以删除左递归。尽管访问语法树是西奥普的练习。

    from parsimonious import Grammar
    
    grammar = Grammar(r"""
        start = term
    
        term = ('(' _* term1 _* ')') / term1
        term1 = app / atom1
    
        atom = ('(' _* atom1 _* ')') / atom1
        atom1 = abs / id
    
        abs = 'λ' _* id _* '.' _* term
    
        app = atom _+ term
    
        id = ~"[A-Za-z]+"
    
        _ = ~"[^\S\n\r]"u
    """)
    
    print(grammar.parse("x y z w"))