| (* M2StackAddress.mod provides a generic stack for ADDRESS sized objects. |
| |
| Copyright (C) 2001-2026 Free Software Foundation, Inc. |
| Contributed by Gaius Mulley <gaius.mulley@southwales.ac.uk>. |
| |
| This file is part of GNU Modula-2. |
| |
| GNU Modula-2 is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 3, or (at your option) |
| any later version. |
| |
| GNU Modula-2 is distributed in the hope that it will be useful, but |
| WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with GNU Modula-2; see the file COPYING3. If not see |
| <http://www.gnu.org/licenses/>. *) |
| |
| IMPLEMENTATION MODULE M2StackAddress ; |
| |
| FROM Storage IMPORT ALLOCATE, DEALLOCATE ; |
| FROM M2Error IMPORT InternalError ; |
| FROM M2Debug IMPORT Assert ; |
| |
| CONST |
| MaxBucket = 10 ; |
| |
| TYPE |
| StackBucket = POINTER TO RECORD |
| bucket: ARRAY [0..MaxBucket-1] OF ADDRESS ; |
| items : CARDINAL ; |
| prev : StackBucket ; |
| END ; |
| |
| StackOfAddress = POINTER TO RECORD |
| tail: StackBucket ; |
| END ; |
| |
| |
| (* |
| InitStackAddress - creates and returns a new stack. |
| *) |
| |
| PROCEDURE InitStackAddress () : StackOfAddress ; |
| VAR |
| s: StackOfAddress ; |
| BEGIN |
| NEW (s) ; |
| WITH s^ DO |
| tail := NIL |
| END ; |
| RETURN s |
| END InitStackAddress ; |
| |
| |
| (* |
| KillBucket - destroys a StackBucket and returns, NIL. |
| *) |
| |
| PROCEDURE KillBucket (b: StackBucket) : StackBucket ; |
| BEGIN |
| IF b # NIL |
| THEN |
| b := KillBucket (b^.prev) ; |
| DISPOSE (b) |
| END ; |
| RETURN NIL |
| END KillBucket ; |
| |
| |
| (* |
| KillStackAddress - destroys a stack, returning NIL. |
| *) |
| |
| PROCEDURE KillStackAddress (s: StackOfAddress) : StackOfAddress ; |
| BEGIN |
| IF s#NIL |
| THEN |
| s^.tail := KillBucket (s^.tail) ; |
| DISPOSE (s) |
| END ; |
| RETURN NIL |
| END KillStackAddress ; |
| |
| |
| (* |
| InitBucket - returns an empty StackBucket. |
| *) |
| |
| PROCEDURE InitBucket (l: StackBucket) : StackBucket ; |
| VAR |
| b: StackBucket ; |
| BEGIN |
| NEW(b) ; |
| WITH b^ DO |
| items := 0 ; |
| prev := l |
| END ; |
| RETURN( b ) |
| END InitBucket ; |
| |
| |
| (* |
| PushAddress - pushes a word, w, onto, s. |
| *) |
| |
| PROCEDURE PushAddress (s: StackOfAddress; w: ADDRESS) ; |
| BEGIN |
| IF s=NIL |
| THEN |
| InternalError ('stack has not been initialized') |
| ELSE |
| WITH s^ DO |
| IF (tail=NIL) OR (tail^.items=MaxBucket) |
| THEN |
| tail := InitBucket(tail) |
| END ; |
| WITH tail^ DO |
| IF items<MaxBucket |
| THEN |
| bucket[items] := w ; |
| INC(items) |
| END |
| END |
| END |
| END |
| END PushAddress ; |
| |
| |
| (* |
| PopAddress - pops an element from stack, s. |
| *) |
| |
| PROCEDURE PopAddress (s: StackOfAddress) : ADDRESS ; |
| VAR |
| b: StackBucket ; |
| BEGIN |
| IF s=NIL |
| THEN |
| InternalError ('stack has not been initialized') |
| ELSE |
| IF s^.tail=NIL |
| THEN |
| InternalError ('stack underflow') |
| ELSE |
| IF s^.tail^.items=0 |
| THEN |
| b := s^.tail ; |
| IF b=NIL |
| THEN |
| InternalError ('stack underflow') |
| ELSE |
| s^.tail := b^.prev |
| END ; |
| DISPOSE(b) |
| END ; |
| IF s^.tail = NIL |
| THEN |
| InternalError ('stack underflow') |
| ELSE |
| WITH s^.tail^ DO |
| DEC(items) ; |
| RETURN( bucket[items] ) |
| END |
| END |
| END |
| END |
| END PopAddress ; |
| |
| |
| (* |
| IsEmptyAddress - returns TRUE if stack, s, is empty. |
| *) |
| |
| PROCEDURE IsEmptyAddress (s: StackOfAddress) : BOOLEAN ; |
| BEGIN |
| RETURN( (s=NIL) OR (s^.tail=NIL) ) |
| END IsEmptyAddress ; |
| |
| |
| (* |
| PeepAddress - returns the element at, n, items below in the stack. |
| Top of stack can be seen via Peep(s, 1) |
| *) |
| |
| PROCEDURE PeepAddress (s: StackOfAddress; n: CARDINAL) : ADDRESS ; |
| VAR |
| b: StackBucket ; |
| BEGIN |
| IF s^.tail=NIL |
| THEN |
| InternalError ('stack underflow') |
| ELSE |
| IF s^.tail^.items=0 |
| THEN |
| b := s^.tail ; |
| IF b=NIL |
| THEN |
| InternalError ('stack underflow') |
| ELSE |
| s^.tail := b^.prev |
| END ; |
| DISPOSE(b) |
| END ; |
| b := s^.tail ; |
| WHILE n>=1 DO |
| IF b=NIL |
| THEN |
| InternalError ('stack underflow') |
| ELSIF b^.items>=n |
| THEN |
| RETURN( b^.bucket[b^.items-n] ) |
| ELSE |
| Assert(b^.items<n) ; |
| DEC(n, b^.items) ; |
| b := b^.prev |
| END |
| END ; |
| InternalError ('stack underflow') |
| END |
| END PeepAddress ; |
| |
| |
| (* |
| ReduceAddress - reduce the stack by n elements. |
| *) |
| |
| PROCEDURE ReduceAddress (s: StackOfAddress; n: CARDINAL) ; |
| VAR |
| b: StackBucket ; |
| BEGIN |
| IF s^.tail=NIL |
| THEN |
| InternalError ('stack underflow') |
| ELSE |
| IF s^.tail^.items=0 |
| THEN |
| b := s^.tail ; |
| IF b=NIL |
| THEN |
| InternalError ('stack underflow') |
| ELSE |
| s^.tail := b^.prev |
| END ; |
| DISPOSE(b) |
| END ; |
| LOOP |
| IF s^.tail=NIL |
| THEN |
| InternalError ('stack underflow') |
| ELSIF s^.tail^.items>=n |
| THEN |
| DEC( s^.tail^.items, n) ; |
| RETURN (* all done exit *) |
| ELSE |
| b := s^.tail ; |
| DEC(n, b^.items) ; |
| s^.tail := s^.tail^.prev ; |
| DISPOSE(b) |
| END |
| END |
| END |
| END ReduceAddress ; |
| |
| |
| (* |
| NoOfItemsInStackAddress - returns the number of items held in the stack, s. |
| *) |
| |
| PROCEDURE NoOfItemsInStackAddress (s: StackOfAddress) : CARDINAL ; |
| VAR |
| b: StackBucket ; |
| n: CARDINAL ; |
| BEGIN |
| IF IsEmptyAddress(s) |
| THEN |
| RETURN( 0 ) |
| ELSE |
| n := 0 ; |
| b := s^.tail ; |
| WHILE b#NIL DO |
| INC (n, b^.items) ; |
| b := b^.prev |
| END ; |
| RETURN( n ) |
| END |
| END NoOfItemsInStackAddress ; |
| |
| |
| END M2StackAddress. |