2016-04-24 28 views
5

Próbuję utworzyć parser za pomocą golang's yacc tool. Znalazłem nex, aby uprościć tworzenie lexera, aby dać parser. Mój problem polega na tym, że wygenerowany analizator składni nie ma żadnej metody ani pola, które dałoby mi dostęp do wyniku analizowania. Mógłbym po prostu zapisać wynik analizy w zmiennej globalnej, ale wydaje się, że jest błędny.Uzyskiwanie dostępu do wyniku parser wygenerowanego przez golang yacc

Obecnie Dodałem następujące jako Pierwsza próba górze mojego pliku 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{} 
} 

Czy istnieje Zalecanych/lepszy sposób na uzyskanie w wyniku z parsera?
(Ponieważ to czuje się trochę nadużycie generatora ...)

+0

Co masz na myśli przez wyniku parsowania? – andlabs

+0

Podczas analizowania danych wejściowych buduję strukturę drzewa. Jest przechowywany w '$$. Expr'. Chcę uzyskać korzeń tego drzewa. Wydaje się, że powyższa funkcja "Wynik" uzyskuje dostęp do właściwego wyniku, ale wydaje się nieco zła. Nie jestem w 100% pewny, że 'p.stack [1]' będzie tam, gdzie wynik root/parsowania jest zawsze przechowywany ... –

+1

Tak, nie upuszczajcie w nieudokumentowanych strukturach danych Yacca, jak przypuszczam. Sądzę, że jest to albo "zmienne globalne", albo "pola typu bazowego interfejsu yyLexer"; Używam tego ostatniego – andlabs

Odpowiedz

5

No, dostępu stack[1] nie działa niezawodnie. Nie zawiera żadnych rezultatów, gdy tylko stos musi przekroczyć 16, początkowy rozmiar. (Patrz #16163.)

Oświadczenie if po etykieta yystack następnie tworzy nowy stos i całkowicie zapomina o jednej zapisanej w yyParserImpl.


Wykonałem następujące czynności.

Dodaj pole result do rodzaju Lexer:

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

Extend gramatykę według następującej reguły na samym początku:

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

(Zależy to od nazwy parametru metody Parse (który może mieć niestandardowy prefiks), ale myślę, że jest ok.)

1

Alternatywne rozwiązanie: użyj sed, aby wstawić dodatkowe pole do wygenerowany analizator składni. Następnie, w swojej akcji gramatycznej, przypisz wartość.

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

Wygenerowany parser:

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

Gramatyka działanie:

filter { Filterrcvr.tree = $1 }