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

Annotation of /stack/stack.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.135 - (hide annotations)
Wed Aug 13 11:58:00 2003 UTC (20 years, 8 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 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.135 const char* start_message= "Stack version $Revision: 1.134 $\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     under certain conditions; type 'copying;' for details.\n";
31    
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     default:
70     in_string= "Unknown error";
71     break;
72     }
73    
74 masse 1.133 fprintf(stderr, "\"%s\":\nErr: %s\n", env->errsymb, in_string);
75 teddy 1.48 }
76    
77 masse 1.132
78 teddy 1.27 /* Returns a pointer to a pointer to an element in the hash table. */
79 teddy 1.28 symbol **hash(hashtbl in_hashtbl, const char *in_string)
80 masse 1.1 {
81 masse 1.46 int i= 0;
82     unsigned int out_hash= 0;
83 teddy 1.18 char key= '\0';
84 teddy 1.28 symbol **position;
85 masse 1.1
86 masse 1.16 while(1){ /* Hash in_string */
87 masse 1.1 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 masse 1.25 while(1){
97 teddy 1.18 if(*position==NULL) /* If empty */
98 masse 1.1 return position;
99    
100 teddy 1.18 if(strcmp(in_string, (*position)->id)==0) /* If match */
101 masse 1.1 return position;
102    
103 masse 1.16 position= &((*position)->next); /* Try next */
104 masse 1.1 }
105     }
106    
107 masse 1.132
108 masse 1.95 /* Create new value */
109     value* new_val(environment *env)
110     {
111 masse 1.87 value *nval= malloc(sizeof(value));
112     stackitem *nitem= malloc(sizeof(stackitem));
113    
114 teddy 1.118 assert(nval != NULL);
115     assert(nitem != NULL);
116    
117 masse 1.87 nval->content.ptr= NULL;
118 teddy 1.117 nval->type= empty;
119 masse 1.87
120     nitem->item= nval;
121     nitem->next= env->gc_ref;
122 masse 1.102
123 masse 1.87 env->gc_ref= nitem;
124    
125 teddy 1.101 env->gc_count += sizeof(value);
126 teddy 1.99 nval->gc.flag.mark= 0;
127     nval->gc.flag.protect= 0;
128 masse 1.93
129 masse 1.87 return nval;
130     }
131    
132 masse 1.126
133 masse 1.95 /* Mark values recursively.
134     Marked values are not collected by the GC. */
135 teddy 1.96 inline void gc_mark(value *val)
136 masse 1.95 {
137 masse 1.102 if(val==NULL || val->gc.flag.mark)
138 masse 1.87 return;
139    
140 teddy 1.99 val->gc.flag.mark= 1;
141 masse 1.87
142 masse 1.104 if(val->type==tcons) {
143     gc_mark(CAR(val));
144     gc_mark(CDR(val));
145 masse 1.87 }
146     }
147    
148 teddy 1.96
149 masse 1.95 /* Start GC */
150     extern void gc_init(environment *env)
151     {
152 masse 1.102 stackitem *new_head= NULL, *titem;
153 masse 1.87 symbol *tsymb;
154     int i;
155    
156 masse 1.102 if(env->interactive)
157 teddy 1.101 printf("Garbage collecting.");
158 teddy 1.100
159 masse 1.95 /* Mark values on stack */
160 masse 1.104 gc_mark(env->head);
161 masse 1.87
162 masse 1.102 if(env->interactive)
163 teddy 1.100 printf(".");
164 masse 1.102
165 masse 1.93 /* Mark values in hashtable */
166 masse 1.102 for(i= 0; i<HASHTBLSIZE; i++)
167     for(tsymb= env->symbols[i]; tsymb!=NULL; tsymb= tsymb->next)
168 masse 1.97 if (tsymb->val != NULL)
169     gc_mark(tsymb->val);
170 masse 1.87
171 masse 1.102 if(env->interactive)
172 teddy 1.100 printf(".");
173 masse 1.102
174 masse 1.87 env->gc_count= 0;
175    
176 masse 1.95 while(env->gc_ref!=NULL) { /* Sweep unused values */
177 teddy 1.99 if(!(env->gc_ref->item->gc.no_gc)){ /* neither mark nor protect */
178 masse 1.93
179 teddy 1.116 /* Remove content */
180     switch(env->gc_ref->item->type){
181     case string:
182 masse 1.130 free(env->gc_ref->item->content.string);
183 teddy 1.116 break;
184     case tcons:
185     free(env->gc_ref->item->content.c);
186     break;
187 teddy 1.124 case port:
188 teddy 1.116 case empty:
189 masse 1.133 case unknown:
190 teddy 1.116 case integer:
191     case tfloat:
192     case func:
193     case symb:
194     /* Symbol strings are freed when walking the hash table */
195 masse 1.126 break;
196 teddy 1.116 }
197 masse 1.102
198 masse 1.93 free(env->gc_ref->item); /* Remove from gc_ref */
199 masse 1.87 titem= env->gc_ref->next;
200 masse 1.93 free(env->gc_ref); /* Remove value */
201 masse 1.87 env->gc_ref= titem;
202 masse 1.97 continue;
203 teddy 1.110 }
204 masse 1.132
205 teddy 1.110 #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 masse 1.128 printf(" func: %p", env->gc_ref->item->content.func);
217 teddy 1.110 break;
218     case symb:
219     printf(" symb: %s", env->gc_ref->item->content.sym->id);
220     break;
221     case tcons:
222 masse 1.127 printf(" tcons: %p\t%p", CAR(env->gc_ref->item),
223     CDR(env->gc_ref->item));
224 teddy 1.110 break;
225     default:
226     printf(" <unknown %d>", (env->gc_ref->item->type));
227     }
228     printf("\n");
229     #endif /* DEBUG */
230 masse 1.102
231     /* Keep values */
232     env->gc_count += sizeof(value);
233     if(env->gc_ref->item->type==string)
234 masse 1.128 env->gc_count += strlen(env->gc_ref->item->content.string)+1;
235 masse 1.97
236     titem= env->gc_ref->next;
237     env->gc_ref->next= new_head;
238     new_head= env->gc_ref;
239 teddy 1.99 new_head->item->gc.flag.mark= 0;
240 masse 1.97 env->gc_ref= titem;
241 masse 1.87 }
242    
243 teddy 1.100 if (env->gc_limit < env->gc_count*2)
244     env->gc_limit= env->gc_count*2;
245 teddy 1.101
246 masse 1.87 env->gc_ref= new_head;
247 teddy 1.100
248 masse 1.102 if(env->interactive)
249 teddy 1.110 printf("done (%d bytes still allocated)\n", env->gc_count);
250 teddy 1.100
251 masse 1.87 }
252    
253 masse 1.132
254 masse 1.126 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 masse 1.132
263 masse 1.95 /* Protect values from GC */
264 masse 1.98 void protect(value *val)
265 masse 1.90 {
266 masse 1.102 if(val==NULL || val->gc.flag.protect)
267 masse 1.98 return;
268    
269 teddy 1.99 val->gc.flag.protect= 1;
270 masse 1.98
271 masse 1.104 if(val->type==tcons) {
272     protect(CAR(val));
273     protect(CDR(val));
274 masse 1.98 }
275 masse 1.90 }
276    
277 masse 1.132
278 masse 1.95 /* Unprotect values from GC */
279 masse 1.98 void unprotect(value *val)
280 masse 1.90 {
281 masse 1.102 if(val==NULL || !(val->gc.flag.protect))
282 masse 1.98 return;
283    
284 teddy 1.99 val->gc.flag.protect= 0;
285 masse 1.98
286 masse 1.104 if(val->type==tcons) {
287     unprotect(CAR(val));
288     unprotect(CDR(val));
289 masse 1.98 }
290 masse 1.90 }
291    
292 masse 1.132
293 teddy 1.29 /* Push a value onto the stack */
294 masse 1.72 void push_val(environment *env, value *val)
295 teddy 1.29 {
296 masse 1.104 value *new_value= new_val(env);
297 masse 1.102
298 teddy 1.115 new_value->content.c= malloc(sizeof(pair));
299 masse 1.108 assert(new_value->content.c!=NULL);
300 teddy 1.116 env->gc_count += sizeof(pair);
301 masse 1.104 new_value->type= tcons;
302     CAR(new_value)= val;
303     CDR(new_value)= env->head;
304     env->head= new_value;
305 teddy 1.29 }
306    
307 masse 1.132
308 masse 1.95 /* Push an integer onto the stack */
309 masse 1.72 void push_int(environment *env, int in_val)
310 masse 1.1 {
311 masse 1.87 value *new_value= new_val(env);
312 teddy 1.28
313 masse 1.93 new_value->content.i= in_val;
314 teddy 1.28 new_value->type= integer;
315 masse 1.1
316 masse 1.75 push_val(env, new_value);
317 masse 1.1 }
318    
319 masse 1.132
320 masse 1.95 /* Push a floating point number onto the stack */
321 masse 1.93 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 masse 1.132
332 masse 1.14 /* Copy a string onto the stack. */
333 masse 1.72 void push_cstring(environment *env, const char *in_string)
334 masse 1.1 {
335 masse 1.87 value *new_value= new_val(env);
336 teddy 1.101 int length= strlen(in_string)+1;
337 teddy 1.28
338 masse 1.128 new_value->content.string= malloc(length);
339 teddy 1.118 assert(new_value != NULL);
340 teddy 1.101 env->gc_count += length;
341 masse 1.128 strcpy(new_value->content.string, in_string);
342 teddy 1.28 new_value->type= string;
343 masse 1.1
344 masse 1.75 push_val(env, new_value);
345 masse 1.1 }
346    
347 masse 1.132
348 teddy 1.48 /* Mangle a symbol name to a valid C identifier name */
349 masse 1.95 char *mangle_str(const char *old_string)
350     {
351 masse 1.90 char validchars[]= "0123456789abcdef";
352 teddy 1.48 char *new_string, *current;
353    
354 masse 1.90 new_string= malloc((strlen(old_string)*2)+4);
355 teddy 1.118 assert(new_string != NULL);
356 teddy 1.48 strcpy(new_string, "sx_"); /* Stack eXternal */
357 masse 1.90 current= new_string+3;
358 masse 1.132
359 teddy 1.48 while(old_string[0] != '\0'){
360 masse 1.90 current[0]= validchars[(unsigned char)(old_string[0])/16];
361     current[1]= validchars[(unsigned char)(old_string[0])%16];
362     current+= 2;
363 teddy 1.48 old_string++;
364     }
365 masse 1.90 current[0]= '\0';
366 teddy 1.48
367     return new_string; /* The caller must free() it */
368     }
369    
370 masse 1.132
371 teddy 1.28 /* Push a symbol onto the stack. */
372 teddy 1.35 void push_sym(environment *env, const char *in_string)
373 masse 1.1 {
374 teddy 1.28 value *new_value; /* A new symbol value */
375     /* ...which might point to... */
376 teddy 1.29 symbol **new_symbol; /* (if needed) A new actual symbol */
377 teddy 1.28 /* ...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 teddy 1.48 const char *dlerr; /* Dynamic linker error */
384     char *mangled; /* Mangled function name */
385 teddy 1.28
386 masse 1.87 new_value= new_val(env);
387 masse 1.93 new_fvalue= new_val(env);
388 teddy 1.28
389     /* The new value is a symbol */
390     new_value->type= symb;
391    
392     /* Look up the symbol name in the hash table */
393 teddy 1.29 new_symbol= hash(env->symbols, in_string);
394 masse 1.130 new_value->content.sym= *new_symbol;
395 teddy 1.28
396 teddy 1.30 if(*new_symbol==NULL) { /* If symbol was undefined */
397 teddy 1.28
398     /* Create a new symbol */
399 teddy 1.30 (*new_symbol)= malloc(sizeof(symbol));
400 teddy 1.118 assert((*new_symbol) != NULL);
401 teddy 1.29 (*new_symbol)->val= NULL; /* undefined value */
402     (*new_symbol)->next= NULL;
403     (*new_symbol)->id= malloc(strlen(in_string)+1);
404 teddy 1.118 assert((*new_symbol)->id != NULL);
405 teddy 1.29 strcpy((*new_symbol)->id, in_string);
406 masse 1.1
407 teddy 1.28 /* Intern the new symbol in the hash table */
408 masse 1.130 new_value->content.sym= *new_symbol;
409 masse 1.1
410 teddy 1.28 /* 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 masse 1.16 if(handle==NULL) /* If no handle */
413 teddy 1.28 handle= dlopen(NULL, RTLD_LAZY);
414 masse 1.6
415 masse 1.90 mangled= mangle_str(in_string); /* mangle the name */
416 teddy 1.86 funcptr= dlsym(handle, mangled); /* and try to find it */
417 masse 1.95
418 masse 1.90 dlerr= dlerror();
419 teddy 1.48 if(dlerr != NULL) { /* If no function was found */
420 teddy 1.86 funcptr= dlsym(handle, in_string); /* Get function pointer */
421 masse 1.90 dlerr= dlerror();
422 teddy 1.48 }
423 masse 1.95
424 teddy 1.48 if(dlerr==NULL) { /* If a function was found */
425 masse 1.90 new_fvalue->type= func; /* The new value is a function pointer */
426 masse 1.128 new_fvalue->content.func= funcptr; /* Store function pointer */
427 teddy 1.29 (*new_symbol)->val= new_fvalue; /* Bind the symbol to the new
428     function value */
429 teddy 1.28 }
430 masse 1.95
431     free(mangled);
432 masse 1.1 }
433 masse 1.95
434 masse 1.75 push_val(env, new_value);
435 masse 1.1 }
436    
437 masse 1.132
438 teddy 1.114 /* Print a value */
439 masse 1.132 void print_val(environment *env, value *val, int noquote, stackitem *stack,
440     FILE *stream)
441 masse 1.8 {
442 teddy 1.117 stackitem *titem, *tstack;
443     int depth;
444    
445 teddy 1.113 switch(val->type) {
446 teddy 1.112 case empty:
447 teddy 1.124 if(fprintf(stream, "[]") < 0){
448     perror("print_val");
449     env->err= 5;
450     return;
451     }
452 teddy 1.112 break;
453 masse 1.133 case unknown:
454     if(fprintf(stream, "UNKNOWN") < 0){
455     perror("print_val");
456     env->err= 5;
457     return;
458     }
459     break;
460 teddy 1.28 case integer:
461 teddy 1.124 if(fprintf(stream, "%d", val->content.i) < 0){
462     perror("print_val");
463     env->err= 5;
464     return;
465     }
466 masse 1.93 break;
467     case tfloat:
468 teddy 1.124 if(fprintf(stream, "%f", val->content.f) < 0){
469     perror("print_val");
470     env->err= 5;
471     return;
472     }
473 teddy 1.2 break;
474     case string:
475 teddy 1.124 if(noquote){
476 masse 1.128 if(fprintf(stream, "%s", val->content.string) < 0){
477 teddy 1.124 perror("print_val");
478     env->err= 5;
479     return;
480     }
481     } else { /* quote */
482 masse 1.128 if(fprintf(stream, "\"%s\"", val->content.string) < 0){
483 teddy 1.124 perror("print_val");
484     env->err= 5;
485     return;
486     }
487     }
488 teddy 1.2 break;
489 teddy 1.28 case symb:
490 teddy 1.124 if(fprintf(stream, "%s", val->content.sym->id) < 0){
491     perror("print_val");
492     env->err= 5;
493     return;
494     }
495 masse 1.6 break;
496 teddy 1.35 case func:
497 masse 1.128 if(fprintf(stream, "#<function %p>", val->content.func) < 0){
498 teddy 1.124 perror("print_val");
499     env->err= 5;
500     return;
501     }
502     break;
503     case port:
504 masse 1.128 if(fprintf(stream, "#<port %p>", val->content.p) < 0){
505 teddy 1.124 perror("print_val");
506     env->err= 5;
507     return;
508     }
509 teddy 1.35 break;
510 masse 1.102 case tcons:
511 teddy 1.124 if(fprintf(stream, "[ ") < 0){
512     perror("print_val");
513     env->err= 5;
514     return;
515     }
516 teddy 1.117 tstack= stack;
517 masse 1.132
518 teddy 1.113 do {
519 teddy 1.117 titem=malloc(sizeof(stackitem));
520 teddy 1.118 assert(titem != NULL);
521 teddy 1.117 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 masse 1.132
529 teddy 1.117 while(titem != NULL && titem->item != CAR(val)){
530     titem=titem->next;
531     depth++;
532     }
533 masse 1.132
534 teddy 1.117 if(titem != NULL){ /* If we found it on the stack, */
535 teddy 1.124 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 teddy 1.117 } else {
542 teddy 1.124 print_val(env, CAR(val), noquote, tstack, stream);
543 teddy 1.117 }
544 masse 1.132
545 teddy 1.114 val= CDR(val);
546     switch(val->type){
547 teddy 1.112 case empty:
548     break;
549     case tcons:
550 teddy 1.117 /* Search a stack of values being printed to see if we are already
551     printing this value */
552     titem=tstack;
553     depth=0;
554 masse 1.132
555 teddy 1.117 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 teddy 1.124 if(fprintf(stream, " . #%d#", depth) < 0){ /* print a depth reference */
561     perror("print_val");
562     env->err= 5;
563     goto printval_end;
564     }
565 teddy 1.117 } else {
566 teddy 1.124 if(fprintf(stream, " ") < 0){
567     perror("print_val");
568     env->err= 5;
569     goto printval_end;
570     }
571 teddy 1.117 }
572 teddy 1.112 break;
573     default:
574 teddy 1.124 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 teddy 1.112 }
581 teddy 1.117 } while(val->type == tcons && titem == NULL);
582 teddy 1.124
583     printval_end:
584    
585 teddy 1.117 titem=tstack;
586     while(titem != stack){
587     tstack=titem->next;
588     free(titem);
589     titem=tstack;
590     }
591 teddy 1.124
592     if(! (env->err)){
593     if(fprintf(stream, " ]") < 0){
594     perror("print_val");
595     env->err= 5;
596     }
597     }
598 teddy 1.35 break;
599 teddy 1.2 }
600 masse 1.1 }
601    
602 masse 1.132
603 masse 1.26 /* Swap the two top elements on the stack. */
604 teddy 1.28 extern void swap(environment *env)
605 masse 1.26 {
606 masse 1.104 value *temp= env->head;
607 masse 1.134
608 masse 1.135 if(check_args(env, unknown, unknown, empty))
609     return printerr(env);
610 masse 1.134
611 masse 1.104 env->head= CDR(env->head);
612     CDR(temp)= CDR(env->head);
613     CDR(env->head)= temp;
614 masse 1.26 }
615    
616 masse 1.132
617 teddy 1.33 /* Recall a value from a symbol, if bound */
618 teddy 1.31 extern void rcl(environment *env)
619     {
620     value *val;
621    
622 masse 1.135 if(check_args(env, symb, empty))
623     return printerr(env);
624 teddy 1.35
625 masse 1.105 val= CAR(env->head)->content.sym->val;
626 teddy 1.33 if(val == NULL){
627 masse 1.102 env->err= 3;
628 masse 1.135 return printerr(env);
629 teddy 1.33 }
630 masse 1.135
631 teddy 1.110 push_val(env, val); /* Return the symbol's bound value */
632     swap(env);
633     if(env->err) return;
634 masse 1.132 env->head= CDR(env->head);
635 teddy 1.31 }
636 masse 1.26
637 masse 1.126
638 teddy 1.29 /* 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 teddy 1.28 extern void eval(environment *env)
642 masse 1.1 {
643     funcp in_func;
644 masse 1.44 value* temp_val;
645 masse 1.104 value* iterator;
646 masse 1.44
647 teddy 1.80 eval_start:
648    
649 teddy 1.96 gc_maybe(env);
650    
651 masse 1.135 if(check_args(env, unknown, empty))
652     return printerr(env);
653 masse 1.1
654 masse 1.104 switch(CAR(env->head)->type) {
655 masse 1.46 /* if it's a symbol */
656     case symb:
657 masse 1.133 env->errsymb= CAR(env->head)->content.sym->id;
658 teddy 1.35 rcl(env); /* get its contents */
659     if(env->err) return;
660 masse 1.104 if(CAR(env->head)->type!=symb){ /* don't recurse symbols */
661 teddy 1.64 goto eval_start;
662 teddy 1.29 }
663 teddy 1.59 return;
664 masse 1.22
665 masse 1.46 /* If it's a lone function value, run it */
666     case func:
667 masse 1.128 in_func= CAR(env->head)->content.func;
668 masse 1.132 env->head= CDR(env->head);
669 masse 1.135 return in_func((void*)env);
670 masse 1.44
671 masse 1.46 /* If it's a list */
672 masse 1.102 case tcons:
673 masse 1.104 temp_val= CAR(env->head);
674 masse 1.98 protect(temp_val);
675 masse 1.93
676 masse 1.132 env->head= CDR(env->head);
677 masse 1.104 iterator= temp_val;
678 masse 1.90
679 teddy 1.111 while(iterator->type != empty) {
680 masse 1.104 push_val(env, CAR(iterator));
681 masse 1.90
682 masse 1.132 if(CAR(env->head)->type==symb
683 masse 1.105 && CAR(env->head)->content.sym->id[0]==';') {
684 masse 1.132 env->head= CDR(env->head);
685 masse 1.90
686 teddy 1.111 if(CDR(iterator)->type == empty){
687 teddy 1.64 goto eval_start;
688 teddy 1.59 }
689 masse 1.44 eval(env);
690 masse 1.46 if(env->err) return;
691 masse 1.44 }
692 teddy 1.111 if (CDR(iterator)->type == empty || CDR(iterator)->type == tcons)
693 masse 1.104 iterator= CDR(iterator);
694 teddy 1.103 else {
695 masse 1.135 env->err= 2; /* Improper list */
696     return printerr(env);
697 teddy 1.103 }
698 masse 1.44 }
699 masse 1.98 unprotect(temp_val);
700 teddy 1.59 return;
701 masse 1.46
702 teddy 1.116 case empty:
703 masse 1.132 env->head= CDR(env->head);
704 teddy 1.116 case integer:
705     case tfloat:
706     case string:
707 teddy 1.124 case port:
708 masse 1.133 case unknown:
709 teddy 1.59 return;
710 masse 1.26 }
711 masse 1.1 }
712    
713 teddy 1.40
714 masse 1.126 /* Internal forget function */
715     void forget_sym(symbol **hash_entry)
716 masse 1.19 {
717 masse 1.126 symbol *temp;
718 teddy 1.111
719 masse 1.126 temp= *hash_entry;
720     *hash_entry= (*hash_entry)->next;
721    
722     free(temp->id);
723     free(temp);
724     }
725 masse 1.93
726 masse 1.65
727 masse 1.126 int main(int argc, char **argv)
728 masse 1.95 {
729 masse 1.126 environment myenv;
730     int c; /* getopt option character */
731 masse 1.89
732 masse 1.126 #ifdef __linux__
733     mtrace();
734     #endif
735 masse 1.89
736 masse 1.126 init_env(&myenv);
737 masse 1.89
738 masse 1.126 myenv.interactive = isatty(STDIN_FILENO) && isatty(STDOUT_FILENO);
739 masse 1.89
740 masse 1.126 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 masse 1.89 }
762     }
763    
764 masse 1.132 if(myenv.interactive)
765 masse 1.134 puts(start_message);
766 masse 1.65
767 masse 1.126 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 masse 1.132 if(myenv.head->type != empty)
788     myenv.head= CDR(myenv.head);
789 masse 1.126 eval(&myenv);
790 teddy 1.103 } else {
791 masse 1.126 gc_maybe(&myenv);
792 teddy 1.103 }
793 masse 1.65 }
794 masse 1.126 quit(&myenv);
795     return EXIT_FAILURE;
796 masse 1.65 }
797 masse 1.66
798 masse 1.132
799 masse 1.126 /* Return copy of a value */
800     value *copy_val(environment *env, value *old_value)
801 masse 1.95 {
802 masse 1.126 value *new_value;
803 masse 1.121
804 masse 1.126 if(old_value==NULL)
805     return NULL;
806 masse 1.95
807 masse 1.126 new_value= new_val(env);
808     new_value->type= old_value->type;
809 masse 1.66
810 masse 1.126 switch(old_value->type){
811     case tfloat:
812     case integer:
813     case func:
814     case symb:
815     case empty:
816 masse 1.133 case unknown:
817 masse 1.126 case port:
818     new_value->content= old_value->content;
819     break;
820     case string:
821 masse 1.128 new_value->content.string= strdup(old_value->content.string);
822 masse 1.126 break;
823     case tcons:
824 masse 1.66
825 masse 1.126 new_value->content.c= malloc(sizeof(pair));
826     assert(new_value->content.c!=NULL);
827     env->gc_count += sizeof(pair);
828 masse 1.66
829 masse 1.126 CAR(new_value)= copy_val(env, CAR(old_value)); /* recurse */
830     CDR(new_value)= copy_val(env, CDR(old_value)); /* recurse */
831     break;
832 masse 1.67 }
833 masse 1.66
834 masse 1.126 return new_value;
835 teddy 1.124 }
836    
837 masse 1.132
838 teddy 1.124 /* read a line from a stream; used by readline */
839     void readlinestream(environment *env, FILE *stream)
840     {
841 masse 1.68 char in_string[101];
842    
843 teddy 1.124 if(fgets(in_string, 100, stream)==NULL) {
844 teddy 1.84 push_cstring(env, "");
845 teddy 1.124 if (! feof(stream)){
846     perror("readline");
847     env->err= 5;
848     }
849     } else {
850 teddy 1.84 push_cstring(env, in_string);
851 teddy 1.124 }
852 masse 1.68 }
853    
854 masse 1.132
855 masse 1.126 /* Reverse (flip) a list */
856     extern void rev(environment *env)
857 masse 1.95 {
858 masse 1.126 value *old_head, *new_head, *item;
859 teddy 1.124
860 masse 1.126 if(CAR(env->head)->type==empty)
861     return; /* Don't reverse an empty list */
862    
863 masse 1.135 if(check_args(env, tcons, empty))
864     return printerr(env);
865 teddy 1.124
866 masse 1.126 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 masse 1.132
878 masse 1.126 /* 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 masse 1.132 if(env->head->type != empty)
891     env->head= CDR(env->head);
892 masse 1.126 } 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 masse 1.132 env->head= CDR(env->head);
906 masse 1.126 }
907    
908     /* Push list */
909 teddy 1.124
910 masse 1.126 push_val(env, temp);
911     rev(env);
912 teddy 1.124 }
913    
914 masse 1.132
915 teddy 1.124 /* read from a stream; used by "read" and "readport" */
916     void readstream(environment *env, FILE *stream)
917     {
918 teddy 1.78 const char symbform[]= "%[a-zA-Z0-9!$%*+./:<=>?@^_~-]%n";
919     const char strform[]= "\"%[^\"]\"%n";
920     const char intform[]= "%i%n";
921 masse 1.93 const char fltform[]= "%f%n";
922 teddy 1.78 const char blankform[]= "%*[ \t]%n";
923 masse 1.90 const char ebrackform[]= "]%n";
924     const char semicform[]= ";%n";
925     const char bbrackform[]= "[%n";
926 masse 1.68
927 teddy 1.78 int itemp, readlength= -1;
928 masse 1.93 int count= -1;
929     float ftemp;
930 masse 1.68 static int depth= 0;
931 teddy 1.116 char *match;
932 masse 1.68 size_t inlength;
933    
934 masse 1.70 if(env->in_string==NULL) {
935 teddy 1.84 if(depth > 0 && env->interactive) {
936 teddy 1.80 printf("]> ");
937     }
938 masse 1.126 readlinestream(env, env->inputstream);
939     if(env->err) return;
940 teddy 1.84
941 masse 1.128 if((CAR(env->head)->content.string)[0]=='\0'){
942 teddy 1.85 env->err= 4; /* "" means EOF */
943 teddy 1.84 return;
944     }
945 masse 1.68
946 masse 1.128 env->in_string= malloc(strlen(CAR(env->head)->content.string)+1);
947 teddy 1.118 assert(env->in_string != NULL);
948 teddy 1.78 env->free_string= env->in_string; /* Save the original pointer */
949 masse 1.128 strcpy(env->in_string, CAR(env->head)->content.string);
950 masse 1.132 env->head= CDR(env->head);
951 masse 1.68 }
952    
953 masse 1.70 inlength= strlen(env->in_string)+1;
954 masse 1.68 match= malloc(inlength);
955 teddy 1.118 assert(match != NULL);
956 masse 1.68
957 masse 1.93 if(sscanf(env->in_string, blankform, &readlength) != EOF
958 teddy 1.78 && readlength != -1) {
959 masse 1.71 ;
960 masse 1.93 } else if(sscanf(env->in_string, fltform, &ftemp, &readlength) != EOF
961 teddy 1.78 && readlength != -1) {
962 masse 1.93 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 teddy 1.114 } else if(sscanf(env->in_string, "\"\"%n", &readlength) != EOF
969     && readlength != -1) {
970     push_cstring(env, "");
971 teddy 1.78 } else if(sscanf(env->in_string, strform, match, &readlength) != EOF
972     && readlength != -1) {
973 masse 1.72 push_cstring(env, match);
974 teddy 1.78 } else if(sscanf(env->in_string, symbform, match, &readlength) != EOF
975     && readlength != -1) {
976 masse 1.68 push_sym(env, match);
977 teddy 1.78 } else if(sscanf(env->in_string, ebrackform, &readlength) != EOF
978     && readlength != -1) {
979 masse 1.68 pack(env); if(env->err) return;
980 teddy 1.78 if(depth != 0) depth--;
981     } else if(sscanf(env->in_string, semicform, &readlength) != EOF
982     && readlength != -1) {
983 masse 1.68 push_sym(env, ";");
984 teddy 1.78 } else if(sscanf(env->in_string, bbrackform, &readlength) != EOF
985     && readlength != -1) {
986 masse 1.68 push_sym(env, "[");
987     depth++;
988     } else {
989 teddy 1.78 free(env->free_string);
990     env->in_string = env->free_string = NULL;
991     }
992 masse 1.126 if (env->in_string != NULL) {
993     env->in_string += readlength;
994 teddy 1.91 }
995    
996 masse 1.126 free(match);
997 teddy 1.91
998 masse 1.126 if(depth)
999     return readstream(env, env->inputstream);
1000 masse 1.133 }
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 masse 1.95 }

root@recompile.se
ViewVC Help
Powered by ViewVC 1.1.26