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

Annotation of /stack/stack.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.94 - (hide annotations)
Sat Mar 9 09:58:31 2002 UTC (22 years, 1 month ago) by masse
Branch: MAIN
Changes since 1.93: +28 -2 lines
File MIME type: text/plain
(sx_646976): New function "div", integer division.

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

root@recompile.se
ViewVC Help
Powered by ViewVC 1.1.26