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

Contents of /stack/stack.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.45 - (show annotations)
Thu Feb 7 01:06:44 2002 UTC (22 years, 2 months ago) by teddy
Branch: MAIN
Changes since 1.44: +1 -1 lines
File MIME type: text/plain
(print_h): Fixed print<->read equivalence of symbols.

1 /* printf */
2 #include <stdio.h>
3 /* EXIT_SUCCESS */
4 #include <stdlib.h>
5 /* NULL */
6 #include <stddef.h>
7 /* dlopen, dlsym, dlerror */
8 #include <dlfcn.h>
9 /* assert */
10 #include <assert.h>
11
12 #define HASHTBLSIZE 65536
13
14 /* First, define some types. */
15
16 /* A value of some type */
17 typedef struct {
18 enum {
19 integer,
20 string,
21 func, /* Function pointer */
22 symb,
23 list
24 } type; /* Type of stack element */
25
26 union {
27 void *ptr; /* Pointer to the content */
28 int val; /* ...or an integer */
29 } content; /* Stores a pointer or an integer */
30
31 int refcount; /* Reference counter */
32
33 } value;
34
35 /* A symbol with a name and possible value */
36 /* (These do not need reference counters, they are kept unique by
37 hashing.) */
38 typedef struct symbol_struct {
39 char *id; /* Symbol name */
40 value *val; /* The value (if any) bound to it */
41 struct symbol_struct *next; /* In case of hashing conflicts, a */
42 } symbol; /* symbol is a kind of stack item. */
43
44 /* A type for a hash table for symbols */
45 typedef symbol *hashtbl[HASHTBLSIZE]; /* Hash table declaration */
46
47 /* An item (value) on a stack */
48 typedef struct stackitem_struct
49 {
50 value *item; /* The value on the stack */
51 struct stackitem_struct *next; /* Next item */
52 } stackitem;
53
54 /* An environment; gives access to the stack and a hash table of
55 defined symbols */
56 typedef struct {
57 stackitem *head; /* Head of the stack */
58 hashtbl symbols; /* Hash table of all variable bindings */
59 int err; /* Error flag */
60 } environment;
61
62 /* A type for pointers to external functions */
63 typedef void (*funcp)(environment *); /* funcp is a pointer to a void
64 function (environment *) */
65
66 /* Initialize a newly created environment */
67 void init_env(environment *env)
68 {
69 long i;
70
71 env->err=0;
72 for(i= 0; i<HASHTBLSIZE; i++)
73 env->symbols[i]= NULL;
74 }
75
76 /* Returns a pointer to a pointer to an element in the hash table. */
77 symbol **hash(hashtbl in_hashtbl, const char *in_string)
78 {
79 long i= 0;
80 unsigned long out_hash= 0;
81 char key= '\0';
82 symbol **position;
83
84 while(1){ /* Hash in_string */
85 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 while(1){
95 if(*position==NULL) /* If empty */
96 return position;
97
98 if(strcmp(in_string, (*position)->id)==0) /* If match */
99 return position;
100
101 position= &((*position)->next); /* Try next */
102 }
103 }
104
105 /* Generic push function. */
106 void push(stackitem** stack_head, stackitem* in_item)
107 {
108 in_item->next= *stack_head;
109 *stack_head= in_item;
110 }
111
112 /* Push a value onto the stack */
113 void push_val(stackitem **stack_head, value *val)
114 {
115 stackitem *new_item= malloc(sizeof(stackitem));
116 new_item->item= val;
117 val->refcount++;
118 push(stack_head, new_item);
119 }
120
121 /* Push an integer onto the stack. */
122 void push_int(stackitem **stack_head, int in_val)
123 {
124 value *new_value= malloc(sizeof(value));
125 stackitem *new_item= malloc(sizeof(stackitem));
126 new_item->item= new_value;
127
128 new_value->content.val= in_val;
129 new_value->type= integer;
130 new_value->refcount=1;
131
132 push(stack_head, new_item);
133 }
134
135 /* Copy a string onto the stack. */
136 void push_cstring(stackitem **stack_head, const char *in_string)
137 {
138 value *new_value= malloc(sizeof(value));
139 stackitem *new_item= malloc(sizeof(stackitem));
140 new_item->item=new_value;
141
142 new_value->content.ptr= malloc(strlen(in_string)+1);
143 strcpy(new_value->content.ptr, in_string);
144 new_value->type= string;
145 new_value->refcount=1;
146
147 push(stack_head, new_item);
148 }
149
150 /* Push a symbol onto the stack. */
151 void push_sym(environment *env, const char *in_string)
152 {
153 stackitem *new_item; /* The new stack item */
154 /* ...which will contain... */
155 value *new_value; /* A new symbol value */
156 /* ...which might point to... */
157 symbol **new_symbol; /* (if needed) A new actual symbol */
158 /* ...which, if possible, will be bound to... */
159 value *new_fvalue; /* (if needed) A new function value */
160 /* ...which will point to... */
161 void *funcptr; /* A function pointer */
162
163 static void *handle= NULL; /* Dynamic linker handle */
164
165 /* Create a new stack item containing a new value */
166 new_item= malloc(sizeof(stackitem));
167 new_value= malloc(sizeof(value));
168 new_item->item=new_value;
169
170 /* The new value is a symbol */
171 new_value->type= symb;
172 new_value->refcount= 1;
173
174 /* Look up the symbol name in the hash table */
175 new_symbol= hash(env->symbols, in_string);
176 new_value->content.ptr= *new_symbol;
177
178 if(*new_symbol==NULL) { /* If symbol was undefined */
179
180 /* Create a new symbol */
181 (*new_symbol)= malloc(sizeof(symbol));
182 (*new_symbol)->val= NULL; /* undefined value */
183 (*new_symbol)->next= NULL;
184 (*new_symbol)->id= malloc(strlen(in_string)+1);
185 strcpy((*new_symbol)->id, in_string);
186
187 /* Intern the new symbol in the hash table */
188 new_value->content.ptr= *new_symbol;
189
190 /* Try to load the symbol name as an external function, to see if
191 we should bind the symbol to a new function pointer value */
192 if(handle==NULL) /* If no handle */
193 handle= dlopen(NULL, RTLD_LAZY);
194
195 funcptr= dlsym(handle, in_string); /* Get function pointer */
196 if(dlerror()==NULL) { /* If a function was found */
197 new_fvalue= malloc(sizeof(value)); /* Create a new value */
198 new_fvalue->type=func; /* The new value is a function pointer */
199 new_fvalue->content.ptr=funcptr; /* Store function pointer */
200 (*new_symbol)->val= new_fvalue; /* Bind the symbol to the new
201 function value */
202 new_fvalue->refcount= 1;
203 }
204 }
205 push(&(env->head), new_item);
206 }
207
208 void printerr(const char* in_string) {
209 fprintf(stderr, "Err: %s\n", in_string);
210 }
211
212 /* Throw away a value */
213 void free_val(value *val){
214 stackitem *item, *temp;
215
216 val->refcount--; /* Decrease the reference count */
217 if(val->refcount == 0){
218 switch (val->type){ /* and free the contents if necessary */
219 case string:
220 free(val->content.ptr);
221 break;
222 case list: /* lists needs to be freed recursively */
223 item=val->content.ptr;
224 while(item != NULL) { /* for all stack items */
225 free_val(item->item); /* free the value */
226 temp=item->next; /* save next ptr */
227 free(item); /* free the stackitem */
228 item=temp; /* go to next stackitem */
229 }
230 free(val); /* Free the actual list value */
231 break;
232 default:
233 break;
234 }
235 }
236 }
237
238 /* Discard the top element of the stack. */
239 extern void toss(environment *env)
240 {
241 stackitem *temp= env->head;
242
243 if((env->head)==NULL) {
244 printerr("Too Few Arguments");
245 env->err=1;
246 return;
247 }
248
249 free_val(env->head->item); /* Free the value */
250 env->head= env->head->next; /* Remove the top stack item */
251 free(temp); /* Free the old top stack item */
252 }
253
254 /* Print newline. */
255 extern void nl()
256 {
257 printf("\n");
258 }
259
260 /* Gets the type of a value */
261 extern void type(environment *env){
262 int typenum;
263
264 if((env->head)==NULL) {
265 printerr("Too Few Arguments");
266 env->err=1;
267 return;
268 }
269 typenum=env->head->item->type;
270 toss(env);
271 switch(typenum){
272 case integer:
273 push_sym(env, "integer");
274 break;
275 case string:
276 push_sym(env, "string");
277 break;
278 case symb:
279 push_sym(env, "symbol");
280 break;
281 case func:
282 push_sym(env, "function");
283 break;
284 case list:
285 push_sym(env, "list");
286 break;
287 default:
288 push_sym(env, "unknown");
289 break;
290 }
291 }
292
293 /* Prints the top element of the stack. */
294 void print_h(stackitem *stack_head)
295 {
296 switch(stack_head->item->type) {
297 case integer:
298 printf("%d", stack_head->item->content.val);
299 break;
300 case string:
301 printf("\"%s\"", (char*)stack_head->item->content.ptr);
302 break;
303 case symb:
304 printf("%s", ((symbol *)(stack_head->item->content.ptr))->id);
305 break;
306 case func:
307 printf("#<function %p>", (funcp)(stack_head->item->content.ptr));
308 break;
309 case list:
310 /* A list is just a stack, so make stack_head point to it */
311 stack_head=(stackitem *)(stack_head->item->content.ptr);
312 printf("[ ");
313 while(stack_head != NULL) {
314 print_h(stack_head);
315 printf(" ");
316 stack_head=stack_head->next;
317 }
318 printf("]");
319 break;
320 default:
321 printf("#<unknown %p>", (stack_head->item->content.ptr));
322 break;
323 }
324 }
325
326 extern void print_(environment *env) {
327 if(env->head==NULL) {
328 printerr("Too Few Arguments");
329 env->err=1;
330 return;
331 }
332 print_h(env->head);
333 }
334
335 /* Prints the top element of the stack and then discards it. */
336 extern void print(environment *env)
337 {
338 print_(env);
339 if(env->err) return;
340 toss(env);
341 }
342
343 /* Only to be called by function printstack. */
344 void print_st(stackitem *stack_head, long counter)
345 {
346 if(stack_head->next != NULL)
347 print_st(stack_head->next, counter+1);
348 printf("%ld: ", counter);
349 print_h(stack_head);
350 nl();
351 }
352
353
354
355 /* Prints the stack. */
356 extern void printstack(environment *env)
357 {
358 if(env->head == NULL) {
359 return;
360 }
361 print_st(env->head, 1);
362 nl();
363 }
364
365 /* Swap the two top elements on the stack. */
366 extern void swap(environment *env)
367 {
368 stackitem *temp= env->head;
369
370 if((env->head)==NULL) {
371 printerr("Too Few Arguments");
372 env->err=1;
373 return;
374 }
375
376 if(env->head->next==NULL) {
377 printerr("Too Few Arguments");
378 env->err=1;
379 return;
380 }
381
382 env->head= env->head->next;
383 temp->next= env->head->next;
384 env->head->next= temp;
385 }
386
387 stackitem* copy(stackitem* in_item)
388 {
389 stackitem *out_item= malloc(sizeof(stackitem));
390
391 memcpy(out_item, in_item, sizeof(stackitem));
392 out_item->next= NULL;
393
394 return out_item;
395 }
396
397 /* Recall a value from a symbol, if bound */
398 extern void rcl(environment *env)
399 {
400 value *val;
401
402 if(env->head == NULL) {
403 printerr("Too Few Arguments");
404 env->err=1;
405 return;
406 }
407
408 if(env->head->item->type!=symb) {
409 printerr("Bad Argument Type");
410 env->err=2;
411 return;
412 }
413
414 val=((symbol *)(env->head->item->content.ptr))->val;
415 if(val == NULL){
416 printerr("Unbound Variable");
417 env->err=3;
418 return;
419 }
420 toss(env); /* toss the symbol */
421 if(env->err) return;
422 push_val(&(env->head), val); /* Return its bound value */
423 }
424
425 /* If the top element is a symbol, determine if it's bound to a
426 function value, and if it is, toss the symbol and execute the
427 function. */
428 extern void eval(environment *env)
429 {
430 funcp in_func;
431 value* temp_val;
432 stackitem* iterator;
433
434 if(env->head==NULL) {
435 printerr("Too Few Arguments");
436 env->err=1;
437 return;
438 }
439
440 /* if it's a symbol */
441 if(env->head->item->type==symb) {
442
443 rcl(env); /* get its contents */
444 if(env->err) return;
445 if(env->head->item->type!=symb){ /* don't recurse symbols */
446 eval(env); /* evaluate the value */
447 return;
448 }
449 }
450
451 /* If it's a lone function value, run it */
452 if(env->head->item->type==func) {
453 in_func= (funcp)(env->head->item->content.ptr);
454 toss(env);
455 if(env->err) return;
456 (*in_func)(env);
457 return;
458 }
459
460 /* If it's a list */
461 if(env->head->item->type==list) {
462 temp_val= env->head->item;
463 env->head->item->refcount++;
464 toss(env);
465 if(env->err) return;
466 iterator= (stackitem*)temp_val->content.ptr;
467 while(iterator!=NULL && iterator->item!=NULL) {
468 push_val(&(env->head), iterator->item);
469 if(env->head->item->type==symb
470 && strcmp(";", ((symbol*)(env->head->item->content.ptr))->id)==0) {
471 toss(env);
472 if(env->err) return;
473 eval(env);
474 }
475 iterator= iterator->next;
476 }
477 free_val(temp_val);
478 }
479 }
480
481 /* Reverse (flip) a list */
482 extern void rev(environment *env){
483 stackitem *old_head, *new_head, *item;
484
485 if((env->head)==NULL) {
486 printerr("Too Few Arguments");
487 env->err=1;
488 return;
489 }
490
491 if(env->head->item->type!=list) {
492 printerr("Bad Argument Type");
493 env->err=2;
494 return;
495 }
496
497 old_head=(stackitem *)(env->head->item->content.ptr);
498 new_head=NULL;
499 while(old_head != NULL){
500 item=old_head;
501 old_head=old_head->next;
502 item->next=new_head;
503 new_head=item;
504 }
505 env->head->item->content.ptr=new_head;
506 }
507
508 /* Make a list. */
509 extern void pack(environment *env)
510 {
511 void* delimiter;
512 stackitem *iterator, *temp;
513 value *pack;
514
515 delimiter= env->head->item->content.ptr; /* Get delimiter */
516 toss(env);
517
518 iterator= env->head;
519
520 if(iterator==NULL || iterator->item->content.ptr==delimiter) {
521 temp= NULL;
522 toss(env);
523 } else {
524 /* Search for first delimiter */
525 while(iterator->next!=NULL
526 && iterator->next->item->content.ptr!=delimiter)
527 iterator= iterator->next;
528
529 /* Extract list */
530 temp= env->head;
531 env->head= iterator->next;
532 iterator->next= NULL;
533
534 if(env->head!=NULL)
535 toss(env);
536 }
537
538 /* Push list */
539 pack= malloc(sizeof(value));
540 pack->type= list;
541 pack->content.ptr= temp;
542 pack->refcount= 1;
543
544 temp= malloc(sizeof(stackitem));
545 temp->item= pack;
546
547 push(&(env->head), temp);
548 rev(env);
549 }
550
551 /* Parse input. */
552 void stack_read(environment *env, char *in_line)
553 {
554 char *temp, *rest;
555 int itemp;
556 size_t inlength= strlen(in_line)+1;
557 int convert= 0;
558 static int non_eval_flag= 0;
559
560 temp= malloc(inlength);
561 rest= malloc(inlength);
562
563 do {
564 /* If comment */
565 if((convert= sscanf(in_line, "#%[^\n\r]", rest))) {
566 free(temp); free(rest);
567 return;
568 }
569
570 /* If string */
571 if((convert= sscanf(in_line, "\"%[^\"\n\r]\" %[^\n\r]", temp, rest))) {
572 push_cstring(&(env->head), temp);
573 break;
574 }
575 /* If integer */
576 if((convert= sscanf(in_line, "%d %[^\n\r]", &itemp, rest))) {
577 push_int(&(env->head), itemp);
578 break;
579 }
580 /* Escape ';' with '\' */
581 if((convert= sscanf(in_line, "\\%c%[^\n\r]", temp, rest))) {
582 temp[1]= '\0';
583 push_sym(env, temp);
584 break;
585 }
586 /* If symbol */
587 if((convert= sscanf(in_line, "%[^][ ;\n\r]%[^\n\r]", temp, rest))) {
588 push_sym(env, temp);
589 break;
590 }
591 /* If single char */
592 if((convert= sscanf(in_line, "%c%[^\n\r]", temp, rest))) {
593 if(*temp==';') {
594 if(!non_eval_flag) {
595 eval(env); /* Evaluate top element */
596 break;
597 }
598
599 push_sym(env, ";");
600 break;
601 }
602
603 if(*temp==']') {
604 push_sym(env, "[");
605 pack(env);
606 if(non_eval_flag!=0)
607 non_eval_flag--;
608 break;
609 }
610
611 if(*temp=='[') {
612 push_sym(env, "[");
613 non_eval_flag++;
614 break;
615 }
616 }
617 } while(0);
618
619 free(temp);
620
621 if(convert<2) {
622 free(rest);
623 return;
624 }
625
626 stack_read(env, rest);
627
628 free(rest);
629 }
630
631 /* Relocate elements of the list on the stack. */
632 extern void expand(environment *env)
633 {
634 stackitem *temp, *new_head;
635
636 /* Is top element a list? */
637 if(env->head==NULL) {
638 printerr("Too Few Arguments");
639 env->err=1;
640 return;
641 }
642 if(env->head->item->type!=list) {
643 printerr("Bad Argument Type");
644 env->err=2;
645 return;
646 }
647
648 rev(env);
649
650 if(env->err)
651 return;
652
653 /* The first list element is the new stack head */
654 new_head= temp= env->head->item->content.ptr;
655
656 env->head->item->refcount++;
657 toss(env);
658
659 /* Find the end of the list */
660 while(temp->next!=NULL)
661 temp= temp->next;
662
663 /* Connect the tail of the list with the old stack head */
664 temp->next= env->head;
665 env->head= new_head; /* ...and voila! */
666
667 }
668
669 /* Compares two elements by reference. */
670 extern void eq(environment *env)
671 {
672 void *left, *right;
673 int result;
674
675 if((env->head)==NULL || env->head->next==NULL) {
676 printerr("Too Few Arguments");
677 env->err=1;
678 return;
679 }
680
681 left= env->head->item->content.ptr;
682 swap(env);
683 right= env->head->item->content.ptr;
684 result= (left==right);
685
686 toss(env); toss(env);
687 push_int(&(env->head), result);
688 }
689
690 /* Negates the top element on the stack. */
691 extern void not(environment *env)
692 {
693 int val;
694
695 if((env->head)==NULL) {
696 printerr("Too Few Arguments");
697 env->err=1;
698 return;
699 }
700
701 if(env->head->item->type!=integer) {
702 printerr("Bad Argument Type");
703 env->err=2;
704 return;
705 }
706
707 val= env->head->item->content.val;
708 toss(env);
709 push_int(&(env->head), !val);
710 }
711
712 /* Compares the two top elements on the stack and return 0 if they're the
713 same. */
714 extern void neq(environment *env)
715 {
716 eq(env);
717 not(env);
718 }
719
720 /* Give a symbol some content. */
721 extern void def(environment *env)
722 {
723 symbol *sym;
724
725 /* Needs two values on the stack, the top one must be a symbol */
726 if(env->head==NULL || env->head->next==NULL) {
727 printerr("Too Few Arguments");
728 env->err=1;
729 return;
730 }
731
732 if(env->head->item->type!=symb) {
733 printerr("Bad Argument Type");
734 env->err=2;
735 return;
736 }
737
738 /* long names are a pain */
739 sym=env->head->item->content.ptr;
740
741 /* if the symbol was bound to something else, throw it away */
742 if(sym->val != NULL)
743 free_val(sym->val);
744
745 /* Bind the symbol to the value */
746 sym->val= env->head->next->item;
747 sym->val->refcount++; /* Increase the reference counter */
748
749 toss(env); toss(env);
750 }
751
752 /* Quit stack. */
753 extern void quit(environment *env)
754 {
755 exit(EXIT_SUCCESS);
756 }
757
758 /* Clear stack */
759 extern void clear(environment *env)
760 {
761 while(env->head!=NULL)
762 toss(env);
763 }
764
765 /* List all defined words */
766 extern void words(environment *env)
767 {
768 symbol *temp;
769 int i;
770
771 for(i= 0; i<HASHTBLSIZE; i++) {
772 temp= env->symbols[i];
773 while(temp!=NULL) {
774 printf("%s\n", temp->id);
775 temp= temp->next;
776 }
777 }
778 }
779
780 /* Forgets a symbol (remove it from the hash table) */
781 extern void forget(environment *env)
782 {
783 char* sym_id;
784 stackitem *stack_head= env->head;
785 symbol **hash_entry, *temp;
786
787 if(stack_head==NULL) {
788 printerr("Too Few Arguments");
789 env->err=1;
790 return;
791 }
792
793 if(stack_head->item->type!=symb) {
794 printerr("Bad Argument Type");
795 env->err=2;
796 return;
797 }
798
799 sym_id= ((symbol*)(stack_head->item->content.ptr))->id;
800 toss(env);
801
802 hash_entry= hash(env->symbols, sym_id);
803 temp= *hash_entry;
804 *hash_entry= (*hash_entry)->next;
805
806 if(temp->val!=NULL) {
807 free_val(temp->val);
808 }
809 free(temp->id);
810 free(temp);
811 }
812
813 /* Returns the current error number to the stack */
814 extern void errn(environment *env){
815 push_int(&(env->head), env->err);
816 }
817
818 int main()
819 {
820 environment myenv;
821 char in_string[100];
822
823 init_env(&myenv);
824
825 printf("okidok\n ");
826
827 while(fgets(in_string, 100, stdin) != NULL) {
828 stack_read(&myenv, in_string);
829 if(myenv.err) {
830 printf("(error %d) ", myenv.err);
831 myenv.err=0;
832 }
833 printf("okidok\n ");
834 }
835 quit(&myenv);
836 return EXIT_FAILURE;
837 }

root@recompile.se
ViewVC Help
Powered by ViewVC 1.1.26