Arcee:又一個 Parser Generator 輪子
阿新 • • 發佈:2018-09-02
sig 方法 install let expr example npm 教材 user
項目地址:tdkihrr/arcee
為什麽要做這樣一個東西呢?不是有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 包吧,這個再說。
Arcee:又一個 Parser Generator 輪子