Il C ++ è privo di contesto o sensibile al contesto?


405

Sento spesso affermazioni che il C ++ è un linguaggio sensibile al contesto. Prendi il seguente esempio:

a b(c);

È una definizione variabile o una dichiarazione di funzione? Dipende dal significato del simbolo c. If cè una variabile , quindi a b(c);definisce una variabile denominata bdi tipo a. Viene inizializzato direttamente con c. Ma se cè un tipo , quindi a b(c);dichiara una funzione denominata bche accetta un ce restituisce un a.

Se cerchi la definizione di linguaggi senza contesto, ti dirà sostanzialmente che tutte le regole grammaticali devono avere i lati di sinistra che consistono esattamente di un simbolo non terminale. Le grammatiche sensibili al contesto, d'altra parte, consentono stringhe arbitrarie di simboli terminali e non terminali sul lato sinistro.

Sfogliando l'Appendice A di "Il linguaggio di programmazione C ++", non sono riuscito a trovare una singola regola grammaticale che avesse nient'altro oltre a un singolo simbolo non terminale sul lato sinistro. Ciò implicherebbe che C ++ è privo di contesto. (Naturalmente, ogni lingua senza contesto è anche sensibile al contesto, nel senso che le lingue senza contesto formano un sottoinsieme delle lingue sensibili al contesto, ma non è questo il punto.)

Quindi, C ++ è privo di contesto o sensibile al contesto?


12
@CarlNorum Per favore, mostrami una singola regola grammaticale di C ++ che non consiste in un singolo simbolo non terminale sul lato sinistro e ti crederò immediatamente.
Fredoverflow,

9
IIUC dipende un po 'da dove si disegna la linea per la sensibilità al contesto. Penso di aver visto la gente sostenere che quasi tutti i linguaggi di programmazione tipicamente statici sono sensibili al contesto, non perché non è possibile creare un compilatore pratico per loro con strumenti di analisi CFG, ma perché tali implementazioni "ingannano" analizzando alcuni programmi non validi e rifiutandoli solo in seguito, durante il controllo del tipo. Quindi, se si considera che i programmi mal digitati non sono nella lingua (in senso CS, cioè un insieme di stringhe), il parser dovrebbe accettare, più lingue rispetto al C ++ sono sensibili al contesto.

6
@DeadMG: No, ti sbagli. Non c'è affatto "analisi" o "semantica" nella teoria formale del linguaggio, solo "linguaggio" che è un insieme di stringhe.
jpalecek,

27
Finora nessuna risposta ha effettivamente affrontato la tua definizione di "grammatica senza contesto". A mio avviso, la risposta corretta a questa domanda cita una produzione nell'appendice A che non si adatta alla tua definizione o dimostra che la tua definizione è errata o insufficiente. Sopportare la tua terra!
Corse di leggerezza in orbita

8
Vedi La grammatica di D è davvero senza contesto? . In effetti, penso che tutti qui dovrebbero leggere quella domanda e le sue risposte!
Corse di leggerezza in orbita

Risposte:


341

Di seguito è la mia (attuale) dimostrazione preferita del perché l'analisi del C ++ è (probabilmente) Turing completa , poiché mostra un programma sintatticamente corretto se e solo se un dato intero è primo.

Quindi asserisco che C ++ non è né privo di contesto né sensibile al contesto .

Se consenti sequenze di simboli arbitrarie su entrambi i lati di qualsiasi produzione, produci una grammatica di tipo 0 ("senza restrizioni") nella gerarchia di Chomsky , che è più potente di una grammatica sensibile al contesto; le grammatiche senza restrizioni sono complete di Turing. Una grammatica sensibile al contesto (Tipo 1) consente più simboli di contesto sul lato sinistro di una produzione, ma lo stesso contesto deve apparire sul lato destro della produzione (da cui il nome "sensibile al contesto"). [1] Le grammatiche sensibili al contesto sono equivalenti alle macchine di Turing con limite lineare .

Nel programma di esempio, il calcolo primo potrebbe essere eseguito da una macchina di Turing con limiti lineari, quindi non dimostra del tutto l'equivalenza di Turing, ma la parte importante è che il parser deve eseguire il calcolo per eseguire l'analisi sintattica. Potrebbe essere stato qualsiasi calcolo esprimibile come un'istanza del modello e ci sono tutte le ragioni per credere che l'istanza del modello C ++ sia Turing completa. Vedi, ad esempio, l'articolo di Todd L. Veldhuizen del 2003 .

Indipendentemente da ciò, C ++ può essere analizzato da un computer, quindi potrebbe sicuramente essere analizzato da una macchina di Turing. Di conseguenza, una grammatica senza restrizioni potrebbe riconoscerla. In realtà scrivere una tale grammatica sarebbe poco pratico, motivo per cui lo standard non prova a farlo. (Vedi sotto.)

Il problema con "ambiguità" di alcune espressioni è principalmente un'aringa rossa. Per cominciare, l'ambiguità è una caratteristica di una grammatica particolare, non una lingua. Anche se si può dimostrare che una lingua non ha grammatiche inequivocabili, se può essere riconosciuta da una grammatica senza contesto, è senza contesto. Allo stesso modo, se non può essere riconosciuto da una grammatica senza contesto ma può essere riconosciuto da una grammatica sensibile al contesto, è sensibile al contesto. L'ambiguità non è rilevante.

Ma in ogni caso, come nella riga 21 (cioè auto b = foo<IsPrime<234799>>::typen<1>();) nel programma in basso, le espressioni non sono affatto ambigue; vengono semplicemente analizzati in modo diverso a seconda del contesto. Nell'espressione più semplice del problema, la categoria sintattica di alcuni identificatori dipende da come sono stati dichiarati (tipi e funzioni, ad esempio), il che significa che il linguaggio formale dovrebbe riconoscere il fatto che due stringhe di lunghezza arbitraria in lo stesso programma è identico (dichiarazione e uso). Questo può essere modellato dalla grammatica "copia", che è la grammatica che riconosce due copie esatte consecutive della stessa parola. È facile dimostrarlo con il lemma del pompaggioche questa lingua non è senza contesto. Una grammatica sensibile al contesto per questa lingua è possibile e una grammatica di tipo 0 è fornita nella risposta a questa domanda: /math/163830/context-sensitive-grammar-for-the- copia-lingua .

Se si dovesse tentare di scrivere una grammatica sensibile al contesto (o senza restrizioni) per analizzare il C ++, molto probabilmente riempirebbe l'universo di scarabocchi. Scrivere una macchina di Turing per analizzare il C ++ sarebbe un'impresa altrettanto impossibile. Anche scrivere un programma C ++ è difficile e per quanto ne so nessuno è stato dimostrato corretto. Questo è il motivo per cui lo standard non tenta di fornire una grammatica formale completa e perché sceglie di scrivere alcune delle regole di analisi in inglese tecnico.

Ciò che sembra una grammatica formale nello standard C ++ non è la definizione formale completa della sintassi del linguaggio C ++. Non è nemmeno la definizione formale completa della lingua dopo la preelaborazione, che potrebbe essere più facile da formalizzare. (Questo non sarebbe il linguaggio, però: il linguaggio C ++ come definito dallo standard include il preprocessore, e il funzionamento del preprocessore è descritto in modo algoritmico poiché sarebbe estremamente difficile da descrivere in qualsiasi formalismo grammaticale. È in quella sezione dello standard in cui è descritta la decomposizione lessicale, comprese le regole in cui deve essere applicato più di una volta.)

Le varie grammatiche (due grammatiche sovrapposte per l'analisi lessicale, una che si svolge prima della preelaborazione e l'altra, se necessario, in seguito, più la grammatica "sintattica") sono raccolte nell'Appendice A, con questa nota importante (enfasi aggiunta):

Questo riassunto della sintassi C ++ è inteso come un aiuto alla comprensione. Non è un'affermazione esatta della lingua . In particolare, la grammatica qui descritta accetta un superset di costrutti C ++ validi . Le regole di chiarimento delle ambiguità (6.8, 7.1, 10.2) devono essere applicate per distinguere le espressioni dalle dichiarazioni. Inoltre, le regole di controllo dell'accesso, ambiguità e tipo devono essere utilizzate per eliminare costrutti sintatticamente validi ma privi di significato.

Infine, ecco il programma promesso. La riga 21 è sintatticamente corretta se e solo se N in IsPrime<N>è primo. Altrimenti, typenè un numero intero, non un modello, quindi typen<1>()viene analizzato come (typen<1)>()sintatticamente errato perché ()non è un'espressione sintatticamente valida.

template<bool V> struct answer { answer(int) {} bool operator()(){return V;}};

template<bool no, bool yes, int f, int p> struct IsPrimeHelper
  : IsPrimeHelper<p % f == 0, f * f >= p, f + 2, p> {};
