Che cosa significa "senza contesto" nel termine "grammatica senza contesto"?


55

Data la quantità di materiale che cerca di spiegare cos'è una grammatica senza contesto (CFG), ho trovato sorprendente che pochissimi (nel mio campione, meno di 1 su 20) danno una spiegazione sul perché tali grammatiche sono chiamate "contesto- gratuito". E, a mio avviso, nessuno riesce a farlo.

La mia domanda è: perché le grammatiche senza contesto sono chiamate senza contesto? Che cos'è "il contesto"? Ho avuto un'intuizione che il contesto potrebbe essere altri costrutti linguistici che circondano il costrutto attualmente analizzato, ma questo non sembra essere il caso. Qualcuno potrebbe fornire una spiegazione precisa?


4
cerca "l'analisi più fastidiosa" per C ++ che ti insegnerà perché la contestualità è utile
maniaco del cricchetto

6
Pensavo di sapere cosa fosse una grammatica senza contesto fino a quando non ho appena letto alcune definizioni su Google. Ora vorrei avere un incisione e uno spazio vuoto morbido ... forse andrò fuori ... +1 per una buona domanda. In attesa di alcune risposte intelligibili!
BrianH,

La tua intuizione è ciò che capisco che sia, anche se la definizione formale di "costrutti di altre lingue che circondano il costrutto attualmente analizzato" è opportunamente arcana. Ma non sono abbastanza sicuro di pubblicarlo come risposta.
Telastyn,

1
Guarda i wiki sulla grammatica senza contesto e sulla gerarchia di Chomsky . In pratica l' analisi del linguaggio di programmazione ha un certo contesto, spesso gestito "al di fuori" dell'analisi "privo di contesto" (LR o LL), ad esempio da una tabella di simboli, attributi o ambiente
Basile Starynkevitch

1
Ecco un riferimento a xkcd: xkcd.com/1090
CaptainCodeman,

Risposte:


60

Significa che tutte le sue regole di produzione hanno un unico non terminale sul lato sinistro.

Ad esempio, questa grammatica che riconosce le stringhe di parentesi corrispondenti ("()", "() ()", "(()) ()", ...) è senza contesto:

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

Il lato sinistro di ogni regola è costituito da un singolo non terminale (in questo caso è sempre S, ma potrebbe essercene di più).

Ora considera quest'altra grammatica che riconosce le stringhe della forma {a ^ nb ^ nc ^ n: n> = 1} (ad esempio "abc", "aabbcc", "aaabbbccc"):

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

Se il non terminale Bè preceduto dal carattere terminale / letterale c, si riscrive quel termine in WBma se è preceduto da b, si espande bbinvece in. Questo è presumibilmente ciò a cui allude la sensibilità al contesto delle grammatiche sensibili al contesto.

Un linguaggio senza contesto può essere riconosciuto un automa push-down . Mentre una macchina a stati finiti non utilizza alcuna memoria ausiliaria, cioè la sua decisione si basa solo sul suo stato e sul suo input attuali, un automa push-down ha anche una pila a sua disposizione e può sbirciare in cima alla pila per prendere decisioni.

Per vederlo in azione, puoi analizzare le parentesi annidate spostando da sinistra a destra e spingendo una parentesi sinistra su una pila ogni volta che ne incontri una e saltando fuori ogni volta che incontri una parentesi destra. Se non finisci mai per provare a fare il pop da uno stack vuoto e lo stack è vuoto alla fine della stringa, la stringa è valida.

