Простой рекурсивный спуск в PyParsing

Так как Вы - удобные мечущие икру внешние процессы от своего кода, Вы могли использовать tee самого. Я не знаю ни о каких системных вызовах Unix, которые делают точно, что tee делает.

# Note this version was written circa Python 2.6, see below for
# an updated 3.3+-compatible version.
import subprocess, os, sys

# Unbuffer output (this ensures the output is in the correct order)
sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)

tee = subprocess.Popen(["tee", "log.txt"], stdin=subprocess.PIPE)
os.dup2(tee.stdin.fileno(), sys.stdout.fileno())
os.dup2(tee.stdin.fileno(), sys.stderr.fileno())

print "\nstdout"
print >>sys.stderr, "stderr"
os.spawnve("P_WAIT", "/bin/ls", ["/bin/ls"], {})
os.execve("/bin/ls", ["/bin/ls"], os.environ)

Вы могли также эмулировать tee использование многопроцессорная обработка пакет (или использование обработка при использовании Python 2.5 или ранее).

Обновление

Вот является Python 3.3 +-compatible версией:

import subprocess, os, sys

tee = subprocess.Popen(["tee", "log.txt"], stdin=subprocess.PIPE)
# Cause tee's stdin to get a copy of our stdin/stdout (as well as that
# of any child processes we spawn)
os.dup2(tee.stdin.fileno(), sys.stdout.fileno())
os.dup2(tee.stdin.fileno(), sys.stderr.fileno())

# The flush flag is needed to guarantee these lines are written before
# the two spawned /bin/ls processes emit any output
print("\nstdout", flush=True)
print("stderr", file=sys.stderr, flush=True)

# These child processes' stdin/stdout are 
os.spawnve("P_WAIT", "/bin/ls", ["/bin/ls"], {})
os.execve("/bin/ls", ["/bin/ls"], os.environ)

17
задан Community 23 May 2017 в 12:24
поделиться

3 ответа

Это более или менее то, что вы хотите ...?

from pyparsing import Literal,Word,ZeroOrMore,Forward,nums,oneOf

def Syntax():
    op = oneOf( '+ - / *')
    lpar  = Literal( '(' )
    rpar  = Literal( ')' )
    num = Word(nums)

    expr = Forward()
    atom = num | ( lpar + expr + rpar )
    expr << atom + ZeroOrMore( op + expr )
    return expr


if __name__ == "__main__":

    expr = Syntax()

    def test(s):
        results = expr.parseString( s )
        print s,'->', results

    test( "(9 + 3)" )
    test( "(9 + 3) * (4 / 5)" )

излучает

(9 + 3) -> ['(', '9', '+', '3', ')']
(9 + 3) * (4 / 5) -> ['(', '9', '+', '3', ')', '*', '(', '4', '/', '5', ')']

? Это «закрепляет» рекурсию, отделяя «атом» (число или выражение в скобках) от «выражения» (один или несколько «атомов» с операторами между ними). ​​

9
ответ дан 30 November 2019 в 11:37
поделиться

С такой грамматикой, как:

expr :: expr op expr

трудно работать, потому что рекурсия просто продолжает уходить влево.

Обычная арифметическая грамматика будет выглядеть примерно так:

expr :: mulxp | mulxp '+' expr
mulxp :: atom | atom '*' expr
atom :: Word(nums) | '(' + expr + ')'

По сути, вы никогда не получите S :: S ; Каждый раз, когда нетерминал появляется слева и справа от строки в грамматике, в середине должен быть какой-то литерал, чтобы синтаксический анализатор мог его обработать.

4
ответ дан 30 November 2019 в 11:37
поделиться

Ух ты, я думаю, пипарсинг действительно актуален! Спасибо, Алекс и Джон, что ответили на этот вопрос. Вы оба на высоте со своими ответами. Но позвольте мне добавить один-два комментария:

  1. Если мы подавим символы открывающей и закрывающей скобок и сгруппируем заключенное в скобки выражение с помощью Group, pyparsing даст структурированный результат, который ближе к AST.

     из pyparsing import Literal, Word, ZeroOrMore, Forward, nums, oneOf, Group
    
    def Синтаксис ():
     op = oneOf ('+ -')
     lpar = Literal ('(') .suppress ()
     rpar = Литерал (')') .suppress ()
     num = Слово (числа)
     expr = Вперед ()
    атом = число | Группа (lpar + expr + rpar)
     expr << атом + ZeroOrMore (op + атом)
     return expr
    
    если __name__ == "__main__":
     expr = Синтаксис ()
     def тест (ы):
     results = expr.parseString (s)
     print s, '->', результаты
    
     тест ("(9 + 3)")
     тест ("(9 + 3) * (4/5)")
    

    Раздача:

     (9 + 3) -> [['9', '+', '3']]
    (9 + 3) * (4/5) -> [['9', '+', '3'], '*', ['4', '/', '5']]
    

    В противном случае pyparsing - это просто токенизация, и вам нужно пройти по списку проанализированных токенов, чтобы найти вложенные выражения.

  2. Поскольку op определен как просто oneOf ("+ - * /"), нет приоритета операции. В репозитории pyparsing есть примеры https://github.com/pyparsing/pyparsing/tree/master/examples ручного способа определения этого (fourFn.py) или более свежего подхода с использованием помощник infixNotation (simpleArith.py). Опять же, у этого pyparsing больше ценности, чем просто токенизация.

Что касается OP, пожалуйста, ознакомьтесь с этими примерами, я думаю, они помогут продвинуть вас вперед в вашем проекте.

- Paul

25
ответ дан 30 November 2019 в 11:37
поделиться
Другие вопросы по тегам:

Похожие вопросы: