使用自己的 pyparsing class

pyparsing using own class

我正在尝试遵循 this 教程,但很难将教程中使用的语法转换为 pyparsing 语法。该博客的主旨是创建一种表达式语言来解析和执行字典比较。

properties = {
    "name": "David Bowie",
    "years_active2": 47
}

要计算的表达式:

properties["name"] == "David Bowie"

他们使用的语法是:

 expr:   literal                      { return  } 
  | "properties" "[" literal "]" { return PropertyLookup() }
  | expr "[" expr "]"            { return Index(, ) }
  | expr "and" expr              { return And(, ) }
  | expr "==" expr               { return Equals(, ) }
  | expr ">" expr                { return GreaterThan(, ) }
;

literal:   QUOTED_STRING  { return Literal() }
     | DECIMAL_NUMBER { return Literal() }
;

到目前为止我有:

string_literal = pp.Word(pp.alphas, pp.alphanums)
numeric_literal = pp.Word(pp.nums)
literal = string_literal | numeric_literal
properties = "properties" + "[" + literal + "]"  

PropertyLookup()、Index()、And()、Equals() 和 GreaterThan() 是为构建表达式而创建的自定义 classes。

如何更改我的第 4 行属性,使其与第二行的行为相同?我最困惑的是如何将文字传递到自定义 class 中,例如 PropertyLookup()

class PropertyLookup(object):
    def evaluate(self, props):
        return props[self.key]

感谢任何帮助!

要让 pyparsing 为您构建 classes,请将它们作为解析操作附加到表达式。这是一个如何执行此操作的小示例:

import pyparsing as pp

class Node(object):
    def __init__(self, tokens):
        self._tokens = tokens
    def __repr__(self):
        return "{}: ({})".format(self.__class__.__name__, self._tokens.asList())

class AlphaNode(Node): pass
class NumericNode(Node): pass
class BinExprNode(Node): pass
class OperatorNode(Node): pass

alpha_expr = pp.Word(pp.alphas)
numeric_expr = pp.Word(pp.nums)
operand = alpha_expr | numeric_expr
operator = pp.oneOf("+ - * /")
bin_expr = operand + pp.OneOrMore(operator + operand)

# by setting the node classes as each expression's parse action, 
# the node instances will be constructed at parse time and returned 
# as pyparsing's parse results
alpha_expr.addParseAction(AlphaNode)
numeric_expr.addParseAction(NumericNode)
operator.addParseAction(OperatorNode)
bin_expr.addParseAction(BinExprNode)

result = bin_expr.parseString("a + 27 * X")
print(repr(result[0]))

打印

BinExprNode: ([AlphaNode: (['a']), OperatorNode: (['+']), NumericNode: (['27']), OperatorNode: (['*']), AlphaNode: (['X'])])

您还必须清除语法中的一些左递归 - 您将无法实现以 expr 开头的 expr,这只会递归自身直到你达到了递归限制。首先将基本操作数表达式定义为:

expr:   literal                 
  | "properties" ("[" expr "]")...
;

使用 pyparsing 的 OneOrMore class 重复索引到 "properties"。然后使用 pyparsing 示例中的方法,例如 SimpleBool.py 或 evalArith.py 来构建中缀符号表达式和评估器。