it-swarm.com.de

Was bedeutet "kontextfrei" im Begriff "kontextfreie Grammatik"?

Angesichts der Menge an Material, das zu erklären versucht, was eine kontextfreie Grammatik (CFG) ist, fand ich es überraschend, dass nur sehr wenige (in meiner Stichprobe weniger als 1 von 20) eine Erklärung dafür geben, warum solche Grammatiken als "Kontext" bezeichnet werden. kostenlos". Und meiner Meinung nach gelingt dies niemandem.

Meine Frage ist, warum kontextfreie Grammatiken als kontextfrei bezeichnet werden. Was ist "der Kontext"? Ich hatte die Intuition, dass der Kontext andere Sprachkonstrukte sein könnte, die das aktuell analysierte Konstrukt umgeben, aber das scheint nicht der Fall zu sein. Könnte jemand eine genaue Erklärung geben?

56
rick

Dies bedeutet, dass alle Produktionsregeln ein einzelnes nicht terminal auf der linken Seite haben.

Zum Beispiel ist diese Grammatik , die Zeichenfolgen übereinstimmender Klammern ("()", "() ()", "(()) ()", ...) erkennt, kontextfrei:

S → SS
S → (S)
S → ()

Die linke Seite jeder Regel besteht aus einem einzelnen Nicht-Terminal (in diesem Fall ist es immer S, aber es könnte noch mehr geben.)

Betrachten Sie nun diese andere Grammatik , die Zeichenfolgen der Form {a ^ n b ^ n c ^ n: n> = 1} erkennt (z. B. "abc", "aabbcc", "aaabbbccc"):

S  → abc
S  → aSBc
cB → WB
WB → WX
WX → BX
BX → Bc
bB → bb

Wenn dem Nicht-Terminal B das Terminal-/Literalzeichen c vorangestellt ist, schreiben Sie diesen Begriff in WB um, aber wenn ihm b vorangestellt ist, Sie Erweitern Sie stattdessen auf bb. Dies ist vermutlich das, worauf die Kontextsensitivität kontextsensitiver Grammatiken anspielt.

Eine kontextfreie Sprache kann als Push-Down-Automat erkannt werden. Während eine Finite-State-Maschine keinen Hilfsspeicher verwendet, d. H. Ihre Entscheidung basiert nur auf ihrem aktuellen Zustand und ihrer Eingabe, verfügt ein Push-Down-Automat auch über einen Stapel und kann zum Treffen von Entscheidungen auf die Oberseite des Stapels blicken.

Um dies in Aktion zu sehen, können Sie verschachtelte Klammern analysieren, indem Sie sich von links nach rechts bewegen und jedes Mal, wenn Sie auf eine stoßen, eine linke Klammer auf einen Stapel schieben und jedes Mal, wenn Sie auf eine rechte Klammer stoßen, ein Popup ausführen. Wenn Sie nie versuchen, von einem leeren Stapel zu springen, und der Stapel am Ende der Zeichenfolge leer ist, ist die Zeichenfolge gültig.

Für eine kontextsensitive Sprache reicht ein PDA nicht aus. Sie benötigen einen linear begrenzten Automaten , der einer Turing-Maschine ähnelt, deren Band nicht ist unbegrenzt (obwohl die verfügbare Bandmenge proportional zur Eingabe ist). Beachten Sie, dass dies Computer ziemlich gut beschreibt - wir betrachten sie gerne als Turing-Maschinen, aber in der realen Welt können Sie nicht willkürlich mehr RAM Mid-Program. Wenn Ihnen nicht klar ist, wie leistungsfähig ein LBA ist als ein PDA, kann ein LBA einen PDA emulieren, indem er einen Teil seines Bandes als Stapel verwendet, aber Es kann sein Band auch auf andere Weise verwenden.

