A hagyományos értelemben vett verem speciális célorientált kiterjesztésekkel
és potenciálisan végtelen hosszal. A modul generikus, azaz a verem elemeinek
megszorítás nélküli típusa paraméterként szerepel.
Az elemeket kötegeljük, s az egyes kötegeket (oldalakat) ábrázoljuk
egy láncolt verem-struktúrában. A kötegek tárolását a Page Stack modul
végzi, s itt "csak" az elemek kötegeken belüli kezelése valósul meg. A
kötegelésnek tisztán hatékonysági célja van! A kötegek mérete ugyancsak
generikus paraméter.
Újdonság a virtuális verem-műveletek halmaza,
és az aktuális veremmutatók eltárolásának lehetősége.
A virtuális műveletek egy nem üres vermen
alkalmazhatók. A VReset függvény hívásával kell a virtuális műveletek végrehajtását
elkezdeni. A virtuális pop a verem tetején levő
elemet leveszi (és visszaszolgáltatja), s onnan virtuálisan törli, de fizikailag
nem. Ezzel a verem egy olyan virtuális állapotba kerül, melynek hossza
egyel kisebb a valódi hosszánál (illetve annyival, ahány virtuális Pop
műveletet csináltunk...) és elemei a tényleges verem elemeinek kezdőszeletét
képezi. A VEmtpy az üres virtuális állapotba hozza a vermet. Közvetlen
ezután a VPop nem alkalmazható eredményesen, de a VPush igen. Általánosságban
a VPush használatával a virtuális verem mérete növelhető
meg egy, a veremben ténylegesen létező, s a virtuális verem vége utáni
pozícióban levő elemmel, ezzel párhuzamosan visszaadja az adott elemet
a visszatérési érétkében. Tehát a VPush akkor használható, ha a
virtuális hossz kisebb a fizikai hossznál. A VTop ezek után már nyilvánvaló
hatást gyakorol a virtuális veremre: kiolvassa ugyanazt az elemet, mint
a VPop, de nem veszi ki onnan, sem fizikailag,
sem virtuálisan.
Könnyen meggondolható, hogy a valódi verem-műveleteket
kombinálva a virtuálisokkal egy kvázi-sorszerkezet is megvalósitható.
A verem állapotát egy futás közben dinamikusan
változó méretű tömbben tároljuk, veremszerű elérhetőséggel. Itt tehát valóban
kihasználjuk a CLU speciális tulajdonságát.
Ha a PushState művelet után bármikor meghívjuk
a RestoreState műveletet, az megpróbálja beállítani a legutoljára
elmentett értéket. Ez (ebben a verzióban) csak akkor lesz sikeres, ha az
óta több Push volt, mint Pop. Ekkor ugyanis mident kitöröl a tárolt határig
bezálólag a verem aktuális tetejétől kezdve.
(Ez ideális lesz a szimbólum-táblához, hisz ott nincs Pop). Végül
a VRestoreState egy virtuális RestoreState: nem törli ugyan a legutolsó
tárolt állapotot, de a virtuális állapotot erre állítja be.
Vigyázat! A modul jelen verziójában (Internal Version Number 1.30CLU) még rendkívűl sok veszélyforrást rejt magában a virtuális verem-műveletek nem kellően átgondolt használata, azonban kellő körültekintés mellett igen széles a lehetőségek skálája.
Megjegyzés: látható, hogy definiálhatjuk és használhatjuk a típus-implementációs modulokban is a standard outputot esetleges nyomkövetési információk kijelzésére. Ennek legkézenfekvőbb módja, ha "globális" változóként definiáljuk a stream-et. Erre a célra pedig nem más, mint az own kulcsszó alkalmas...
TStack=cluster [Elmt:type,PageSize:int] is Create, Push, Pop, Top, Empty, IsEmpty, VReset, VEmpty, VPush, VPop, VTop, PushState, RestoreState, VRestoreState TStackState=record [ Element:int, CurrentPage:int, CurrentIndex:int ] TSymbolStack=record [ Element:int, % Number of element DefElement:Elmt, Pages:TStackPage[Elmt,PageSize], CurrentPage:int, CurrentIndex:int, Virtual:TStackState, States:array[TStackState] ] rep=variant[Stack:TSymbolStack, Empty:null] % own out:stream := stream$primary_output() %for debug reasons % ---------------------[ Create ]---------------------------- Create = proc (E:Elmt) returns (cvt) return(rep$make_Stack(TSymbolStack${ Element:0, DefElement:E, Pages:TStackPage[Elmt,PageSize]$Create(), CurrentPage:-1, CurrentIndex:PageSize-1, Virtual:TStackState${Element:0, CurrentPage:-1, CurrentIndex:PageSize-1 }, States:array[TStackState]$Create(0)})) end Create % ---------------------[ Push ]----------------------------- Push = proc (Stack:cvt,e:Elmt) returns (Elmt) St:TSymbolStack:=rep$value_Stack(Stack) if (St.CurrentIndex=PageSize-1) then % stream$puts(out,"Calling AddPage by Push...\n") %for debug St.Pages:=TStackPage[Elmt,PageSize]$AddPage(St.Pages) St.CurrentPage:=St.CurrentPage+1 St.CurrentIndex:=0 else St.CurrentIndex:=St.CurrentIndex+1 end TStackPage[Elmt,PageSize]$PutIntoLast(St.Pages,St.CurrentIndex,e) St.Element:=St.Element+1 return (e) end Push % ---------------------[ Pop ]------------------------ Pop = proc (Stack:cvt) returns (Elmt) signals (ST_NullStack) St:TSymbolStack:=rep$value_Stack(Stack) ret:Elmt if (St.Element=0) then signal ST_NullStack end ret:=TStackPage[Elmt,PageSize]$GetFromLast(St.Pages,St.CurrentIndex) St.Element:=St.Element-1 if (St.CurrentIndex=0) then St.Pages:=TStackPage[Elmt,PageSize]$DelPage(St.Pages) St.CurrentPage:=St.CurrentPage-1 St.CurrentIndex:=PageSize-1 else St.CurrentIndex:=St.CurrentIndex-1 end return (ret) end Pop % ---------------------[ Top ]------------------------------ Top = proc (Stack:cvt) returns (Elmt) signals (ST_NullStack) St:TSymbolStack:=rep$value_Stack(Stack) ret:Elmt if (St.Element=0) then signal ST_NullStack end ret:=TStackPage[Elmt,PageSize]$GetFromLast(St.Pages,St.CurrentIndex) return (ret) end Top % -----------------------[ Empty ]------------------------- Empty = proc (Stack:cvt) St:TSymbolStack:=rep$value_Stack(Stack) while bool$not(TStackPage[Elmt,PageSize]$IsEmpty(St.Pages)) do St.Pages:=TStackPage[Elmt,PageSize]$DelPage(St.Pages) end St.Element:=0 St.Pages:=TStackPage[Elmt,PageSize]$Create() St.CurrentPage:=-1 St.CurrentIndex:=PageSize-1 end Empty % -----------------------[ IsEmpty ]----------------------- IsEmpty = proc (Stack:cvt) returns (bool) return (rep$value_Stack(Stack).Element=0) end IsEmpty % ----------------------[ PushState ]---------------------- PushState = proc (Stack:cvt) St:TSymbolStack:=rep$value_Stack(Stack) State:TStackState State:=TStackState${Element:St.Element, CurrentPage:St.CurrentPage, CurrentIndex:St.CurrentIndex} Array[TStackState]$addh(St.States,State) end PushState % -------------------[ RestoreState ]---------------------- RestoreState = proc (Stack:cvt) signals (ST_NoMoreState) St:TSymbolStack:=rep$value_Stack(Stack) State:TStackState State:=Array[TStackState]$remh(St.States) while State.CurrentPage<St.CurrentPage do St.Pages:=TStackPage[Elmt,PageSize]$DelPage(St.Pages) St.CurrentPage:=St.CurrentPage-1 end St.CurrentIndex:=State.CurrentIndex St.Element:=State.Element end RestoreState % -------------------[ VRestoreState ]--------------------- VRestoreState = proc (Stack:cvt) signals (ST_NoMoreState) St:TSymbolStack:=rep$value_Stack(Stack) State:TStackState:=Array[TStackState]$top(St.States) St.Virtual.CurrentIndex:=State.CurrentIndex St.Virtual.CurrentPage:=State.CurrentPage St.Virtual.Element:=State.Element end VRestoreState % ----------------------[ VReset ]------------------------- VReset = proc (Stack:cvt) St:TSymbolStack:=rep$value_Stack(Stack) St.Virtual.Element:=St.Element St.Virtual.CurrentIndex:=St.CurrentIndex St.Virtual.CurrentPage:=St.CurrentPage end VReset % -----------------------[ VEmpty ]------------------------ VEmpty = proc (Stack:cvt) St:TSymbolStack:=rep$value_Stack(Stack) St.Virtual.Element:=0 St.Virtual.CurrentPage:=-1 St.Virtual.CurrentIndex:=PageSize-1 end VEmpty % ------------------------[ VPush ]------------------------- VPush = proc (Stack:cvt) returns (Elmt) signals (ST_VPushOverFlow) St:TSymbolStack:=rep$value_Stack(Stack) if (St.CurrentIndex=St.Virtual.CurrentIndex) & (St.CurrentPage=St.Virtual.CurrentPage) then signal ST_VPushOverflow end if (St.Virtual.CurrentPage=-1) then % after VEmpty ! St.Virtual.CurrentPage:=0 St.Virtual.CurrentIndex:=0 else if (St.Virtual.CurrentIndex=PageSize-1) then St.Virtual.CurrentPage:=St.Virtual.CurrentPage+1 St.Virtual.CurrentIndex:=0 else St.Virtual.CurrentIndex:=St.Virtual.CurrentIndex+1 end end St.Virtual.Element:=St.Virtual.Element+1 return (TStackPage[Elmt,PageSize]$GetFrom(St.Pages,St.Virtual.CurrentPage,St.Virtual.CurrentIndex)) end VPush % -----------------------[ VPop ]-------------------------- VPop = proc (Stack:cvt) returns (Elmt) signals (ST_NullVStack) St:TSymbolStack:=rep$value_Stack(Stack) ret:Elmt if (St.Virtual.Element=0) then signal ST_NullVStack end ret:=TStackPage[Elmt,PageSize]$GetFrom(St.Pages,St.Virtual.CurrentPage,St.Virtual.CurrentIndex) St.Virtual.Element:=St.Virtual.Element-1 if (St.Virtual.CurrentIndex=0) then St.Virtual.CurrentPage:=St.Virtual.CurrentPage-1 St.Virtual.CurrentIndex:=PageSize-1 else St.Virtual.CurrentIndex:=St.Virtual.CurrentIndex-1 end return (ret) end VPop % -----------------------[ VTop ]-------------------------- VTop = proc (Stack:cvt) returns (Elmt) signals (ST_NullVStack) St:TSymbolStack:=rep$value_Stack(Stack) ret:Elmt if (St.Virtual.Element=0) then signal ST_NullVStack end ret:=TStackPage[Elmt,PageSize]$GetFrom(St.Pages,St.Virtual.CurrentPage,St.Virtual.CurrentIndex) return (ret) end VTop end TStack
Készítette Bodnát Imre.