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

Annotation of /stack/stack.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.137 - (hide annotations)
Thu Feb 19 15:35:38 2004 UTC (20 years, 2 months ago) by masse
Branch: MAIN
CVS Tags: HEAD
Changes since 1.136: +1 -161 lines
File MIME type: text/plain
Extracted garbage collector to gc.c

1 teddy 1.116 /* -*- coding: utf-8; -*- */
2 teddy 1.91 /*
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 teddy 1.88 #include "stack.h"
25 masse 1.1
26 masse 1.137 const char* start_message= "Stack version $Revision: 1.136 $\n\
27 masse 1.132 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 masse 1.136 under certain conditions; type 'copying;' for details.";
31 masse 1.132
32    
33 teddy 1.28 /* Initialize a newly created environment */
34     void init_env(environment *env)
35 masse 1.1 {
36 masse 1.46 int i;
37 masse 1.1
38 teddy 1.100 env->gc_limit= 400000;
39 masse 1.87 env->gc_count= 0;
40 masse 1.90 env->gc_ref= NULL;
41 masse 1.87
42 teddy 1.111 env->head= new_val(env);
43 masse 1.1 for(i= 0; i<HASHTBLSIZE; i++)
44 teddy 1.28 env->symbols[i]= NULL;
45 teddy 1.84 env->err= 0;
46     env->in_string= NULL;
47     env->free_string= NULL;
48     env->inputstream= stdin;
49     env->interactive= 1;
50 masse 1.1 }
51    
52 masse 1.132
53 masse 1.135 void printerr(environment *env)
54 masse 1.95 {
55 masse 1.135 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 masse 1.136 case 5:
70     return perror(env->errsymb);
71 masse 1.135 default:
72     in_string= "Unknown error";
73     break;
74     }
75    
76 masse 1.133 fprintf(stderr, "\"%s\":\nErr: %s\n", env->errsymb, in_string);
77 teddy 1.48 }
78    
79 masse 1.132
80 teddy 1.27 /* Returns a pointer to a pointer to an element in the hash table. */
81 teddy 1.28 symbol **hash(hashtbl in_hashtbl, const char *in_string)
82 masse 1.1 {
83 masse 1.46 int i= 0;
84     unsigned int out_hash= 0;
85 teddy 1.18 char key= '\0';
86 teddy 1.28 symbol **position;
87 masse 1.1
88 masse 1.16 while(1){ /* Hash in_string */
89 masse 1.1 key= in_string[i++];
90     if(key=='\0')
91     break;
92     out_hash= out_hash*32+key;
93     }
94    
95     out_hash= out_hash%HASHTBLSIZE;
96     position= &(in_hashtbl[out_hash]);
97    
98 masse 1.25 while(1){
99 teddy 1.18 if(*position==NULL) /* If empty */
100 masse 1.1 return position;
101    
102 teddy 1.18 if(strcmp(in_string, (*position)->id)==0) /* If match */
103 masse 1.1 return position;
104    
105 masse 1.16 position= &((*position)->next); /* Try next */
106 masse 1.1 }
107     }
108    
109 masse 1.132
110 masse 1.95 /* Create new value */
111     value* new_val(environment *env)
112     {
113 masse 1.87 value *nval= malloc(sizeof(value));
114     stackitem *nitem= malloc(sizeof(stackitem));
115    
116 teddy 1.118 assert(nval != NULL);
117     assert(nitem != NULL);
118    
119 masse 1.87 nval->content.ptr= NULL;
120 teddy 1.117 nval->type= empty;
121 masse 1.87
122     nitem->item= nval;
123     nitem->next= env->gc_ref;
124 masse 1.102
125 masse 1.87 env->gc_ref= nitem;
126    
127 teddy 1.101 env->gc_count += sizeof(value);
128 teddy 1.99 nval->gc.flag.mark= 0;
129     nval->gc.flag.protect= 0;
130 masse 1.93
131 masse 1.87 return nval;
132 masse 1.90 }
133    
134 masse 1.132
135 teddy 1.29 /* Push a value onto the stack */
136 masse 1.72 void push_val(environment *env, value *val)
137 teddy 1.29 {
138 masse 1.104 value *new_value= new_val(env);
139 masse 1.102
140 teddy 1.115 new_value->content.c= malloc(sizeof(pair));
141 masse 1.108 assert(new_value->content.c!=NULL);
142 teddy 1.116 env->gc_count += sizeof(pair);
143 masse 1.104 new_value->type= tcons;
144     CAR(new_value)= val;
145     CDR(new_value)= env->head;
146     env->head= new_value;
147 teddy 1.29 }
148    
149 masse 1.132
150 masse 1.95 /* Push an integer onto the stack */
151 masse 1.72 void push_int(environment *env, int in_val)
152 masse 1.1 {
153 masse 1.87 value *new_value= new_val(env);
154 teddy 1.28
155 masse 1.93 new_value->content.i= in_val;
156 teddy 1.28 new_value->type= integer;
157 masse 1.1
158 masse 1.75 push_val(env, new_value);
159 masse 1.1 }
160    
161 masse 1.132
162 masse 1.95 /* Push a floating point number onto the stack */
163 masse 1.93 void push_float(environment *env, float in_val)
164     {
165     value *new_value= new_val(env);
166    
167     new_value->content.f= in_val;
168     new_value->type= tfloat;
169    
170     push_val(env, new_value);
171     }
172    
173 masse 1.132
174 masse 1.14 /* Copy a string onto the stack. */
175 masse 1.72 void push_cstring(environment *env, const char *in_string)
176 masse 1.1 {
177 masse 1.87 value *new_value= new_val(env);
178 teddy 1.101 int length= strlen(in_string)+1;
179 teddy 1.28
180 masse 1.128 new_value->content.string= malloc(length);
181 teddy 1.118 assert(new_value != NULL);
182 teddy 1.101 env->gc_count += length;
183 masse 1.128 strcpy(new_value->content.string, in_string);
184 teddy 1.28 new_value->type= string;
185 masse 1.1
186 masse 1.75 push_val(env, new_value);
187 masse 1.1 }
188    
189 masse 1.132
190 teddy 1.48 /* Mangle a symbol name to a valid C identifier name */
191 masse 1.95 char *mangle_str(const char *old_string)
192     {
193 masse 1.90 char validchars[]= "0123456789abcdef";
194 teddy 1.48 char *new_string, *current;
195    
196 masse 1.90 new_string= malloc((strlen(old_string)*2)+4);
197 teddy 1.118 assert(new_string != NULL);
198 teddy 1.48 strcpy(new_string, "sx_"); /* Stack eXternal */
199 masse 1.90 current= new_string+3;
200 masse 1.132
201 teddy 1.48 while(old_string[0] != '\0'){
202 masse 1.90 current[0]= validchars[(unsigned char)(old_string[0])/16];
203     current[1]= validchars[(unsigned char)(old_string[0])%16];
204     current+= 2;
205 teddy 1.48 old_string++;
206     }
207 masse 1.90 current[0]= '\0';
208 teddy 1.48
209     return new_string; /* The caller must free() it */
210     }
211    
212 masse 1.132
213 teddy 1.28 /* Push a symbol onto the stack. */
214 teddy 1.35 void push_sym(environment *env, const char *in_string)
215 masse 1.1 {
216 teddy 1.28 value *new_value; /* A new symbol value */
217     /* ...which might point to... */
218 teddy 1.29 symbol **new_symbol; /* (if needed) A new actual symbol */
219 teddy 1.28 /* ...which, if possible, will be bound to... */
220     value *new_fvalue; /* (if needed) A new function value */
221     /* ...which will point to... */
222     void *funcptr; /* A function pointer */
223    
224     static void *handle= NULL; /* Dynamic linker handle */
225 teddy 1.48 const char *dlerr; /* Dynamic linker error */
226     char *mangled; /* Mangled function name */
227 teddy 1.28
228 masse 1.87 new_value= new_val(env);
229 masse 1.93 new_fvalue= new_val(env);
230 teddy 1.28
231     /* The new value is a symbol */
232     new_value->type= symb;
233    
234     /* Look up the symbol name in the hash table */
235 teddy 1.29 new_symbol= hash(env->symbols, in_string);
236 masse 1.130 new_value->content.sym= *new_symbol;
237 teddy 1.28
238 teddy 1.30 if(*new_symbol==NULL) { /* If symbol was undefined */
239 teddy 1.28
240     /* Create a new symbol */
241 teddy 1.30 (*new_symbol)= malloc(sizeof(symbol));
242 teddy 1.118 assert((*new_symbol) != NULL);
243 teddy 1.29 (*new_symbol)->val= NULL; /* undefined value */
244     (*new_symbol)->next= NULL;
245     (*new_symbol)->id= malloc(strlen(in_string)+1);
246 teddy 1.118 assert((*new_symbol)->id != NULL);
247 teddy 1.29 strcpy((*new_symbol)->id, in_string);
248 masse 1.1
249 teddy 1.28 /* Intern the new symbol in the hash table */
250 masse 1.130 new_value->content.sym= *new_symbol;
251 masse 1.1
252 teddy 1.28 /* Try to load the symbol name as an external function, to see if
253     we should bind the symbol to a new function pointer value */
254 masse 1.16 if(handle==NULL) /* If no handle */
255 teddy 1.28 handle= dlopen(NULL, RTLD_LAZY);
256 masse 1.6
257 masse 1.90 mangled= mangle_str(in_string); /* mangle the name */
258 teddy 1.86 funcptr= dlsym(handle, mangled); /* and try to find it */
259 masse 1.95
260 masse 1.90 dlerr= dlerror();
261 teddy 1.48 if(dlerr != NULL) { /* If no function was found */
262 teddy 1.86 funcptr= dlsym(handle, in_string); /* Get function pointer */
263 masse 1.90 dlerr= dlerror();
264 teddy 1.48 }
265 masse 1.95
266 teddy 1.48 if(dlerr==NULL) { /* If a function was found */
267 masse 1.90 new_fvalue->type= func; /* The new value is a function pointer */
268 masse 1.128 new_fvalue->content.func= funcptr; /* Store function pointer */
269 teddy 1.29 (*new_symbol)->val= new_fvalue; /* Bind the symbol to the new
270     function value */
271 teddy 1.28 }
272 masse 1.95
273     free(mangled);
274 masse 1.1 }
275 masse 1.95
276 masse 1.75 push_val(env, new_value);
277 masse 1.1 }
278    
279 masse 1.132
280 teddy 1.114 /* Print a value */
281 masse 1.132 void print_val(environment *env, value *val, int noquote, stackitem *stack,
282     FILE *stream)
283 masse 1.8 {
284 teddy 1.117 stackitem *titem, *tstack;
285     int depth;
286    
287 teddy 1.113 switch(val->type) {
288 teddy 1.112 case empty:
289 masse 1.136 if(fprintf(stream, "[]") < 0)
290 teddy 1.124 env->err= 5;
291 teddy 1.112 break;
292 masse 1.133 case unknown:
293 masse 1.136 if(fprintf(stream, "UNKNOWN") < 0)
294 masse 1.133 env->err= 5;
295     break;
296 teddy 1.28 case integer:
297 masse 1.136 if(fprintf(stream, "%d", val->content.i) < 0)
298 teddy 1.124 env->err= 5;
299 masse 1.93 break;
300     case tfloat:
301 masse 1.136 if(fprintf(stream, "%f", val->content.f) < 0)
302 teddy 1.124 env->err= 5;
303 teddy 1.2 break;
304     case string:
305 teddy 1.124 if(noquote){
306 masse 1.136 if(fprintf(stream, "%s", val->content.string) < 0)
307 teddy 1.124 env->err= 5;
308     } else { /* quote */
309 masse 1.136 if(fprintf(stream, "\"%s\"", val->content.string) < 0)
310 teddy 1.124 env->err= 5;
311     }
312 teddy 1.2 break;
313 teddy 1.28 case symb:
314 masse 1.136 if(fprintf(stream, "%s", val->content.sym->id) < 0)
315 teddy 1.124 env->err= 5;
316 masse 1.6 break;
317 teddy 1.35 case func:
318 masse 1.136 if(fprintf(stream, "#<function %p>", val->content.func) < 0)
319 teddy 1.124 env->err= 5;
320     break;
321     case port:
322 masse 1.136 if(fprintf(stream, "#<port %p>", val->content.p) < 0)
323 teddy 1.124 env->err= 5;
324 teddy 1.35 break;
325 masse 1.102 case tcons:
326 masse 1.136 if(fprintf(stream, "[ ") < 0) {
327 teddy 1.124 env->err= 5;
328 masse 1.136 return printerr(env);
329 teddy 1.124 }
330 teddy 1.117 tstack= stack;
331 masse 1.132
332 teddy 1.113 do {
333 teddy 1.117 titem=malloc(sizeof(stackitem));
334 teddy 1.118 assert(titem != NULL);
335 teddy 1.117 titem->item=val;
336     titem->next=tstack;
337     tstack=titem; /* Put it on the stack */
338     /* Search a stack of values being printed to see if we are already
339     printing this value */
340     titem=tstack;
341     depth=0;
342 masse 1.132
343 teddy 1.117 while(titem != NULL && titem->item != CAR(val)){
344     titem=titem->next;
345     depth++;
346     }
347 masse 1.132
348 teddy 1.117 if(titem != NULL){ /* If we found it on the stack, */
349 teddy 1.124 if(fprintf(stream, "#%d#", depth) < 0){ /* print a depth reference */
350     env->err= 5;
351     free(titem);
352 masse 1.136 return printerr(env);
353 teddy 1.124 }
354 teddy 1.117 } else {
355 teddy 1.124 print_val(env, CAR(val), noquote, tstack, stream);
356 teddy 1.117 }
357 masse 1.132
358 teddy 1.114 val= CDR(val);
359     switch(val->type){
360 teddy 1.112 case empty:
361     break;
362     case tcons:
363 teddy 1.117 /* Search a stack of values being printed to see if we are already
364     printing this value */
365     titem=tstack;
366     depth=0;
367 masse 1.132
368 teddy 1.117 while(titem != NULL && titem->item != val){
369     titem=titem->next;
370     depth++;
371     }
372     if(titem != NULL){ /* If we found it on the stack, */
373 teddy 1.124 if(fprintf(stream, " . #%d#", depth) < 0){ /* print a depth reference */
374     env->err= 5;
375 masse 1.136 printerr(env);
376 teddy 1.124 goto printval_end;
377     }
378 teddy 1.117 } else {
379 teddy 1.124 if(fprintf(stream, " ") < 0){
380     env->err= 5;
381 masse 1.136 printerr(env);
382 teddy 1.124 goto printval_end;
383     }
384 teddy 1.117 }
385 teddy 1.112 break;
386     default:
387 teddy 1.124 if(fprintf(stream, " . ") < 0){ /* Improper list */
388     env->err= 5;
389 masse 1.136 printerr(env);
390 teddy 1.124 goto printval_end;
391     }
392     print_val(env, val, noquote, tstack, stream);
393 teddy 1.112 }
394 teddy 1.117 } while(val->type == tcons && titem == NULL);
395 teddy 1.124
396     printval_end:
397    
398 teddy 1.117 titem=tstack;
399     while(titem != stack){
400     tstack=titem->next;
401     free(titem);
402     titem=tstack;
403     }
404 teddy 1.124
405     if(! (env->err)){
406     if(fprintf(stream, " ]") < 0){
407     env->err= 5;
408     }
409     }
410 teddy 1.35 break;
411 teddy 1.2 }
412 masse 1.136
413     if(env->err)
414     return printerr(env);
415 masse 1.1 }
416    
417 masse 1.132
418 masse 1.26 /* Swap the two top elements on the stack. */
419 teddy 1.28 extern void swap(environment *env)
420 masse 1.26 {
421 masse 1.104 value *temp= env->head;
422 masse 1.134
423 masse 1.136 if(check_args(env, 2, unknown, unknown))
424 masse 1.135 return printerr(env);
425 masse 1.134
426 masse 1.104 env->head= CDR(env->head);
427     CDR(temp)= CDR(env->head);
428     CDR(env->head)= temp;
429 masse 1.26 }
430    
431 masse 1.132
432 teddy 1.33 /* Recall a value from a symbol, if bound */
433 teddy 1.31 extern void rcl(environment *env)
434     {
435     value *val;
436    
437 masse 1.136 if(check_args(env, 1, symb))
438 masse 1.135 return printerr(env);
439 teddy 1.35
440 masse 1.105 val= CAR(env->head)->content.sym->val;
441 teddy 1.33 if(val == NULL){
442 masse 1.102 env->err= 3;
443 masse 1.135 return printerr(env);
444 teddy 1.33 }
445 masse 1.135
446 teddy 1.110 push_val(env, val); /* Return the symbol's bound value */
447     swap(env);
448     if(env->err) return;
449 masse 1.132 env->head= CDR(env->head);
450 teddy 1.31 }
451 masse 1.26
452 masse 1.126
453 teddy 1.29 /* If the top element is a symbol, determine if it's bound to a
454     function value, and if it is, toss the symbol and execute the
455     function. */
456 teddy 1.28 extern void eval(environment *env)
457 masse 1.1 {
458     funcp in_func;
459 masse 1.44 value* temp_val;
460 masse 1.104 value* iterator;
461 masse 1.44
462 teddy 1.80 eval_start:
463    
464 teddy 1.96 gc_maybe(env);
465    
466 masse 1.136 if(check_args(env, 1, unknown))
467 masse 1.135 return printerr(env);
468 masse 1.1
469 masse 1.104 switch(CAR(env->head)->type) {
470 masse 1.46 /* if it's a symbol */
471     case symb:
472 masse 1.133 env->errsymb= CAR(env->head)->content.sym->id;
473 teddy 1.35 rcl(env); /* get its contents */
474     if(env->err) return;
475 masse 1.104 if(CAR(env->head)->type!=symb){ /* don't recurse symbols */
476 teddy 1.64 goto eval_start;
477 teddy 1.29 }
478 teddy 1.59 return;
479 masse 1.22
480 masse 1.46 /* If it's a lone function value, run it */
481     case func:
482 masse 1.128 in_func= CAR(env->head)->content.func;
483 masse 1.132 env->head= CDR(env->head);
484 masse 1.135 return in_func((void*)env);
485 masse 1.44
486 masse 1.46 /* If it's a list */
487 masse 1.102 case tcons:
488 masse 1.104 temp_val= CAR(env->head);
489 masse 1.98 protect(temp_val);
490 masse 1.93
491 masse 1.132 env->head= CDR(env->head);
492 masse 1.104 iterator= temp_val;
493 masse 1.90
494 teddy 1.111 while(iterator->type != empty) {
495 masse 1.104 push_val(env, CAR(iterator));
496 masse 1.90
497 masse 1.132 if(CAR(env->head)->type==symb
498 masse 1.105 && CAR(env->head)->content.sym->id[0]==';') {
499 masse 1.132 env->head= CDR(env->head);
500 masse 1.90
501 teddy 1.111 if(CDR(iterator)->type == empty){
502 teddy 1.64 goto eval_start;
503 teddy 1.59 }
504 masse 1.44 eval(env);
505 masse 1.46 if(env->err) return;
506 masse 1.44 }
507 teddy 1.111 if (CDR(iterator)->type == empty || CDR(iterator)->type == tcons)
508 masse 1.104 iterator= CDR(iterator);
509 teddy 1.103 else {
510 masse 1.135 env->err= 2; /* Improper list */
511     return printerr(env);
512 teddy 1.103 }
513 masse 1.44 }
514 masse 1.98 unprotect(temp_val);
515 teddy 1.59 return;
516 masse 1.46
517 teddy 1.116 case empty:
518 masse 1.132 env->head= CDR(env->head);
519 teddy 1.116 case integer:
520     case tfloat:
521     case string:
522 teddy 1.124 case port:
523 masse 1.133 case unknown:
524 teddy 1.59 return;
525 masse 1.26 }
526 masse 1.1 }
527    
528 teddy 1.40
529 masse 1.126 /* Internal forget function */
530     void forget_sym(symbol **hash_entry)
531 masse 1.19 {
532 masse 1.126 symbol *temp;
533 teddy 1.111
534 masse 1.126 temp= *hash_entry;
535     *hash_entry= (*hash_entry)->next;
536    
537     free(temp->id);
538     free(temp);
539     }
540 masse 1.93
541 masse 1.65
542 masse 1.126 int main(int argc, char **argv)
543 masse 1.95 {
544 masse 1.126 environment myenv;
545     int c; /* getopt option character */
546 masse 1.89
547 masse 1.126 #ifdef __linux__
548     mtrace();
549     #endif
550 masse 1.89
551 masse 1.126 init_env(&myenv);
552 masse 1.89
553 masse 1.126 myenv.interactive = isatty(STDIN_FILENO) && isatty(STDOUT_FILENO);
554 masse 1.89
555 masse 1.126 while ((c = getopt (argc, argv, "i")) != -1)
556     switch (c)
557     {
558     case 'i':
559     myenv.interactive = 1;
560     break;
561     case '?':
562     fprintf (stderr,
563     "Unknown option character '\\x%x'.\n",
564     optopt);
565     return EX_USAGE;
566     default:
567     abort ();
568     }
569    
570     if (optind < argc) {
571     myenv.interactive = 0;
572     myenv.inputstream= fopen(argv[optind], "r");
573     if(myenv.inputstream== NULL) {
574     perror(argv[0]);
575     exit (EX_NOINPUT);
576 masse 1.89 }
577     }
578    
579 masse 1.132 if(myenv.interactive)
580 masse 1.134 puts(start_message);
581 masse 1.65
582 masse 1.126 while(1) {
583     if(myenv.in_string==NULL) {
584     if (myenv.interactive) {
585     if(myenv.err) {
586     printf("(error %d)\n", myenv.err);
587     myenv.err= 0;
588     }
589     printf("\n");
590     printstack(&myenv);
591     printf("> ");
592     }
593     myenv.err=0;
594     }
595     readstream(&myenv, myenv.inputstream);
596     if (myenv.err) { /* EOF or other error */
597     myenv.err=0;
598     quit(&myenv);
599     } else if(myenv.head->type!=empty
600     && CAR(myenv.head)->type==symb
601     && CAR(myenv.head)->content.sym->id[0] == ';') {
602 masse 1.132 if(myenv.head->type != empty)
603     myenv.head= CDR(myenv.head);
604 masse 1.126 eval(&myenv);
605 teddy 1.103 } else {
606 masse 1.126 gc_maybe(&myenv);
607 teddy 1.103 }
608 masse 1.65 }
609 masse 1.126 quit(&myenv);
610     return EXIT_FAILURE;
611 masse 1.65 }
612 masse 1.66
613 masse 1.132
614 masse 1.126 /* Return copy of a value */
615     value *copy_val(environment *env, value *old_value)
616 masse 1.95 {
617 masse 1.126 value *new_value;
618 masse 1.121
619 masse 1.126 if(old_value==NULL)
620     return NULL;
621 masse 1.95
622 masse 1.126 new_value= new_val(env);
623     new_value->type= old_value->type;
624 masse 1.66
625 masse 1.126 switch(old_value->type){
626     case tfloat:
627     case integer:
628     case func:
629     case symb:
630     case empty:
631 masse 1.133 case unknown:
632 masse 1.126 case port:
633     new_value->content= old_value->content;
634     break;
635     case string:
636 masse 1.128 new_value->content.string= strdup(old_value->content.string);
637 masse 1.126 break;
638     case tcons:
639 masse 1.66
640 masse 1.126 new_value->content.c= malloc(sizeof(pair));
641     assert(new_value->content.c!=NULL);
642     env->gc_count += sizeof(pair);
643 masse 1.66
644 masse 1.126 CAR(new_value)= copy_val(env, CAR(old_value)); /* recurse */
645     CDR(new_value)= copy_val(env, CDR(old_value)); /* recurse */
646     break;
647 masse 1.67 }
648 masse 1.66
649 masse 1.126 return new_value;
650 teddy 1.124 }
651    
652 masse 1.132
653 teddy 1.124 /* read a line from a stream; used by readline */
654     void readlinestream(environment *env, FILE *stream)
655     {
656 masse 1.68 char in_string[101];
657    
658 teddy 1.124 if(fgets(in_string, 100, stream)==NULL) {
659 teddy 1.84 push_cstring(env, "");
660 teddy 1.124 if (! feof(stream)){
661     env->err= 5;
662 masse 1.136 return printerr(env);
663 teddy 1.124 }
664     } else {
665 teddy 1.84 push_cstring(env, in_string);
666 teddy 1.124 }
667 masse 1.68 }
668    
669 masse 1.132
670 masse 1.126 /* Reverse (flip) a list */
671     extern void rev(environment *env)
672 masse 1.95 {
673 masse 1.126 value *old_head, *new_head, *item;
674 teddy 1.124
675 masse 1.126 if(CAR(env->head)->type==empty)
676     return; /* Don't reverse an empty list */
677    
678 masse 1.136 if(check_args(env, 1, tcons))
679 masse 1.135 return printerr(env);
680 teddy 1.124
681 masse 1.126 old_head= CAR(env->head);
682     new_head= new_val(env);
683     while(old_head->type != empty) {
684     item= old_head;
685     old_head= CDR(old_head);
686     CDR(item)= new_head;
687     new_head= item;
688     }
689     CAR(env->head)= new_head;
690     }
691    
692 masse 1.132
693 masse 1.126 /* Make a list. */
694     extern void pack(environment *env)
695     {
696     value *iterator, *temp, *ending;
697    
698     ending=new_val(env);
699    
700     iterator= env->head;
701     if(iterator->type == empty
702     || (CAR(iterator)->type==symb
703     && CAR(iterator)->content.sym->id[0]=='[')) {
704     temp= ending;
705 masse 1.132 if(env->head->type != empty)
706     env->head= CDR(env->head);
707 masse 1.126 } else {
708     /* Search for first delimiter */
709     while(CDR(iterator)->type != empty
710     && (CAR(CDR(iterator))->type!=symb
711     || CAR(CDR(iterator))->content.sym->id[0]!='['))
712     iterator= CDR(iterator);
713    
714     /* Extract list */
715     temp= env->head;
716     env->head= CDR(iterator);
717     CDR(iterator)= ending;
718    
719     if(env->head->type != empty)
720 masse 1.132 env->head= CDR(env->head);
721 masse 1.126 }
722    
723     /* Push list */
724 teddy 1.124
725 masse 1.126 push_val(env, temp);
726     rev(env);
727 teddy 1.124 }
728    
729 masse 1.132
730 teddy 1.124 /* read from a stream; used by "read" and "readport" */
731     void readstream(environment *env, FILE *stream)
732     {
733 teddy 1.78 const char symbform[]= "%[a-zA-Z0-9!$%*+./:<=>?@^_~-]%n";
734     const char strform[]= "\"%[^\"]\"%n";
735     const char intform[]= "%i%n";
736 masse 1.93 const char fltform[]= "%f%n";
737 teddy 1.78 const char blankform[]= "%*[ \t]%n";
738 masse 1.90 const char ebrackform[]= "]%n";
739     const char semicform[]= ";%n";
740     const char bbrackform[]= "[%n";
741 masse 1.68
742 teddy 1.78 int itemp, readlength= -1;
743 masse 1.93 int count= -1;
744     float ftemp;
745 masse 1.68 static int depth= 0;
746 teddy 1.116 char *match;
747 masse 1.68 size_t inlength;
748    
749 masse 1.70 if(env->in_string==NULL) {
750 teddy 1.84 if(depth > 0 && env->interactive) {
751 teddy 1.80 printf("]> ");
752     }
753 masse 1.126 readlinestream(env, env->inputstream);
754     if(env->err) return;
755 teddy 1.84
756 masse 1.128 if((CAR(env->head)->content.string)[0]=='\0'){
757 teddy 1.85 env->err= 4; /* "" means EOF */
758 teddy 1.84 return;
759     }
760 masse 1.68
761 masse 1.128 env->in_string= malloc(strlen(CAR(env->head)->content.string)+1);
762 teddy 1.118 assert(env->in_string != NULL);
763 teddy 1.78 env->free_string= env->in_string; /* Save the original pointer */
764 masse 1.128 strcpy(env->in_string, CAR(env->head)->content.string);
765 masse 1.132 env->head= CDR(env->head);
766 masse 1.68 }
767    
768 masse 1.70 inlength= strlen(env->in_string)+1;
769 masse 1.68 match= malloc(inlength);
770 teddy 1.118 assert(match != NULL);
771 masse 1.68
772 masse 1.93 if(sscanf(env->in_string, blankform, &readlength) != EOF
773 teddy 1.78 && readlength != -1) {
774 masse 1.71 ;
775 masse 1.93 } else if(sscanf(env->in_string, fltform, &ftemp, &readlength) != EOF
776 teddy 1.78 && readlength != -1) {
777 masse 1.93 if(sscanf(env->in_string, intform, &itemp, &count) != EOF
778     && count==readlength) {
779     push_int(env, itemp);
780     } else {
781     push_float(env, ftemp);
782     }
783 teddy 1.114 } else if(sscanf(env->in_string, "\"\"%n", &readlength) != EOF
784     && readlength != -1) {
785     push_cstring(env, "");
786 teddy 1.78 } else if(sscanf(env->in_string, strform, match, &readlength) != EOF
787     && readlength != -1) {
788 masse 1.72 push_cstring(env, match);
789 teddy 1.78 } else if(sscanf(env->in_string, symbform, match, &readlength) != EOF
790     && readlength != -1) {
791 masse 1.68 push_sym(env, match);
792 teddy 1.78 } else if(sscanf(env->in_string, ebrackform, &readlength) != EOF
793     && readlength != -1) {
794 masse 1.68 pack(env); if(env->err) return;
795 teddy 1.78 if(depth != 0) depth--;
796     } else if(sscanf(env->in_string, semicform, &readlength) != EOF
797     && readlength != -1) {
798 masse 1.68 push_sym(env, ";");
799 teddy 1.78 } else if(sscanf(env->in_string, bbrackform, &readlength) != EOF
800     && readlength != -1) {
801 masse 1.68 push_sym(env, "[");
802     depth++;
803     } else {
804 teddy 1.78 free(env->free_string);
805     env->in_string = env->free_string = NULL;
806     }
807 masse 1.126 if (env->in_string != NULL) {
808     env->in_string += readlength;
809 teddy 1.91 }
810    
811 masse 1.126 free(match);
812 teddy 1.91
813 masse 1.126 if(depth)
814     return readstream(env, env->inputstream);
815 masse 1.133 }
816    
817    
818 masse 1.136 int check_args(environment *env, int num_args, ...)
819 masse 1.133 {
820     va_list ap;
821     enum type_enum mytype;
822 masse 1.136 int i;
823 masse 1.133
824     value *iter= env->head;
825     int errval= 0;
826    
827 masse 1.136 va_start(ap, num_args);
828     for(i=1; i<=num_args; i++) {
829 masse 1.133 mytype= va_arg(ap, enum type_enum);
830     // fprintf(stderr, "%s\n", env->errsymb);
831    
832     if(iter->type==empty || iter==NULL) {
833     errval= 1;
834     break;
835     }
836    
837 masse 1.136 if(mytype!=unknown && CAR(iter)->type!=mytype) {
838 masse 1.133 errval= 2;
839     break;
840     }
841    
842     iter= CDR(iter);
843     }
844    
845     va_end(ap);
846    
847     env->err= errval;
848     return errval;
849 masse 1.95 }

root@recompile.se
ViewVC Help
Powered by ViewVC 1.1.26