一个python解析器,它在502行python中构建python ast而不使用模块
pymetaterp的Python项目详细描述
侏儒虫
这是一个不使用python模块的python ast构建器。更长的无堆栈版本可用于更容易的移植。single_file.py
是一个独立的502行脚本。
它(也)只是另一个基于解析表达式语法(peg)的解析器,有一个主要区别。解析的语法将被解释而不是编译。这使得修改语言(通过编辑其语法)和编写语法的语言(以及编写语法的语言)变得很容易。
[这是一种预发布的类型。可能有一些错误和信息丢失。]
下载并运行
git clone https://github.com/asrp/pymetaterp
cd pymetaterp
python single_file.py
或
python single_file.py filename.py
这将打印出给定文件的ast(或single_file.py
自己的ast)。输出的示例开头:
file_input
regular_assign
testlist
NAME
str 'NAME'
NAME
str 'FLAGS'
从库中运行文件
python test/boot_test.py
python test/python_parse_test.py
文件
single_file.py
主要用于演示。否则,此模块将被分为多个文件。有许多文件,但大多是分开的。导入依赖项是
util.py
boot.py
boot_stackless.py
python.py
其他文件没有导入。要获得有用的信息,必须导入多个文件。有关一些示例,请参见test/python_parse_test.py
和test/boot_test.py
。
回复
很明显,缺少语法读取评估打印循环(repl),因此可以一次为解释器提供一条规则,使用目前看到的规则解析子序列输入。
源读取顺序
我建议首先阅读boot_grammar.py
中的boot.py
和bootstrap
。这两个函数构成核心,它们与boot-tree.py一起可以重新生成boot-tree。
然后boot_stackless
与boot.py
相同,但不使用python调用堆栈/递归进行解析。
python.py
为boot.py
解释器添加功能。diff
在boot_grammar.py
中添加这些语法。
最后,python_grammar.py
包含要最终解析的python语法。
已分析Python语言
模块为Python2.x程序构建AST。它能够解析所有的Python2.x(事实上,它包含了Python2.x语法的一个稍微修改过的版本),但是对空白的处理不够宽容。例如,解析
from my_module import (var1, var2,
var3, var4)
出现错误。
因为这是一个预发行版,所以我不经常使用的部分语言可能有错误。它可以为这里包含的所有文件构建ast。
Gramamr语言差异
boot_grammar.py
的开头自描述语法。它是一个peg-so all"or"()返回第一个匹配和"and"和"quantified"(
*,+,?
)贪婪。
name = (letter | '_') (letter | digit | '_')*
expr = apply | exactly | token | parenthesis | output
exactly! = "'" {(escaped_char | ~'\'' anything)*} "'"
token! = "\"" {(escaped_char | ~'"' anything)*} "\""
escaped_char! = '\\' {'n'|'r'|'t'|'b'|'f'|'"'|'\''|'\\'}
apply! = ('\t'|' ')* {name}
parenthesis = "(" {or} ")"
output! = "{" {or} "}"
not = "~" {expr=negation} | expr
quantified = not (('*' | '+' | '?')=quantifier)?
bound = quantified ('=' {name=inline})?
and = bound*
or = and ("|" {and})*
rule = spaces {name=rule_name '!'?=flags and=args ("=" {or})}
grammar = {rule*} spaces
与其他销钉的主要区别。
- 输出规则:
a{b c}d
将匹配a b c d
的连接,但只返回匹配的b c
- 量词折叠:
letter letter*
返回一个列表,而不是第二个元素与letter*
匹配的列表对 - 嵌套和折叠:
a(b(c d))e
与a b c d e
具有相同的输出(如果某些对需要显式分组,请参见下面的内联部分)。 - 节点折叠:输出中只有一个子节点被其父节点替换,除非
!
("不要折叠")标志已为该节点设置。 - 内联:不知羞耻地接受了欧姆,但解释略有不同。
expression=name
创建名为name的节点
包装expression的输出
- 规则替换:使用第二个
规则名称=表达式
行替换规则名称
的第一个定义(而不是附加到或中)。 - 两种基本令牌:有两种基本令牌类型:
'a'
(单引号)和"a"
(双引号)。双引号标记允许在匹配前使用空格。
重新生成引导树.py
使用解释器创建一些树
匹配树
并对结果调用
保存
。
match_tree.save("tree.py")
左递归
虽然"peg/packrat解析器可以支持左递归",但树输出不是我们想要的。python函数reformat_binary
和reformat_atom
修复解析树的输出。
来源奇怪
两个硬编码规则
if root[NAME] == "anything":
return pop(self.input)
elif root[NAME] == "void":
return
标记的硬编码语义
git clone https://github.com/asrp/pymetaterp
cd pymetaterp
python single_file.py
0
优化
为了缩短这些文件(特别是single_file.py
)做了一些努力,但没有做太多。仍然有一些断言和注释的打印语句可用于调试。当然,最终的目标是减少程序的复杂性和冗长性,而不是行数。
缺少功能
此程序较长版本的功能/膨胀尚未(尚未?)移过去:
- 已访问节点的调试树及其输入和输出
- 函数参数(在语法中,但不在解释器中)
- 嵌套列表输入(也在语法中,但不在解释器中)
- 名称、参数、标志、正文作为参数而不是位置子项
备忘录匹配的输入开始和结束位置- 谓词、操作和规则值的精确python表达式匹配。
平衡的
目前被用作更简单的启发式方法。- 谓词、操作和规则值的精确python表达式匹配。
删除功能
只需要一些基本知识就可以得到一个较小的文件。
git clone https://github.com/asrp/pymetaterp
cd pymetaterp
python single_file.py
1
读数
- ometa-warth的论文读得很好。
- PEG和packrat解析器
- packrat解析器可以支持左递归