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

Annotation of /stack/stack.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.114 - (hide annotations)
Sun Mar 17 02:15:01 2002 UTC (22 years, 1 month ago) by teddy
Branch: MAIN
Changes since 1.113: +9 -6 lines
File MIME type: text/plain
stack.c (gc_init): Bugfix: Calculate strings' memory usage correctly.
(print_val): Inconsequential rewrite.
(sx_72656164 "read"): Bugfix: Extra case for empty strings.

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

root@recompile.se
ViewVC Help
Powered by ViewVC 1.1.26