Práce s číselnými konstantami
GScanner umí rozpoznávat číselné konstanty v různých formátech. Úplný výčet všech druhů včetně atributů, které jejich rozpoznávání zapínají, shrnuje následující tabulka.
| Druh | Token | Příklady | Volba GScannerConfig u |
Pozn. |
| Binární (dvojkové) | G_TOKEN_BINARY |
0b10110001 0B10110001 |
guint scan_binary; |
Binární číslo má prefix 0b nebo 0B. |
| Oktální (osmičkové) | G_TOKEN_OCTAL |
013 027 |
guint scan_octal; |
Číslo v osmičkové soustavě se pozná stejně jako v C: podle předřazené nuly ( 0). |
| Racionální | G_TOKEN_FLOAT |
3.14159 1.602e-19 |
guint scan_float; |
Ve shodě s jazykem C |
| Hexadecimální (šestnáctkové) 1 | G_TOKEN_HEX |
0xff993a 0XABcdEF |
guint scan_hex; |
Hexadecimální číslo se pozná podle prefixu 0x popř. 0X. Velikost písmen nehraje roli. |
| Hexadecimální (šestnáctkové) 2 | G_TOKEN_HEX |
$ff993a $ABcdEF |
guint scan_hex_dollar; |
Druhý možný formát hexadecimálního čísla: s předřazeným znakem dolaru ( $). |
| Decimální (desítkové) | G_TOKEN_INT |
2001 |
rozpoznáván vždy | Rozpoznávání obyčejných integerů zakázat nelze. |
Jak je vidět, schopnosti GScanner u jsou na poli číselných konstant velmi dobré. Žádný formát se nevymyká konvencím, a to je zajisté příjemné zjištění. Chcete-li, aby GScanner rozpoznával ten či onen formát, nastavte příslušný atribut scan_* na TRUE.
Práce s řetězci
Řetězec znaků je text uzavřený do apostrofů ( '') nebo uvozovek ( ""). GScanner jej zpracuje do tokenu G_TOKEN_STRING.
Zatímco single-quoted ( '') řetězce vrátí GScanner přesně tak, jak jsou napsány, u double-quoted ( "") řetězců se provádí ještě obvyklé substituce escape sekvencí: \\, \n, \t, \r, \b, \f a \<oktální_hodnota>. (Jejich význam je shodný s normou jazyka C.)
K povolení zpracování jednotlivých druhů řetězců slouží následující položky:
guint scan_string_sq;
– TRUE pro zpracovávání single-quoted ( '') řetězců,
guint scan_string_dq;
– TRUE pro zapnutí rozpoznávání double-quoted ( "") řetězců.
Sekundární pravidla
V okamžiku, kdy scanner na vstupu nalezne ucelenou část textu a převede ji na token, jeho práce ještě nekončí. V té chvíli se totiž na získaný token začnou uplatňovat další volitelná pravidla. Například, nastavíte-li položku
guint numbers_2_int;
na TRUE, veškeré číselné hodnoty (ať už binární, oktální, decimální nebo hexadecimální) se zkonvertují na G_TOKEN_INT. (Pokud je hodnota numbers_2_int FALSE, přečtené konstanty budou vraceny ve svém originálním formátu, tedy G_TOKEN_BINARY, G_TOKEN_OCTAL, G_TOKEN_INT atd.)
Podobně můžete chtít, aby se všechny integerové konstanty převáděly rovnou na racionální čísla ( G_TOKEN_FLOAT). Docílíte toho pomocí volby
guint int_2_float;
Konfigurací:
numbers_2_int = TRUE; int_2_float = TRUE;
…dosáhnete toho, že všechny číselné konstanty (i oktální, binární a hexadecimální) se interně převedou na float a vrátí se ve formě tokenu G_TOKEN_FLOAT.
Scanner můžete přinutit, aby implicitně převáděl identifikátory na řetězce. Stačí jen vložit hodnotu TRUE do položky
guint identifier_2_string;
Osamocený znak zpracuje GScanner do tokenu, jehož typem bude G_TOKEN_CHAR a daty (value) ordinální hodnota daného znaku. Je-li ale nastaven na TRUE atribut
guint char_2_token;
(což je mimochodem standardní stav), upraví se token G_TOKEN_CHAR tak, že ordinální hodnota znaku se použije přímo jako typ tokenu. Umožníte tím mimo jiné i vracení tokenů typu G_TOKEN_EQUAL_SIGN, G_TOKEN_LEFT_BRACE a podobně. Znakům, které nemají svou výčtovou konstantu, ji můžete sami dodefinovat nebo rovnou provádět porovnávání formou:
g_scanner_get_next_token(scanner);
if (scanner->token != '=') {
...
}
…tak, jako v příkladu z předminulého dílu.
Občas může být užitečná i volba:
guint symbol_2_token;
Chová se podobně, jako char_2_token. Přečtený symbol vrátí jako token, jehož typem bude definovaná hodnota symbolu. Viz rovněž příklad z předminulého dílu (upraveno, zkráceno):
/* definice vyctovych konstant pro symboly */
enum {
SYMBOL_DELKA = G_TOKEN_LAST + 1,
SYMBOL_VYSKA = G_TOKEN_LAST + 2
};
...
/* nastaveni */
scanner->config->symbol_2_token = true;
/* nacteni symbolu do tabulky symbolu */
g_scanner_add_symbol(scanner, "delka",
GINT_TO_POINTER(SYMBOL_DELKA));
g_scanner_add_symbol(scanner, "vyska",
GINT_TO_POINTER(SYMBOL_VYSKA));
...
g_scanner_get_next_token(scanner);
if (scanner->token == SYMBOL_DELKA) {
puts("Na vstupu je symbol \"delka\"");
}
Bez aktivovaného pravidla symbol_2_token bychom poslední příkaz porovnávání museli realizovat takto:
if ((scanner->token == G_TOKEN_SYMBOL) &&
(GPOINTER_TO_INT(scanner->value.v_symbol) == SYMBOL_DELKA)) {
puts("Na vstupu je symbol \"delka\"");
}
Univerzální obor platnosti
Poslední volba GScannerConfig u se týká tzv. oborů platnosti. V GScanner u můžete symboly sdružovat do logických celků ( scope), které v určitý okamžik zpracování zdrojového textu dávají smysl. Mezi těmito obory se můžete přepínat a tak určovat, jaké identifikátory a kdy mají být chápány jako symboly.
O oborech platnosti bude ještě řeč, na tomto místě jenom popíšu, jaký význam má atribut
guint scope_0_fallback;
Nastavíte-li jej na TRUE, získá obor platnosti 0 zvláštní význam: jeho tabulka symbolů bude prohledávána vždy, když se identifikátor nenalezne v aktuálním oboru platnosti. Do scope 0 si vložíte jen ty symboly, které mají smysl pořád, a zbytek množiny symbolů rozložíte do dalších oborů platnosti.
Závěr
Prokousali jsme se všemi možnými atributy nastavení GScanner u. Jeho konfigurační možnosti jsou docela slušné a pro texty s jednoduchými sémantickými a syntaktickými pravidly jistě i dostatečné. Příště se začneme konečně zabývat samotným procesem čtení.