template<bool yes, int f, int p> struct IsPrimeHelper<true, yes, f, p> { using type = answer<false>; };
template<int f, int p> struct IsPrimeHelper<false, true, f, p> { using type = answer<true>; };

template<int I> using IsPrime = typename IsPrimeHelper<!(I&1), false, 3, I>::type;
template<int I>
struct X { static const int i = I; int a[i]; }; 

template<typename A> struct foo;
template<>struct foo<answer<true>>{
  template<int I> using typen = X<I>;
};
template<> struct foo<answer<false>>{
  static const int typen = 0;
};

int main() {
  auto b = foo<IsPrime<234799>>::typen<1>(); // Syntax error if not prime
  return 0;
}

[1] Per dirla più tecnicamente, ogni produzione in una grammatica sensibile al contesto deve avere la forma:

αAβ → αγβ

dove Aè un non terminale e α, βpossibilmente , sono sequenze vuote di simboli grammaticali, ed γè una sequenza non vuota. (I simboli grammaticali possono essere terminali o non terminali).

Questo può essere letto come A → γsolo nel contesto [α, β]. In una grammatica senza contesto (Tipo 2) αe βdeve essere vuoto.

Si scopre che puoi anche limitare le grammatiche con la restrizione "monotona", dove ogni produzione deve essere nella forma:

α → βdove |α| ≥ |β| > 0  ( |α|significa "la lunghezza di α")

È possibile dimostrare che l'insieme delle lingue riconosciute dalle grammatiche monotone è esattamente lo stesso dell'insieme delle lingue riconosciute dalle grammatiche sensibili al contesto, ed è spesso il caso che sia più facile basare le prove sulle grammatiche monotone. Di conseguenza, è abbastanza comune vedere "sensibile al contesto" usato come se significasse "monotonico".


27
Quindi non solo è sensibile al contesto, ma può essere fatto dipendere da qualsiasi contesto che puoi esprimere nei modelli, che sono Turing-completi.
Cucciolo

7
@mehrdad, l'OP dice "linguaggio sensibile al contesto", non grammatica sensibile al contesto. L'ambiguità è una caratteristica di una grammatica, non una lingua. La lingua è davvero sensibile al contesto, ma non perché una grammatica particolare è ambigua.
rici,

2
Nota che il mio esempio non è ambiguo. È un'espressione inequivocabile di un programma valido. Se si modifica il valore nella riga 21, potrebbe non essere corretto. Ma in nessuno dei due casi è ambiguo.
rici,

5
Ho un dubbio: come dimostrate, il risultato della valutazione del modello può fare la differenza tra un programma ben formato e uno mal formato. La valutazione del modello è completa. Quindi determinare correttamente se una stringa è nel linguaggio (C ++) non richiederebbe completezza turing? Come dici tu, un linguaggio sensibile al contesto è "solo" un "automa lineare limitato", che non è AFAIK completo di turing. Oppure il tuo argomento si avvale dei limiti che lo standard C ++ pone su alcune cose, inclusa la profondità di valutazione dei template?

4
@AntonGolov: La mia versione originale di questo esempio ha fatto proprio questo (si può raggiungere mettendo 0dentro (), per un semplice), ma penso che sia più interessante in questo modo, perché dimostra che è necessario l'istanza modello anche di riconoscere se una stringa è un programma C ++ sintatticamente corretto. Se entrambi i rami vengono compilati, allora dovrei lavorare di più per contestare l'argomento secondo cui la differenza è "semantica". Curiosamente, anche se sono spesso sfidato a definire "sintattico", nessuno ha mai offerto una definizione di "semantico" oltre a "cose ​​che non penso siano sintattiche" :)
rici

115

Innanzitutto, hai giustamente osservato che non ci sono regole sensibili al contesto nella grammatica alla fine dello standard C ++, quindi la grammatica è senza contesto.

Tuttavia, quella grammatica non descrive esattamente il linguaggio C ++, perché produce programmi non C ++ come

int m() { m++; }

o

typedef static int int;

Il linguaggio C ++ definito come "l'insieme di programmi C ++ ben formati" non è privo di contesto (è possibile mostrare che le variabili meramente richieste da dichiarare lo rendono così). Dato che in teoria puoi scrivere programmi completi di Turing in template e creare un programma mal formato in base al loro risultato, non è nemmeno sensibile al contesto.

Ora, le persone (ignoranti) (di solito non teorici del linguaggio, ma progettisti di parser) usano in genere "non privo di contesto" in alcuni dei seguenti significati

  • ambiguo
  • non può essere analizzato con Bison
  • non LL (k), LR (k), LALR (k) o qualunque classe di linguaggio definita dal parser abbiano scelto

La grammatica sul retro dello standard non soddisfa queste categorie (cioè è ambigua, non LL (k) ...) quindi la grammatica C ++ non è "senza contesto" per loro. E in un certo senso, hanno ragione, è dannatamente difficile produrre un parser C ++ funzionante.

Si noti che le proprietà qui utilizzate sono solo debolmente connesse a linguaggi senza contesto - l'ambiguità non ha nulla a che fare con la sensibilità al contesto (in effetti, le regole sensibili al contesto in genere aiutano a chiarire le produzioni), le altre due sono semplicemente sottoinsiemi di contesto lingue libere. E l'analisi delle lingue senza contesto non è un processo lineare (anche se l'analisi delle lingue deterministiche lo è).


7
ambiguity doesn't have anything to do with context-sensitivityAnche questa era la mia intuizione, quindi sono felice di vedere qualcuno (a) essere d'accordo e (b) spiegarlo dove non ho potuto. Credo che squalifica tutti gli argomenti su cui si basano a b(c);e in parte soddisfano la domanda originale la cui premessa era affermazioni "spesso ascoltate" della sensibilità al contesto dovute all'ambiguità ... specialmente quando per la grammatica non c'è in realtà alcuna ambiguità anche nel MVP.
Corse di leggerezza in orbita

6
@KonradRudolph: Ciò che dice lo standard è "Esiste una quantità definita dall'implementazione che specifica il limite sulla profondità totale delle istanze ricorsive, che potrebbe coinvolgere più di un modello. Il risultato di una ricorsione infinita nell'istanza non è definito." (14.7.1p15) Interpreto che significhi che non è necessaria un'implementazione per comprendere ogni programma c ++ valido, non che i programmi con una profondità di ricorsione troppo grande non siano validi. Gli unici contrassegnati come non validi sono quelli con una profondità di ricorsione infinita.
rici,

3
@KonradRudolph: contendo che si tratti di "riferimento generale". Il fatto di aver letto l' articolo piuttosto complesso e di non comprenderlo sufficientemente per mettere in luce questo piccolo fatto dovrebbe essere sufficiente per dimostrarlo. Non è come se dicessi qualcosa del tipo "i computer usano comunemente l'elettricità" o "i bit possono essere veri o falsi".
Corse di leggerezza in orbita

3
Se questo fatto fosse davvero così noto, penso che sarebbe molto più facile trovare un riferimento ad esso piuttosto che discutere a lungo sull'opportunità o meno di fornire uno. Per non parlare di costruttivo.
Samuel Edwin Ward,

5
Per quanto ne so, @Konrad si è sbagliato quando ha detto "Il contesto sensibile è equivalente a Turing completo". (almeno, lo era se stesse indicando "Elenco ricorsivo" da "Turing completo"), e da allora non è stato in grado di riconoscere questo errore. Ecco un riferimento per la relazione di inclusione dell'insieme appropriato coinvolta qui: en.wikipedia.org/wiki/Chomsky_hierarchy
pnkfelix

61

Sì. L'espressione seguente ha un ordine delle operazioni diverso a seconda del tipo di contesto risolto :

Modifica: quando l'ordine effettivo dell'operazione varia, rende incredibilmente difficile utilizzare un compilatore "normale" che analizza un AST non decorato prima di decorarlo (informazioni sul tipo di propagazione). Altre cose sensibili al contesto menzionate sono "piuttosto facili" rispetto a questo (non che la valutazione del modello sia affatto facile).

#if FIRST_MEANING
   template<bool B>
   class foo
   { };
#else
   static const int foo = 0;
   static const int bar = 15;
#endif

Seguito da:

static int foobar( foo < 2 ? 1 < 1 : 0 > & bar );

Perché questo problema non può essere risolto come per C, ricordando quali definizioni di tipo rientrano nell'ambito di applicazione?
Blaisorblade,

1
@Blaisorblade: un modo per rendere "pulito" un compilatore è quello di separare le attività in passaggi indipendenti in una catena, come la creazione di un albero di analisi dall'input seguito da un passaggio che esegue l'analisi del tipo. Il C ++ ti obbliga a 1) unire questi passaggi in uno o 2) analizzare il documento in base a entrambe / tutte le possibili interpretazioni e consentendo alle fasi di risoluzione del tipo di restringerlo all'interpretazione corretta.
Sam Harwell,

