Cosa rende Java più facile da analizzare rispetto a C?


90

Conosco il fatto che le grammatiche di C e C ++ sono sensibili al contesto , e in particolare hai bisogno di un "lexer hack" in C. D'altra parte, ho l'impressione che tu possa analizzare Java solo con 2 segni di anticipazione, nonostante la notevole somiglianza tra le due lingue.

Cosa dovresti cambiare di C per renderlo più trattabile da analizzare?

Lo chiedo perché tutti gli esempi che ho visto della sensibilità al contesto di C sono tecnicamente ammissibili ma terribilmente strani. Per esempio,

foo (a);

potrebbe chiamare la funzione void foocon argomento a. Oppure potrebbe dichiarare adi essere un oggetto di tipo foo, ma potresti sbarazzarti altrettanto facilmente delle parentesi. In parte, questa stranezza si verifica perché la regola di produzione del "dichiaratore diretto" per la grammatica C soddisfa il duplice scopo di dichiarare sia le funzioni che le variabili.

D'altra parte, la grammatica Java ha regole di produzione separate per la dichiarazione delle variabili e la dichiarazione delle funzioni. Se scrivi

foo a;

allora sai che è una dichiarazione di variabile e foopuò essere analizzata in modo univoco come un nome di tipo. Questo potrebbe non essere un codice valido se la classe foonon è stata definita da qualche parte nell'ambito corrente, ma è un lavoro per l'analisi semantica che può essere eseguita in un passaggio successivo del compilatore.

Ho visto che è stato detto che C è difficile da analizzare a causa di typedef, ma puoi dichiarare i tuoi tipi anche in Java. Quali sono le regole grammaticali in C, inoltre direct_declarator, sono in errore?


7
Bella domanda. Probabilmente però troppo ampio o principalmente supponente.
asteri

37
Questa è una domanda valida sui parser e l'unica cosa ampia o basata su un'opinione su di essa sono le ultime due frasi (che probabilmente dovrebbero essere eliminate o modificate). Esci con i voti vicini.
R .. GitHub SMETTA DI AIUTARE ICE

1
Ho modificato la domanda di conseguenza, grazie per @R .. per il feedback.
korrok

3
Praticamente ogni linguaggio (standard) per computer è sensibile al contesto ; non puoi dichiarare una variabile di un tipo e usarla in modo improprio nella maggior parte dei linguaggi . Ciò è diverso dal fatto che "tutte le grammatiche per la lingua" sono sensibili al contesto; la maggior parte delle persone che costruiscono parser costruisce un parser senza contesto (o anche più restrittivo) e quindi utilizza hack al di fuori del parser per verificare le proprietà senza contesto.
Ira Baxter

1
@IraBaxter non lo chiamerei "hack". Dividere il problema in due sembra una cosa ragionevole da fare, dal momento che l'analisi dei linguaggi sensibili al contesto non può essere eseguita in modo efficiente (e in effetti anche l'analisi dei linguaggi privi di contesto non è efficiente, ed è per questo che generalmente ci limitiamo a sottoinsiemi di privi di contesto) . Un'analisi senza contesto + un'analisi statica per controllare solo le proprietà sensibili al contesto sull'AST è una cosa ragionevole da fare.
Bakuriu

Risposte:


76

L'analisi del C ++ sta diventando difficile. L'analisi di Java sta diventando altrettanto difficile.

Vedi questa risposta SO che spiega perché C (e C ++) è "difficile" da analizzare . Il breve riassunto è che le grammatiche C e C ++ sono intrinsecamente ambigue; che vi darà più analizza e si devono utilizzare contesto per risolvere le ambiguità. Le persone quindi commettono l'errore di presumere che sia necessario risolvere le ambiguità durante l'analisi; non è così, vedi sotto. Se ti ostini a risolvere le ambiguità durante l'analisi, il tuo parser diventa più complicato e molto più difficile da costruire; ma quella complessità è una ferita autoinflitta.

IIRC, la grammatica LALR (1) "ovvia" di Java 1.4 non era ambigua, quindi era "facile" da analizzare. Non sono così sicuro che il Java moderno non abbia almeno ambiguità locali a lunga distanza; c'è sempre il problema di decidere se "... >>" chiude due template o è un "operatore di spostamento a destra". Sospetto che Java moderno non analizzi più con LALR (1) .