(Wenn Sie sich fragen, was eine Finite-State-Maschine erkennen kann, lautet die Antwort reguläre Ausdrücke. Aber nicht die regulären Ausdrücke für Steroide mit Erfassungsgruppen und Look-Behind/Look-Ahead, die Sie in Programmiersprachen sehen. Ich meine die, die Sie erstellen können mit Operatoren wie [abc], |, *, + und ?. Sie können sehen, dass abbbz übereinstimmt Regex ab*z Nur indem Sie Ihre aktuelle Position in der Zeichenfolge und Regex beibehalten, ist kein Stapel erforderlich.)

60
Doval

Die anderen Antworten sind ziemlich lang, auch wenn sie genau und richtig sind. Dies ist die Kurzversion.

Wenn Sie eine Zeichenfolge (Terminals und Nicht-Terminals) haben und ein Nicht-Terminal in der Zeichenfolge ersetzen möchten, können Sie dies mit einer kontextfreien Grammatik unabhängig von den Zeichen tun, die das Nicht-Terminal umgeben.

Beachten Sie die folgenden Regeln (Kleinbuchstaben sind Terminals, Großbuchstaben sind keine Terminals):

A -> a
AB -> a

In der ersten Regel können Sie ein A ersetzen, unabhängig davon, was um es herum angezeigt wird (Kontext). In der zweiten Regel können Sie A nur ersetzen, wenn B folgt. Während in diesem Fall beide Nichtterminals ersetzt werden, ist der wichtige Punkt, dass die Nichtterminals die A Materie umgeben. Man kann BA nicht durch a oder B durch a ersetzen: nur ein A gefolgt von einem B weil Die Reihenfolge, der Kontext der Nichtterminals ist wichtig. Dies bedeutet, dass der Kontext einer nicht terminalen Angelegenheit in der zweiten Regel kontextsensitiv ist, während die erste Regel kontextfrei ist.

20
user22815

Um die Unterscheidung und die Terminologie besser zu verstehen, ist es eine gute Idee, eine kontextfreie Sprache wie a gegenüberzustellen n b n  mit einem kontextsensitiven wie einem n b n c n . (Notation: a, b und c sind hier Literale und der Exponent n bedeutet, dass das Literal n mal wiederholt wird, n > 0, sagen wir.) Zum Beispiel ist aabbc oder aabbbcc nicht in der letzteren Sprache, wohingegen aabbcc ist.

Ein Akzeptor für die kontextfreie Sprache a n b n  kann ein Paar von a und b zusammenziehen, unabhängig davon, was sich um es herum befindet (dh unabhängig vom Kontext, in dem ab erscheint), und es funktioniert ordnungsgemäß, akzeptiert nur Zeichenfolgen in der Sprache und lehnt alles andere ab. dh die Grammatik ist S -> aSb | ab. Beachten Sie, dass sich auf der linken Seite der Produktion (en) keine Terminals befinden. (Es gibt zwei Produktionsregeln, aber wir schreiben sie nur kompakt.) Der Akzeptor kann grundsätzlich eine lokale, kontextfreie Entscheidung treffen.

Im Gegensatz dazu können Sie so etwas für die kontextsensitive Sprache nicht tun. A. n b n c n , weil Sie sich für letztere irgendwie an den Kontext erinnern müssen, in dem Sie sich befanden, d. h. wie viele Kontraktionen von ab Sie tun, um sie mit Kontraktionen von bc abzugleichen. Eine Grammatik für die letztere Sprache ist

S -> abc | aBSc
Ba -> aB
Bb -> bb

Beachten Sie, dass Sie in den letzten beiden Regeln links sowohl Terminals als auch Nicht-Terminals haben. Die Terminals auf der linken Seite sind der Kontext, in dem die Nicht-Terminals erweitert werden können.


