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

Annotation of /stack/stack.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.103 - (hide annotations)
Mon Mar 11 08:52:59 2002 UTC (22 years, 1 month ago) by teddy
Branch: MAIN
Changes since 1.102: +39 -29 lines
File MIME type: text/plain
stack.h: Some comments added.
stack.c (print_h, eval, rev, expand, copy_val, foreach, to):
	content.ptr changed to content.c in those places where the
	type already has been checked to be "tcons" or where it's part
	of the stack, (which always must be a proper list).
(eval, expand, foreach): Check for improper lists.
(copy_val): Don't loop, recurse into both car and cdr instead.

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

root@recompile.se
ViewVC Help
Powered by ViewVC 1.1.26