2016-04-24 33 views
5

Sto cercando di creare un parser utilizzando golang's yacc tool. Ho trovato nex per semplificare la creazione di un lexer per fornire il parser. Il mio problema ora è che il parser generato non ha alcun metodo o campo per darmi accesso al risultato dell'analisi. Potrei semplicemente memorizzare il risultato dell'analisi in una variabile globale, ma ciò sembra sbagliato.Accesso al risultato di un parser golang yacc generato

Attualmente ho aggiunto la segue come un primo tentativo alla cima del mio file parser.y:

type ResultParser interface { 
    yyParser // Generated parser interface 
    Result() s.Expr // s.Expr is an interface for the parsed result 
} 

func (p *yyParserImpl) Result() s.Expr { 
    return p.stack[1].expr 
} 

func NewResultParser() ResultParser { 
    return &yyParserImpl{} 
} 

Esiste un Recomended/modo migliore di ottenere il risultato del parser?
(Dal momento che questo si sente come un po 'di un abuso del generatore ...)

+0

Che cosa si intende per risultato di analisi? – andlabs

+0

Quando analizzo l'input, costruisco una struttura ad albero. È memorizzato in $ $$ expr'. Voglio ottenere la radice di quell'albero. La precedente funzione 'Result' sembra accedere al risultato giusto, ma sembra un po 'hacky. Non sono sicuro al 100% che 'p.stack [1]' sarà dove il risultato root/parse è sempre archiviato ... –

+1

Sì, non importare le strutture dati non documentate di yacc, suppongo. Immagino che sia "variabili globali" o "campi del tipo sottostante dell'interfaccia yyLexer"; Io uso il secondo – andlabs

risposta

5

No, l'accesso stack[1] non funziona in modo affidabile. Non contiene alcun risultato non appena la pila ha bisogno di crescere oltre 16, la sua dimensione iniziale. (Vedere #16163.)

Il if dichiarazione dopo l'etichetta yystack crea quindi un nuovo stack e totalmente dimentica quello salvato nella yyParserImpl.


Ho fatto quanto segue.

Aggiungi un campo result al tipo lexer:

type ShellLexer struct { 
    /* … */ 
    result *ShellProgram 
} 

Estendere la grammatica dal seguente regola, proprio all'inizio:

start : program { 
    shyylex.(*ShellLexer).result = $$ 
} 

(Questo dipende dal nome del parametro del metodo Parse (che può avere un prefisso personalizzato), ma penso che sia ok)

1

Soluzione alternativa: usare sed per inserire campi aggiuntivi nel parser generato. Quindi, nella tua azione grammaticale, assegna il valore.

go tool yacc -o parser.go -p Filter parser.y 
sed -i '/type FilterParserImpl struct/a tree *treeNode' parser.go 

Il parser generato:

type FilterParserImpl struct { 
tree *treeNode 
    lval FilterSymType 
    stack [FilterInitialStackSize]FilterSymType 
    char int 
} 

azione Grammatica:

filter { Filterrcvr.tree = $1 }