python - 将 EBNF 语法转换为 pyparsing 会出错
问题描述
我正在制作一个解析器来将一个简单的 DSL 转换为elasticsearch
查询。一些可能的查询是:
response:success
response:success AND extension:php OR extension:css
response:sucess AND (extension:php OR extension:css)
time >= 2020-01-09
time >= 2020-01-09 AND response:success OR os:windows
NOT reponse:success
response:success AND NOT os:windows
我EBNF
为此编写了以下语法:
<expr> ::= <or>
<or> ::= <and> (" OR " <and>)*
<and> ::= <unary> ((" AND ") <unary>)*
<unary> ::= " NOT " <unary> | <equality>
<equality> ::= (<word> ":" <word>) | <comparison>
<comparison> ::= "(" <expr> ")" | (<word> (" > " | " >= " | " < " | " <= ") <word>)+
<word> ::= ("a" | "b" | "c" | "d" | "e" | "f" | "g"
| "h" | "i" | "j" | "k" | "l" | "m" | "n"
| "o" | "p" | "q" | "r" | "s" | "t" | "u"
| "v" | "w" | "x" | "y" | "z")+
DSL 中运算符的优先级是:
() > NOT > AND > OR
同样精确的数学运算,即':' 具有比比较运算符更高的优先级。
我相信上面的语法抓住了我的 DSL 的想法。我很难将它翻译成 pyparsing,这就是我现在所拥有的:
from pyparsing import *
AND = Keyword('AND') | Keyword('and')
OR = Keyword('OR') | Keyword('or')
NOT = Keyword('NOT') | Keyword('not')
word = Word(printables, excludeChars=':')
expr = Forward()
expr << Or
Comparison = Literal('(') + expr + Literal(')') + OneOrMore(word + ( Literal('>') | Literal('>=') | Literal('<') | Literal('<=')) + word)
Equality = (word + Literal(':') + word) | Comparison
Unary = Forward()
Unary << (NOT + Unary) | Equality
And = Unary + ZeroOrMore(AND + Unary)
Or = And + ZeroOrMore(OR + And)
我得到的错误是:
Traceback (most recent call last):
File "qql.py", line 54, in <module>
expr << Or
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/pyparsing.py", line 5006, in __lshift__
self.mayIndexError = self.expr.mayIndexError
AttributeError: type object 'Or' has no attribute 'mayIndexError'
我认为这是因为我无法Forward()
正确理解。
问题:我怎样才能正确地将上述语法翻译成pyparsing?
**编辑**:当我将pyparsing代码更改为:
AND = Keyword('AND')
OR = Keyword('OR')
NOT = Keyword('NOT')
word = Word(printables, excludeChars=':')
expr = Forward()
Comparison = Literal('(') + expr + Literal(')') + OneOrMore(word + ( Literal('>') | Literal('>=') | Literal('<') | Literal('<=')) + word)
Equality = (word + Literal(':') + word) | Comparison
Unary = Forward()
Unary << ((NOT + Unary) | Equality)
And = Unary + ZeroOrMore(AND) + Unary
Or = And + ZeroOrMore(OR + And)
expr << Or
Q = """response : 200 \
AND extesnion: php \
OR extension: css \
"""
print(expr.parseString(Q))
我得到这个输出:
['response', ':', '200', 'AND', 'extesnion', ':', 'php']
为什么不解析 OR 表达式?
解决方案
推荐阅读
- unity3d - 字符串构造函数不能在统一 c# 中工作
- github - Github - 如何将我的项目提交到现有存储库的子文件夹/目录?
- machine-learning - 在 NEAT 算法中向结构添加节点/连接
- python - 如何将 apscheduler 执行器保留在不同的应用程序中并在不同的应用程序中添加作业
- php - 在 Symfony4 中将 Doctrine-Entity 依赖注入到服务中?
- android - 片段已经添加了带有单例对话框的异常
- ios - Flutter 包构建错误“找不到 swift 文件”
- mysql - 如何修复:错误代码:1242。子查询返回多于 1 行
- java - 无法更改片段的背景颜色
- python - 如何用 django 2 创建一个适应用户数量的表单?