% Hj¾lpev¾rkt¿j til brug ved afleveringsopgaven, del 1. % Typecheck og fortolker for PaX %%%%%%%%%%%%%%%%%%%% % Indledende bem¾rkninger: % :- use_module(library(lists)). :- op(800,xfx, :=). %%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % Til typecheck: % symbol_tabel_find(VariabelId, SymbolTabel, Type) symbol_tabel_find(Id, Tabel, Type):- atom(Id), dif(Id, true), dif(Id, false) -> (member((Id,Fundet), Tabel) -> (Fundet = Type -> true ; write('Typefejl for '), write(Id), write(': forventede '), write(Beskriv), write(', fandt '), write(Fundet),nl,abort ) ; write('Fejl: '),write(Id),write(' ikke erkl¾ret'), (var(Beskriv)-> true; write(' med type '),write(Beskriv)), nl, abort) ; write('Illegal term anvendt som variabel: '), write(Id), abort. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % Til fortolkeren %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % Pr¾dikater til at hente og lagre v¾rdier % i rekursionsstakken % % NB: De er ikke s¾rligt effektive fordi de er fyldt op med % alskens fejlkontrol. Hvis dette droppes kan det programmeres % sŒ det fylder en br¿kdel! %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % hent_var(Var, Stak, Vaerdi). % - hvor Var er af form som Atom (for simpel eller array variabel) % eller (Atom, N) for celle N i array'et ved navn Atom % % Fungerer ved, at den kigger efter en Var, f¿rst i % det ¿verste stakafsnit, og hvis den ikke er der, kigges % der efter det nederste (hvis der altsŒ er mere end et). % % Den er fyldt op med en masse kontrol af argumenterne, % som er un¿dvendig, hvis hent_var benyttes fra et % program, som er typechecket med en *korrekt* typechecker! % % Det g¿r den temmelig ineffektiv, men det er en nyttig % opf¿rsel i forbindelse med brug i afleveringsopgave. hent_var(Var,Stak):- legal_rekursionsstak(Stak) -> fail % OK, gaa til de interessante regler ; write('Fors¿g pŒ at hente variabel '), write(Var), write(' i illegal stak: '), write(Stak), abort. % Lokal variabel: (eller global accesses fra "hovedprogram") % Indicering i array: hent_var( Var^Index, [Lokal|_], Vaerdi):- member((Var, _), Lokal), !, hent_array_felt_i_stak_afsnit( Var^Index, Lokal, Vaerdi). % Simpelt variable eller helt array hent_var( Var, [Lokal|_], Vaerdi):- atom(Var), member((Var, Vaerdi), Lokal), !. % Ellers, access til global var fra procedure hent_var( Var, Stak, Vaerdi):- hent_var_globalt( Var, Stak, Vaerdi). hent_var_globalt( Var^Index, [Global], Vaerdi):- !, hent_array_felt_i_stak_afsnit( Var^Index, Global, Vaerdi). hent_var_globalt( Var, [Global], Vaerdi):- member((Var, Vaerdi), Global) -> true ; write('Reference til utilg¾ngelig variabel: '), write(Var), abort. hent_var_globalt( Var, [_|Rest], Vaerdi):- hent_var_globalt( Var, Rest, Vaerdi). %%% hent_array_felt_i_stak_afsnit( Var^Index, Afsnit, Vaerdi):- member((Var, Vektor), Afsnit), (integer(Index) -> ( is_list(Vektor) -> (nth(Index, Vektor, Vaerdi) -> true ; write('Indeksfejl: '),write(Var^Index),abort) ; write('Arrayopslag i simple variabel: '), write(Var^Index),abort) ; write('Illegalt array-indeks: '), write(Var^Index), abort). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % gem_var(Var, Vaerdi, StakF¿r, StakEfter). % % - hvor Var er af form som Atom (for simpel eller array variabel) % eller (Atom, N) for celle N i array'et ved navn ATom % % Fungerer ved, at den kigger efter en Var, f¿rst i % det ¿verste stakafsnit, og hvis den ikke er der, kigges % der efter det nederste (hvis der altsŒ er mere end et). % % % Den er fyldt op med en masse kontrol af argumenterne, % som er un¿dvendig, hvis hent_var benyttes fra et % program, som er typechecket med en *korrekt* typechecker! % % Det g¿r den temmelig ineffektiv, men det er en nyttig % opf¿rsel i forbindelse med brug i afleveringsopgave. gem_var(Var,_,Stak,_):- legal_rekursionsstak(Stak) -> fail % OK, gaa til de interessante regler ; write('Fors¿g pŒ at gemme variabel '), write(Var), write(' i illegal stak: '), write(Stak), abort. gem_var( Var^Index,Vaerdi, [Lokal|Rest], [NyLokal|Rest]):- member((Var, _), Lokal), !, gem_array_felt_i_stak_afsnit( Var^Index,Vaerdi,Lokal,NyLokal). % Simpelt variable eller helt array gem_var( Var, Vaerdi, [Lokal|Rest], [NyLokal|Rest]):- atom(Var), member((Var,_), Lokal), !, gem_var_i_stak_afsnit( Var,Vaerdi,Lokal,NyLokal). % Ellers, access til global var fra procedure gem_var( Var, Vaerdi, Stak, NyStak):- gem_var_globalt( Var, Vaerdi, Stak, NyStak). gem_var_globalt( Var^Index, Vaerdi, [Global], [NyGlobal]):- !, gem_array_felt_i_stak_afsnit( Var^Index, Vaerdi, Global, NyGlobal). gem_var_globalt( Var, Vaerdi, [Global], [NyGlobal]):- member((Var, _), Global) -> !, gem_var_i_stak_afsnit( Var,Vaerdi,Global,NyGlobal) ; write('Reference til utilg¾ngelig variabel: '), write(Var), abort. gem_var_globalt( Var, Vaerdi, [Lokal|Rest], [Lokal|NyRest]):- gem_var_globalt( Var, Vaerdi, Rest, NyRest). %%% gem_var_i_stak_afsnit( Var, NyVaerdi, [(Var,GammelVaerdi)|Rest], [(Var,NyVaerdi)|Rest]):- !, (integer(GammelVaerdi), integer(NyVaerdi) -> true ; member(GammelVaerdi,[true,false]), member(NyVaerdi,[true,false]) -> true ; length(GammelVaerdi,N), length(NyVaerdi,N) -> true ; write('Inkompatibel overskrivning af variabel: '), write(GammelVaerdi), write(' <- '), write(NyVaerdi), abort). gem_var_i_stak_afsnit( VarId, Vaerdi, [Par|Rest], [Par|NyRest]):- gem_var_i_stak_afsnit( VarId, Vaerdi, Rest, NyRest). %%% gem_array_felt_i_stak_afsnit( Var^Index, Vaerdi, [(Var,Array)|Rest], [(Var,NytArray)|Rest]):- !, (integer(Index) -> (is_list(Array) -> !, length(Array, N), ( (Index < 1 ; Index >N) -> write('Indeksfejl: '), write( Var^Index), write('. Tilladt: 1..'),write(N), abort ; erstat_liste_element(Vaerdi, Index, Array, NytArray)) ; write('Arrayopslag i simple variabel: '), write(Var^Index),abort) ; write('Illegalt array-indeks: '), write(Var^Index), abort). gem_array_felt_i_stak_afsnit( Var, Vaerdi, [Par|Rest], [Par|NyRest]):- gem_array_felt_i_stak_afsnit( Var, Vaerdi, Rest, NyRest). %%%%%%%%% erstat_liste_element(NyVaerdi, 1, [GammelVaerdi|L], [NyVaerdi|L]):- !, (integer(GammelVaerdi), integer(NyVaerdi) -> true ; write('Inkompatibel overskrivning af variabel: '), write(GammelVaerdi), write(' <- '), write(NyVaerdi), abort). erstat_liste_element(V, N, [E|L1], [E|L2]):- N1 is N-1, erstat_liste_element(V, N1, L1, L2). %%%%%%%%%%%%%%% % legal_rekursionsstak % % Stakken har mindst en element legal_rekursionsstak(Var):- var(Var), !, fail. legal_rekursionsstak([Afsnit]):- legalt_rekursionsstakafsnit(Afsnit). legal_rekursionsstak([Afsnit|Mere]):- legalt_rekursionsstakafsnit(Afsnit), legal_rekursionsstak(Mere). legalt_rekursionsstakafsnit([]). legalt_rekursionsstakafsnit([(VarId,Vaerdi)|Mere]):- legal_variabel_id(VarId), legal_vaerdi(Vaerdi), legalt_rekursionsstakafsnit(Mere). legal_variabel_id(VarId):- (atom(VarId), \+ member(VarId, [program,var,tom,int,bool,array,proc,';', :=, if, while, repeat, for,write,write_text,nl, true,false,[], '.', +, -, //, =, >, >=, <, =<, =\=, /\, \/, \+, ^ ])) -> true ; write('Illegal variabel identifier: '), write(VarId),nl, fail. legal_vaerdi(Vaerdi):- var(Vaerdi) -> write('Uinstantieret Prolog variabel '), write(Vaerdi), write(' som v¾rdi'),nl, fail ; integer(Vaerdi) -> true ; Vaerdi=true -> true ; Vaerdi=false -> true ; is_list(Vaerdi) -> heltalsliste(Vaerdi) ; write('Illegal v¾rdi: '), write(Vaerdi),nl, fail. heltalsliste([N]):- % mindst en integer(N) -> true ; var(N) -> write('Uinstantieret Prolog variabel '), write(N), write(' som v¾rdi i array'),nl, fail ; write('Illegal v¾rdi i array: '), write(N),nl, fail. heltalsliste([N|Mere]):- integer(N), heltalsliste(Mere).