@ 280Z28: d'accordo, ma è anche il caso di C; Penso che una buona risposta a questa domanda dovrebbe mostrare il motivo per cui C ++ è peggio di C. La tesi di dottorato collegato qui lo fa: stackoverflow.com/a/243447/53974
Blaisorblade

26

Per rispondere alla tua domanda, devi distinguere due domande diverse.

  1. La semplice sintassi di quasi tutti i linguaggi di programmazione è senza contesto. Tipicamente, è dato come una forma estesa di Backus-Naur o gramar senza contesto.

  2. Tuttavia, anche se un programma è conforme al programma senza contesto definito dal linguaggio di programmazione, non è necessariamente un programma valido . Esistono molte categorie senza contesto che un programma deve soddisfare per essere un programma valido. Ad esempio, la più semplice di tali proprietà è l'ambito delle variabili.

Per concludere, se il C ++ sia o meno libero dal contesto dipende dalla domanda che ci si pone.


5
È interessante notare che spesso è necessario posizionare il livello di "semplice sintassi" al di sotto di quanto ci si aspetterebbe, al fine di ottenere un CFG per il proprio linguaggio di programmazione. Prendi C, per esempio. Potresti pensare che sarebbe la regola grammaticale per una semplice dichiarazione di variabile in C VARDECL : TYPENAME IDENTIFIER, ma non puoi averlo, perché non puoi distinguere i nomi dei tipi da altri identificatori a livello CF. Un altro esempio: a livello di CF, non è possibile decidere se analizzare a*bcome una dichiarazione variabile ( bdi tipo puntatore a a) o come moltiplicazione.
LaC

2
@LaC: Sì, grazie per averlo segnalato! A proposito, sono sicuro che esiste un termine tecnico più comunemente usato per pura sintassi . Qualcuno è il termine corretto?
Dan

4
@Dan: di cosa stai parlando è un'approssimazione della lingua data da una grammatica senza contesto. Ovviamente tale approssimazione è per definizione priva di contesti. Questo è il senso in cui la "sintassi" viene spesso usata quando si discute di linguaggi di programmazione.
reinierpost,

13

Potresti dare un'occhiata a The Design & Evolution of C ++ , di Bjarne Stroustrup. In esso descrive i suoi problemi nel tentativo di usare yacc (o simile) per analizzare una versione precedente di C ++, e desiderando invece aver usato la discesa ricorsiva.


Wow grazie. Mi chiedo se abbia davvero senso pensare all'utilizzo di qualcosa di più potente di un CFG per analizzare qualsiasi linguaggio artificiale.
Dervin Thunk,

Ottimo libro per comprendere i perché del C ++. Lo consiglio e il modello a oggetti Inside the C ++ di Lippman per capire come funziona C ++. Sebbene entrambi siano un po 'datati, sono comunque una buona lettura.
Matt Price,

"Meta-S" è un motore di analisi sensibile al contesto di Quinn Tyler Jackson. Non l'ho usato, ma racconta una storia impressionante. Guarda i suoi commenti su comp.compilers e vedi rnaparse.com/MetaS%20defined.htm
Ira Baxter,

@IraBaxter: la tua x-ref è MIA oggi - e solidi riferimenti al software sembrano essere inafferrabili (la ricerca di Google non fornisce alcun buon vantaggio, né con 'site: rnaparse.com meta-s' o 'quinn jackson meta- s '; ci sono frammenti, ma meta-s.com conduce ad un sito non informativo, per esempio).
Jonathan Leffler,

@Jonathan: è stato un po ', ho appena notato la tua lamentela. Non so perché il link sia cattivo, ho pensato che fosse buono quando l'ho scritto. Quinn era piuttosto attivo in comp.compilers. Sembra che Google stia diventando traballante, questo è tutto ciò che riesco a trovare: groups.google.com/group/comp.compilers/browse_thread/thread/… IIRC, ha firmato i diritti di MetaS su alcuni outfit nelle Hawaii per la commercializzazione. Dato quanto tecnicamente era strano, IMHO sta firmando il suo mandato di morte. Sembrava uno schema molto intelligente.
Ira Baxter,

12

Sì, C ++ è sensibile al contesto, molto sensibile al contesto. Non è possibile creare l'albero della sintassi semplicemente analizzando il file utilizzando un parser privo di contesto perché in alcuni casi è necessario conoscere il simbolo dalle conoscenze precedenti per decidere (ad es. Creare una tabella dei simboli durante l'analisi).

Primo esempio:

A*B;

È un'espressione di moltiplicazione?

O

È una dichiarazione di Bvariabile un puntatore di tipo A?

Se A è una variabile, allora è un'espressione, se A è di tipo, è una dichiarazione del puntatore.

Secondo esempio:

A B(bar);

È un prototipo di funzione che accetta un argomento di bartipo?

O

Questa è una variabile Bdi tipo dichiarata Ae chiama il costruttore di A con barcostante come inizializzatore?

Devi sapere di nuovo se si bartratta di una variabile o di un tipo dalla tabella dei simboli.

Terzo esempio:

class Foo
{
public:
    void fn(){x*y;}
    int x, y;
};

Questo è il caso quando si costruisce una tabella dei simboli durante l'analisi non aiuta perché la dichiarazione di xey segue la definizione della funzione. Quindi devi prima scansionare la definizione della classe e guardare le definizioni del metodo in un secondo passaggio, per dire che x * y è un'espressione e non una dichiarazione del puntatore o altro.


1
A B();è una dichiarazione di funzione anche in una definizione di funzione. Cerca l'analisi più irritante ...
AProgrammer,

"Non è possibile creare l'albero della sintassi semplicemente analizzando il file" FALSE. Vedi la mia risposta
Ira Baxter,

10

Il C ++ viene analizzato con il parser GLR. Ciò significa che durante l'analisi del codice sorgente, il parser può incontrare ambiguità ma dovrebbe continuare e decidere quale regola grammaticale usare in seguito .

guarda anche

Perché C ++ non può essere analizzato con un parser LR (1)?


Ricorda che la grammatica senza contesto non può descrivere TUTTE le regole di una sintassi del linguaggio di programmazione. Ad esempio, la grammatica degli attributi viene utilizzata per verificare la validità di un tipo di espressione.

int x;
x = 9 + 1.0;

Non puoi descrivere la seguente regola con una grammatica senza contesto: il lato destro del compito dovrebbe essere dello stesso tipo del lato sinistro.


4
La maggior parte dei parser C ++ non utilizza la tecnologia di analisi GLR. GCC no. Alcuni lo fanno. Vedi semanticdesigns.com/Products/FrontEnds/CppFrontEnd.html per uno che lo fa.
Ira Baxter,

10

Ho la sensazione che ci sia un po 'di confusione tra la definizione formale di "sensibile al contesto" e l'uso informale di "sensibile al contesto". Il primo ha un significato ben definito. Quest'ultimo viene utilizzato per dire "è necessario un contesto per analizzare l'input".

Questo è anche chiesto qui: sensibilità al contesto vs ambiguità .

Ecco una grammatica senza contesto:

<a> ::= <b> | <c>
<b> ::= "x"
<c> ::= "x"

È ambiguo, quindi per analizzare l'input "x" è necessario un certo contesto (o vivere con l'ambiguità o emettere "Avvertenza: E8271 - L'input è ambiguo nella riga 115"). Ma non è certamente una grammatica sensibile al contesto.


In che modo avere più simboli sul lato sinistro di una produzione risolve questo problema? Non credo che questa risposta stia rispondendo alla domanda.
user541686

1
La mia risposta è in risposta alla prima frase: "Sento spesso affermazioni secondo cui il C ++ è un linguaggio sensibile al contesto". Se tali affermazioni utilizzano l'espressione "sensibile al contesto" in modo informale, non vi sono problemi. Non credo che il C ++ sia formalmente sensibile al contesto.
Omri Barel,

Penso che il C ++ sia formalmente sensibile al contesto, ma il problema che sto riscontrando è che non capisco come una grammatica sensibile al contesto avrebbe più successo nell'analisi del C ++ rispetto a un CFG.
user541686

6

Nessun linguaggio simile all'Algol è privo di contesto, perché hanno regole che limitano le espressioni e le dichiarazioni in cui gli identificatori possono apparire in base al loro tipo e perché non vi è alcun limite al numero di dichiarazioni che possono verificarsi tra dichiarazione e uso.

La solita soluzione è scrivere un parser senza contesto che accetti effettivamente un superset di programmi validi e inserisca le parti sensibili al contesto in un codice "semantico" ad hoc collegato alle regole.

Il C ++ va ben oltre, grazie al suo sistema di template completo di Turing. Vedi domanda di overflow dello stack 794015 .




5

