Die folgende Herausforderung erfordert, dass Sie mit der formalen Parsertheorie vertraut sind. Wenn Sie nicht wissen, was die Frage ist, weil Sie nicht wissen, was die Begriffe bedeuten, werden in vielen Universitätskursen kontextfreie Grammatiken und First / Follow-Sets behandelt.
Ich kann diesen Stanford-Kurs empfehlen , insbesondere die Handouts 08 und 09 (ab Seite 7). Ich habe auch einen Spickzettel aus diesen Handouts extrahiert. Ich empfehle jedem, der diese Herausforderung versucht, sie zu lesen .
Schreiben Sie ein Programm oder eine Funktion, die bei einer kontextfreien Grammatik die Folgemenge jedes Nichtterminals findet. Informell ist die folgende Menge eines Nichtterminals eine Menge von Terminals und $
(was das Ende der Eingabe bedeutet), die Sie möglicherweise nach diesem Terminal in einem gültigen Satz finden können.
Die Eingabe erfolgt als einzelne druckbare ASCII-Zeichenfolge oder als Array druckbarer ASCII-Zeilen. Sie können die Sätze in jedem vernünftigen Format ausgeben, indem Sie $
(entweder als Literalausgabe oder als Zeichenfolge in einem Satz usw.) das Ende der Eingabe angeben. Sie können davon ausgehen, dass die Eingabe immer im unten angegebenen Format gültig ist.
Die kontextfreie Grammatik wird sehr vereinfacht angegeben. Jede Linie enthält eine einzelne Produktion. Jede Produktion ist eine durch Leerzeichen getrennte Liste von Symbolen. Ein Terminal ist eine Zeichenfolge, die von Apostrophen umgeben ist (z '**'
. B. ). Der Einfachheit halber können Sie davon ausgehen, dass Terminals keine Leerzeichen enthalten, aber es wäre schön, wenn Ihr Programm dies zulässt. Ein Nichtterminal kann eine beliebige Zeichenfolge sein, die keine Leerzeichen oder enthält $
. Die leere Produktion (normalerweise mit ε gekennzeichnet) ist einfach eine Zeile, die nur das linke Nicht-Terminal enthält. Die erste Zeile ist die Produktion, die das Startsymbol definiert.
Als Beispiel die folgende Grammatik:
S → aSa | bSb | ε
Wird angegeben als:
S 'a' S 'a'
S 'b' S 'b'
S
Beispiel Ein- / Ausgänge:
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', $}
Kürzester Code in Bytes gewinnt.