Проблема разбора Ply Lex - PullRequest
       65

Проблема разбора Ply Lex

6 голосов
/ 17 февраля 2011

Я использую 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)  

Он не распознает токен THEN, вместо этого он использует "курицу" как идентификатор.

Есть идеи?

Ответы [ 2 ]

8 голосов
/ 17 февраля 2011

Причина, по которой это не сработало, связана с тем, как 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
4 голосов
/ 10 мая 2012

PLY определяет приоритетность токенов, объявленных как простые строки, в соответствии с самым длинным регулярным выражением, но токены, объявленные как функции, имеют приоритет по порядку.

Из документов:

При построенииосновное регулярное выражение, правила добавляются в следующем порядке:

  1. Все токены, определенные функциями, добавляются в том же порядке, в котором они указаны в файле лексера.
  2. Токены, определенные в строкахзатем добавляются путем сортировки их в порядке уменьшения длины регулярного выражения (сначала добавляются более длинные выражения).

Таким образом, альтернативным решением будет просто указать токены, для которых вы хотите назначить приоритеты в качестве функцийвместо строк, например так:

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'

Таким образом, WHILE и THEN будут первыми правилами, которые будут добавлены, и вы получите ожидаемое поведение.

В качестве примечания,вы использовали r' \t' (необработанную строку) для t_ignore, поэтому Python рассматривал \ как обратную косую черту.Вместо этого это должна быть простая строка, как в примере выше.

...