È sensibile al contesto, come a b(c);ha due dichiarazioni di analisi valide e variabili. Quando dici "If cis a type", questo è il contesto, proprio lì, e hai descritto esattamente come C ++ è sensibile ad esso. Se non avessi quel contesto di "Cos'è c?" non puoi analizzarlo in modo inequivocabile.

Qui, il contesto è espresso nella scelta dei token: il parser legge un identificatore come token di nome file se nomina un tipo. Questa è la risoluzione più semplice ed evita gran parte della complessità di essere sensibili al contesto (in questo caso).

Modifica: ci sono, ovviamente, più problemi di sensibilità al contesto, mi sono semplicemente concentrato su quello che hai mostrato. I modelli sono particolarmente cattivi per questo.


1
Inoltre a<b<c>>d, giusto? (Il tuo esempio è in realtà un classico di C , dove è l' unico ostacolo all'essere privo di contesto.)
Kerrek SB

Questo è più un problema lexing, penso. Ma è certamente nella stessa categoria, sì.
Cucciolo

2
L'interrogante non chiede come sia più sensibile al contesto di C, ma solo per dimostrare che è sensibile al contesto.
Cucciolo

Quindi .. è C ++ più sensibile al contesto di C?
Kerrek SB,

2
@DeadMG Non penso che tu stia rispondendo alla domanda (non credo di esserlo neanche io). In che modo avere terminali sul lato sinistro di una produzione risolve questo problema?
user541686

5

Le produzioni nello standard C ++ sono scritte senza contesto, ma come sappiamo tutti non definiscono il linguaggio con precisione. Alcune di quelle che molte persone vedono come ambiguità nella lingua corrente potrebbero (credo) essere risolte in modo inequivocabile con una grammatica sensibile al contesto.

Per l'esempio più ovvio, prendiamo in considerazione il più fastidiosi Parse: int f(X);. Se Xè un valore, questo definisce funa variabile con cui verrà inizializzato X. Se Xè un tipo, definisce fcome una funzione che accetta un singolo parametro di tipo X.

Guardandolo da un punto di vista grammaticale, potremmo vederlo in questo modo:

A variable_decl ::= <type> <identifier> '(' initializer ')' ';'

B function_decl ::= <type> <identifier> '(' param_decl ')' ';'

A ::= [declaration of X as value]
B ::= [declaration of X as type]

Naturalmente, per essere del tutto corretti, avremmo bisogno di aggiungere alcune "cose" extra per tenere conto della possibilità di intervenire dichiarazioni di altri tipi (ad esempio, A e B dovrebbero essere entrambe davvero "dichiarazioni tra cui la dichiarazione di X come ..." o qualcosa in quell'ordine).

Questo è ancora piuttosto diverso da un tipico CSG (o almeno quello che ricordo di loro). Ciò dipende dalla costruzione di una tabella di simboli: la parte che riconosce specificamente Xcome tipo o valore, non solo un tipo di istruzione che precede questo, ma il tipo corretto di istruzione per il giusto simbolo / identificatore.

Come tale, dovrei fare un po 'cercando di esserne sicuro, ma la mia ipotesi immediata è che questo non si qualifichi davvero come un CSG, almeno perché il termine è normalmente usato.


Le produzioni (senza contesto) definiscono l'analisi più fastidiosa abbastanza bene da poter essere analizzata da un motore di analisi privo di contesto. Ciò ritarda il problema di decidere quale delle interpretazioni multiple è valida fino a quando l'analisi non è completa, ma ciò rende più semplice l'ingegnerizzazione del parser e del risolutore di nomi, poiché sono modulari anziché aggrovigliati come nei parser C ++ convenzionali. Vedi AST per l'analisi più irritante: stackoverflow.com/questions/17388771/…
Ira Baxter,

5

Il caso più semplice di grammatica senza contesti comporta l'analisi delle espressioni che coinvolgono modelli.

a<b<c>()

Questo può analizzare come uno dei due

template
   |
   a < expr > ()
        |
        <
      /   \
     b     c

O

 expr
   |
   <
 /   \
a   template
     |
     b < expr > ()
          |
          c

I due AST possono essere chiariti solo esaminando la dichiarazione di "a" - il primo AST se "a" è un modello o il secondo in caso contrario.


Credo che C ++ 11 imponga quest'ultima interpretazione e che si debbano aggiungere parentesi per optare per la prima.
Joseph Garvin,

1
@JosephGarvin, no. Mandati C ++ che <devono essere una parentesi, se possibile (ad esempio, segue un identificatore che nomina un modello). C ++ 11 ha aggiunto il requisito che >e il primo carattere di >>essere interpretato come parentesi quadre se tale uso è plausibile. Ciò influisce sull'analisi di a<b>c>dove aè un modello ma non ha alcun effetto a<b<c>.
rici,

@aaron: come è più semplice di a();(che è o expr.callo expr.type.conv)?
rici,

@rici: Oops, non mi ero reso conto che fosse asimmetrico.
Joseph Garvin,

5
Stai descrivendo l' ambiguità o la sensibilità del contesto?
corazza

4

I modelli C ++ hanno dimostrato di essere Turing Potente. Sebbene non sia un riferimento formale, ecco un punto in cui guardare a questo proposito:

http://cpptruths.blogspot.com/2005/11/c-templates-are-turing-complete.html

Intuirò un'ipotesi (vecchia quanto una dimostrazione CACM folkorica e concisa che dimostra che ALGOL negli anni '60 non poteva essere ripresentata da un CFG) e dire che il C ++ non può quindi essere correttamente analizzato solo da un CFG. CFG, in combinazione con vari meccanismi TP in un passaggio ad albero o durante eventi di riduzione - questa è un'altra storia. In senso generale, a causa del problema dell'arresto, esiste qualche programma C ++ che non può essere mostrato come corretto / errato ma è comunque corretto / errato.

