LINUX.ORG.RU

Про синтаксический разбор


0

0

Те, кто пользовался BibTeX'ом, знают, что он понимает списки имён в формате "Ivan Ivanov and Piotr Piotrov and Ktototam Eshio" (разделителем служет and). Парсит он это просто и без затей, на голом паскале. Но истинному лоровцу чужда эта поганая императивщина, и возник вопрос: как разобрать это кошерным LALR(1) парсером? :) Я честно не знаю.

Я бы сделал без кошерного LALR(1) парсера: разбил бы строку по подстроке 'and' а дальше regexp'ами разбирал бы имена. Такое разбиение на имена можно сделать за один проход (получить индексы начало/конец имени в исходной строке). И это можно реализовать без поганой проприетарщины.

Begemoth ★★★★★
()

Такие списки конечным автоматом разбираются. Никакой вложенности же нет, не только бесконечной.

zaregazza
()
Ответ на: комментарий от Begemoth

> Я бы сделал без кошерного LALR(1) парсера: разбил бы строку по подстроке 'and' а дальше regexp'ами разбирал бы имена.

Да и я бы так сделал, но там есть ещё другая фишка: BibTeX игнорирует это and, если оно заключено в фигурные скобки. Например "John {grom and molnija} Silver" - это один человек, а не два. Фиг знает, зачем это может понадобиться, но всё равно. Конечно, и это несложно разобрать, но стало интересно: неужели без императивщины никак?

ero-sennin ★★
() автор топика
Ответ на: комментарий от zaregazza

> Такие списки конечным автоматом разбираются.

Не сомневаюсь, но простого решения придумать не могу.

ero-sennin ★★
() автор топика
Ответ на: комментарий от Begemoth

> В догонку: а разве BibTeX не на С написан?

Как выяснилось, на быдлопаскале, точнее на web. :) Сейчас ради интереса переписываю его на Питоне.

ero-sennin ★★
() автор топика
Ответ на: комментарий от ero-sennin

У меня есть аналог BibTeX на Haskell, стили там тоже на Haskell пишутся. Надо вот собраться да допилить ГОСТовский стиль. Только у меня базы лишь частично совместимы с BibTeX'ом.

Begemoth ★★★★★
()

Мне кажется такая грамматика вполне прокатит:

name_list : string_list
| name_list and string_list

string_list : string
| string_list string

andron01
()
Ответ на: комментарий от Begemoth

В общем, забил и сделал так:

def parse_name_list(s):
    after_white = False
    brace_level = 0
    name_start = 0
    current_pos = -1
    for c in s:
        current_pos += 1
        if c.isspace():
            after_white = True
        elif c == '{':
            brace_level += 1
        elif c == '}':
            brace_level -= 1
        elif c.lower() == 'a':
            if s[pos:pos + 4].lower() == 'and ' and brace_level == 0:
                yield s[name_start:current_pos - 1]
                name_start = current_pos + 4
        after_white = False
    yield s[name_start:]

> Надо вот собраться да допилить ГОСТовский стиль.

Вот и я сейчас на том же этапе. :D А на этих выходных пытаюсь
приделать инетпретатор BibTeX'овских стилей, тогда хоть кому-то
моё поделие может пригодиться. :)

ero-sennin ★★
() автор топика
Ответ на: комментарий от ero-sennin

>Ну а как определить string, чтоб он не зохавал and?
Ну это должен делать лексический анализатор.
Выделив строку он должен сравнить ее с "and", если равно, то возращается токен and, в противном случае токен string.
Также лексический анализатор должен различать стороки начинающиеся с '{'. Если строка начинается с '{' то сканить ее до следующего '}' вместе со всеми пробелами.

andron01
()
Ответ на: комментарий от andron01

Ну так и получится, что (императивный) лексический анализатор сделает всю работу, а парсер вообще останется не у дел. :)

ero-sennin ★★
() автор топика
Ответ на: комментарий от ero-sennin

А теперь объясни, чем в данном случае быдлопаскаль хуже быдлопитона? Та же самая голимая императивщина получилась. Может стоит принять тот факт, что многие задачи гораздо проще решаются в императивном стиле, и не сношать себе моск по пустякам?

anonymous
()
Ответ на: комментарий от anonymous

Да проще-то оно, проще, но я всю жизнь был уверен, что уж для синтаксического-то разбора декларативный стиль всегда рулит, ан ведь нет. :)

ero-sennin ★★
() автор топика

Ну, ээ. На Parse::RecDescent наваялось вот такое (правда, это, вроде как, LL(1) парсер - но какая разница-то?):

namelist: name "and" namelist | name
name: string(s)
string: '{' /[^}]+/ '}' | /^\w+(?<!^and)\b/

Целиковая программа не Perl - печатает деревья разбора:

#!/usr/bin/perl

use strict;
use Parse::RecDescent;
use Data::Dumper;

#$::RD_TRACE = 1;

my $grammar = <<'EOG';
<autotree>

namelist: name "and" namelist | name
name: string(s)
string: '{' /[^}]+/ '}' | /^\w+(?<!^and)\b/

EOG


my $parser = new Parse::RecDescent($grammar);

foreach my $l (
                "Ivan Fedorov",
                "Vasya Petrov and Pytya Sidorov",
                "Ivan Ivanov and Piotr Piotrov and Ktototam Eshio",
                "John {grom and molnija} Silver",
                "John {grom and molnija} Silver and Someone Else",
) {
    print Dumper $parser->namelist($l);
}

anonymous
()

Самое тупое, что придумалось:

parseBibTex [] = [[]]
parseBibTex ('{':xs) = let (inbr,outbr) = parseBibTexBrackets xs
                           ys:yss = parseBibTex outbr
                       in (inbr ++ ys):yss
parseBibTex (' ':'a':'n':'d':' ':xs) = []:(parseBibTex xs)
parseBibTex (x:xs) = let ys:yss = parseBibTex xs in (x:ys):yss

parseBibTexBrackets ('}':xs) = ("",xs)
parseBibTexBrackets ('{':xs) = let (inbr,outbr) = parseBibTexBrackets xs
                                   (inbr',outbr') = parseBibTexBrackets outbr
                               in ('{':(inbr ++ ('}':inbr')), outbr')
parseBibTexBrackets (x:xs) = let (inbr,outbr) = parseBibTexBrackets xs
                             in (x:inbr,outbr)

Miguel ★★★★★
()
Ответ на: комментарий от ero-sennin

А в чем сложность-то, если лексер отдельный (или, как в моей перловой программке, правила вывода понимают PCRE в терминалах)? Даже negaive look-behind в данном конкретном случае не нужен, хотя без него получается спагеттистый регекс в духе:

(\w{1,2}\b)|(\w{4,}\b)|([^a]\w{2}\b)|(\w[^n]\w\b)|(\w{2}[^d]\b)

anonymous
()
Ответ на: комментарий от anonymous

> ^\w+(?<!^and)\b

Гм. Тоже вариант, хоть и жульнический. :)

> (\w{1,2}\b)|(\w{4,}\b)|([^a]\w{2}\b)|(\w[^n]\w\b)|(\w{2}[^d]\b)

Шутку понял, смешно. :)

ero-sennin ★★
() автор топика
Ответ на: комментарий от Miguel

> Самое тупое, что придумалось

Тру! :) И на Бизон вполне переводится.

ero-sennin ★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.