2016-10-07 4 views
1

Я пытаюсь создать парсер, используя Ply, но я столкнулся с странной ошибкой. Вот MCVE, где происходит ошибка соответствия:Python parser ply соответствует неправильному регулярному выражению

Lexer

import ply.lex as lex 

tokens = (
    'IDENTIFIER', 
    'NAME', 
    'EQUALS' 
) 

def t_IDENTIFIER(t): 
    r'\* *[a-zA-Z_]+' 
    print("identifier") 
    return t 

def t_NAME(t): 
    r"[a-zA-Z_]+" 
    print("name") 
    return t 

t_EQUALS = r"=" 
t_ignore = ' \t' 


def t_newline(t): 
    r'\n+' 
    t.lexer.lineno += len(t.value) 

# Error handling rule 
def t_error(t): 
    print("Illegal character '%s' at line' %s'" % (t.value[0] , t.lexer.lineno)) 
    t.lexer.skip(1) 

# Build the lexer 
lexer = lex.lex() 

Parser

import ply.yacc as yacc 
from l import tokens 

def p_main(p): 
    ''' 
    main : NAME EQUALS NAME 
    ''' 

def p_error(p): 
    if p is not None: 
     print ("Line %s, illegal token %s" % (p.lineno, p.value)) 
    else: 
     print("Syntax error in input!") 

parser = yacc.yacc() 

with open('simple2','r') as f: 
    result = parser.parse(f.read()) 

Мой входной файл содержит только это:

A = B 

И то, что происходит в том, что первое слово A совпадает с токеном IDENTIFIER, даже если он не должен делать, поскольку регулярное выражение требует буквы *. После этого анализатор не может распознать выражение, поскольку лексер не возвращает правильные жетоны.

Что не так? Регулярное выражение, используемое для маркера IDENTIFIER, отлично работает в Python.

+0

Возможно, '\ *' рассматривается как '' many \ or none "'? Вы попробовали '\ A = B'? – furas

+0

Нет, это правильный способ соответствия '*'. Я пробовал одно отдельное правило типа «r» \ * », и это правильно соответствует звездочке. – ibi0tux

+0

Я был только quessing – furas

ответ

1

Я думаю, что нашел проблему и решение.

Проблема в ' *''*', поскольку он относится к '\* ' как одна строка - так '\* *' означает '\* ' много раз или ни один (как 'abc*' означает 'abc' много раз или ни одного).

Вам нужно '\*[ ]*' или '\*\s*'

1

Согласно PLY manual: (курсив добавлен)

Внутренне lex.py использует re модуль, чтобы сделать его сопоставления с образцом. Шаблоны скомпилированы с использованием флага re.VERBOSE, который может использоваться для удобства чтения. Однако имейте в виду, что неэкранированные пробелы игнорируются, и комментарии допускаются в этом режиме. Если ваш шаблон содержит пробелы, убедитесь, что вы используете \s. Если вам нужно сопоставить символ #, используйте [#].

Так пробел в вашем регулярном выражении \* *[a-zA-Z_]+ игнорируется, что делает регулярное выражение, эффективно, \**[a-zA-Z_]+; то есть, ноль или более звезд. Если вы действительно хотите, чтобы это была звезда, за которой следовало одно или несколько мест, вам нужно было бы что-то вроде: \*\ [a-zA-Z_]+.

Смежные вопросы