несколько лексеров для одного парсера с PLY?

Я пытаюсь реализовать парсер python, используя PLY для языка Kconfig, используемого для создания параметров конфигурации для ядра Linux.

Есть ключевое слово source, которое выполняет включение, поэтому я делаю следующее: когда лексер встречает это ключевое слово, я изменяю состояние лексера, чтобы создать новый лексер, который будет лексировать исходный файл:

def t_begin_source(t):
    r'source '
    t.lexer.begin('source')

def t_source_path(t):
    r'[^\n]+\n+'
    t.lexer.begin('INITIAL') 
    global path
    source_lexer = lex.lex(errorlog=lex.NullLogger())
    source_file_name = (path +  t.value.strip(' \"\n')) 
    sourced_file = file(path + t.value.strip(' \"\n')).read()

    source_lexer.input(sourced_file)

    while True:
        tok = source_lexer.token()
        if not tok:
            break

Где-то еще у меня есть эта строка

lexer = lex.lex(errorlog=lex.NullLogger()) 

Это «основной» или «корневой» лексер, который будет вызываться синтаксическим анализатором.

Моя проблема в том, что я не знаю, как сказать синтаксическому анализатору использовать другой лексер или сказать "source_lexer" что-то вернуть...

Возможно, следует использовать функцию клонирования...

Спасибо


person LB40    schedule 11.11.2009    source источник


Ответы (3)


Я не знаю подробностей PLY, но в других подобных системах, которые я построил, было бы разумнее иметь один лексер, который управлял бы стеком включаемых файлов. Таким образом, лексер будет возвращать единый поток токенов, открывая и закрывая включаемые файлы по мере их обнаружения.

person Ned Batchelder    schedule 11.11.2009
comment
Вы можете использовать метод лексера input для сброса лексера и ввода новых данных. После того, как включенный файл будет готов, вы должны вернуться к исходному файлу, где вы остановились (более или менее). - person S.Lott; 12.11.2009
comment
да, но я не знаю, как вернуть эти токены парсеру. - person LB40; 12.11.2009

По интересному совпадению ссылка из того же поиска Google, которая привела меня к этому вопросу, объясняет, как написать собственный лексер для парсера PLY. Пост объясняет это просто и хорошо, но речь идет о четырех переменных экземпляра и одном методе token.

person quark    schedule 04.12.2009
comment
я тоже это сделал... но, наконец, решение по созданию полного списка токенов и использованию моей собственной функции getToken было не таким уж плохим... - person LB40; 04.12.2009

Ok,

Итак, что я сделал, так это создал список всех токенов, который создается до фактического синтаксического анализа.

Парсер больше не вызывает лексер, потому что вы можете переопределить функцию getToken, используемую парсером, используя параметр tokenfunc при вызове функции разбора.

result = yacc.parse(kconfig,debug=1,tokenfunc=my_function)

и моя функция, которая теперь является функцией, вызываемой для получения следующего токена, выполняет итерацию по списку ранее созданных токенов.

Учитывая лексирование, когда я встречаю исходное ключевое слово, я клонирую свой лексер и меняю ввод, чтобы включить файл.

def sourcing_file(source_file_name):
    print "SOURCE FILE NAME " , source_file_name
    sourced_file = file(source_file_name).read()
    source_lexer = lexer.clone()
    source_lexer.input(sourced_file)
    print 'END OF SOURCING FILE'

    while True:
        tok = source_lexer.token()
        if not tok:
            break
        token_list.append(tok)
person LB40    schedule 13.11.2009