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

Contents of /stack/stack.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.134 - (show annotations)
Wed Aug 13 06:12:26 2003 UTC (20 years, 8 months ago) by masse
Branch: MAIN
Changes since 1.133: +30 -22 lines
File MIME type: text/plain
stack.c, symbols.c: Some functions changed to use check_args. Replaced printf
with puts where possible.

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.133 $\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 switch(check_args(env, unknown, unknown, empty)) {
590 case 1:
591 printerr(env, "Too Few Arguments");
592 return;
593 case 2:
594 printerr(env, "Bad Argument Type");
595 return;
596 default:
597 break;
598 }
599
600 env->head= CDR(env->head);
601 CDR(temp)= CDR(env->head);
602 CDR(env->head)= temp;
603 }
604
605
606 /* Recall a value from a symbol, if bound */
607 extern void rcl(environment *env)
608 {
609 value *val;
610
611 switch(check_args(env, symb, empty)) {
612 case 1:
613 printerr(env, "Too Few Arguments");
614 return;
615 case 2:
616 printerr(env, "Bad Argument Type");
617 return;
618 default:
619 break;
620 }
621
622 val= CAR(env->head)->content.sym->val;
623 if(val == NULL){
624 printerr(env, "Unbound Variable");
625 env->err= 3;
626 return;
627 }
628 push_val(env, val); /* Return the symbol's bound value */
629 swap(env);
630 if(env->err) return;
631 env->head= CDR(env->head);
632 }
633
634
635 /* If the top element is a symbol, determine if it's bound to a
636 function value, and if it is, toss the symbol and execute the
637 function. */
638 extern void eval(environment *env)
639 {
640 funcp in_func;
641 value* temp_val;
642 value* iterator;
643
644 eval_start:
645
646 gc_maybe(env);
647
648 switch(check_args(env, unknown, empty)) {
649 case 1:
650 printerr(env, "Too Few Arguments");
651 return;
652 case 2:
653 printerr(env, "Bad Argument Type");
654 return;
655 default:
656 break;
657 }
658
659 switch(CAR(env->head)->type) {
660 /* if it's a symbol */
661 case symb:
662 env->errsymb= CAR(env->head)->content.sym->id;
663 rcl(env); /* get its contents */
664 if(env->err) return;
665 if(CAR(env->head)->type!=symb){ /* don't recurse symbols */
666 goto eval_start;
667 }
668 return;
669
670 /* If it's a lone function value, run it */
671 case func:
672 in_func= CAR(env->head)->content.func;
673 env->head= CDR(env->head);
674 return in_func(env);
675
676 /* If it's a list */
677 case tcons:
678 temp_val= CAR(env->head);
679 protect(temp_val);
680
681 env->head= CDR(env->head);
682 iterator= temp_val;
683
684 while(iterator->type != empty) {
685 push_val(env, CAR(iterator));
686
687 if(CAR(env->head)->type==symb
688 && CAR(env->head)->content.sym->id[0]==';') {
689 env->head= CDR(env->head);
690
691 if(CDR(iterator)->type == empty){
692 goto eval_start;
693 }
694 eval(env);
695 if(env->err) return;
696 }
697 if (CDR(iterator)->type == empty || CDR(iterator)->type == tcons)
698 iterator= CDR(iterator);
699 else {
700 printerr(env, "Bad Argument Type"); /* Improper list */
701 env->err= 2;
702 return;
703 }
704 }
705 unprotect(temp_val);
706 return;
707
708 case empty:
709 env->head= CDR(env->head);
710 case integer:
711 case tfloat:
712 case string:
713 case port:
714 case unknown:
715 return;
716 }
717 }
718
719
720 /* Internal forget function */
721 void forget_sym(symbol **hash_entry)
722 {
723 symbol *temp;
724
725 temp= *hash_entry;
726 *hash_entry= (*hash_entry)->next;
727
728 free(temp->id);
729 free(temp);
730 }
731
732
733 int main(int argc, char **argv)
734 {
735 environment myenv;
736 int c; /* getopt option character */
737
738 #ifdef __linux__
739 mtrace();
740 #endif
741
742 init_env(&myenv);
743
744 myenv.interactive = isatty(STDIN_FILENO) && isatty(STDOUT_FILENO);
745
746 while ((c = getopt (argc, argv, "i")) != -1)
747 switch (c)
748 {
749 case 'i':
750 myenv.interactive = 1;
751 break;
752 case '?':
753 fprintf (stderr,
754 "Unknown option character '\\x%x'.\n",
755 optopt);
756 return EX_USAGE;
757 default:
758 abort ();
759 }
760
761 if (optind < argc) {
762 myenv.interactive = 0;
763 myenv.inputstream= fopen(argv[optind], "r");
764 if(myenv.inputstream== NULL) {
765 perror(argv[0]);
766 exit (EX_NOINPUT);
767 }
768 }
769
770 if(myenv.interactive)
771 puts(start_message);
772
773 while(1) {
774 if(myenv.in_string==NULL) {
775 if (myenv.interactive) {
776 if(myenv.err) {
777 printf("(error %d)\n", myenv.err);
778 myenv.err= 0;
779 }
780 printf("\n");
781 printstack(&myenv);
782 printf("> ");
783 }
784 myenv.err=0;
785 }
786 readstream(&myenv, myenv.inputstream);
787 if (myenv.err) { /* EOF or other error */
788 myenv.err=0;
789 quit(&myenv);
790 } else if(myenv.head->type!=empty
791 && CAR(myenv.head)->type==symb
792 && CAR(myenv.head)->content.sym->id[0] == ';') {
793 if(myenv.head->type != empty)
794 myenv.head= CDR(myenv.head);
795 eval(&myenv);
796 } else {
797 gc_maybe(&myenv);
798 }
799 }
800 quit(&myenv);
801 return EXIT_FAILURE;
802 }
803
804
805 /* Return copy of a value */
806 value *copy_val(environment *env, value *old_value)
807 {
808 value *new_value;
809
810 if(old_value==NULL)
811 return NULL;
812
813 new_value= new_val(env);
814 new_value->type= old_value->type;
815
816 switch(old_value->type){
817 case tfloat:
818 case integer:
819 case func:
820 case symb:
821 case empty:
822 case unknown:
823 case port:
824 new_value->content= old_value->content;
825 break;
826 case string:
827 new_value->content.string= strdup(old_value->content.string);
828 break;
829 case tcons:
830
831 new_value->content.c= malloc(sizeof(pair));
832 assert(new_value->content.c!=NULL);
833 env->gc_count += sizeof(pair);
834
835 CAR(new_value)= copy_val(env, CAR(old_value)); /* recurse */
836 CDR(new_value)= copy_val(env, CDR(old_value)); /* recurse */
837 break;
838 }
839
840 return new_value;
841 }
842
843
844 /* read a line from a stream; used by readline */
845 void readlinestream(environment *env, FILE *stream)
846 {
847 char in_string[101];
848
849 if(fgets(in_string, 100, stream)==NULL) {
850 push_cstring(env, "");
851 if (! feof(stream)){
852 perror("readline");
853 env->err= 5;
854 }
855 } else {
856 push_cstring(env, in_string);
857 }
858 }
859
860
861 /* Reverse (flip) a list */
862 extern void rev(environment *env)
863 {
864 value *old_head, *new_head, *item;
865
866 if(CAR(env->head)->type==empty)
867 return; /* Don't reverse an empty list */
868
869 switch(check_args(env, tcons, empty)) {
870 case 1:
871 printerr(env, "Too Few Arguments");
872 return;
873 case 2:
874 printerr(env, "Bad Argument Type");
875 return;
876 default:
877 break;
878 }
879
880 old_head= CAR(env->head);
881 new_head= new_val(env);
882 while(old_head->type != empty) {
883 item= old_head;
884 old_head= CDR(old_head);
885 CDR(item)= new_head;
886 new_head= item;
887 }
888 CAR(env->head)= new_head;
889 }
890
891
892 /* Make a list. */
893 extern void pack(environment *env)
894 {
895 value *iterator, *temp, *ending;
896
897 ending=new_val(env);
898
899 iterator= env->head;
900 if(iterator->type == empty
901 || (CAR(iterator)->type==symb
902 && CAR(iterator)->content.sym->id[0]=='[')) {
903 temp= ending;
904 if(env->head->type != empty)
905 env->head= CDR(env->head);
906 } else {
907 /* Search for first delimiter */
908 while(CDR(iterator)->type != empty
909 && (CAR(CDR(iterator))->type!=symb
910 || CAR(CDR(iterator))->content.sym->id[0]!='['))
911 iterator= CDR(iterator);
912
913 /* Extract list */
914 temp= env->head;
915 env->head= CDR(iterator);
916 CDR(iterator)= ending;
917
918 if(env->head->type != empty)
919 env->head= CDR(env->head);
920 }
921
922 /* Push list */
923
924 push_val(env, temp);
925 rev(env);
926 }
927
928
929 /* read from a stream; used by "read" and "readport" */
930 void readstream(environment *env, FILE *stream)
931 {
932 const char symbform[]= "%[a-zA-Z0-9!$%*+./:<=>?@^_~-]%n";
933 const char strform[]= "\"%[^\"]\"%n";
934 const char intform[]= "%i%n";
935 const char fltform[]= "%f%n";
936 const char blankform[]= "%*[ \t]%n";
937 const char ebrackform[]= "]%n";
938 const char semicform[]= ";%n";
939 const char bbrackform[]= "[%n";
940
941 int itemp, readlength= -1;
942 int count= -1;
943 float ftemp;
944 static int depth= 0;
945 char *match;
946 size_t inlength;
947
948 if(env->in_string==NULL) {
949 if(depth > 0 && env->interactive) {
950 printf("]> ");
951 }
952 readlinestream(env, env->inputstream);
953 if(env->err) return;
954
955 if((CAR(env->head)->content.string)[0]=='\0'){
956 env->err= 4; /* "" means EOF */
957 return;
958 }
959
960 env->in_string= malloc(strlen(CAR(env->head)->content.string)+1);
961 assert(env->in_string != NULL);
962 env->free_string= env->in_string; /* Save the original pointer */
963 strcpy(env->in_string, CAR(env->head)->content.string);
964 env->head= CDR(env->head);
965 }
966
967 inlength= strlen(env->in_string)+1;
968 match= malloc(inlength);
969 assert(match != NULL);
970
971 if(sscanf(env->in_string, blankform, &readlength) != EOF
972 && readlength != -1) {
973 ;
974 } else if(sscanf(env->in_string, fltform, &ftemp, &readlength) != EOF
975 && readlength != -1) {
976 if(sscanf(env->in_string, intform, &itemp, &count) != EOF
977 && count==readlength) {
978 push_int(env, itemp);
979 } else {
980 push_float(env, ftemp);
981 }
982 } else if(sscanf(env->in_string, "\"\"%n", &readlength) != EOF
983 && readlength != -1) {
984 push_cstring(env, "");
985 } else if(sscanf(env->in_string, strform, match, &readlength) != EOF
986 && readlength != -1) {
987 push_cstring(env, match);
988 } else if(sscanf(env->in_string, symbform, match, &readlength) != EOF
989 && readlength != -1) {
990 push_sym(env, match);
991 } else if(sscanf(env->in_string, ebrackform, &readlength) != EOF
992 && readlength != -1) {
993 pack(env); if(env->err) return;
994 if(depth != 0) depth--;
995 } else if(sscanf(env->in_string, semicform, &readlength) != EOF
996 && readlength != -1) {
997 push_sym(env, ";");
998 } else if(sscanf(env->in_string, bbrackform, &readlength) != EOF
999 && readlength != -1) {
1000 push_sym(env, "[");
1001 depth++;
1002 } else {
1003 free(env->free_string);
1004 env->in_string = env->free_string = NULL;
1005 }
1006 if (env->in_string != NULL) {
1007 env->in_string += readlength;
1008 }
1009
1010 free(match);
1011
1012 if(depth)
1013 return readstream(env, env->inputstream);
1014 }
1015
1016
1017 int check_args(environment *env, ...)
1018 {
1019 va_list ap;
1020 enum type_enum mytype;
1021
1022 value *iter= env->head;
1023 int errval= 0;
1024
1025 va_start(ap, env);
1026 while(1) {
1027 mytype= va_arg(ap, enum type_enum);
1028 // fprintf(stderr, "%s\n", env->errsymb);
1029
1030 if(mytype==empty)
1031 break;
1032
1033 if(iter->type==empty || iter==NULL) {
1034 errval= 1;
1035 break;
1036 }
1037
1038 if(mytype==unknown) {
1039 iter=CDR(iter);
1040 continue;
1041 }
1042
1043 if(CAR(iter)->type!=mytype) {
1044 errval= 2;
1045 break;
1046 }
1047
1048 iter= CDR(iter);
1049 }
1050
1051 va_end(ap);
1052
1053 env->err= errval;
1054 return errval;
1055 }

root@recompile.se
ViewVC Help
Powered by ViewVC 1.1.26