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

Annotation of /stack/stack.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.102 - (hide annotations)
Sun Mar 10 20:08:47 2002 UTC (22 years, 1 month ago) by masse
Branch: MAIN
Changes since 1.101: +320 -346 lines
File MIME type: text/plain
Modified internal data structure to use cons cells instead of simple linked
lists. There is now a new value type "tcons".

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

root@recompile.se
ViewVC Help
Powered by ViewVC 1.1.26