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

Contents of /stack/stack.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.135 - (show annotations)
Wed Aug 13 11:58:00 2003 UTC (20 years, 9 months ago) by masse
Branch: MAIN
Changes since 1.134: +34 -48 lines
File MIME type: text/plain
messages.h: Removed "\n" at the end of messages.
stack.c, stack.h (printerr): Made function smarter.
stack.c, symbols.c: Made better use of "check_args" and "printerr".

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

root@recompile.se
ViewVC Help
Powered by ViewVC 1.1.26