Проблема синтаксического анализа Ply Lex
Я использую ply как мой парсер lex. Мои спецификации следующие:
t_WHILE = r'while'
t_THEN = r'then'
t_ID = r'[a-zA-Z_][a-zA-Z0-9_]*'
t_NUMBER = r'd+'
t_LESSEQUAL = r'<='
t_ASSIGN = r'='
t_ignore = r' t'
когда я пытаюсь разобрать следующую строку:
"while n <= 0 then h = 1"
Он дает следующий вывод:
LexToken(ID,'while',1,0)
LexToken(ID,'n',1,6)
LexToken(LESSEQUAL,'<=',1,8)
LexToken(NUMBER,'0',1,11)
LexToken(ID,'hen',1,14) ------> PROBLEM!
LexToken(ID,'h',1,18)
LexToken(ASSIGN,'=',1,20)
LexToken(NUMBER,'1',1,22)
он не распознает токен, вместо этого он принимает "курицу" в качестве идентификатора.
какие идеи?
2 ответов
причина, по которой это не сработало, связана с тем, как ply устанавливает приоритеты совпадений токенов, сначала тестируется самое длинное регулярное выражение токена.
самый простой способ предотвратить эту проблему-сопоставить идентификаторы и зарезервированные слова одного типа и выбрать соответствующий Тип маркера на основе совпадения. Следующий код аналогичен примеру в ply документация
import ply.lex
tokens = [ 'ID', 'NUMBER', 'LESSEQUAL', 'ASSIGN' ]
reserved = {
'while' : 'WHILE',
'then' : 'THEN'
}
tokens += reserved.values()
t_ignore = ' \t'
t_NUMBER = '\d+'
t_LESSEQUAL = '\<\='
t_ASSIGN = '\='
def t_ID(t):
r'[a-zA-Z_][a-zA-Z0-9_]*'
if t.value in reserved:
t.type = reserved[ t.value ]
return t
def t_error(t):
print 'Illegal character'
t.lexer.skip(1)
lexer = ply.lex.lex()
lexer.input("while n <= 0 then h = 1")
while True:
tok = lexer.token()
if not tok:
break
print tok
PLY приоритизирует маркеры, объявленные как простые строки в соответствии с самым длинным регулярным выражением,но маркеры, объявленные как функции, имеют приоритет своего порядка.
документы:
при построении главного регулярного выражения правила добавляются в следующий порядок:
- все маркеры, определенные функциями, добавляются в том же порядке, что и в файле lexer.
- маркеры, определенные строками добавлено далее, сортируя их в порядке уменьшения длины регулярного выражения (добавляются более длинные выражения сначала.)
таким образом, альтернативным решением было бы просто указать токены, которые вы хотите приоритизировать как функции, а не строки, например:
def t_WHILE(t): r'while'; return t
def t_THEN(t): r'then'; return t
t_ID = r'[a-zA-Z_][a-zA-Z0-9_]*'
t_NUMBER = r'\d+'
t_LESSEQUAL = r'<='
t_ASSIGN = r'='
t_ignore = ' \t'
таким образом, а затем будут добавлены первые правила, и вы получите поведение, которое вы ожидали.
в качестве примечания, вы использовали r' \t'
(необработанная строка) для t_ignore, Итак, питон лечил \
как таковой. Вместо этого должна быть простая строка, как в приведенном выше примере.