2017-01-02 9 views
1

Я стараюсь следовать учебнику this, и мне трудно преобразовать грамматику, используемую в учебнике, к грамматике пифарирования. Суть блога заключается в создании языка выражения для синтаксического анализа и сравнения словарей.pyparsing с использованием собственного класса

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

выражение для оценки:

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

Грамматика они использовали это:

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

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

до сих пор у меня есть:

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() являются пользовательскими cl ослы, созданные для создания выражения.

Как я могу изменить свою четвертую строчку свойств так же, как и их вторая линия? Я в основном путают о том, как передать буквальным в пользовательский класс, такие как PropertyLookup(), который

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

Любая помощь приветствуется!

+0

Что вы пробовали? Каков был результат? Как он отличался от того, что вы ожидали? Иногда хороший способ отделиться от учебника - это скопировать его * точно *, а затем начать вносить изменения. Если он сломается, вернитесь туда, где он все еще работает, а затем узнайте, что * вы * это нарушили. –

ответ

3

Чтобы иметь pyparsing, постройте для себя классы, присоедините их к синтаксическим выражениям. Вот небольшой пример того, как сделать это:

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, это будет просто рекурсивно, пока вы не достигнете предела рекурсии. Начните с определения вашего выражения базового операнда как: класс OneOrMore

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

Используйте Pyparsing для повторения индексации в «свойства». Затем используйте методы в примерах pyparsing, таких как SimpleBool.py или evalArith.py, для создания выражений и оценщиков инфиксной нотации.