Merge tag 'upstream/0.2.1'
[debian/yforth] / yforth.c
1 /* yForth? - A Forth interpreter written in ANSI C
2  * Copyright (C) 2012 Luca Padovani
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 * ------------------------------------------------------------------------
17  * Module name:     yforth.c
18  * Abstract:        Main program
19  */
20
21 #include <setjmp.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include "yforth.h"
25 #include "defaults.h"
26 #include "core.h"
27 #include "block.h"
28 #include "search.h"
29 #include "ver.h"
30 #include "file.h"
31
32 jmp_buf warm_start_jump, cold_start_jump;
33
34 Char *dp0;                          /* Data-Space base pointer */
35 Cell dspace_size = DEF_DSPACE_SIZE; /* Data-Space size */
36 Cell dstack_size = DEF_DSTACK_SIZE, /* Data-Stack size */
37      rstack_size = DEF_RSTACK_SIZE, /* Return-stack size */
38      fstack_size = DEF_FSTACK_SIZE; /* Floating-stack size */
39 Cell tib_size    = DEF_TIB_SIZE;    /* TIB size */
40 Cell in_pnos, pnos_size;            /* Pictured Numeric Output String */
41 Char *pnos, *p_pnos;                /* Ptrs inside PNOS */
42 Cell pad_size    = DEF_PAD_SIZE;    /* PAD size */
43
44 static char *file_name,             /* Ptr to file name on command line, if present */
45             *image_file;            /* Ptr to image file name on cmd line, if present */
46
47 static int silent,
48     image_file_loaded;
49
50 static struct image_header hd;
51
52 void print_version() {
53   printf("yForth? v%d.%d%s  Copyright (C) 2012  Luca Padovani\n\
54 This program comes with ABSOLUTELY NO WARRANTY.\n\
55 This is free software, and you are welcome to redistribute it\n\
56 under certain conditions; see LICENSE for details.\n",
57          VER_HI, VER_LO, VER_TEST);
58 }
59
60 void print_help(void) {
61         print_version();
62         printf("Usage: yForth [options] [file name]\n\
63 -d<n>   Data-Space size         -s<n>   Data-Stack size\n\
64 -r<n>   Return-Stack size       -f<n>   Floating-Stack size\n\
65 -t<n>   TIB size                -p<n>   PAD size\n\
66 -h,-H   This help               -q      Quiet\n\
67 -i<file> Image file\n\
68 All sizes are expressed in cells.\n");
69 }
70
71 /* do_parameters: processes parameters passed on command line */
72 void do_parameters(int argc, char *argv[]) {
73         int i = 1;
74     while (argc-- > 1) {
75                 if (argv[i][0] == '-')
76                         switch (argv[i][1]) {
77                                 case 'd': dspace_size = atoi(argv[i] + 2); break;
78                                 case 's': dstack_size = atoi(argv[i] + 2); break;
79                                 case 'r': rstack_size = atoi(argv[i] + 2); break;
80                                 case 'f': fstack_size = atoi(argv[i] + 2); break;
81                                 case 't': tib_size = atoi(argv[i] + 2); break;
82                                 case 'p': pad_size = atoi(argv[i] + 2); break;
83                                 case 'q': silent = 1; break;
84                                 case 'i': image_file = argv[i] + 2; break;
85                                 case 'h':
86                                 case 'H':
87                                         print_help();
88                                         exit(0);
89                                         break;
90                                 default:
91                     fprintf(stderr, "%c unknown option, use -h for help.\n");
92                                         exit(0);
93                                         break;
94                         }
95                 else {
96                         file_name = argv[i];
97                         break;
98                 }
99         }
100 }
101
102 /* default_parameters: adjust environment parameters in case they do not
103  * fall into required range
104  */
105 void default_parameters(void) {
106         dspace_size = max(MIN_DSPACE_SIZE, dspace_size);
107         dstack_size = max(MIN_DSTACK_SIZE, dstack_size);
108         rstack_size = max(MIN_RSTACK_SIZE, rstack_size);
109         fstack_size = max(MIN_FSTACK_SIZE, fstack_size);
110         tib_size = max(MIN_TIB_SIZE, tib_size);
111         pad_size = max(MIN_PAD_SIZE, pad_size);
112 }
113
114 /* load_image_file: loads image file named "name" into the dictionary. Loading
115  * is divided in two parts: when "header" is set to 1 the file is opened and
116  * the header is loaded into the structure "hd". Then some checks are made
117  * to adjust parameters in case of a corrupted image.
118  * Finally, when "load_image_file" is called with "header" set to 0, the
119  * actual loading is performed. Note that pointers inside the dictionary
120  * are absolute, so an image file can be loaded only if the allocated
121  * memory is placed at the same address when it's been saved. Furthermore,
122  * the same image file cannot be loaded thru different version of the
123  * executable file "yForth".
124  */
125 int load_image_file(char *name, int header) {
126         FILE *f = fopen(name, "rb");
127         int res = 1;
128         if (f) {
129                 if (header) {
130                         if (fread(&hd, sizeof(struct image_header), 1, f)) {
131                                 if (hd.ver_hi != VER_HI || hd.ver_lo != VER_LO)
132                                         if (!silent)
133                         fprintf(stderr, "Warning: different image file version (%d.%d).\n",
134                                                 hd.ver_hi, hd.ver_lo);
135                                 if (hd.pattern != VERSION_PATTERN)
136                                         if (!silent)
137                                                 fprintf(stderr, "Warning: different version pattern (Image: %x).\n",
138                                                         hd.pattern); 
139                                 res = 0;
140             } else fprintf(stderr, "Error: can't read image file header.\n");
141                 } else {
142                         fseek(f, sizeof(struct image_header), SEEK_SET);
143                         if (hd.base == dp0) {
144                                 struct voc_marker vm;
145                                 if (fread(&vm, sizeof(struct voc_marker), 1, f) < 1 ||
146                                         fread(dp0, sizeof(Cell), hd.dspace_size, f) != hd.dspace_size)
147                     fprintf(stderr, "Error: can't read image file.\n");
148                                 else {
149                                         load_vocabulary(&vm);
150                                         res = 0;
151                                 }
152             } else fprintf(stderr, "Error: can't load image file with base %u at %u.\n",
153                                 hd.base, dp0);
154                 }
155                 fclose(f);
156     } else fprintf(stderr, "Can't open image file (%s).\n", name);
157         return (res);
158 }
159
160 main(int argc, char *argv[]) {
161         do_parameters(argc, argv);
162         if (image_file) {
163                 if (load_image_file(image_file, 1)) exit(-1);
164         } else fopen(argv[0], "rb");
165         /* !!! WARNING !!! Previous line opens a file even if no image-file
166          * is specified. This is because in some system data space would 
167          * result unaligned in subsequent loadings. I have to find a more
168          * smart trick here...
169          */ 
170
171         default_parameters();
172 #if BLOCK_DEF
173         open_block_file("YFORTH.BLK");
174 #endif
175         init_stacks(dstack_size, rstack_size, fstack_size);
176         if (image_file && dspace_size < hd.dspace_size) {
177                 if (!silent)
178             fprintf(stderr, "Warning: can't restrict dictionary to %u cells, now is %u cells.\n",
179                         dspace_size, hd.dspace_size);
180                 dspace_size = max(dspace_size, hd.dspace_size);
181         }
182         init_data_space(dspace_size);
183         init_tib(tib_size);
184         init_pad(pad_size);
185         init_pnos();
186         init_signals();
187
188         silent |= setjmp(cold_start_jump);
189         if (image_file)
190                 if (load_image_file(image_file, 0)) exit(-1);
191
192     /* Note that after a cold start the vocabulary is reloaded */
193
194         if (!silent) {
195                 print_version();
196                 /*
197                 printf("Cell: %d  Double-Cell: %d  Char: %d  Real: %d\n",
198                         sizeof(Cell), sizeof(DCell), sizeof(Char), sizeof(Real));
199                 */
200         }
201         init_forth_environment(!image_file);
202         if (!setjmp(warm_start_jump) && file_name) load_file(file_name);
203         _quit();
204         return 0;
205 }
206