1 Píklady popisu typických konstrukcí V tomto odstavci se pokusíme ilustrovat denotaní popis sémantiky ve funkcionálním modelu pro typické píklady jazykových konstrukcí. Popisované konstrukce budou fragmenty jazyk PL0 a ILPL0, zjednodušené maximáln pro úely demonstrace. 1.1 Popis sémantiky výraz Jednou ze syntaktických konstrukcí jazyka PL0 jsou výrazy. Uvažme fragment gramatiky, popisující syntaxi výraz. p 1 : Výraz konst p 2 : Výraz ident p 3 : Výraz Výraz + Výraz Výrazy jazyka se skládají ze symbol konstant (jisté signatury), identifikátor promnných a operátoru "+". Nap. zápis "x+1" je správn vytvoený výraz. Každý takový výraz nabývá jisté hodnoty v závislosti na stavu promnných, které se v nm vyskytují. Význam výrazu proto obecn mže záviset na stavu pamti, ve kterém výraz vyhodnocujeme. Uživatel jazyka PL0 má k dispozici pam skládající se z bunk, do nichž lze ukládat celá ísla. Jednotlivé buky pamti (promnné) jsou oznaeny identifikátory. Aktuální stav pamti jazyka PL0 pak lze modelovat jako zobrazení: Pam = Id Val, kde Id je množina pípustných identifikátor a Val je množina pípustných hodnot, tj. Val = Int. Význam výraz závisí na aktuálním stavu pamti a má tedy charakter zobrazení: M Výraz = Pam Val = (Id Val) Val. Sémantika výraz bude zobrazení, které každému výrazu piadí jeho význam, tj. Sem Výraz : Výraz M Výraz. Popíšeme ji sadou sémantických rovností ízenou popisem syntaxe výraz. rp 1 : Sem Výraz [konst] = λp:pam.konst (konstanta oznauje sebe sama, bez ohledu na stav pamti) rp 2 : Sem Výraz [ident] = λp:pam.p(ident) (promnná ve výrazu oznauje obsah píslušné buky pamti) rp 3 : Sem Výraz [v 1 +v 2 ] = λp:pam.sem Výraz [v 1 ](p)+sem Výraz [v 2 ](p) (výraz s operátorem + oznauje souet hodnot operand). Karel Richta 1
1.1.1 Píklad Sémantickou interpretaci výrazu "x+1" získáme: Sem Výraz [x+1] = = λp:pam.(semvýrazx(p)+semvýraz1(p)) = = λp:pam.((λq:pam.q(x))(p)+(λr:pam.1)(p)) = = λp:pam.(p(x)+1). Výrazem tedy bude funkce, jejíž hodnotu pro aktuální stav pamti p získáme jako souet obsahu pamti na adrese x a konstanty 1. Poznámka: Použitý fragment gramatiky popisující syntaxi výraz není jednoznaný, nebo nap. pro výraz "x+y+z" existují dv možné derivace p 3 (p 3 (p 2,p 2 ),p 2 ) a p 3 (p 2,p 3 (p 2,p 2 )). Vzhledem k asociativit sítání však v obou pípadech dospíváme ke stejnému významu. Sem [x+y+z] = λp:pam.sem[x+y](p)+sem[z](p) = = λp:pam.sem[x](p)+sem[y](p)+sem[z](p) = = λp:pam.sem[x](p)+sem[y+z](p) Nejednoznanost této gramatiky pak pi popisu sémantiky není na závadu, naopak pináší zjednodušené vyjádení. Pevod na jednoznanou gramatiku a odpovídající úpravu sémantických rovností ponecháme jako cviení tenái. 1.2 Popis statické sémantiky Jazyk PL0 je kontextový. Jeden z dvod kontextového charakteru jazyka je podmínka, aby každý identifikátor byl nejdíve deklarován a teprve poté použit. Tuto kontextovou závislost korektnosti výskytu identifikátoru nejsme schopni zachytit bezkontextovou gramatikou. Vyjádíme ji proto statickou sémantikou jazyka, jako doplující podmínky k bezkontextové gramatice. Uvažme opt fragment gramatiky: p 4 : Deklarace var ident Pi zpracování deklarace "var x" je nutno si poznamenat, že výskyt identifikátoru x v dalším textu programu je korektní. Rozšííme proto model stavu výpoetních prostedk o tabulku identifikátor: Tab = Id Bool, kde pro t:tab fakt t(x)=true vyjaduje, že identifikátor x již byl deklarován. Významy výraz modelujeme opt zobrazením ze stavu do hodnot. Významy deklarací modelujeme jako zmnu stavu, kdy do tabulky identifikátor zaneseme informaci o píslušné deklaraci. Stav = Pam Tab M výraz = Stav Val M deklarace = Stav Stav. Význam deklarace definujeme: rp 4 : Sem Deklarace [var ident] = λs:stav.<s.1,s.2[ident true]> Karel Richta 2
nebo alternativn zapsáno: rp 4 : Sem Deklarace [var ident](<p,t>) = <p,t[ident true]>. Sémantická rovnost rp 4 vyjaduje fakt, že deklarací "var x" se nemní stav pamti, ale do tabulky identifikátor se deklarace poznamená. Novému modelu je samozejm nutno pizpsobit i ostatní sémantické rovnosti, nap.: rp 2 : Sem Výraz [ident](<p,t>) = if t(ident) then p(ident) else Val {chyba kontextové syntaxe - výskyt nedeklarovaného identifikátoru ve výrazu}. 1.3 Popis sémantiky operaních píkaz Základními operaními píkazy jazyka PL0 jsou piazení, vstup a výstup. Ostatní píkazy slouží pro ízení výpotu, tj. správné uspoádání operaních píkaz tak, aby se dosáhlo zamýšleného efektu programu. Pro každý píkaz použijeme zjednodušený model, nutný pro popis jeho sémantiky. Popis sémantiky piazovacího píkazu musí vyjadovat fakt, že tento píkaz slouží pro zmnu stavu pamti. Nech tedy: p 5 : Píkaz ident := Výraz M píkaz = Pam Pam M Výraz = Pam Val rp 5 : Sem Píkaz [ident := V] = λp:pam.p[ident SemVýraz[V](p)] Pro popis sémantiky vstupu a výstupu musíme rozšíit model stavu o vstupní a výstupní zaízení: Stav = Pam Vstup Výstup. Vstupní i výstupní zaízení použitelná v jazyce PL0 jsou zaízení se sekvenním pístupem bez možnosti návratu. Vstupující i vystupující údaje jsou celá ísla. Stav vstupu proto mžeme modelovat jako posloupnost i Val*, zastupující soubor dosud nepetených dat. Podobn stav výstupu lze modelovat jako posloupnost o Val*, zastupující soubor již zapsaných dat. Vstup = Val* Výstup = Val* Stav = Pam Vstup Výstup. M Píkaz = Stav Stav Zavedeme nový píkaz pro vstup: p 6 : Píkaz read ident Nech <p,i,o> Pam Vstup Výstup je stav ped provedením píkazu "read x". Popis sémantiky píkazu read vyjádí fakt, že píkaz pete jedno íslo ze vstupu a uloží jej na adresu x. Pokud byl vstup, tj. posloupnost i prázdná, dojde pi provádní píkazu read k chyb. Karel Richta 3
rp 6 : Sem Píkaz [read ident](<p,i,o>) = = if not null(i) then <p[ident head(i)],tail(i),o> else chyba(<p,i,o>) {chyba dynamické sémantiky - tení za koncem vstupních dat}, kde chyba je funkce pro hlášení chyb dynamické sémantiky definovaná nap. chyba = λs:stav.s. Pro výstup údaj zavedeme píkaz: p 7 : Píkaz write Výraz Nech opt <p,i,o> je stav ped provedením píkazu "write V". Sémantický efekt píkazu zpsobí pipsání hodnoty výrazu V na konec výstupní posloupnosti o. rp 7 : Sem Píkaz [write V](<p,i,o>) = <p,i,append(o,sem Výraz [V](p))> 1.4 Popis sémantiky ídících píkaz Základní ídící strukturou procedurálních jazyk je zetzení píkaz, nap.: p 8 : Píkaz Píkaz ; Píkaz. Poznámka: Nejednoznanost jsme již diskutovali u výraz. Provedení posloupnosti píkaz "P;Q" znamená nejprve provedení píkazu P a poté píkazu Q. kde: rp 8 : Sem Píkaz [P;Q] = Sem Píkaz [P].SemPíkaz[Q], f.q = λx:t.q(f(x)), pro f,q:t T, je kompozice zobrazení (kompozice zobrazení je asociativní). Strukturované jazyky dále zavádjí strukturované ídící konstrukce - podmínný píkaz a píkaz cyklu. p 9 : Píkaz if Výraz then Píkaz else Píkaz Kvli zjednodušení jsme nezavádli nový neterminální symbol "Logický-výraz". Jako podmínku použijeme test na nulu. rp 9 : Sem Píkaz [if V then P 1 else P 2 ] = = λs:stav.if Sem Výraz [V](s)==0 then Sem Píkaz [P 1 ](s) else Sem Píkaz [P 2 ](s). Podobn zavedeme píkaz cyklu: p 10 : Píkaz while Výraz do Píkaz rp 10 : Sem Píkaz [while V do P] = = λs:stav.if Sem Výraz [V](s)==0 then Sem Píkaz [while V do P](Sem Píkaz [P](s)) else s. S využitím znalostí modelu λ-kalkulu lze ešení této rekurzivní rovnosti zapsat explicitn Karel Richta 4
pomocí operátoru pevného bodu následovn: rp 10 : Sem Píkaz [while V do P] = = fix(λf:(stav Stav).λs:Stav.if Sem Výraz [V](s)==0 then f(sem Píkaz [P](s)) else s). 1.5 Popis sémantiky výjimek Nestrukturované jazyky používají jako základní ídící konstrukci píkaz skoku (podmínného skoku). Obvykle i strukturované jazyky pipouštjí konstrukce pro ešení výjimek, nap. práv píkaz skoku. Popis sémantiky píkazu skoku si vynucuje komplikovanjší sémantický model, než jsme dosud využívali. Uvažme nap. popis sémantiky zetzení píkaz rovností rp 8. Pokud píkaz P v konstrukci "P;Q" bude píkaz skoku, nebude význam konstrukce "P;Q" závislý na významu píkazu Q, ale bude záviset na významu cílového místa skoku P. Rozšime tedy jazyk o možnost oznaení píkaz návštím a o píkaz skoku na návští. p 11 : Píkaz Návští: Píkaz p 12 : Píkaz goto Návští. Pro vyjádení významu píkazu "goto n" bude podstatné, jaký píkaz je oznaen návštím n. Význam skoku bude pímo význam programu, který zaíná píkazem, oznaeným odpovídajícím návštím. Zavedeme proto tabulku význam návští jako zobrazení: Env = (Návští C), kde: C = Stav Stav je model význam program. Tabulku Env budeme nazývat prostedí programu (environment). Pi urení významu konstrukce "goto n;q" budeme ignorovat "normální" pokraování Q a význam najdeme pímo v odpovídajícím prostedí. Pokud ovšem v konstrukci "P;Q" není P píkaz skoku, musíme do celkového významu zapoítat i význam pokraování Q. To nás pivádí k myšlence, abychom význam píkazu popsali pomocí jeho efektu na význam programu, který pipojíme za nj. Bude-li nap. Q píkaz takový, že: c = Sem[Q]: (Stav Stav), pak význam konstrukce "x:=1;q" získáme aplikací c na stav, který vznikne provedením píkazu "x:=1", tj. c(sem[x:=1]). Význam "goto n;q" však na c závislý nebude. Významy píkaz proto popíšeme zobrazením, které bude závislé na prostedí (Env) a významu pokraování píkazu (C). Výsledkem bude opt dvojice: nové prostedí a význam celku. M Píkaz = (Env C Env C) Sem Píkaz : Píkaz (Env C Env C) Nejprve vyjádíme význam píkazu oznaeného návštím: rp 11 : Sem Píkaz [n:p](<e,c>) = Sem Píkaz [P](<e',c>) kde e' = e[n Sem Píkaz [P](<e',c>)]. Karel Richta 5
Návští tedy nemní význam píkazu, ale mní prostedí, ve kterém se význam programu hledá. Píkaz skoku prostedí nemní, ale využívá pro zjištní významu cílového návští. rp 12 : Sem Píkaz [goto a](<e,c>) = <e,e(n)> Skok ignoruje význam pokraování c a pímo vybírá význam z prostedí. Pro nový sémantický model by samozejm bylo nutné upravit i všechny ostatní rovnosti, nap. sémantické rovnosti pro piazení a zetzení píkaz by mly tvar: rp 5 ': Sem Píkaz [ident := V](<e,c>) = <e,λs:stav.c(s[ident Sem Výraz [V](s)])> rp 8 ': Sem Píkaz [P;Q](<e,c>) = Sem Píkaz [P](Sem Píkaz [Q](<e,c>)). V pípadech sémantických rovností jsme nkdy použili rekurze (nap. rp 11 ). Aby bylo použití rekurzivních definic oprávnné, musí být zaruena jejich jednoznaná interpretace. Pi použití doménového modelu λ kalkulu má však každá soustava rekurzivních rovností jednoznané ešení. Karel Richta 6