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

Contents of /stack/stack.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.55 - (show annotations)
Fri Feb 8 00:59:34 2002 UTC (22 years, 2 months ago) by teddy
Branch: MAIN
Changes since 1.54: +55 -0 lines
File MIME type: text/plain
(copy_val): New function; makes a copy of a value.
(dup): New function; uses 'copy_val' to make a copy of an item on the stack.

1 /* printf, sscanf, fgets, fprintf */
2 #include <stdio.h>
3 /* exit, EXIT_SUCCESS, malloc, free */
4 #include <stdlib.h>
5 /* NULL */
6 #include <stddef.h>
7 /* dlopen, dlsym, dlerror */
8 #include <dlfcn.h>
9 /* strcmp, strcpy, strlen, strcat, strdup */
10 #include <string.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 int non_eval_flag;
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
67 /* Initialize a newly created environment */
68 void init_env(environment *env)
69 {
70 int i;
71
72 env->err= 0;
73 env->non_eval_flag= 0;
74 for(i= 0; i<HASHTBLSIZE; i++)
75 env->symbols[i]= NULL;
76 }
77
78 void printerr(const char* in_string) {
79 fprintf(stderr, "Err: %s\n", in_string);
80 }
81
82 /* Throw away a value */
83 void free_val(value *val){
84 stackitem *item, *temp;
85
86 val->refcount--; /* Decrease the reference count */
87 if(val->refcount == 0){
88 switch (val->type){ /* and free the contents if necessary */
89 case string:
90 free(val->content.ptr);
91 break;
92 case list: /* lists needs to be freed recursively */
93 item=val->content.ptr;
94 while(item != NULL) { /* for all stack items */
95 free_val(item->item); /* free the value */
96 temp=item->next; /* save next ptr */
97 free(item); /* free the stackitem */
98 item=temp; /* go to next stackitem */
99 }
100 free(val); /* Free the actual list value */
101 break;
102 case integer:
103 case func:
104 case symb:
105 break;
106 }
107 }
108 }
109
110 /* Discard the top element of the stack. */
111 extern void toss(environment *env)
112 {
113 stackitem *temp= env->head;
114
115 if((env->head)==NULL) {
116 printerr("Too Few Arguments");
117 env->err=1;
118 return;
119 }
120
121 free_val(env->head->item); /* Free the value */
122 env->head= env->head->next; /* Remove the top stack item */
123 free(temp); /* Free the old top stack item */
124 }
125
126 /* Returns a pointer to a pointer to an element in the hash table. */
127 symbol **hash(hashtbl in_hashtbl, const char *in_string)
128 {
129 int i= 0;
130 unsigned int out_hash= 0;
131 char key= '\0';
132 symbol **position;
133
134 while(1){ /* Hash in_string */
135 key= in_string[i++];
136 if(key=='\0')
137 break;
138 out_hash= out_hash*32+key;
139 }
140
141 out_hash= out_hash%HASHTBLSIZE;
142 position= &(in_hashtbl[out_hash]);
143
144 while(1){
145 if(*position==NULL) /* If empty */
146 return position;
147
148 if(strcmp(in_string, (*position)->id)==0) /* If match */
149 return position;
150
151 position= &((*position)->next); /* Try next */
152 }
153 }
154
155 /* Generic push function. */
156 void push(stackitem** stack_head, stackitem* in_item)
157 {
158 in_item->next= *stack_head;
159 *stack_head= in_item;
160 }
161
162 /* Push a value onto the stack */
163 void push_val(stackitem **stack_head, value *val)
164 {
165 stackitem *new_item= malloc(sizeof(stackitem));
166 new_item->item= val;
167 val->refcount++;
168 push(stack_head, new_item);
169 }
170
171 /* Push an integer onto the stack. */
172 void push_int(stackitem **stack_head, int in_val)
173 {
174 value *new_value= malloc(sizeof(value));
175 stackitem *new_item= malloc(sizeof(stackitem));
176 new_item->item= new_value;
177
178 new_value->content.val= in_val;
179 new_value->type= integer;
180 new_value->refcount=1;
181
182 push(stack_head, new_item);
183 }
184
185 /* Copy a string onto the stack. */
186 void push_cstring(stackitem **stack_head, const char *in_string)
187 {
188 value *new_value= malloc(sizeof(value));
189 stackitem *new_item= malloc(sizeof(stackitem));
190 new_item->item=new_value;
191
192 new_value->content.ptr= malloc(strlen(in_string)+1);
193 strcpy(new_value->content.ptr, in_string);
194 new_value->type= string;
195 new_value->refcount=1;
196
197 push(stack_head, new_item);
198 }
199
200 /* Mangle a symbol name to a valid C identifier name */
201 char *mangle_str(const char *old_string){
202 char validchars[]
203 ="0123456789abcdef";
204 char *new_string, *current;
205
206 new_string=malloc((strlen(old_string)*2)+4);
207 strcpy(new_string, "sx_"); /* Stack eXternal */
208 current=new_string+3;
209 while(old_string[0] != '\0'){
210 current[0]=validchars[(unsigned char)(old_string[0])/16];
211 current[1]=validchars[(unsigned char)(old_string[0])%16];
212 current+=2;
213 old_string++;
214 }
215 current[0]='\0';
216
217 return new_string; /* The caller must free() it */
218 }
219
220 extern void mangle(environment *env){
221 value *new_value;
222 char *new_string;
223
224 if((env->head)==NULL) {
225 printerr("Too Few Arguments");
226 env->err=1;
227 return;
228 }
229
230 if(env->head->item->type!=string) {
231 printerr("Bad Argument Type");
232 env->err=2;
233 return;
234 }
235
236 new_string= mangle_str((const char *)(env->head->item->content.ptr));
237
238 toss(env);
239 if(env->err) return;
240
241 new_value= malloc(sizeof(value));
242 new_value->content.ptr= new_string;
243 new_value->type= string;
244 new_value->refcount=1;
245
246 push_val(&(env->head), new_value);
247 }
248
249 /* Push a symbol onto the stack. */
250 void push_sym(environment *env, const char *in_string)
251 {
252 stackitem *new_item; /* The new stack item */
253 /* ...which will contain... */
254 value *new_value; /* A new symbol value */
255 /* ...which might point to... */
256 symbol **new_symbol; /* (if needed) A new actual symbol */
257 /* ...which, if possible, will be bound to... */
258 value *new_fvalue; /* (if needed) A new function value */
259 /* ...which will point to... */
260 void *funcptr; /* A function pointer */
261
262 static void *handle= NULL; /* Dynamic linker handle */
263 const char *dlerr; /* Dynamic linker error */
264 char *mangled; /* Mangled function name */
265
266 /* Create a new stack item containing a new value */
267 new_item= malloc(sizeof(stackitem));
268 new_value= malloc(sizeof(value));
269 new_item->item=new_value;
270
271 /* The new value is a symbol */
272 new_value->type= symb;
273 new_value->refcount= 1;
274
275 /* Look up the symbol name in the hash table */
276 new_symbol= hash(env->symbols, in_string);
277 new_value->content.ptr= *new_symbol;
278
279 if(*new_symbol==NULL) { /* If symbol was undefined */
280
281 /* Create a new symbol */
282 (*new_symbol)= malloc(sizeof(symbol));
283 (*new_symbol)->val= NULL; /* undefined value */
284 (*new_symbol)->next= NULL;
285 (*new_symbol)->id= malloc(strlen(in_string)+1);
286 strcpy((*new_symbol)->id, in_string);
287
288 /* Intern the new symbol in the hash table */
289 new_value->content.ptr= *new_symbol;
290
291 /* Try to load the symbol name as an external function, to see if
292 we should bind the symbol to a new function pointer value */
293 if(handle==NULL) /* If no handle */
294 handle= dlopen(NULL, RTLD_LAZY);
295
296 funcptr= dlsym(handle, in_string); /* Get function pointer */
297 dlerr=dlerror();
298 if(dlerr != NULL) { /* If no function was found */
299 mangled=mangle_str(in_string);
300 funcptr= dlsym(handle, mangled); /* try mangling it */
301 free(mangled);
302 dlerr=dlerror();
303 }
304 if(dlerr==NULL) { /* If a function was found */
305 new_fvalue= malloc(sizeof(value)); /* Create a new value */
306 new_fvalue->type=func; /* The new value is a function pointer */
307 new_fvalue->content.ptr=funcptr; /* Store function pointer */
308 (*new_symbol)->val= new_fvalue; /* Bind the symbol to the new
309 function value */
310 new_fvalue->refcount= 1;
311 }
312 }
313 push(&(env->head), new_item);
314 }
315
316 /* Print newline. */
317 extern void nl()
318 {
319 printf("\n");
320 }
321
322 /* Gets the type of a value */
323 extern void type(environment *env){
324 int typenum;
325
326 if((env->head)==NULL) {
327 printerr("Too Few Arguments");
328 env->err=1;
329 return;
330 }
331 typenum=env->head->item->type;
332 toss(env);
333 switch(typenum){
334 case integer:
335 push_sym(env, "integer");
336 break;
337 case string:
338 push_sym(env, "string");
339 break;
340 case symb:
341 push_sym(env, "symbol");
342 break;
343 case func:
344 push_sym(env, "function");
345 break;
346 case list:
347 push_sym(env, "list");
348 break;
349 default:
350 push_sym(env, "unknown");
351 break;
352 }
353 }
354
355 /* Prints the top element of the stack. */
356 void print_h(stackitem *stack_head)
357 {
358 switch(stack_head->item->type) {
359 case integer:
360 printf("%d", stack_head->item->content.val);
361 break;
362 case string:
363 printf("\"%s\"", (char*)stack_head->item->content.ptr);
364 break;
365 case symb:
366 printf("%s", ((symbol *)(stack_head->item->content.ptr))->id);
367 break;
368 case func:
369 printf("#<function %p>", (funcp)(stack_head->item->content.ptr));
370 break;
371 case list:
372 /* A list is just a stack, so make stack_head point to it */
373 stack_head=(stackitem *)(stack_head->item->content.ptr);
374 printf("[ ");
375 while(stack_head != NULL) {
376 print_h(stack_head);
377 printf(" ");
378 stack_head=stack_head->next;
379 }
380 printf("]");
381 break;
382 default:
383 printf("#<unknown %p>", (stack_head->item->content.ptr));
384 break;
385 }
386 }
387
388 extern void print_(environment *env) {
389 if(env->head==NULL) {
390 printerr("Too Few Arguments");
391 env->err=1;
392 return;
393 }
394 print_h(env->head);
395 }
396
397 /* Prints the top element of the stack and then discards it. */
398 extern void print(environment *env)
399 {
400 print_(env);
401 if(env->err) return;
402 toss(env);
403 }
404
405 /* Only to be called by function printstack. */
406 void print_st(stackitem *stack_head, long counter)
407 {
408 if(stack_head->next != NULL)
409 print_st(stack_head->next, counter+1);
410 printf("%ld: ", counter);
411 print_h(stack_head);
412 nl();
413 }
414
415 /* Prints the stack. */
416 extern void printstack(environment *env)
417 {
418 if(env->head == NULL) {
419 return;
420 }
421 print_st(env->head, 1);
422 nl();
423 }
424
425 /* Swap the two top elements on the stack. */
426 extern void swap(environment *env)
427 {
428 stackitem *temp= env->head;
429
430 if(env->head==NULL || env->head->next==NULL) {
431 printerr("Too Few Arguments");
432 env->err=1;
433 return;
434 }
435
436 env->head= env->head->next;
437 temp->next= env->head->next;
438 env->head->next= temp;
439 }
440
441 /* Recall a value from a symbol, if bound */
442 extern void rcl(environment *env)
443 {
444 value *val;
445
446 if(env->head == NULL) {
447 printerr("Too Few Arguments");
448 env->err=1;
449 return;
450 }
451
452 if(env->head->item->type!=symb) {
453 printerr("Bad Argument Type");
454 env->err=2;
455 return;
456 }
457
458 val=((symbol *)(env->head->item->content.ptr))->val;
459 if(val == NULL){
460 printerr("Unbound Variable");
461 env->err=3;
462 return;
463 }
464 toss(env); /* toss the symbol */
465 if(env->err) return;
466 push_val(&(env->head), val); /* Return its bound value */
467 }
468
469 void stack_read(environment*, char*);
470
471 /* If the top element is a symbol, determine if it's bound to a
472 function value, and if it is, toss the symbol and execute the
473 function. */
474 extern void eval(environment *env)
475 {
476 funcp in_func;
477 value* temp_val;
478 stackitem* iterator;
479 char* temp_string;
480
481 if(env->head==NULL) {
482 printerr("Too Few Arguments");
483 env->err=1;
484 return;
485 }
486
487 switch(env->head->item->type) {
488 /* if it's a symbol */
489 case symb:
490 rcl(env); /* get its contents */
491 if(env->err) return;
492 if(env->head->item->type!=symb){ /* don't recurse symbols */
493 eval(env); /* evaluate the value */
494 return;
495 }
496 break;
497
498 /* If it's a lone function value, run it */
499 case func:
500 in_func= (funcp)(env->head->item->content.ptr);
501 toss(env);
502 if(env->err) return;
503 (*in_func)(env);
504 break;
505
506 /* If it's a list */
507 case list:
508 temp_val= env->head->item;
509 env->head->item->refcount++;
510 toss(env);
511 if(env->err) return;
512 iterator= (stackitem*)temp_val->content.ptr;
513 while(iterator!=NULL && iterator->item!=NULL) {
514 push_val(&(env->head), iterator->item);
515 if(env->head->item->type==symb
516 && strcmp(";", ((symbol*)(env->head->item->content.ptr))->id)==0) {
517 toss(env);
518 if(env->err) return;
519 eval(env);
520 if(env->err) return;
521 }
522 iterator= iterator->next;
523 }
524 free_val(temp_val);
525 break;
526
527 /* If it's a string */
528 case string:
529 temp_val= env->head->item;
530 env->head->item->refcount++;
531 toss(env);
532 if(env->err) return;
533 temp_string= malloc(strlen((char*)temp_val->content.ptr)+5);
534 strcpy(temp_string, "[ ");
535 strcat(temp_string, (char*)temp_val->content.ptr);
536 strcat(temp_string, " ]");
537 stack_read(env, temp_string);
538 eval(env);
539 if(env->err) return;
540 free_val(temp_val);
541 free(temp_string);
542 break;
543
544 case integer:
545 break;
546 }
547 }
548
549 /* Reverse (flip) a list */
550 extern void rev(environment *env){
551 stackitem *old_head, *new_head, *item;
552
553 if((env->head)==NULL) {
554 printerr("Too Few Arguments");
555 env->err=1;
556 return;
557 }
558
559 if(env->head->item->type!=list) {
560 printerr("Bad Argument Type");
561 env->err=2;
562 return;
563 }
564
565 old_head=(stackitem *)(env->head->item->content.ptr);
566 new_head=NULL;
567 while(old_head != NULL){
568 item=old_head;
569 old_head=old_head->next;
570 item->next=new_head;
571 new_head=item;
572 }
573 env->head->item->content.ptr=new_head;
574 }
575
576 /* Make a list. */
577 extern void pack(environment *env)
578 {
579 void* delimiter;
580 stackitem *iterator, *temp;
581 value *pack;
582
583 delimiter= env->head->item->content.ptr; /* Get delimiter */
584 toss(env);
585
586 iterator= env->head;
587
588 if(iterator==NULL || iterator->item->content.ptr==delimiter) {
589 temp= NULL;
590 toss(env);
591 } else {
592 /* Search for first delimiter */
593 while(iterator->next!=NULL
594 && iterator->next->item->content.ptr!=delimiter)
595 iterator= iterator->next;
596
597 /* Extract list */
598 temp= env->head;
599 env->head= iterator->next;
600 iterator->next= NULL;
601
602 if(env->head!=NULL)
603 toss(env);
604 }
605
606 /* Push list */
607 pack= malloc(sizeof(value));
608 pack->type= list;
609 pack->content.ptr= temp;
610 pack->refcount= 1;
611
612 temp= malloc(sizeof(stackitem));
613 temp->item= pack;
614
615 push(&(env->head), temp);
616 rev(env);
617 }
618
619 /* Parse input. */
620 void stack_read(environment *env, char *in_line)
621 {
622 char *temp, *rest;
623 int itemp;
624 size_t inlength= strlen(in_line)+1;
625 int convert= 0;
626
627 temp= malloc(inlength);
628 rest= malloc(inlength);
629
630 do {
631 /* If comment */
632 if((convert= sscanf(in_line, "#%[^\n\r]", rest))) {
633 free(temp); free(rest);
634 return;
635 }
636
637 /* If string */
638 if((convert= sscanf(in_line, "\"%[^\"\n\r]\" %[^\n\r]", temp, rest))) {
639 push_cstring(&(env->head), temp);
640 break;
641 }
642 /* If integer */
643 if((convert= sscanf(in_line, "%d %[^\n\r]", &itemp, rest))) {
644 push_int(&(env->head), itemp);
645 break;
646 }
647 /* Escape ';' with '\' */
648 if((convert= sscanf(in_line, "\\%c%[^\n\r]", temp, rest))) {
649 temp[1]= '\0';
650 push_sym(env, temp);
651 break;
652 }
653 /* If symbol */
654 if((convert= sscanf(in_line, "%[^][ ;\n\r]%[^\n\r]", temp, rest))) {
655 push_sym(env, temp);
656 break;
657 }
658 /* If single char */
659 if((convert= sscanf(in_line, "%c%[^\n\r]", temp, rest))) {
660 if(*temp==';') {
661 if(!env->non_eval_flag) {
662 eval(env); /* Evaluate top element */
663 break;
664 }
665
666 push_sym(env, ";");
667 break;
668 }
669
670 if(*temp==']') {
671 push_sym(env, "[");
672 pack(env);
673 if(env->non_eval_flag)
674 env->non_eval_flag--;
675 break;
676 }
677
678 if(*temp=='[') {
679 push_sym(env, "[");
680 env->non_eval_flag++;
681 break;
682 }
683 }
684 } while(0);
685
686 free(temp);
687
688 if(convert<2) {
689 free(rest);
690 return;
691 }
692
693 stack_read(env, rest);
694
695 free(rest);
696 }
697
698 /* Relocate elements of the list on the stack. */
699 extern void expand(environment *env)
700 {
701 stackitem *temp, *new_head;
702
703 /* Is top element a list? */
704 if(env->head==NULL) {
705 printerr("Too Few Arguments");
706 env->err=1;
707 return;
708 }
709 if(env->head->item->type!=list) {
710 printerr("Bad Argument Type");
711 env->err=2;
712 return;
713 }
714
715 rev(env);
716
717 if(env->err)
718 return;
719
720 /* The first list element is the new stack head */
721 new_head= temp= env->head->item->content.ptr;
722
723 env->head->item->refcount++;
724 toss(env);
725
726 /* Find the end of the list */
727 while(temp->next!=NULL)
728 temp= temp->next;
729
730 /* Connect the tail of the list with the old stack head */
731 temp->next= env->head;
732 env->head= new_head; /* ...and voila! */
733
734 }
735
736 /* Compares two elements by reference. */
737 extern void eq(environment *env)
738 {
739 void *left, *right;
740 int result;
741
742 if((env->head)==NULL || env->head->next==NULL) {
743 printerr("Too Few Arguments");
744 env->err=1;
745 return;
746 }
747
748 left= env->head->item->content.ptr;
749 swap(env);
750 right= env->head->item->content.ptr;
751 result= (left==right);
752
753 toss(env); toss(env);
754 push_int(&(env->head), result);
755 }
756
757 /* Negates the top element on the stack. */
758 extern void not(environment *env)
759 {
760 int val;
761
762 if((env->head)==NULL) {
763 printerr("Too Few Arguments");
764 env->err=1;
765 return;
766 }
767
768 if(env->head->item->type!=integer) {
769 printerr("Bad Argument Type");
770 env->err=2;
771 return;
772 }
773
774 val= env->head->item->content.val;
775 toss(env);
776 push_int(&(env->head), !val);
777 }
778
779 /* Compares the two top elements on the stack and return 0 if they're the
780 same. */
781 extern void neq(environment *env)
782 {
783 eq(env);
784 not(env);
785 }
786
787 /* Give a symbol some content. */
788 extern void def(environment *env)
789 {
790 symbol *sym;
791
792 /* Needs two values on the stack, the top one must be a symbol */
793 if(env->head==NULL || env->head->next==NULL) {
794 printerr("Too Few Arguments");
795 env->err=1;
796 return;
797 }
798
799 if(env->head->item->type!=symb) {
800 printerr("Bad Argument Type");
801 env->err=2;
802 return;
803 }
804
805 /* long names are a pain */
806 sym=env->head->item->content.ptr;
807
808 /* if the symbol was bound to something else, throw it away */
809 if(sym->val != NULL)
810 free_val(sym->val);
811
812 /* Bind the symbol to the value */
813 sym->val= env->head->next->item;
814 sym->val->refcount++; /* Increase the reference counter */
815
816 toss(env); toss(env);
817 }
818
819 /* Quit stack. */
820 extern void quit(environment *env)
821 {
822 exit(EXIT_SUCCESS);
823 }
824
825 /* Clear stack */
826 extern void clear(environment *env)
827 {
828 while(env->head!=NULL)
829 toss(env);
830 }
831
832 /* List all defined words */
833 extern void words(environment *env)
834 {
835 symbol *temp;
836 int i;
837
838 for(i= 0; i<HASHTBLSIZE; i++) {
839 temp= env->symbols[i];
840 while(temp!=NULL) {
841 printf("%s\n", temp->id);
842 temp= temp->next;
843 }
844 }
845 }
846
847 /* Forgets a symbol (remove it from the hash table) */
848 extern void forget(environment *env)
849 {
850 char* sym_id;
851 stackitem *stack_head= env->head;
852 symbol **hash_entry, *temp;
853
854 if(stack_head==NULL) {
855 printerr("Too Few Arguments");
856 env->err=1;
857 return;
858 }
859
860 if(stack_head->item->type!=symb) {
861 printerr("Bad Argument Type");
862 env->err=2;
863 return;
864 }
865
866 sym_id= ((symbol*)(stack_head->item->content.ptr))->id;
867 toss(env);
868
869 hash_entry= hash(env->symbols, sym_id);
870 temp= *hash_entry;
871 *hash_entry= (*hash_entry)->next;
872
873 if(temp->val!=NULL) {
874 free_val(temp->val);
875 }
876 free(temp->id);
877 free(temp);
878 }
879
880 /* Returns the current error number to the stack */
881 extern void errn(environment *env){
882 push_int(&(env->head), env->err);
883 }
884
885 int main()
886 {
887 environment myenv;
888 char in_string[100];
889
890 init_env(&myenv);
891
892 printf("okidok\n ");
893
894 while(fgets(in_string, 100, stdin) != NULL) {
895 stack_read(&myenv, in_string);
896 if(myenv.err) {
897 printf("(error %d) ", myenv.err);
898 myenv.err=0;
899 }
900 printf("okidok\n ");
901 }
902 quit(&myenv);
903 return EXIT_FAILURE;
904 }
905
906 /* + */
907 extern void sx_2b(environment *env) {
908 int a, b;
909 size_t len;
910 char* new_string;
911 value *a_val, *b_val;
912
913 if((env->head)==NULL || env->head->next==NULL) {
914 printerr("Too Few Arguments");
915 env->err=1;
916 return;
917 }
918
919 if(env->head->item->type==string
920 && env->head->next->item->type==string) {
921 a_val= env->head->item;
922 b_val= env->head->next->item;
923 a_val->refcount++;
924 b_val->refcount++;
925 toss(env); if(env->err) return;
926 toss(env); if(env->err) return;
927 len= strlen(a_val->content.ptr)+strlen(b_val->content.ptr)+1;
928 new_string= malloc(len);
929 strcpy(new_string, b_val->content.ptr);
930 strcat(new_string, a_val->content.ptr);
931 free_val(a_val); free_val(b_val);
932 push_cstring(&(env->head), new_string);
933 free(new_string);
934 return;
935 }
936
937 if(env->head->item->type!=integer
938 || env->head->next->item->type!=integer) {
939 printerr("Bad Argument Type");
940 env->err=2;
941 return;
942 }
943 a=env->head->item->content.val;
944 toss(env);
945 if(env->err) return;
946 b=env->head->item->content.val;
947 toss(env);
948 if(env->err) return;
949 push_int(&(env->head), a+b);
950 }
951
952 /* Return copy of a value */
953 value *copy_val(value *old_value){
954 stackitem *old_item, *new_item, *prev_item;
955
956 value *new_value=malloc(sizeof(value));
957
958 new_value->type=old_value->type;
959 new_value->refcount=0; /* This is increased if/when this
960 value is referenced somewhere, like
961 in a stack item or a variable */
962 switch(old_value->type){
963 case integer:
964 new_value->content.val=old_value->content.val;
965 break;
966 case string:
967 (char *)(new_value->content.ptr)
968 = strdup((char *)(old_value->content.ptr));
969 break;
970 case func:
971 case symb:
972 new_value->content.ptr=old_value->content.ptr;
973 break;
974 case list:
975 new_value->content.ptr=NULL;
976
977 prev_item=NULL;
978 old_item=(stackitem *)(old_value->content.ptr);
979
980 while(old_item != NULL) { /* While list is not empty */
981 new_item= malloc(sizeof(stackitem));
982 new_item->item=copy_val(old_item->item); /* recurse */
983 new_item->next=NULL;
984 if(prev_item != NULL) /* If this wasn't the first item */
985 prev_item->next=new_item; /* point the previous item to the
986 new item */
987 else
988 new_value->content.ptr=new_item;
989 old_item=old_item->next;
990 prev_item=new_item;
991 }
992 break;
993 }
994 return new_value;
995 }
996
997 /* duplicates an item on the stack */
998 extern void dup(environment *env) {
999 if((env->head)==NULL) {
1000 printerr("Too Few Arguments");
1001 env->err=1;
1002 return;
1003 }
1004 push_val(&(env->head), copy_val(env->head->item));
1005 }

root@recompile.se
ViewVC Help
Powered by ViewVC 1.1.26