Hlavní navigace

GLib: Lexikální scanner (4)

11. 4. 2001
Doba čtení: 4 minuty

Sdílet

Dnes nás čeká dokončení výkladu o konfiguraci lexikálního scanneru.

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.

Tabulka č. 113
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  at­d.)

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 GScannerConfi­g 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;

root_podpora

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

Byl pro vás článek přínosný?

Autor článku

Michal Burda vystudoval informatiku a aplikovanou matematiku a nyní pracuje na Ostravské univerzitě jako odborný asistent. Zajímá se o data mining, Javu a Linux.