Bootnote zur Terminologie "Vertrag" vs. "Erweitern" usw.: Obwohl die formalen Grammatiken [formal, hah] generativ sind, ist die Art und Weise, wie sie tatsächlich in Parsern implementiert werden, tatsächlich reduktionistisch, dh Sie kontaktieren im Grunde alles mit einem Nicht-Terminal Anwenden der Regeln "in umgekehrter Reihenfolge", weshalb selbst die oben angegebene erste Grammatik in einem Programm nicht praktikabel ist (dies würde Ihnen den berühmten Konflikt zur Schichtreduzierung geben, da Sie sich nicht entscheiden können, welche Regel angewendet werden soll), sondern die beiden oben genannten Grammatiken reichen aus, um die Unterscheidung zwischen kontextfrei und kontextsensitiv zu veranschaulichen. Das Problem der Mehrdeutigkeit in kontextfreien Grammatiken ist ziemlich kompliziert und nicht wirklich das Thema dieser Frage, daher werde ich hier nicht mehr darauf eingehen, zumal sich herausstellt, dass Wikipedia einen anständigen Artikel dazu hat . Im Gegensatz dazu sind die Artikel über kontextfreie und insbesondere die kontextsensitive Sprache! @ # $ @! # $, Besonders wenn Sie neu im Thema sind ... Ich denke, das steht mehr auf meiner TODO-Liste.

7
Fizz

Die obigen Antworten geben eine ziemlich gute Definition dessen, was es ist. Mal sehen, ob ich es in meine eigenen Worte fassen kann, so dass Sie 23 statt 20 Erklärungen haben. Der ganze Zweck einer Grammatik, jeder Grammatik, besteht darin, herauszufinden, ob ein bestimmter Satz ein Satz in der gegebenen Sprache ist. Wir verwenden jedoch wirklich Grammatik und Analyse, um herauszufinden, was der Satz bedeutet. Es ist wie das alte Diagramm eines Satzes, den Sie vielleicht schon in der Schule im Englischunterricht gemacht haben oder nicht. Ein Satz besteht aus einem Subjektteil und einem Prädikatteil, ein Subjektteil hat ein Substantiv und möglicherweise einige Adjektive, ein Prädikatteil hat ein Verb und möglicherweise ein Objektnomen mit einigen weiteren Adjektiven usw.

Wenn es eine Grammatik für Englisch gäbe (und ich glaube nicht, dass dies nicht im Sinne der Informatik der Fall ist), dann hätte sie Regeln der folgenden Form, Produktionen genannt.

Sentence -> SubjectPart PredicatePart
SubjectPart -> Adjective Noun

usw...

Sie könnten dann ein Programm schreiben und ihm einen beliebigen Satz geben, und das Programm könnte die Grammatik verwenden, um herauszufinden, welcher Teil des Satzes jedes Wort ist und welche Beziehung sie zueinander haben.

Wenn es in jeder Produktion nur eine Sache auf der linken Seite gibt, bedeutet dies, dass Sie immer dann, wenn Sie die rechte Seite im Satz sehen, die linke Seite ersetzen dürfen. Wenn Sie beispielsweise ein Adjektivnomen gesehen haben, können Sie "That's a SubjectPart" sagen, ohne auf etwas außerhalb dieser Phrase zu achten.

Englisch (sogar die vereinfachte Beschreibung von Englisch, die ich oben gegeben habe) ist jedoch kontextsensitiv. "Adjektiv Nomen" ist nicht immer ein SubjectPart, es könnte eine NounPhrase in einem PredicatePart sein. Das hängt vom Kontext ab. Lassen Sie uns unsere pseudo-englische Grammatik ein wenig erweitern:

Sentence -> SubjectPart PredicatePart
SubjectPart -> Adjective Noun
PredicatePart -> VerbPhrase ObjectNounPhrase
VerbPhrase ObjectNounPhrase -> VerbPhrase Adjective Noun

Sie können ein "Adjektiv Nomen" nur dann in eine ObjectNounPhrase verwandeln, wenn es direkt nach einer VerbPhrase steht.

Wenn Sie eine Produktion haben und diese jederzeit anwenden können, ist sie kontextfrei, unabhängig davon, was sie umgibt.

Sie können immer leicht erkennen, ob eine Grammatik kontextfrei ist. Überprüfen Sie einfach, ob sich auf der linken Seite der Pfeile mehr als ein Symbol befindet.