Per un linguaggio sensibile al contesto, un PDA non è sufficiente. Avrai bisogno di un automa lineare che è come una macchina di Turing il cui nastro non è illimitato (sebbene la quantità di nastro disponibile sia proporzionale all'input). Nota che questo descrive i computer abbastanza bene: ci piace pensarli come Turing Machines ma nel mondo reale non puoi prendere arbitrariamente più RAM a metà programma. Se non è ovvio per te come un LBA sia più potente di un PDA, un LBA può emulare un PDA usando parte del suo nastro come uno stack, ma può anche scegliere di usare il suo nastro in altri modi.

(Se ti stai chiedendo cosa può riconoscere una macchina a stati finiti, la risposta è espressioni regolari. Ma non le regex sugli steroidi con gruppi di cattura e look-behind / look-ahead che vedi nei linguaggi del programma; intendo quelli che puoi costruire con operatori come [abc], |, *, +, e ?. si può vedere che abbbzcorrisponde all'espressione regolare ab*zsolo mantenendo la posizione corrente nella stringa e regex, nessuna pila richiesto.)


14
Spiegazione molto bella. Tuttavia, il nastro di una macchina Turing non deve essere infinito, solo illimitato. Ci può essere una fabbrica di nastri alle due estremità che, quando la macchina vi si imbatte, produce semplicemente più nastro. In questo modo, in qualsiasi momento, è finito.
Mike Dunlavey,

2
@MikeDunlavey Grazie per il chiarimento, risolto.
Doval,

10
Ma la fabbrica di nastri avrebbe bisogno di materiali per la fabbricazione di nastri infiniti, o materiali per la fabbricazione di nastri infiniti, o ... [overflow dello stack]
flamingpenguin

8
@Mehrdad: puoi simulare qualsiasi numero di pile usando due pile: mantieni tutte le pile accatastate l'una sull'altra su una pila e quando hai bisogno di accedere ad una pila più in basso fai saltare le pile superiori e spingile sulla seconda pila. Ciò dimostra che n> 2 pile non sono più potenti di 2 pile. Ora, se 2 pile sono più potenti di 1 pila, non lo so. La mia intuizione dice di no, ma ciò potrebbe dipendere esattamente da cosa sono le primitive dello stack.
Jörg W Mittag,

10
@ JörgWMittag: due pile sono buone come un nastro. Mano ondulata: usa una pila come il lato sinistro del nastro e l'altra pila come il lato destro, rispetto alla tua posizione corrente. Quindi un 2-PDA è una macchina di Turing. Per le primitive devi solo essere in grado di estrarre un valore da uno stack e spingerlo sull'altro, che è il modo in cui ti sposti sul nastro.
Steve Jessop,

20

Le altre risposte sono piuttosto lunghe, anche se accurate e corrette. Questa è la versione breve.

Se hai una stringa di caratteri (terminali e non terminali) e desideri sostituire un non terminale nella stringa, una grammatica senza contesto ti consente di farlo indipendentemente dai caratteri che circondano il non terminale.

Considera le seguenti regole (le lettere minuscole sono terminali, le lettere maiuscole non sono terminali):

A -> a
AB -> a

Nella prima regola, è possibile sostituire un A indipendentemente da ciò che appare intorno (contesto). Nella seconda regola, non è possibile sostituire a Ameno che non sia seguito da B. Mentre entrambi i non-terminali saranno sostituiti in quel caso, il punto importante è che i non-terminali che circondano la Aquestione. Non si può sostituire BAcon ao Bcon a: solo un Aseguito da un Bperché l'ordine, il contesto dei non terminali è importante. Ciò significa che il contesto di un argomento non terminale nella seconda regola, rendendolo sensibile al contesto, mentre la prima regola è senza contesto.


Questa è una spiegazione davvero buona, anche se non sono qualificato per garantire l'accuratezza o la completezza. È tutto quello che c'è da fare?
Rick

1
Le grammatiche informatiche fanno parte della gerarchia di Chomsky . Quell'articolo è un buon punto di partenza. Inoltre, questo argomento dovrebbe far parte di qualsiasi programma di diploma di maturità in informatica. Per lo meno, le università dovrebbero insegnare grammatiche regolari e prive di contesto, dal momento che quelle comprendono la stragrande maggioranza delle lingue che noi programmatori probabilmente incontreremo.

@Snowman: Molto crisp.It sarebbe meglio se dici che "non è possibile derivare a ada ABa meno che non Aè seguito da Binvece di dire 'Non è possibile sostituire A' che potrebbe non essere possibile, perché in realtà si sta sostituendo ABnon è vero?
Giusto il

@justin corretto. Ho aggiornato la mia risposta per essere più chiaro su questo.

@Snowman: Intendi sostituire Ao ABnella seconda regola (sensibile al contesto)? Penso che stai ancora cercando di sostituire Acome detto dalla tua risposta.
Giusto il

7

Per comprendere meglio la distinzione e la terminologia, è una buona idea contrastare un linguaggio privo di contesto come un n b n con un linguaggio sensibile al contesto come un n b n c n . (Notazione: a, b e c sono letterali qui e l'esponente n significa ripetere il letterale n volte, n > 0, per esempio.) Ad esempio, aabbco aabbbccnon è in quest'ultima lingua, mentre lo aabbccè.

Un accettore per il linguaggio context-free a n b n può contrarre un paio di ae bindipendentemente da ciò che è intorno ad esso (cioè indipendentemente dal contesto in cui appare ab) e funzionerà correttamente, accettando solo stringhe nel linguaggio e rigettando ogni altra cosa, cioè la grammatica è S -> aSb | ab. Si noti che non ci sono terminali sul lato sinistro della produzione o delle produzioni . (Esistono due regole di produzione, ma le stiamo solo scrivendo in modo compatto.) L'accettatore può sostanzialmente prendere una decisione locale e senza contesto.

Al contrario, non si può fare qualcosa di simile per la lingua sensibile al contesto di un n b n c n , perché per questi ultimi si deve ricordare in qualche modo il contesto eri in, vale a dire quanti contrazioni di ab che fate per abbinarli con contrazioni di bc. Una grammatica per quest'ultima lingua è

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

Nota che hai entrambi i terminali e non terminali a sinistra nelle ultime due regole. I terminali a sinistra sono il contesto in cui i non terminali possono essere espansi.


Nota introduttiva sulla terminologia del "contratto" vs. applicare le regole "al contrario", motivo per cui anche la prima grammatica di cui sopra non è pratica in un programma (ti darebbe il famoso conflitto di riduzione del turno perché non puoi decidere quale regola applicare), ma le due precedenti le grammatiche sono sufficienti per illustrare la distinzione tra senza contesto e sensibile al contesto. Il problema dell'ambiguità nelle grammatiche senza contesto è piuttosto complicato, e non è proprio l'argomento di questa domanda, quindi non ho intenzione di aggiungere altro qui, soprattutto perché si scopre che Wikipedia ha un articolo decente su questo. Al contrario, i suoi articoli sul contesto senza contesto e in particolare quello sul linguaggio sensibile al contesto sono! @ # $ @! # $ Soprattutto se sei nuovo sull'argomento ... Immagino che sia più sulla mia lista TODO.


5

Le risposte sopra danno una definizione abbastanza buona di ciò che è. Vediamo se riesco a metterlo con le mie parole, in modo che tu abbia 23 spiegazioni invece di 20. Lo scopo di una grammatica, qualsiasi grammatica, è di capire se una particolare frase è una frase in una determinata lingua. Tuttavia, ciò a cui veramente usiamo le grammatiche e l'analisi è capire cosa significa la frase. È come il vecchio schema di una frase che potresti aver fatto o meno in classe inglese a scuola. Una frase è composta da una parte soggetto e una parte predicato, una parte soggetto ha un sostantivo e forse alcuni aggettivi, una parte predicato ha un verbo e forse un nome oggetto, con alcuni aggettivi, ecc.

Se ci fosse una grammatica per l'inglese (e non penso che ci sia, non nel senso dell'informatica), avrebbe regole della forma seguente, chiamate produzioni.

Sentence -> SubjectPart PredicatePart
SubjectPart -> Adjective Noun

eccetera...

Potresti quindi scrivere un programma e consegnarlo a qualsiasi frase, e il programma potrebbe usare la grammatica per capire quale parte della frase è ogni parola e quale relazione hanno l'una con l'altra.

Se in ogni produzione c'è solo una cosa sul lato sinistro, ciò significa che ogni volta che vedi il lato destro nella frase, ti è permesso sostituire il lato sinistro. Ad esempio, ogni volta che vedevi un sostantivo aggettivo, potresti dire "That's a SubjectPart" senza prestare attenzione a nulla al di fuori di quella frase.

Tuttavia, l'inglese (anche la descrizione semplificata dell'inglese che ho dato sopra) è sensibile al contesto. "Aggettivo sostantivo" non è sempre un soggetto, potrebbe essere un NounPhrase in un PredicatePart. Dipende dal contesto. Espandiamo un po 'la nostra grammatica pseudo-inglese:

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

Puoi creare un "sostantivo aggettivo" in un ObjectNounPhrase solo dopo un VerbPhrase.

Fondamentalmente, se hai una produzione e puoi applicarla ogni volta che vuoi, indipendentemente da ciò che la circonda, è senza contesto.

Puoi sempre dire se una grammatica è facilmente libera dal contesto. Controlla se c'è più di un simbolo sul lato sinistro delle frecce.

Qualsiasi lingua potrebbe essere descritta da più di una grammatica. Se un po 'di grammatica per una lingua è senza contesto, la lingua è senza contesto. Per alcune lingue può essere dimostrato che non esiste una grammatica libera dal contesto. Suppongo che potrebbe esserci una grammatica senza contesto per il sottoinsieme pseudo-inglese semplificato che sto descrivendo sopra.

Per quanto riguarda il perché è importante, richiede un tipo più semplice di programma per analizzare una grammatica senza contesto. Come notato nelle altre risposte, non richiede la piena potenza di una macchina Turing per analizzare una grammatica senza contesto. Un parser LR (1) lookahead (che è una sorta di pushdown machine) per una particolare grammatica senza contesto può analizzare qualsiasi frase in quella grammatica in tempo e spazio lineari rispetto alla lunghezza della frase. Se la frase è nella lingua, il parser produrrà una struttura ad albero che identifica cosa significa ogni simbolo nella frase (o almeno quale parte gioca nella struttura). Se la frase non è nella grammatica, il parser noterà e si fermerà sul primo simbolo che è impossibile riconciliare con la grammatica e i simboli precedenti (sul primo "errore").

La cosa ancora migliore è che ci sono programmi a cui puoi dare una descrizione di una grammatica e un elenco di istruzioni su cosa fare con ogni parte (in un certo senso allegando un "significato" a ogni produzione) e il programma scriverà il parser per te. Il programma analizzerà la frase, troverà la struttura ed eseguirà le istruzioni su ciascuna parte della struttura. Questo tipo di programma è chiamato parser-generator o compilatore-compilatore.

Questo tipo di analisi del linguaggio è stato inventato per l'analisi automatica del linguaggio naturale (come l'inglese), ma risulta che questo è molto utile per l'analisi dei linguaggi informatici. Un designer linguistico può scrivere una grammatica che acquisisce la sua nuova lingua, quindi eseguirla attraverso il generatore di parser per ottenere un programma che analizza la sua lingua e, se lo desidera, traduce, interpreta, compila, esegue, ecc.

