Program Var_Compiler_1_0; { Autor: Igor CHLADIL ic0092@mendelu.cz Funkce programu: Prekladac promennych. Vstup: blok promennych v pascalovske syntaxi ze standardniho vstupu cely blok musi byt uveden 'var', ktery se tam jiz nesmi vicekrat vyskytnout Vystup: Tabulka promennych s maximalne MaxVar promennymi, je ulozena v TVarTable. Jednotlive promenne jsou v zaznamech typu TVar. Pozadavky: Jsou akceptovany identifikatory zacinajici pismenem/_, dale i cislice. Typ promennych muze byt jeden z uvedenych v TypSez. Funkce: GetSym ziskava ze vstupu dalsi lexikalni jednotku. Neprovadi zadne porovnani, to je nechano na vlastni syntakticke analyze, ktera provadi i semanticke akce. Bezkontextova gramatika, na ktere je program postaven (V hranatych zavorka jsou uvedeny semanticke akce): S ->var [VarTab.Init] A A ->B _A _A->B _A | @ B ->C : identifikator [VarTab.LinkType] D ; C ->identifikator [VarTab.InsVar] _C _C->, identifikator [VarTab.InsVar] _C | @ D ->absolute E | @ E ->identifikator [VarTab.LinkProm] | cislo : cislo [VarTab.LinkAbs] Hezky si to uzijte, a na chyby moc nenadavejte; Iggy } procedure Error(S : String); {Pardon, je to dosti jednoducha reakce na chybu} begin Writeln(S); Halt; end; const MaxSym = 8; MaxVar = 50; MaxTyp = 6; const SymRep:array [0..MaxSym-1] of string = ('id', 'VAR', ',', ';', ':', 'ABSOLUTE', 'num', 'eof'); {Jak se maji symboly jevit} type TSymTyp = (idsym, varsym, comsym, semsym, colsym, abssym, numsym, eofsym); {Jednotlive typy symbolu} SymSet = Set of TSymTyp; procedure ErrorSym(MaByt : SymSet); var I : TSymTyp; begin Write('Ma byt: '); for I:=idsym to eofsym do if I in MaByt then Write(SymRep[ord(I)],' '); Writeln; Halt; end; type TSymbol = record SymTyp : TSymTyp; {syntakticka slozka} Atrib : String[15]; {semanticka slozka ... jmeno atributu} end; var Nacteny : String; NactenyC : Char; {Posledni nacteny znak, pouzit proto, ze nemuzu znak dat zpet na vstup} procedure GetSym(var Sym : TSymbol); {Lexikalni analyzator, vraci TSymboly} var State : Integer; C : Char; begin State := 1; Nacteny := ''; Sym.Atrib:=''; {Osetreni starych vstupnich symbolu} case NactenyC of ':' : Sym.SymTyp:= colsym; ';' : Sym.SymTyp:= semsym; ',' : Sym.SymTyp:= comsym; end; if NactenyC in [',',':',';'] then begin NactenyC:=#0;State:=0 end; if SeekEof and (State<>0) then Sym.SymTyp:=eofSym; {Nacitani novych symbolu} while (not eof) and (State>0) do begin {start ns} Read(NactenyC); NactenyC:=Upcase(NactenyC); Case State of 1 : case NactenyC of {Prvni znak} '_','A'..'Z' : begin State:=2; Nacteny:=Nacteny+NactenyC; end; '0'..'9' : begin State:=3; Nacteny:=Nacteny+NactenyC; end; '$' : begin State:=4; Nacteny:=Nacteny+NactenyC; end; ',',':',';' : begin State:=0; case NactenyC of ':' : Sym.SymTyp:= colsym; ';' : Sym.SymTyp:= semsym; ',' : Sym.SymTyp:= comsym; end; NactenyC:=#0; end; #13, #10, #9, ' ' : State:=1; else Error('Spatny prvni znak ' + NactenyC) end; 2 : case NactenyC of {Identifikator} #13,#10,#9,' ',',',':',';' : begin State:=0; if Nacteny='VAR' then Sym.SymTyp:=varsym else if Nacteny='ABSOLUTE' then Sym.SymTyp:=abssym else begin Sym.SymTyp := idsym; Sym.Atrib := Nacteny; end; end; 'A'..'Z','_','0'..'9' : Nacteny:=Nacteny+NactenyC; else Error('Chybne znaky v retezci ' + Nacteny); end; 3 : case NactenyC of {Dec Cisla} #13,#10,#9,' ',',',':',';' : begin State:=0; Sym.SymTyp:=numsym; Sym.Atrib := Nacteny; end; '0'..'9' : Nacteny:=Nacteny+NactenyC; else Error('Spatne cislo.' + Nacteny) end; 4 : case NactenyC of {Hex. cisla} #13,#10,#9,' ',',',':',';' : begin State:=0; Sym.SymTyp:=numsym; Sym.Atrib := Nacteny; end; '0'..'9','A'..'F' : Nacteny:=Nacteny+NactenyC; else Error('Spatne hexadecimalni cislo ' + Nacteny) end; end; end; {end ns} end; {Konec lexikalniho analyzatoru} type TTypy = record Id : String[15]; Size : Word; end; const TypSez:array [1..MaxTyp] of TTypy = ((Id:'INTEGER'; Size:2), (Id:'WORD'; Size:2), (Id:'STRING'; Size:256), (Id:'POINTER'; Size:4), (Id:'CHAR'; Size:1), (Id:'REAL'; Size:8) ); type TVar = object Id : String [15]; {Jmeno promenne} Typ : Integer; {Typ Promenne} Seg, Ofs : Word; {Adresa} Size : Word; {Velikost promenne .. Absolute=0} JustLinked : Boolean; {Zda-li je jim prave prirazen typ} procedure Clear; {Vynuluje vse} procedure Report; end; procedure TVar.Clear; begin Id:=''; Typ:=0; Seg:=0; Ofs:=0; JustLinked:=False; Size:=0 end; procedure TVar.Report; begin Writeln(Id:18, TypSez[Typ].Id:15, Seg:6,':',Ofs:6, Size:10); end; type PVarTable = ^TVarTable; TVarTable = object Count : Word; LastOfs : Word; LastSeg : Word; Vars : Array [1..MaxVar] of TVar; constructor Init; {Inicializuje tabulku promennych} procedure InsVar(Id : String); {Vlozi promennou daneho jmena} procedure LinkType(Typ : String); {Prilinkuje k vlozenym typ} procedure LinkAbs(ASeg, AOfs : Word); {Urci absolutni adresu} procedure LinkProm(Id : String); {Urci abs. adresu v pripade odkazu na prom.} procedure Report; end; constructor TVarTable.Init; begin Count:=0; LastOfs:=0; LastSeg:=DSeg; end; procedure TVarTable.InsVar; var I : Word; begin if Count=MaxVar then Error('Moc promennych'); if Count>0 then for I:=1 to MaxVar do if Vars[I].Id=Id then Error ('Duplicitni promenna '+Id); Inc(Count); Vars[Count].Clear; Vars[Count].Id:=Id; end; procedure TVarTable.LinkType; var I : Word; NTyp : Integer; begin NTyp:=0; for I:=1 to MaxTyp do if Typ=TypSez[I].Id then Ntyp:=I; if NTyp=0 then Error('Spatny typ '+Typ); for I:=1 to Count do if Vars[I].Typ=0 then with Vars[I] do begin Typ:=NTyp; JustLinked:=True; Size:=TypSez[NTyp].Size; Seg:=LastSeg; Ofs:=LastOfs; Inc(LastOfs, Size); end else Vars[I].JustLinked:=False; {JustLinked pouziji v LinkAbs} end; procedure TVarTable.LinkAbs; var I : Word; begin for I:=1 to Count do if Vars[I].JustLinked then with Vars[I] do begin Seg:=ASeg; Ofs:=AOfs; Dec(LastOfs, Size); Size:=0; JustLinked:=False; end; end; procedure TVarTable.LinkProm; var I : Word; Nalez : Boolean; begin Nalez:=False; for I:=1 to Count do if Vars[I].Id=Id then begin Nalez:=True; if not Vars[I].JustLinked then LinkAbs(Vars[I].Seg,Vars[I].Ofs) else Error('Neplatny odkaz '+Id); end; if not Nalez then Error('Neplatna promenna '+Id); end; procedure TVarTable.Report; var I : Word; Suma : Word; begin Writeln('Identifikator':18, 'Typ':15, 'Seg':6,':','Ofs':6, 'Velikost':10); Suma := 0; for I:=1 to Count do begin Vars[I].Report; Inc(Suma,Vars[I].Size); end; Writeln('Promenne celkem zabiraji ',Suma,'.'); end; var Sym : TSymbol; Tab : TVarTable; (*** Sekce syntakticke analyzy ***) procedure E; var Adr : String; Seg, Ofs : Word; C : Integer; begin case Sym.SymTyp of idsym : begin Tab.LinkProm(Sym.Atrib); {Semanticka akce, nastavi adresu na abs} getsym(Sym); end; numsym: begin Val(Sym.Atrib, Seg, C); GetSym(Sym); if Sym.SymTyp<>colsym then ErrorSym([colsym]); GetSym(Sym); Val(Sym.Atrib, Ofs, C); if Sym.SymTyp=numsym then Tab.LinkAbs(Seg, Ofs) {Semanticka akce, nastavi adresu na abs} else ErrorSym([numsym]); GetSym(Sym); end; else ErrorSym([numsym, idsym]); end; end; procedure D; begin case Sym.SymTyp of abssym : begin getsym(Sym); E; end; semsym : ; else ErrorSym([abssym, semsym]) end; end; procedure _C; begin case Sym.SymTyp of comsym : begin getsym(Sym); if Sym.SymTyp=idSym then Tab.InsVar(Sym.Atrib) {Semanticka akce, vlozi nazev prom} else ErrorSym([idSym]); getsym(Sym); _C; end; colsym : ; else ErrorSym([comsym, colsym]); end; end; procedure C; begin case Sym.SymTyp of idSym : begin Tab.InsVar(Sym.Atrib); {Semanticka akce, vlozi nazev prom} GetSym(Sym); _C; end; else ErrorSym([idSym]); end; end; procedure B; begin case Sym.SymTyp of idSym : begin C; if Sym.SymTyp<>colsym then ErrorSym([colsym]); getsym(Sym); if Sym.SymTyp=idSym then Tab.LinkType(Sym.Atrib) {Semanticka akce, priradi prom typ} else ErrorSym([idsym]); getsym(Sym); D; if Sym.SymTyp<>semsym then ErrorSym([semsym, abssym]); GetSym(Sym); end; else ErrorSym([idsym]); end; end; procedure _A; begin case Sym.SymTyp of idsym : begin B; _A; end; eofsym : ; else ErrorSym([idsym, eofsym]); end; end; procedure A; begin case Sym.SymTyp of idsym : begin B; _A; end; else ErrorSym([idsym]); end; end; procedure S; begin GetSym(Sym); case Sym.SymTyp of varsym : begin Tab.Init; GetSym(Sym);A; end; else ErrorSym([varsym]); end; end; begin NactenyC := #0; {Neni nacten zadny znak} S; {Volam pocatecni symbol} Tab.Report; {Vypisuji vysledky analyzy} end.