Commit | Line | Data |
---|---|---|
f87489ac WJ |
1 | /* load.c: This code "loads" code into the code segments. */ |
2 | ||
3 | /* This file is part of bc written for MINIX. | |
4 | Copyright (C) 1991 Free Software Foundation, Inc. | |
5 | ||
6 | This program is free software; you can redistribute it and/or modify | |
7 | it under the terms of the GNU General Public License as published by | |
8 | the Free Software Foundation; either version 2 of the License , or | |
9 | (at your option) any later version. | |
10 | ||
11 | This program is distributed in the hope that it will be useful, | |
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | GNU General Public License for more details. | |
15 | ||
16 | You should have received a copy of the GNU General Public License | |
17 | along with this program; see the file COPYING. If not, write to | |
18 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | |
19 | ||
20 | You may contact the author by: | |
21 | e-mail: phil@cs.wwu.edu | |
22 | us-mail: Philip A. Nelson | |
23 | Computer Science Department, 9062 | |
24 | Western Washington University | |
25 | Bellingham, WA 98226-9062 | |
26 | ||
27 | *************************************************************************/ | |
28 | ||
29 | #include "bcdefs.h" | |
30 | #include "global.h" | |
31 | #include "proto.h" | |
32 | ||
33 | /* Load variables. */ | |
34 | ||
35 | program_counter load_adr; | |
36 | char load_str; | |
37 | char load_const; | |
38 | ||
39 | /* Initialize the load sequence. */ | |
40 | void | |
41 | init_load () | |
42 | { | |
43 | clear_func(0); | |
44 | load_adr.pc_func = 0; | |
45 | load_adr.pc_addr = 0; | |
46 | load_str = FALSE; | |
47 | load_const = FALSE; | |
48 | } | |
49 | ||
50 | /* addbyte adds one BYTE to the current code segment. */ | |
51 | void | |
52 | addbyte (byte) | |
53 | char byte; | |
54 | { | |
55 | int seg, offset, func; | |
56 | ||
57 | /* Calculate the segment and offset. */ | |
58 | seg = load_adr.pc_addr >> BC_SEG_LOG; | |
59 | offset = load_adr.pc_addr++ % BC_SEG_SIZE; | |
60 | func = load_adr.pc_func; | |
61 | ||
62 | if (functions[func].f_body[seg] == NULL) | |
63 | functions[func].f_body[seg] = (char *) bc_malloc (BC_SEG_SIZE); | |
64 | ||
65 | /* Store the byte. */ | |
66 | functions[func].f_body[seg][offset] = byte; | |
67 | functions[func].f_code_size++; | |
68 | } | |
69 | ||
70 | ||
71 | /* Define a label LAB to be the current program counter. */ | |
72 | ||
73 | void | |
74 | def_label (lab) | |
75 | long lab; | |
76 | { | |
77 | bc_label_group *temp; | |
78 | int group, offset, func; | |
79 | ||
80 | /* Get things ready. */ | |
81 | group = lab >> BC_LABEL_LOG; | |
82 | offset = lab % BC_LABEL_GROUP; | |
83 | func = load_adr.pc_func; | |
84 | ||
85 | /* Make sure there is at least one label group. */ | |
86 | if (functions[func].f_label == NULL) | |
87 | { | |
88 | functions[func].f_label = | |
89 | (bc_label_group *) bc_malloc (sizeof(bc_label_group)); | |
90 | functions[func].f_label->l_next = NULL; | |
91 | } | |
92 | ||
93 | /* Add the label group. */ | |
94 | temp = functions[func].f_label; | |
95 | while (group > 0) | |
96 | { | |
97 | if (temp->l_next == NULL) | |
98 | { | |
99 | temp->l_next = (bc_label_group *) bc_malloc (sizeof(bc_label_group)); | |
100 | temp->l_next->l_next = NULL; | |
101 | } | |
102 | temp = temp->l_next; | |
103 | group --; | |
104 | } | |
105 | ||
106 | /* Define it! */ | |
107 | temp->l_adrs [offset] = load_adr.pc_addr; | |
108 | } | |
109 | ||
110 | /* Several instructions have integers in the code. They | |
111 | are all known to be legal longs. So, no error code | |
112 | is added. STR is the pointer to the load string and | |
113 | must be moved to the last non-digit character. */ | |
114 | ||
115 | long | |
116 | long_val (str) | |
117 | char **str; | |
118 | { int val = 0; | |
119 | char neg = FALSE; | |
120 | ||
121 | if (**str == '-') | |
122 | { | |
123 | neg = TRUE; | |
124 | (*str)++; | |
125 | } | |
126 | while (isdigit(**str)) | |
127 | val = val*10 + *(*str)++ - '0'; | |
128 | ||
129 | if (neg) | |
130 | return -val; | |
131 | else | |
132 | return val; | |
133 | } | |
134 | ||
135 | ||
136 | /* load_code loads the CODE into the machine. */ | |
137 | ||
138 | void | |
139 | load_code (code) | |
140 | char *code; | |
141 | { | |
142 | char *str; | |
143 | long ap_name; /* auto or parameter name. */ | |
144 | long label_no; | |
145 | long vaf_name; /* variable, array or function number. */ | |
146 | long func; | |
147 | program_counter save_adr; | |
148 | ||
149 | /* Initialize. */ | |
150 | str = code; | |
151 | ||
152 | /* Scan the code. */ | |
153 | while (*str != 0) | |
154 | { | |
155 | if (load_str) | |
156 | { | |
157 | if (*str == '"') load_str = FALSE; | |
158 | addbyte (*str++); | |
159 | } | |
160 | else | |
161 | if (load_const) | |
162 | { | |
163 | if (*str == '\n') | |
164 | str++; | |
165 | else | |
166 | { | |
167 | if (*str == ':') | |
168 | { | |
169 | load_const = FALSE; | |
170 | addbyte (*str++); | |
171 | } | |
172 | else | |
173 | if (*str == '.') | |
174 | addbyte (*str++); | |
175 | else | |
176 | if (*str >= 'A') | |
177 | addbyte (*str++ + 10 - 'A'); | |
178 | else | |
179 | addbyte (*str++ - '0'); | |
180 | } | |
181 | } | |
182 | else | |
183 | { | |
184 | switch (*str) | |
185 | { | |
186 | ||
187 | case '"': /* Starts a string. */ | |
188 | load_str = TRUE; | |
189 | break; | |
190 | ||
191 | case 'N': /* A label */ | |
192 | str++; | |
193 | label_no = long_val (&str); | |
194 | def_label (label_no); | |
195 | break; | |
196 | ||
197 | case 'B': /* Branch to label. */ | |
198 | case 'J': /* Jump to label. */ | |
199 | case 'Z': /* Branch Zero to label. */ | |
200 | addbyte(*str++); | |
201 | label_no = long_val (&str); | |
202 | if (label_no > 65535L) | |
203 | { /* Better message? */ | |
204 | fprintf (stderr,"Program too big.\n"); | |
205 | exit(1); | |
206 | } | |
207 | addbyte ( (char) label_no & 0xFF); | |
208 | addbyte ( (char) label_no >> 8); | |
209 | break; | |
210 | ||
211 | case 'F': /* A function, get the name and initialize it. */ | |
212 | str++; | |
213 | func = long_val (&str); | |
214 | clear_func (func); | |
215 | #if DEBUG > 2 | |
216 | printf ("Loading function number %d\n", func); | |
217 | #endif | |
218 | /* get the parameters */ | |
219 | while (*str++ != '.') | |
220 | { | |
221 | if (*str == '.') | |
222 | { | |
223 | str++; | |
224 | break; | |
225 | } | |
226 | ap_name = long_val (&str); | |
227 | #if DEBUG > 2 | |
228 | printf ("parameter number %d\n", ap_name); | |
229 | #endif | |
230 | functions[(int)func].f_params = | |
231 | nextarg (functions[(int)func].f_params, ap_name); | |
232 | } | |
233 | ||
234 | /* get the auto vars */ | |
235 | while (*str != '[') | |
236 | { | |
237 | if (*str == ',') str++; | |
238 | ap_name = long_val (&str); | |
239 | #if DEBUG > 2 | |
240 | printf ("auto number %d\n", ap_name); | |
241 | #endif | |
242 | functions[(int)func].f_autos = | |
243 | nextarg (functions[(int)func].f_autos, ap_name); | |
244 | } | |
245 | save_adr = load_adr; | |
246 | load_adr.pc_func = func; | |
247 | load_adr.pc_addr = 0; | |
248 | break; | |
249 | ||
250 | case ']': /* A function end */ | |
251 | if (!had_error) | |
252 | functions[load_adr.pc_func].f_defined = TRUE; | |
253 | load_adr = save_adr; | |
254 | break; | |
255 | ||
256 | case 'C': /* Call a function. */ | |
257 | addbyte (*str++); | |
258 | func = long_val (&str); | |
259 | if (func < 128) | |
260 | addbyte ( (char) func); | |
261 | else | |
262 | { | |
263 | addbyte ((func >> 8) & 0xff | 0x80); | |
264 | addbyte (func & 0xff); | |
265 | } | |
266 | if (*str == ',') str++; | |
267 | while (*str != ':') | |
268 | addbyte (*str++); | |
269 | addbyte (':'); | |
270 | break; | |
271 | ||
272 | case 'c': /* Call a special function. */ | |
273 | addbyte (*str++); | |
274 | addbyte (*str); | |
275 | break; | |
276 | ||
277 | case 'K': /* A constant.... may have an "F" in it. */ | |
278 | addbyte (*str); | |
279 | load_const = TRUE; | |
280 | break; | |
281 | ||
282 | case 'd': /* Decrement. */ | |
283 | case 'i': /* Increment. */ | |
284 | case 'l': /* Load. */ | |
285 | case 's': /* Store. */ | |
286 | case 'A': /* Array Increment */ | |
287 | case 'M': /* Array Decrement */ | |
288 | case 'L': /* Array Load */ | |
289 | case 'S': /* Array Store */ | |
290 | addbyte (*str++); | |
291 | vaf_name = long_val (&str); | |
292 | if (vaf_name < 128) | |
293 | addbyte (vaf_name); | |
294 | else | |
295 | { | |
296 | addbyte ((vaf_name >> 8) & 0xff | 0x80); | |
297 | addbyte (vaf_name & 0xff); | |
298 | } | |
299 | break; | |
300 | ||
301 | case '@': /* A command! */ | |
302 | switch (*(++str)) | |
303 | { | |
304 | case 'i': | |
305 | init_load (); | |
306 | break; | |
307 | case 'r': | |
308 | execute (); | |
309 | break; | |
310 | } | |
311 | break; | |
312 | ||
313 | case '\n': /* Ignore the newlines */ | |
314 | break; | |
315 | ||
316 | default: /* Anything else */ | |
317 | addbyte (*str); | |
318 | } | |
319 | str++; | |
320 | } | |
321 | } | |
322 | } |