blob: 99de4e26c6d21c59ef4551a197c96c356adea57f [file] [log] [blame]
(* M2StackWord.mod provides a generic stack for WORD sized objects.
Copyright (C) 2001-2025 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 M2StackWord ;
FROM Storage IMPORT ALLOCATE, DEALLOCATE ;
FROM M2Error IMPORT InternalError ;
FROM M2Debug IMPORT Assert ;
CONST
MaxBucket = 10 ;
TYPE
StackBucketWord = POINTER TO BucketWord ;
BucketWord = RECORD
bucket: ARRAY [0..MaxBucket-1] OF WORD ;
items : CARDINAL ;
last : StackBucketWord ;
END ;
StackOfWord = POINTER TO StackDescriptor ;
StackDescriptor = RECORD
tail: StackBucketWord ;
END ;
(*
InitStackWord - creates and returns a new stack.
*)
PROCEDURE InitStackWord () : StackOfWord ;
VAR
s: StackOfWord ;
BEGIN
NEW(s) ;
WITH s^ DO
tail := NIL
END ;
RETURN( s )
END InitStackWord ;
(*
KillBucket - destroys a StackBucketWord and returns, NIL.
*)
PROCEDURE KillBucket (b: StackBucketWord) : StackBucketWord ;
BEGIN
IF b#NIL
THEN
b := KillBucket(b^.last) ;
DISPOSE(b)
END ;
RETURN( NIL )
END KillBucket ;
(*
KillStackWord - destroys a stack, returning NIL.
*)
PROCEDURE KillStackWord (s: StackOfWord) : StackOfWord ;
BEGIN
IF s#NIL
THEN
s^.tail := KillBucket(s^.tail) ;
DISPOSE(s)
END ;
RETURN( NIL )
END KillStackWord ;
(*
InitBucket - returns an empty StackBucketWord.
*)
PROCEDURE InitBucket (l: StackBucketWord) : StackBucketWord ;
VAR
b: StackBucketWord ;
BEGIN
NEW(b) ;
WITH b^ DO
items := 0 ;
last := l
END ;
RETURN( b )
END InitBucket ;
(*
PushWord - pushes a word, w, onto, s.
*)
PROCEDURE PushWord (s: StackOfWord; w: WORD) ;
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 PushWord ;
(*
PopWord - pops an element from stack, s.
*)
PROCEDURE PopWord (s: StackOfWord) : WORD ;
VAR
b: StackBucketWord ;
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^.last
END ;
DISPOSE(b)
END ;
WITH s^.tail^ DO
DEC(items) ;
RETURN( bucket[items] )
END
END
END
END PopWord ;
(*
IsEmptyWord - returns TRUE if stack, s, is empty.
*)
PROCEDURE IsEmptyWord (s: StackOfWord) : BOOLEAN ;
BEGIN
RETURN( (s=NIL) OR (s^.tail=NIL) )
END IsEmptyWord ;
(*
PeepWord - returns the element at, n, items below in the stack.
Top of stack can be seen via Peep(s, 1)
*)
PROCEDURE PeepWord (s: StackOfWord; n: CARDINAL) : WORD ;
VAR
b: StackBucketWord ;
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^.last
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^.last
END
END ;
InternalError ('stack underflow')
END
END PeepWord ;
(*
ReduceWord - reduce the stack by n elements.
*)
PROCEDURE ReduceWord (s: StackOfWord; n: CARDINAL) ;
VAR
b: StackBucketWord ;
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^.last
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^.last ;
DISPOSE(b)
END
END
END
END ReduceWord ;
(*
RemoveTop - throw away the top element of the stack.
*)
PROCEDURE RemoveTop (s: StackOfWord) ;
BEGIN
ReduceWord (s, 1)
END RemoveTop ;
(*
NoOfItemsInStackWord - returns the number of items held in the stack, s.
*)
PROCEDURE NoOfItemsInStackWord (s: StackOfWord) : CARDINAL ;
VAR
b: StackBucketWord ;
n: CARDINAL ;
BEGIN
IF IsEmptyWord(s)
THEN
RETURN( 0 )
ELSE
n := 0 ;
b := s^.tail ;
WHILE b#NIL DO
INC(n, b^.items) ;
b := b^.last
END ;
RETURN( n )
END
END NoOfItemsInStackWord ;
END M2StackWord.