(root)/
gcc-13.2.0/
gcc/
m2/
gm2-compiler/
M2StackWord.mod
(* M2StackWord.mod provides a generic stack for WORD sized objects.

Copyright (C) 2001-2023 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.