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

Annotation of /stack/stack.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.92 - (hide annotations)
Fri Mar 8 06:44:15 2002 UTC (22 years, 1 month ago) by masse
Branch: MAIN
Changes since 1.91: +76 -1 lines
File MIME type: text/plain
(sx_2a, sx_2f, mod): "*", "/" and "mod". Arithmetic functions.

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

root@recompile.se
ViewVC Help
Powered by ViewVC 1.1.26