/[cvs]/stack/stack.c
ViewVC logotype

Annotation of /stack/stack.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.24 - (hide annotations)
Sat Feb 2 19:30:07 2002 UTC (22 years, 2 months ago) by masse
Branch: MAIN
Changes since 1.23: +25 -15 lines
File MIME type: text/plain
Added possibility to make empty lists.

1 masse 1.1 /* printf */
2     #include <stdio.h>
3     /* EXIT_SUCCESS */
4     #include <stdlib.h>
5     /* NULL */
6     #include <stddef.h>
7 teddy 1.3 /* dlopen, dlsym, dlerror */
8 masse 1.1 #include <dlfcn.h>
9 teddy 1.18 /* assert */
10     #include <assert.h>
11 masse 1.1
12     #define HASHTBLSIZE 65536
13    
14     typedef struct stack_item
15     {
16 masse 1.16 enum {
17     value, /* Integer */
18 teddy 1.18 string,
19     ref, /* Reference (to an element in the
20     hash table) */
21 masse 1.16 func, /* Function pointer */
22     symbol,
23     list
24 teddy 1.18 } type; /* Type of stack element */
25    
26 masse 1.1 union {
27 masse 1.16 void* ptr; /* Pointer to the content */
28     int val; /* ...or an integer */
29     } content; /* Stores a pointer or an integer */
30 masse 1.1
31 masse 1.16 char* id; /* Symbol name */
32     struct stack_item* next; /* Next element */
33 masse 1.1 } stackitem;
34    
35    
36 masse 1.16 typedef stackitem* hashtbl[HASHTBLSIZE]; /* Hash table declaration */
37 teddy 1.18 typedef void (*funcp)(stackitem**); /* funcp is a pointer to a
38     void function (stackitem **) */
39 masse 1.14
40 teddy 1.18 /* Initialize a newly created hash table. */
41 masse 1.1 void init_hashtbl(hashtbl out_hash)
42     {
43     long i;
44    
45     for(i= 0; i<HASHTBLSIZE; i++)
46     out_hash[i]= NULL;
47     }
48    
49 masse 1.14 /* Returns a pointer to an element in the hash table. */
50 masse 1.1 stackitem** hash(hashtbl in_hashtbl, const char* in_string)
51     {
52     long i= 0;
53     unsigned long out_hash= 0;
54 teddy 1.18 char key= '\0';
55 masse 1.1 stackitem** position;
56    
57 masse 1.16 while(1){ /* Hash in_string */
58 masse 1.1 key= in_string[i++];
59     if(key=='\0')
60     break;
61     out_hash= out_hash*32+key;
62     }
63    
64     out_hash= out_hash%HASHTBLSIZE;
65     position= &(in_hashtbl[out_hash]);
66    
67 teddy 1.18 while(position != NULL){
68     if(*position==NULL) /* If empty */
69 masse 1.1 return position;
70    
71 teddy 1.18 if(strcmp(in_string, (*position)->id)==0) /* If match */
72 masse 1.1 return position;
73    
74 masse 1.16 position= &((*position)->next); /* Try next */
75 masse 1.1 }
76 teddy 1.18 return NULL; /* end of list reached without finding
77     an empty position */
78 masse 1.1 }
79    
80 masse 1.14 /* Generic push function. */
81 masse 1.1 int push(stackitem** stack_head, stackitem* in_item)
82     {
83     in_item->next= *stack_head;
84     *stack_head= in_item;
85     return 1;
86     }
87    
88 masse 1.14 /* Push a value on the stack. */
89 masse 1.1 int push_val(stackitem** stack_head, int in_val)
90     {
91     stackitem* new_item= malloc(sizeof(stackitem));
92 teddy 1.18 assert(new_item != NULL);
93 masse 1.1 new_item->content.val= in_val;
94     new_item->type= value;
95    
96     push(stack_head, new_item);
97     return 1;
98     }
99    
100 masse 1.14 /* Copy a string onto the stack. */
101 masse 1.1 int push_cstring(stackitem** stack_head, const char* in_string)
102     {
103     stackitem* new_item= malloc(sizeof(stackitem));
104     new_item->content.ptr= malloc(strlen(in_string)+1);
105     strcpy(new_item->content.ptr, in_string);
106     new_item->type= string;
107    
108     push(stack_head, new_item);
109     return 1;
110     }
111    
112 masse 1.14 /* Create a new hash entry. */
113 masse 1.1 int mk_hashentry(hashtbl in_hashtbl, stackitem* in_item, const char* id)
114     {
115     in_item->id= malloc(strlen(id)+1);
116    
117     strcpy(in_item->id, id);
118     push(hash(in_hashtbl, id), in_item);
119    
120     return 1;
121     }
122    
123 teddy 1.18 /* Define a new function in the hash table. */
124 masse 1.1 void def_func(hashtbl in_hashtbl, funcp in_func, const char* id)
125     {
126     stackitem* temp= malloc(sizeof(stackitem));
127    
128     temp->type= func;
129     temp->content.ptr= in_func;
130    
131     mk_hashentry(in_hashtbl, temp, id);
132     }
133    
134 masse 1.14 /* Define a new symbol in the hash table. */
135 masse 1.4 void def_sym(hashtbl in_hashtbl, const char* id)
136     {
137     stackitem* temp= malloc(sizeof(stackitem));
138    
139     temp->type= symbol;
140     mk_hashentry(in_hashtbl, temp, id);
141     }
142    
143 masse 1.14 /* Push a reference to an entry in the hash table onto the stack. */
144 masse 1.1 int push_ref(stackitem** stack_head, hashtbl in_hash, const char* in_string)
145     {
146 masse 1.6 static void* handle= NULL;
147 masse 1.1 void* symbol;
148 masse 1.6
149 masse 1.1 stackitem* new_item= malloc(sizeof(stackitem));
150     new_item->content.ptr= *hash(in_hash, in_string);
151     new_item->type= ref;
152    
153 masse 1.16 if(new_item->content.ptr==NULL) { /* If hash entry empty */
154     if(handle==NULL) /* If no handle */
155 masse 1.9 handle= dlopen(NULL, RTLD_LAZY);
156 masse 1.6
157 masse 1.16 symbol= dlsym(handle, in_string); /* Get function pointer */
158     if(dlerror()==NULL) /* If existing function pointer */
159     def_func(in_hash, symbol, in_string); /* Store function pointer */
160 masse 1.4 else
161 masse 1.16 def_sym(in_hash, in_string); /* Make symbol */
162 masse 1.4
163 masse 1.23 new_item->content.ptr= *hash(in_hash, in_string); /* The new reference
164     shouldn't point at
165     NULL */
166 masse 1.4 new_item->type= ref;
167 masse 1.1 }
168    
169     push(stack_head, new_item);
170     return 1;
171     }
172    
173 masse 1.17 void printerr(const char* in_string) {
174     fprintf(stderr, "Err: %s\n", in_string);
175     }
176    
177 masse 1.14 /* Discard the top element of the stack. */
178 masse 1.1 extern void toss(stackitem** stack_head)
179     {
180     stackitem* temp= *stack_head;
181    
182 masse 1.17 if((*stack_head)==NULL) {
183     printerr("Stack empty");
184 masse 1.7 return;
185 masse 1.17 }
186 masse 1.7
187     if((*stack_head)->type==string)
188     free((*stack_head)->content.ptr);
189    
190 masse 1.1 *stack_head= (*stack_head)->next;
191     free(temp);
192     }
193    
194 masse 1.14 /* Print newline. */
195 masse 1.8 extern void nl()
196     {
197     printf("\n");
198     }
199 masse 1.1
200 masse 1.14 /* Prints the top element of the stack. */
201 masse 1.23 extern void print_(stackitem** stack_head)
202 masse 1.8 {
203 masse 1.23 stackitem* temp= *stack_head;
204    
205     if(temp==NULL) {
206 masse 1.17 printerr("Stack empty");
207 masse 1.8 return;
208 masse 1.17 }
209 masse 1.1
210 masse 1.23 while(temp->type==ref)
211     temp= temp->content.ptr;
212    
213     switch(temp->type) {
214 teddy 1.2 case value:
215 masse 1.23 printf("%d", temp->content.val);
216 teddy 1.2 break;
217     case string:
218 masse 1.23 printf("\"%s\"", (char*)temp->content.ptr);
219 teddy 1.2 break;
220 masse 1.23 case symbol:
221     printf("%s", temp->id);
222 masse 1.6 break;
223 masse 1.7 default:
224 masse 1.23 printf("%p", temp->content.ptr);
225 teddy 1.2 break;
226     }
227 masse 1.1 }
228    
229 masse 1.14 /* Prints the top element of the stack and then discards it. */
230 masse 1.8 extern void print(stackitem** stack_head)
231     {
232 masse 1.11 print_(stack_head);
233 masse 1.8 toss(stack_head);
234     }
235    
236 masse 1.14 /* Only to be called by function printstack. */
237 masse 1.8 void print_st(stackitem* stack_head, long counter)
238     {
239     if(stack_head->next != NULL)
240     print_st(stack_head->next, counter+1);
241    
242     printf("%ld: ", counter);
243 masse 1.11 print_(&stack_head);
244 masse 1.8 nl();
245     }
246    
247 masse 1.14 /* Prints the stack. */
248 masse 1.1 extern void printstack(stackitem** stack_head)
249     {
250     if(*stack_head != NULL) {
251     print_st(*stack_head, 1);
252 masse 1.21 nl();
253 masse 1.17 } else {
254     printerr("Stack empty");
255 masse 1.1 }
256     }
257    
258 masse 1.14 /* If the top element is a reference, determine if it's a reference to a
259 masse 1.16 function, and if it is, toss the reference and execute the function. */
260 masse 1.1 extern void eval(stackitem** stack_head)
261     {
262     funcp in_func;
263 masse 1.22 stackitem* temp= *stack_head;
264 masse 1.1
265 masse 1.22 if(temp==NULL) {
266     printerr("Stack empty");
267 masse 1.1 return;
268 masse 1.17 }
269 masse 1.1
270 masse 1.22 while(temp->type==ref)
271     temp= temp->content.ptr;
272    
273     if(temp->type==func) {
274     in_func= (funcp)(temp->content.ptr);
275 masse 1.1 toss(stack_head);
276     (*in_func)(stack_head);
277     return;
278 masse 1.22 }
279    
280     printerr("Couldn't evaluate");
281 masse 1.1 }
282    
283 masse 1.19 /* Make a list. */
284     extern void pack(stackitem** stack_head)
285     {
286     void* delimiter;
287     stackitem *iterator, *temp, *pack;
288    
289     delimiter= (*stack_head)->content.ptr; /* Get delimiter */
290     toss(stack_head);
291    
292     iterator= *stack_head;
293    
294 masse 1.24 if(iterator==NULL || iterator->content.ptr==delimiter) {
295     temp= NULL;
296 masse 1.19 toss(stack_head);
297 masse 1.24 } else {
298     /* Search for first delimiter */
299     while(iterator->next!=NULL && iterator->next->content.ptr!=delimiter)
300     iterator= iterator->next;
301    
302     /* Extract list */
303     temp= *stack_head;
304     *stack_head= iterator->next;
305     iterator->next= NULL;
306    
307     if(*stack_head!=NULL && (*stack_head)->content.ptr==delimiter)
308     toss(stack_head);
309     }
310 masse 1.19
311     /* Push list */
312     pack= malloc(sizeof(stackitem));
313     pack->type= list;
314     pack->content.ptr= temp;
315    
316     push(stack_head, pack);
317     }
318    
319 masse 1.14 /* Parse input. */
320 masse 1.1 int stack_read(stackitem** stack_head, hashtbl in_hash, char* in_line)
321     {
322     char *temp, *rest;
323     int itemp;
324     size_t inlength= strlen(in_line)+1;
325     int convert= 0;
326 masse 1.20 static int non_eval_flag= 0;
327 masse 1.1
328     temp= malloc(inlength);
329     rest= malloc(inlength);
330    
331 masse 1.15 do {
332 masse 1.16 /* If string */
333 masse 1.15 if((convert= sscanf(in_line, "\"%[^\"\n\r]\" %[^\n\r]", temp, rest))) {
334     push_cstring(stack_head, temp);
335     break;
336     }
337 masse 1.16 /* If value */
338 masse 1.15 if((convert= sscanf(in_line, "%d %[^\n\r]", &itemp, rest))) {
339     push_val(stack_head, itemp);
340     break;
341     }
342 masse 1.16 /* Escape ';' with '\' */
343 masse 1.15 if((convert= sscanf(in_line, "\\%c%[^\n\r]", temp, rest))) {
344     temp[1]= '\0';
345     push_ref(stack_head, in_hash, temp);
346     break;
347     }
348 masse 1.16 /* If symbol */
349 masse 1.21 if((convert= sscanf(in_line, "%[^][ ;\n\r]%[^\n\r]", temp, rest))) {
350 masse 1.15 push_ref(stack_head, in_hash, temp);
351     break;
352     }
353 masse 1.19 /* If single char */
354     if((convert= sscanf(in_line, "%c%[^\n\r]", temp, rest))) {
355     if(*temp==';') {
356 masse 1.21 if(!non_eval_flag) {
357 masse 1.20 eval(stack_head); /* Evaluate top element */
358     break;
359     }
360    
361     push_ref(stack_head, in_hash, ";");
362 masse 1.19 break;
363     }
364    
365     if(*temp==']') {
366     push_ref(stack_head, in_hash, "[");
367     pack(stack_head);
368 masse 1.21 if(non_eval_flag!=0)
369     non_eval_flag--;
370 masse 1.20 break;
371     }
372    
373     if(*temp=='[') {
374     push_ref(stack_head, in_hash, "[");
375     non_eval_flag++;
376 masse 1.19 break;
377     }
378 masse 1.15 }
379     } while(0);
380    
381 masse 1.1
382     free(temp);
383    
384     if(convert<2) {
385     free(rest);
386     return 0;
387     }
388    
389     stack_read(stack_head, in_hash, rest);
390    
391     free(rest);
392     return 1;
393 masse 1.7 }
394 masse 1.1
395 masse 1.16 /* Relocate elements of the list on the stack. */
396 masse 1.8 extern void expand(stackitem** stack_head)
397 masse 1.1 {
398 masse 1.8 stackitem *temp, *new_head;
399    
400 masse 1.16 /* Is top element a list? */
401 masse 1.17 if((*stack_head)==NULL || (*stack_head)->type!=list) {
402     printerr("Stack empty or not a list");
403 masse 1.8 return;
404 masse 1.17 }
405 masse 1.8
406 masse 1.16 /* The first list element is the new stack head */
407 masse 1.8 new_head= temp= (*stack_head)->content.ptr;
408     toss(stack_head);
409    
410 masse 1.24 if(temp==NULL)
411     return;
412    
413 masse 1.16 /* Search the end of the list */
414 masse 1.8 while(temp->next!=NULL)
415     temp= temp->next;
416    
417 masse 1.16 /* Connect the the tail of the list with the old stack head */
418 masse 1.8 temp->next= *stack_head;
419 masse 1.16 *stack_head= new_head; /* ...and voila! */
420 teddy 1.5 }
421    
422 masse 1.14 /* Swap the two top elements on the stack. */
423 masse 1.10 extern void swap(stackitem** stack_head)
424     {
425     stackitem* temp= (*stack_head);
426    
427 masse 1.17 if((*stack_head)==NULL) {
428     printerr("Stack empty");
429     return;
430     }
431    
432     if((*stack_head)->next==NULL)
433 masse 1.10 return;
434    
435     *stack_head= (*stack_head)->next;
436     temp->next= (*stack_head)->next;
437     (*stack_head)->next= temp;
438     }
439 masse 1.11
440 masse 1.14 /* Compares two elements by reference. */
441 masse 1.11 extern void eq(stackitem** stack_head)
442     {
443     void *left, *right;
444     int result;
445    
446 masse 1.17 if((*stack_head)==NULL || (*stack_head)->next==NULL) {
447     printerr("Not enough elements to compare");
448 masse 1.11 return;
449 masse 1.17 }
450 masse 1.11
451     left= (*stack_head)->content.ptr;
452 masse 1.12 swap(stack_head);
453     right= (*stack_head)->content.ptr;
454 masse 1.11 result= (left==right);
455    
456     toss(stack_head); toss(stack_head);
457     push_val(stack_head, (left==right));
458     }
459    
460 masse 1.14 /* Negates the top element on the stack. */
461 masse 1.11 extern void not(stackitem** stack_head)
462     {
463     int value;
464    
465 masse 1.17 if((*stack_head)==NULL || (*stack_head)->type!=value) {
466     printerr("Stack empty or element is not a value");
467 masse 1.11 return;
468 masse 1.17 }
469 masse 1.11
470     value= (*stack_head)->content.val;
471     toss(stack_head);
472     push_val(stack_head, !value);
473     }
474    
475 masse 1.14 /* Compares the two top elements on the stack and return 0 if they're the
476     same. */
477 masse 1.11 extern void neq(stackitem** stack_head)
478     {
479     eq(stack_head);
480     not(stack_head);
481     }
482 masse 1.12
483 masse 1.14 /* Give a symbol some content. */
484 masse 1.12 extern void def(stackitem** stack_head)
485     {
486     stackitem *temp, *value;
487    
488     if(*stack_head==NULL || (*stack_head)->next==NULL
489 masse 1.17 || (*stack_head)->type!=ref) {
490     printerr("Define what?");
491 masse 1.12 return;
492 masse 1.17 }
493 masse 1.12
494     temp= (*stack_head)->content.ptr;
495     value= (*stack_head)->next;
496     temp->content= value->content;
497     value->content.ptr=NULL;
498     temp->type= value->type;
499    
500     toss(stack_head); toss(stack_head);
501     }
502 masse 1.10
503 masse 1.14 /* Quit stack. */
504 teddy 1.5 extern void quit()
505     {
506     exit(EXIT_SUCCESS);
507 masse 1.24 }
508    
509     /* Clear stack */
510     extern void clear(stackitem** stack_head)
511     {
512     while(*stack_head!=NULL)
513     toss(stack_head);
514 masse 1.1 }
515    
516     int main()
517     {
518     stackitem* s= NULL;
519     hashtbl myhash;
520     char in_string[100];
521    
522     init_hashtbl(myhash);
523    
524     printf("okidok\n ");
525    
526     while(fgets(in_string, 100, stdin) != NULL) {
527     stack_read(&s, myhash, in_string);
528     printf("okidok\n ");
529     }
530    
531 masse 1.10 exit(EXIT_SUCCESS);
532 masse 1.1 }
533 teddy 1.3
534     /* Local Variables: */
535     /* compile-command:"make CFLAGS=\"-Wall -g -rdynamic -ldl\" stack" */
536     /* End: */

root@recompile.se
ViewVC Help
Powered by ViewVC 1.1.26