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

Annotation of /stack/stack.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.30 - (hide annotations)
Tue Feb 5 12:33:21 2002 UTC (22 years, 2 months ago) by teddy
Branch: MAIN
Changes since 1.29: +2 -5 lines
File MIME type: text/plain
Cosmetic changes.

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 teddy 1.28 /* First, define some types. */
15    
16     /* A value of some type */
17     typedef struct {
18 masse 1.16 enum {
19 teddy 1.28 integer,
20 teddy 1.18 string,
21     ref, /* Reference (to an element in the
22     hash table) */
23 masse 1.16 func, /* Function pointer */
24 teddy 1.28 symb,
25 masse 1.16 list
26 teddy 1.18 } type; /* Type of stack element */
27    
28 masse 1.1 union {
29 teddy 1.28 void *ptr; /* Pointer to the content */
30 masse 1.16 int val; /* ...or an integer */
31     } content; /* Stores a pointer or an integer */
32 masse 1.1
33 teddy 1.28 int refcount; /* Reference counter */
34    
35     } value;
36    
37     /* A symbol with a name and possible value */
38     /* (These do not need reference counters, they are kept unique by
39     hashing.) */
40     typedef struct symbol_struct {
41     char *id; /* Symbol name */
42     value *val; /* The value (if any) bound to it */
43     struct symbol_struct *next; /* In case of hashing conflicts, a */
44     } symbol; /* symbol is a kind of stack item. */
45    
46     /* A type for a hash table for symbols */
47     typedef symbol *hashtbl[HASHTBLSIZE]; /* Hash table declaration */
48    
49     /* An item (value) on a stack */
50     typedef struct stackitem_struct
51     {
52     value *item; /* The value on the stack */
53     struct stackitem_struct *next; /* Next item */
54 masse 1.1 } stackitem;
55    
56 teddy 1.28 /* An environment; gives access to the stack and a hash table of
57     defined symbols */
58     typedef struct {
59     stackitem *head; /* Head of the stack */
60     hashtbl symbols; /* Hash table of all variable bindings */
61     } environment;
62    
63     /* A type for pointers to external functions */
64     typedef void (*funcp)(environment *); /* funcp is a pointer to a void
65     function (environment *) */
66 masse 1.1
67 teddy 1.28 /* Initialize a newly created environment */
68     void init_env(environment *env)
69 masse 1.1 {
70     long i;
71    
72     for(i= 0; i<HASHTBLSIZE; i++)
73 teddy 1.28 env->symbols[i]= NULL;
74 masse 1.1 }
75    
76 teddy 1.27 /* Returns a pointer to a pointer to an element in the hash table. */
77 teddy 1.28 symbol **hash(hashtbl in_hashtbl, const char *in_string)
78 masse 1.1 {
79     long i= 0;
80     unsigned long out_hash= 0;
81 teddy 1.18 char key= '\0';
82 teddy 1.28 symbol **position;
83 masse 1.1
84 masse 1.16 while(1){ /* Hash in_string */
85 masse 1.1 key= in_string[i++];
86     if(key=='\0')
87     break;
88     out_hash= out_hash*32+key;
89     }
90    
91     out_hash= out_hash%HASHTBLSIZE;
92     position= &(in_hashtbl[out_hash]);
93    
94 masse 1.25 while(1){
95 teddy 1.18 if(*position==NULL) /* If empty */
96 masse 1.1 return position;
97    
98 teddy 1.18 if(strcmp(in_string, (*position)->id)==0) /* If match */
99 masse 1.1 return position;
100    
101 masse 1.16 position= &((*position)->next); /* Try next */
102 masse 1.1 }
103     }
104    
105 masse 1.14 /* Generic push function. */
106 masse 1.1 int push(stackitem** stack_head, stackitem* in_item)
107     {
108     in_item->next= *stack_head;
109     *stack_head= in_item;
110     return 1;
111     }
112    
113 teddy 1.29 /* Push a value onto the stack */
114     void push_val(stackitem **stack_head, value *val)
115     {
116     stackitem *new_item= malloc(sizeof(stackitem));
117     new_item->item= val;
118     val->refcount++;
119     push(stack_head, new_item);
120     }
121    
122 teddy 1.28 /* Push an integer onto the stack. */
123 teddy 1.29 int push_int(stackitem **stack_head, int in_val)
124 masse 1.1 {
125 teddy 1.28 value *new_value= malloc(sizeof(value));
126     stackitem *new_item= malloc(sizeof(stackitem));
127     new_item->item= new_value;
128    
129     new_value->content.val= in_val;
130     new_value->type= integer;
131     new_value->refcount=1;
132 masse 1.1
133     push(stack_head, new_item);
134     return 1;
135     }
136    
137 masse 1.14 /* Copy a string onto the stack. */
138 teddy 1.28 int push_cstring(stackitem **stack_head, const char *in_string)
139 masse 1.1 {
140 teddy 1.28 value *new_value= malloc(sizeof(value));
141     stackitem *new_item= malloc(sizeof(stackitem));
142     new_item->item=new_value;
143    
144     new_value->content.ptr= malloc(strlen(in_string)+1);
145     strcpy(new_value->content.ptr, in_string);
146     new_value->type= string;
147     new_value->refcount=1;
148 masse 1.1
149     push(stack_head, new_item);
150     return 1;
151     }
152    
153 teddy 1.28 /* Push a symbol onto the stack. */
154     int push_sym(environment *env, const char *in_string)
155 masse 1.1 {
156 teddy 1.28 stackitem *new_item; /* The new stack item */
157     /* ...which will contain... */
158     value *new_value; /* A new symbol value */
159     /* ...which might point to... */
160 teddy 1.29 symbol **new_symbol; /* (if needed) A new actual symbol */
161 teddy 1.28 /* ...which, if possible, will be bound to... */
162     value *new_fvalue; /* (if needed) A new function value */
163     /* ...which will point to... */
164     void *funcptr; /* A function pointer */
165    
166     static void *handle= NULL; /* Dynamic linker handle */
167    
168     /* Create a new stack item containing a new value */
169     new_item= malloc(sizeof(stackitem));
170     new_value= malloc(sizeof(value));
171     new_item->item=new_value;
172    
173     /* The new value is a symbol */
174     new_value->type= symb;
175     new_value->refcount= 1;
176    
177     /* Look up the symbol name in the hash table */
178 teddy 1.29 new_symbol= hash(env->symbols, in_string);
179     new_value->content.ptr= *new_symbol;
180 teddy 1.28
181 teddy 1.30 if(*new_symbol==NULL) { /* If symbol was undefined */
182 teddy 1.28
183     /* Create a new symbol */
184 teddy 1.30 (*new_symbol)= malloc(sizeof(symbol));
185 teddy 1.29 (*new_symbol)->val= NULL; /* undefined value */
186     (*new_symbol)->next= NULL;
187     (*new_symbol)->id= malloc(strlen(in_string)+1);
188     strcpy((*new_symbol)->id, in_string);
189 masse 1.1
190 teddy 1.28 /* Intern the new symbol in the hash table */
191 teddy 1.29 new_value->content.ptr= *new_symbol;
192 masse 1.1
193 teddy 1.28 /* Try to load the symbol name as an external function, to see if
194     we should bind the symbol to a new function pointer value */
195 masse 1.16 if(handle==NULL) /* If no handle */
196 teddy 1.28 handle= dlopen(NULL, RTLD_LAZY);
197 masse 1.6
198 teddy 1.28 funcptr= dlsym(handle, in_string); /* Get function pointer */
199     if(dlerror()==NULL) { /* If a function was found */
200     new_fvalue= malloc(sizeof(value)); /* Create a new value */
201     new_fvalue->type=func; /* The new value is a function pointer */
202     new_fvalue->content.ptr=funcptr; /* Store function pointer */
203 teddy 1.29 (*new_symbol)->val= new_fvalue; /* Bind the symbol to the new
204     function value */
205 teddy 1.28 new_fvalue->refcount= 1;
206     }
207 masse 1.1 }
208 teddy 1.28 push(&(env->head), new_item);
209 masse 1.1 return 1;
210     }
211    
212 masse 1.17 void printerr(const char* in_string) {
213     fprintf(stderr, "Err: %s\n", in_string);
214     }
215    
216 teddy 1.28 /* Throw away a value */
217     void free_val(value *val){
218     stackitem *item, *temp;
219    
220     val->refcount--; /* Decrease the reference count */
221     if(val->refcount == 0){
222     switch (val->type){ /* and free the contents if necessary */
223     case string:
224     free(val->content.ptr);
225     case list: /* lists needs to be freed recursively */
226     item=val->content.ptr;
227     while(item != NULL) { /* for all stack items */
228     free_val(item->item); /* free the value */
229     temp=item->next; /* save next ptr */
230     free(item); /* free the stackitem */
231     item=temp; /* go to next stackitem */
232     }
233     free(val); /* Free the actual list value */
234     break;
235     default:
236     break;
237     }
238     }
239     }
240    
241 masse 1.14 /* Discard the top element of the stack. */
242 teddy 1.28 extern void toss(environment *env)
243 masse 1.1 {
244 teddy 1.28 stackitem *temp= env->head;
245 masse 1.1
246 teddy 1.28 if((env->head)==NULL) {
247 masse 1.17 printerr("Stack empty");
248 masse 1.7 return;
249 masse 1.17 }
250 masse 1.7
251 teddy 1.28 free_val(env->head->item); /* Free the value */
252     env->head= env->head->next; /* Remove the top stack item */
253     free(temp); /* Free the old top stack item */
254 masse 1.1 }
255    
256 masse 1.14 /* Print newline. */
257 masse 1.8 extern void nl()
258     {
259     printf("\n");
260     }
261 masse 1.1
262 masse 1.14 /* Prints the top element of the stack. */
263 teddy 1.28 void print_h(stackitem *stack_head)
264 masse 1.8 {
265 masse 1.23
266 teddy 1.28 if(stack_head==NULL) {
267 masse 1.17 printerr("Stack empty");
268 masse 1.8 return;
269 masse 1.17 }
270 masse 1.1
271 teddy 1.28 switch(stack_head->item->type) {
272     case integer:
273     printf("%d", stack_head->item->content.val);
274 teddy 1.2 break;
275     case string:
276 teddy 1.28 printf("\"%s\"", (char*)stack_head->item->content.ptr);
277 teddy 1.2 break;
278 teddy 1.28 case symb:
279     printf("'%s'", ((symbol *)(stack_head->item->content.ptr))->id);
280 masse 1.6 break;
281 masse 1.7 default:
282 teddy 1.28 printf("%p", (funcp)(stack_head->item->content.ptr));
283 teddy 1.2 break;
284     }
285 masse 1.1 }
286    
287 teddy 1.28 extern void print_(environment *env) {
288     print_h(env->head);
289     }
290    
291 masse 1.14 /* Prints the top element of the stack and then discards it. */
292 teddy 1.28 extern void print(environment *env)
293 masse 1.8 {
294 teddy 1.28 print_(env);
295     toss(env);
296 masse 1.8 }
297    
298 masse 1.14 /* Only to be called by function printstack. */
299 teddy 1.28 void print_st(stackitem *stack_head, long counter)
300 masse 1.8 {
301     if(stack_head->next != NULL)
302     print_st(stack_head->next, counter+1);
303     printf("%ld: ", counter);
304 teddy 1.28 print_h(stack_head);
305 masse 1.8 nl();
306     }
307    
308 teddy 1.28
309    
310 masse 1.14 /* Prints the stack. */
311 teddy 1.28 extern void printstack(environment *env)
312 masse 1.1 {
313 teddy 1.28 if(env->head != NULL) {
314     print_st(env->head, 1);
315 masse 1.21 nl();
316 masse 1.17 } else {
317     printerr("Stack empty");
318 masse 1.1 }
319     }
320    
321 masse 1.26 /* Swap the two top elements on the stack. */
322 teddy 1.28 extern void swap(environment *env)
323 masse 1.26 {
324 teddy 1.28 stackitem *temp= env->head;
325 masse 1.26
326 teddy 1.28 if((env->head)==NULL) {
327 masse 1.26 printerr("Stack empty");
328     return;
329     }
330    
331 teddy 1.28 if(env->head->next==NULL) {
332     printerr("Not enough arguments");
333 masse 1.26 return;
334 teddy 1.28 }
335 masse 1.26
336 teddy 1.28 env->head= env->head->next;
337     temp->next= env->head->next;
338     env->head->next= temp;
339 masse 1.26 }
340    
341     stackitem* copy(stackitem* in_item)
342     {
343 teddy 1.28 stackitem *out_item= malloc(sizeof(stackitem));
344 masse 1.26
345     memcpy(out_item, in_item, sizeof(stackitem));
346     out_item->next= NULL;
347    
348     return out_item;
349     }
350    
351    
352 teddy 1.29 /* If the top element is a symbol, determine if it's bound to a
353     function value, and if it is, toss the symbol and execute the
354     function. */
355 teddy 1.28 extern void eval(environment *env)
356 masse 1.1 {
357     funcp in_func;
358 teddy 1.29 value* val;
359     if(env->head==NULL) {
360 masse 1.22 printerr("Stack empty");
361 masse 1.1 return;
362 masse 1.17 }
363 masse 1.1
364 teddy 1.29 /* if it's a symbol */
365     if(env->head->item->type==symb) {
366    
367     /* If it's not bound to anything */
368     if (((symbol *)(env->head->item->content.ptr))->val == NULL) {
369     printerr("Unbound variable");
370     return;
371     }
372    
373     /* If it contains a function */
374     if (((symbol *)(env->head->item->content.ptr))->val->type == func) {
375     in_func=
376     (funcp)(((symbol *)(env->head->item->content.ptr))->val->content.ptr);
377     toss(env);
378     (*in_func)(env); /* Run the function */
379     return;
380     } else { /* If it's not a function */
381     val=((symbol *)(env->head->item->content.ptr))->val;
382     toss(env); /* toss the symbol */
383     push_val(&(env->head), val); /* Return its bound value */
384     }
385 teddy 1.28 }
386 masse 1.22
387 teddy 1.29 /* If it's a lone function value, run it */
388     if(env->head->item->type==func) {
389     in_func= (funcp)(env->head->item->content.ptr);
390 teddy 1.28 toss(env);
391     (*in_func)(env);
392 masse 1.1 return;
393 masse 1.26 }
394    
395 masse 1.1 }
396    
397 masse 1.19 /* Make a list. */
398 teddy 1.28 extern void pack(environment *env)
399 masse 1.19 {
400     void* delimiter;
401 teddy 1.28 stackitem *iterator, *temp;
402     value *pack;
403 masse 1.19
404 teddy 1.28 delimiter= env->head->item->content.ptr; /* Get delimiter */
405     toss(env);
406 masse 1.19
407 teddy 1.28 iterator= env->head;
408 masse 1.19
409 teddy 1.28 if(iterator==NULL || iterator->item->content.ptr==delimiter) {
410 masse 1.24 temp= NULL;
411 teddy 1.28 toss(env);
412 masse 1.24 } else {
413     /* Search for first delimiter */
414 teddy 1.28 while(iterator->next!=NULL
415     && iterator->next->item->content.ptr!=delimiter)
416 masse 1.24 iterator= iterator->next;
417    
418     /* Extract list */
419 teddy 1.28 temp= env->head;
420     env->head= iterator->next;
421 masse 1.24 iterator->next= NULL;
422    
423 teddy 1.28 if(env->head!=NULL)
424     toss(env);
425 masse 1.24 }
426 masse 1.19
427     /* Push list */
428 teddy 1.28 pack= malloc(sizeof(value));
429 masse 1.19 pack->type= list;
430     pack->content.ptr= temp;
431 teddy 1.28 pack->refcount= 1;
432    
433     temp= malloc(sizeof(stackitem));
434     temp->item= pack;
435 masse 1.19
436 teddy 1.28 push(&(env->head), temp);
437 masse 1.19 }
438    
439 masse 1.14 /* Parse input. */
440 teddy 1.28 int stack_read(environment *env, char *in_line)
441 masse 1.1 {
442     char *temp, *rest;
443     int itemp;
444     size_t inlength= strlen(in_line)+1;
445     int convert= 0;
446 masse 1.20 static int non_eval_flag= 0;
447 masse 1.1
448     temp= malloc(inlength);
449     rest= malloc(inlength);
450    
451 masse 1.15 do {
452 masse 1.16 /* If string */
453 masse 1.15 if((convert= sscanf(in_line, "\"%[^\"\n\r]\" %[^\n\r]", temp, rest))) {
454 teddy 1.28 push_cstring(&(env->head), temp);
455 masse 1.15 break;
456     }
457 teddy 1.28 /* If integer */
458 masse 1.15 if((convert= sscanf(in_line, "%d %[^\n\r]", &itemp, rest))) {
459 teddy 1.29 push_int(&(env->head), itemp);
460 masse 1.15 break;
461     }
462 masse 1.16 /* Escape ';' with '\' */
463 masse 1.15 if((convert= sscanf(in_line, "\\%c%[^\n\r]", temp, rest))) {
464 teddy 1.28 temp[1]= '\0';
465     push_sym(env, temp);
466 masse 1.15 break;
467     }
468 masse 1.16 /* If symbol */
469 teddy 1.28 if((convert= sscanf(in_line, "%[^][ ;\n\r_]%[^\n\r]", temp, rest))) {
470     push_sym(env, temp);
471 masse 1.15 break;
472     }
473 masse 1.19 /* If single char */
474     if((convert= sscanf(in_line, "%c%[^\n\r]", temp, rest))) {
475     if(*temp==';') {
476 masse 1.21 if(!non_eval_flag) {
477 teddy 1.28 eval(env); /* Evaluate top element */
478 masse 1.20 break;
479     }
480    
481 teddy 1.28 push_sym(env, ";");
482 masse 1.19 break;
483     }
484    
485     if(*temp==']') {
486 teddy 1.28 push_sym(env, "[");
487     pack(env);
488 masse 1.21 if(non_eval_flag!=0)
489     non_eval_flag--;
490 masse 1.20 break;
491     }
492    
493     if(*temp=='[') {
494 teddy 1.28 push_sym(env, "[");
495 masse 1.20 non_eval_flag++;
496 masse 1.19 break;
497     }
498 masse 1.15 }
499     } while(0);
500    
501 masse 1.1
502     free(temp);
503    
504     if(convert<2) {
505     free(rest);
506     return 0;
507     }
508    
509 teddy 1.28 stack_read(env, rest);
510 masse 1.1
511     free(rest);
512     return 1;
513 masse 1.7 }
514 masse 1.1
515 masse 1.16 /* Relocate elements of the list on the stack. */
516 teddy 1.28 extern void expand(environment *env)
517 masse 1.1 {
518 masse 1.8 stackitem *temp, *new_head;
519    
520 masse 1.16 /* Is top element a list? */
521 teddy 1.28 if(env->head==NULL || env->head->item->type!=list) {
522 masse 1.17 printerr("Stack empty or not a list");
523 masse 1.8 return;
524 masse 1.17 }
525 masse 1.8
526 masse 1.16 /* The first list element is the new stack head */
527 teddy 1.28 new_head= temp= env->head->item->content.ptr;
528 masse 1.8
529 teddy 1.28 env->head->item->refcount++;
530     toss(env);
531 masse 1.24
532 teddy 1.28 /* Find the end of the list */
533 masse 1.8 while(temp->next!=NULL)
534     temp= temp->next;
535    
536 teddy 1.28 /* Connect the tail of the list with the old stack head */
537     temp->next= env->head;
538     env->head= new_head; /* ...and voila! */
539    
540 teddy 1.5 }
541 masse 1.11
542 masse 1.14 /* Compares two elements by reference. */
543 teddy 1.28 extern void eq(environment *env)
544 masse 1.11 {
545     void *left, *right;
546     int result;
547    
548 teddy 1.28 if((env->head)==NULL || env->head->next==NULL) {
549 masse 1.17 printerr("Not enough elements to compare");
550 masse 1.11 return;
551 masse 1.17 }
552 masse 1.11
553 teddy 1.28 left= env->head->item->content.ptr;
554     swap(env);
555     right= env->head->item->content.ptr;
556 masse 1.11 result= (left==right);
557    
558 teddy 1.28 toss(env); toss(env);
559 teddy 1.29 push_int(&(env->head), result);
560 masse 1.11 }
561    
562 masse 1.14 /* Negates the top element on the stack. */
563 teddy 1.28 extern void not(environment *env)
564 masse 1.11 {
565 teddy 1.28 int val;
566 masse 1.11
567 teddy 1.28 if((env->head)==NULL || env->head->item->type!=integer) {
568     printerr("Stack empty or element is not a integer");
569 masse 1.11 return;
570 masse 1.17 }
571 masse 1.11
572 teddy 1.28 val= env->head->item->content.val;
573     toss(env);
574 teddy 1.29 push_int(&(env->head), !val);
575 masse 1.11 }
576    
577 masse 1.14 /* Compares the two top elements on the stack and return 0 if they're the
578     same. */
579 teddy 1.28 extern void neq(environment *env)
580 masse 1.11 {
581 teddy 1.28 eq(env);
582     not(env);
583 masse 1.11 }
584 masse 1.12
585 masse 1.14 /* Give a symbol some content. */
586 teddy 1.28 extern void def(environment *env)
587 masse 1.12 {
588 teddy 1.28 symbol *sym;
589 masse 1.12
590 teddy 1.28 /* Needs two values on the stack, the top one must be a symbol */
591     if(env->head==NULL || env->head->next==NULL
592     || env->head->item->type!=symb) {
593 masse 1.17 printerr("Define what?");
594 masse 1.12 return;
595 masse 1.17 }
596 masse 1.12
597 teddy 1.28 /* long names are a pain */
598     sym=env->head->item->content.ptr;
599    
600     /* if the symbol was bound to something else, throw it away */
601     if(sym->val != NULL)
602     free_val(sym->val);
603    
604     /* Bind the symbol to the value */
605     sym->val= env->head->next->item;
606     sym->val->refcount++; /* Increase the reference counter */
607 masse 1.12
608 teddy 1.28 toss(env); toss(env);
609 masse 1.12 }
610 masse 1.10
611 masse 1.14 /* Quit stack. */
612 teddy 1.28 extern void quit(environment *env)
613 teddy 1.5 {
614     exit(EXIT_SUCCESS);
615 masse 1.24 }
616    
617     /* Clear stack */
618 teddy 1.28 extern void clear(environment *env)
619 masse 1.24 {
620 teddy 1.28 while(env->head!=NULL)
621     toss(env);
622 masse 1.1 }
623    
624     int main()
625     {
626 teddy 1.28 environment myenv;
627 masse 1.1 char in_string[100];
628    
629 teddy 1.28 init_env(&myenv);
630 masse 1.1
631     printf("okidok\n ");
632    
633     while(fgets(in_string, 100, stdin) != NULL) {
634 teddy 1.28 stack_read(&myenv, in_string);
635 masse 1.1 printf("okidok\n ");
636     }
637    
638 masse 1.10 exit(EXIT_SUCCESS);
639 masse 1.1 }

root@recompile.se
ViewVC Help
Powered by ViewVC 1.1.26