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

Annotation of /stack/stack.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.124 - (hide annotations)
Sat Mar 30 02:31:24 2002 UTC (22 years, 1 month ago) by teddy
Branch: MAIN
Changes since 1.123: +330 -40 lines
File MIME type: text/plain
stack.c (gc_init): Don't GC ports.
(nl): Added an "environment*" argument.  All callers changed.
(nlport): New function.
(type): Know about ports.
(print_val): Added a FILE* argument to print to.  All callers changed.
	Also check for write errors from "fprintf".  Also, print
	ports.  If printing a list, goto out of it if a write error
	occurs and don't print any further.
(print_): Check for errors after "print_val".
(printport_, printport, princport_, princport): New functions.
(print_st): Added an "environment*" argument.  All callers changed.
(eval): Toss empty lists; if lists are functions, then empty lists are
	NOPs.  Also, don't eval ports.
(main): Reset error after showing it to protect "nl" and "printstack".
(copy_val): Don't protect the old value.  Was there ever a need to do
	that?  Also, know about ports.
(readline): Just call "readlinestream".
(readlineport, readlinestream): New functions.
(read): Just call "readstream".
(readport, readstream): New functions.
(sx_6f70656e, sx_636c6f7365): New functions "open" and "close".

stack.h (value.type): New type; "port".
(value.content): New container; "p".
(nl): Added an "environment*" argument.
(nlport): New function.
(print_val): Added a FILE* argument.
(printport_, printport, princport_, princport): New functions.
(print_st): Added an "environment*" argument.
(readlineport, readlinestream, readport, readstream, sx_6f70656e,
sx_636c6f7365): New functions.

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.117 #define CAR(X) ((X)->content.c->car)
25     #define CDR(X) ((X)->content.c->cdr)
26 masse 1.104
27 teddy 1.84 /* printf, sscanf, fgets, fprintf, fopen, perror */
28 masse 1.1 #include <stdio.h>
29 teddy 1.52 /* exit, EXIT_SUCCESS, malloc, free */
30 masse 1.1 #include <stdlib.h>
31     /* NULL */
32     #include <stddef.h>
33 teddy 1.3 /* dlopen, dlsym, dlerror */
34 masse 1.1 #include <dlfcn.h>
35 teddy 1.52 /* strcmp, strcpy, strlen, strcat, strdup */
36 masse 1.47 #include <string.h>
37 teddy 1.91 /* getopt, STDIN_FILENO, STDOUT_FILENO, usleep */
38 teddy 1.84 #include <unistd.h>
39     /* EX_NOINPUT, EX_USAGE */
40     #include <sysexits.h>
41 masse 1.108 /* assert */
42     #include <assert.h>
43 masse 1.107
44     #ifdef __linux__
45 masse 1.83 /* mtrace, muntrace */
46     #include <mcheck.h>
47 teddy 1.91 /* ioctl */
48     #include <sys/ioctl.h>
49     /* KDMKTONE */
50     #include <linux/kd.h>
51 masse 1.107 #endif /* __linux__ */
52 masse 1.1
53 teddy 1.88 #include "stack.h"
54 masse 1.1
55 teddy 1.28 /* Initialize a newly created environment */
56     void init_env(environment *env)
57 masse 1.1 {
58 masse 1.46 int i;
59 masse 1.1
60 teddy 1.100 env->gc_limit= 400000;
61 masse 1.87 env->gc_count= 0;
62 masse 1.90 env->gc_ref= NULL;
63 masse 1.87
64 teddy 1.111 env->head= new_val(env);
65 masse 1.1 for(i= 0; i<HASHTBLSIZE; i++)
66 teddy 1.28 env->symbols[i]= NULL;
67 teddy 1.84 env->err= 0;
68     env->in_string= NULL;
69     env->free_string= NULL;
70     env->inputstream= stdin;
71     env->interactive= 1;
72 masse 1.1 }
73    
74 masse 1.95 void printerr(const char* in_string)
75     {
76 teddy 1.48 fprintf(stderr, "Err: %s\n", in_string);
77     }
78    
79     /* Discard the top element of the stack. */
80     extern void toss(environment *env)
81     {
82 teddy 1.111 if(env->head->type==empty) {
83 teddy 1.48 printerr("Too Few Arguments");
84 masse 1.90 env->err= 1;
85 teddy 1.48 return;
86     }
87    
88 masse 1.104 env->head= CDR(env->head); /* Remove the top stack item */
89 teddy 1.48 }
90    
91 teddy 1.27 /* Returns a pointer to a pointer to an element in the hash table. */
92 teddy 1.28 symbol **hash(hashtbl in_hashtbl, const char *in_string)
93 masse 1.1 {
94 masse 1.46 int i= 0;
95     unsigned int out_hash= 0;
96 teddy 1.18 char key= '\0';
97 teddy 1.28 symbol **position;
98 masse 1.1
99 masse 1.16 while(1){ /* Hash in_string */
100 masse 1.1 key= in_string[i++];
101     if(key=='\0')
102     break;
103     out_hash= out_hash*32+key;
104     }
105    
106     out_hash= out_hash%HASHTBLSIZE;
107     position= &(in_hashtbl[out_hash]);
108    
109 masse 1.25 while(1){
110 teddy 1.18 if(*position==NULL) /* If empty */
111 masse 1.1 return position;
112    
113 teddy 1.18 if(strcmp(in_string, (*position)->id)==0) /* If match */
114 masse 1.1 return position;
115    
116 masse 1.16 position= &((*position)->next); /* Try next */
117 masse 1.1 }
118     }
119    
120 masse 1.95 /* Create new value */
121     value* new_val(environment *env)
122     {
123 masse 1.87 value *nval= malloc(sizeof(value));
124     stackitem *nitem= malloc(sizeof(stackitem));
125    
126 teddy 1.118 assert(nval != NULL);
127     assert(nitem != NULL);
128    
129 masse 1.87 nval->content.ptr= NULL;
130 teddy 1.117 nval->type= empty;
131 masse 1.87
132     nitem->item= nval;
133     nitem->next= env->gc_ref;
134 masse 1.102
135 masse 1.87 env->gc_ref= nitem;
136    
137 teddy 1.101 env->gc_count += sizeof(value);
138 teddy 1.99 nval->gc.flag.mark= 0;
139     nval->gc.flag.protect= 0;
140 masse 1.93
141 masse 1.87 return nval;
142     }
143    
144 masse 1.95 /* Mark values recursively.
145     Marked values are not collected by the GC. */
146 teddy 1.96 inline void gc_mark(value *val)
147 masse 1.95 {
148 masse 1.102 if(val==NULL || val->gc.flag.mark)
149 masse 1.87 return;
150    
151 teddy 1.99 val->gc.flag.mark= 1;
152 masse 1.87
153 masse 1.104 if(val->type==tcons) {
154     gc_mark(CAR(val));
155     gc_mark(CDR(val));
156 masse 1.87 }
157     }
158    
159 teddy 1.96 inline void gc_maybe(environment *env)
160     {
161     if(env->gc_count < env->gc_limit)
162     return;
163     else
164     return gc_init(env);
165     }
166    
167 masse 1.95 /* Start GC */
168     extern void gc_init(environment *env)
169     {
170 masse 1.102 stackitem *new_head= NULL, *titem;
171 masse 1.87 symbol *tsymb;
172     int i;
173    
174 masse 1.102 if(env->interactive)
175 teddy 1.101 printf("Garbage collecting.");
176 teddy 1.100
177 masse 1.95 /* Mark values on stack */
178 masse 1.104 gc_mark(env->head);
179 masse 1.87
180 masse 1.102 if(env->interactive)
181 teddy 1.100 printf(".");
182 masse 1.102
183 teddy 1.100
184 masse 1.93 /* Mark values in hashtable */
185 masse 1.102 for(i= 0; i<HASHTBLSIZE; i++)
186     for(tsymb= env->symbols[i]; tsymb!=NULL; tsymb= tsymb->next)
187 masse 1.97 if (tsymb->val != NULL)
188     gc_mark(tsymb->val);
189 masse 1.87
190 masse 1.102
191     if(env->interactive)
192 teddy 1.100 printf(".");
193 masse 1.102
194 masse 1.87 env->gc_count= 0;
195    
196 masse 1.95 while(env->gc_ref!=NULL) { /* Sweep unused values */
197 masse 1.90
198 teddy 1.99 if(!(env->gc_ref->item->gc.no_gc)){ /* neither mark nor protect */
199 masse 1.93
200 teddy 1.116 /* Remove content */
201     switch(env->gc_ref->item->type){
202     case string:
203 masse 1.87 free(env->gc_ref->item->content.ptr);
204 teddy 1.116 break;
205     case tcons:
206     free(env->gc_ref->item->content.c);
207     break;
208 teddy 1.124 case port:
209 teddy 1.116 case empty:
210     case integer:
211     case tfloat:
212     case func:
213     case symb:
214     /* Symbol strings are freed when walking the hash table */
215     }
216 masse 1.102
217 masse 1.93 free(env->gc_ref->item); /* Remove from gc_ref */
218 masse 1.87 titem= env->gc_ref->next;
219 masse 1.93 free(env->gc_ref); /* Remove value */
220 masse 1.87 env->gc_ref= titem;
221 masse 1.97 continue;
222 teddy 1.110 }
223     #ifdef DEBUG
224     printf("Kept value (%p)", env->gc_ref->item);
225     if(env->gc_ref->item->gc.flag.mark)
226     printf(" (marked)");
227     if(env->gc_ref->item->gc.flag.protect)
228     printf(" (protected)");
229     switch(env->gc_ref->item->type){
230     case integer:
231     printf(" integer: %d", env->gc_ref->item->content.i);
232     break;
233     case func:
234     printf(" func: %p", env->gc_ref->item->content.ptr);
235     break;
236     case symb:
237     printf(" symb: %s", env->gc_ref->item->content.sym->id);
238     break;
239     case tcons:
240     printf(" tcons: %p\t%p", env->gc_ref->item->content.c->car,
241     env->gc_ref->item->content.c->cdr);
242     break;
243     default:
244     printf(" <unknown %d>", (env->gc_ref->item->type));
245     }
246     printf("\n");
247     #endif /* DEBUG */
248 masse 1.102
249     /* Keep values */
250     env->gc_count += sizeof(value);
251     if(env->gc_ref->item->type==string)
252 teddy 1.114 env->gc_count += strlen(env->gc_ref->item->content.ptr)+1;
253 masse 1.97
254     titem= env->gc_ref->next;
255     env->gc_ref->next= new_head;
256     new_head= env->gc_ref;
257 teddy 1.99 new_head->item->gc.flag.mark= 0;
258 masse 1.97 env->gc_ref= titem;
259 masse 1.87 }
260    
261 teddy 1.100 if (env->gc_limit < env->gc_count*2)
262     env->gc_limit= env->gc_count*2;
263 teddy 1.101
264 masse 1.87 env->gc_ref= new_head;
265 teddy 1.100
266 masse 1.102 if(env->interactive)
267 teddy 1.110 printf("done (%d bytes still allocated)\n", env->gc_count);
268 teddy 1.100
269 masse 1.87 }
270    
271 masse 1.95 /* Protect values from GC */
272 masse 1.98 void protect(value *val)
273 masse 1.90 {
274 masse 1.102 if(val==NULL || val->gc.flag.protect)
275 masse 1.98 return;
276    
277 teddy 1.99 val->gc.flag.protect= 1;
278 masse 1.98
279 masse 1.104 if(val->type==tcons) {
280     protect(CAR(val));
281     protect(CDR(val));
282 masse 1.98 }
283 masse 1.90 }
284    
285 masse 1.95 /* Unprotect values from GC */
286 masse 1.98 void unprotect(value *val)
287 masse 1.90 {
288 masse 1.102 if(val==NULL || !(val->gc.flag.protect))
289 masse 1.98 return;
290    
291 teddy 1.99 val->gc.flag.protect= 0;
292 masse 1.98
293 masse 1.104 if(val->type==tcons) {
294     unprotect(CAR(val));
295     unprotect(CDR(val));
296 masse 1.98 }
297 masse 1.90 }
298    
299 teddy 1.29 /* Push a value onto the stack */
300 masse 1.72 void push_val(environment *env, value *val)
301 teddy 1.29 {
302 masse 1.104 value *new_value= new_val(env);
303 masse 1.102
304 teddy 1.115 new_value->content.c= malloc(sizeof(pair));
305 masse 1.108 assert(new_value->content.c!=NULL);
306 teddy 1.116 env->gc_count += sizeof(pair);
307 masse 1.104 new_value->type= tcons;
308     CAR(new_value)= val;
309     CDR(new_value)= env->head;
310     env->head= new_value;
311 teddy 1.29 }
312    
313 masse 1.95 /* Push an integer onto the stack */
314 masse 1.72 void push_int(environment *env, int in_val)
315 masse 1.1 {
316 masse 1.87 value *new_value= new_val(env);
317 teddy 1.28
318 masse 1.93 new_value->content.i= in_val;
319 teddy 1.28 new_value->type= integer;
320 masse 1.1
321 masse 1.75 push_val(env, new_value);
322 masse 1.1 }
323    
324 masse 1.95 /* Push a floating point number onto the stack */
325 masse 1.93 void push_float(environment *env, float in_val)
326     {
327     value *new_value= new_val(env);
328    
329     new_value->content.f= in_val;
330     new_value->type= tfloat;
331    
332     push_val(env, new_value);
333     }
334    
335 masse 1.14 /* Copy a string onto the stack. */
336 masse 1.72 void push_cstring(environment *env, const char *in_string)
337 masse 1.1 {
338 masse 1.87 value *new_value= new_val(env);
339 teddy 1.101 int length= strlen(in_string)+1;
340 teddy 1.28
341 teddy 1.101 new_value->content.ptr= malloc(length);
342 teddy 1.118 assert(new_value != NULL);
343 teddy 1.101 env->gc_count += length;
344 teddy 1.28 strcpy(new_value->content.ptr, in_string);
345     new_value->type= string;
346 masse 1.1
347 masse 1.75 push_val(env, new_value);
348 masse 1.1 }
349    
350 teddy 1.48 /* Mangle a symbol name to a valid C identifier name */
351 masse 1.95 char *mangle_str(const char *old_string)
352     {
353 masse 1.90 char validchars[]= "0123456789abcdef";
354 teddy 1.48 char *new_string, *current;
355    
356 masse 1.90 new_string= malloc((strlen(old_string)*2)+4);
357 teddy 1.118 assert(new_string != NULL);
358 teddy 1.48 strcpy(new_string, "sx_"); /* Stack eXternal */
359 masse 1.90 current= new_string+3;
360 teddy 1.48 while(old_string[0] != '\0'){
361 masse 1.90 current[0]= validchars[(unsigned char)(old_string[0])/16];
362     current[1]= validchars[(unsigned char)(old_string[0])%16];
363     current+= 2;
364 teddy 1.48 old_string++;
365     }
366 masse 1.90 current[0]= '\0';
367 teddy 1.48
368     return new_string; /* The caller must free() it */
369     }
370    
371 masse 1.95 extern void mangle(environment *env)
372     {
373 teddy 1.48 char *new_string;
374    
375 teddy 1.111 if(env->head->type==empty) {
376 teddy 1.48 printerr("Too Few Arguments");
377 masse 1.90 env->err= 1;
378 teddy 1.48 return;
379     }
380    
381 masse 1.104 if(CAR(env->head)->type!=string) {
382 teddy 1.48 printerr("Bad Argument Type");
383 masse 1.90 env->err= 2;
384 teddy 1.48 return;
385     }
386    
387 masse 1.104 new_string=
388     mangle_str((const char *)(CAR(env->head)->content.ptr));
389 teddy 1.48
390     toss(env);
391     if(env->err) return;
392    
393 masse 1.81 push_cstring(env, new_string);
394 teddy 1.48 }
395    
396 teddy 1.28 /* Push a symbol onto the stack. */
397 teddy 1.35 void push_sym(environment *env, const char *in_string)
398 masse 1.1 {
399 teddy 1.28 value *new_value; /* A new symbol value */
400     /* ...which might point to... */
401 teddy 1.29 symbol **new_symbol; /* (if needed) A new actual symbol */
402 teddy 1.28 /* ...which, if possible, will be bound to... */
403     value *new_fvalue; /* (if needed) A new function value */
404     /* ...which will point to... */
405     void *funcptr; /* A function pointer */
406    
407     static void *handle= NULL; /* Dynamic linker handle */
408 teddy 1.48 const char *dlerr; /* Dynamic linker error */
409     char *mangled; /* Mangled function name */
410 teddy 1.28
411 masse 1.87 new_value= new_val(env);
412 masse 1.98 protect(new_value);
413 masse 1.93 new_fvalue= new_val(env);
414 masse 1.98 protect(new_fvalue);
415 teddy 1.28
416     /* The new value is a symbol */
417     new_value->type= symb;
418    
419     /* Look up the symbol name in the hash table */
420 teddy 1.29 new_symbol= hash(env->symbols, in_string);
421     new_value->content.ptr= *new_symbol;
422 teddy 1.28
423 teddy 1.30 if(*new_symbol==NULL) { /* If symbol was undefined */
424 teddy 1.28
425     /* Create a new symbol */
426 teddy 1.30 (*new_symbol)= malloc(sizeof(symbol));
427 teddy 1.118 assert((*new_symbol) != NULL);
428 teddy 1.29 (*new_symbol)->val= NULL; /* undefined value */
429     (*new_symbol)->next= NULL;
430     (*new_symbol)->id= malloc(strlen(in_string)+1);
431 teddy 1.118 assert((*new_symbol)->id != NULL);
432 teddy 1.29 strcpy((*new_symbol)->id, in_string);
433 masse 1.1
434 teddy 1.28 /* Intern the new symbol in the hash table */
435 teddy 1.29 new_value->content.ptr= *new_symbol;
436 masse 1.1
437 teddy 1.28 /* Try to load the symbol name as an external function, to see if
438     we should bind the symbol to a new function pointer value */
439 masse 1.16 if(handle==NULL) /* If no handle */
440 teddy 1.28 handle= dlopen(NULL, RTLD_LAZY);
441 masse 1.6
442 masse 1.90 mangled= mangle_str(in_string); /* mangle the name */
443 teddy 1.86 funcptr= dlsym(handle, mangled); /* and try to find it */
444 masse 1.95
445 masse 1.90 dlerr= dlerror();
446 teddy 1.48 if(dlerr != NULL) { /* If no function was found */
447 teddy 1.86 funcptr= dlsym(handle, in_string); /* Get function pointer */
448 masse 1.90 dlerr= dlerror();
449 teddy 1.48 }
450 masse 1.95
451 teddy 1.48 if(dlerr==NULL) { /* If a function was found */
452 masse 1.90 new_fvalue->type= func; /* The new value is a function pointer */
453     new_fvalue->content.ptr= funcptr; /* Store function pointer */
454 teddy 1.29 (*new_symbol)->val= new_fvalue; /* Bind the symbol to the new
455     function value */
456 teddy 1.28 }
457 masse 1.95
458     free(mangled);
459 masse 1.1 }
460 masse 1.95
461 masse 1.75 push_val(env, new_value);
462 masse 1.98 unprotect(new_value); unprotect(new_fvalue);
463 masse 1.1 }
464    
465 masse 1.14 /* Print newline. */
466 teddy 1.124 extern void nl(environment *env)
467 masse 1.8 {
468     printf("\n");
469     }
470 masse 1.1
471 teddy 1.124 /* Print a newline to a port */
472     extern void nlport(environment *env)
473     {
474     if(env->head->type==empty) {
475     printerr("Too Few Arguments");
476     env->err= 1;
477     return;
478     }
479    
480     if(CAR(env->head)->type!=port) {
481     printerr("Bad Argument Type");
482     env->err= 2;
483     return;
484     }
485    
486     if(fprintf(CAR(env->head)->content.p, "\n") < 0){
487     perror("nl");
488     env->err= 5;
489     return;
490     }
491     toss(env);
492     }
493    
494 teddy 1.37 /* Gets the type of a value */
495 masse 1.95 extern void type(environment *env)
496     {
497 teddy 1.111 if(env->head->type==empty) {
498 teddy 1.37 printerr("Too Few Arguments");
499 masse 1.104 env->err= 1;
500 teddy 1.37 return;
501     }
502 masse 1.104
503 teddy 1.112 switch(CAR(env->head)->type){
504     case empty:
505     push_sym(env, "empty");
506     break;
507 teddy 1.37 case integer:
508     push_sym(env, "integer");
509     break;
510 masse 1.93 case tfloat:
511     push_sym(env, "float");
512     break;
513 teddy 1.37 case string:
514     push_sym(env, "string");
515     break;
516     case symb:
517     push_sym(env, "symbol");
518     break;
519     case func:
520     push_sym(env, "function");
521     break;
522 masse 1.102 case tcons:
523 teddy 1.113 push_sym(env, "pair");
524 teddy 1.37 break;
525 teddy 1.124 case port:
526     push_sym(env, "port");
527     break;
528 teddy 1.37 }
529 teddy 1.112 swap(env);
530     if (env->err) return;
531     toss(env);
532 teddy 1.124 }
533 teddy 1.37
534 teddy 1.114 /* Print a value */
535 teddy 1.124 void print_val(environment *env, value *val, int noquote, stackitem *stack, FILE *stream)
536 masse 1.8 {
537 teddy 1.117 stackitem *titem, *tstack;
538     int depth;
539    
540 teddy 1.113 switch(val->type) {
541 teddy 1.112 case empty:
542 teddy 1.124 if(fprintf(stream, "[]") < 0){
543     perror("print_val");
544     env->err= 5;
545     return;
546     }
547 teddy 1.112 break;
548 teddy 1.28 case integer:
549 teddy 1.124 if(fprintf(stream, "%d", val->content.i) < 0){
550     perror("print_val");
551     env->err= 5;
552     return;
553     }
554 masse 1.93 break;
555     case tfloat:
556 teddy 1.124 if(fprintf(stream, "%f", val->content.f) < 0){
557     perror("print_val");
558     env->err= 5;
559     return;
560     }
561 teddy 1.2 break;
562     case string:
563 teddy 1.124 if(noquote){
564     if(fprintf(stream, "%s", (char*)(val->content.ptr)) < 0){
565     perror("print_val");
566     env->err= 5;
567     return;
568     }
569     } else { /* quote */
570     if(fprintf(stream, "\"%s\"", (char*)(val->content.ptr)) < 0){
571     perror("print_val");
572     env->err= 5;
573     return;
574     }
575     }
576 teddy 1.2 break;
577 teddy 1.28 case symb:
578 teddy 1.124 if(fprintf(stream, "%s", val->content.sym->id) < 0){
579     perror("print_val");
580     env->err= 5;
581     return;
582     }
583 masse 1.6 break;
584 teddy 1.35 case func:
585 teddy 1.124 if(fprintf(stream, "#<function %p>", (funcp)(val->content.ptr)) < 0){
586     perror("print_val");
587     env->err= 5;
588     return;
589     }
590     break;
591     case port:
592     if(fprintf(stream, "#<port %p>", (funcp)(val->content.p)) < 0){
593     perror("print_val");
594     env->err= 5;
595     return;
596     }
597 teddy 1.35 break;
598 masse 1.102 case tcons:
599 teddy 1.124 if(fprintf(stream, "[ ") < 0){
600     perror("print_val");
601     env->err= 5;
602     return;
603     }
604 teddy 1.117 tstack= stack;
605 teddy 1.113 do {
606 teddy 1.117 titem=malloc(sizeof(stackitem));
607 teddy 1.118 assert(titem != NULL);
608 teddy 1.117 titem->item=val;
609     titem->next=tstack;
610     tstack=titem; /* Put it on the stack */
611     /* Search a stack of values being printed to see if we are already
612     printing this value */
613     titem=tstack;
614     depth=0;
615     while(titem != NULL && titem->item != CAR(val)){
616     titem=titem->next;
617     depth++;
618     }
619     if(titem != NULL){ /* If we found it on the stack, */
620 teddy 1.124 if(fprintf(stream, "#%d#", depth) < 0){ /* print a depth reference */
621     perror("print_val");
622     env->err= 5;
623     free(titem);
624     return;
625     }
626 teddy 1.117 } else {
627 teddy 1.124 print_val(env, CAR(val), noquote, tstack, stream);
628 teddy 1.117 }
629 teddy 1.114 val= CDR(val);
630     switch(val->type){
631 teddy 1.112 case empty:
632     break;
633     case tcons:
634 teddy 1.117 /* Search a stack of values being printed to see if we are already
635     printing this value */
636     titem=tstack;
637     depth=0;
638     while(titem != NULL && titem->item != val){
639     titem=titem->next;
640     depth++;
641     }
642     if(titem != NULL){ /* If we found it on the stack, */
643 teddy 1.124 if(fprintf(stream, " . #%d#", depth) < 0){ /* print a depth reference */
644     perror("print_val");
645     env->err= 5;
646     goto printval_end;
647     }
648 teddy 1.117 } else {
649 teddy 1.124 if(fprintf(stream, " ") < 0){
650     perror("print_val");
651     env->err= 5;
652     goto printval_end;
653     }
654 teddy 1.117 }
655 teddy 1.112 break;
656     default:
657 teddy 1.124 if(fprintf(stream, " . ") < 0){ /* Improper list */
658     perror("print_val");
659     env->err= 5;
660     goto printval_end;
661     }
662     print_val(env, val, noquote, tstack, stream);
663 teddy 1.112 }
664 teddy 1.117 } while(val->type == tcons && titem == NULL);
665 teddy 1.124
666     printval_end:
667    
668 teddy 1.117 titem=tstack;
669     while(titem != stack){
670     tstack=titem->next;
671     free(titem);
672     titem=tstack;
673     }
674 teddy 1.124
675     if(! (env->err)){
676     if(fprintf(stream, " ]") < 0){
677     perror("print_val");
678     env->err= 5;
679     }
680     }
681 teddy 1.35 break;
682 teddy 1.2 }
683 masse 1.1 }
684    
685 teddy 1.124 /* Print the top element of the stack but don't discard it */
686 masse 1.95 extern void print_(environment *env)
687     {
688 teddy 1.111 if(env->head->type==empty) {
689 teddy 1.36 printerr("Too Few Arguments");
690 masse 1.104 env->err= 1;
691 teddy 1.35 return;
692     }
693 teddy 1.124 print_val(env, CAR(env->head), 0, NULL, stdout);
694     if(env->err) return;
695     nl(env);
696 teddy 1.28 }
697    
698 teddy 1.124 /* Prints the top element of the stack */
699 teddy 1.28 extern void print(environment *env)
700 masse 1.8 {
701 teddy 1.28 print_(env);
702 teddy 1.35 if(env->err) return;
703 teddy 1.28 toss(env);
704 masse 1.8 }
705    
706 teddy 1.124 /* Print the top element of the stack without quotes, but don't
707     discard it. */
708 masse 1.95 extern void princ_(environment *env)
709     {
710 teddy 1.111 if(env->head->type==empty) {
711 teddy 1.80 printerr("Too Few Arguments");
712 masse 1.104 env->err= 1;
713 teddy 1.80 return;
714     }
715 teddy 1.124 print_val(env, CAR(env->head), 1, NULL, stdout);
716 teddy 1.80 }
717    
718 teddy 1.124 /* Prints the top element of the stack without quotes. */
719 teddy 1.80 extern void princ(environment *env)
720     {
721     princ_(env);
722     if(env->err) return;
723     toss(env);
724     }
725    
726 teddy 1.124 /* Print a value to a port, but don't discard it */
727     extern void printport_(environment *env)
728     {
729     if(env->head->type==empty || CDR(env->head)->type == empty) {
730     printerr("Too Few Arguments");
731     env->err= 1;
732     return;
733     }
734    
735     if(CAR(env->head)->type!=port) {
736     printerr("Bad Argument Type");
737     env->err= 2;
738     return;
739     }
740    
741     print_val(env, CAR(CDR(env->head)), 0, NULL, CAR(env->head)->content.p);
742     if(env->err) return;
743     nlport(env);
744     }
745    
746     /* Print a value to a port */
747     extern void printport(environment *env)
748     {
749     printport_(env);
750     if(env->err) return;
751     toss(env);
752     }
753    
754     /* Print, without quotes, to a port, a value, but don't discard it. */
755     extern void princport_(environment *env)
756     {
757     if(env->head->type==empty || CDR(env->head)->type == empty) {
758     printerr("Too Few Arguments");
759     env->err= 1;
760     return;
761     }
762    
763     if(CAR(env->head)->type!=port) {
764     printerr("Bad Argument Type");
765     env->err= 2;
766     return;
767     }
768    
769     print_val(env, CAR(CDR(env->head)), 1, NULL, CAR(env->head)->content.p);
770     toss(env); if(env->err) return;
771     }
772    
773     /* Print, without quotes, to a port, the top element. */
774     extern void princport(environment *env)
775     {
776     princport_(env);
777     if(env->err) return;
778     toss(env);
779     }
780    
781     /* Only to be called by itself function printstack. */
782     void print_st(environment *env, value *stack_head, long counter)
783 masse 1.8 {
784 teddy 1.111 if(CDR(stack_head)->type != empty)
785 teddy 1.124 print_st(env, CDR(stack_head), counter+1);
786 masse 1.8 printf("%ld: ", counter);
787 teddy 1.124 print_val(env, CAR(stack_head), 0, NULL, stdout);
788     nl(env);
789 masse 1.8 }
790    
791 masse 1.14 /* Prints the stack. */
792 teddy 1.28 extern void printstack(environment *env)
793 masse 1.1 {
794 teddy 1.111 if(env->head->type == empty) {
795 teddy 1.80 printf("Stack Empty\n");
796 teddy 1.35 return;
797 masse 1.1 }
798 masse 1.95
799 teddy 1.124 print_st(env, env->head, 1);
800 masse 1.1 }
801    
802 masse 1.26 /* Swap the two top elements on the stack. */
803 teddy 1.28 extern void swap(environment *env)
804 masse 1.26 {
805 masse 1.104 value *temp= env->head;
806 masse 1.26
807 teddy 1.111 if(env->head->type == empty || CDR(env->head)->type == empty) {
808 teddy 1.36 printerr("Too Few Arguments");
809 teddy 1.35 env->err=1;
810 masse 1.26 return;
811 teddy 1.28 }
812 masse 1.26
813 masse 1.104 env->head= CDR(env->head);
814     CDR(temp)= CDR(env->head);
815     CDR(env->head)= temp;
816 masse 1.26 }
817    
818 teddy 1.56 /* Rotate the first three elements on the stack. */
819     extern void rot(environment *env)
820     {
821 masse 1.104 value *temp= env->head;
822 teddy 1.56
823 teddy 1.111 if(env->head->type == empty || CDR(env->head)->type == empty
824     || CDR(CDR(env->head))->type == empty) {
825 teddy 1.56 printerr("Too Few Arguments");
826 masse 1.104 env->err= 1;
827 teddy 1.56 return;
828     }
829 masse 1.104
830     env->head= CDR(CDR(env->head));
831     CDR(CDR(temp))= CDR(env->head);
832     CDR(env->head)= temp;
833 teddy 1.56 }
834    
835 teddy 1.33 /* Recall a value from a symbol, if bound */
836 teddy 1.31 extern void rcl(environment *env)
837     {
838     value *val;
839    
840 teddy 1.111 if(env->head->type==empty) {
841 teddy 1.36 printerr("Too Few Arguments");
842 masse 1.102 env->err= 1;
843 teddy 1.31 return;
844     }
845    
846 masse 1.104 if(CAR(env->head)->type!=symb) {
847 teddy 1.36 printerr("Bad Argument Type");
848 masse 1.102 env->err= 2;
849 teddy 1.31 return;
850     }
851 teddy 1.35
852 masse 1.105 val= CAR(env->head)->content.sym->val;
853 teddy 1.33 if(val == NULL){
854 teddy 1.36 printerr("Unbound Variable");
855 masse 1.102 env->err= 3;
856 teddy 1.33 return;
857     }
858 teddy 1.110 push_val(env, val); /* Return the symbol's bound value */
859     swap(env);
860     if(env->err) return;
861     toss(env); /* toss the symbol */
862 teddy 1.35 if(env->err) return;
863 teddy 1.31 }
864 masse 1.26
865 teddy 1.29 /* If the top element is a symbol, determine if it's bound to a
866     function value, and if it is, toss the symbol and execute the
867     function. */
868 teddy 1.28 extern void eval(environment *env)
869 masse 1.1 {
870     funcp in_func;
871 masse 1.44 value* temp_val;
872 masse 1.104 value* iterator;
873 masse 1.44
874 teddy 1.80 eval_start:
875    
876 teddy 1.96 gc_maybe(env);
877    
878 teddy 1.111 if(env->head->type==empty) {
879 teddy 1.36 printerr("Too Few Arguments");
880 masse 1.102 env->err= 1;
881 masse 1.1 return;
882 masse 1.17 }
883 masse 1.1
884 masse 1.104 switch(CAR(env->head)->type) {
885 masse 1.46 /* if it's a symbol */
886     case symb:
887 teddy 1.35 rcl(env); /* get its contents */
888     if(env->err) return;
889 masse 1.104 if(CAR(env->head)->type!=symb){ /* don't recurse symbols */
890 teddy 1.64 goto eval_start;
891 teddy 1.29 }
892 teddy 1.59 return;
893 masse 1.22
894 masse 1.46 /* If it's a lone function value, run it */
895     case func:
896 masse 1.104 in_func= (funcp)(CAR(env->head)->content.ptr);
897 teddy 1.28 toss(env);
898 teddy 1.35 if(env->err) return;
899 masse 1.89 return in_func(env);
900 masse 1.44
901 masse 1.46 /* If it's a list */
902 masse 1.102 case tcons:
903 masse 1.104 temp_val= CAR(env->head);
904 masse 1.98 protect(temp_val);
905 masse 1.93
906     toss(env); if(env->err) return;
907 masse 1.104 iterator= temp_val;
908 masse 1.90
909 teddy 1.111 while(iterator->type != empty) {
910 masse 1.104 push_val(env, CAR(iterator));
911 masse 1.90
912 masse 1.104 if(CAR(env->head)->type==symb
913 masse 1.105 && CAR(env->head)->content.sym->id[0]==';') {
914 masse 1.44 toss(env);
915     if(env->err) return;
916 masse 1.90
917 teddy 1.111 if(CDR(iterator)->type == empty){
918 teddy 1.64 goto eval_start;
919 teddy 1.59 }
920 masse 1.44 eval(env);
921 masse 1.46 if(env->err) return;
922 masse 1.44 }
923 teddy 1.111 if (CDR(iterator)->type == empty || CDR(iterator)->type == tcons)
924 masse 1.104 iterator= CDR(iterator);
925 teddy 1.103 else {
926     printerr("Bad Argument Type"); /* Improper list */
927     env->err= 2;
928     return;
929     }
930 masse 1.44 }
931 masse 1.98 unprotect(temp_val);
932 teddy 1.59 return;
933 masse 1.46
934 teddy 1.116 case empty:
935 teddy 1.124 toss(env);
936 teddy 1.116 case integer:
937     case tfloat:
938     case string:
939 teddy 1.124 case port:
940 teddy 1.59 return;
941 masse 1.26 }
942 masse 1.1 }
943    
944 masse 1.44 /* Reverse (flip) a list */
945 masse 1.95 extern void rev(environment *env)
946     {
947 masse 1.104 value *old_head, *new_head, *item;
948 teddy 1.40
949 teddy 1.111 if(env->head->type==empty) {
950 teddy 1.40 printerr("Too Few Arguments");
951 masse 1.90 env->err= 1;
952 teddy 1.40 return;
953     }
954    
955 teddy 1.111 if(CAR(env->head)->type==empty)
956     return; /* Don't reverse an empty list */
957    
958 masse 1.104 if(CAR(env->head)->type!=tcons) {
959 teddy 1.40 printerr("Bad Argument Type");
960 masse 1.90 env->err= 2;
961 teddy 1.40 return;
962     }
963    
964 masse 1.104 old_head= CAR(env->head);
965 teddy 1.111 new_head= new_val(env);
966     while(old_head->type != empty) {
967 masse 1.90 item= old_head;
968 masse 1.104 old_head= CDR(old_head);
969     CDR(item)= new_head;
970 masse 1.90 new_head= item;
971 teddy 1.40 }
972 masse 1.104 CAR(env->head)= new_head;
973 teddy 1.40 }
974    
975 masse 1.19 /* Make a list. */
976 teddy 1.28 extern void pack(environment *env)
977 masse 1.19 {
978 teddy 1.111 value *iterator, *temp, *ending;
979    
980     ending=new_val(env);
981 masse 1.19
982 teddy 1.28 iterator= env->head;
983 teddy 1.111 if(iterator->type == empty
984 masse 1.104 || (CAR(iterator)->type==symb
985 masse 1.105 && CAR(iterator)->content.sym->id[0]=='[')) {
986 teddy 1.111 temp= ending;
987 teddy 1.28 toss(env);
988 masse 1.24 } else {
989     /* Search for first delimiter */
990 teddy 1.111 while(CDR(iterator)->type != empty
991 masse 1.104 && (CAR(CDR(iterator))->type!=symb
992 masse 1.105 || CAR(CDR(iterator))->content.sym->id[0]!='['))
993 masse 1.104 iterator= CDR(iterator);
994 masse 1.24
995     /* Extract list */
996 teddy 1.28 temp= env->head;
997 masse 1.104 env->head= CDR(iterator);
998 teddy 1.111 CDR(iterator)= ending;
999 masse 1.93
1000 teddy 1.111 if(env->head->type != empty)
1001 teddy 1.28 toss(env);
1002 masse 1.24 }
1003 masse 1.19
1004     /* Push list */
1005 teddy 1.28
1006 masse 1.104 push_val(env, temp);
1007 teddy 1.40 rev(env);
1008 masse 1.19 }
1009    
1010 masse 1.16 /* Relocate elements of the list on the stack. */
1011 teddy 1.28 extern void expand(environment *env)
1012 masse 1.1 {
1013 masse 1.104 value *temp, *new_head;
1014 masse 1.8
1015 masse 1.16 /* Is top element a list? */
1016 teddy 1.111 if(env->head->type==empty) {
1017 teddy 1.36 printerr("Too Few Arguments");
1018 masse 1.90 env->err= 1;
1019 masse 1.8 return;
1020 masse 1.17 }
1021 masse 1.104
1022     if(CAR(env->head)->type!=tcons) {
1023 teddy 1.36 printerr("Bad Argument Type");
1024 masse 1.90 env->err= 2;
1025 teddy 1.36 return;
1026     }
1027 masse 1.43
1028     rev(env);
1029    
1030     if(env->err)
1031     return;
1032 masse 1.8
1033 masse 1.16 /* The first list element is the new stack head */
1034 masse 1.104 new_head= temp= CAR(env->head);
1035 masse 1.8
1036 teddy 1.28 toss(env);
1037 masse 1.24
1038 teddy 1.28 /* Find the end of the list */
1039 teddy 1.111 while(CDR(temp)->type != empty) {
1040 masse 1.104 if (CDR(temp)->type == tcons)
1041     temp= CDR(temp);
1042 teddy 1.103 else {
1043     printerr("Bad Argument Type"); /* Improper list */
1044     env->err= 2;
1045     return;
1046     }
1047     }
1048 masse 1.8
1049 teddy 1.28 /* Connect the tail of the list with the old stack head */
1050 masse 1.104 CDR(temp)= env->head;
1051 teddy 1.28 env->head= new_head; /* ...and voila! */
1052    
1053 teddy 1.5 }
1054 masse 1.11
1055 masse 1.14 /* Compares two elements by reference. */
1056 teddy 1.28 extern void eq(environment *env)
1057 masse 1.11 {
1058     void *left, *right;
1059    
1060 teddy 1.111 if(env->head->type==empty || CDR(env->head)->type==empty) {
1061 teddy 1.36 printerr("Too Few Arguments");
1062 masse 1.90 env->err= 1;
1063 masse 1.11 return;
1064 masse 1.17 }
1065 masse 1.11
1066 masse 1.104 left= CAR(env->head)->content.ptr;
1067     right= CAR(CDR(env->head))->content.ptr;
1068 teddy 1.28 toss(env); toss(env);
1069 masse 1.102
1070     push_int(env, left==right);
1071 masse 1.11 }
1072    
1073 masse 1.14 /* Negates the top element on the stack. */
1074 teddy 1.28 extern void not(environment *env)
1075 masse 1.11 {
1076 teddy 1.28 int val;
1077 masse 1.11
1078 teddy 1.111 if(env->head->type==empty) {
1079 teddy 1.36 printerr("Too Few Arguments");
1080 masse 1.90 env->err= 1;
1081 masse 1.11 return;
1082 masse 1.17 }
1083 masse 1.11
1084 masse 1.104 if(CAR(env->head)->type!=integer) {
1085 teddy 1.36 printerr("Bad Argument Type");
1086 masse 1.90 env->err= 2;
1087 teddy 1.36 return;
1088     }
1089    
1090 masse 1.104 val= CAR(env->head)->content.i;
1091 teddy 1.28 toss(env);
1092 masse 1.72 push_int(env, !val);
1093 masse 1.11 }
1094    
1095 masse 1.14 /* Compares the two top elements on the stack and return 0 if they're the
1096     same. */
1097 teddy 1.28 extern void neq(environment *env)
1098 masse 1.11 {
1099 teddy 1.28 eq(env);
1100     not(env);
1101 masse 1.11 }
1102 masse 1.12
1103 masse 1.14 /* Give a symbol some content. */
1104 teddy 1.28 extern void def(environment *env)
1105 masse 1.12 {
1106 teddy 1.28 symbol *sym;
1107 masse 1.12
1108 teddy 1.28 /* Needs two values on the stack, the top one must be a symbol */
1109 teddy 1.111 if(env->head->type==empty || CDR(env->head)->type==empty) {
1110 teddy 1.36 printerr("Too Few Arguments");
1111 masse 1.90 env->err= 1;
1112 masse 1.12 return;
1113 masse 1.17 }
1114 masse 1.12
1115 masse 1.104 if(CAR(env->head)->type!=symb) {
1116 teddy 1.36 printerr("Bad Argument Type");
1117 masse 1.90 env->err= 2;
1118 teddy 1.36 return;
1119     }
1120    
1121 teddy 1.28 /* long names are a pain */
1122 masse 1.104 sym= CAR(env->head)->content.ptr;
1123 teddy 1.28
1124     /* Bind the symbol to the value */
1125 masse 1.104 sym->val= CAR(CDR(env->head));
1126 masse 1.12
1127 teddy 1.28 toss(env); toss(env);
1128 masse 1.12 }
1129 masse 1.10
1130 masse 1.14 /* Quit stack. */
1131 teddy 1.28 extern void quit(environment *env)
1132 teddy 1.5 {
1133 masse 1.95 int i;
1134 teddy 1.77
1135     clear(env);
1136 masse 1.83
1137 teddy 1.77 if (env->err) return;
1138     for(i= 0; i<HASHTBLSIZE; i++) {
1139 masse 1.79 while(env->symbols[i]!= NULL) {
1140 teddy 1.77 forget_sym(&(env->symbols[i]));
1141     }
1142 teddy 1.80 env->symbols[i]= NULL;
1143 teddy 1.77 }
1144 masse 1.83
1145 masse 1.90 env->gc_limit= 0;
1146 teddy 1.96 gc_maybe(env);
1147 masse 1.87
1148 teddy 1.110 words(env);
1149    
1150 masse 1.83 if(env->free_string!=NULL)
1151     free(env->free_string);
1152    
1153 masse 1.107 #ifdef __linux__
1154 masse 1.83 muntrace();
1155 masse 1.107 #endif
1156 masse 1.83
1157 teddy 1.5 exit(EXIT_SUCCESS);
1158 masse 1.24 }
1159    
1160     /* Clear stack */
1161 teddy 1.28 extern void clear(environment *env)
1162 masse 1.24 {
1163 teddy 1.111 while(env->head->type != empty)
1164 teddy 1.28 toss(env);
1165 masse 1.1 }
1166    
1167 teddy 1.33 /* List all defined words */
1168 masse 1.32 extern void words(environment *env)
1169     {
1170     symbol *temp;
1171     int i;
1172    
1173     for(i= 0; i<HASHTBLSIZE; i++) {
1174     temp= env->symbols[i];
1175     while(temp!=NULL) {
1176 teddy 1.110 #ifdef DEBUG
1177     if (temp->val != NULL && temp->val->gc.flag.protect)
1178     printf("(protected) ");
1179     #endif /* DEBUG */
1180 masse 1.32 printf("%s\n", temp->id);
1181     temp= temp->next;
1182     }
1183     }
1184     }
1185 masse 1.34
1186 teddy 1.77 /* Internal forget function */
1187 masse 1.95 void forget_sym(symbol **hash_entry)
1188     {
1189 teddy 1.77 symbol *temp;
1190    
1191     temp= *hash_entry;
1192     *hash_entry= (*hash_entry)->next;
1193    
1194     free(temp->id);
1195     free(temp);
1196     }
1197    
1198 masse 1.34 /* Forgets a symbol (remove it from the hash table) */
1199     extern void forget(environment *env)
1200     {
1201     char* sym_id;
1202    
1203 teddy 1.111 if(env->head->type==empty) {
1204 teddy 1.36 printerr("Too Few Arguments");
1205 masse 1.102 env->err= 1;
1206 teddy 1.36 return;
1207     }
1208    
1209 teddy 1.111 if(CAR(env->head)->type!=symb) {
1210 teddy 1.36 printerr("Bad Argument Type");
1211 masse 1.102 env->err= 2;
1212 masse 1.34 return;
1213     }
1214    
1215 teddy 1.111 sym_id= CAR(env->head)->content.sym->id;
1216 masse 1.34 toss(env);
1217    
1218 teddy 1.77 return forget_sym(hash(env->symbols, sym_id));
1219 teddy 1.36 }
1220    
1221     /* Returns the current error number to the stack */
1222 masse 1.95 extern void errn(environment *env)
1223     {
1224 masse 1.72 push_int(env, env->err);
1225 teddy 1.36 }
1226 masse 1.69
1227 teddy 1.84 int main(int argc, char **argv)
1228 masse 1.1 {
1229 teddy 1.28 environment myenv;
1230 masse 1.1
1231 teddy 1.84 int c; /* getopt option character */
1232    
1233 masse 1.107 #ifdef __linux__
1234 masse 1.83 mtrace();
1235 masse 1.107 #endif
1236 masse 1.83
1237 teddy 1.28 init_env(&myenv);
1238 masse 1.1
1239 teddy 1.84 myenv.interactive = isatty(STDIN_FILENO) && isatty(STDOUT_FILENO);
1240    
1241     while ((c = getopt (argc, argv, "i")) != -1)
1242     switch (c)
1243     {
1244     case 'i':
1245     myenv.interactive = 1;
1246     break;
1247     case '?':
1248     fprintf (stderr,
1249 teddy 1.110 "Unknown option character '\\x%x'.\n",
1250 teddy 1.84 optopt);
1251     return EX_USAGE;
1252     default:
1253     abort ();
1254     }
1255    
1256     if (optind < argc) {
1257     myenv.interactive = 0;
1258     myenv.inputstream= fopen(argv[optind], "r");
1259     if(myenv.inputstream== NULL) {
1260     perror(argv[0]);
1261     exit (EX_NOINPUT);
1262     }
1263     }
1264    
1265 teddy 1.91 if(myenv.interactive) {
1266 teddy 1.124 printf("Stack version $Revision: 1.123 $\n\
1267 teddy 1.91 Copyright (C) 2002 Mats Alritzson and Teddy Hogeborn\n\
1268 teddy 1.110 Stack comes with ABSOLUTELY NO WARRANTY; for details type 'warranty;'.\n\
1269 teddy 1.91 This is free software, and you are welcome to redistribute it\n\
1270 teddy 1.110 under certain conditions; type 'copying;' for details.\n");
1271 teddy 1.91 }
1272    
1273 masse 1.69 while(1) {
1274 teddy 1.85 if(myenv.in_string==NULL) {
1275     if (myenv.interactive) {
1276     if(myenv.err) {
1277     printf("(error %d)\n", myenv.err);
1278 teddy 1.124 myenv.err= 0;
1279 teddy 1.85 }
1280 teddy 1.124 nl(&myenv);
1281 teddy 1.85 printstack(&myenv);
1282     printf("> ");
1283     }
1284     myenv.err=0;
1285 teddy 1.80 }
1286 teddy 1.110 sx_72656164(&myenv); /* "read" */
1287     if (myenv.err==4) { /* EOF */
1288     myenv.err=0;
1289     quit(&myenv);
1290 teddy 1.111 } else if(myenv.head->type!=empty
1291 masse 1.104 && CAR(myenv.head)->type==symb
1292 teddy 1.124 && CAR(myenv.head)->content.sym->id[0] == ';') {
1293 masse 1.69 toss(&myenv); /* No error check in main */
1294     eval(&myenv);
1295 teddy 1.35 }
1296 teddy 1.96 gc_maybe(&myenv);
1297 masse 1.1 }
1298 teddy 1.41 quit(&myenv);
1299 teddy 1.42 return EXIT_FAILURE;
1300 teddy 1.48 }
1301    
1302 teddy 1.85 /* "+" */
1303 masse 1.95 extern void sx_2b(environment *env)
1304     {
1305 teddy 1.48 int a, b;
1306 masse 1.93 float fa, fb;
1307 masse 1.49 size_t len;
1308     char* new_string;
1309     value *a_val, *b_val;
1310 teddy 1.48
1311 teddy 1.111 if(env->head->type==empty || CDR(env->head)->type==empty) {
1312 teddy 1.48 printerr("Too Few Arguments");
1313 masse 1.90 env->err= 1;
1314 masse 1.49 return;
1315     }
1316    
1317 masse 1.104 if(CAR(env->head)->type==string
1318     && CAR(CDR(env->head))->type==string) {
1319     a_val= CAR(env->head);
1320     b_val= CAR(CDR(env->head));
1321 masse 1.98 protect(a_val); protect(b_val);
1322 masse 1.49 toss(env); if(env->err) return;
1323     toss(env); if(env->err) return;
1324     len= strlen(a_val->content.ptr)+strlen(b_val->content.ptr)+1;
1325     new_string= malloc(len);
1326 teddy 1.118 assert(new_string != NULL);
1327 masse 1.49 strcpy(new_string, b_val->content.ptr);
1328     strcat(new_string, a_val->content.ptr);
1329 masse 1.72 push_cstring(env, new_string);
1330 masse 1.98 unprotect(a_val); unprotect(b_val);
1331 masse 1.49 free(new_string);
1332 masse 1.93
1333 teddy 1.48 return;
1334     }
1335    
1336 masse 1.104 if(CAR(env->head)->type==integer
1337     && CAR(CDR(env->head))->type==integer) {
1338     a= CAR(env->head)->content.i;
1339 masse 1.93 toss(env); if(env->err) return;
1340 masse 1.104 b= CAR(env->head)->content.i;
1341 masse 1.93 toss(env); if(env->err) return;
1342     push_int(env, b+a);
1343    
1344     return;
1345     }
1346    
1347 masse 1.104 if(CAR(env->head)->type==tfloat
1348     && CAR(CDR(env->head))->type==tfloat) {
1349     fa= CAR(env->head)->content.f;
1350 masse 1.93 toss(env); if(env->err) return;
1351 masse 1.104 fb= CAR(env->head)->content.f;
1352 masse 1.93 toss(env); if(env->err) return;
1353     push_float(env, fb+fa);
1354    
1355     return;
1356     }
1357    
1358 masse 1.104 if(CAR(env->head)->type==tfloat
1359     && CAR(CDR(env->head))->type==integer) {
1360     fa= CAR(env->head)->content.f;
1361 masse 1.93 toss(env); if(env->err) return;
1362 masse 1.104 b= CAR(env->head)->content.i;
1363 masse 1.93 toss(env); if(env->err) return;
1364     push_float(env, b+fa);
1365    
1366     return;
1367     }
1368    
1369 masse 1.104 if(CAR(env->head)->type==integer
1370     && CAR(CDR(env->head))->type==tfloat) {
1371     a= CAR(env->head)->content.i;
1372 masse 1.93 toss(env); if(env->err) return;
1373 masse 1.104 fb= CAR(env->head)->content.f;
1374 masse 1.93 toss(env); if(env->err) return;
1375     push_float(env, fb+a);
1376    
1377 teddy 1.48 return;
1378     }
1379 masse 1.93
1380     printerr("Bad Argument Type");
1381     env->err=2;
1382 masse 1.1 }
1383 teddy 1.55
1384 teddy 1.85 /* "-" */
1385 masse 1.95 extern void sx_2d(environment *env)
1386     {
1387 teddy 1.62 int a, b;
1388 masse 1.93 float fa, fb;
1389 teddy 1.60
1390 teddy 1.111 if(env->head->type==empty || CDR(env->head)->type==empty) {
1391 teddy 1.60 printerr("Too Few Arguments");
1392     env->err=1;
1393     return;
1394     }
1395    
1396 masse 1.104 if(CAR(env->head)->type==integer
1397     && CAR(CDR(env->head))->type==integer) {
1398     a= CAR(env->head)->content.i;
1399 masse 1.93 toss(env); if(env->err) return;
1400 masse 1.104 b= CAR(env->head)->content.i;
1401 masse 1.93 toss(env); if(env->err) return;
1402     push_int(env, b-a);
1403    
1404     return;
1405     }
1406    
1407 masse 1.104 if(CAR(env->head)->type==tfloat
1408     && CAR(CDR(env->head))->type==tfloat) {
1409     fa= CAR(env->head)->content.f;
1410 masse 1.93 toss(env); if(env->err) return;
1411 masse 1.104 fb= CAR(env->head)->content.f;
1412 masse 1.93 toss(env); if(env->err) return;
1413     push_float(env, fb-fa);
1414    
1415     return;
1416     }
1417    
1418 masse 1.104 if(CAR(env->head)->type==tfloat
1419     && CAR(CDR(env->head))->type==integer) {
1420     fa= CAR(env->head)->content.f;
1421 masse 1.93 toss(env); if(env->err) return;
1422 masse 1.104 b= CAR(env->head)->content.i;
1423 masse 1.93 toss(env); if(env->err) return;
1424     push_float(env, b-fa);
1425    
1426     return;
1427     }
1428    
1429 masse 1.104 if(CAR(env->head)->type==integer
1430     && CAR(CDR(env->head))->type==tfloat) {
1431     a= CAR(env->head)->content.i;
1432 masse 1.93 toss(env); if(env->err) return;
1433 masse 1.104 fb= CAR(env->head)->content.f;
1434 masse 1.93 toss(env); if(env->err) return;
1435     push_float(env, fb-a);
1436    
1437 teddy 1.60 return;
1438     }
1439 masse 1.90
1440 masse 1.93 printerr("Bad Argument Type");
1441     env->err=2;
1442 teddy 1.60 }
1443    
1444 teddy 1.85 /* ">" */
1445 masse 1.95 extern void sx_3e(environment *env)
1446     {
1447 teddy 1.62 int a, b;
1448 masse 1.93 float fa, fb;
1449 teddy 1.61
1450 teddy 1.111 if(env->head->type==empty || CDR(env->head)->type==empty) {
1451 teddy 1.61 printerr("Too Few Arguments");
1452 masse 1.102 env->err= 1;
1453 teddy 1.61 return;
1454     }
1455    
1456 masse 1.104 if(CAR(env->head)->type==integer
1457     && CAR(CDR(env->head))->type==integer) {
1458     a= CAR(env->head)->content.i;
1459 masse 1.93 toss(env); if(env->err) return;
1460 masse 1.104 b= CAR(env->head)->content.i;
1461 masse 1.93 toss(env); if(env->err) return;
1462     push_int(env, b>a);
1463    
1464     return;
1465     }
1466    
1467 masse 1.104 if(CAR(env->head)->type==tfloat
1468     && CAR(CDR(env->head))->type==tfloat) {
1469     fa= CAR(env->head)->content.f;
1470 masse 1.93 toss(env); if(env->err) return;
1471 masse 1.104 fb= CAR(env->head)->content.f;
1472 masse 1.93 toss(env); if(env->err) return;
1473     push_int(env, fb>fa);
1474    
1475     return;
1476     }
1477    
1478 masse 1.104 if(CAR(env->head)->type==tfloat
1479     && CAR(CDR(env->head))->type==integer) {
1480     fa= CAR(env->head)->content.f;
1481 masse 1.93 toss(env); if(env->err) return;
1482 masse 1.104 b= CAR(env->head)->content.i;
1483 masse 1.93 toss(env); if(env->err) return;
1484     push_int(env, b>fa);
1485    
1486     return;
1487     }
1488    
1489 masse 1.104 if(CAR(env->head)->type==integer
1490     && CAR(CDR(env->head))->type==tfloat) {
1491     a= CAR(env->head)->content.i;
1492 masse 1.93 toss(env); if(env->err) return;
1493 masse 1.104 fb= CAR(env->head)->content.f;
1494 masse 1.93 toss(env); if(env->err) return;
1495     push_int(env, fb>a);
1496    
1497 teddy 1.61 return;
1498     }
1499 masse 1.90
1500 masse 1.93 printerr("Bad Argument Type");
1501 masse 1.104 env->err= 2;
1502 masse 1.93 }
1503    
1504     /* "<" */
1505 masse 1.95 extern void sx_3c(environment *env)
1506     {
1507 masse 1.93 swap(env); if(env->err) return;
1508     sx_3e(env);
1509     }
1510    
1511     /* "<=" */
1512 masse 1.95 extern void sx_3c3d(environment *env)
1513     {
1514 masse 1.93 sx_3e(env); if(env->err) return;
1515     not(env);
1516     }
1517    
1518     /* ">=" */
1519 masse 1.95 extern void sx_3e3d(environment *env)
1520     {
1521 masse 1.93 sx_3c(env); if(env->err) return;
1522     not(env);
1523 teddy 1.61 }
1524    
1525 teddy 1.55 /* Return copy of a value */
1526 masse 1.95 value *copy_val(environment *env, value *old_value)
1527     {
1528 masse 1.93 value *new_value;
1529 teddy 1.55
1530 masse 1.104 if(old_value==NULL)
1531     return NULL;
1532    
1533 masse 1.93 new_value= new_val(env);
1534 masse 1.90 new_value->type= old_value->type;
1535 masse 1.87
1536 teddy 1.55 switch(old_value->type){
1537 masse 1.93 case tfloat:
1538 teddy 1.55 case integer:
1539 masse 1.93 case func:
1540     case symb:
1541 teddy 1.116 case empty:
1542 teddy 1.124 case port:
1543 masse 1.93 new_value->content= old_value->content;
1544 teddy 1.55 break;
1545     case string:
1546 masse 1.90 (char *)(new_value->content.ptr)=
1547     strdup((char *)(old_value->content.ptr));
1548 teddy 1.55 break;
1549 masse 1.102 case tcons:
1550 teddy 1.55
1551 teddy 1.115 new_value->content.c= malloc(sizeof(pair));
1552 masse 1.108 assert(new_value->content.c!=NULL);
1553 teddy 1.116 env->gc_count += sizeof(pair);
1554 masse 1.108
1555 masse 1.104 CAR(new_value)= copy_val(env, CAR(old_value)); /* recurse */
1556     CDR(new_value)= copy_val(env, CDR(old_value)); /* recurse */
1557 teddy 1.55 break;
1558     }
1559 masse 1.90
1560 teddy 1.55 return new_value;
1561     }
1562    
1563 teddy 1.84 /* "dup"; duplicates an item on the stack */
1564 masse 1.95 extern void sx_647570(environment *env)
1565     {
1566 teddy 1.111 if(env->head->type==empty) {
1567 teddy 1.55 printerr("Too Few Arguments");
1568 masse 1.90 env->err= 1;
1569 teddy 1.55 return;
1570     }
1571 masse 1.104 push_val(env, copy_val(env, CAR(env->head)));
1572 teddy 1.55 }
1573 teddy 1.56
1574 teddy 1.59 /* "if", If-Then */
1575 masse 1.95 extern void sx_6966(environment *env)
1576     {
1577 teddy 1.56 int truth;
1578    
1579 teddy 1.111 if(env->head->type==empty || CDR(env->head)->type==empty) {
1580 teddy 1.56 printerr("Too Few Arguments");
1581 masse 1.90 env->err= 1;
1582 teddy 1.56 return;
1583     }
1584    
1585 masse 1.104 if(CAR(CDR(env->head))->type != integer) {
1586 teddy 1.56 printerr("Bad Argument Type");
1587 masse 1.102 env->err= 2;
1588 teddy 1.56 return;
1589     }
1590    
1591     swap(env);
1592     if(env->err) return;
1593    
1594 masse 1.104 truth= CAR(env->head)->content.i;
1595 teddy 1.56
1596     toss(env);
1597     if(env->err) return;
1598    
1599     if(truth)
1600     eval(env);
1601     else
1602     toss(env);
1603     }
1604    
1605     /* If-Then-Else */
1606 masse 1.95 extern void ifelse(environment *env)
1607     {
1608 teddy 1.56 int truth;
1609    
1610 teddy 1.111 if(env->head->type==empty || CDR(env->head)->type==empty
1611     || CDR(CDR(env->head))->type==empty) {
1612 teddy 1.56 printerr("Too Few Arguments");
1613 masse 1.102 env->err= 1;
1614 teddy 1.56 return;
1615     }
1616    
1617 masse 1.104 if(CAR(CDR(CDR(env->head)))->type!=integer) {
1618 teddy 1.56 printerr("Bad Argument Type");
1619 masse 1.102 env->err= 2;
1620 teddy 1.56 return;
1621     }
1622    
1623     rot(env);
1624     if(env->err) return;
1625    
1626 masse 1.104 truth= CAR(env->head)->content.i;
1627 teddy 1.56
1628     toss(env);
1629     if(env->err) return;
1630    
1631     if(!truth)
1632     swap(env);
1633     if(env->err) return;
1634    
1635     toss(env);
1636     if(env->err) return;
1637    
1638     eval(env);
1639 masse 1.106 }
1640    
1641 teddy 1.124 /* "else" */
1642 masse 1.106 extern void sx_656c7365(environment *env)
1643     {
1644 teddy 1.111 if(env->head->type==empty || CDR(env->head)->type==empty
1645     || CDR(CDR(env->head))->type==empty || CDR(CDR(CDR(env->head)))->type==empty
1646     || CDR(CDR(CDR(CDR(env->head))))->type==empty) {
1647 masse 1.109 printerr("Too Few Arguments");
1648     env->err= 1;
1649     return;
1650     }
1651    
1652     if(CAR(CDR(env->head))->type!=symb
1653     || strcmp(CAR(CDR(env->head))->content.sym->id, "then")!=0
1654     || CAR(CDR(CDR(CDR(env->head))))->type!=symb
1655     || strcmp(CAR(CDR(CDR(CDR(env->head))))->content.sym->id, "if")!=0) {
1656     printerr("Bad Argument Type");
1657     env->err= 2;
1658     return;
1659     }
1660    
1661     swap(env); toss(env); rot(env); toss(env);
1662     ifelse(env);
1663     }
1664    
1665     extern void then(environment *env)
1666     {
1667 teddy 1.111 if(env->head->type==empty || CDR(env->head)->type==empty
1668     || CDR(CDR(env->head))->type==empty) {
1669 masse 1.106 printerr("Too Few Arguments");
1670     env->err= 1;
1671     return;
1672     }
1673    
1674     if(CAR(CDR(env->head))->type!=symb
1675     || strcmp(CAR(CDR(env->head))->content.sym->id, "if")!=0) {
1676     printerr("Bad Argument Type");
1677     env->err= 2;
1678     return;
1679     }
1680    
1681     swap(env); toss(env);
1682 masse 1.109 sx_6966(env);
1683 masse 1.58 }
1684    
1685 teddy 1.85 /* "while" */
1686 masse 1.95 extern void sx_7768696c65(environment *env)
1687     {
1688 masse 1.58 int truth;
1689 masse 1.63 value *loop, *test;
1690 masse 1.58
1691 teddy 1.111 if(env->head->type==empty || CDR(env->head)->type==empty) {
1692 masse 1.58 printerr("Too Few Arguments");
1693 masse 1.102 env->err= 1;
1694 masse 1.58 return;
1695     }
1696    
1697 masse 1.104 loop= CAR(env->head);
1698 masse 1.98 protect(loop);
1699 masse 1.63 toss(env); if(env->err) return;
1700    
1701 masse 1.104 test= CAR(env->head);
1702 masse 1.98 protect(test);
1703 masse 1.63 toss(env); if(env->err) return;
1704    
1705 masse 1.58 do {
1706 masse 1.72 push_val(env, test);
1707 masse 1.63 eval(env);
1708 masse 1.58
1709 masse 1.104 if(CAR(env->head)->type != integer) {
1710 masse 1.58 printerr("Bad Argument Type");
1711 masse 1.90 env->err= 2;
1712 masse 1.58 return;
1713     }
1714    
1715 masse 1.104 truth= CAR(env->head)->content.i;
1716 masse 1.58 toss(env); if(env->err) return;
1717    
1718     if(truth) {
1719 masse 1.72 push_val(env, loop);
1720 masse 1.58 eval(env);
1721     } else {
1722     toss(env);
1723     }
1724    
1725     } while(truth);
1726 masse 1.90
1727 masse 1.98 unprotect(loop); unprotect(test);
1728 teddy 1.56 }
1729 masse 1.65
1730 masse 1.89
1731     /* "for"; for-loop */
1732 masse 1.95 extern void sx_666f72(environment *env)
1733     {
1734 masse 1.89 value *loop;
1735     int foo1, foo2;
1736    
1737 teddy 1.111 if(env->head->type==empty || CDR(env->head)->type==empty
1738     || CDR(CDR(env->head))->type==empty) {
1739 masse 1.89 printerr("Too Few Arguments");
1740     env->err= 1;
1741     return;
1742     }
1743    
1744 masse 1.104 if(CAR(CDR(env->head))->type!=integer
1745     || CAR(CDR(CDR(env->head)))->type!=integer) {
1746 masse 1.89 printerr("Bad Argument Type");
1747     env->err= 2;
1748     return;
1749     }
1750    
1751 masse 1.104 loop= CAR(env->head);
1752 masse 1.98 protect(loop);
1753 masse 1.89 toss(env); if(env->err) return;
1754    
1755 masse 1.104 foo2= CAR(env->head)->content.i;
1756 masse 1.89 toss(env); if(env->err) return;
1757    
1758 masse 1.104 foo1= CAR(env->head)->content.i;
1759 masse 1.89 toss(env); if(env->err) return;
1760    
1761     if(foo1<=foo2) {
1762     while(foo1<=foo2) {
1763     push_int(env, foo1);
1764     push_val(env, loop);
1765     eval(env); if(env->err) return;
1766     foo1++;
1767     }
1768     } else {
1769     while(foo1>=foo2) {
1770     push_int(env, foo1);
1771     push_val(env, loop);
1772     eval(env); if(env->err) return;
1773     foo1--;
1774     }
1775     }
1776 masse 1.98 unprotect(loop);
1777 masse 1.89 }
1778    
1779     /* Variant of for-loop */
1780 masse 1.95 extern void foreach(environment *env)
1781     {
1782 masse 1.65 value *loop, *foo;
1783 masse 1.104 value *iterator;
1784 masse 1.65
1785 teddy 1.111 if(env->head->type==empty || CDR(env->head)->type==empty) {
1786 masse 1.65 printerr("Too Few Arguments");
1787 masse 1.90 env->err= 1;
1788 masse 1.65 return;
1789     }
1790    
1791 masse 1.104 if(CAR(CDR(env->head))->type!=tcons) {
1792 masse 1.65 printerr("Bad Argument Type");
1793 masse 1.90 env->err= 2;
1794 masse 1.65 return;
1795     }
1796    
1797 masse 1.104 loop= CAR(env->head);
1798 masse 1.98 protect(loop);
1799 masse 1.65 toss(env); if(env->err) return;
1800    
1801 masse 1.104 foo= CAR(env->head);
1802 masse 1.98 protect(foo);
1803 masse 1.65 toss(env); if(env->err) return;
1804    
1805 masse 1.104 iterator= foo;
1806 masse 1.65
1807 masse 1.122 while(iterator->type!=empty) {
1808 masse 1.104 push_val(env, CAR(iterator));
1809 masse 1.72 push_val(env, loop);
1810 masse 1.65 eval(env); if(env->err) return;
1811 masse 1.105 if (iterator->type == tcons){
1812 masse 1.104 iterator= CDR(iterator);
1813 teddy 1.103 } else {
1814     printerr("Bad Argument Type"); /* Improper list */
1815     env->err= 2;
1816     break;
1817     }
1818 masse 1.65 }
1819 masse 1.98 unprotect(loop); unprotect(foo);
1820 masse 1.65 }
1821 masse 1.66
1822 teddy 1.85 /* "to" */
1823 masse 1.95 extern void to(environment *env)
1824     {
1825     int ending, start, i;
1826 masse 1.121 value *iterator, *temp, *end;
1827    
1828     end= new_val(env);
1829 masse 1.95
1830 teddy 1.111 if(env->head->type==empty || CDR(env->head)->type==empty) {
1831 masse 1.66 printerr("Too Few Arguments");
1832 masse 1.102 env->err= 1;
1833 masse 1.66 return;
1834     }
1835    
1836 masse 1.104 if(CAR(env->head)->type!=integer
1837     || CAR(CDR(env->head))->type!=integer) {
1838 masse 1.66 printerr("Bad Argument Type");
1839 masse 1.102 env->err= 2;
1840 masse 1.66 return;
1841     }
1842    
1843 masse 1.104 ending= CAR(env->head)->content.i;
1844 masse 1.66 toss(env); if(env->err) return;
1845 masse 1.104 start= CAR(env->head)->content.i;
1846 masse 1.66 toss(env); if(env->err) return;
1847    
1848 masse 1.95 push_sym(env, "[");
1849 masse 1.66
1850 masse 1.67 if(ending>=start) {
1851 masse 1.74 for(i= ending; i>=start; i--)
1852 masse 1.72 push_int(env, i);
1853 masse 1.67 } else {
1854 masse 1.74 for(i= ending; i<=start; i++)
1855 masse 1.72 push_int(env, i);
1856 masse 1.67 }
1857 masse 1.66
1858 masse 1.95 iterator= env->head;
1859 masse 1.93
1860 teddy 1.111 if(iterator->type==empty
1861 masse 1.104 || (CAR(iterator)->type==symb
1862 masse 1.105 && CAR(iterator)->content.sym->id[0]=='[')) {
1863 masse 1.121 temp= end;
1864 masse 1.95 toss(env);
1865     } else {
1866     /* Search for first delimiter */
1867 masse 1.121 while(CDR(iterator)->type!=empty
1868 masse 1.104 && (CAR(CDR(iterator))->type!=symb
1869 masse 1.105 || CAR(CDR(iterator))->content.sym->id[0]!='['))
1870 masse 1.104 iterator= CDR(iterator);
1871 masse 1.95
1872     /* Extract list */
1873     temp= env->head;
1874 masse 1.104 env->head= CDR(iterator);
1875 masse 1.121 CDR(iterator)= end;
1876 masse 1.95
1877 masse 1.121 if(env->head->type!=empty)
1878 masse 1.95 toss(env);
1879     }
1880    
1881     /* Push list */
1882 masse 1.104 push_val(env, temp);
1883 masse 1.66 }
1884 masse 1.68
1885     /* Read a string */
1886 masse 1.95 extern void readline(environment *env)
1887     {
1888 teddy 1.124 readlinestream(env, env->inputstream);
1889     }
1890    
1891     /* Read a string from a port */
1892     extern void readlineport(environment *env)
1893     {
1894     FILE *stream;
1895    
1896     if(env->head->type==empty) {
1897     printerr("Too Few Arguments");
1898     env->err= 1;
1899     return;
1900     }
1901    
1902     if(CAR(env->head)->type!=port) {
1903     printerr("Bad Argument Type");
1904     env->err= 2;
1905     return;
1906     }
1907    
1908     stream=CAR(env->head)->content.p;
1909     readlinestream(env, stream); if(env->err) return;
1910    
1911     swap(env); if(env->err) return;
1912     toss(env);
1913     }
1914    
1915     /* read a line from a stream; used by readline */
1916     void readlinestream(environment *env, FILE *stream)
1917     {
1918 masse 1.68 char in_string[101];
1919    
1920 teddy 1.124 if(fgets(in_string, 100, stream)==NULL) {
1921 teddy 1.84 push_cstring(env, "");
1922 teddy 1.124 if (! feof(stream)){
1923     perror("readline");
1924     env->err= 5;
1925     }
1926     } else {
1927 teddy 1.84 push_cstring(env, in_string);
1928 teddy 1.124 }
1929 masse 1.68 }
1930    
1931 teddy 1.84 /* "read"; Read a value and place on stack */
1932 masse 1.95 extern void sx_72656164(environment *env)
1933     {
1934 teddy 1.124 readstream(env, env->inputstream);
1935     }
1936    
1937     /* "readport"; Read a value from a port and place on stack */
1938     extern void readport(environment *env)
1939     {
1940     FILE *stream;
1941    
1942     if(env->head->type==empty) {
1943     printerr("Too Few Arguments");
1944     env->err= 1;
1945     return;
1946     }
1947    
1948     if(CAR(env->head)->type!=port) {
1949     printerr("Bad Argument Type");
1950     env->err= 2;
1951     return;
1952     }
1953    
1954     stream=CAR(env->head)->content.p;
1955     readstream(env, stream); if(env->err) return;
1956    
1957     swap(env); if(env->err) return;
1958     toss(env);
1959     }
1960    
1961     /* read from a stream; used by "read" and "readport" */
1962     void readstream(environment *env, FILE *stream)
1963     {
1964 teddy 1.78 const char symbform[]= "%[a-zA-Z0-9!$%*+./:<=>?@^_~-]%n";
1965     const char strform[]= "\"%[^\"]\"%n";
1966     const char intform[]= "%i%n";
1967 masse 1.93 const char fltform[]= "%f%n";
1968 teddy 1.78 const char blankform[]= "%*[ \t]%n";
1969 masse 1.90 const char ebrackform[]= "]%n";
1970     const char semicform[]= ";%n";
1971     const char bbrackform[]= "[%n";
1972 masse 1.68
1973 teddy 1.78 int itemp, readlength= -1;
1974 masse 1.93 int count= -1;
1975     float ftemp;
1976 masse 1.68 static int depth= 0;
1977 teddy 1.116 char *match;
1978 masse 1.68 size_t inlength;
1979    
1980 masse 1.70 if(env->in_string==NULL) {
1981 teddy 1.84 if(depth > 0 && env->interactive) {
1982 teddy 1.80 printf("]> ");
1983     }
1984 masse 1.68 readline(env); if(env->err) return;
1985 teddy 1.84
1986 masse 1.104 if(((char *)(CAR(env->head)->content.ptr))[0]=='\0'){
1987 teddy 1.85 env->err= 4; /* "" means EOF */
1988 teddy 1.84 return;
1989     }
1990 masse 1.68
1991 masse 1.104 env->in_string= malloc(strlen(CAR(env->head)->content.ptr)+1);
1992 teddy 1.118 assert(env->in_string != NULL);
1993 teddy 1.78 env->free_string= env->in_string; /* Save the original pointer */
1994 masse 1.104 strcpy(env->in_string, CAR(env->head)->content.ptr);
1995 masse 1.68 toss(env); if(env->err) return;
1996     }
1997    
1998 masse 1.70 inlength= strlen(env->in_string)+1;
1999 masse 1.68 match= malloc(inlength);
2000 teddy 1.118 assert(match != NULL);
2001 masse 1.68
2002 masse 1.93 if(sscanf(env->in_string, blankform, &readlength) != EOF
2003 teddy 1.78 && readlength != -1) {
2004 masse 1.71 ;
2005 masse 1.93 } else if(sscanf(env->in_string, fltform, &ftemp, &readlength) != EOF
2006 teddy 1.78 && readlength != -1) {
2007 masse 1.93 if(sscanf(env->in_string, intform, &itemp, &count) != EOF
2008     && count==readlength) {
2009     push_int(env, itemp);
2010     } else {
2011     push_float(env, ftemp);
2012     }
2013 teddy 1.114 } else if(sscanf(env->in_string, "\"\"%n", &readlength) != EOF
2014     && readlength != -1) {
2015     push_cstring(env, "");
2016 teddy 1.78 } else if(sscanf(env->in_string, strform, match, &readlength) != EOF
2017     && readlength != -1) {
2018 masse 1.72 push_cstring(env, match);
2019 teddy 1.78 } else if(sscanf(env->in_string, symbform, match, &readlength) != EOF
2020     && readlength != -1) {
2021 masse 1.68 push_sym(env, match);
2022 teddy 1.78 } else if(sscanf(env->in_string, ebrackform, &readlength) != EOF
2023     && readlength != -1) {
2024 masse 1.68 pack(env); if(env->err) return;
2025 teddy 1.78 if(depth != 0) depth--;
2026     } else if(sscanf(env->in_string, semicform, &readlength) != EOF
2027     && readlength != -1) {
2028 masse 1.68 push_sym(env, ";");
2029 teddy 1.78 } else if(sscanf(env->in_string, bbrackform, &readlength) != EOF
2030     && readlength != -1) {
2031 masse 1.68 push_sym(env, "[");
2032     depth++;
2033     } else {
2034 teddy 1.78 free(env->free_string);
2035     env->in_string = env->free_string = NULL;
2036     }
2037 masse 1.93 if (env->in_string != NULL) {
2038 teddy 1.78 env->in_string += readlength;
2039 masse 1.68 }
2040 masse 1.83
2041     free(match);
2042 masse 1.68
2043 masse 1.71 if(depth)
2044 teddy 1.84 return sx_72656164(env);
2045 teddy 1.91 }
2046    
2047 masse 1.107 #ifdef __linux__
2048 masse 1.95 extern void beep(environment *env)
2049     {
2050 teddy 1.91 int freq, dur, period, ticks;
2051    
2052 teddy 1.111 if(env->head->type==empty || CDR(env->head)->type==empty) {
2053 teddy 1.91 printerr("Too Few Arguments");
2054 masse 1.102 env->err= 1;
2055 teddy 1.91 return;
2056     }
2057    
2058 masse 1.104 if(CAR(env->head)->type!=integer
2059     || CAR(CDR(env->head))->type!=integer) {
2060 teddy 1.91 printerr("Bad Argument Type");
2061 masse 1.102 env->err= 2;
2062 teddy 1.91 return;
2063     }
2064    
2065 masse 1.104 dur= CAR(env->head)->content.i;
2066 teddy 1.91 toss(env);
2067 masse 1.104 freq= CAR(env->head)->content.i;
2068 teddy 1.91 toss(env);
2069    
2070 masse 1.102 period= 1193180/freq; /* convert freq from Hz to period
2071 teddy 1.91 length */
2072 masse 1.102 ticks= dur*.001193180; /* convert duration from µseconds to
2073 teddy 1.91 timer ticks */
2074    
2075     /* ticks=dur/1000; */
2076    
2077 masse 1.102 /* if (ioctl(STDOUT_FILENO, KDMKTONE, (125<<16) + 0x637)==0) */
2078 teddy 1.91 switch (ioctl(STDOUT_FILENO, KDMKTONE, (ticks<<16) | period)){
2079     case 0:
2080     usleep(dur);
2081     return;
2082     case -1:
2083     perror("beep");
2084 masse 1.102 env->err= 5;
2085 teddy 1.91 return;
2086     default:
2087     abort();
2088     }
2089 masse 1.95 }
2090 masse 1.107 #endif /* __linux__ */
2091 teddy 1.91
2092     /* "wait" */
2093 masse 1.95 extern void sx_77616974(environment *env)
2094     {
2095 teddy 1.91 int dur;
2096    
2097 teddy 1.111 if(env->head->type==empty) {
2098 teddy 1.91 printerr("Too Few Arguments");
2099 masse 1.102 env->err= 1;
2100 teddy 1.91 return;
2101     }
2102    
2103 masse 1.104 if(CAR(env->head)->type!=integer) {
2104 teddy 1.91 printerr("Bad Argument Type");
2105 masse 1.102 env->err= 2;
2106 teddy 1.91 return;
2107     }
2108    
2109 masse 1.104 dur= CAR(env->head)->content.i;
2110 teddy 1.91 toss(env);
2111    
2112     usleep(dur);
2113 masse 1.95 }
2114 teddy 1.91
2115 masse 1.95 extern void copying(environment *env)
2116     {
2117 teddy 1.111 printf(" GNU GENERAL PUBLIC LICENSE\n\
2118 teddy 1.91 Version 2, June 1991\n\
2119     \n\
2120     Copyright (C) 1989, 1991 Free Software Foundation, Inc.\n\
2121     59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n\
2122     Everyone is permitted to copy and distribute verbatim copies\n\
2123     of this license document, but changing it is not allowed.\n\
2124     \n\
2125     Preamble\n\
2126     \n\
2127     The licenses for most software are designed to take away your\n\
2128     freedom to share and change it. By contrast, the GNU General Public\n\
2129     License is intended to guarantee your freedom to share and change free\n\
2130     software--to make sure the software is free for all its users. This\n\
2131     General Public License applies to most of the Free Software\n\
2132     Foundation's software and to any other program whose authors commit to\n\
2133     using it. (Some other Free Software Foundation software is covered by\n\
2134     the GNU Library General Public License instead.) You can apply it to\n\
2135     your programs, too.\n\
2136     \n\
2137     When we speak of free software, we are referring to freedom, not\n\
2138     price. Our General Public Licenses are designed to make sure that you\n\
2139     have the freedom to distribute copies of free software (and charge for\n\
2140     this service if you wish), that you receive source code or can get it\n\
2141     if you want it, that you can change the software or use pieces of it\n\
2142     in new free programs; and that you know you can do these things.\n\
2143     \n\
2144     To protect your rights, we need to make restrictions that forbid\n\
2145     anyone to deny you these rights or to ask you to surrender the rights.\n\
2146     These restrictions translate to certain responsibilities for you if you\n\
2147     distribute copies of the software, or if you modify it.\n\
2148     \n\
2149     For example, if you distribute copies of such a program, whether\n\
2150     gratis or for a fee, you must give the recipients all the rights that\n\
2151     you have. You must make sure that they, too, receive or can get the\n\
2152     source code. And you must show them these terms so they know their\n\
2153     rights.\n\
2154     \n\
2155     We protect your rights with two steps: (1) copyright the software, and\n\
2156     (2) offer you this license which gives you legal permission to copy,\n\
2157     distribute and/or modify the software.\n\
2158     \n\
2159     Also, for each author's protection and ours, we want to make certain\n\
2160     that everyone understands that there is no warranty for this free\n\
2161     software. If the software is modified by someone else and passed on, we\n\
2162     want its recipients to know that what they have is not the original, so\n\
2163     that any problems introduced by others will not reflect on the original\n\
2164     authors' reputations.\n\
2165     \n\
2166     Finally, any free program is threatened constantly by software\n\
2167     patents. We wish to avoid the danger that redistributors of a free\n\
2168     program will individually obtain patent licenses, in effect making the\n\
2169     program proprietary. To prevent this, we have made it clear that any\n\
2170     patent must be licensed for everyone's free use or not licensed at all.\n\
2171     \n\
2172     The precise terms and conditions for copying, distribution and\n\
2173     modification follow.\n\
2174     \n\
2175     GNU GENERAL PUBLIC LICENSE\n\
2176     TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION\n\
2177     \n\
2178     0. This License applies to any program or other work which contains\n\
2179     a notice placed by the copyright holder saying it may be distributed\n\
2180     under the terms of this General Public License. The \"Program\", below,\n\
2181     refers to any such program or work, and a \"work based on the Program\"\n\
2182     means either the Program or any derivative work under copyright law:\n\
2183     that is to say, a work containing the Program or a portion of it,\n\
2184     either verbatim or with modifications and/or translated into another\n\
2185     language. (Hereinafter, translation is included without limitation in\n\
2186     the term \"modification\".) Each licensee is addressed as \"you\".\n\
2187     \n\
2188     Activities other than copying, distribution and modification are not\n\
2189     covered by this License; they are outside its scope. The act of\n\
2190     running the Program is not restricted, and the output from the Program\n\
2191     is covered only if its contents constitute a work based on the\n\
2192     Program (independent of having been made by running the Program).\n\
2193     Whether that is true depends on what the Program does.\n\
2194     \n\
2195     1. You may copy and distribute verbatim copies of the Program's\n\
2196     source code as you receive it, in any medium, provided that you\n\
2197     conspicuously and appropriately publish on each copy an appropriate\n\
2198     copyright notice and disclaimer of warranty; keep intact all the\n\
2199     notices that refer to this License and to the absence of any warranty;\n\
2200     and give any other recipients of the Program a copy of this License\n\
2201     along with the Program.\n\
2202     \n\
2203     You may charge a fee for the physical act of transferring a copy, and\n\
2204     you may at your option offer warranty protection in exchange for a fee.\n\
2205     \n\
2206     2. You may modify your copy or copies of the Program or any portion\n\
2207     of it, thus forming a work based on the Program, and copy and\n\
2208     distribute such modifications or work under the terms of Section 1\n\
2209     above, provided that you also meet all of these conditions:\n\
2210     \n\
2211     a) You must cause the modified files to carry prominent notices\n\
2212     stating that you changed the files and the date of any change.\n\
2213     \n\
2214     b) You must cause any work that you distribute or publish, that in\n\
2215     whole or in part contains or is derived from the Program or any\n\
2216     part thereof, to be licensed as a whole at no charge to all third\n\
2217     parties under the terms of this License.\n\
2218     \n\
2219     c) If the modified program normally reads commands interactively\n\
2220     when run, you must cause it, when started running for such\n\
2221     interactive use in the most ordinary way, to print or display an\n\
2222     announcement including an appropriate copyright notice and a\n\
2223     notice that there is no warranty (or else, saying that you provide\n\
2224     a warranty) and that users may redistribute the program under\n\
2225     these conditions, and telling the user how to view a copy of this\n\
2226     License. (Exception: if the Program itself is interactive but\n\
2227     does not normally print such an announcement, your work based on\n\
2228     the Program is not required to print an announcement.)\n\
2229     \n\
2230     These requirements apply to the modified work as a whole. If\n\
2231     identifiable sections of that work are not derived from the Program,\n\
2232     and can be reasonably considered independent and separate works in\n\
2233     themselves, then this License, and its terms, do not apply to those\n\
2234     sections when you distribute them as separate works. But when you\n\
2235     distribute the same sections as part of a whole which is a work based\n\
2236     on the Program, the distribution of the whole must be on the terms of\n\
2237     this License, whose permissions for other licensees extend to the\n\
2238     entire whole, and thus to each and every part regardless of who wrote it.\n\
2239     \n\
2240     Thus, it is not the intent of this section to claim rights or contest\n\
2241     your rights to work written entirely by you; rather, the intent is to\n\
2242     exercise the right to control the distribution of derivative or\n\
2243     collective works based on the Program.\n\
2244     \n\
2245     In addition, mere aggregation of another work not based on the Program\n\
2246     with the Program (or with a work based on the Program) on a volume of\n\
2247     a storage or distribution medium does not bring the other work under\n\
2248     the scope of this License.\n\
2249     \n\
2250     3. You may copy and distribute the Program (or a work based on it,\n\
2251     under Section 2) in object code or executable form under the terms of\n\
2252     Sections 1 and 2 above provided that you also do one of the following:\n\
2253     \n\
2254     a) Accompany it with the complete corresponding machine-readable\n\
2255     source code, which must be distributed under the terms of Sections\n\
2256     1 and 2 above on a medium customarily used for software interchange; or,\n\
2257     \n\
2258     b) Accompany it with a written offer, valid for at least three\n\
2259     years, to give any third party, for a charge no more than your\n\
2260     cost of physically performing source distribution, a complete\n\
2261     machine-readable copy of the corresponding source code, to be\n\
2262     distributed under the terms of Sections 1 and 2 above on a medium\n\
2263     customarily used for software interchange; or,\n\
2264     \n\
2265     c) Accompany it with the information you received as to the offer\n\
2266     to distribute corresponding source code. (This alternative is\n\
2267     allowed only for noncommercial distribution and only if you\n\
2268     received the program in object code or executable form with such\n\
2269     an offer, in accord with Subsection b above.)\n\
2270     \n\
2271     The source code for a work means the preferred form of the work for\n\
2272     making modifications to it. For an executable work, complete source\n\
2273     code means all the source code for all modules it contains, plus any\n\
2274     associated interface definition files, plus the scripts used to\n\
2275     control compilation and installation of the executable. However, as a\n\
2276     special exception, the source code distributed need not include\n\
2277     anything that is normally distributed (in either source or binary\n\
2278     form) with the major components (compiler, kernel, and so on) of the\n\
2279     operating system on which the executable runs, unless that component\n\
2280     itself accompanies the executable.\n\
2281     \n\
2282     If distribution of executable or object code is made by offering\n\
2283     access to copy from a designated place, then offering equivalent\n\
2284     access to copy the source code from the same place counts as\n\
2285     distribution of the source code, even though third parties are not\n\
2286     compelled to copy the source along with the object code.\n\
2287     \n\
2288     4. You may not copy, modify, sublicense, or distribute the Program\n\
2289     except as expressly provided under this License. Any attempt\n\
2290     otherwise to copy, modify, sublicense or distribute the Program is\n\
2291     void, and will automatically terminate your rights under this License.\n\
2292     However, parties who have received copies, or rights, from you under\n\
2293     this License will not have their licenses terminated so long as such\n\
2294     parties remain in full compliance.\n\
2295     \n\
2296     5. You are not required to accept this License, since you have not\n\
2297     signed it. However, nothing else grants you permission to modify or\n\
2298     distribute the Program or its derivative works. These actions are\n\
2299     prohibited by law if you do not accept this License. Therefore, by\n\
2300     modifying or distributing the Program (or any work based on the\n\
2301     Program), you indicate your acceptance of this License to do so, and\n\
2302     all its terms and conditions for copying, distributing or modifying\n\
2303     the Program or works based on it.\n\
2304     \n\
2305     6. Each time you redistribute the Program (or any work based on the\n\
2306     Program), the recipient automatically receives a license from the\n\
2307     original licensor to copy, distribute or modify the Program subject to\n\
2308     these terms and conditions. You may not impose any further\n\
2309     restrictions on the recipients' exercise of the rights granted herein.\n\
2310     You are not responsible for enforcing compliance by third parties to\n\
2311     this License.\n\
2312     \n\
2313     7. If, as a consequence of a court judgment or allegation of patent\n\
2314     infringement or for any other reason (not limited to patent issues),\n\
2315     conditions are imposed on you (whether by court order, agreement or\n\
2316     otherwise) that contradict the conditions of this License, they do not\n\
2317     excuse you from the conditions of this License. If you cannot\n\
2318     distribute so as to satisfy simultaneously your obligations under this\n\
2319     License and any other pertinent obligations, then as a consequence you\n\
2320     may not distribute the Program at all. For example, if a patent\n\
2321     license would not permit royalty-free redistribution of the Program by\n\
2322     all those who receive copies directly or indirectly through you, then\n\
2323     the only way you could satisfy both it and this License would be to\n\
2324     refrain entirely from distribution of the Program.\n\
2325     \n\
2326     If any portion of this section is held invalid or unenforceable under\n\
2327     any particular circumstance, the balance of the section is intended to\n\
2328     apply and the section as a whole is intended to apply in other\n\
2329     circumstances.\n\
2330     \n\
2331     It is not the purpose of this section to induce you to infringe any\n\
2332     patents or other property right claims or to contest validity of any\n\
2333     such claims; this section has the sole purpose of protecting the\n\
2334     integrity of the free software distribution system, which is\n\
2335     implemented by public license practices. Many people have made\n\
2336     generous contributions to the wide range of software distributed\n\
2337     through that system in reliance on consistent application of that\n\
2338     system; it is up to the author/donor to decide if he or she is willing\n\
2339     to distribute software through any other system and a licensee cannot\n\
2340     impose that choice.\n\
2341     \n\
2342     This section is intended to make thoroughly clear what is believed to\n\
2343     be a consequence of the rest of this License.\n\
2344     \n\
2345     8. If the distribution and/or use of the Program is restricted in\n\
2346     certain countries either by patents or by copyrighted interfaces, the\n\
2347     original copyright holder who places the Program under this License\n\
2348     may add an explicit geographical distribution limitation excluding\n\
2349     those countries, so that distribution is permitted only in or among\n\
2350     countries not thus excluded. In such case, this License incorporates\n\
2351     the limitation as if written in the body of this License.\n\
2352     \n\
2353     9. The Free Software Foundation may publish revised and/or new versions\n\
2354     of the General Public License from time to time. Such new versions will\n\
2355     be similar in spirit to the present version, but may differ in detail to\n\
2356     address new problems or concerns.\n\
2357     \n\
2358     Each version is given a distinguishing version number. If the Program\n\
2359     specifies a version number of this License which applies to it and \"any\n\
2360     later version\", you have the option of following the terms and conditions\n\
2361     either of that version or of any later version published by the Free\n\
2362     Software Foundation. If the Program does not specify a version number of\n\
2363     this License, you may choose any version ever published by the Free Software\n\
2364     Foundation.\n\
2365     \n\
2366     10. If you wish to incorporate parts of the Program into other free\n\
2367     programs whose distribution conditions are different, write to the author\n\
2368     to ask for permission. For software which is copyrighted by the Free\n\
2369     Software Foundation, write to the Free Software Foundation; we sometimes\n\
2370     make exceptions for this. Our decision will be guided by the two goals\n\
2371     of preserving the free status of all derivatives of our free software and\n\
2372     of promoting the sharing and reuse of software generally.\n");
2373     }
2374    
2375 masse 1.95 extern void warranty(environment *env)
2376     {
2377 teddy 1.91 printf(" NO WARRANTY\n\
2378     \n\
2379     11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\n\
2380     FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN\n\
2381     OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\n\
2382     PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\n\
2383     OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n\
2384     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS\n\
2385     TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE\n\
2386     PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\n\
2387     REPAIR OR CORRECTION.\n\
2388     \n\
2389     12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\n\
2390     WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\n\
2391     REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\n\
2392     INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\n\
2393     OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\n\
2394     TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\n\
2395     YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\n\
2396     PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\n\
2397     POSSIBILITY OF SUCH DAMAGES.\n");
2398 masse 1.92 }
2399    
2400     /* "*" */
2401     extern void sx_2a(environment *env)
2402     {
2403     int a, b;
2404 masse 1.93 float fa, fb;
2405 masse 1.92
2406 teddy 1.111 if(env->head->type==empty || CDR(env->head)->type==empty) {
2407 masse 1.92 printerr("Too Few Arguments");
2408 masse 1.102 env->err= 1;
2409 masse 1.92 return;
2410     }
2411    
2412 masse 1.104 if(CAR(env->head)->type==integer
2413     && CAR(CDR(env->head))->type==integer) {
2414     a= CAR(env->head)->content.i;
2415 masse 1.93 toss(env); if(env->err) return;
2416 masse 1.104 b= CAR(env->head)->content.i;
2417 masse 1.93 toss(env); if(env->err) return;
2418     push_int(env, b*a);
2419    
2420     return;
2421     }
2422    
2423 masse 1.104 if(CAR(env->head)->type==tfloat
2424     && CAR(CDR(env->head))->type==tfloat) {
2425     fa= CAR(env->head)->content.f;
2426 masse 1.93 toss(env); if(env->err) return;
2427 masse 1.104 fb= CAR(env->head)->content.f;
2428 masse 1.93 toss(env); if(env->err) return;
2429     push_float(env, fb*fa);
2430    
2431     return;
2432     }
2433    
2434 masse 1.104 if(CAR(env->head)->type==tfloat
2435     && CAR(CDR(env->head))->type==integer) {
2436     fa= CAR(env->head)->content.f;
2437 masse 1.93 toss(env); if(env->err) return;
2438 masse 1.104 b= CAR(env->head)->content.i;
2439 masse 1.93 toss(env); if(env->err) return;
2440     push_float(env, b*fa);
2441    
2442     return;
2443     }
2444    
2445 masse 1.104 if(CAR(env->head)->type==integer
2446     && CAR(CDR(env->head))->type==tfloat) {
2447     a= CAR(env->head)->content.i;
2448 masse 1.93 toss(env); if(env->err) return;
2449 masse 1.104 fb= CAR(env->head)->content.f;
2450 masse 1.93 toss(env); if(env->err) return;
2451     push_float(env, fb*a);
2452    
2453 masse 1.92 return;
2454     }
2455    
2456 masse 1.93 printerr("Bad Argument Type");
2457 masse 1.102 env->err= 2;
2458 masse 1.92 }
2459    
2460     /* "/" */
2461     extern void sx_2f(environment *env)
2462     {
2463     int a, b;
2464 masse 1.93 float fa, fb;
2465 masse 1.92
2466 teddy 1.111 if(env->head->type==empty || CDR(env->head)->type==empty) {
2467 masse 1.92 printerr("Too Few Arguments");
2468 masse 1.102 env->err= 1;
2469 masse 1.92 return;
2470     }
2471    
2472 masse 1.104 if(CAR(env->head)->type==integer
2473     && CAR(CDR(env->head))->type==integer) {
2474     a= CAR(env->head)->content.i;
2475 masse 1.93 toss(env); if(env->err) return;
2476 masse 1.104 b= CAR(env->head)->content.i;
2477 masse 1.93 toss(env); if(env->err) return;
2478     push_float(env, b/a);
2479    
2480     return;
2481     }
2482    
2483 masse 1.104 if(CAR(env->head)->type==tfloat
2484     && CAR(CDR(env->head))->type==tfloat) {
2485     fa= CAR(env->head)->content.f;
2486 masse 1.93 toss(env); if(env->err) return;
2487 masse 1.104 fb= CAR(env->head)->content.f;
2488 masse 1.93 toss(env); if(env->err) return;
2489     push_float(env, fb/fa);
2490    
2491     return;
2492     }
2493    
2494 masse 1.104 if(CAR(env->head)->type==tfloat
2495     && CAR(CDR(env->head))->type==integer) {
2496     fa= CAR(env->head)->content.f;
2497 masse 1.93 toss(env); if(env->err) return;
2498 masse 1.104 b= CAR(env->head)->content.i;
2499 masse 1.93 toss(env); if(env->err) return;
2500     push_float(env, b/fa);
2501    
2502     return;
2503     }
2504    
2505 masse 1.104 if(CAR(env->head)->type==integer
2506     && CAR(CDR(env->head))->type==tfloat) {
2507     a= CAR(env->head)->content.i;
2508 masse 1.93 toss(env); if(env->err) return;
2509 masse 1.104 fb= CAR(env->head)->content.f;
2510 masse 1.93 toss(env); if(env->err) return;
2511     push_float(env, fb/a);
2512    
2513 masse 1.92 return;
2514     }
2515    
2516 masse 1.93 printerr("Bad Argument Type");
2517 masse 1.102 env->err= 2;
2518 masse 1.92 }
2519    
2520     /* "mod" */
2521     extern void mod(environment *env)
2522     {
2523     int a, b;
2524    
2525 teddy 1.111 if(env->head->type==empty || CDR(env->head)->type==empty) {
2526 masse 1.92 printerr("Too Few Arguments");
2527 masse 1.94 env->err= 1;
2528 masse 1.92 return;
2529     }
2530    
2531 masse 1.104 if(CAR(env->head)->type==integer
2532     && CAR(CDR(env->head))->type==integer) {
2533     a= CAR(env->head)->content.i;
2534 masse 1.93 toss(env); if(env->err) return;
2535 masse 1.104 b= CAR(env->head)->content.i;
2536 masse 1.93 toss(env); if(env->err) return;
2537     push_int(env, b%a);
2538    
2539 masse 1.92 return;
2540     }
2541    
2542 masse 1.93 printerr("Bad Argument Type");
2543 masse 1.102 env->err= 2;
2544 masse 1.94 }
2545    
2546     /* "div" */
2547     extern void sx_646976(environment *env)
2548     {
2549     int a, b;
2550    
2551 teddy 1.111 if(env->head->type==empty || CDR(env->head)->type==empty) {
2552 masse 1.94 printerr("Too Few Arguments");
2553     env->err= 1;
2554     return;
2555     }
2556    
2557 masse 1.104 if(CAR(env->head)->type==integer
2558     && CAR(CDR(env->head))->type==integer) {
2559     a= CAR(env->head)->content.i;
2560 masse 1.94 toss(env); if(env->err) return;
2561 masse 1.104 b= CAR(env->head)->content.i;
2562 masse 1.94 toss(env); if(env->err) return;
2563     push_int(env, (int)b/a);
2564    
2565     return;
2566     }
2567    
2568     printerr("Bad Argument Type");
2569     env->err= 2;
2570 teddy 1.113 }
2571    
2572     extern void setcar(environment *env)
2573     {
2574     if(env->head->type==empty || CDR(env->head)->type==empty) {
2575     printerr("Too Few Arguments");
2576     env->err= 1;
2577     return;
2578     }
2579    
2580     if(CDR(env->head)->type!=tcons) {
2581     printerr("Bad Argument Type");
2582     env->err= 2;
2583     return;
2584     }
2585    
2586     CAR(CAR(CDR(env->head)))=CAR(env->head);
2587     toss(env);
2588     }
2589    
2590     extern void setcdr(environment *env)
2591     {
2592     if(env->head->type==empty || CDR(env->head)->type==empty) {
2593     printerr("Too Few Arguments");
2594     env->err= 1;
2595     return;
2596     }
2597    
2598     if(CDR(env->head)->type!=tcons) {
2599     printerr("Bad Argument Type");
2600     env->err= 2;
2601     return;
2602     }
2603    
2604     CDR(CAR(CDR(env->head)))=CAR(env->head);
2605     toss(env);
2606     }
2607    
2608     extern void car(environment *env)
2609     {
2610     if(env->head->type==empty) {
2611     printerr("Too Few Arguments");
2612     env->err= 1;
2613     return;
2614     }
2615    
2616     if(CAR(env->head)->type!=tcons) {
2617     printerr("Bad Argument Type");
2618     env->err= 2;
2619     return;
2620     }
2621    
2622     CAR(env->head)=CAR(CAR(env->head));
2623     }
2624    
2625     extern void cdr(environment *env)
2626     {
2627     if(env->head->type==empty) {
2628     printerr("Too Few Arguments");
2629     env->err= 1;
2630     return;
2631     }
2632    
2633     if(CAR(env->head)->type!=tcons) {
2634     printerr("Bad Argument Type");
2635     env->err= 2;
2636     return;
2637     }
2638    
2639     CAR(env->head)=CDR(CAR(env->head));
2640 teddy 1.115 }
2641    
2642     extern void cons(environment *env)
2643     {
2644     value *val;
2645    
2646     if(env->head->type==empty || CDR(env->head)->type==empty) {
2647     printerr("Too Few Arguments");
2648     env->err= 1;
2649     return;
2650     }
2651    
2652     val=new_val(env);
2653     val->content.c= malloc(sizeof(pair));
2654     assert(val->content.c!=NULL);
2655 teddy 1.116
2656     env->gc_count += sizeof(pair);
2657 teddy 1.115 val->type=tcons;
2658    
2659     CAR(val)= CAR(CDR(env->head));
2660     CDR(val)= CAR(env->head);
2661    
2662     push_val(env, val);
2663    
2664     swap(env); if(env->err) return;
2665     toss(env); if(env->err) return;
2666     swap(env); if(env->err) return;
2667     toss(env); if(env->err) return;
2668 teddy 1.119 }
2669    
2670     /* 2: 3 => */
2671     /* 1: [ [ 1 . 2 ] [ 3 . 4 ] ] => 1: [ 3 . 4 ] */
2672     extern void assq(environment *env)
2673     {
2674 teddy 1.120 assocgen(env, eq);
2675     }
2676    
2677    
2678     /* General assoc function */
2679     void assocgen(environment *env, funcp eqfunc)
2680     {
2681 teddy 1.119 value *key, *item;
2682    
2683     /* Needs two values on the stack, the top one must be an association
2684     list */
2685     if(env->head->type==empty || CDR(env->head)->type==empty) {
2686     printerr("Too Few Arguments");
2687     env->err= 1;
2688     return;
2689     }
2690    
2691     if(CAR(env->head)->type!=tcons) {
2692     printerr("Bad Argument Type");
2693     env->err= 2;
2694     return;
2695     }
2696    
2697     key=CAR(CDR(env->head));
2698     item=CAR(env->head);
2699    
2700     while(item->type == tcons){
2701     if(CAR(item)->type != tcons){
2702     printerr("Bad Argument Type");
2703     env->err= 2;
2704     return;
2705     }
2706     push_val(env, key);
2707     push_val(env, CAR(CAR(item)));
2708 teddy 1.120 eqfunc(env); if(env->err) return;
2709    
2710     /* Check the result of 'eqfunc' */
2711     if(env->head->type==empty) {
2712     printerr("Too Few Arguments");
2713     env->err= 1;
2714     return;
2715     }
2716     if(CAR(env->head)->type!=integer) {
2717     printerr("Bad Argument Type");
2718     env->err= 2;
2719     return;
2720     }
2721    
2722 teddy 1.119 if(CAR(env->head)->content.i){
2723 teddy 1.120 toss(env); if(env->err) return;
2724 teddy 1.119 break;
2725     }
2726 teddy 1.120 toss(env); if(env->err) return;
2727    
2728     if(item->type!=tcons) {
2729     printerr("Bad Argument Type");
2730     env->err= 2;
2731     return;
2732     }
2733    
2734 teddy 1.119 item=CDR(item);
2735     }
2736    
2737     if(item->type == tcons){ /* A match was found */
2738     push_val(env, CAR(item));
2739     } else {
2740     push_int(env, 0);
2741     }
2742     swap(env); if(env->err) return;
2743     toss(env); if(env->err) return;
2744     swap(env); if(env->err) return;
2745     toss(env);
2746 masse 1.123 }
2747    
2748 teddy 1.124 /* "do" */
2749 masse 1.123 extern void sx_646f(environment *env)
2750     {
2751     swap(env); if(env->err) return;
2752     eval(env);
2753 teddy 1.124 }
2754    
2755     /* "open" */
2756     /* 2: "file" */
2757     /* 1: "r" => 1: #<port 0x47114711> */
2758     extern void sx_6f70656e(environment *env)
2759     {
2760     value *new_port;
2761     FILE *stream;
2762    
2763     if(env->head->type == empty || CDR(env->head)->type == empty) {
2764     printerr("Too Few Arguments");
2765     env->err=1;
2766     return;
2767     }
2768    
2769     if(CAR(env->head)->type != string
2770     || CAR(CDR(env->head))->type != string) {
2771     printerr("Bad Argument Type");
2772     env->err= 2;
2773     return;
2774     }
2775    
2776     stream=fopen(CAR(CDR(env->head))->content.ptr,
2777     CAR(env->head)->content.ptr);
2778    
2779     if(stream == NULL) {
2780     perror("open");
2781     env->err= 5;
2782     return;
2783     }
2784    
2785     new_port=new_val(env);
2786     new_port->type=port;
2787     new_port->content.p=stream;
2788    
2789     push_val(env, new_port);
2790    
2791     swap(env); if(env->err) return;
2792     toss(env); if(env->err) return;
2793     swap(env); if(env->err) return;
2794     toss(env);
2795     }
2796    
2797    
2798     /* "close" */
2799     extern void sx_636c6f7365(environment *env)
2800     {
2801     int ret;
2802    
2803     if(env->head->type == empty) {
2804     printerr("Too Few Arguments");
2805     env->err=1;
2806     return;
2807     }
2808    
2809     if(CAR(env->head)->type != port) {
2810     printerr("Bad Argument Type");
2811     env->err= 2;
2812     return;
2813     }
2814    
2815     ret= fclose(CAR(env->head)->content.p);
2816    
2817     if(ret != 0){
2818     perror("close");
2819     env->err= 5;
2820     return;
2821     }
2822    
2823     toss(env);
2824 masse 1.68 }

root@recompile.se
ViewVC Help
Powered by ViewVC 1.1.26