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

Annotation of /stack/stack.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.118 - (hide annotations)
Wed Mar 20 13:20:29 2002 UTC (22 years, 1 month ago) by teddy
Branch: MAIN
Changes since 1.117: +12 -1 lines
File MIME type: text/plain
stack.c: Added a call to assert() after every malloc().

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

root@recompile.se
ViewVC Help
Powered by ViewVC 1.1.26