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

Annotation of /stack/stack.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.125 - (hide annotations)
Sun Mar 31 02:19:54 2002 UTC (22 years, 1 month ago) by teddy
Branch: MAIN
Changes since 1.124: +5 -4 lines
File MIME type: text/plain
stack.c (main): Exit on any error from "read", not just EOF.
		Loop around if the "toss" call fails.
		Don't call 'gc_init' if we already called "eval".

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.125 printf("Stack version $Revision: 1.124 $\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 teddy 1.125 if (myenv.err) { /* EOF or other error */
1288 teddy 1.110 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 teddy 1.125 toss(&myenv); if(myenv.err) continue;
1294 masse 1.69 eval(&myenv);
1295 teddy 1.125 } else {
1296     gc_maybe(&myenv);
1297 teddy 1.35 }
1298 masse 1.1 }
1299 teddy 1.41 quit(&myenv);
1300 teddy 1.42 return EXIT_FAILURE;
1301 teddy 1.48 }
1302    
1303 teddy 1.85 /* "+" */
1304 masse 1.95 extern void sx_2b(environment *env)
1305     {
1306 teddy 1.48 int a, b;
1307 masse 1.93 float fa, fb;
1308 masse 1.49 size_t len;
1309     char* new_string;
1310     value *a_val, *b_val;
1311 teddy 1.48
1312 teddy 1.111 if(env->head->type==empty || CDR(env->head)->type==empty) {
1313 teddy 1.48 printerr("Too Few Arguments");
1314 masse 1.90 env->err= 1;
1315 masse 1.49 return;
1316     }
1317    
1318 masse 1.104 if(CAR(env->head)->type==string
1319     && CAR(CDR(env->head))->type==string) {
1320     a_val= CAR(env->head);
1321     b_val= CAR(CDR(env->head));
1322 masse 1.98 protect(a_val); protect(b_val);
1323 masse 1.49 toss(env); if(env->err) return;
1324     toss(env); if(env->err) return;
1325     len= strlen(a_val->content.ptr)+strlen(b_val->content.ptr)+1;
1326     new_string= malloc(len);
1327 teddy 1.118 assert(new_string != NULL);
1328 masse 1.49 strcpy(new_string, b_val->content.ptr);
1329     strcat(new_string, a_val->content.ptr);
1330 masse 1.72 push_cstring(env, new_string);
1331 masse 1.98 unprotect(a_val); unprotect(b_val);
1332 masse 1.49 free(new_string);
1333 masse 1.93
1334 teddy 1.48 return;
1335     }
1336    
1337 masse 1.104 if(CAR(env->head)->type==integer
1338     && CAR(CDR(env->head))->type==integer) {
1339     a= CAR(env->head)->content.i;
1340 masse 1.93 toss(env); if(env->err) return;
1341 masse 1.104 b= CAR(env->head)->content.i;
1342 masse 1.93 toss(env); if(env->err) return;
1343     push_int(env, b+a);
1344    
1345     return;
1346     }
1347    
1348 masse 1.104 if(CAR(env->head)->type==tfloat
1349     && CAR(CDR(env->head))->type==tfloat) {
1350     fa= CAR(env->head)->content.f;
1351 masse 1.93 toss(env); if(env->err) return;
1352 masse 1.104 fb= CAR(env->head)->content.f;
1353 masse 1.93 toss(env); if(env->err) return;
1354     push_float(env, fb+fa);
1355    
1356     return;
1357     }
1358    
1359 masse 1.104 if(CAR(env->head)->type==tfloat
1360     && CAR(CDR(env->head))->type==integer) {
1361     fa= CAR(env->head)->content.f;
1362 masse 1.93 toss(env); if(env->err) return;
1363 masse 1.104 b= CAR(env->head)->content.i;
1364 masse 1.93 toss(env); if(env->err) return;
1365     push_float(env, b+fa);
1366    
1367     return;
1368     }
1369    
1370 masse 1.104 if(CAR(env->head)->type==integer
1371     && CAR(CDR(env->head))->type==tfloat) {
1372     a= CAR(env->head)->content.i;
1373 masse 1.93 toss(env); if(env->err) return;
1374 masse 1.104 fb= CAR(env->head)->content.f;
1375 masse 1.93 toss(env); if(env->err) return;
1376     push_float(env, fb+a);
1377    
1378 teddy 1.48 return;
1379     }
1380 masse 1.93
1381     printerr("Bad Argument Type");
1382     env->err=2;
1383 masse 1.1 }
1384 teddy 1.55
1385 teddy 1.85 /* "-" */
1386 masse 1.95 extern void sx_2d(environment *env)
1387     {
1388 teddy 1.62 int a, b;
1389 masse 1.93 float fa, fb;
1390 teddy 1.60
1391 teddy 1.111 if(env->head->type==empty || CDR(env->head)->type==empty) {
1392 teddy 1.60 printerr("Too Few Arguments");
1393     env->err=1;
1394     return;
1395     }
1396    
1397 masse 1.104 if(CAR(env->head)->type==integer
1398     && CAR(CDR(env->head))->type==integer) {
1399     a= CAR(env->head)->content.i;
1400 masse 1.93 toss(env); if(env->err) return;
1401 masse 1.104 b= CAR(env->head)->content.i;
1402 masse 1.93 toss(env); if(env->err) return;
1403     push_int(env, b-a);
1404    
1405     return;
1406     }
1407    
1408 masse 1.104 if(CAR(env->head)->type==tfloat
1409     && CAR(CDR(env->head))->type==tfloat) {
1410     fa= CAR(env->head)->content.f;
1411 masse 1.93 toss(env); if(env->err) return;
1412 masse 1.104 fb= CAR(env->head)->content.f;
1413 masse 1.93 toss(env); if(env->err) return;
1414     push_float(env, fb-fa);
1415    
1416     return;
1417     }
1418    
1419 masse 1.104 if(CAR(env->head)->type==tfloat
1420     && CAR(CDR(env->head))->type==integer) {
1421     fa= CAR(env->head)->content.f;
1422 masse 1.93 toss(env); if(env->err) return;
1423 masse 1.104 b= CAR(env->head)->content.i;
1424 masse 1.93 toss(env); if(env->err) return;
1425     push_float(env, b-fa);
1426    
1427     return;
1428     }
1429    
1430 masse 1.104 if(CAR(env->head)->type==integer
1431     && CAR(CDR(env->head))->type==tfloat) {
1432     a= CAR(env->head)->content.i;
1433 masse 1.93 toss(env); if(env->err) return;
1434 masse 1.104 fb= CAR(env->head)->content.f;
1435 masse 1.93 toss(env); if(env->err) return;
1436     push_float(env, fb-a);
1437    
1438 teddy 1.60 return;
1439     }
1440 masse 1.90
1441 masse 1.93 printerr("Bad Argument Type");
1442     env->err=2;
1443 teddy 1.60 }
1444    
1445 teddy 1.85 /* ">" */
1446 masse 1.95 extern void sx_3e(environment *env)
1447     {
1448 teddy 1.62 int a, b;
1449 masse 1.93 float fa, fb;
1450 teddy 1.61
1451 teddy 1.111 if(env->head->type==empty || CDR(env->head)->type==empty) {
1452 teddy 1.61 printerr("Too Few Arguments");
1453 masse 1.102 env->err= 1;
1454 teddy 1.61 return;
1455     }
1456    
1457 masse 1.104 if(CAR(env->head)->type==integer
1458     && CAR(CDR(env->head))->type==integer) {
1459     a= CAR(env->head)->content.i;
1460 masse 1.93 toss(env); if(env->err) return;
1461 masse 1.104 b= CAR(env->head)->content.i;
1462 masse 1.93 toss(env); if(env->err) return;
1463     push_int(env, b>a);
1464    
1465     return;
1466     }
1467    
1468 masse 1.104 if(CAR(env->head)->type==tfloat
1469     && CAR(CDR(env->head))->type==tfloat) {
1470     fa= CAR(env->head)->content.f;
1471 masse 1.93 toss(env); if(env->err) return;
1472 masse 1.104 fb= CAR(env->head)->content.f;
1473 masse 1.93 toss(env); if(env->err) return;
1474     push_int(env, fb>fa);
1475    
1476     return;
1477     }
1478    
1479 masse 1.104 if(CAR(env->head)->type==tfloat
1480     && CAR(CDR(env->head))->type==integer) {
1481     fa= CAR(env->head)->content.f;
1482 masse 1.93 toss(env); if(env->err) return;
1483 masse 1.104 b= CAR(env->head)->content.i;
1484 masse 1.93 toss(env); if(env->err) return;
1485     push_int(env, b>fa);
1486    
1487     return;
1488     }
1489    
1490 masse 1.104 if(CAR(env->head)->type==integer
1491     && CAR(CDR(env->head))->type==tfloat) {
1492     a= CAR(env->head)->content.i;
1493 masse 1.93 toss(env); if(env->err) return;
1494 masse 1.104 fb= CAR(env->head)->content.f;
1495 masse 1.93 toss(env); if(env->err) return;
1496     push_int(env, fb>a);
1497    
1498 teddy 1.61 return;
1499     }
1500 masse 1.90
1501 masse 1.93 printerr("Bad Argument Type");
1502 masse 1.104 env->err= 2;
1503 masse 1.93 }
1504    
1505     /* "<" */
1506 masse 1.95 extern void sx_3c(environment *env)
1507     {
1508 masse 1.93 swap(env); if(env->err) return;
1509     sx_3e(env);
1510     }
1511    
1512     /* "<=" */
1513 masse 1.95 extern void sx_3c3d(environment *env)
1514     {
1515 masse 1.93 sx_3e(env); if(env->err) return;
1516     not(env);
1517     }
1518    
1519     /* ">=" */
1520 masse 1.95 extern void sx_3e3d(environment *env)
1521     {
1522 masse 1.93 sx_3c(env); if(env->err) return;
1523     not(env);
1524 teddy 1.61 }
1525    
1526 teddy 1.55 /* Return copy of a value */
1527 masse 1.95 value *copy_val(environment *env, value *old_value)
1528     {
1529 masse 1.93 value *new_value;
1530 teddy 1.55
1531 masse 1.104 if(old_value==NULL)
1532     return NULL;
1533    
1534 masse 1.93 new_value= new_val(env);
1535 masse 1.90 new_value->type= old_value->type;
1536 masse 1.87
1537 teddy 1.55 switch(old_value->type){
1538 masse 1.93 case tfloat:
1539 teddy 1.55 case integer:
1540 masse 1.93 case func:
1541     case symb:
1542 teddy 1.116 case empty:
1543 teddy 1.124 case port:
1544 masse 1.93 new_value->content= old_value->content;
1545 teddy 1.55 break;
1546     case string:
1547 masse 1.90 (char *)(new_value->content.ptr)=
1548     strdup((char *)(old_value->content.ptr));
1549 teddy 1.55 break;
1550 masse 1.102 case tcons:
1551 teddy 1.55
1552 teddy 1.115 new_value->content.c= malloc(sizeof(pair));
1553 masse 1.108 assert(new_value->content.c!=NULL);
1554 teddy 1.116 env->gc_count += sizeof(pair);
1555 masse 1.108
1556 masse 1.104 CAR(new_value)= copy_val(env, CAR(old_value)); /* recurse */
1557     CDR(new_value)= copy_val(env, CDR(old_value)); /* recurse */
1558 teddy 1.55 break;
1559     }
1560 masse 1.90
1561 teddy 1.55 return new_value;
1562     }
1563    
1564 teddy 1.84 /* "dup"; duplicates an item on the stack */
1565 masse 1.95 extern void sx_647570(environment *env)
1566     {
1567 teddy 1.111 if(env->head->type==empty) {
1568 teddy 1.55 printerr("Too Few Arguments");
1569 masse 1.90 env->err= 1;
1570 teddy 1.55 return;
1571     }
1572 masse 1.104 push_val(env, copy_val(env, CAR(env->head)));
1573 teddy 1.55 }
1574 teddy 1.56
1575 teddy 1.59 /* "if", If-Then */
1576 masse 1.95 extern void sx_6966(environment *env)
1577     {
1578 teddy 1.56 int truth;
1579    
1580 teddy 1.111 if(env->head->type==empty || CDR(env->head)->type==empty) {
1581 teddy 1.56 printerr("Too Few Arguments");
1582 masse 1.90 env->err= 1;
1583 teddy 1.56 return;
1584     }
1585    
1586 masse 1.104 if(CAR(CDR(env->head))->type != integer) {
1587 teddy 1.56 printerr("Bad Argument Type");
1588 masse 1.102 env->err= 2;
1589 teddy 1.56 return;
1590     }
1591    
1592     swap(env);
1593     if(env->err) return;
1594    
1595 masse 1.104 truth= CAR(env->head)->content.i;
1596 teddy 1.56
1597     toss(env);
1598     if(env->err) return;
1599    
1600     if(truth)
1601     eval(env);
1602     else
1603     toss(env);
1604     }
1605    
1606     /* If-Then-Else */
1607 masse 1.95 extern void ifelse(environment *env)
1608     {
1609 teddy 1.56 int truth;
1610    
1611 teddy 1.111 if(env->head->type==empty || CDR(env->head)->type==empty
1612     || CDR(CDR(env->head))->type==empty) {
1613 teddy 1.56 printerr("Too Few Arguments");
1614 masse 1.102 env->err= 1;
1615 teddy 1.56 return;
1616     }
1617    
1618 masse 1.104 if(CAR(CDR(CDR(env->head)))->type!=integer) {
1619 teddy 1.56 printerr("Bad Argument Type");
1620 masse 1.102 env->err= 2;
1621 teddy 1.56 return;
1622     }
1623    
1624     rot(env);
1625     if(env->err) return;
1626    
1627 masse 1.104 truth= CAR(env->head)->content.i;
1628 teddy 1.56
1629     toss(env);
1630     if(env->err) return;
1631    
1632     if(!truth)
1633     swap(env);
1634     if(env->err) return;
1635    
1636     toss(env);
1637     if(env->err) return;
1638    
1639     eval(env);
1640 masse 1.106 }
1641    
1642 teddy 1.124 /* "else" */
1643 masse 1.106 extern void sx_656c7365(environment *env)
1644     {
1645 teddy 1.111 if(env->head->type==empty || CDR(env->head)->type==empty
1646     || CDR(CDR(env->head))->type==empty || CDR(CDR(CDR(env->head)))->type==empty
1647     || CDR(CDR(CDR(CDR(env->head))))->type==empty) {
1648 masse 1.109 printerr("Too Few Arguments");
1649     env->err= 1;
1650     return;
1651     }
1652    
1653     if(CAR(CDR(env->head))->type!=symb
1654     || strcmp(CAR(CDR(env->head))->content.sym->id, "then")!=0
1655     || CAR(CDR(CDR(CDR(env->head))))->type!=symb
1656     || strcmp(CAR(CDR(CDR(CDR(env->head))))->content.sym->id, "if")!=0) {
1657     printerr("Bad Argument Type");
1658     env->err= 2;
1659     return;
1660     }
1661    
1662     swap(env); toss(env); rot(env); toss(env);
1663     ifelse(env);
1664     }
1665    
1666     extern void then(environment *env)
1667     {
1668 teddy 1.111 if(env->head->type==empty || CDR(env->head)->type==empty
1669     || CDR(CDR(env->head))->type==empty) {
1670 masse 1.106 printerr("Too Few Arguments");
1671     env->err= 1;
1672     return;
1673     }
1674    
1675     if(CAR(CDR(env->head))->type!=symb
1676     || strcmp(CAR(CDR(env->head))->content.sym->id, "if")!=0) {
1677     printerr("Bad Argument Type");
1678     env->err= 2;
1679     return;
1680     }
1681    
1682     swap(env); toss(env);
1683 masse 1.109 sx_6966(env);
1684 masse 1.58 }
1685    
1686 teddy 1.85 /* "while" */
1687 masse 1.95 extern void sx_7768696c65(environment *env)
1688     {
1689 masse 1.58 int truth;
1690 masse 1.63 value *loop, *test;
1691 masse 1.58
1692 teddy 1.111 if(env->head->type==empty || CDR(env->head)->type==empty) {
1693 masse 1.58 printerr("Too Few Arguments");
1694 masse 1.102 env->err= 1;
1695 masse 1.58 return;
1696     }
1697    
1698 masse 1.104 loop= CAR(env->head);
1699 masse 1.98 protect(loop);
1700 masse 1.63 toss(env); if(env->err) return;
1701    
1702 masse 1.104 test= CAR(env->head);
1703 masse 1.98 protect(test);
1704 masse 1.63 toss(env); if(env->err) return;
1705    
1706 masse 1.58 do {
1707 masse 1.72 push_val(env, test);
1708 masse 1.63 eval(env);
1709 masse 1.58
1710 masse 1.104 if(CAR(env->head)->type != integer) {
1711 masse 1.58 printerr("Bad Argument Type");
1712 masse 1.90 env->err= 2;
1713 masse 1.58 return;
1714     }
1715    
1716 masse 1.104 truth= CAR(env->head)->content.i;
1717 masse 1.58 toss(env); if(env->err) return;
1718    
1719     if(truth) {
1720 masse 1.72 push_val(env, loop);
1721 masse 1.58 eval(env);
1722     } else {
1723     toss(env);
1724     }
1725    
1726     } while(truth);
1727 masse 1.90
1728 masse 1.98 unprotect(loop); unprotect(test);
1729 teddy 1.56 }
1730 masse 1.65
1731 masse 1.89
1732     /* "for"; for-loop */
1733 masse 1.95 extern void sx_666f72(environment *env)
1734     {
1735 masse 1.89 value *loop;
1736     int foo1, foo2;
1737    
1738 teddy 1.111 if(env->head->type==empty || CDR(env->head)->type==empty
1739     || CDR(CDR(env->head))->type==empty) {
1740 masse 1.89 printerr("Too Few Arguments");
1741     env->err= 1;
1742     return;
1743     }
1744    
1745 masse 1.104 if(CAR(CDR(env->head))->type!=integer
1746     || CAR(CDR(CDR(env->head)))->type!=integer) {
1747 masse 1.89 printerr("Bad Argument Type");
1748     env->err= 2;
1749     return;
1750     }
1751    
1752 masse 1.104 loop= CAR(env->head);
1753 masse 1.98 protect(loop);
1754 masse 1.89 toss(env); if(env->err) return;
1755    
1756 masse 1.104 foo2= CAR(env->head)->content.i;
1757 masse 1.89 toss(env); if(env->err) return;
1758    
1759 masse 1.104 foo1= CAR(env->head)->content.i;
1760 masse 1.89 toss(env); if(env->err) return;
1761    
1762     if(foo1<=foo2) {
1763     while(foo1<=foo2) {
1764     push_int(env, foo1);
1765     push_val(env, loop);
1766     eval(env); if(env->err) return;
1767     foo1++;
1768     }
1769     } else {
1770     while(foo1>=foo2) {
1771     push_int(env, foo1);
1772     push_val(env, loop);
1773     eval(env); if(env->err) return;
1774     foo1--;
1775     }
1776     }
1777 masse 1.98 unprotect(loop);
1778 masse 1.89 }
1779    
1780     /* Variant of for-loop */
1781 masse 1.95 extern void foreach(environment *env)
1782     {
1783 masse 1.65 value *loop, *foo;
1784 masse 1.104 value *iterator;
1785 masse 1.65
1786 teddy 1.111 if(env->head->type==empty || CDR(env->head)->type==empty) {
1787 masse 1.65 printerr("Too Few Arguments");
1788 masse 1.90 env->err= 1;
1789 masse 1.65 return;
1790     }
1791    
1792 masse 1.104 if(CAR(CDR(env->head))->type!=tcons) {
1793 masse 1.65 printerr("Bad Argument Type");
1794 masse 1.90 env->err= 2;
1795 masse 1.65 return;
1796     }
1797    
1798 masse 1.104 loop= CAR(env->head);
1799 masse 1.98 protect(loop);
1800 masse 1.65 toss(env); if(env->err) return;
1801    
1802 masse 1.104 foo= CAR(env->head);
1803 masse 1.98 protect(foo);
1804 masse 1.65 toss(env); if(env->err) return;
1805    
1806 masse 1.104 iterator= foo;
1807 masse 1.65
1808 masse 1.122 while(iterator->type!=empty) {
1809 masse 1.104 push_val(env, CAR(iterator));
1810 masse 1.72 push_val(env, loop);
1811 masse 1.65 eval(env); if(env->err) return;
1812 masse 1.105 if (iterator->type == tcons){
1813 masse 1.104 iterator= CDR(iterator);
1814 teddy 1.103 } else {
1815     printerr("Bad Argument Type"); /* Improper list */
1816     env->err= 2;
1817     break;
1818     }
1819 masse 1.65 }
1820 masse 1.98 unprotect(loop); unprotect(foo);
1821 masse 1.65 }
1822 masse 1.66
1823 teddy 1.85 /* "to" */
1824 masse 1.95 extern void to(environment *env)
1825     {
1826     int ending, start, i;
1827 masse 1.121 value *iterator, *temp, *end;
1828    
1829     end= new_val(env);
1830 masse 1.95
1831 teddy 1.111 if(env->head->type==empty || CDR(env->head)->type==empty) {
1832 masse 1.66 printerr("Too Few Arguments");
1833 masse 1.102 env->err= 1;
1834 masse 1.66 return;
1835     }
1836    
1837 masse 1.104 if(CAR(env->head)->type!=integer
1838     || CAR(CDR(env->head))->type!=integer) {
1839 masse 1.66 printerr("Bad Argument Type");
1840 masse 1.102 env->err= 2;
1841 masse 1.66 return;
1842     }
1843    
1844 masse 1.104 ending= CAR(env->head)->content.i;
1845 masse 1.66 toss(env); if(env->err) return;
1846 masse 1.104 start= CAR(env->head)->content.i;
1847 masse 1.66 toss(env); if(env->err) return;
1848    
1849 masse 1.95 push_sym(env, "[");
1850 masse 1.66
1851 masse 1.67 if(ending>=start) {
1852 masse 1.74 for(i= ending; i>=start; i--)
1853 masse 1.72 push_int(env, i);
1854 masse 1.67 } else {
1855 masse 1.74 for(i= ending; i<=start; i++)
1856 masse 1.72 push_int(env, i);
1857 masse 1.67 }
1858 masse 1.66
1859 masse 1.95 iterator= env->head;
1860 masse 1.93
1861 teddy 1.111 if(iterator->type==empty
1862 masse 1.104 || (CAR(iterator)->type==symb
1863 masse 1.105 && CAR(iterator)->content.sym->id[0]=='[')) {
1864 masse 1.121 temp= end;
1865 masse 1.95 toss(env);
1866     } else {
1867     /* Search for first delimiter */
1868 masse 1.121 while(CDR(iterator)->type!=empty
1869 masse 1.104 && (CAR(CDR(iterator))->type!=symb
1870 masse 1.105 || CAR(CDR(iterator))->content.sym->id[0]!='['))
1871 masse 1.104 iterator= CDR(iterator);
1872 masse 1.95
1873     /* Extract list */
1874     temp= env->head;
1875 masse 1.104 env->head= CDR(iterator);
1876 masse 1.121 CDR(iterator)= end;
1877 masse 1.95
1878 masse 1.121 if(env->head->type!=empty)
1879 masse 1.95 toss(env);
1880     }
1881    
1882     /* Push list */
1883 masse 1.104 push_val(env, temp);
1884 masse 1.66 }
1885 masse 1.68
1886     /* Read a string */
1887 masse 1.95 extern void readline(environment *env)
1888     {
1889 teddy 1.124 readlinestream(env, env->inputstream);
1890     }
1891    
1892     /* Read a string from a port */
1893     extern void readlineport(environment *env)
1894     {
1895     FILE *stream;
1896    
1897     if(env->head->type==empty) {
1898     printerr("Too Few Arguments");
1899     env->err= 1;
1900     return;
1901     }
1902    
1903     if(CAR(env->head)->type!=port) {
1904     printerr("Bad Argument Type");
1905     env->err= 2;
1906     return;
1907     }
1908    
1909     stream=CAR(env->head)->content.p;
1910     readlinestream(env, stream); if(env->err) return;
1911    
1912     swap(env); if(env->err) return;
1913     toss(env);
1914     }
1915    
1916     /* read a line from a stream; used by readline */
1917     void readlinestream(environment *env, FILE *stream)
1918     {
1919 masse 1.68 char in_string[101];
1920    
1921 teddy 1.124 if(fgets(in_string, 100, stream)==NULL) {
1922 teddy 1.84 push_cstring(env, "");
1923 teddy 1.124 if (! feof(stream)){
1924     perror("readline");
1925     env->err= 5;
1926     }
1927     } else {
1928 teddy 1.84 push_cstring(env, in_string);
1929 teddy 1.124 }
1930 masse 1.68 }
1931    
1932 teddy 1.84 /* "read"; Read a value and place on stack */
1933 masse 1.95 extern void sx_72656164(environment *env)
1934     {
1935 teddy 1.124 readstream(env, env->inputstream);
1936     }
1937    
1938     /* "readport"; Read a value from a port and place on stack */
1939     extern void readport(environment *env)
1940     {
1941     FILE *stream;
1942    
1943     if(env->head->type==empty) {
1944     printerr("Too Few Arguments");
1945     env->err= 1;
1946     return;
1947     }
1948    
1949     if(CAR(env->head)->type!=port) {
1950     printerr("Bad Argument Type");
1951     env->err= 2;
1952     return;
1953     }
1954    
1955     stream=CAR(env->head)->content.p;
1956     readstream(env, stream); if(env->err) return;
1957    
1958     swap(env); if(env->err) return;
1959     toss(env);
1960     }
1961    
1962     /* read from a stream; used by "read" and "readport" */
1963     void readstream(environment *env, FILE *stream)
1964     {
1965 teddy 1.78 const char symbform[]= "%[a-zA-Z0-9!$%*+./:<=>?@^_~-]%n";
1966     const char strform[]= "\"%[^\"]\"%n";
1967     const char intform[]= "%i%n";
1968 masse 1.93 const char fltform[]= "%f%n";
1969 teddy 1.78 const char blankform[]= "%*[ \t]%n";
1970 masse 1.90 const char ebrackform[]= "]%n";
1971     const char semicform[]= ";%n";
1972     const char bbrackform[]= "[%n";
1973 masse 1.68
1974 teddy 1.78 int itemp, readlength= -1;
1975 masse 1.93 int count= -1;
1976     float ftemp;
1977 masse 1.68 static int depth= 0;
1978 teddy 1.116 char *match;
1979 masse 1.68 size_t inlength;
1980    
1981 masse 1.70 if(env->in_string==NULL) {
1982 teddy 1.84 if(depth > 0 && env->interactive) {
1983 teddy 1.80 printf("]> ");
1984     }
1985 masse 1.68 readline(env); if(env->err) return;
1986 teddy 1.84
1987 masse 1.104 if(((char *)(CAR(env->head)->content.ptr))[0]=='\0'){
1988 teddy 1.85 env->err= 4; /* "" means EOF */
1989 teddy 1.84 return;
1990     }
1991 masse 1.68
1992 masse 1.104 env->in_string= malloc(strlen(CAR(env->head)->content.ptr)+1);
1993 teddy 1.118 assert(env->in_string != NULL);
1994 teddy 1.78 env->free_string= env->in_string; /* Save the original pointer */
1995 masse 1.104 strcpy(env->in_string, CAR(env->head)->content.ptr);
1996 masse 1.68 toss(env); if(env->err) return;
1997     }
1998    
1999 masse 1.70 inlength= strlen(env->in_string)+1;
2000 masse 1.68 match= malloc(inlength);
2001 teddy 1.118 assert(match != NULL);
2002 masse 1.68
2003 masse 1.93 if(sscanf(env->in_string, blankform, &readlength) != EOF
2004 teddy 1.78 && readlength != -1) {
2005 masse 1.71 ;
2006 masse 1.93 } else if(sscanf(env->in_string, fltform, &ftemp, &readlength) != EOF
2007 teddy 1.78 && readlength != -1) {
2008 masse 1.93 if(sscanf(env->in_string, intform, &itemp, &count) != EOF
2009     && count==readlength) {
2010     push_int(env, itemp);
2011     } else {
2012     push_float(env, ftemp);
2013     }
2014 teddy 1.114 } else if(sscanf(env->in_string, "\"\"%n", &readlength) != EOF
2015     && readlength != -1) {
2016     push_cstring(env, "");
2017 teddy 1.78 } else if(sscanf(env->in_string, strform, match, &readlength) != EOF
2018     && readlength != -1) {
2019 masse 1.72 push_cstring(env, match);
2020 teddy 1.78 } else if(sscanf(env->in_string, symbform, match, &readlength) != EOF
2021     && readlength != -1) {
2022 masse 1.68 push_sym(env, match);
2023 teddy 1.78 } else if(sscanf(env->in_string, ebrackform, &readlength) != EOF
2024     && readlength != -1) {
2025 masse 1.68 pack(env); if(env->err) return;
2026 teddy 1.78 if(depth != 0) depth--;
2027     } else if(sscanf(env->in_string, semicform, &readlength) != EOF
2028     && readlength != -1) {
2029 masse 1.68 push_sym(env, ";");
2030 teddy 1.78 } else if(sscanf(env->in_string, bbrackform, &readlength) != EOF
2031     && readlength != -1) {
2032 masse 1.68 push_sym(env, "[");
2033     depth++;
2034     } else {
2035 teddy 1.78 free(env->free_string);
2036     env->in_string = env->free_string = NULL;
2037     }
2038 masse 1.93 if (env->in_string != NULL) {
2039 teddy 1.78 env->in_string += readlength;
2040 masse 1.68 }
2041 masse 1.83
2042     free(match);
2043 masse 1.68
2044 masse 1.71 if(depth)
2045 teddy 1.84 return sx_72656164(env);
2046 teddy 1.91 }
2047    
2048 masse 1.107 #ifdef __linux__
2049 masse 1.95 extern void beep(environment *env)
2050     {
2051 teddy 1.91 int freq, dur, period, ticks;
2052    
2053 teddy 1.111 if(env->head->type==empty || CDR(env->head)->type==empty) {
2054 teddy 1.91 printerr("Too Few Arguments");
2055 masse 1.102 env->err= 1;
2056 teddy 1.91 return;
2057     }
2058    
2059 masse 1.104 if(CAR(env->head)->type!=integer
2060     || CAR(CDR(env->head))->type!=integer) {
2061 teddy 1.91 printerr("Bad Argument Type");
2062 masse 1.102 env->err= 2;
2063 teddy 1.91 return;
2064     }
2065    
2066 masse 1.104 dur= CAR(env->head)->content.i;
2067 teddy 1.91 toss(env);
2068 masse 1.104 freq= CAR(env->head)->content.i;
2069 teddy 1.91 toss(env);
2070    
2071 masse 1.102 period= 1193180/freq; /* convert freq from Hz to period
2072 teddy 1.91 length */
2073 masse 1.102 ticks= dur*.001193180; /* convert duration from µseconds to
2074 teddy 1.91 timer ticks */
2075    
2076     /* ticks=dur/1000; */
2077    
2078 masse 1.102 /* if (ioctl(STDOUT_FILENO, KDMKTONE, (125<<16) + 0x637)==0) */
2079 teddy 1.91 switch (ioctl(STDOUT_FILENO, KDMKTONE, (ticks<<16) | period)){
2080     case 0:
2081     usleep(dur);
2082     return;
2083     case -1:
2084     perror("beep");
2085 masse 1.102 env->err= 5;
2086 teddy 1.91 return;
2087     default:
2088     abort();
2089     }
2090 masse 1.95 }
2091 masse 1.107 #endif /* __linux__ */
2092 teddy 1.91
2093     /* "wait" */
2094 masse 1.95 extern void sx_77616974(environment *env)
2095     {
2096 teddy 1.91 int dur;
2097    
2098 teddy 1.111 if(env->head->type==empty) {
2099 teddy 1.91 printerr("Too Few Arguments");
2100 masse 1.102 env->err= 1;
2101 teddy 1.91 return;
2102     }
2103    
2104 masse 1.104 if(CAR(env->head)->type!=integer) {
2105 teddy 1.91 printerr("Bad Argument Type");
2106 masse 1.102 env->err= 2;
2107 teddy 1.91 return;
2108     }
2109    
2110 masse 1.104 dur= CAR(env->head)->content.i;
2111 teddy 1.91 toss(env);
2112    
2113     usleep(dur);
2114 masse 1.95 }
2115 teddy 1.91
2116 masse 1.95 extern void copying(environment *env)
2117     {
2118 teddy 1.111 printf(" GNU GENERAL PUBLIC LICENSE\n\
2119 teddy 1.91 Version 2, June 1991\n\
2120     \n\
2121     Copyright (C) 1989, 1991 Free Software Foundation, Inc.\n\
2122     59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n\
2123     Everyone is permitted to copy and distribute verbatim copies\n\
2124     of this license document, but changing it is not allowed.\n\
2125     \n\
2126     Preamble\n\
2127     \n\
2128     The licenses for most software are designed to take away your\n\
2129     freedom to share and change it. By contrast, the GNU General Public\n\
2130     License is intended to guarantee your freedom to share and change free\n\
2131     software--to make sure the software is free for all its users. This\n\
2132     General Public License applies to most of the Free Software\n\
2133     Foundation's software and to any other program whose authors commit to\n\
2134     using it. (Some other Free Software Foundation software is covered by\n\
2135     the GNU Library General Public License instead.) You can apply it to\n\
2136     your programs, too.\n\
2137     \n\
2138     When we speak of free software, we are referring to freedom, not\n\
2139     price. Our General Public Licenses are designed to make sure that you\n\
2140     have the freedom to distribute copies of free software (and charge for\n\
2141     this service if you wish), that you receive source code or can get it\n\
2142     if you want it, that you can change the software or use pieces of it\n\
2143     in new free programs; and that you know you can do these things.\n\
2144     \n\
2145     To protect your rights, we need to make restrictions that forbid\n\
2146     anyone to deny you these rights or to ask you to surrender the rights.\n\
2147     These restrictions translate to certain responsibilities for you if you\n\
2148     distribute copies of the software, or if you modify it.\n\
2149     \n\
2150     For example, if you distribute copies of such a program, whether\n\
2151     gratis or for a fee, you must give the recipients all the rights that\n\
2152     you have. You must make sure that they, too, receive or can get the\n\
2153     source code. And you must show them these terms so they know their\n\
2154     rights.\n\
2155     \n\
2156     We protect your rights with two steps: (1) copyright the software, and\n\
2157     (2) offer you this license which gives you legal permission to copy,\n\
2158     distribute and/or modify the software.\n\
2159     \n\
2160     Also, for each author's protection and ours, we want to make certain\n\
2161     that everyone understands that there is no warranty for this free\n\
2162     software. If the software is modified by someone else and passed on, we\n\
2163     want its recipients to know that what they have is not the original, so\n\
2164     that any problems introduced by others will not reflect on the original\n\
2165     authors' reputations.\n\
2166     \n\
2167     Finally, any free program is threatened constantly by software\n\
2168     patents. We wish to avoid the danger that redistributors of a free\n\
2169     program will individually obtain patent licenses, in effect making the\n\
2170     program proprietary. To prevent this, we have made it clear that any\n\
2171     patent must be licensed for everyone's free use or not licensed at all.\n\
2172     \n\
2173     The precise terms and conditions for copying, distribution and\n\
2174     modification follow.\n\
2175     \n\
2176     GNU GENERAL PUBLIC LICENSE\n\
2177     TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION\n\
2178     \n\
2179     0. This License applies to any program or other work which contains\n\
2180     a notice placed by the copyright holder saying it may be distributed\n\
2181     under the terms of this General Public License. The \"Program\", below,\n\
2182     refers to any such program or work, and a \"work based on the Program\"\n\
2183     means either the Program or any derivative work under copyright law:\n\
2184     that is to say, a work containing the Program or a portion of it,\n\
2185     either verbatim or with modifications and/or translated into another\n\
2186     language. (Hereinafter, translation is included without limitation in\n\
2187     the term \"modification\".) Each licensee is addressed as \"you\".\n\
2188     \n\
2189     Activities other than copying, distribution and modification are not\n\
2190     covered by this License; they are outside its scope. The act of\n\
2191     running the Program is not restricted, and the output from the Program\n\
2192     is covered only if its contents constitute a work based on the\n\
2193     Program (independent of having been made by running the Program).\n\
2194     Whether that is true depends on what the Program does.\n\
2195     \n\
2196     1. You may copy and distribute verbatim copies of the Program's\n\
2197     source code as you receive it, in any medium, provided that you\n\
2198     conspicuously and appropriately publish on each copy an appropriate\n\
2199     copyright notice and disclaimer of warranty; keep intact all the\n\
2200     notices that refer to this License and to the absence of any warranty;\n\
2201     and give any other recipients of the Program a copy of this License\n\
2202     along with the Program.\n\
2203     \n\
2204     You may charge a fee for the physical act of transferring a copy, and\n\
2205     you may at your option offer warranty protection in exchange for a fee.\n\
2206     \n\
2207     2. You may modify your copy or copies of the Program or any portion\n\
2208     of it, thus forming a work based on the Program, and copy and\n\
2209     distribute such modifications or work under the terms of Section 1\n\
2210     above, provided that you also meet all of these conditions:\n\
2211     \n\
2212     a) You must cause the modified files to carry prominent notices\n\
2213     stating that you changed the files and the date of any change.\n\
2214     \n\
2215     b) You must cause any work that you distribute or publish, that in\n\
2216     whole or in part contains or is derived from the Program or any\n\
2217     part thereof, to be licensed as a whole at no charge to all third\n\
2218     parties under the terms of this License.\n\
2219     \n\
2220     c) If the modified program normally reads commands interactively\n\
2221     when run, you must cause it, when started running for such\n\
2222     interactive use in the most ordinary way, to print or display an\n\
2223     announcement including an appropriate copyright notice and a\n\
2224     notice that there is no warranty (or else, saying that you provide\n\
2225     a warranty) and that users may redistribute the program under\n\
2226     these conditions, and telling the user how to view a copy of this\n\
2227     License. (Exception: if the Program itself is interactive but\n\
2228     does not normally print such an announcement, your work based on\n\
2229     the Program is not required to print an announcement.)\n\
2230     \n\
2231     These requirements apply to the modified work as a whole. If\n\
2232     identifiable sections of that work are not derived from the Program,\n\
2233     and can be reasonably considered independent and separate works in\n\
2234     themselves, then this License, and its terms, do not apply to those\n\
2235     sections when you distribute them as separate works. But when you\n\
2236     distribute the same sections as part of a whole which is a work based\n\
2237     on the Program, the distribution of the whole must be on the terms of\n\
2238     this License, whose permissions for other licensees extend to the\n\
2239     entire whole, and thus to each and every part regardless of who wrote it.\n\
2240     \n\
2241     Thus, it is not the intent of this section to claim rights or contest\n\
2242     your rights to work written entirely by you; rather, the intent is to\n\
2243     exercise the right to control the distribution of derivative or\n\
2244     collective works based on the Program.\n\
2245     \n\
2246     In addition, mere aggregation of another work not based on the Program\n\
2247     with the Program (or with a work based on the Program) on a volume of\n\
2248     a storage or distribution medium does not bring the other work under\n\
2249     the scope of this License.\n\
2250     \n\
2251     3. You may copy and distribute the Program (or a work based on it,\n\
2252     under Section 2) in object code or executable form under the terms of\n\
2253     Sections 1 and 2 above provided that you also do one of the following:\n\
2254     \n\
2255     a) Accompany it with the complete corresponding machine-readable\n\
2256     source code, which must be distributed under the terms of Sections\n\
2257     1 and 2 above on a medium customarily used for software interchange; or,\n\
2258     \n\
2259     b) Accompany it with a written offer, valid for at least three\n\
2260     years, to give any third party, for a charge no more than your\n\
2261     cost of physically performing source distribution, a complete\n\
2262     machine-readable copy of the corresponding source code, to be\n\
2263     distributed under the terms of Sections 1 and 2 above on a medium\n\
2264     customarily used for software interchange; or,\n\
2265     \n\
2266     c) Accompany it with the information you received as to the offer\n\
2267     to distribute corresponding source code. (This alternative is\n\
2268     allowed only for noncommercial distribution and only if you\n\
2269     received the program in object code or executable form with such\n\
2270     an offer, in accord with Subsection b above.)\n\
2271     \n\
2272     The source code for a work means the preferred form of the work for\n\
2273     making modifications to it. For an executable work, complete source\n\
2274     code means all the source code for all modules it contains, plus any\n\
2275     associated interface definition files, plus the scripts used to\n\
2276     control compilation and installation of the executable. However, as a\n\
2277     special exception, the source code distributed need not include\n\
2278     anything that is normally distributed (in either source or binary\n\
2279     form) with the major components (compiler, kernel, and so on) of the\n\
2280     operating system on which the executable runs, unless that component\n\
2281     itself accompanies the executable.\n\
2282     \n\
2283     If distribution of executable or object code is made by offering\n\
2284     access to copy from a designated place, then offering equivalent\n\
2285     access to copy the source code from the same place counts as\n\
2286     distribution of the source code, even though third parties are not\n\
2287     compelled to copy the source along with the object code.\n\
2288     \n\
2289     4. You may not copy, modify, sublicense, or distribute the Program\n\
2290     except as expressly provided under this License. Any attempt\n\
2291     otherwise to copy, modify, sublicense or distribute the Program is\n\
2292     void, and will automatically terminate your rights under this License.\n\
2293     However, parties who have received copies, or rights, from you under\n\
2294     this License will not have their licenses terminated so long as such\n\
2295     parties remain in full compliance.\n\
2296     \n\
2297     5. You are not required to accept this License, since you have not\n\
2298     signed it. However, nothing else grants you permission to modify or\n\
2299     distribute the Program or its derivative works. These actions are\n\
2300     prohibited by law if you do not accept this License. Therefore, by\n\
2301     modifying or distributing the Program (or any work based on the\n\
2302     Program), you indicate your acceptance of this License to do so, and\n\
2303     all its terms and conditions for copying, distributing or modifying\n\
2304     the Program or works based on it.\n\
2305     \n\
2306     6. Each time you redistribute the Program (or any work based on the\n\
2307     Program), the recipient automatically receives a license from the\n\
2308     original licensor to copy, distribute or modify the Program subject to\n\
2309     these terms and conditions. You may not impose any further\n\
2310     restrictions on the recipients' exercise of the rights granted herein.\n\
2311     You are not responsible for enforcing compliance by third parties to\n\
2312     this License.\n\
2313     \n\
2314     7. If, as a consequence of a court judgment or allegation of patent\n\
2315     infringement or for any other reason (not limited to patent issues),\n\
2316     conditions are imposed on you (whether by court order, agreement or\n\
2317     otherwise) that contradict the conditions of this License, they do not\n\
2318     excuse you from the conditions of this License. If you cannot\n\
2319     distribute so as to satisfy simultaneously your obligations under this\n\
2320     License and any other pertinent obligations, then as a consequence you\n\
2321     may not distribute the Program at all. For example, if a patent\n\
2322     license would not permit royalty-free redistribution of the Program by\n\
2323     all those who receive copies directly or indirectly through you, then\n\
2324     the only way you could satisfy both it and this License would be to\n\
2325     refrain entirely from distribution of the Program.\n\
2326     \n\
2327     If any portion of this section is held invalid or unenforceable under\n\
2328     any particular circumstance, the balance of the section is intended to\n\
2329     apply and the section as a whole is intended to apply in other\n\
2330     circumstances.\n\
2331     \n\
2332     It is not the purpose of this section to induce you to infringe any\n\
2333     patents or other property right claims or to contest validity of any\n\
2334     such claims; this section has the sole purpose of protecting the\n\
2335     integrity of the free software distribution system, which is\n\
2336     implemented by public license practices. Many people have made\n\
2337     generous contributions to the wide range of software distributed\n\
2338     through that system in reliance on consistent application of that\n\
2339     system; it is up to the author/donor to decide if he or she is willing\n\
2340     to distribute software through any other system and a licensee cannot\n\
2341     impose that choice.\n\
2342     \n\
2343     This section is intended to make thoroughly clear what is believed to\n\
2344     be a consequence of the rest of this License.\n\
2345     \n\
2346     8. If the distribution and/or use of the Program is restricted in\n\
2347     certain countries either by patents or by copyrighted interfaces, the\n\
2348     original copyright holder who places the Program under this License\n\
2349     may add an explicit geographical distribution limitation excluding\n\
2350     those countries, so that distribution is permitted only in or among\n\
2351     countries not thus excluded. In such case, this License incorporates\n\
2352     the limitation as if written in the body of this License.\n\
2353     \n\
2354     9. The Free Software Foundation may publish revised and/or new versions\n\
2355     of the General Public License from time to time. Such new versions will\n\
2356     be similar in spirit to the present version, but may differ in detail to\n\
2357     address new problems or concerns.\n\
2358     \n\
2359     Each version is given a distinguishing version number. If the Program\n\
2360     specifies a version number of this License which applies to it and \"any\n\
2361     later version\", you have the option of following the terms and conditions\n\
2362     either of that version or of any later version published by the Free\n\
2363     Software Foundation. If the Program does not specify a version number of\n\
2364     this License, you may choose any version ever published by the Free Software\n\
2365     Foundation.\n\
2366     \n\
2367     10. If you wish to incorporate parts of the Program into other free\n\
2368     programs whose distribution conditions are different, write to the author\n\
2369     to ask for permission. For software which is copyrighted by the Free\n\
2370     Software Foundation, write to the Free Software Foundation; we sometimes\n\
2371     make exceptions for this. Our decision will be guided by the two goals\n\
2372     of preserving the free status of all derivatives of our free software and\n\
2373     of promoting the sharing and reuse of software generally.\n");
2374     }
2375    
2376 masse 1.95 extern void warranty(environment *env)
2377     {
2378 teddy 1.91 printf(" NO WARRANTY\n\
2379     \n\
2380     11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\n\
2381     FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN\n\
2382     OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\n\
2383     PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\n\
2384     OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n\
2385     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS\n\
2386     TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE\n\
2387     PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\n\
2388     REPAIR OR CORRECTION.\n\
2389     \n\
2390     12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\n\
2391     WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\n\
2392     REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\n\
2393     INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\n\
2394     OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\n\
2395     TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\n\
2396     YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\n\
2397     PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\n\
2398     POSSIBILITY OF SUCH DAMAGES.\n");
2399 masse 1.92 }
2400    
2401     /* "*" */
2402     extern void sx_2a(environment *env)
2403     {
2404     int a, b;
2405 masse 1.93 float fa, fb;
2406 masse 1.92
2407 teddy 1.111 if(env->head->type==empty || CDR(env->head)->type==empty) {
2408 masse 1.92 printerr("Too Few Arguments");
2409 masse 1.102 env->err= 1;
2410 masse 1.92 return;
2411     }
2412    
2413 masse 1.104 if(CAR(env->head)->type==integer
2414     && CAR(CDR(env->head))->type==integer) {
2415     a= CAR(env->head)->content.i;
2416 masse 1.93 toss(env); if(env->err) return;
2417 masse 1.104 b= CAR(env->head)->content.i;
2418 masse 1.93 toss(env); if(env->err) return;
2419     push_int(env, b*a);
2420    
2421     return;
2422     }
2423    
2424 masse 1.104 if(CAR(env->head)->type==tfloat
2425     && CAR(CDR(env->head))->type==tfloat) {
2426     fa= CAR(env->head)->content.f;
2427 masse 1.93 toss(env); if(env->err) return;
2428 masse 1.104 fb= CAR(env->head)->content.f;
2429 masse 1.93 toss(env); if(env->err) return;
2430     push_float(env, fb*fa);
2431    
2432     return;
2433     }
2434    
2435 masse 1.104 if(CAR(env->head)->type==tfloat
2436     && CAR(CDR(env->head))->type==integer) {
2437     fa= CAR(env->head)->content.f;
2438 masse 1.93 toss(env); if(env->err) return;
2439 masse 1.104 b= CAR(env->head)->content.i;
2440 masse 1.93 toss(env); if(env->err) return;
2441     push_float(env, b*fa);
2442    
2443     return;
2444     }
2445    
2446 masse 1.104 if(CAR(env->head)->type==integer
2447     && CAR(CDR(env->head))->type==tfloat) {
2448     a= CAR(env->head)->content.i;
2449 masse 1.93 toss(env); if(env->err) return;
2450 masse 1.104 fb= CAR(env->head)->content.f;
2451 masse 1.93 toss(env); if(env->err) return;
2452     push_float(env, fb*a);
2453    
2454 masse 1.92 return;
2455     }
2456    
2457 masse 1.93 printerr("Bad Argument Type");
2458 masse 1.102 env->err= 2;
2459 masse 1.92 }
2460    
2461     /* "/" */
2462     extern void sx_2f(environment *env)
2463     {
2464     int a, b;
2465 masse 1.93 float fa, fb;
2466 masse 1.92
2467 teddy 1.111 if(env->head->type==empty || CDR(env->head)->type==empty) {
2468 masse 1.92 printerr("Too Few Arguments");
2469 masse 1.102 env->err= 1;
2470 masse 1.92 return;
2471     }
2472    
2473 masse 1.104 if(CAR(env->head)->type==integer
2474     && CAR(CDR(env->head))->type==integer) {
2475     a= CAR(env->head)->content.i;
2476 masse 1.93 toss(env); if(env->err) return;
2477 masse 1.104 b= CAR(env->head)->content.i;
2478 masse 1.93 toss(env); if(env->err) return;
2479     push_float(env, b/a);
2480    
2481     return;
2482     }
2483    
2484 masse 1.104 if(CAR(env->head)->type==tfloat
2485     && CAR(CDR(env->head))->type==tfloat) {
2486     fa= CAR(env->head)->content.f;
2487 masse 1.93 toss(env); if(env->err) return;
2488 masse 1.104 fb= CAR(env->head)->content.f;
2489 masse 1.93 toss(env); if(env->err) return;
2490     push_float(env, fb/fa);
2491    
2492     return;
2493     }
2494    
2495 masse 1.104 if(CAR(env->head)->type==tfloat
2496     && CAR(CDR(env->head))->type==integer) {
2497     fa= CAR(env->head)->content.f;
2498 masse 1.93 toss(env); if(env->err) return;
2499 masse 1.104 b= CAR(env->head)->content.i;
2500 masse 1.93 toss(env); if(env->err) return;
2501     push_float(env, b/fa);
2502    
2503     return;
2504     }
2505    
2506 masse 1.104 if(CAR(env->head)->type==integer
2507     && CAR(CDR(env->head))->type==tfloat) {
2508     a= CAR(env->head)->content.i;
2509 masse 1.93 toss(env); if(env->err) return;
2510 masse 1.104 fb= CAR(env->head)->content.f;
2511 masse 1.93 toss(env); if(env->err) return;
2512     push_float(env, fb/a);
2513    
2514 masse 1.92 return;
2515     }
2516    
2517 masse 1.93 printerr("Bad Argument Type");
2518 masse 1.102 env->err= 2;
2519 masse 1.92 }
2520    
2521     /* "mod" */
2522     extern void mod(environment *env)
2523     {
2524     int a, b;
2525    
2526 teddy 1.111 if(env->head->type==empty || CDR(env->head)->type==empty) {
2527 masse 1.92 printerr("Too Few Arguments");
2528 masse 1.94 env->err= 1;
2529 masse 1.92 return;
2530     }
2531    
2532 masse 1.104 if(CAR(env->head)->type==integer
2533     && CAR(CDR(env->head))->type==integer) {
2534     a= CAR(env->head)->content.i;
2535 masse 1.93 toss(env); if(env->err) return;
2536 masse 1.104 b= CAR(env->head)->content.i;
2537 masse 1.93 toss(env); if(env->err) return;
2538     push_int(env, b%a);
2539    
2540 masse 1.92 return;
2541     }
2542    
2543 masse 1.93 printerr("Bad Argument Type");
2544 masse 1.102 env->err= 2;
2545 masse 1.94 }
2546    
2547     /* "div" */
2548     extern void sx_646976(environment *env)
2549     {
2550     int a, b;
2551    
2552 teddy 1.111 if(env->head->type==empty || CDR(env->head)->type==empty) {
2553 masse 1.94 printerr("Too Few Arguments");
2554     env->err= 1;
2555     return;
2556     }
2557    
2558 masse 1.104 if(CAR(env->head)->type==integer
2559     && CAR(CDR(env->head))->type==integer) {
2560     a= CAR(env->head)->content.i;
2561 masse 1.94 toss(env); if(env->err) return;
2562 masse 1.104 b= CAR(env->head)->content.i;
2563 masse 1.94 toss(env); if(env->err) return;
2564     push_int(env, (int)b/a);
2565    
2566     return;
2567     }
2568    
2569     printerr("Bad Argument Type");
2570     env->err= 2;
2571 teddy 1.113 }
2572    
2573     extern void setcar(environment *env)
2574     {
2575     if(env->head->type==empty || CDR(env->head)->type==empty) {
2576     printerr("Too Few Arguments");
2577     env->err= 1;
2578     return;
2579     }
2580    
2581     if(CDR(env->head)->type!=tcons) {
2582     printerr("Bad Argument Type");
2583     env->err= 2;
2584     return;
2585     }
2586    
2587     CAR(CAR(CDR(env->head)))=CAR(env->head);
2588     toss(env);
2589     }
2590    
2591     extern void setcdr(environment *env)
2592     {
2593     if(env->head->type==empty || CDR(env->head)->type==empty) {
2594     printerr("Too Few Arguments");
2595     env->err= 1;
2596     return;
2597     }
2598    
2599     if(CDR(env->head)->type!=tcons) {
2600     printerr("Bad Argument Type");
2601     env->err= 2;
2602     return;
2603     }
2604    
2605     CDR(CAR(CDR(env->head)))=CAR(env->head);
2606     toss(env);
2607     }
2608    
2609     extern void car(environment *env)
2610     {
2611     if(env->head->type==empty) {
2612     printerr("Too Few Arguments");
2613     env->err= 1;
2614     return;
2615     }
2616    
2617     if(CAR(env->head)->type!=tcons) {
2618     printerr("Bad Argument Type");
2619     env->err= 2;
2620     return;
2621     }
2622    
2623     CAR(env->head)=CAR(CAR(env->head));
2624     }
2625    
2626     extern void cdr(environment *env)
2627     {
2628     if(env->head->type==empty) {
2629     printerr("Too Few Arguments");
2630     env->err= 1;
2631     return;
2632     }
2633    
2634     if(CAR(env->head)->type!=tcons) {
2635     printerr("Bad Argument Type");
2636     env->err= 2;
2637     return;
2638     }
2639    
2640     CAR(env->head)=CDR(CAR(env->head));
2641 teddy 1.115 }
2642    
2643     extern void cons(environment *env)
2644     {
2645     value *val;
2646    
2647     if(env->head->type==empty || CDR(env->head)->type==empty) {
2648     printerr("Too Few Arguments");
2649     env->err= 1;
2650     return;
2651     }
2652    
2653     val=new_val(env);
2654     val->content.c= malloc(sizeof(pair));
2655     assert(val->content.c!=NULL);
2656 teddy 1.116
2657     env->gc_count += sizeof(pair);
2658 teddy 1.115 val->type=tcons;
2659    
2660     CAR(val)= CAR(CDR(env->head));
2661     CDR(val)= CAR(env->head);
2662    
2663     push_val(env, val);
2664    
2665     swap(env); if(env->err) return;
2666     toss(env); if(env->err) return;
2667     swap(env); if(env->err) return;
2668     toss(env); if(env->err) return;
2669 teddy 1.119 }
2670    
2671     /* 2: 3 => */
2672     /* 1: [ [ 1 . 2 ] [ 3 . 4 ] ] => 1: [ 3 . 4 ] */
2673     extern void assq(environment *env)
2674     {
2675 teddy 1.120 assocgen(env, eq);
2676     }
2677    
2678    
2679     /* General assoc function */
2680     void assocgen(environment *env, funcp eqfunc)
2681     {
2682 teddy 1.119 value *key, *item;
2683    
2684     /* Needs two values on the stack, the top one must be an association
2685     list */
2686     if(env->head->type==empty || CDR(env->head)->type==empty) {
2687     printerr("Too Few Arguments");
2688     env->err= 1;
2689     return;
2690     }
2691    
2692     if(CAR(env->head)->type!=tcons) {
2693     printerr("Bad Argument Type");
2694     env->err= 2;
2695     return;
2696     }
2697    
2698     key=CAR(CDR(env->head));
2699     item=CAR(env->head);
2700    
2701     while(item->type == tcons){
2702     if(CAR(item)->type != tcons){
2703     printerr("Bad Argument Type");
2704     env->err= 2;
2705     return;
2706     }
2707     push_val(env, key);
2708     push_val(env, CAR(CAR(item)));
2709 teddy 1.120 eqfunc(env); if(env->err) return;
2710    
2711     /* Check the result of 'eqfunc' */
2712     if(env->head->type==empty) {
2713     printerr("Too Few Arguments");
2714     env->err= 1;
2715     return;
2716     }
2717     if(CAR(env->head)->type!=integer) {
2718     printerr("Bad Argument Type");
2719     env->err= 2;
2720     return;
2721     }
2722    
2723 teddy 1.119 if(CAR(env->head)->content.i){
2724 teddy 1.120 toss(env); if(env->err) return;
2725 teddy 1.119 break;
2726     }
2727 teddy 1.120 toss(env); if(env->err) return;
2728    
2729     if(item->type!=tcons) {
2730     printerr("Bad Argument Type");
2731     env->err= 2;
2732     return;
2733     }
2734    
2735 teddy 1.119 item=CDR(item);
2736     }
2737    
2738     if(item->type == tcons){ /* A match was found */
2739     push_val(env, CAR(item));
2740     } else {
2741     push_int(env, 0);
2742     }
2743     swap(env); if(env->err) return;
2744     toss(env); if(env->err) return;
2745     swap(env); if(env->err) return;
2746     toss(env);
2747 masse 1.123 }
2748    
2749 teddy 1.124 /* "do" */
2750 masse 1.123 extern void sx_646f(environment *env)
2751     {
2752     swap(env); if(env->err) return;
2753     eval(env);
2754 teddy 1.124 }
2755    
2756     /* "open" */
2757     /* 2: "file" */
2758     /* 1: "r" => 1: #<port 0x47114711> */
2759     extern void sx_6f70656e(environment *env)
2760     {
2761     value *new_port;
2762     FILE *stream;
2763    
2764     if(env->head->type == empty || CDR(env->head)->type == empty) {
2765     printerr("Too Few Arguments");
2766     env->err=1;
2767     return;
2768     }
2769    
2770     if(CAR(env->head)->type != string
2771     || CAR(CDR(env->head))->type != string) {
2772     printerr("Bad Argument Type");
2773     env->err= 2;
2774     return;
2775     }
2776    
2777     stream=fopen(CAR(CDR(env->head))->content.ptr,
2778     CAR(env->head)->content.ptr);
2779    
2780     if(stream == NULL) {
2781     perror("open");
2782     env->err= 5;
2783     return;
2784     }
2785    
2786     new_port=new_val(env);
2787     new_port->type=port;
2788     new_port->content.p=stream;
2789    
2790     push_val(env, new_port);
2791    
2792     swap(env); if(env->err) return;
2793     toss(env); if(env->err) return;
2794     swap(env); if(env->err) return;
2795     toss(env);
2796     }
2797    
2798    
2799     /* "close" */
2800     extern void sx_636c6f7365(environment *env)
2801     {
2802     int ret;
2803    
2804     if(env->head->type == empty) {
2805     printerr("Too Few Arguments");
2806     env->err=1;
2807     return;
2808     }
2809    
2810     if(CAR(env->head)->type != port) {
2811     printerr("Bad Argument Type");
2812     env->err= 2;
2813     return;
2814     }
2815    
2816     ret= fclose(CAR(env->head)->content.p);
2817    
2818     if(ret != 0){
2819     perror("close");
2820     env->err= 5;
2821     return;
2822     }
2823    
2824     toss(env);
2825 masse 1.68 }

root@recompile.se
ViewVC Help
Powered by ViewVC 1.1.26