1 /*
2  * Copyright © 1988-2004 Keith Packard and Bart Massey.
3  * All Rights Reserved.  See the file COPYING in this directory
4  * for licensing information.
5  */
6 
7 #include	<assert.h>
8 
9 #include	"nickle-config.h"
10 #include	"mem.h"
11 #include	"stack.h"
12 
13 static void	stackMark (void *);
14 
15 DataType stackType = { stackMark, 0, "stackType" };
16 
17 DataType stackChunkType = { 0, 0, "stackChunkType" };
18 
19 static void
addChunk(StackObject * stack)20 addChunk (StackObject *stack)
21 {
22     StackChunk	*chunk;
23 
24     if (stack->save)
25     {
26 	chunk = stack->save;
27 	stack->save = 0;
28     }
29     else
30 	chunk = MemAllocate (&stackChunkType, sizeof (StackChunk));
31 
32     chunk->previous = stack->current;
33     stack->current = chunk;
34     STACK_TOP(stack) = CHUNK_MAX(chunk);
35 }
36 
37 StackObject *
StackCreate(void)38 StackCreate (void)
39 {
40     StackObject	*stack;
41 
42     stack = MemAllocate (&stackType, sizeof (StackObject));
43     stack->current = 0;
44     stack->save = 0;
45     stack->temp = 0;
46     stack->stackPointer = 0;
47     TemporaryData = stack;
48     addChunk (stack);
49     TemporaryData = 0;
50     return stack;
51 }
52 
53 void *
StackPush(StackObject * stack,StackElement object)54 StackPush (StackObject *stack, StackElement object)
55 {
56     STACK_ASSERT (stack);
57     if (STACK_TOP(stack) == STACK_MIN(stack))
58     {
59 	stack->temp = object;
60 	addChunk (stack);
61 	stack->temp = 0;
62     }
63     return *--STACK_TOP(stack) = object;
64 }
65 
66 void *
StackPop(StackObject * stack)67 StackPop (StackObject *stack)
68 {
69     STACK_ASSERT (stack);
70     if (STACK_TOP(stack) == STACK_MAX(stack))
71     {
72 	StackChunk  *previous = stack->current->previous;
73 
74 	if (!stack->save)
75 	{
76 	    stack->save = stack->current;
77 	    stack->save->previous = 0;
78 	}
79 	stack->current = previous;
80 	if (!stack->current)
81 	    panic ("Stack underflow\n");
82 	STACK_TOP(stack) = previous->elements;
83     }
84     return *STACK_TOP(stack)++;
85 }
86 
87 void
StackDrop(StackObject * stack,int i)88 StackDrop (StackObject *stack, int i)
89 {
90     int		this;
91     StackChunk	*previous;
92     STACK_ASSERT (stack);
93     while (i)
94     {
95 	this = STACK_MAX(stack) - STACK_TOP(stack);
96 	if (this >= i)
97 	{
98 	    STACK_TOP(stack) += i;
99 	    break;
100 	}
101 	i -= this;
102 	previous = stack->current->previous;
103 
104 	if (!stack->save)
105 	{
106 	    stack->save = stack->current;
107 	    stack->save->previous = 0;
108 	}
109 	stack->current = previous;
110 	if (!stack->current)
111 	    panic ("Stack underflow\n");
112 	STACK_TOP(stack) = CHUNK_MIN(previous);
113     }
114     STACK_ASSERT (stack);
115 }
116 
117 void
StackReset(StackObject * stack,StackPointer stackPointer)118 StackReset (StackObject *stack, StackPointer stackPointer)
119 {
120     STACK_ASSERT (stack);
121     while (!(STACK_TOP(stack) <= stackPointer && stackPointer <= STACK_MAX(stack)))
122     {
123 	StackChunk  *previous = stack->current->previous;
124 
125 	if (!stack->save)
126 	{
127 	    stack->save = stack->current;
128 	    stack->save->previous = 0;
129 	}
130 	stack->current = previous;
131 	if (!stack->current)
132 	    panic ("Stack underflow\n");
133 	STACK_TOP(stack) = CHUNK_MIN(previous);
134     }
135     STACK_TOP(stack) = stackPointer;
136     STACK_ASSERT (stack);
137 }
138 
139 StackElement
StackReturn(StackObject * stack,StackPointer stackPointer,StackElement object)140 StackReturn (StackObject *stack, StackPointer stackPointer, StackElement object)
141 {
142     STACK_ASSERT (stack);
143     STACK_RESET(stack, stackPointer);
144     return STACK_PUSH(stack,object);
145 }
146 
147 StackElement
StackElt(StackObject * stack,int i)148 StackElt (StackObject *stack, int i)
149 {
150     StackChunk	    *chunk;
151     StackPointer    stackPointer;
152 
153     STACK_ASSERT (stack);
154     chunk = stack->current;
155     stackPointer = STACK_TOP(stack);
156     while (stackPointer + i >= CHUNK_MAX(chunk))
157     {
158 	i -= CHUNK_MAX(chunk) - stackPointer;
159 	chunk = chunk->previous;
160 	if (!chunk)
161 	    panic ("StackElt underflow\n");
162 	stackPointer = CHUNK_MIN(chunk);
163     }
164     return stackPointer[i];
165 }
166 
167 StackObject *
StackCopy(StackObject * stack)168 StackCopy (StackObject *stack)
169 {
170     StackObject	*new;
171     StackChunk	*chunk, *nchunk, **prev;
172 
173     STACK_ASSERT (stack);
174     new = StackCreate ();
175     REFERENCE (new);
176     chunk = stack->current;
177     nchunk = new->current;
178     prev = &new->current;
179     while (chunk)
180     {
181 	STACK_ASSERT (new);
182 	STACK_ASSERT (stack);
183 	if (!nchunk)
184 	    nchunk = MemAllocate (&stackChunkType, sizeof (StackChunk));
185 	else
186 	    STACK_TOP(new) = (new->current->elements +
187 			      (STACK_TOP(stack) - stack->current->elements));
188 
189 	/*
190 	 * Copy stack data and fix stack pointer
191 	 */
192 	*nchunk = *chunk;
193 	STACK_CHUNK_ASSERT(chunk->type == &stackChunkType);
194 
195 	/*
196 	 * Link into chain
197 	 */
198 	*prev = nchunk;
199 	prev = &nchunk->previous;
200 	*prev = 0;
201 	chunk = chunk->previous;
202 	nchunk = 0;
203     }
204     STACK_ASSERT (new);
205     return new;
206 }
207 
208 static void
stackMark(void * object)209 stackMark (void *object)
210 {
211     StackObject	    *stack = object;
212     StackChunk	    *chunk;
213     StackPointer    stackPointer;
214 
215     STACK_ASSERT (stack);
216     MemReference (stack->temp);
217     MemReference (stack->save);
218     chunk = stack->current;
219     if (chunk)
220     {
221 	stackPointer = STACK_TOP(stack);
222 	for (;;)
223 	{
224 	    MemReference (chunk);
225 	    while (stackPointer != CHUNK_MAX(chunk))
226 		MemReference (*stackPointer++);
227 	    chunk = chunk->previous;
228 	    if (!chunk)
229 		break;
230 	    stackPointer = CHUNK_MIN(chunk);
231 	}
232     }
233 }
234