Вообще, я использую PLY, но поскольку синтаксис описания грамматики он использует от Yacc, то вопрос скорее по нему, а не по питоноспецифичным вещам.
На самом деле моя грамматика гораздо больше, но чтобы не загромождать сообщение написал minimal not working example:
from ply import lex, yacc
tokens = ('LT', 'LPAREN', 'RPAREN', 'NAME')
t_NAME = r'[A-Za-z_@][A-Za-z0-9_@]*'
t_LPAREN = r'\('
t_RPAREN = r'\)'
t_LT = r'<'
t_ignore = ' '
precedence = (
('left', 'LT'),
('left', 'CALL')
)
def p_expression_binop(p):
'expression : expression LT expression'
p[0] = (p[2], p[1], p[3])
def p_expression_call(p):
'expression : expression LPAREN RPAREN %prec CALL'
p[0] = ('Call', p[1])
def p_expression_name(p):
'expression : NAME'
p[0] = ('Name', p[1])
lexer = lex.lex()
parser = yacc.yacc()
print(parser.parse('a < b()'))
Если выполнить этот скрипт (PLY должен быть установлен через пакетный менеджер дистрибутива или pip), то можно получить результат (добавил отступы и переносы для читабельности):
[
('Call',
('<',
('Name', 'a'),
('Name', 'b')
)
)
]
Как можно заметить, операция сравнения оказалась более приоритетной (хотя в precedence она идёт раньше, что даёт меньший приоритет - проверено на другой грамматике, где есть сложение и умножение - 2 + 2 * 2 вычисляется с верными приоритетами), чем вызов функции и в результате мы получаем вызов как функции результата сравнения переменной (a) и функции (b), что, конечно же, полная чушь.
Где я допустил ошибку и как её исправить?