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

Annotation of /stack/stack.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.105 - (hide annotations)
Tue Mar 12 14:53:19 2002 UTC (22 years, 1 month ago) by masse
Branch: MAIN
Changes since 1.104: +12 -13 lines
File MIME type: text/plain
stack.h:
(value->content.sym): New entry in content union. All callers changed.

stack.c:
(foreach): Bugfix.

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

root@recompile.se
ViewVC Help
Powered by ViewVC 1.1.26