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

Annotation of /stack/stack.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.112 - (hide annotations)
Sat Mar 16 20:09:51 2002 UTC (22 years, 1 month ago) by teddy
Branch: MAIN
Changes since 1.111: +21 -11 lines
File MIME type: text/plain
stack.c (type): Eliminated unnecessary variable "typenum".
		Detect type of empty list value.
		Bugfix: Toss the *value*, not the *result*...
(print_h): Print empty list value correctly.

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

root@recompile.se
ViewVC Help
Powered by ViewVC 1.1.26