przejście do zawartości
zpr c++ quick reference
Narzędzia użytkownika
Zarejestruj się!
Zaloguj
Narzędzia witryny
Narzędzia
Pokaż stronę
Poprzednie wersje
Odnośniki
Ostatnie zmiany
Menadżer multimediów
Indeks
Zaloguj
Zarejestruj się!
Ostatnie zmiany
Menadżer multimediów
Indeks
Ślad:
spirit
Ta strona jest tylko do odczytu. Możesz wyświetlić źródła tej strony ale nie możesz ich zmienić.
====== Biblioteka Boost Spirit ====== Bartłomiej Wojcieszek G1SST ==== Wstęp ==== Parser, zwany także analizatorem składniowym, pozwala na analize danych wejściowych i określenie czy są zgodne z daną gramatyką. Zazwyczaj parsery są wykorzystywane przy przetwarzaniu danych zrozumialych dla czlowieka w dane najbardziej wygodne dla komputera. Biblioteka Spirit pozwala tworzyć własne złożone parsery lub wykorzytywać te najprostsze wbudowane w bibliotekę. Szablony wyrażeń zastosowanych w bibliotece pozwalają na zapis w notcacji bardzo podobnej do EBNF (Extended Backus-Normal Form): \\ Gramatyka EBNF: <code cpp> group ::= '(' expression ')' factor ::= integer | group term ::= factor (('*' factor) | ('/' factor))* expression ::= term (('+' term) | ('-' term))* </code> I ten sam parser zapisany w C++ z pomocą biblioteki Spirit: <code cpp> group = '(' >> expression >> ')'; factor = integer | group; term = factor >> *(('*' >> factor) | ('/' >> factor)); expression = term >> *(('+' >> term) | ('-' >> term)); </code> ==== Jak używać? ==== Aby wykorzystywać w swoich programach bibliotekę spirit, należy dołączyć odpowiednie nagłówki do naszego pliku: <code cpp> #include <boost/spirit/core.hpp> #include <boost/spirit/actor/push_back_actor.hpp> </code> ==== Na początek coś prostego ==== Załóżmy,że chcemy aby nasz program akceptował tylko takie dane wejsciowe, że pierwszym elementem jest liczba rzeczywista, a następnym znak alfabetyczny. Tworzymy parser: <code cpp> real_p>>alpha_p </code> Aby go wykorzystać, należy skorzystać z funkcji //parse//: <code cpp> bool parseInput(String str){ return parse(str,real_p>>alpha_p,space_p); } </code> Funkcja //parse// zwraca //true// jeżeli parsowanie przebiegło pomyślnie. Przyjmuje trzy argumenty: - Zakończone nullem //const char*// dane do sparsowania - Obiekt parsujący - Parser pomijania (mówi na co nie zwracać uwagi w danych wejściowych, w tym przypadku na spacje) ====Teraz trochę o gramatyce==== Wyrażenia parsujące tworzy się za pomocą wbudowanych w bibliotekę prymitywów oraz operatorów. Kilka podstawowych prymitywów (więcej można znaleźć w dokumentacji): <code cpp> ch_p('X') //parsuje char podany jako argument range_p('a','z') //parsuje pojedynczy char z podanego zakresu str_p("Hello") //parsuje podany string anychar_p //dowolny znak alnum_p //znak alfanumeryczny alpha_p //znak alfabetu blank_p //spacje i tabulacje lower_p //male litery print_p //znaki drukowane punct_p //znaki punktuacyjne space_p //spacja tab,nowa linia upper_p //duze litery digit_p //cyfra int_p //int real_p //liczba rzeczywista </code> I operatory: <code cpp> a | b //a lub b a & b //a i b a - b //a ale nie b a ^ b //a lub b ale nie oba (XOR) a>>b //a i b w sekwencji a&&b //jw a||b //a lub b w sekwencji *a //a zero lub wiecej razy +a //a raz lub wiecej razy !a //a zero lub jeden raz a%b //lista a oddzielonych przez b </code> Dodatkowo parsery numeryczna możemy bardziej sprecyzować. Oto szablon takiego parsera: <code cpp> template < typename T = unsigned, //bazowy typ parsera, default jest unsigned int Radix = 10, //podstawa systemu, czyli dziesiętny szesnastkowy itp. unsigned MinDigits = 1, //minimalna liczba cyfr int MaxDigits = -1> //maksymalna liczba cyfr (-1 oznacza niograniczona) struct uint_parser { /*...*/ }; //zatem jeżeli chcemy sparsować liczbę szesnastkową, nasz parser będzie wyglądał następująco: uint_parser<unsigned, 16, 1, -1> const //lub to samo osiągniemy korzystając z wbudowanego parsera hex_p //chcielibyśmy sparsować liczbe odzdzieloną przecinkami, taką jak: 1,234,567,891 uint_parser<unsigned, 10, 1, 3> uint3_p; // parsuje od 1 do 3 cyfr,czyli pierwsza część uint_parser<unsigned, 10, 3, 3> uint3_3_p; // dokładnie 3 cyfry ts_num_p = (uint3_p >> *(',' >> uint3_3_p)); // dowolna liczba oddzielana co 3 cyfry przecinkami </code> Załóżmy, że chcemy wczytać ze standardowego wyjscia do wektora ciąg liczb oddzielonych przecinkami (oczywiście przecinki nas nie interesują, tylko liczby). Czyli n a wejsciu ma się pojawić liczba, nastepnie dowolna ilość razy przecinek i kolejna liczba. Zatem w kodzie c++ wygląda to następująco: <code cpp> bool parse_numbers(char const* str, vector<double>& v) { return parse(str, ( real_p[push_back_a(v)] >> *(',' >> real_p[push_back_a(v)]) ) , space_p).full; } </code> Wywołana metoda ''full'' zwraca true jeżeli wszystkie dane zostały poprawnie sparsowane. A co to za dziwne nawiasy kwadratowe za wyrażeniem? Jest to akcja semantyczna (ang. Semantic Action). Sam parser sprawdza tylko czy dane wyrażenie pasuje do wzorca, ale nic więcej z nim nie robi. Z pomocą przychodzą akcje semantyczne. Mogą być one dodane w dowolnym miejscu. Funkcja jest wywoływana w momencie, gdy parsowanie przebiegło pomyślnie. Jak to się robi?: <code cpp> //jeżeli P to nasz parser a F to funkcja w c++ to aby "podłączyć" funkcję do parsera, należy to zrobić w następujący sposób: P[&F] //jeżeli natomiast F jest funktorem: P[F] //dodatkowo argument fukncji musi się zgadzać z elementem parsowanym: void Foo(double d); real_p[&Foo] </code> ==== Bardziej użyteczny przykład ==== ==== Wykorzytanie funkcji ==== ==== O bibliotece Spirit w sieci ==== * [[http://spirit.sourceforge.net/|Witryna biblioteki]]
spirit.1208322902.txt.gz
· ostatnio zmienione: 2008/04/16 07:15 przez
bwojcies
Narzędzia strony
Pokaż stronę
Poprzednie wersje
Odnośniki
Do góry