5

Stavo cercando di implementare un parser LL (1) dall'alto verso il basso per una lingua della calcolatrice. Ci consente solo di sommare, sottrarre, dividere e moltiplicare i numeri. Nessuna parentesi.Un operatore associativo sinistro può essere espresso in modo tale che i parser LL (1) dall'alto verso il basso possano comprendere?

S -> A 

A -> B + A 
    | B - A 
    | B 

B -> int * B 
    | int/B 
    | int 

Poiché questa grammatica non è adatto a un LL (1) parser, ho dovuto cambiare un bel po ':

S -> A 

A -> B A' 
A'-> + A 
    | - A 
    | λ 

B -> int B' 
B'-> * B 
    |/B 
    | λ 

Il problema è che ora la grammatica non è lasciato associativa per il 4 operatori mostrati, e ho bisogno che sia così. Come risolvere questo problema? È persino possibile farlo?

+1

Suppongo che tu non stia cercando la risposta "non usare un parser LL (1), quindi" :). Ma questa è la realtà: i parser di 'LL (1) 'non sono una buona corrispondenza per le espressioni di analisi; se non vuoi usare 'LR (1)' per qualche ragione, scrivi un parser di Pratt o un parser di precedenza per gli operatori (vedi "Algoritmo di Shunting Yard") – rici

+1

Beh, sto solo imparando i parser. Intendevo provare a implementare un semplice linguaggio di calcolo per diversi tipi di parser. Stai affermando che non è possibile eseguire una calcolatrice con un LL (1)? –

+0

Non sto affermando che è impossibile, solo che non è banale. È possibile farlo utilizzando il parser LL (1) per generare un albero di analisi per la grammatica modificata, quindi invertire la trasformazione nell'albero di analisi per creare l'albero di analisi per la grammatica originale. – rici

risposta

6

È possibile ottenere l'associatività a sinistra sostituendo la ricorsione con iterazione. Il seguente tipo di pseudocodice calcola direttamente i valori solo per semplicità, ma è possibile generare un albero di analisi usando lo stesso metodo.

function A() { 
    val = B(); 
    t = peek(); 
    while (t=='+' || t=='-') { 
    match(t); 
    val1 = B(); 
    if (t=='+') 
     val = val + val1; 
    else 
     val = val - val1; 
    t = peek(); 
    } 
    return(val) 
} 

dove peek() restituisce il token successivo senza mangiare, e match() mangia il token successivo. Faresti la stessa cosa per B().

Problemi correlati