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

Annotation of /stack/stack.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.117 - (hide annotations)
Wed Mar 20 05:29:29 2002 UTC (22 years, 1 month ago) by teddy
Branch: MAIN
Changes since 1.116: +50 -15 lines
File MIME type: text/plain
stack.h: Reordered to match the order in "stack.c".
(print_h): Renamed to "print_val" and added an argument.
(setcar, setcdr, car, cdr, cons): Added declarations.

stack.c (CAR, CDR): Added more parentheses.
(new_val): All new values are the empty list.  All callers changed.
(print_val): Print circular lists correctly by searching a stack which
	     is passed recursively as a new argument.  All callers
	     changed.

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

root@recompile.se
ViewVC Help
Powered by ViewVC 1.1.26