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

Annotation of /stack/stack.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.110 - (hide annotations)
Sat Mar 16 09:12:39 2002 UTC (22 years, 1 month ago) by teddy
Branch: MAIN
Changes since 1.109: +46 -15 lines
File MIME type: text/plain
stack.c (gc_init): Extra optional debugging output.
(rcl): Don't call protect(), no need for it if we don't toss the value.
(eval): Don't crash on lists with exactly one element.
(quit): Print all defined words (hopefully none) just before quitting.
(words): Extra optional debugging output.
(main): Changed ` to ' where appropriate.
	On EOF, reset error flag before calling "quit".

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

root@recompile.se
ViewVC Help
Powered by ViewVC 1.1.26