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

Contents of /stack/stack.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.133 - (show annotations)
Mon Aug 11 14:31:48 2003 UTC (20 years, 8 months ago) by masse
Branch: MAIN
Changes since 1.132: +63 -14 lines
File MIME type: text/plain
(check_args) New function to ease the checking of parameters.

1 /* -*- coding: utf-8; -*- */
2 /*
3 stack - an interactive interpreter for a stack-based language
4 Copyright (C) 2002 Mats Alritzson and Teddy Hogeborn
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
20 Authors: Mats Alritzson <masse@fukt.bth.se>
21 Teddy Hogeborn <teddy@fukt.bth.se>
22 */
23
24 #include "stack.h"
25
26 const char* start_message= "Stack version $Revision: 1.132 $\n\
27 Copyright (C) 2002 Mats Alritzson and Teddy Hogeborn\n\
28 Stack comes with ABSOLUTELY NO WARRANTY; for details type 'warranty;'.\n\
29 This is free software, and you are welcome to redistribute it\n\
30 under certain conditions; type 'copying;' for details.\n";
31
32
33 /* Initialize a newly created environment */
34 void init_env(environment *env)
35 {
36 int i;
37
38 env->gc_limit= 400000;
39 env->gc_count= 0;
40 env->gc_ref= NULL;
41
42 env->head= new_val(env);
43 for(i= 0; i<HASHTBLSIZE; i++)
44 env->symbols[i]= NULL;
45 env->err= 0;
46 env->in_string= NULL;
47 env->free_string= NULL;
48 env->inputstream= stdin;
49 env->interactive= 1;
50 }
51
52
53 void printerr(environment *env, const char* in_string)
54 {
55 fprintf(stderr, "\"%s\":\nErr: %s\n", env->errsymb, in_string);
56 }
57
58
59 /* Returns a pointer to a pointer to an element in the hash table. */
60 symbol **hash(hashtbl in_hashtbl, const char *in_string)
61 {
62 int i= 0;
63 unsigned int out_hash= 0;
64 char key= '\0';
65 symbol **position;
66
67 while(1){ /* Hash in_string */
68 key= in_string[i++];
69 if(key=='\0')
70 break;
71 out_hash= out_hash*32+key;
72 }
73
74 out_hash= out_hash%HASHTBLSIZE;
75 position= &(in_hashtbl[out_hash]);
76
77 while(1){
78 if(*position==NULL) /* If empty */
79 return position;
80
81 if(strcmp(in_string, (*position)->id)==0) /* If match */
82 return position;
83
84 position= &((*position)->next); /* Try next */
85 }
86 }
87
88
89 /* Create new value */
90 value* new_val(environment *env)
91 {
92 value *nval= malloc(sizeof(value));
93 stackitem *nitem= malloc(sizeof(stackitem));
94
95 assert(nval != NULL);
96 assert(nitem != NULL);
97
98 nval->content.ptr= NULL;
99 nval->type= empty;
100
101 nitem->item= nval;
102 nitem->next= env->gc_ref;
103
104 env->gc_ref= nitem;
105
106 env->gc_count += sizeof(value);
107 nval->gc.flag.mark= 0;
108 nval->gc.flag.protect= 0;
109
110 return nval;
111 }
112
113
114 /* Mark values recursively.
115 Marked values are not collected by the GC. */
116 inline void gc_mark(value *val)
117 {
118 if(val==NULL || val->gc.flag.mark)
119 return;
120
121 val->gc.flag.mark= 1;
122
123 if(val->type==tcons) {
124 gc_mark(CAR(val));
125 gc_mark(CDR(val));
126 }
127 }
128
129
130 /* Start GC */
131 extern void gc_init(environment *env)
132 {
133 stackitem *new_head= NULL, *titem;
134 symbol *tsymb;
135 int i;
136
137 if(env->interactive)
138 printf("Garbage collecting.");
139
140 /* Mark values on stack */
141 gc_mark(env->head);
142
143 if(env->interactive)
144 printf(".");
145
146 /* Mark values in hashtable */
147 for(i= 0; i<HASHTBLSIZE; i++)
148 for(tsymb= env->symbols[i]; tsymb!=NULL; tsymb= tsymb->next)
149 if (tsymb->val != NULL)
150 gc_mark(tsymb->val);
151
152 if(env->interactive)
153 printf(".");
154
155 env->gc_count= 0;
156
157 while(env->gc_ref!=NULL) { /* Sweep unused values */
158 if(!(env->gc_ref->item->gc.no_gc)){ /* neither mark nor protect */
159
160 /* Remove content */
161 switch(env->gc_ref->item->type){
162 case string:
163 free(env->gc_ref->item->content.string);
164 break;
165 case tcons:
166 free(env->gc_ref->item->content.c);
167 break;
168 case port:
169 case empty:
170 case unknown:
171 case integer:
172 case tfloat:
173 case func:
174 case symb:
175 /* Symbol strings are freed when walking the hash table */
176 break;
177 }
178
179 free(env->gc_ref->item); /* Remove from gc_ref */
180 titem= env->gc_ref->next;
181 free(env->gc_ref); /* Remove value */
182 env->gc_ref= titem;
183 continue;
184 }
185
186 #ifdef DEBUG
187 printf("Kept value (%p)", env->gc_ref->item);
188 if(env->gc_ref->item->gc.flag.mark)
189 printf(" (marked)");
190 if(env->gc_ref->item->gc.flag.protect)
191 printf(" (protected)");
192 switch(env->gc_ref->item->type){
193 case integer:
194 printf(" integer: %d", env->gc_ref->item->content.i);
195 break;
196 case func:
197 printf(" func: %p", env->gc_ref->item->content.func);
198 break;
199 case symb:
200 printf(" symb: %s", env->gc_ref->item->content.sym->id);
201 break;
202 case tcons:
203 printf(" tcons: %p\t%p", CAR(env->gc_ref->item),
204 CDR(env->gc_ref->item));
205 break;
206 default:
207 printf(" <unknown %d>", (env->gc_ref->item->type));
208 }
209 printf("\n");
210 #endif /* DEBUG */
211
212 /* Keep values */
213 env->gc_count += sizeof(value);
214 if(env->gc_ref->item->type==string)
215 env->gc_count += strlen(env->gc_ref->item->content.string)+1;
216
217 titem= env->gc_ref->next;
218 env->gc_ref->next= new_head;
219 new_head= env->gc_ref;
220 new_head->item->gc.flag.mark= 0;
221 env->gc_ref= titem;
222 }
223
224 if (env->gc_limit < env->gc_count*2)
225 env->gc_limit= env->gc_count*2;
226
227 env->gc_ref= new_head;
228
229 if(env->interactive)
230 printf("done (%d bytes still allocated)\n", env->gc_count);
231
232 }
233
234
235 inline void gc_maybe(environment *env)
236 {
237 if(env->gc_count < env->gc_limit)
238 return;
239 else
240 return gc_init(env);
241 }
242
243
244 /* Protect values from GC */
245 void protect(value *val)
246 {
247 if(val==NULL || val->gc.flag.protect)
248 return;
249
250 val->gc.flag.protect= 1;
251
252 if(val->type==tcons) {
253 protect(CAR(val));
254 protect(CDR(val));
255 }
256 }
257
258
259 /* Unprotect values from GC */
260 void unprotect(value *val)
261 {
262 if(val==NULL || !(val->gc.flag.protect))
263 return;
264
265 val->gc.flag.protect= 0;
266
267 if(val->type==tcons) {
268 unprotect(CAR(val));
269 unprotect(CDR(val));
270 }
271 }
272
273
274 /* Push a value onto the stack */
275 void push_val(environment *env, value *val)
276 {
277 value *new_value= new_val(env);
278
279 new_value->content.c= malloc(sizeof(pair));
280 assert(new_value->content.c!=NULL);
281 env->gc_count += sizeof(pair);
282 new_value->type= tcons;
283 CAR(new_value)= val;
284 CDR(new_value)= env->head;
285 env->head= new_value;
286 }
287
288
289 /* Push an integer onto the stack */
290 void push_int(environment *env, int in_val)
291 {
292 value *new_value= new_val(env);
293
294 new_value->content.i= in_val;
295 new_value->type= integer;
296
297 push_val(env, new_value);
298 }
299
300
301 /* Push a floating point number onto the stack */
302 void push_float(environment *env, float in_val)
303 {
304 value *new_value= new_val(env);
305
306 new_value->content.f= in_val;
307 new_value->type= tfloat;
308
309 push_val(env, new_value);
310 }
311
312
313 /* Copy a string onto the stack. */
314 void push_cstring(environment *env, const char *in_string)
315 {
316 value *new_value= new_val(env);
317 int length= strlen(in_string)+1;
318
319 new_value->content.string= malloc(length);
320 assert(new_value != NULL);
321 env->gc_count += length;
322 strcpy(new_value->content.string, in_string);
323 new_value->type= string;
324
325 push_val(env, new_value);
326 }
327
328
329 /* Mangle a symbol name to a valid C identifier name */
330 char *mangle_str(const char *old_string)
331 {
332 char validchars[]= "0123456789abcdef";
333 char *new_string, *current;
334
335 new_string= malloc((strlen(old_string)*2)+4);
336 assert(new_string != NULL);
337 strcpy(new_string, "sx_"); /* Stack eXternal */
338 current= new_string+3;
339
340 while(old_string[0] != '\0'){
341 current[0]= validchars[(unsigned char)(old_string[0])/16];
342 current[1]= validchars[(unsigned char)(old_string[0])%16];
343 current+= 2;
344 old_string++;
345 }
346 current[0]= '\0';
347
348 return new_string; /* The caller must free() it */
349 }
350
351
352 /* Push a symbol onto the stack. */
353 void push_sym(environment *env, const char *in_string)
354 {
355 value *new_value; /* A new symbol value */
356 /* ...which might point to... */
357 symbol **new_symbol; /* (if needed) A new actual symbol */
358 /* ...which, if possible, will be bound to... */
359 value *new_fvalue; /* (if needed) A new function value */
360 /* ...which will point to... */
361 void *funcptr; /* A function pointer */
362
363 static void *handle= NULL; /* Dynamic linker handle */
364 const char *dlerr; /* Dynamic linker error */
365 char *mangled; /* Mangled function name */
366
367 new_value= new_val(env);
368 new_fvalue= new_val(env);
369
370 /* The new value is a symbol */
371 new_value->type= symb;
372
373 /* Look up the symbol name in the hash table */
374 new_symbol= hash(env->symbols, in_string);
375 new_value->content.sym= *new_symbol;
376
377 if(*new_symbol==NULL) { /* If symbol was undefined */
378
379 /* Create a new symbol */
380 (*new_symbol)= malloc(sizeof(symbol));
381 assert((*new_symbol) != NULL);
382 (*new_symbol)->val= NULL; /* undefined value */
383 (*new_symbol)->next= NULL;
384 (*new_symbol)->id= malloc(strlen(in_string)+1);
385 assert((*new_symbol)->id != NULL);
386 strcpy((*new_symbol)->id, in_string);
387
388 /* Intern the new symbol in the hash table */
389 new_value->content.sym= *new_symbol;
390
391 /* Try to load the symbol name as an external function, to see if
392 we should bind the symbol to a new function pointer value */
393 if(handle==NULL) /* If no handle */
394 handle= dlopen(NULL, RTLD_LAZY);
395
396 mangled= mangle_str(in_string); /* mangle the name */
397 funcptr= dlsym(handle, mangled); /* and try to find it */
398
399 dlerr= dlerror();
400 if(dlerr != NULL) { /* If no function was found */
401 funcptr= dlsym(handle, in_string); /* Get function pointer */
402 dlerr= dlerror();
403 }
404
405 if(dlerr==NULL) { /* If a function was found */
406 new_fvalue->type= func; /* The new value is a function pointer */
407 new_fvalue->content.func= funcptr; /* Store function pointer */
408 (*new_symbol)->val= new_fvalue; /* Bind the symbol to the new
409 function value */
410 }
411
412 free(mangled);
413 }
414
415 push_val(env, new_value);
416 }
417
418
419 /* Print a value */
420 void print_val(environment *env, value *val, int noquote, stackitem *stack,
421 FILE *stream)
422 {
423 stackitem *titem, *tstack;
424 int depth;
425
426 switch(val->type) {
427 case empty:
428 if(fprintf(stream, "[]") < 0){
429 perror("print_val");
430 env->err= 5;
431 return;
432 }
433 break;
434 case unknown:
435 if(fprintf(stream, "UNKNOWN") < 0){
436 perror("print_val");
437 env->err= 5;
438 return;
439 }
440 break;
441 case integer:
442 if(fprintf(stream, "%d", val->content.i) < 0){
443 perror("print_val");
444 env->err= 5;
445 return;
446 }
447 break;
448 case tfloat:
449 if(fprintf(stream, "%f", val->content.f) < 0){
450 perror("print_val");
451 env->err= 5;
452 return;
453 }
454 break;
455 case string:
456 if(noquote){
457 if(fprintf(stream, "%s", val->content.string) < 0){
458 perror("print_val");
459 env->err= 5;
460 return;
461 }
462 } else { /* quote */
463 if(fprintf(stream, "\"%s\"", val->content.string) < 0){
464 perror("print_val");
465 env->err= 5;
466 return;
467 }
468 }
469 break;
470 case symb:
471 if(fprintf(stream, "%s", val->content.sym->id) < 0){
472 perror("print_val");
473 env->err= 5;
474 return;
475 }
476 break;
477 case func:
478 if(fprintf(stream, "#<function %p>", val->content.func) < 0){
479 perror("print_val");
480 env->err= 5;
481 return;
482 }
483 break;
484 case port:
485 if(fprintf(stream, "#<port %p>", val->content.p) < 0){
486 perror("print_val");
487 env->err= 5;
488 return;
489 }
490 break;
491 case tcons:
492 if(fprintf(stream, "[ ") < 0){
493 perror("print_val");
494 env->err= 5;
495 return;
496 }
497 tstack= stack;
498
499 do {
500 titem=malloc(sizeof(stackitem));
501 assert(titem != NULL);
502 titem->item=val;
503 titem->next=tstack;
504 tstack=titem; /* Put it on the stack */
505 /* Search a stack of values being printed to see if we are already
506 printing this value */
507 titem=tstack;
508 depth=0;
509
510 while(titem != NULL && titem->item != CAR(val)){
511 titem=titem->next;
512 depth++;
513 }
514
515 if(titem != NULL){ /* If we found it on the stack, */
516 if(fprintf(stream, "#%d#", depth) < 0){ /* print a depth reference */
517 perror("print_val");
518 env->err= 5;
519 free(titem);
520 return;
521 }
522 } else {
523 print_val(env, CAR(val), noquote, tstack, stream);
524 }
525
526 val= CDR(val);
527 switch(val->type){
528 case empty:
529 break;
530 case tcons:
531 /* Search a stack of values being printed to see if we are already
532 printing this value */
533 titem=tstack;
534 depth=0;
535
536 while(titem != NULL && titem->item != val){
537 titem=titem->next;
538 depth++;
539 }
540 if(titem != NULL){ /* If we found it on the stack, */
541 if(fprintf(stream, " . #%d#", depth) < 0){ /* print a depth reference */
542 perror("print_val");
543 env->err= 5;
544 goto printval_end;
545 }
546 } else {
547 if(fprintf(stream, " ") < 0){
548 perror("print_val");
549 env->err= 5;
550 goto printval_end;
551 }
552 }
553 break;
554 default:
555 if(fprintf(stream, " . ") < 0){ /* Improper list */
556 perror("print_val");
557 env->err= 5;
558 goto printval_end;
559 }
560 print_val(env, val, noquote, tstack, stream);
561 }
562 } while(val->type == tcons && titem == NULL);
563
564 printval_end:
565
566 titem=tstack;
567 while(titem != stack){
568 tstack=titem->next;
569 free(titem);
570 titem=tstack;
571 }
572
573 if(! (env->err)){
574 if(fprintf(stream, " ]") < 0){
575 perror("print_val");
576 env->err= 5;
577 }
578 }
579 break;
580 }
581 }
582
583
584 /* Swap the two top elements on the stack. */
585 extern void swap(environment *env)
586 {
587 value *temp= env->head;
588
589 if(env->head->type == empty || CDR(env->head)->type == empty) {
590 printerr(env, "Too Few Arguments");
591 env->err=1;
592 return;
593 }
594
595 env->head= CDR(env->head);
596 CDR(temp)= CDR(env->head);
597 CDR(env->head)= temp;
598 }
599
600
601 /* Recall a value from a symbol, if bound */
602 extern void rcl(environment *env)
603 {
604 value *val;
605
606 if(env->head->type==empty) {
607 printerr(env, "Too Few Arguments");
608 env->err= 1;
609 return;
610 }
611
612 if(CAR(env->head)->type!=symb) {
613 printerr(env, "Bad Argument Type");
614 env->err= 2;
615 return;
616 }
617
618 val= CAR(env->head)->content.sym->val;
619 if(val == NULL){
620 printerr(env, "Unbound Variable");
621 env->err= 3;
622 return;
623 }
624 push_val(env, val); /* Return the symbol's bound value */
625 swap(env);
626 if(env->err) return;
627 env->head= CDR(env->head);
628 }
629
630
631 /* If the top element is a symbol, determine if it's bound to a
632 function value, and if it is, toss the symbol and execute the
633 function. */
634 extern void eval(environment *env)
635 {
636 funcp in_func;
637 value* temp_val;
638 value* iterator;
639
640 eval_start:
641
642 gc_maybe(env);
643
644 if(env->head->type==empty) {
645 printerr(env, "Too Few Arguments");
646 env->err= 1;
647 return;
648 }
649
650 switch(CAR(env->head)->type) {
651 /* if it's a symbol */
652 case symb:
653 env->errsymb= CAR(env->head)->content.sym->id;
654 rcl(env); /* get its contents */
655 if(env->err) return;
656 if(CAR(env->head)->type!=symb){ /* don't recurse symbols */
657 goto eval_start;
658 }
659 return;
660
661 /* If it's a lone function value, run it */
662 case func:
663 in_func= CAR(env->head)->content.func;
664 env->head= CDR(env->head);
665 return in_func(env);
666
667 /* If it's a list */
668 case tcons:
669 temp_val= CAR(env->head);
670 protect(temp_val);
671
672 env->head= CDR(env->head);
673 iterator= temp_val;
674
675 while(iterator->type != empty) {
676 push_val(env, CAR(iterator));
677
678 if(CAR(env->head)->type==symb
679 && CAR(env->head)->content.sym->id[0]==';') {
680 env->head= CDR(env->head);
681
682 if(CDR(iterator)->type == empty){
683 goto eval_start;
684 }
685 eval(env);
686 if(env->err) return;
687 }
688 if (CDR(iterator)->type == empty || CDR(iterator)->type == tcons)
689 iterator= CDR(iterator);
690 else {
691 printerr(env, "Bad Argument Type"); /* Improper list */
692 env->err= 2;
693 return;
694 }
695 }
696 unprotect(temp_val);
697 return;
698
699 case empty:
700 env->head= CDR(env->head);
701 case integer:
702 case tfloat:
703 case string:
704 case port:
705 case unknown:
706 return;
707 }
708 }
709
710
711 /* Internal forget function */
712 void forget_sym(symbol **hash_entry)
713 {
714 symbol *temp;
715
716 temp= *hash_entry;
717 *hash_entry= (*hash_entry)->next;
718
719 free(temp->id);
720 free(temp);
721 }
722
723
724 int main(int argc, char **argv)
725 {
726 environment myenv;
727 int c; /* getopt option character */
728
729 #ifdef __linux__
730 mtrace();
731 #endif
732
733 init_env(&myenv);
734
735 myenv.interactive = isatty(STDIN_FILENO) && isatty(STDOUT_FILENO);
736
737 while ((c = getopt (argc, argv, "i")) != -1)
738 switch (c)
739 {
740 case 'i':
741 myenv.interactive = 1;
742 break;
743 case '?':
744 fprintf (stderr,
745 "Unknown option character '\\x%x'.\n",
746 optopt);
747 return EX_USAGE;
748 default:
749 abort ();
750 }
751
752 if (optind < argc) {
753 myenv.interactive = 0;
754 myenv.inputstream= fopen(argv[optind], "r");
755 if(myenv.inputstream== NULL) {
756 perror(argv[0]);
757 exit (EX_NOINPUT);
758 }
759 }
760
761 if(myenv.interactive)
762 printf(start_message);
763
764 while(1) {
765 if(myenv.in_string==NULL) {
766 if (myenv.interactive) {
767 if(myenv.err) {
768 printf("(error %d)\n", myenv.err);
769 myenv.err= 0;
770 }
771 printf("\n");
772 printstack(&myenv);
773 printf("> ");
774 }
775 myenv.err=0;
776 }
777 readstream(&myenv, myenv.inputstream);
778 if (myenv.err) { /* EOF or other error */
779 myenv.err=0;
780 quit(&myenv);
781 } else if(myenv.head->type!=empty
782 && CAR(myenv.head)->type==symb
783 && CAR(myenv.head)->content.sym->id[0] == ';') {
784 if(myenv.head->type != empty)
785 myenv.head= CDR(myenv.head);
786 eval(&myenv);
787 } else {
788 gc_maybe(&myenv);
789 }
790 }
791 quit(&myenv);
792 return EXIT_FAILURE;
793 }
794
795
796 /* Return copy of a value */
797 value *copy_val(environment *env, value *old_value)
798 {
799 value *new_value;
800
801 if(old_value==NULL)
802 return NULL;
803
804 new_value= new_val(env);
805 new_value->type= old_value->type;
806
807 switch(old_value->type){
808 case tfloat:
809 case integer:
810 case func:
811 case symb:
812 case empty:
813 case unknown:
814 case port:
815 new_value->content= old_value->content;
816 break;
817 case string:
818 new_value->content.string= strdup(old_value->content.string);
819 break;
820 case tcons:
821
822 new_value->content.c= malloc(sizeof(pair));
823 assert(new_value->content.c!=NULL);
824 env->gc_count += sizeof(pair);
825
826 CAR(new_value)= copy_val(env, CAR(old_value)); /* recurse */
827 CDR(new_value)= copy_val(env, CDR(old_value)); /* recurse */
828 break;
829 }
830
831 return new_value;
832 }
833
834
835 /* read a line from a stream; used by readline */
836 void readlinestream(environment *env, FILE *stream)
837 {
838 char in_string[101];
839
840 if(fgets(in_string, 100, stream)==NULL) {
841 push_cstring(env, "");
842 if (! feof(stream)){
843 perror("readline");
844 env->err= 5;
845 }
846 } else {
847 push_cstring(env, in_string);
848 }
849 }
850
851
852 /* Reverse (flip) a list */
853 extern void rev(environment *env)
854 {
855 value *old_head, *new_head, *item;
856
857 if(env->head->type==empty) {
858 printerr(env, "Too Few Arguments");
859 env->err= 1;
860 return;
861 }
862
863 if(CAR(env->head)->type==empty)
864 return; /* Don't reverse an empty list */
865
866 if(CAR(env->head)->type!=tcons) {
867 printerr(env, "Bad Argument Type");
868 env->err= 2;
869 return;
870 }
871
872 old_head= CAR(env->head);
873 new_head= new_val(env);
874 while(old_head->type != empty) {
875 item= old_head;
876 old_head= CDR(old_head);
877 CDR(item)= new_head;
878 new_head= item;
879 }
880 CAR(env->head)= new_head;
881 }
882
883
884 /* Make a list. */
885 extern void pack(environment *env)
886 {
887 value *iterator, *temp, *ending;
888
889 ending=new_val(env);
890
891 iterator= env->head;
892 if(iterator->type == empty
893 || (CAR(iterator)->type==symb
894 && CAR(iterator)->content.sym->id[0]=='[')) {
895 temp= ending;
896 if(env->head->type != empty)
897 env->head= CDR(env->head);
898 } else {
899 /* Search for first delimiter */
900 while(CDR(iterator)->type != empty
901 && (CAR(CDR(iterator))->type!=symb
902 || CAR(CDR(iterator))->content.sym->id[0]!='['))
903 iterator= CDR(iterator);
904
905 /* Extract list */
906 temp= env->head;
907 env->head= CDR(iterator);
908 CDR(iterator)= ending;
909
910 if(env->head->type != empty)
911 env->head= CDR(env->head);
912 }
913
914 /* Push list */
915
916 push_val(env, temp);
917 rev(env);
918 }
919
920
921 /* read from a stream; used by "read" and "readport" */
922 void readstream(environment *env, FILE *stream)
923 {
924 const char symbform[]= "%[a-zA-Z0-9!$%*+./:<=>?@^_~-]%n";
925 const char strform[]= "\"%[^\"]\"%n";
926 const char intform[]= "%i%n";
927 const char fltform[]= "%f%n";
928 const char blankform[]= "%*[ \t]%n";
929 const char ebrackform[]= "]%n";
930 const char semicform[]= ";%n";
931 const char bbrackform[]= "[%n";
932
933 int itemp, readlength= -1;
934 int count= -1;
935 float ftemp;
936 static int depth= 0;
937 char *match;
938 size_t inlength;
939
940 if(env->in_string==NULL) {
941 if(depth > 0 && env->interactive) {
942 printf("]> ");
943 }
944 readlinestream(env, env->inputstream);
945 if(env->err) return;
946
947 if((CAR(env->head)->content.string)[0]=='\0'){
948 env->err= 4; /* "" means EOF */
949 return;
950 }
951
952 env->in_string= malloc(strlen(CAR(env->head)->content.string)+1);
953 assert(env->in_string != NULL);
954 env->free_string= env->in_string; /* Save the original pointer */
955 strcpy(env->in_string, CAR(env->head)->content.string);
956 env->head= CDR(env->head);
957 }
958
959 inlength= strlen(env->in_string)+1;
960 match= malloc(inlength);
961 assert(match != NULL);
962
963 if(sscanf(env->in_string, blankform, &readlength) != EOF
964 && readlength != -1) {
965 ;
966 } else if(sscanf(env->in_string, fltform, &ftemp, &readlength) != EOF
967 && readlength != -1) {
968 if(sscanf(env->in_string, intform, &itemp, &count) != EOF
969 && count==readlength) {
970 push_int(env, itemp);
971 } else {
972 push_float(env, ftemp);
973 }
974 } else if(sscanf(env->in_string, "\"\"%n", &readlength) != EOF
975 && readlength != -1) {
976 push_cstring(env, "");
977 } else if(sscanf(env->in_string, strform, match, &readlength) != EOF
978 && readlength != -1) {
979 push_cstring(env, match);
980 } else if(sscanf(env->in_string, symbform, match, &readlength) != EOF
981 && readlength != -1) {
982 push_sym(env, match);
983 } else if(sscanf(env->in_string, ebrackform, &readlength) != EOF
984 && readlength != -1) {
985 pack(env); if(env->err) return;
986 if(depth != 0) depth--;
987 } else if(sscanf(env->in_string, semicform, &readlength) != EOF
988 && readlength != -1) {
989 push_sym(env, ";");
990 } else if(sscanf(env->in_string, bbrackform, &readlength) != EOF
991 && readlength != -1) {
992 push_sym(env, "[");
993 depth++;
994 } else {
995 free(env->free_string);
996 env->in_string = env->free_string = NULL;
997 }
998 if (env->in_string != NULL) {
999 env->in_string += readlength;
1000 }
1001
1002 free(match);
1003
1004 if(depth)
1005 return readstream(env, env->inputstream);
1006 }
1007
1008
1009 int check_args(environment *env, ...)
1010 {
1011 va_list ap;
1012 enum type_enum mytype;
1013
1014 value *iter= env->head;
1015 int errval= 0;
1016
1017 va_start(ap, env);
1018 while(1) {
1019 mytype= va_arg(ap, enum type_enum);
1020 // fprintf(stderr, "%s\n", env->errsymb);
1021
1022 if(mytype==empty)
1023 break;
1024
1025 if(iter->type==empty || iter==NULL) {
1026 errval= 1;
1027 break;
1028 }
1029
1030 if(mytype==unknown) {
1031 iter=CDR(iter);
1032 continue;
1033 }
1034
1035 if(CAR(iter)->type!=mytype) {
1036 errval= 2;
1037 break;
1038 }
1039
1040 iter= CDR(iter);
1041 }
1042
1043 va_end(ap);
1044
1045 env->err= errval;
1046 return errval;
1047 }

root@recompile.se
ViewVC Help
Powered by ViewVC 1.1.26