2011-07-09 11 views
5

To nie jest duplikat this question, ponieważ rozwiązaniem nie było użycie parsera!Interfejs Yacc/Bison Parser z programem C++

Mam parser Bison, który mogę uruchomić wykonując ./parser < file_to_parse. Chcę wywołać parser Bison z mojego programu C++. To, czego nie chcę, to zrobić system(./parser < file_to_parse), ponieważ zakładałoby to, że parser jest wstępnie skompilowany, a wtedy mój cały program nie byłby niezależny od platformy.

Jeśli mam funkcję:

void foo(file_name) { 
    // call parser on file_name 
} 

to w jaki sposób można to zrobić? Jakieś pomysły? Myślę, że jest tak w przypadku wywoływania yyparse lub czegoś takiego, ale nigdzie się z tym nie dogaduję!

Dziękuję :).

Odpowiedz

1

Dokładnie to robisz - nazywasz yyparse(). Napisałeś yylex() tak, że twój główny program może określić swoje wejście. Przypuszczalnie twoja aktualna funkcja yylex() wywołuje getchar() lub coś, co przeczyta znak; zamiast tego będziesz prawdopodobnie musiał napisać to, aby odebrać dane z jakiegoś miejsca określonego przez twój główny program.

+0

Dziękuję Ernest .. wciąż walczę, ale mam nadzieję, że się tam dostanę. W rzeczywistości nie mam yylex() w moim lexer - Flex tworzy domyślny, który prawdopodobnie robi getchar(). Chyba muszę napisać własne w lexer czy coś takiego. – ale

2

Czy używasz wersji przystosowanej do C++?

Używam tego przez Alaina Coetmeura.

W tej chwili mam tylko kod przydatny do stosowania flex ++, ale powinien pokazać, jak to działa.

Po uruchomieniu Flex ++ wypisze plik nagłówkowy i plik implementacji dla nowej klasy, aby wykonać parsowanie. Dodaj je do swojego projektu, a następnie napisz:

+0

Dziękuję. W rzeczywistości używam starego Flex/Bison .. Byłem świadomy, że wczoraj było C++! .. Na pewno lepiej byłoby użyć tego, którego używasz. Zamierzam spróbować rozwiązać go za pomocą moich narzędzi, a jeśli się nie uda, przejrzę te C++. Dziękuję +1. – ale

+0

Polecam teraz dokonać zmiany. Nowe parsery są kompatybilne ze starszymi, więc nie stracisz żadnych inwestycji w skryptowanie. I życie będzie o wiele łatwiejsze. – ravenspoint

+0

Utknąłem, więc zamierzam to zrobić :). Zostanie oznaczony jako rozwiązanie, jeśli działa. Dziękuję Ci. – ale

1

To jest kod C, ale myślę, że będzie to również wskazówka dla C++.
Kiedy mieliśmy zrobić kompilator na uniwersytecie musieliśmy określić YY_DECL w pliku jak to .l:

 
#define YY_DECL int alpha_yylex(yylval_) void *yylval_; 

int alpha_yylex(yylval_) jest funkcja i void *yylval jest typem parametru.
Oczywiście, musisz to zrobić, aby analizator składni wiedział, od czego zacząć, od której funkcji należy wykonać parsowanie.

Należy również wyeksportować ten prototyp funkcji (extern int alpha_yylex(void *yylval_);) do pliku .y.
Po tym, narzędzia Flex/Bison automatycznie wygenerują odpowiednie pliki .c.

Ogólnie rzecz biorąc, .l jest dla reguł leksykalnych, a .y jest dla reguł gramatycznych. Dlatego, jeśli chcesz uzyskać wartość skądś trzeba zdefiniować unii w .y tak (przykład):

%union { 

    union { 
     int Integer; 
     double Double; 
     char Character; 
     char* String; 
    } value; 

} 

Następnie, w zależności od Twoich składniowych i zasad, można zrobić yylval.value.String = strdup(yytext) w swoim .l file oraz, w zależności od reguł gramatycznych, $$.Double = $1.Double + $3.Double w pliku .y.

nie pamiętam wiele, ponieważ to było natomiast, że zrobiłem to, ale myślę, że można spróbować można znaleźć w dokumentacji lub zapytać tutaj :)

PS: (miałem Dobre FAQ gdzieś, ale nie pamiętam, gdzie to jest -> opublikuję później, jeśli będę miał szczęście, aby znaleźć to xD: D xD)