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í.