Ma si può superare il problema dell'analisi utilizzando potenti parser (o parser deboli e hack di raccolta del contesto come fanno principalmente i front-end C e C ++ ora), per entrambi i linguaggi. C e C ++ hanno l'ulteriore complicazione di avere un preprocessore; questi sono più complicati nella pratica di quanto sembri. Un'affermazione è che i parser C e C ++ sono così difficili che devono essere scritti a mano. Non è vero; puoi costruire parser Java e C ++ perfettamente con i generatori di parser GLR.

Ma l'analisi non è davvero dove si trova il problema.

Dopo aver analizzato, vorrai fare qualcosa con l'albero di analisi / AST. In pratica, è necessario sapere, per ogni identificatore, qual è la sua definizione e dove viene utilizzato ("risoluzione di nome e tipo", sciatto, costruzione di tabelle di simboli). Questo risulta essere MOLTO più lavoro che ottenere il parser corretto, aggravato da ereditarietà, interfacce, sovraccarico e modelli, e confuso dal fatto che la semantica per tutto questo è scritta in un linguaggio naturale informale distribuito su decine di centinaia di pagine dello standard linguistico. Il C ++ è davvero pessimo qui. Java 7 e 8 stanno diventando piuttosto terribili da questo punto di vista. (E le tabelle dei simboli non sono tutto ciò di cui hai bisogno; guarda la mia biografia per un saggio più lungo su "Life After Parsing").

La maggior parte delle persone ha difficoltà con la parte di analisi pura (spesso non finisce mai; controlla SO stesso per le molte, molte domande su come costruire parser funzionanti per i linguaggi reali), quindi non vedono mai la vita dopo l'analisi. E poi otteniamo teoremi popolari su ciò che è difficile da analizzare e nessun segnale su ciò che accade dopo quella fase.

La correzione della sintassi C ++ non ti porterà da nessuna parte.

Per quanto riguarda la modifica della sintassi C ++: scoprirai che devi applicare patch a molti punti per occuparti della varietà di ambiguità locali e reali in qualsiasi grammatica C ++. Se insisti, il seguente elenco potrebbe essere un buon punto di partenza . Affermo che non ha senso farlo se non sei il comitato per gli standard C ++; se lo facessi e costruissi un compilatore usando quello, nessuno sano di mente lo userebbe. Si è investito troppo nelle applicazioni C ++ esistenti per cambiare per comodità dei ragazzi che costruiscono parser; inoltre, il loro dolore è finito e gli analizzatori esistenti funzionano bene.

Potresti voler scrivere il tuo parser. Ok va bene; semplicemente non aspettarti che il resto della comunità ti permetta di cambiare la lingua che deve usare per renderti più facile. Vogliono tutti che sia più facile per loro, e questo è usare il linguaggio così come documentato e implementato.


Buona risposta. Vedi anche D e C +, che cercano di risolvere alcuni di questi problemi. s / content /
contend

3
Ho letto Life After Parsing prima e ho scoperto che mi ha aperto gli occhi; mi ha reso chiaro che c'è molto più lavoro nell'analisi semantica (risoluzione nome / tipo, ...) che nell'analisi. Sto Non cercando di cambiare la sintassi di ogni linguaggio. Io non voglio capire quali sono le proprietà sono di un linguaggio in cui è possibile fare l'analisi sintattica e poi l'analisi semantica. Il C non è un tale linguaggio (necessita di un lexer hack); Ho sempre pensato che Java fosse e voglio sapere perché.
korrok

1
@Korrok: leggi la mia risposta sulla creazione di Java / C ++ con parser GLR. Non hai bisogno di alcun hack lexer . Quindi, la distinzione è nella mente delle persone che utilizzano la tecnologia di analisi sbagliata. ... Certo, costruire un front-end C ++ completo (specialmente C ++ 14, cosa che abbiamo fatto) è più difficile che fare Java8, ma sono entrambi difficili (in termini di impegno e attenzione ai dettagli) e analisi è il pezzo più semplice.
Ira Baxter

1
Sono d'accordo sulla tua "Vita dopo l'analisi": ad esempio, la risoluzione dell'overload in C # può codificare qualsiasi problema 3-SAT ed è quindi NP-difficile.
Jörg W Mittag

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.