Jede Sprache kann durch mehr als eine Grammatik beschrieben werden. Wenn eine Grammatik für eine Sprache kontextfrei ist, ist die Sprache kontextfrei. Für einige Sprachen kann nachgewiesen werden, dass keine kontextfreie Grammatik möglich ist. Ich nehme an, es könnte eine kontextfreie Grammatik für die vereinfachte pseudo-englische Teilmenge geben, die ich oben beschreibe.

Warum es wichtig ist, erfordert eine einfachere Art von Programm, um eine kontextfreie Grammatik zu analysieren. Wie in den anderen Antworten erwähnt, ist nicht die volle Leistung einer Turing-Maschine erforderlich, um eine kontextfreie Grammatik zu analysieren. Ein Lookahead LR (1) -Parser (eine Art Pushdown-Maschine) für eine bestimmte kontextfreie Grammatik kann jeden Satz in dieser Grammatik zeitlich und räumlich linear zur Länge des Satzes analysieren. Wenn der Satz in der Sprache vorliegt, erstellt der Parser einen Strukturbaum, der angibt, was jedes Symbol im Satz bedeutet (oder zumindest welche Rolle es in der Struktur spielt). Wenn der Satz nicht in der Grammatik enthalten ist, bemerkt und stoppt der Parser das erste Symbol, das nicht mit der Grammatik und den vorhergehenden Symbolen in Einklang gebracht werden kann (beim ersten "Fehler").

Was noch besser ist, ist, dass es Programme gibt, in denen Sie eine Beschreibung einer Grammatik und eine Liste von Anweisungen geben können, was mit jedem Teil zu tun ist (in gewissem Sinne, indem jeder Produktion eine "Bedeutung" zugewiesen wird), und das Programm den Parser schreibt für dich. Das Programm analysiert den Satz, findet die Struktur und führt Ihre Anweisungen für jeden Teil der Struktur aus. Diese Art von Programm wird als Parser-Generator oder Compiler-Compiler bezeichnet.

Diese Art der Sprachanalyse wurde für die automatische Analyse natürlicher Sprachen (z. B. Englisch) erfunden. Es stellt sich jedoch heraus, dass dies für die Analyse von Computersprachen am nützlichsten ist. Ein Sprachdesigner kann eine Grammatik schreiben, die seine neue Sprache erfasst, und sie dann durch den Parser-Generator ausführen, um ein Programm zu erhalten, das seine Sprache analysiert und übersetzt, interpretiert, kompiliert, ausführt usw., wenn er möchte.

In den meisten Fällen können Sie dies nicht wirklich tun. Ausgeglichene Klammern sind beispielsweise eine kontextfreie Sprache, aber eine Sprache, in der alle Variablen deklariert werden müssen, bevor Sie sie verwenden, ist kontextsensitiv. Der Parser ist Teil des Compilers, aber zusätzliche Logik ist erforderlich, um diese anderen Anforderungen durchzusetzen. Was Sie dann tun müssen, ist eine Grammatik zu schreiben, die so viel wie möglich von Ihrer Sprache erfasst, diese durch einen Parser-Generator zu führen und dann Code zu schreiben, der den Rest der Anforderungen erzwingt (Symboltabellen-Handler usw.).

Wir verwenden im Allgemeinen keine kontextsensitiven Grammatiken, da diese viel schlechter unterstützt werden. Ich weiß nicht, ob es ein Äquivalent zu einem LR (k) -Parser-Generator für kontextsensitive Sprachen gibt. Ja, eine Turing-Maschine (oder eine linear gebundene Maschine) kann eine analysieren, aber ich weiß nicht, ob es einen allgemeinen Algorithmus gibt, mit dem eine kontextsensitive Grammatik in ein Programm für eine Turing-Maschine umgewandelt werden kann, in dem Sinne, dass ein LR (1 ) Generator erstellt Analysetabellen für eine Pushdown-Maschine. Ich vermute, dass die Tabellen, die dem Parser zugrunde liegen, exponentiell größer wären. In jedem Fall werden CS-Schülern (wie ich früher) normalerweise kontextfreie Grammatiken und LR (1) -Parser-Generatoren wie YACC beigebracht.

5
kwan3217