zoukankan      html  css  js  c++  java
  • Arcee:又一个 Parser Generator 轮子

    项目地址:https://www.cnblogs.com/estrigriac/p/9573397.html 

    为什么要做这样一个东西呢?不是有Antlr吗,Python下不是也有相应的bind吗?人类为什么又要再做一遍已经成熟了的东西呢?

    答案是不爽!

    之前刷 EOPL ,想用 Python 改写其中的玩具语言,重写了三四个后,感觉很别扭。教材里自带了一个parser,所以不用考虑解释器前端的东西,但我用Python改写时,由于没有可口的前端,写起来很不爽,每次写完后端,都只能自己用 Python 手敲一遍AST,真的很麻烦,所以我就萌生了自己写一个 parser generator 的想法。

    所以,就有 Arcee 。

    使用方法:

    Install

    $ pip install Arcee

    Example

    It's really readable.

    grammar:

    KEYWORDS        : let, if, zero, -
    NUMBER          : d+(.d*)?
    ASSIGN          : =
    SUBTRACTION     : -
    RIGHT_BRACKET   : (
    COLON           : ,
    LETF_BRACKET    : )
    ID              : [A-Za-z]+
    SKIP            : [ \t]+
    
    program : expression ;
    expression : zeroexp
        | diffexp
        | ifexp
        | varexp
        | letexp
        | constexp
        ;
    constexp : $NUMBER ;
    diffexp : '-' '(' expression ',' expression ')' ;
    zeroexp : 'zero' '(' expression ')' ;
    ifexp : 'if' expression 'then' expression 'else' expression ;
    varexp : $ID ;
    letexp : 'let' $ID '=' expression 'in' expression ;
    
    $ arcee grammar > result.py
    

    result.py has three parts:

    Token

    from collections import namedtuple
    
    Token = namedtuple('Token', ['type', 'value', 'line', 'column'])
    Program = namedtuple('Program', ['expression'])
    # ...

    Lexer

    import re
    
    def tokenize(code):
        pass # ...

    Parser

    class Parser:
        def __init__(self, token_list):
            pass
        
        # ... 
            
        def parse_expression(self):
            if xxx:
                self.parse_constexp()
            elif yyy:
                self.parse_diffexp()
            #...
    
        def parse_constexp(self):
            pass
            
        def parse_diffexp(self):
            pass
    
        def parse_zeroexp(self):
            pass
    
        def parse_ifexp(self):
            pass
    
        def parse_varexp(self):
            pass
    
        def parse_letexp(self):
            pass
    You can parse input such as:
    
    input = '''let a = 0 in if zero(a) then -(a, 1) else -(a, 2)'''
    
    tokens = list(tokenize(input))
    
    parser = Parser(tokens)
    
    parser.parse_program()
    result is:
    
    result = Program(
        expression=Expression(
            nonterminal=Letexp(
                ID=Token(type='ID', value='a', line=2, column=4),
                expression1=Expression(
                    nonterminal=Constexp(
                        NUMBER=Token(type='NUMBER', value='0', line=2, column=8))),
                expression2=Expression(
                    nonterminal=Ifexp(
                        expression1=Expression(
                            nonterminal=Zeroexp(
                                expression=Expression(
                                    nonterminal=Varexp(
                                        ID=Token(type='ID', value='a', line=2, column=21))))),
                        expression2=Expression(
                            nonterminal=Diffexp(
                                expression1=Expression(
                                    nonterminal=Varexp(
                                        ID=Token(type='ID', value='a', line=2, column=31))),
                                expression2=Expression(
                                    nonterminal=Constexp(
                                        NUMBER=Token(type='NUMBER', value='1', line=2,
                                                     column=34))))),
                        expression3=Expression(
                            nonterminal=Diffexp(
                                expression1=Expression(
                                    nonterminal=Varexp(
                                        ID=Token(type='ID', value='a', line=2, column=44))),
                                expression2=Expression(
                                    nonterminal=Constexp(
                                        NUMBER=Token(type='NUMBER', value='2', line=2,
                                                     column=47))))))))))

    Now, you can use this ast to do what you like.

    这个轮子目前还有一点小问题,不过自己用的话还是没问题。由于工作缘故,估计是要去学 JavaScript 了,这个东西估计不会再更新了(也许哪天还会的。。。),到时估计就是重写一个 npm 包吧,这个再说。

  • 相关阅读:
    [USACO06FEB] Stall Reservations 贪心
    [USACO14MAR] Sabotage 二分答案 分数规划
    【机房史】笑面与学弟们的日常正文17最近一次更新20200802
    8.22返校前记
    2020年7月1日
    我TM怎么这么垃圾
    平安夜
    2018 12 21
    新blog
    写在搬家之后.
  • 原文地址:https://www.cnblogs.com/estrigriac/p/9573397.html
Copyright © 2011-2022 走看看