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

Contents of /stack/stack.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.85 - (show annotations)
Fri Feb 15 12:45:28 2002 UTC (22 years, 2 months ago) by teddy
Branch: MAIN
Changes since 1.84: +18 -15 lines
File MIME type: text/plain
(main): Only reset error flag after a complete read.

More consistent comments on mangled functions.

1 /* printf, sscanf, fgets, fprintf, fopen, perror */
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 /* getopt, STDIN_FILENO, STDOUT_FILENO */
12 #include <unistd.h>
13 /* EX_NOINPUT, EX_USAGE */
14 #include <sysexits.h>
15 /* mtrace, muntrace */
16 #include <mcheck.h>
17
18 #define HASHTBLSIZE 2048
19
20 /* First, define some types. */
21
22 /* A value of some type */
23 typedef struct {
24 enum {
25 integer,
26 string,
27 func, /* Function pointer */
28 symb,
29 list
30 } type; /* Type of stack element */
31
32 union {
33 void *ptr; /* Pointer to the content */
34 int val; /* ...or an integer */
35 } content; /* Stores a pointer or an integer */
36
37 int refcount; /* Reference counter */
38
39 } value;
40
41 /* A symbol with a name and possible value */
42 /* (These do not need reference counters, they are kept unique by
43 hashing.) */
44 typedef struct symbol_struct {
45 char *id; /* Symbol name */
46 value *val; /* The value (if any) bound to it */
47 struct symbol_struct *next; /* In case of hashing conflicts, a */
48 } symbol; /* symbol is a kind of stack item. */
49
50 /* A type for a hash table for symbols */
51 typedef symbol *hashtbl[HASHTBLSIZE]; /* Hash table declaration */
52
53 /* An item (value) on a stack */
54 typedef struct stackitem_struct
55 {
56 value *item; /* The value on the stack */
57 /* (This is never NULL) */
58 struct stackitem_struct *next; /* Next item */
59 } stackitem;
60
61 /* An environment; gives access to the stack and a hash table of
62 defined symbols */
63 typedef struct {
64 stackitem *head; /* Head of the stack */
65 hashtbl symbols; /* Hash table of all variable bindings */
66 int err; /* Error flag */
67 char *in_string; /* Input pending to be read */
68 char *free_string; /* Free this string when all input is
69 read from in_string */
70 FILE *inputstream; /* stdin or a file, most likely */
71 int interactive; /* print prompts, stack, etc */
72 } environment;
73
74 /* A type for pointers to external functions */
75 typedef void (*funcp)(environment *); /* funcp is a pointer to a void
76 function (environment *) */
77
78 /* Initialize a newly created environment */
79 void init_env(environment *env)
80 {
81 int i;
82
83 env->head= NULL;
84 for(i= 0; i<HASHTBLSIZE; i++)
85 env->symbols[i]= NULL;
86 env->err= 0;
87 env->in_string= NULL;
88 env->free_string= NULL;
89 env->inputstream= stdin;
90 env->interactive= 1;
91 }
92
93 void printerr(const char* in_string) {
94 fprintf(stderr, "Err: %s\n", in_string);
95 }
96
97 /* Throw away a value */
98 void free_val(value *val){
99 stackitem *item, *temp;
100
101 val->refcount--; /* Decrease the reference count */
102 if(val->refcount == 0){
103 switch (val->type){ /* and free the contents if necessary */
104 case string:
105 free(val->content.ptr);
106 break;
107 case list: /* lists needs to be freed recursively */
108 item=val->content.ptr;
109 while(item != NULL) { /* for all stack items */
110 free_val(item->item); /* free the value */
111 temp=item->next; /* save next ptr */
112 free(item); /* free the stackitem */
113 item=temp; /* go to next stackitem */
114 }
115 break;
116 case integer:
117 case func:
118 break;
119 case symb:
120 free(((symbol*)(val->content.ptr))->id);
121 if(((symbol*)(val->content.ptr))->val!=NULL)
122 free_val(((symbol*)(val->content.ptr))->val);
123 free(val->content.ptr);
124 break;
125 }
126 free(val); /* Free the actual value structure */
127 }
128 }
129
130 /* Discard the top element of the stack. */
131 extern void toss(environment *env)
132 {
133 stackitem *temp= env->head;
134
135 if((env->head)==NULL) {
136 printerr("Too Few Arguments");
137 env->err=1;
138 return;
139 }
140
141 free_val(env->head->item); /* Free the value */
142 env->head= env->head->next; /* Remove the top stack item */
143 free(temp); /* Free the old top stack item */
144 }
145
146 /* Returns a pointer to a pointer to an element in the hash table. */
147 symbol **hash(hashtbl in_hashtbl, const char *in_string)
148 {
149 int i= 0;
150 unsigned int out_hash= 0;
151 char key= '\0';
152 symbol **position;
153
154 while(1){ /* Hash in_string */
155 key= in_string[i++];
156 if(key=='\0')
157 break;
158 out_hash= out_hash*32+key;
159 }
160
161 out_hash= out_hash%HASHTBLSIZE;
162 position= &(in_hashtbl[out_hash]);
163
164 while(1){
165 if(*position==NULL) /* If empty */
166 return position;
167
168 if(strcmp(in_string, (*position)->id)==0) /* If match */
169 return position;
170
171 position= &((*position)->next); /* Try next */
172 }
173 }
174
175 /* Push a value onto the stack */
176 void push_val(environment *env, value *val)
177 {
178 stackitem *new_item= malloc(sizeof(stackitem));
179 new_item->item= val;
180 val->refcount++;
181 new_item->next= env->head;
182 env->head= new_item;
183 }
184
185 /* Push an integer onto the stack. */
186 void push_int(environment *env, int in_val)
187 {
188 value *new_value= malloc(sizeof(value));
189
190 new_value->content.val= in_val;
191 new_value->type= integer;
192 new_value->refcount= 0;
193
194 push_val(env, new_value);
195 }
196
197 /* Copy a string onto the stack. */
198 void push_cstring(environment *env, const char *in_string)
199 {
200 value *new_value= malloc(sizeof(value));
201
202 new_value->content.ptr= malloc(strlen(in_string)+1);
203 strcpy(new_value->content.ptr, in_string);
204 new_value->type= string;
205 new_value->refcount= 0;
206
207 push_val(env, new_value);
208 }
209
210 /* Mangle a symbol name to a valid C identifier name */
211 char *mangle_str(const char *old_string){
212 char validchars[]
213 ="0123456789abcdef";
214 char *new_string, *current;
215
216 new_string=malloc((strlen(old_string)*2)+4);
217 strcpy(new_string, "sx_"); /* Stack eXternal */
218 current=new_string+3;
219 while(old_string[0] != '\0'){
220 current[0]=validchars[(unsigned char)(old_string[0])/16];
221 current[1]=validchars[(unsigned char)(old_string[0])%16];
222 current+=2;
223 old_string++;
224 }
225 current[0]='\0';
226
227 return new_string; /* The caller must free() it */
228 }
229
230 extern void mangle(environment *env){
231 char *new_string;
232
233 if((env->head)==NULL) {
234 printerr("Too Few Arguments");
235 env->err=1;
236 return;
237 }
238
239 if(env->head->item->type!=string) {
240 printerr("Bad Argument Type");
241 env->err=2;
242 return;
243 }
244
245 new_string= mangle_str((const char *)(env->head->item->content.ptr));
246
247 toss(env);
248 if(env->err) return;
249
250 push_cstring(env, new_string);
251 }
252
253 /* Push a symbol onto the stack. */
254 void push_sym(environment *env, const char *in_string)
255 {
256 value *new_value; /* A new symbol value */
257 /* ...which might point to... */
258 symbol **new_symbol; /* (if needed) A new actual symbol */
259 /* ...which, if possible, will be bound to... */
260 value *new_fvalue; /* (if needed) A new function value */
261 /* ...which will point to... */
262 void *funcptr; /* A function pointer */
263
264 static void *handle= NULL; /* Dynamic linker handle */
265 const char *dlerr; /* Dynamic linker error */
266 char *mangled; /* Mangled function name */
267
268 new_value= malloc(sizeof(value));
269
270 /* The new value is a symbol */
271 new_value->type= symb;
272 new_value->refcount= 1;
273
274 /* Look up the symbol name in the hash table */
275 new_symbol= hash(env->symbols, in_string);
276 new_value->content.ptr= *new_symbol;
277
278 if(*new_symbol==NULL) { /* If symbol was undefined */
279
280 /* Create a new symbol */
281 (*new_symbol)= malloc(sizeof(symbol));
282 (*new_symbol)->val= NULL; /* undefined value */
283 (*new_symbol)->next= NULL;
284 (*new_symbol)->id= malloc(strlen(in_string)+1);
285 strcpy((*new_symbol)->id, in_string);
286
287 /* Intern the new symbol in the hash table */
288 new_value->content.ptr= *new_symbol;
289
290 /* Try to load the symbol name as an external function, to see if
291 we should bind the symbol to a new function pointer value */
292 if(handle==NULL) /* If no handle */
293 handle= dlopen(NULL, RTLD_LAZY);
294
295 funcptr= dlsym(handle, in_string); /* Get function pointer */
296 dlerr=dlerror();
297 if(dlerr != NULL) { /* If no function was found */
298 mangled=mangle_str(in_string);
299 funcptr= dlsym(handle, mangled); /* try mangling it */
300 free(mangled);
301 dlerr=dlerror();
302 }
303 if(dlerr==NULL) { /* If a function was found */
304 new_fvalue= malloc(sizeof(value)); /* Create a new value */
305 new_fvalue->type=func; /* The new value is a function pointer */
306 new_fvalue->content.ptr=funcptr; /* Store function pointer */
307 (*new_symbol)->val= new_fvalue; /* Bind the symbol to the new
308 function value */
309 new_fvalue->refcount= 1;
310 }
311 }
312 push_val(env, new_value);
313 }
314
315 /* Print newline. */
316 extern void nl()
317 {
318 printf("\n");
319 }
320
321 /* Gets the type of a value */
322 extern void type(environment *env){
323 int typenum;
324
325 if((env->head)==NULL) {
326 printerr("Too Few Arguments");
327 env->err=1;
328 return;
329 }
330 typenum=env->head->item->type;
331 toss(env);
332 switch(typenum){
333 case integer:
334 push_sym(env, "integer");
335 break;
336 case string:
337 push_sym(env, "string");
338 break;
339 case symb:
340 push_sym(env, "symbol");
341 break;
342 case func:
343 push_sym(env, "function");
344 break;
345 case list:
346 push_sym(env, "list");
347 break;
348 }
349 }
350
351 /* Prints the top element of the stack. */
352 void print_h(stackitem *stack_head, int noquote)
353 {
354 switch(stack_head->item->type) {
355 case integer:
356 printf("%d", stack_head->item->content.val);
357 break;
358 case string:
359 if(noquote)
360 printf("%s", (char*)stack_head->item->content.ptr);
361 else
362 printf("\"%s\"", (char*)stack_head->item->content.ptr);
363 break;
364 case symb:
365 printf("%s", ((symbol *)(stack_head->item->content.ptr))->id);
366 break;
367 case func:
368 printf("#<function %p>", (funcp)(stack_head->item->content.ptr));
369 break;
370 case list:
371 /* A list is just a stack, so make stack_head point to it */
372 stack_head=(stackitem *)(stack_head->item->content.ptr);
373 printf("[ ");
374 while(stack_head != NULL) {
375 print_h(stack_head, noquote);
376 printf(" ");
377 stack_head=stack_head->next;
378 }
379 printf("]");
380 break;
381 }
382 }
383
384 extern void print_(environment *env) {
385 if(env->head==NULL) {
386 printerr("Too Few Arguments");
387 env->err=1;
388 return;
389 }
390 print_h(env->head, 0);
391 nl();
392 }
393
394 /* Prints the top element of the stack and then discards it. */
395 extern void print(environment *env)
396 {
397 print_(env);
398 if(env->err) return;
399 toss(env);
400 }
401
402 extern void princ_(environment *env) {
403 if(env->head==NULL) {
404 printerr("Too Few Arguments");
405 env->err=1;
406 return;
407 }
408 print_h(env->head, 1);
409 }
410
411 /* Prints the top element of the stack and then discards it. */
412 extern void princ(environment *env)
413 {
414 princ_(env);
415 if(env->err) return;
416 toss(env);
417 }
418
419 /* Only to be called by function printstack. */
420 void print_st(stackitem *stack_head, long counter)
421 {
422 if(stack_head->next != NULL)
423 print_st(stack_head->next, counter+1);
424 printf("%ld: ", counter);
425 print_h(stack_head, 0);
426 nl();
427 }
428
429 /* Prints the stack. */
430 extern void printstack(environment *env)
431 {
432 if(env->head == NULL) {
433 printf("Stack Empty\n");
434 return;
435 }
436 print_st(env->head, 1);
437 }
438
439 /* Swap the two top elements on the stack. */
440 extern void swap(environment *env)
441 {
442 stackitem *temp= env->head;
443
444 if(env->head==NULL || env->head->next==NULL) {
445 printerr("Too Few Arguments");
446 env->err=1;
447 return;
448 }
449
450 env->head= env->head->next;
451 temp->next= env->head->next;
452 env->head->next= temp;
453 }
454
455 /* Rotate the first three elements on the stack. */
456 extern void rot(environment *env)
457 {
458 stackitem *temp= env->head;
459
460 if(env->head==NULL || env->head->next==NULL
461 || env->head->next->next==NULL) {
462 printerr("Too Few Arguments");
463 env->err=1;
464 return;
465 }
466
467 env->head= env->head->next->next;
468 temp->next->next= env->head->next;
469 env->head->next= temp;
470 }
471
472 /* Recall a value from a symbol, if bound */
473 extern void rcl(environment *env)
474 {
475 value *val;
476
477 if(env->head == NULL) {
478 printerr("Too Few Arguments");
479 env->err=1;
480 return;
481 }
482
483 if(env->head->item->type!=symb) {
484 printerr("Bad Argument Type");
485 env->err=2;
486 return;
487 }
488
489 val=((symbol *)(env->head->item->content.ptr))->val;
490 if(val == NULL){
491 printerr("Unbound Variable");
492 env->err=3;
493 return;
494 }
495 toss(env); /* toss the symbol */
496 if(env->err) return;
497 push_val(env, val); /* Return its bound value */
498 }
499
500 /* If the top element is a symbol, determine if it's bound to a
501 function value, and if it is, toss the symbol and execute the
502 function. */
503 extern void eval(environment *env)
504 {
505 funcp in_func;
506 value* temp_val;
507 stackitem* iterator;
508
509 eval_start:
510
511 if(env->head==NULL) {
512 printerr("Too Few Arguments");
513 env->err=1;
514 return;
515 }
516
517 switch(env->head->item->type) {
518 /* if it's a symbol */
519 case symb:
520 rcl(env); /* get its contents */
521 if(env->err) return;
522 if(env->head->item->type!=symb){ /* don't recurse symbols */
523 goto eval_start;
524 }
525 return;
526
527 /* If it's a lone function value, run it */
528 case func:
529 in_func= (funcp)(env->head->item->content.ptr);
530 toss(env);
531 if(env->err) return;
532 return (*in_func)(env);
533
534 /* If it's a list */
535 case list:
536 temp_val= env->head->item;
537 env->head->item->refcount++;
538 toss(env);
539 if(env->err) return;
540 iterator= (stackitem*)temp_val->content.ptr;
541 while(iterator!=NULL) {
542 push_val(env, iterator->item);
543 if(env->head->item->type==symb
544 && strcmp(";", ((symbol*)(env->head->item->content.ptr))->id)==0) {
545 toss(env);
546 if(env->err) return;
547 if(iterator->next == NULL){
548 free_val(temp_val);
549 goto eval_start;
550 }
551 eval(env);
552 if(env->err) return;
553 }
554 iterator= iterator->next;
555 }
556 free_val(temp_val);
557 return;
558
559 default:
560 return;
561 }
562 }
563
564 /* Reverse (flip) a list */
565 extern void rev(environment *env){
566 stackitem *old_head, *new_head, *item;
567
568 if((env->head)==NULL) {
569 printerr("Too Few Arguments");
570 env->err=1;
571 return;
572 }
573
574 if(env->head->item->type!=list) {
575 printerr("Bad Argument Type");
576 env->err=2;
577 return;
578 }
579
580 old_head=(stackitem *)(env->head->item->content.ptr);
581 new_head=NULL;
582 while(old_head != NULL){
583 item=old_head;
584 old_head=old_head->next;
585 item->next=new_head;
586 new_head=item;
587 }
588 env->head->item->content.ptr=new_head;
589 }
590
591 /* Make a list. */
592 extern void pack(environment *env)
593 {
594 stackitem *iterator, *temp;
595 value *pack;
596
597 iterator= env->head;
598
599 if(iterator==NULL
600 || (iterator->item->type==symb
601 && ((symbol*)(iterator->item->content.ptr))->id[0]=='[')) {
602 temp= NULL;
603 toss(env);
604 } else {
605 /* Search for first delimiter */
606 while(iterator->next!=NULL
607 && (iterator->next->item->type!=symb
608 || ((symbol*)(iterator->next->item->content.ptr))->id[0]!='['))
609 iterator= iterator->next;
610
611 /* Extract list */
612 temp= env->head;
613 env->head= iterator->next;
614 iterator->next= NULL;
615
616 if(env->head!=NULL)
617 toss(env);
618 }
619
620 /* Push list */
621 pack= malloc(sizeof(value));
622 pack->type= list;
623 pack->content.ptr= temp;
624 pack->refcount= 0;
625
626 push_val(env, pack);
627 rev(env);
628 }
629
630 /* Relocate elements of the list on the stack. */
631 extern void expand(environment *env)
632 {
633 stackitem *temp, *new_head;
634
635 /* Is top element a list? */
636 if(env->head==NULL) {
637 printerr("Too Few Arguments");
638 env->err=1;
639 return;
640 }
641 if(env->head->item->type!=list) {
642 printerr("Bad Argument Type");
643 env->err=2;
644 return;
645 }
646
647 rev(env);
648
649 if(env->err)
650 return;
651
652 /* The first list element is the new stack head */
653 new_head= temp= env->head->item->content.ptr;
654
655 env->head->item->refcount++;
656 toss(env);
657
658 /* Find the end of the list */
659 while(temp->next!=NULL)
660 temp= temp->next;
661
662 /* Connect the tail of the list with the old stack head */
663 temp->next= env->head;
664 env->head= new_head; /* ...and voila! */
665
666 }
667
668 /* Compares two elements by reference. */
669 extern void eq(environment *env)
670 {
671 void *left, *right;
672 int result;
673
674 if((env->head)==NULL || env->head->next==NULL) {
675 printerr("Too Few Arguments");
676 env->err=1;
677 return;
678 }
679
680 left= env->head->item->content.ptr;
681 swap(env);
682 right= env->head->item->content.ptr;
683 result= (left==right);
684
685 toss(env); toss(env);
686 push_int(env, result);
687 }
688
689 /* Negates the top element on the stack. */
690 extern void not(environment *env)
691 {
692 int val;
693
694 if((env->head)==NULL) {
695 printerr("Too Few Arguments");
696 env->err=1;
697 return;
698 }
699
700 if(env->head->item->type!=integer) {
701 printerr("Bad Argument Type");
702 env->err=2;
703 return;
704 }
705
706 val= env->head->item->content.val;
707 toss(env);
708 push_int(env, !val);
709 }
710
711 /* Compares the two top elements on the stack and return 0 if they're the
712 same. */
713 extern void neq(environment *env)
714 {
715 eq(env);
716 not(env);
717 }
718
719 /* Give a symbol some content. */
720 extern void def(environment *env)
721 {
722 symbol *sym;
723
724 /* Needs two values on the stack, the top one must be a symbol */
725 if(env->head==NULL || env->head->next==NULL) {
726 printerr("Too Few Arguments");
727 env->err=1;
728 return;
729 }
730
731 if(env->head->item->type!=symb) {
732 printerr("Bad Argument Type");
733 env->err=2;
734 return;
735 }
736
737 /* long names are a pain */
738 sym=env->head->item->content.ptr;
739
740 /* if the symbol was bound to something else, throw it away */
741 if(sym->val != NULL)
742 free_val(sym->val);
743
744 /* Bind the symbol to the value */
745 sym->val= env->head->next->item;
746 sym->val->refcount++; /* Increase the reference counter */
747
748 toss(env); toss(env);
749 }
750
751 extern void clear(environment *);
752 void forget_sym(symbol **);
753 extern void words(environment *);
754
755 /* Quit stack. */
756 extern void quit(environment *env)
757 {
758 long i;
759
760 clear(env);
761
762 if (env->err) return;
763 for(i= 0; i<HASHTBLSIZE; i++) {
764 while(env->symbols[i]!= NULL) {
765 forget_sym(&(env->symbols[i]));
766 }
767 env->symbols[i]= NULL;
768 }
769
770 if(env->free_string!=NULL)
771 free(env->free_string);
772
773 muntrace();
774
775 exit(EXIT_SUCCESS);
776 }
777
778 /* Clear stack */
779 extern void clear(environment *env)
780 {
781 while(env->head!=NULL)
782 toss(env);
783 }
784
785 /* List all defined words */
786 extern void words(environment *env)
787 {
788 symbol *temp;
789 int i;
790
791 for(i= 0; i<HASHTBLSIZE; i++) {
792 temp= env->symbols[i];
793 while(temp!=NULL) {
794 printf("%s\n", temp->id);
795 temp= temp->next;
796 }
797 }
798 }
799
800 /* Internal forget function */
801 void forget_sym(symbol **hash_entry) {
802 symbol *temp;
803
804 temp= *hash_entry;
805 *hash_entry= (*hash_entry)->next;
806
807 if(temp->val!=NULL) {
808 free_val(temp->val);
809 }
810 free(temp->id);
811 free(temp);
812 }
813
814 /* Forgets a symbol (remove it from the hash table) */
815 extern void forget(environment *env)
816 {
817 char* sym_id;
818 stackitem *stack_head= env->head;
819
820 if(stack_head==NULL) {
821 printerr("Too Few Arguments");
822 env->err=1;
823 return;
824 }
825
826 if(stack_head->item->type!=symb) {
827 printerr("Bad Argument Type");
828 env->err=2;
829 return;
830 }
831
832 sym_id= ((symbol*)(stack_head->item->content.ptr))->id;
833 toss(env);
834
835 return forget_sym(hash(env->symbols, sym_id));
836 }
837
838 /* Returns the current error number to the stack */
839 extern void errn(environment *env){
840 push_int(env, env->err);
841 }
842
843 extern void sx_72656164(environment*);
844
845 int main(int argc, char **argv)
846 {
847 environment myenv;
848
849 int c; /* getopt option character */
850
851 mtrace();
852
853 init_env(&myenv);
854
855 myenv.interactive = isatty(STDIN_FILENO) && isatty(STDOUT_FILENO);
856
857 while ((c = getopt (argc, argv, "i")) != -1)
858 switch (c)
859 {
860 case 'i':
861 myenv.interactive = 1;
862 break;
863 case '?':
864 fprintf (stderr,
865 "Unknown option character `\\x%x'.\n",
866 optopt);
867 return EX_USAGE;
868 default:
869 abort ();
870 }
871
872 if (optind < argc) {
873 myenv.interactive = 0;
874 myenv.inputstream= fopen(argv[optind], "r");
875 if(myenv.inputstream== NULL) {
876 perror(argv[0]);
877 exit (EX_NOINPUT);
878 }
879 }
880
881 while(1) {
882 if(myenv.in_string==NULL) {
883 if (myenv.interactive) {
884 if(myenv.err) {
885 printf("(error %d)\n", myenv.err);
886 }
887 nl();
888 printstack(&myenv);
889 printf("> ");
890 }
891 myenv.err=0;
892 }
893 sx_72656164(&myenv);
894 if (myenv.err==4) {
895 return EX_NOINPUT;
896 } else if(myenv.head!=NULL
897 && myenv.head->item->type==symb
898 && ((symbol*)(myenv.head->item->content.ptr))->id[0]==';') {
899 toss(&myenv); /* No error check in main */
900 eval(&myenv);
901 }
902 }
903 quit(&myenv);
904 return EXIT_FAILURE;
905 }
906
907 /* "+" */
908 extern void sx_2b(environment *env) {
909 int a, b;
910 size_t len;
911 char* new_string;
912 value *a_val, *b_val;
913
914 if((env->head)==NULL || env->head->next==NULL) {
915 printerr("Too Few Arguments");
916 env->err=1;
917 return;
918 }
919
920 if(env->head->item->type==string
921 && env->head->next->item->type==string) {
922 a_val= env->head->item;
923 b_val= env->head->next->item;
924 a_val->refcount++;
925 b_val->refcount++;
926 toss(env); if(env->err) return;
927 toss(env); if(env->err) return;
928 len= strlen(a_val->content.ptr)+strlen(b_val->content.ptr)+1;
929 new_string= malloc(len);
930 strcpy(new_string, b_val->content.ptr);
931 strcat(new_string, a_val->content.ptr);
932 free_val(a_val); free_val(b_val);
933 push_cstring(env, new_string);
934 free(new_string);
935 return;
936 }
937
938 if(env->head->item->type!=integer
939 || env->head->next->item->type!=integer) {
940 printerr("Bad Argument Type");
941 env->err=2;
942 return;
943 }
944 a=env->head->item->content.val;
945 toss(env);
946 if(env->err) return;
947 if(env->head->item->refcount == 1)
948 env->head->item->content.val += a;
949 else {
950 b=env->head->item->content.val;
951 toss(env);
952 if(env->err) return;
953 push_int(env, a+b);
954 }
955 }
956
957 /* "-" */
958 extern void sx_2d(environment *env) {
959 int a, b;
960
961 if((env->head)==NULL || env->head->next==NULL) {
962 printerr("Too Few Arguments");
963 env->err=1;
964 return;
965 }
966
967 if(env->head->item->type!=integer
968 || env->head->next->item->type!=integer) {
969 printerr("Bad Argument Type");
970 env->err=2;
971 return;
972 }
973 a=env->head->item->content.val;
974 toss(env);
975 if(env->err) return;
976 if(env->head->item->refcount == 1)
977 env->head->item->content.val -= a;
978 else {
979 b=env->head->item->content.val;
980 toss(env);
981 if(env->err) return;
982 push_int(env, b-a);
983 }
984 }
985
986 /* ">" */
987 extern void sx_3e(environment *env) {
988 int a, b;
989
990 if((env->head)==NULL || env->head->next==NULL) {
991 printerr("Too Few Arguments");
992 env->err=1;
993 return;
994 }
995
996 if(env->head->item->type!=integer
997 || env->head->next->item->type!=integer) {
998 printerr("Bad Argument Type");
999 env->err=2;
1000 return;
1001 }
1002 a=env->head->item->content.val;
1003 toss(env);
1004 if(env->err) return;
1005 if(env->head->item->refcount == 1)
1006 env->head->item->content.val = (env->head->item->content.val > a);
1007 else {
1008 b=env->head->item->content.val;
1009 toss(env);
1010 if(env->err) return;
1011 push_int(env, b>a);
1012 }
1013 }
1014
1015 /* Return copy of a value */
1016 value *copy_val(value *old_value){
1017 stackitem *old_item, *new_item, *prev_item;
1018
1019 value *new_value=malloc(sizeof(value));
1020
1021 new_value->type=old_value->type;
1022 new_value->refcount=0; /* This is increased if/when this
1023 value is referenced somewhere, like
1024 in a stack item or a variable */
1025 switch(old_value->type){
1026 case integer:
1027 new_value->content.val=old_value->content.val;
1028 break;
1029 case string:
1030 (char *)(new_value->content.ptr)
1031 = strdup((char *)(old_value->content.ptr));
1032 break;
1033 case func:
1034 case symb:
1035 new_value->content.ptr=old_value->content.ptr;
1036 break;
1037 case list:
1038 new_value->content.ptr=NULL;
1039
1040 prev_item=NULL;
1041 old_item=(stackitem *)(old_value->content.ptr);
1042
1043 while(old_item != NULL) { /* While list is not empty */
1044 new_item= malloc(sizeof(stackitem));
1045 new_item->item=copy_val(old_item->item); /* recurse */
1046 new_item->next=NULL;
1047 if(prev_item != NULL) /* If this wasn't the first item */
1048 prev_item->next=new_item; /* point the previous item to the
1049 new item */
1050 else
1051 new_value->content.ptr=new_item;
1052 old_item=old_item->next;
1053 prev_item=new_item;
1054 }
1055 break;
1056 }
1057 return new_value;
1058 }
1059
1060 /* "dup"; duplicates an item on the stack */
1061 extern void sx_647570(environment *env) {
1062 if((env->head)==NULL) {
1063 printerr("Too Few Arguments");
1064 env->err=1;
1065 return;
1066 }
1067 push_val(env, copy_val(env->head->item));
1068 }
1069
1070 /* "if", If-Then */
1071 extern void sx_6966(environment *env) {
1072
1073 int truth;
1074
1075 if((env->head)==NULL || env->head->next==NULL) {
1076 printerr("Too Few Arguments");
1077 env->err=1;
1078 return;
1079 }
1080
1081 if(env->head->next->item->type != integer) {
1082 printerr("Bad Argument Type");
1083 env->err=2;
1084 return;
1085 }
1086
1087 swap(env);
1088 if(env->err) return;
1089
1090 truth=env->head->item->content.val;
1091
1092 toss(env);
1093 if(env->err) return;
1094
1095 if(truth)
1096 eval(env);
1097 else
1098 toss(env);
1099 }
1100
1101 /* If-Then-Else */
1102 extern void ifelse(environment *env) {
1103
1104 int truth;
1105
1106 if((env->head)==NULL || env->head->next==NULL
1107 || env->head->next->next==NULL) {
1108 printerr("Too Few Arguments");
1109 env->err=1;
1110 return;
1111 }
1112
1113 if(env->head->next->next->item->type != integer) {
1114 printerr("Bad Argument Type");
1115 env->err=2;
1116 return;
1117 }
1118
1119 rot(env);
1120 if(env->err) return;
1121
1122 truth=env->head->item->content.val;
1123
1124 toss(env);
1125 if(env->err) return;
1126
1127 if(!truth)
1128 swap(env);
1129 if(env->err) return;
1130
1131 toss(env);
1132 if(env->err) return;
1133
1134 eval(env);
1135 }
1136
1137 /* "while" */
1138 extern void sx_7768696c65(environment *env) {
1139
1140 int truth;
1141 value *loop, *test;
1142
1143 if((env->head)==NULL || env->head->next==NULL) {
1144 printerr("Too Few Arguments");
1145 env->err=1;
1146 return;
1147 }
1148
1149 loop= env->head->item;
1150 loop->refcount++;
1151 toss(env); if(env->err) return;
1152
1153 test= env->head->item;
1154 test->refcount++;
1155 toss(env); if(env->err) return;
1156
1157 do {
1158 push_val(env, test);
1159 eval(env);
1160
1161 if(env->head->item->type != integer) {
1162 printerr("Bad Argument Type");
1163 env->err=2;
1164 return;
1165 }
1166
1167 truth= env->head->item->content.val;
1168 toss(env); if(env->err) return;
1169
1170 if(truth) {
1171 push_val(env, loop);
1172 eval(env);
1173 } else {
1174 toss(env);
1175 }
1176
1177 } while(truth);
1178
1179 free_val(test);
1180 free_val(loop);
1181 }
1182
1183 /* "for"; For-loop */
1184 extern void sx_666f72(environment *env) {
1185
1186 value *loop, *foo;
1187 stackitem *iterator;
1188
1189 if((env->head)==NULL || env->head->next==NULL) {
1190 printerr("Too Few Arguments");
1191 env->err=1;
1192 return;
1193 }
1194
1195 if(env->head->next->item->type != list) {
1196 printerr("Bad Argument Type");
1197 env->err=2;
1198 return;
1199 }
1200
1201 loop= env->head->item;
1202 loop->refcount++;
1203 toss(env); if(env->err) return;
1204
1205 foo= env->head->item;
1206 foo->refcount++;
1207 toss(env); if(env->err) return;
1208
1209 iterator= foo->content.ptr;
1210
1211 while(iterator!=NULL) {
1212 push_val(env, iterator->item);
1213 push_val(env, loop);
1214 eval(env); if(env->err) return;
1215 iterator= iterator->next;
1216 }
1217
1218 free_val(loop);
1219 free_val(foo);
1220 }
1221
1222 /* "to" */
1223 extern void to(environment *env) {
1224 int i, start, ending;
1225 stackitem *temp_head;
1226 value *temp_val;
1227
1228 if((env->head)==NULL || env->head->next==NULL) {
1229 printerr("Too Few Arguments");
1230 env->err=1;
1231 return;
1232 }
1233
1234 if(env->head->item->type!=integer
1235 || env->head->next->item->type!=integer) {
1236 printerr("Bad Argument Type");
1237 env->err=2;
1238 return;
1239 }
1240
1241 ending= env->head->item->content.val;
1242 toss(env); if(env->err) return;
1243 start= env->head->item->content.val;
1244 toss(env); if(env->err) return;
1245
1246 temp_head= env->head;
1247 env->head= NULL;
1248
1249 if(ending>=start) {
1250 for(i= ending; i>=start; i--)
1251 push_int(env, i);
1252 } else {
1253 for(i= ending; i<=start; i++)
1254 push_int(env, i);
1255 }
1256
1257 temp_val= malloc(sizeof(value));
1258 temp_val->content.ptr= env->head;
1259 temp_val->refcount= 0;
1260 temp_val->type= list;
1261 env->head= temp_head;
1262 push_val(env, temp_val);
1263 }
1264
1265 /* Read a string */
1266 extern void readline(environment *env) {
1267 char in_string[101];
1268
1269 if(fgets(in_string, 100, env->inputstream)==NULL)
1270 push_cstring(env, "");
1271 else
1272 push_cstring(env, in_string);
1273 }
1274
1275 /* "read"; Read a value and place on stack */
1276 extern void sx_72656164(environment *env) {
1277 const char symbform[]= "%[a-zA-Z0-9!$%*+./:<=>?@^_~-]%n";
1278 const char strform[]= "\"%[^\"]\"%n";
1279 const char intform[]= "%i%n";
1280 const char blankform[]= "%*[ \t]%n";
1281 const char ebrackform[]= "%*1[]]%n";
1282 const char semicform[]= "%*1[;]%n";
1283 const char bbrackform[]= "%*1[[]%n";
1284
1285 int itemp, readlength= -1;
1286 static int depth= 0;
1287 char *match;
1288 size_t inlength;
1289
1290 if(env->in_string==NULL) {
1291 if(depth > 0 && env->interactive) {
1292 printf("]> ");
1293 }
1294 readline(env); if(env->err) return;
1295
1296 if(((char *)(env->head->item->content.ptr))[0]=='\0'){
1297 env->err= 4; /* "" means EOF */
1298 return;
1299 }
1300
1301 env->in_string= malloc(strlen(env->head->item->content.ptr)+1);
1302 env->free_string= env->in_string; /* Save the original pointer */
1303 strcpy(env->in_string, env->head->item->content.ptr);
1304 toss(env); if(env->err) return;
1305 }
1306
1307 inlength= strlen(env->in_string)+1;
1308 match= malloc(inlength);
1309
1310 if(sscanf(env->in_string, blankform, &readlength)!=EOF
1311 && readlength != -1) {
1312 ;
1313 } else if(sscanf(env->in_string, intform, &itemp, &readlength) != EOF
1314 && readlength != -1) {
1315 push_int(env, itemp);
1316 } else if(sscanf(env->in_string, strform, match, &readlength) != EOF
1317 && readlength != -1) {
1318 push_cstring(env, match);
1319 } else if(sscanf(env->in_string, symbform, match, &readlength) != EOF
1320 && readlength != -1) {
1321 push_sym(env, match);
1322 } else if(sscanf(env->in_string, ebrackform, &readlength) != EOF
1323 && readlength != -1) {
1324 pack(env); if(env->err) return;
1325 if(depth != 0) depth--;
1326 } else if(sscanf(env->in_string, semicform, &readlength) != EOF
1327 && readlength != -1) {
1328 push_sym(env, ";");
1329 } else if(sscanf(env->in_string, bbrackform, &readlength) != EOF
1330 && readlength != -1) {
1331 push_sym(env, "[");
1332 depth++;
1333 } else {
1334 free(env->free_string);
1335 env->in_string = env->free_string = NULL;
1336 }
1337 if ( env->in_string != NULL) {
1338 env->in_string += readlength;
1339 }
1340
1341 free(match);
1342
1343 if(depth)
1344 return sx_72656164(env);
1345 }

root@recompile.se
ViewVC Help
Powered by ViewVC 1.1.26