In effetti, nella maggior parte dei casi non puoi davvero farlo. Ad esempio, le parentesi bilanciate sono un linguaggio privo di contesto, ma una lingua in cui è necessario dichiarare tutte le variabili prima di utilizzarle è sensibile al contesto. Il parser fa parte del compilatore, ma per applicare questi altri requisiti è necessaria una logica aggiuntiva. Quello che devi fare è scrivere una grammatica che acquisisca la maggior parte della tua lingua possibile, eseguirla attraverso un generatore di parser, quindi scrivere un codice che imponga il resto dei requisiti (gestore della tabella dei simboli, ecc.).

Generalmente non usiamo grammatiche sensibili al contesto perché sono molto più scarsamente supportate. Non so se esiste un equivalente a un generatore di parser LR (k) per linguaggi sensibili al contesto. Sì, una macchina di Turing (o macchina a limite lineare) può analizzarne una, ma non so se esiste un algoritmo generale per trasformare una grammatica sensibile al contesto in un programma per una macchina di Turing, nel senso che un LR (1 ) Il generatore crea tabelle di analisi per una macchina pushdown. La mia ipotesi è che le tabelle che stanno alla base del parser sarebbero esponenzialmente più grandi. In ogni caso, agli studenti CS (come me, nel passato) di solito vengono insegnate grammatiche senza contesto e generatori di parser LR (1) come YACC.


-1

Le grammatiche senza contesto non considerano alcun contesto per le regole di produzione. I contesti sono terminali o non terminali.

Quindi: le grammatiche senza contesto hanno solo un singolo non terminale sul lato sinistro delle regole di produzione.


3
Cosa aggiunge questo alle risposte esistenti? Inoltre, una regola di produzione con due o più non terminali sul lato sinistro non è neanche contestuale.

Penso che le risposte fornite siano troppo lunghe. Se uno aggiungesse un TL; DR, eliminerei questo.
Martin Thoma,

Bello! Diresti che il "contesto" sono i caratteri extra che si qualificano quando ogni regola di produzione potrebbe essere applicata?
Rick
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.