Найти следующие наборы

14

Задача ниже требует, чтобы вы были знакомы с формальной теорией синтаксического анализа. Если вы не знаете, что задает вопрос, потому что не знаете, что означают эти термины, грамматики без контекста и наборы «первый / следующий» рассматриваются во многих университетских курсах.

Я могу порекомендовать этот Стэнфордский курс , в частности раздаточные материалы 08 и 09 (со страницы 7). Из этих раздаточных материалов я также извлек шпаргалку - всем, кто пытается выполнить эту задачу, я рекомендую прочитать ее .


Напишите программу или функцию, которая с учетом контекстно-свободной грамматики найдет следующий набор всех нетерминалов. Неформально, следующий набор нетерминала - это набор терминалов и $(имеется в виду конец ввода), который вы можете найти после этого терминала в действительном предложении.

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

Контекстно-свободная грамматика дана в очень упрощенной форме. Каждая линия содержит одну продукцию. Каждое производство представляет собой список символов, разделенных пробелами. Терминал - это строка символов, окруженная апострофами (например '**'). Для простоты вы можете предположить, что терминалы не содержат пробелов, но было бы неплохо, если ваша программа это позволяет. Нетерминал может быть любой строкой, не содержащей пробелов или $. Пустое произведение (обычно обозначаемое ε) - это просто строка, содержащая только нетерминал с левой стороны. Первая строка - это производство, определяющее начальный символ.

В качестве примера приведем следующую грамматику:

S → aSa | bSb | ε

Будет дано как:

S 'a' S 'a'
S 'b' S 'b'
S

Пример ввода / вывода:

In:
S 'a' S 'a'
S 'b' S 'b'
S

Out:
S {'a', 'b', $}

In:
S A B C
A 'a'
A C 'b'
A
B C
B 'd' A
B
C 'e'
C 'f' 

Out:
S {$}
A {'d', 'e', 'f'}
B {'e', 'f'}
C {'b', 'e', 'f', $}

In:
Start Alice Bob
Alice Charlie 'a'
Alice
Bob Bob 'a' Alice Charlie
Bob '!!!'
Charlie 'b'
Charlie

Out:
Start {$}
Alice {'a', '!!!', 'b', $}
Bob {'a', $}
Charlie {'a', $}

Самый короткий код в байтах побеждает.

orlp
источник
4
Предполагая, что люди знают, что такое контекстно-свободная грамматика, это нормально, но я думаю, что это не повредит, если вы включите определение набора следования прямо здесь, вместо того, чтобы просто ссылаться на него.
Мартин Эндер
1
Это возвращает некоторые воспоминания о « Конструкции компилятора » в университете, где нам пришлось решать множество подобных задач.
имя_пользователя здесь

Ответы:

3

Perl, 257 байт

Включает +4 для -0p

Дайте грамматику на STDIN (без конечных пробелов. Обязательно удалите лишний пробел во втором примере). Предполагается, что нетерминальные имена содержат только буквы, цифры и _. Используется #вместо того, $чтобы указывать конец ввода. Может обрабатывать литералы, содержащие пробелы

perl -M5.010 follow.pl
E T e
e '+' T e
e
T F t
t '*' F t
t
F '(' E ')'
F 'id'
^D

Выводит следующие наборы в виде списка non-terminal literalв произвольном порядке. Для приведенного выше примера это выводит:

F ')'
F #
t ')'
t #
T ')'
T #
F '+'
t '+'
T '+'
F '*'
e ')'
e #
E ')'
E #

follow.pl:

#!/usr/bin/perl -0n
s/'.*?'/~$&/eg;s% (?=(\w.*\n))%$_.=">$1"%reg;/\s/;$_.=">$` #\n";s%^((\w+)\K ?\S*).*%$s{$1}++||"\$a.=s/ $2\\b/$&/rg"%eemgr,s%^(\w+ ).*?(\w+)$%"\$a.=s/>$1/>$2 /rg"%eermg,$_.=$a,s%>.*\xd8\K .*%%g,s%.+\n%$&x!/\n$&/g%eg until$$_++;s/\xd8.*?\xd8/~$&/eg;say/>(\w+ \W\S*\n)/g

Работает, как показано, но заменяет их \xd8и \nих буквальными версиями, чтобы получить заявленную оценку.

Это должно быть возможно улучшить, поскольку преобразование firstнаборов в followнаборы в настоящее время очень неудобно.

Тон Хоспел
источник