{PS- Come l'autore di Meta-S (menzionato da molte persone sopra) - Posso sicuramente affermare che Thothic non è né defunto, né il software disponibile gratuitamente. Forse ho formulato questa versione della mia risposta in modo tale da non essere cancellato o votato fino a -3.}


3

C ++ non è privo di contesto. L'ho imparato qualche tempo fa nella lezione dei compilatori. Una rapida ricerca ha fornito questo link, in cui la sezione "Sintassi o semantica" spiega perché C e C ++ non sono liberi dal contesto:

Wikipedia Talk: grammatica senza contesto

Saluti,
Ovanes


2

Ovviamente, se si prende la domanda alla lettera, quasi tutte le lingue con identificatori sono sensibili al contesto.

È necessario sapere se un identificatore è un nome di tipo (un nome di classe, un nome introdotto da typedef, un parametro di modello typename), un nome di modello o un altro nome per essere in grado di utilizzare correttamente l'identificatore. Per esempio:

x = (name)(expression);

è un cast if nameè un nome di tipo e una funzione chiama ifname è un nome di funzione. Un altro caso è il cosiddetto "analisi più irritante" in cui non è possibile differenziare la definizione di variabile e la dichiarazione di funzione (esiste una regola che dice che è una dichiarazione di funzione).

Questa difficoltà ha introdotto la necessità typenamee templatecon nomi dipendenti. Il resto del C ++ non è sensibile al contesto per quanto ne so (cioè è possibile scrivere una grammatica libera dal contesto per questo).


2

Meta-S "è un motore di analisi sensibile al contesto di Quinn Tyler Jackson. Non l'ho usato, ma racconta una storia impressionante. Dai un'occhiata ai suoi commenti su comp.compilers e vedi rnaparse.com/MetaS%20defined.htm - Ira Baxter, 25 luglio alle 10:42

Il link corretto sta analizzando gli enigini

Meta-S era di proprietà di una compagnia defunta chiamata Thothic. Posso inviare una copia gratuita della Meta-S a chiunque sia interessato e l'ho usata per analizzare la ricerca. Si prega di notare che la "grammatica pseudocnotale" inclusa nelle cartelle degli esempi è stata scritta da un programmatore non bioinformatico, amature e sostanzialmente non funziona. Le mie grammatiche hanno un approccio diverso e funzionano abbastanza bene.


Questa è in realtà una scoperta interessante.
Dervin Thunk,

0

Un grosso problema qui è che i termini "senza contesto" e "sensibile al contesto" sono un po 'poco intuitivi all'interno dell'informatica. Per il C ++, la sensibilità al contesto assomiglia molto all'ambiguità, ma ciò non è necessariamente vero nel caso generale.

In C / ++, un'istruzione if è consentita solo all'interno di un corpo di funzione. Sembrerebbe renderlo sensibile al contesto, giusto? Beh no. Le grammatiche senza contesto non hanno effettivamente bisogno della proprietà in cui è possibile estrarre una riga di codice e determinare se è valida. Non è in realtà ciò che significa senza contesto. È davvero solo un'etichetta che implica vagamente qualcosa di simile a quello che sembra.

Ora, se un'istruzione all'interno di un corpo di funzione viene analizzata in modo diverso a seconda di qualcosa definito al di fuori degli antenati grammaticali immediati (ad esempio se un identificatore descrive un tipo o una variabile), come nel a * b;caso, allora è, in effetti, sensibile al contesto. Non c'è vera ambiguità qui; verrà analizzato come una dichiarazione di un puntatore se aè un tipo e una moltiplicazione altrimenti.

Essere sensibili al contesto non significa necessariamente "difficile da analizzare". C in realtà non è così difficile perché la famigerata a * b;"ambiguità" può essere risolta con una tabella di simboli contenentetypedef s incontrati in precedenza. Non richiede istanze arbitrarie di template (che hanno dimostrato di essere Turing Complete) per risolvere quel caso come fa C ++ in alcune occasioni. In realtà non è possibile scrivere un programma C che non si compili in un tempo limitato, anche se ha la stessa sensibilità al contesto di C ++.

Python (e altri linguaggi sensibili agli spazi bianchi) dipende anche dal contesto, in quanto richiede lo stato nel lexer per generare token di rientro e deduzione, ma ciò non rende più difficile l'analisi di una tipica grammatica LL-1. In realtà utilizza un generatore di parser, che è parte del motivo per cui Python ha messaggi di errore di sintassi così poco informativi. È anche importante notare qui che non esiste "ambiguità" come il a * b;problema in Python, fornendo un buon esempio concreto di un linguaggio sensibile al contesto senza grammatica "ambigua" (come menzionato nel primo paragrafo).


-4

Questa risposta dice che il C ++ non è privo di contesto ... c'è un'implicazione (non da parte del risponditore) che non può essere analizzato, e la risposta offre un esempio di codice difficile che produce un programma C ++ non valido se una certa costante non è un numero primo.

Come altri hanno osservato, la domanda se la lingua è sensibile al contesto / libera è diversa dalla stessa domanda su una grammatica specifica.

Per porre a riposo la domanda sulla parseability, offro prove empiriche che ci sono grammatiche senza contesto per C ++, che possono essere utilizzate per produrre un AST per un'analisi senza contesto del testo di origine analizzandolo con un GLR esistente strumento basato su parser guidato da una grammatica esplicita.

Sì, ci riesce "accettando troppo"; non tutto ciò che accetta è un programma C ++ valido, motivo per cui è seguito da ulteriori controlli (controlli del tipo). E sì, il controllo del tipo potrebbe incorrere in problemi di calcolabilità. In pratica gli strumenti non hanno questo problema; se le persone scrivessero programmi del genere, nessuno di loro compilerebbe. (Penso che lo standard in realtà ponga un limite alla quantità di calcolo che puoi fare spiegando un modello, quindi in realtà il calcolo è in realtà finito ma probabilmente piuttosto grande).

Se ciò che vuoi dire è, determinare se il programma di origine è un membro dell'insieme di programmi di origine C ++ validi , quindi concordo sul fatto che il problema è molto più difficile. Ma non è l' analisi che è il problema.

Lo strumento risolve questo problema isolando l'analisi dal controllo del tipo del programma analizzato. (In presenza di più interpretazioni in assenza di contesto, registra un nodo di ambiguità nella struttura di analisi con diverse analisi possibili; la verifica del tipo decide quale è corretta ed elimina i sottotitoli non validi). Puoi vedere un albero di analisi (parziale) nell'esempio seguente; l'intero albero è troppo grande per adattarsi a una risposta SO. Si noti che viene visualizzato un albero di analisi se viene utilizzato il valore 234797 o 234799.

L'esecuzione del risolutore nome / tipo dello strumento sull'AST con il valore originale 234799 ha esito positivo. Con il valore 234797 il risolutore di nomi ha esito negativo (come previsto) con il messaggio di errore "typen non è un tipo". e quindi quella versione non è un programma C ++ valido.

967 tree nodes in tree.
15 ambiguity nodes in tree.
(translation_unit@Cpp~GCC5=2#6b11a20^0 Line 1 Column 1 File C:/temp/prime_with_templates.cpp
 (declaration_seq@Cpp~GCC5=1021#6b06640^1#6b11a20:1 {10} Line 1 Column 1 File C:/temp/prime_with_templates.cpp
  (pp_declaration_seq@Cpp~GCC5=1022#6b049a0^1#6b06640:1 Line 1 Column 1 File C:/temp/prime_with_templates.cpp
   (declaration@Cpp~GCC5=1036#6b04980^1#6b049a0:1 Line 1 Column 1 File C:/temp/prime_with_templates.cpp
   |(template_declaration@Cpp~GCC5=2079#6b04960^1#6b04980:1 Line 1 Column 1 File C:/temp/prime_with_templates.cpp
   | (template_parameter_list@Cpp~GCC5=2082#6afbde0^1#6b04960:1 Line 1 Column 10 File C:/temp/prime_with_templates.cpp
   |  (template_parameter@Cpp~GCC5=2085#6afbd80^1#6afbde0:1 Line 1 Column 10 File C:/temp/prime_with_templates.cpp
   |   (parameter_declaration@Cpp~GCC5=1611#6afbd40^1#6afbd80:1 Line 1 Column 10 File C:/temp/prime_with_templates.cpp
   |   |(basic_decl_specifier_seq@Cpp~GCC5=1070#6afb880^1#6afbd40:1 Line 1 Column 10 File C:/temp/prime_with_templates.cpp
   |   | (decl_specifier@Cpp~GCC5=1073#6afb840^1#6afb880:1 Line 1 Column 10 File C:/temp/prime_with_templates.cpp
   |   |  (trailing_type_specifier@Cpp~GCC5=1118#6afb7e0^1#6afb840:1 Line 1 Column 10 File C:/temp/prime_with_templates.cpp
   |   |   (simple_type_specifier@Cpp~GCC5=1138#6afb7a0^1#6afb7e0:1 Line 1 Column 10 File C:/temp/prime_with_templates.cpp)simple_type_specifier
   |   |  )trailing_type_specifier#6afb7e0
   |   | )decl_specifier#6afb840
   |   |)basic_decl_specifier_seq#6afb880
   |   |(ptr_declarator@Cpp~GCC5=1417#6afbc40^1#6afbd40:2 Line 1 Column 15 File C:/temp/prime_with_templates.cpp
   |   | (noptr_declarator@Cpp~GCC5=1421#6afbba0^1#6afbc40:1 Line 1 Column 15 File C:/temp/prime_with_templates.cpp
   |   |  (declarator_id@Cpp~GCC5=1487#6afbb80^1#6afbba0:1 Line 1 Column 15 File C:/temp/prime_with_templates.cpp
   |   |   (id_expression@Cpp~GCC5=317#6afbaa0^1#6afbb80:1 Line 1 Column 15 File C:/temp/prime_with_templates.cpp
   |   |   |(unqualified_id@Cpp~GCC5=319#6afb9c0^1#6afbaa0:1 Line 1 Column 15 File C:/temp/prime_with_templates.cpp
   |   |   | (IDENTIFIER@Cpp~GCC5=3368#6afb780^1#6afb9c0:1[`V'] Line 1 Column 15 File C:/temp/prime_with_templates.cpp)IDENTIFIER
   |   |   |)unqualified_id#6afb9c0
   |   |   )id_expression#6afbaa0
   |   |  )declarator_id#6afbb80
   |   | )noptr_declarator#6afbba0
   |   |)ptr_declarator#6afbc40
   |   )parameter_declaration#6afbd40
   |  )template_parameter#6afbd80
   | )template_parameter_list#6afbde0
   | (declaration@Cpp~GCC5=1033#6b04940^1#6b04960:2 Line 1 Column 18 File C:/temp/prime_with_templates.cpp
   |  (block_declaration@Cpp~GCC5=1050#6b04920^1#6b04940:1 Line 1 Column 18 File C:/temp/prime_with_templates.cpp
   |   (simple_declaration@Cpp~GCC5=1060#6b04900^1#6b04920:1 Line 1 Column 18 File C:/temp/prime_with_templates.cpp
   |   |(basic_decl_specifier_seq@Cpp~GCC5=1070#6b048e0^1#6b04900:1 Line 1 Column 18 File C:/temp/prime_with_templates.cpp
   |   | (decl_specifier@Cpp~GCC5=1073#6b048c0^1#6b048e0:1 Line 1 Column 18 File C:/temp/prime_with_templates.cpp
   |   |  (type_specifier@Cpp~GCC5=1110#6b048a0^1#6b048c0:1 Line 1 Column 18 File C:/temp/prime_with_templates.cpp
   |   |   (class_specifier@Cpp~GCC5=1761#6b04880^1#6b048a0:1 Line 1 Column 18 File C:/temp/prime_with_templates.cpp
   |   |   |(class_head@Cpp~GCC5=1763#6afb980^1#6b04880:1 Line 1 Column 18 File C:/temp/prime_with_templates.cpp
   |   |   | (class_key@Cpp~GCC5=1791#6afbca0^1#6afb980:1 Line 1 Column 18 File C:/temp/prime_with_templates.cpp)class_key
   |   |   | (IDENTIFIER@Cpp~GCC5=3368#6afbcc0^1#6afb980:2[`answer'] Line 1 Column 25 File C:/temp/prime_with_templates.cpp)IDENTIFIER
   |   |   | (optional_base_clause@Cpp~GCC5=1872#6afba60^1#6afb980:3 Line 1 Column 32 File C:/temp/prime_with_templates.cpp)optional_base_clause
   |   |   |)class_head#6afb980
   |   |   |(member_specification@Cpp~GCC5=1794#6b042e0^1#6b04880:2 {2} Line 1 Column 34 File C:/temp/prime_with_templates.cpp
   |   |   | (member_declaration_or_access_specifier@Cpp~GCC5=1806#6b04060^1#6b042e0:1 Line 1 Column 34 File C:/temp/prime_with_templates.cpp
   |   |   |  (member_declaration@Cpp~GCC5=1822#6b04040^1#6b04060:1 Line 1 Column 34 File C:/temp/prime_with_templates.cpp
   |   |   |   (function_definition@Cpp~GCC5=1632#6b04020^1#6b04040:1 Line 1 Column 34 File C:/temp/prime_with_templates.cpp
   |   |   |   |(function_head@Cpp~GCC5=1673#6afbec0^1#6b04020:1 Line 1 Column 34 File C:/temp/prime_with_templates.cpp
   |   |   |   | (ptr_declarator@Cpp~GCC5=1417#6afbfe0^1#6afbec0:1 Line 1 Column 34 File C:/temp/prime_with_templates.cpp
   |   |   |   |  (noptr_declarator@Cpp~GCC5=1422#6afbf80^1#6afbfe0:1 Line 1 Column 34 File C:/temp/prime_with_templates.cpp
   |   |   |   |   (noptr_declarator@Cpp~GCC5=1421#6afbf60^1#6afbf80:1 Line 1 Column 34 File C:/temp/prime_with_templates.cpp
   |   |   |   |   |(declarator_id@Cpp~GCC5=1487#6afbea0^1#6afbf60:1 Line 1 Column 34 File C:/temp/prime_with_templates.cpp
   |   |   |   |   | (id_expression@Cpp~GCC5=317#6afbb40^1#6afbea0:1 Line 1 Column 34 File C:/temp/prime_with_templates.cpp
   |   |   |   |   |  (unqualified_id@Cpp~GCC5=319#6afbc80^1#6afbb40:1 Line 1 Column 34 File C:/temp/prime_with_templates.cpp
   |   |   |   |   |   (IDENTIFIER@Cpp~GCC5=3368#6afbc20^1#6afbc80:1[`answer'] Line 1 Column 34 File C:/temp/prime_with_templates.cpp)IDENTIFIER
   |   |   |   |   |  )unqualified_id#6afbc80
   |   |   |   |   | )id_expression#6afbb40
   |   |   |   |   |)declarator_id#6afbea0
   |   |   |   |   )noptr_declarator#6afbf60
   |   |   |   |   (parameter_declaration_clause@Cpp~GCC5=1559#6afbd00^1#6afbf80:2 Line 1 Column 41 File C:/temp/prime_with_templates.cpp
   |   |   |   |   |(pp_parameter_declaration_list@Cpp~GCC5=1570#6afb940^1#6afbd00:1 Line 1 Column 41 File C:/temp/prime_with_templates.cpp
   |   |   |   |   | (pp_parameter_declaration_seq@Cpp~GCC5=1574#6afb800^1#6afb940:1 Line 1 Column 41 File C:/temp/prime_with_templates.cpp
   |   |   |   |   |  (parameter_declaration@Cpp~GCC5=1610#6afb9a0^1#6afb800:1 Line 1 Column 41 File C:/temp/prime_with_templates.cpp
   |   |   |   |   |   (basic_decl_specifier_seq@Cpp~GCC5=1070#6afbf40^1#6afb9a0:1 Line 1 Column 41 File C:/temp/prime_with_templates.cpp
   |   |   |   |   |   |(decl_specifier@Cpp~GCC5=1073#6afbfa0^1#6afbf40:1 Line 1 Column 41 File C:/temp/prime_with_templates.cpp
   |   |   |   |   |   | (trailing_type_specifier@Cpp~GCC5=1118#6afbfc0^1#6afbfa0:1 Line 1 Column 41 File C:/temp/prime_with_templates.cpp
   |   |   |   |   |   |  (simple_type_specifier@Cpp~GCC5=1140#6afb860^1#6afbfc0:1 Line 1 Column 41 File C:/temp/prime_with_templates.cpp)simple_type_specifier
   |   |   |   |   |   | )trailing_type_specifier#6afbfc0
   |   |   |   |   |   |)decl_specifier#6afbfa0
   |   |   |   |   |   )basic_decl_specifier_seq#6afbf40
   |   |   |   |   |  )parameter_declaration#6afb9a0
   |   |   |   |   | )pp_parameter_declaration_seq#6afb800
   |   |   |   |   |)pp_parameter_declaration_list#6afb940
   |   |   |   |   )parameter_declaration_clause#6afbd00
   |   |   |   |   (function_qualifiers@Cpp~GCC5=1438#6afbce0^1#6afbf80:3 Line 1 Column 46 File C:/temp/prime_with_templates.cpp)function_qualifiers
   |   |   |   |  )noptr_declarator#6afbf80
   |   |   |   | )ptr_declarator#6afbfe0
   |   |   |   |)function_head#6afbec0
   |   |   |   |(function_body@Cpp~GCC5=1680#6b04000^1#6b04020:2 Line 1 Column 46 File C:/temp/prime_with_templates.cpp
   |   |   |   | (compound_statement@Cpp~GCC5=888#6afbee0^1#6b04000:1 Line 1 Column 46 File C:/temp/prime_with_templates.cpp)compound_statement
   |   |   |   |)function_body#6b04000
   |   |   |   )function_definition#6b04020
   |   |   |  )member_declaration#6b04040
   |   |   | )member_declaration_or_access_specifier#6b04060
   |   |   | (member_declaration_or_access_specifier@Cpp~GCC5=1806#6b042c0^1#6b042e0:2 Line 1 Column 49 File C:/temp/prime_with_templates.cpp
   |   |   |  (member_declaration@Cpp~GCC5=1822#6b04820^1#6b042c0:1 Line 1 Column 49 File C:/temp/prime_with_templates.cpp
   |   |   |   (function_definition@Cpp~GCC5=1632#6b04280^1#6b04820:1 Line 1 Column 49 File C:/temp/prime_with_templates.cpp
   |   |   |   |(function_head@Cpp~GCC5=1674#6b04220^1#6b04280:1 Line 1 Column 49 File C:/temp/prime_with_templates.cpp
   |   |   |   | (basic_decl_specifier_seq@Cpp~GCC5=1070#6b040e0^1#6b04220:1 Line 1 Column 49 File C:/temp/prime_with_templates.cpp
   |   |   |   |  (decl_specifier@Cpp~GCC5=1073#6b040c0^1#6b040e0:1 Line 1 Column 49 File C:/temp/prime_with_templates.cpp
   |   |   |   |   (trailing_type_specifier@Cpp~GCC5=1118#6b040a0^1#6b040c0:1 Line 1 Column 49 File C:/temp/prime_with_templates.cpp
   |   |   |   |   |(simple_type_specifier@Cpp~GCC5=1138#6b04080^1#6b040a0:1 Line 1 Column 49 File C:/temp/prime_with_templates.cpp)simple_type_specifier
   |   |   |   |   )trailing_type_specifier#6b040a0
   |   |   |   |  )decl_specifier#6b040c0
   |   |   |   | )basic_decl_specifier_seq#6b040e0
   |   |   |   | (ptr_declarator@Cpp~GCC5=1417#6b04200^1#6b04220:2 Line 1 Column 54 File C:/temp/prime_with_templates.cpp
   |   |   |   |  (noptr_declarator@Cpp~GCC5=1422#6b041e0^1#6b04200:1 Line 1 Column 54 File C:/temp/prime_with_templates.cpp
   |   |   |   |   (noptr_declarator@Cpp~GCC5=1421#6b041a0^1#6b041e0:1 Line 1 Column 54 File C:/temp/prime_with_templates.cpp
   |   |   |   |   |(declarator_id@Cpp~GCC5=1487#6b04180^1#6b041a0:1 Line 1 Column 54 File C:/temp/prime_with_templates.cpp
   |   |   |   |   | (id_expression@Cpp~GCC5=317#6b04160^1#6b04180:1 Line 1 Column 54 File C:/temp/prime_with_templates.cpp
   |   |   |   |   |  (unqualified_id@Cpp~GCC5=320#6b04140^1#6b04160:1 Line 1 Column 54 File C:/temp/prime_with_templates.cpp
   |   |   |   |   |   (operator_function_id@Cpp~GCC5=2027#6b04120^1#6b04140:1 Line 1 Column 54 File C:/temp/prime_with_templates.cpp
   |   |   |   |   |   |(operator@Cpp~GCC5=2070#6b04100^1#6b04120:1 Line 1 Column 62 File C:/temp/prime_with_templates.cpp)operator
   |   |   |   |   |   )operator_function_id#6b04120
   |   |   |   |   |  )unqualified_id#6b04140
   |   |   |   |   | )id_expression#6b04160
   |   |   |   |   |)declarator_id#6b04180
   |   |   |   |   )noptr_declarator#6b041a0
   |   |   |   |   (parameter_declaration_clause@Cpp~GCC5=1558#6afba40^1#6b041e0:2 Line 1 Column 65 File C:/temp/prime_with_templates.cpp)parameter_declaration_clause
   |   |   |   |   (function_qualifiers@Cpp~GCC5=1438#6b041c0^1#6b041e0:3 Line 1 Column 66 File C:/temp/prime_with_templates.cpp)function_qualifiers
   |   |   |   |  )noptr_declarator#6b041e0
   |   |   |   | )ptr_declarator#6b04200
   |   |   |   |)function_head#6b04220
   |   |   |   |(function_body@Cpp~GCC5=1680#6b04300^1#6b04280:2 Line 1 Column 66 File C:/temp/prime_with_templates.cpp
   |   |   |   | (compound_statement@Cpp~GCC5=889#6b04760^1#6b04300:1 Line 1 Column 66 File C:/temp/prime_with_templates.cpp
   |   |   |   |  (pp_statement_seq@Cpp~GCC5=894#6b04780^1#6b04760:1 Line 1 Column 67 File C:/temp/prime_with_templates.cpp
   |   |   |   |   (statement@Cpp~GCC5=857#6b04440^1#6b04780:1 Line 1 Column 67 File C:/temp/prime_with_templates.cpp
   |   |   |   |   |(jump_statement@Cpp~GCC5=1011#6afba80^1#6b04440:1 Line 1 Column 67 File C:/temp/prime_with_templates.cpp
   |   |   |   |   | (pm_expression@Cpp~GCC5=551#6b04380^1#6afba80:1 Line 1 Column 74 File C:/temp/prime_with_templates.cpp
   |   |   |   |   |  (cast_expression@Cpp~GCC5=543#6b04360^1#6b04380:1 Line 1 Column 74 File C:/temp/prime_with_templates.cpp
   |   |   |   |   |   (unary_expression@Cpp~GCC5=465#6b04340^1#6b04360:1 Line 1 Column 74 File C:/temp/prime_with_templates.cpp
   |   |   |   |   |   |(primary_expression@Cpp~GCC5=307#6b04320^1#6b04340:1 Line 1 Column 74 File C:/temp/prime_with_templates.cpp
   |   |   |   |   |   | (id_expression@Cpp~GCC5=317#6b042a0^1#6b04320:1 Line 1 Column 74 File C:/temp/prime_with_templates.cpp
   |   |   |   |   |   |  (unqualified_id@Cpp~GCC5=319#6b04260^1#6b042a0:1 Line 1 Column 74 File C:/temp/prime_with_templates.cpp
   |   |   |   |   |   |   (IDENTIFIER@Cpp~GCC5=3368#6b04240^1#6b04260:1[`V'] Line 1 Column 74 File C:/temp/prime_with_templates.cpp)IDENTIFIER
   |   |   |   |   |   |  )unqualified_id#6b04260
   |   |   |   |   |   | )id_expression#6b042a0
   |   |   |   |   |   |)primary_expression#6b04320
   |   |   |   |   |   )unary_expression#6b04340
   |   |   |   |   |  )cast_expression#6b04360
   |   |   |   |   | )pm_expression#6b04380
   |   |   |   |   |)jump_statement#6afba80
   |   |   |   |   )statement#6b04440
   |   |   |   |  )pp_statement_seq#6b04780
   |   |   |   | )compound_statement#6b04760
   |   |   |   |)function_body#6b04300
   |   |   |   )function_definition#6b04280
   |   |   |  )member_declaration#6b04820
   |   |   | )member_declaration_or_access_specifier#6b042c0
   |   |   |)member_specification#6b042e0
   |   |   )class_specifier#6b04880
   |   |  )type_specifier#6b048a0
   |   | )decl_specifier#6b048c0
   |   |)basic_decl_specifier_seq#6b048e0
   |   )simple_declaration#6b04900
   |  )block_declaration#6b04920
   | )declaration#6b04940
   |)template_declaration#6b04960
   )declaration#6b04980
  )pp_declaration_seq#6b049a0
  (pp_declaration_seq@Cpp~GCC5=1022#6b06620^1#6b06640:2 Line 3 Column 1 File C:/temp/prime_with_templates.cpp
   (declaration@Cpp~GCC5=1036#6b06600^1#6b06620:1 Line 3 Column 1 File C:/temp/prime_with_templates.cpp
   |(template_declaration@Cpp~GCC5=2079#6b065e0^1#6b06600:1 Line 3 Column 1 File C:/temp/prime_with_templates.cpp
   | (template_parameter_list@Cpp~GCC5=2083#6b05460^1#6b065e0:1 Line 3 Column 10 File C:/temp/prime_with_templates.cpp
   |  (template_parameter_list@Cpp~GCC5=2083#6b05140^1#6b05460:1 Line 3 Column 10 File C:/temp/prime_with_templates.cpp
   |   (template_parameter_list@Cpp~GCC5=2083#6b04ee0^1#6b05140:1 Line 3 Column 10 File C:/temp/prime_with_templates.cpp
   |   |(template_parameter_list@Cpp~GCC5=2082#6b04cc0^1#6b04ee0:1 Line 3 Column 10 File C:/temp/prime_with_templates.cpp
   |   | (template_parameter@Cpp~GCC5=2085#6b04ca0^1#6b04cc0:1 Line 3 Column 10 File C:/temp/prime_with_templates.cpp
   |   |  (parameter_declaration@Cpp~GCC5=1611#6b04c80^1#6b04ca0:1 Line 3 Column 10 File C:/temp/prime_with_templates.cpp
   |   |   (basic_decl_specifier_seq@Cpp~GCC5=1070#6b04a40^1#6b04c80:1 Line 3 Column 10 File C:/temp/prime_with_templates.cpp
   |   |   |(decl_specifier@Cpp~GCC5=1073#6b04a20^1#6b04a40:1 Line 3 Column 10 File C:/temp/prime_with_templates.cpp
   |   |   | (trailing_type_specifier@Cpp~GCC5=1118#6b04a00^1#6b04a20:1 Line 3 Column 10 File C:/temp/prime_with_templates.cpp
   |   |   |  (simple_type_specifier@Cpp~GCC5=1138#6b049e0^1#6b04a00:1 Line 3 Column 10 File C:/temp/prime_with_templates.cpp)simple_type_specifier
   |   |   | )trailing_type_specifier#6b04a00
   |   |   |)decl_specifier#6b04a20
   |   |   )basic_decl_specifier_seq#6b04a40
   |   |   (ptr_declarator@Cpp~GCC5=1417#6b04c40^1#6b04c80:2 Line 3 Column 15 File C:/temp/prime_with_templates.cpp
   |   |   |(noptr_declarator@Cpp~GCC5=1421#6b04be0^1#6b04c40:1 Line 3 Column 15 File C:/temp/prime_with_templates.cpp
   |   |   | (declarator_id@Cpp~GCC5=1487#6b04bc0^1#6b04be0:1 Line 3 Column 15 File C:/temp/prime_with_templates.cpp
   |   |   |  (id_expression@Cpp~GCC5=317#6b04b60^1#6b04bc0:1 Line 3 Column 15 File C:/temp/prime_with_templates.cpp
   |   |   |   (unqualified_id@Cpp~GCC5=319#6b04ac0^1#6b04b60:1 Line 3 Column 15 File C:/temp/prime_with_templates.cpp
   |   |   |   |(IDENTIFIER@Cpp~GCC5=3368#6b049c0^1#6b04ac0:1[`no'] Line 3 Column 15 File C:/temp/prime_with_templates.cpp)IDENTIFIER
   |   |   |   )unqualified_id#6b04ac0
   |   |   |  )id_expression#6b04b60
   |   |   | )declarator_id#6b04bc0
   |   |   |)noptr_declarator#6b04be0
   |   |   )ptr_declarator#6b04c40
   |   |  )parameter_declaration#6b04c80
   |   | )template_parameter#6b04ca0
   |   |)template_parameter_list#6b04cc0
   |   |(template_parameter@Cpp~GCC5=2085#6b04ec0^1#6b04ee0:2 Line 3 Column 19 File C:/temp/prime_with_templates.cpp
   |   | (parameter_declaration@Cpp~GCC5=1611#6b04ea0^1#6b04ec0:1 Line 3 Column 19 File C:/temp/prime_with_templates.cpp
   |   |  (basic_decl_specifier_seq@Cpp~GCC5=1070#6b04b40^1#6b04ea0:1 Line 3 Column 19 File C:/temp/prime_with_templates.cpp
   |   |   (decl_specifier@Cpp~GCC5=1073#6b04ba0^1#6b04b40:1 Line 3 Column 19 File C:/temp/prime_with_templates.cpp
   |   |   |(trailing_type_specifier@Cpp~GCC5=1118#6b04c60^1#6b04ba0:1 Line 3 Column 19 File C:/temp/prime_with_templates.cpp
   |   |   | (simple_type_specifier@Cpp~GCC5=1138#6b04580^1#6b04c60:1 Line 3 Column 19 File C:/temp/prime_with_templates.cpp)simple_type_specifier
   |   |   |)trailing_type_specifier#6b04c60
   |   |   )decl_specifier#6b04ba0
   |   |  )basic_decl_specifier_seq#6b04b40
   |   |  (ptr_declarator@Cpp~GCC5=1417#6b04e60^1#6b04ea0:2 Line 3 Column 24 File C:/temp/prime_with_templates.cpp
   |   |   (noptr_declarator@Cpp~GCC5=1421#6b04e40^1#6b04e60:1 Line 3 Column 24 File C:/temp/prime_with_templates.cpp
   |   |   |(declarator_id@Cpp~GCC5=1487#6b04de0^1#6b04e40:1 Line 3 Column 24 File C:/temp/prime_with_templates.cpp
   |   |   | (id_expression@Cpp~GCC5=317#6b04d80^1#6b04de0:1 Line 3 Column 24 File C:/temp/prime_with_templates.cpp
   |   |   |  (unqualified_id@Cpp~GCC5=319#6b04ce0^1#6b04d80:1 Line 3 Column 24 File C:/temp/prime_with_templates.cpp
   |   |   |   (IDENTIFIER@Cpp~GCC5=3368#6b04560^1#6b04ce0:1[`yes'] Line 3 Column 24 File C:/temp/prime_with_templates.cpp)IDENTIFIER
   |   |   |  )unqualified_id#6b04ce0
   |   |   | )id_expression#6b04d80
   |   |   |)declarator_id#6b04de0
   |   |   )noptr_declarator#6b04e40
   |   |  )ptr_declarator#6b04e60
   |   | )parameter_declaration#6b04ea0
   |   |)template_parameter#6b04ec0
   |   )template_parameter_list#6b04ee0
   |   (template_parameter@Cpp~GCC5=2085#6b05120^1#6b05140:2 Line 3 Column 29 File C:/temp/prime_with_templates.cpp
   |   |(parameter_declaration@Cpp~GCC5=1611#6b05100^1#6b05120:1 Line 3 Column 29 File C:/temp/prime_with_templates.cpp
   |   | (basic_decl_specifier_seq@Cpp~GCC5=1070#6b04d20^1#6b05100:1 Line 3 Column 29 File C:/temp/prime_with_templates.cpp
   |   |  (decl_specifier@Cpp~GCC5=1073#6b04dc0^1#6b04d20:1 Line 3 Column 29 File C:/temp/prime_with_templates.cpp
   |   |   (trailing_type_specifier@Cpp~GCC5=1118#6b04e80^1#6b04dc0:1 Line 3 Column 29 File C:/temp/prime_with_templates.cpp
   |   |   |(simple_type_specifier@Cpp~GCC5=1140#6b046e0^1#6b04e80:1 Line 3 Column 29 File C:/temp/prime_with_templates.cpp)simple_type_specifier
   |   |   )trailing_type_specifier#6b04e80
   |   |  )decl_specifier#6b04dc0
   |   | )basic_decl_specifier_seq#6b04d20
   |   | (ptr_declarator@Cpp~GCC5=1417#6b05080^1#6b05100:2 Line 3 Column 33 File C:/temp/prime_with_templates.cpp
   |   |  (noptr_declarator@Cpp~GCC5=1421#6b05020^1#6b05080:1 Line 3 Column 33 File C:/temp/prime_with_templates.cpp
   |   |   (declarator_id@Cpp~GCC5=1487#6b05000^1#6b05020:1 Line 3 Column 33 File C:/temp/prime_with_templates.cpp
   |   |   |(id_expression@Cpp~GCC5=317#6b04fa0^1#6b05000:1 Line 3 Column 33 File C:/temp/prime_with_templates.cpp
   |   |   | (unqualified_id@Cpp~GCC5=319#6b04f00^1#6b04fa0:1 Line 3 Column 33 File C:/temp/prime_with_templates.cpp
   |   |   |  (IDENTIFIER@Cpp~GCC5=3368#6b046c0^1#6b04f00:1[`f'] Line 3 Column 33 File C:/temp/prime_with_templates.cpp)IDENTIFIER
   |   |   | )unqualified_id#6b04f00
   |   |   |)id_expression#6b04fa0
   |   |   )declarator_id#6b05000
   |   |  )noptr_declarator#6b05020
   |   | )ptr_declarator#6b05080
   |   |)parameter_declaration#6b05100
   |   )template_parameter#6b05120
   |  )template_parameter_list#6b05140
   |  (template_parameter@Cpp~GCC5=2085#6b05440^1#6b05460:2 Line 3 Column 36 File C:/temp/prime_with_templates.cpp
   |   (parameter_declaration@Cpp~GCC5=1611#6b05420^1#6b05440:1 Line 3 Column 36 File C:/temp/prime_with_templates.cpp
   |   |(basic_decl_specifier_seq@Cpp~GCC5=1070#6b05160^1#6b05420:1 Line 3 Column 36 File C:/temp/prime_with_templates.cpp
   |   | (decl_specifier@Cpp~GCC5=1073#6b04fe0^1#6b05160:1 Line 3 Column 36 File C:/temp/prime_with_templates.cpp
   |   |  (trailing_type_specifier@Cpp~GCC5=1118#6b050e0^1#6b04fe0:1 Line 3 Column 36 File C:/temp/prime_with_templates.cpp
   |   |   (simple_type_specifier@Cpp~GCC5=1140#6b050c0^1#6b050e0:1 Line 3 Column 36 File C:/temp/prime_with_templates.cpp)simple_type_specifier
   |   |  )trailing_type_specifier#6b050e0
   |   | )decl_specifier#6b04fe0
   |   |)basic_decl_specifier_seq#6b05160
   |   |(ptr_declarator@Cpp~GCC5=1417#6b053e0^1#6b05420:2 Line 3 Column 40 File C:/temp/prime_with_templates.cpp
   |   | (noptr_declarator@Cpp~GCC5=1421#6b053c0^1#6b053e0:1 Line 3 Column 40 File C:/temp/prime_with_templates.cpp
   |   |  (declarator_id@Cpp~GCC5=1487#6b05360^1#6b053c0:1 Line 3 Column 40 File C:/temp/prime_with_templates.cpp
   |   |   (id_expression@Cpp~GCC5=317#6b05280^1#6b05360:1 Line 3 Column 40 File C:/temp/prime_with_templates.cpp
   |   |   |(unqualified_id@Cpp~GCC5=319#6b051a0^1#6b05280:1 Line 3 Column 40 File C:/temp/prime_with_templates.cpp
   |   |   | (IDENTIFIER@Cpp~GCC5=3368#6b046a0^1#6b051a0:1[`p'] Line 3 Column 40 File C:/temp/prime_with_templates.cpp)IDENTIFIER
   |   |   |)unqualified_id#6b051a0
   |   |   )id_expression#6b05280
   |   |  )declarator_id#6b05360
   |   | )noptr_declarator#6b053c0
   |   |)ptr_declarator#6b053e0
   |   )parameter_declaration#6b05420
   |  )template_parameter#6b05440
   | )template_parameter_list#6b05460

Determinare se si tratta di una dichiarazione variabile o di una moltiplicazione non è una funzione di verifica del tipo. Inoltre, ho dovuto ripulire la tua risposta da quella roba di autopromozione ... di nuovo.
Cucciolo

@Puppy: puoi dire quello che ti piace, ma è così che funziona lo strumento. L'eliminazione del nome dello strumento probabilmente farà semplicemente chiedere alle persone qual è il nome dello strumento.
Ira Baxter,

Indipendentemente dal fatto che lo strumento funzioni o meno è irrilevante, poiché la domanda non richiede il funzionamento dello strumento. Inoltre, penso che possiamo tranquillamente aspettare che ciò accada realmente.
Cucciolo
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.