Вопрос

Я пытаюсь написать что-то, что будет анализировать некоторый код.Я могу успешно анализировать foo(spam) и spam+eggs, но foo(spam+eggs) (рекурсивный спуск?моя терминология из компиляторов немного подзабыта) терпит неудачу.

У меня есть следующий код:

from pyparsing_py3 import *

myVal = Word(alphas+nums+'_')    
myFunction = myVal + '(' + delimitedList( myVal ) + ')'

myExpr = Forward()
mySubExpr = ( \
    myVal \
    | (Suppress('(') + Group(myExpr) + Suppress(')')) \
    | myFunction \
    )
myExpr << Group( mySubExpr + ZeroOrMore( oneOf('+ - / * =') + mySubExpr ) )


# SHOULD return: [blah, [foo, +, bar]]
# but actually returns: [blah]
print(myExpr.parseString('blah(foo+bar)'))
Это было полезно?

Решение

Несколько проблем:delimitedList ищет список myVal, разделенный запятыми, т.е.идентификаторы, как единственная приемлемая форма списка аргументов, поэтому, конечно, он не может соответствовать 'foo+bar' (а не списку myVal, разделенному запятыми!);исправление, которое показывает другое - myVal и myFunction начинаются одинаково, поэтому их порядок в mySubExpr имеет значение;исправление, которое открывает еще одно — ДВА уровня вложенности вместо одного.Эти версии кажутся нормальными...:

myVal = Word(alphas+nums+'_')    

myExpr = Forward()
mySubExpr = (
    (Suppress('(') + Group(myExpr) + Suppress(')'))
    | myVal + Suppress('(') + Group(delimitedList(myExpr)) + Suppress(')')
    | myVal
    )
myExpr << mySubExpr + ZeroOrMore( oneOf('+ - / * =') + mySubExpr ) 

print(myExpr.parseString('blah(foo+bar)'))

излучает ['blah', ['foo', '+', 'bar']] по желанию.Я также удалил лишние обратные косые черты, поскольку логическое продолжение строки в любом случае происходит внутри круглых скобок;они были безобидны, но мешали читабельности.

Другие советы

Я обнаружил, что это хорошая привычка при использовании '<< оператор с Forwards должен всегда заключать RHS в круглые скобки.Это:

myExpr << mySubExpr + ZeroOrMore( oneOf('+ - / * =') + mySubExpr )

лучше так, как:

myExpr << ( mySubExpr + ZeroOrMore( oneOf('+ - / * =') + mySubExpr ) )

Это результат моего неудачного выбора '<<'в качестве оператора "вставки" для вставки выражения в переадресацию.Круглые скобки не нужны в данном конкретном случае, но в данном:

integer = Word(nums)
myExpr << mySubExpr + ZeroOrMore( oneOf('+ - / * =') + mySubExpr ) | integer

мы понимаем, почему я говорю "неудачный".Если я упрощу это до "A << B | C", мы легко видим, что приоритет операций приводит к выполнению оценки как "(A << B) | C", поскольку '<<' имеет более высокий приоритет, чем '|'.Результатом является то, что пересылка A получает только вставленное в нее выражение B.Часть "| C" действительно выполняется, но происходит то, что вы получаете "A | C", который создает объект MatchFirst, который затем немедленно отбрасывается, поскольку ему не присвоено ни одно имя переменной.Решением было бы сгруппировать оператор в круглых скобках как "A << (B| C)".В выражениях, составленных только с использованием операций '+', нет реальной необходимости в круглых скобках, поскольку '+' имеет более высокий приоритет, чем '<<'.Но это просто удачное кодирование, и оно вызывает проблему, когда кто-то позже добавляет альтернативное выражение, используя '|' , и не осознает последствий приоритета.Поэтому я предлагаю просто принять стиль "А << (выражение)", чтобы помочь избежать этой путаницы.

(Когда-нибудь я напишу pyparsing 2.0, который позволит мне нарушить совместимость с существующим кодом, и изменю это, чтобы использовать '<<=' оператор, который устраняет все эти проблемы с приоритетом, поскольку '<<=' имеет более низкий приоритет, чем любой из других операторов, используемых pyparsing.)

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top