Nagłówek: Tokenizer.hpp
Elementy modułu: Tokenizer Module
To prosty tokenizer, który przetwarza ciąg znaków na tokeny takie jak liczby, identifikatory, łańcuchy, symbole itp. Obsługiwana składnia jest wzorowana na C/C++. Jego założeniem jest zastąpić mój stary język opisu XNL2.
Na jego bazie można budować parsery różnych plików np. konfiguracyjnych albo opisujących i przechowujących różne informacje - tekstowe, numeryczne i inne, dowolnie zorganizowane. Polecam go zamiast XML, bo XML jest bardzo rozwlekły. Tokenizer raczej nie nadaje się do budowy języków programowania, a jedynie formatów opisu.
Składnia jest wzorowana na C/C++.
Znak \ po którym od razu następuje koniec linii przełamuje linię tak, że koniec linii jest ignorowany i dalej rozciąga się ta sama linia, np.:
abc\ def
Komentarze mogą być:
// komentarz /* komentarz * / (bez tej spacji, ale inaczej nie dało się tego zapisać w Doxygen) Rozciąga się do napotkania pierwszego * / Symbolami są znaki:
` ~ ! @ # $ % ^ & * ( ) = [ ] { } ; : , . < > ? \ | /
Identyfikatorem jest ciąg liter (tylko ASCII, bez polskich) i cyfr rozpoczynający się od litery. Znak _ jest uważany za literę. Przykłady:
abc a123 _G
Słowo kluczowe jest jak identyfikator. Jedyna różnica polega na tym, że jego specjalne znaczenie jako słowa kluczowego zostało zarejestrowane.
Liczba całkowita to na przykład: Jeśli rozpoczyna się od 0, jest ósemkowa. Jeśli rozpoczyna się od 0x lub 0X, jest szesnastkowa.
10 +2 -7 0777 0xFFFFFFFF
Liczba zmiennoprzecinkowa to na przykład:
10.5 -.2 3.1e-2
Stała znakowa to pojedynczy znak objęty w apostrofy:
'A' '\n'
Stała łańcuchowa to dowolna liczba znaków objęta w cudzysłowy. O tym czy wewnątrz łańcucha może się znajdować koniec wiersza (czy łańcuch może się rozciągać na wiele wierszy) decyduje flaga w konstruktorze tokena. Domyślnie nie może.
"abc" "" "a b \"c\"\n"
Sekwencje ucieczki, czyli sposób zapisywania znaków specjalnych wewnątrz stałych znakowych i łańcuchowych jest podobny do C/C++.
\\ \? \ \'\0 \r \n \t \v \b \f \a\xFF \x41 \xA0Jeśli plik ma strukturę taką jak ten przykład:
{
Nazwa1 = "Wartość1"
Nazwa2 = "Wartość2"
}
To kod, który parsuje go z użyciem modułu Tokenizer może wyglądać tak:
void ParseMyFormat(std::map<string, string> &Out, const string &In) { common::Tokenizer t(&In, 0); t.Next(); t.AssertSymbol('{'); t.Next(); std::pair<string, string> Item; while (!t.QuerySymbol('}')) { t.AssertToken(common::Tokenizer::TOKEN_IDENTIFIER); Item.first = t.GetString(); t.Next(); t.AssertSymbol('='); t.Next(); t.AssertToken(common::Tokenizer::TOKEN_STRING); Item.second = t.GetString(); t.Next(); Out.insert(Item); } t.Next(); t.AssertEOF(); }
== Było w planach, ale ostatecznie zrezygnowałem bo uznałem, że się nie przyda.1.0f Uznałem, że obejdzie się bez tego.
1.6.1