Bez záruky.
Kód: Vybrat vše
Pomocí makra YYSTYPE se definuje sémantický typ, v našem případě:
#define YYSTYPE mlc::MlaskalLval
Uvnitř tohoto typu se schovávají všechny množiny atributů pro symboly. Struktura
mlc::MlaskalLval obsahuje položku pro každý typ množiny (to může být další
struktura). Zde si musíme sami nadefinovat množiny v této struktuře.
Struktura je vystrčena ven v souboru du4lval.hpp. Tam je nadefinovaná a můžeme
si s ní dělat co chceme. Tento zdroják je součástí odevzdání práce.
Jak mohu symbolu v bisonu přiřadit nějakou množinu?
toto:
%token DUTOK_UINT
přepíšu na:
%token<int_ci_> DUTOK_UINT
dále např.:
%token<dtge_> DUTOK_OPER_REL
atp.
A jak to udělat pro neterminály?
%type<vyraz> vyraz, term, faktor
kde "vyraz" v <> je položka mlc::MlaskalLval určijící typ neterminálu.
Následuje výčet neterminálů (odělené mezerou nebo čárkou?)
V pravidlech potřebuju nějak pracovat s těmi atributy. Za poslední symbol
pravidla napíšu do složených závorek kód, který se vykoná při redukci podle
daného pravidla.
N: A1 A2 A3 { /* zde kód */
}
;
Znaky $$ reprezentují strukturu neterminálu N (toho na levé straně). Neterminály
na pravé straně jsou očíslovány od 1. Přístupuje se přes $N
N: A1 A2 A3 {
$$.typ = $1.typ
/* ... */
}
;
Do struktur $N nemá smysl zapisovat, protože pravá strana po redukci zanikne.
%N ... neterminálu (číslo řádky)
Pro komplikovanější kód je lepší vytvořit funkci a necpat to vše do Bisona. Na
to je určen soubor du4sem.cpp, kam si můžeme psát co chceme. Ten je nutno také
odevzdat.
Např. pro bloky budeme potřebovat zavolat příkazy uprostřed pravé strany.
Řešení: vytvoříme si nový neterminál, který se přepíše na prázdno:
N: A1 XX A2 ...
X2: /* empty */ { /* kód */ }
1. úkol: upravit rozhraní, do yylex přibyl parametr ctx. V této struktuře je
vyplněna položka ctx->tab, v ní jsou schovány tabulky literálů (ls_real). To
byly dříve globální proměnné, odteď nutno pracovat s touto strukturou. Jsou to
funkce, takže:
ctx->tab.ls_read().add(...)
K této struktuře je k dispozici doxymentace.
Hlavním úkolem je plnění tabulek deklarací. Zde je rozdíl v bodování, záleží
co všechno budeme dávat do tabulek.
U konstant pozor, že tam jsou také znaménka. Příklad:
const minus1 = -jedna;
Zde musím načíst z tabulky hodnotu konstanty jedna (zkontrolovat typ), aplikovat
znaménko, výsledek uložit do tabulky pro minus1.
Tabulky se skládají ze 3 částí
labels - návětší
symbols - do toho se schovávají jména a typy identifikátorů, např.:
A VAR
B TYPE
C FUNKCE
Již je tam předdefinované např.:
INTEGER TYP (s ukazatelem na typ integer do tabulky types)
Dávají se tam jen "veletypy".
types - Tabulka pro typy. Uvnitř jsou již zabudované typy bool, real, int,
string. Potřebujeme tam vyrobit krabičku pro typ záznam. Uvnitř bude seznam
položek daného typu. V případě záznamu budou z této krabičky odkazy na
jednoduché typy (protože položky záznamu bývají jednoduché typy).
V této tabulce nejsou uloženy názvy symbolů. Kvůli tomu vede odkaz z tabulky
symbols (což je seznam identifikátorů), pokud je to typ, bzde to mít odkaz
do tabulky types.
LABELS
V Mlaskalu používáme jen deklaraci návěští.
ctx->tab.add_label_entry(int line, ls_int_index idx, ic_label lbl)
line - číslo řádky vezmu z lokace příkazu label (%N)
ls_int_index - iterátor do tabulek čísel
příklad:
label 6;
ctx->tab.add_label_entry(%1,$1,new_label(ctx));
To vyrobí záznam v tabulce labels.
DEKLARACE PROMĚNNÉ
var i,j: integer;
"i,j" řeším jedním neterminálem - seznam_id : typ ;
Vytvoříme si vektor, do kterého budeme v cyklu uvnitř seznam_id cpát jednotlivé
identifikátory. Tím to vše "vytlačíme" do společného místa. POZOR, do toho
seznamu si musíme u každé položky uchovávat na jaké je řádce (protože seznam
může být přes více řádků).
Jak najdu v tabulce types příslušný typ?
find_symbol(ls_id_index idx)
Tato funkce vrátí symbol_pointer. Na ní je definován operátor vykřičník, tj.
if (!find_symbol(ls_id_index idx)) { /* symbol v tabulce nenalezen */ }.
Volám patřičnou chybu - špatné jméno typu.
Jak získat jméno identifikátoru? Použiju operátor * u interátoru typu
ls_id_index.
Pokud identifikátor v tabulce je, musím zjistit jeho typ:
ls_id_index.kind() vrací výčtový typ. Funkce access_XXX() (kde XXX je příslušný
typ) vrátí type_symbol_pointer. Na tom je definována funkce type(), která nás
odkáže na příslušnou ohrádku v tabulce types (mám v ruce šipku do tabulky
types).
Jak teď vložit identifikátor typu do tabulky symbols? Nyní mám třeba onen vektor
se seznamem identifikátorů. Když ho mám celý (prošel jsem seznam_id), přidávám
do tabulky symbols:
add_var(int line, ls_id_index id, type_pointer p)
Specialita u procedur a funkcí, musíme navíc přidat seznam parametrů:
add_proc(line,id,parameter_list * pl)
k tomu je funkce create_parameter_list(), ta vrátí prázdný seznam parametrů, ten
musíme naplnit. POZOR, parametr může být vařený nebo nevařený (tj. reference
nebo nereference). Seznam má metody append_parameter_by_value(id,tp)
a append_parameter_by_reference(...)
Když nemá funkce/procedure žádné parametry, musíme i tak vloži prázdný seznam.
Jak vyřešit zotavení z chyb, když se např. uvede chybný typ proměnných? Použije
se funkce logical_undef(). Tato funkce vrací ukazatel na speciální typ pro
"nedefinovaný typ".
BLOKY
Mechanismus překrývání globálních proměnných globálními za nás udělá tabulka
symbolů. Na konci deklarace hlavičky procedury/funkci je třeba zavolat
funkci tabulky symbolů enter(). Na konci bloku funkci leave(). Volání enter
si v tabulce poznamená pozici. Funkce leave smaže identifikátory až k naposledy
zapamatované pozici. enter() se musí volat až za add_proc, enter() má ještě jako
parametr identifikátor funkce.
STRUKTURY
Podobně jako parametry funkcí/procedur.
field_list * create_add_field_list
type_pointer create_record_type(field_list * pl)
type_pointer je ukazatel na typ zkonstruovaný v tabulce types.
Pozn.: Funkce add_* přidávají do tabulky symbols, create_* do tabulky types.
KONSTANTY
Nově vzniklá konstanta přejímá typ původní konstanty (na pravé straně).
type_pointer.cat() vrací kategorii typu.
Domácí úkol č.4 se testuje na výpise tabulek překladače. K nim se dostaneme
použitím parametru "-B" výsledného překladače.