xref: /386bsd/usr/src/usr.bin/bc/load.c (revision a2142627)
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, 1992 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
init_load()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
addbyte(byte)52 addbyte (byte)
53      char byte;
54 {
55   int seg, offset, func;
56 
57   /* If there was an error, don't continue. */
58   if (had_error) return;
59 
60   /* Calculate the segment and offset. */
61   seg = load_adr.pc_addr >> BC_SEG_LOG;
62   offset = load_adr.pc_addr++ % BC_SEG_SIZE;
63   func = load_adr.pc_func;
64 
65   if (seg >= BC_MAX_SEGS)
66     {
67       yyerror ("Function too big.");
68       return;
69     }
70 
71   if (functions[func].f_body[seg] == NULL)
72     functions[func].f_body[seg] = (char *) bc_malloc (BC_SEG_SIZE);
73 
74   /* Store the byte. */
75   functions[func].f_body[seg][offset] = byte;
76   functions[func].f_code_size++;
77 }
78 
79 
80 /* Define a label LAB to be the current program counter. */
81 
82 void
def_label(lab)83 def_label (lab)
84      long lab;
85 {
86   bc_label_group *temp;
87   int group, offset, func;
88 
89   /* Get things ready. */
90   group = lab >> BC_LABEL_LOG;
91   offset = lab % BC_LABEL_GROUP;
92   func = load_adr.pc_func;
93 
94   /* Make sure there is at least one label group. */
95   if (functions[func].f_label == NULL)
96     {
97       functions[func].f_label =
98 	(bc_label_group *) bc_malloc (sizeof(bc_label_group));
99       functions[func].f_label->l_next = NULL;
100     }
101 
102   /* Add the label group. */
103   temp = functions[func].f_label;
104   while (group > 0)
105     {
106       if (temp->l_next == NULL)
107 	{
108 	  temp->l_next = (bc_label_group *) bc_malloc (sizeof(bc_label_group));
109 	  temp->l_next->l_next = NULL;
110 	}
111       temp = temp->l_next;
112       group --;
113     }
114 
115   /* Define it! */
116   temp->l_adrs [offset] = load_adr.pc_addr;
117 }
118 
119 /* Several instructions have integers in the code.  They
120    are all known to be legal longs.  So, no error code
121    is added.  STR is the pointer to the load string and
122    must be moved to the last non-digit character. */
123 
124 long
long_val(str)125 long_val (str)
126      char **str;
127 { int  val = 0;
128   char neg = FALSE;
129 
130   if (**str == '-')
131     {
132       neg = TRUE;
133       (*str)++;
134     }
135   while (isdigit(**str))
136     val = val*10 + *(*str)++ - '0';
137 
138   if (neg)
139     return -val;
140   else
141     return val;
142 }
143 
144 
145 /* load_code loads the CODE into the machine. */
146 
147 void
load_code(code)148 load_code (code)
149      char *code;
150 {
151   char *str;
152   long  ap_name;	/* auto or parameter name. */
153   long  label_no;
154   long  vaf_name;	/* variable, array or function number. */
155   long  func;
156   program_counter save_adr;
157 
158   /* Initialize. */
159   str = code;
160 
161   /* Scan the code. */
162   while (*str != 0)
163     {
164       /* If there was an error, don't continue. */
165       if (had_error) return;
166 
167       if (load_str)
168 	{
169 	  if (*str == '"') load_str = FALSE;
170 	  addbyte (*str++);
171 	}
172       else
173 	if (load_const)
174 	  {
175 	    if (*str == '\n')
176 	      str++;
177 	    else
178 	      {
179 		if (*str == ':')
180 		  {
181 		    load_const = FALSE;
182 		    addbyte (*str++);
183 		  }
184 		else
185 		  if (*str == '.')
186 		    addbyte (*str++);
187 		  else
188 		    if (*str >= 'A')
189 		      addbyte (*str++ + 10 - 'A');
190 		    else
191 		      addbyte (*str++ - '0');
192 	      }
193 	  }
194 	else
195 	  {
196 	    switch (*str)
197 	      {
198 
199 	      case '"':	/* Starts a string. */
200 		load_str = TRUE;
201 		break;
202 
203 	      case 'N': /* A label */
204 		str++;
205 		label_no = long_val (&str);
206 		def_label (label_no);
207 		break;
208 
209 	      case 'B':  /* Branch to label. */
210 	      case 'J':  /* Jump to label. */
211 	      case 'Z':  /* Branch Zero to label. */
212 		addbyte(*str++);
213 		label_no = long_val (&str);
214 		if (label_no > 65535L)
215 		  {  /* Better message? */
216 		    fprintf (stderr,"Program too big.\n");
217 		    exit(1);
218 		  }
219 		addbyte ( (char) label_no & 0xFF);
220 		addbyte ( (char) label_no >> 8);
221 		break;
222 
223 	      case 'F':  /* A function, get the name and initialize it. */
224 		str++;
225 		func = long_val (&str);
226 		clear_func (func);
227 #if DEBUG > 2
228 		printf ("Loading function number %d\n", func);
229 #endif
230 		/* get the parameters */
231 		while (*str++ != '.')
232 		  {
233 		    if (*str == '.')
234 		      {
235 			str++;
236 			break;
237 		      }
238 		    ap_name = long_val (&str);
239 #if DEBUG > 2
240 		    printf ("parameter number %d\n", ap_name);
241 #endif
242 		    functions[(int)func].f_params =
243 		      nextarg (functions[(int)func].f_params, ap_name);
244 		  }
245 
246 		/* get the auto vars */
247 		while (*str != '[')
248 		  {
249 		    if (*str == ',') str++;
250 		    ap_name = long_val (&str);
251 #if DEBUG > 2
252 		    printf ("auto number %d\n", ap_name);
253 #endif
254 		    functions[(int)func].f_autos =
255 		      nextarg (functions[(int)func].f_autos, ap_name);
256 		  }
257 		save_adr = load_adr;
258 		load_adr.pc_func = func;
259 		load_adr.pc_addr = 0;
260 		break;
261 
262 	      case ']':  /* A function end */
263 		functions[load_adr.pc_func].f_defined = TRUE;
264 		load_adr = save_adr;
265 		break;
266 
267 	      case 'C':  /* Call a function. */
268 		addbyte (*str++);
269 		func = long_val (&str);
270 		if (func < 128)
271 		  addbyte ( (char) func);
272 		else
273 		  {
274 		    addbyte ((func >> 8) & 0xff | 0x80);
275 		    addbyte (func & 0xff);
276 		  }
277 		if (*str == ',') str++;
278 		while (*str != ':')
279 		  addbyte (*str++);
280 		addbyte (':');
281 		break;
282 
283 	      case 'c':  /* Call a special function. */
284 		addbyte (*str++);
285 		addbyte (*str);
286 		break;
287 
288 	      case 'K':  /* A constant.... may have an "F" in it. */
289 		addbyte (*str);
290 		load_const = TRUE;
291 		break;
292 
293 	      case 'd':  /* Decrement. */
294 	      case 'i':  /* Increment. */
295 	      case 'l':  /* Load. */
296 	      case 's':  /* Store. */
297 	      case 'A':  /* Array Increment */
298 	      case 'M':  /* Array Decrement */
299 	      case 'L':  /* Array Load */
300 	      case 'S':  /* Array Store */
301 		addbyte (*str++);
302 		vaf_name = long_val (&str);
303 		if (vaf_name < 128)
304 		  addbyte (vaf_name);
305 		else
306 		  {
307 		    addbyte ((vaf_name >> 8) & 0xff | 0x80);
308 		    addbyte (vaf_name & 0xff);
309 		  }
310 		break;
311 
312 	      case '@':  /* A command! */
313 		switch (*(++str))
314 		  {
315 		  case 'i':
316 		    init_load ();
317 		    break;
318 		  case 'r':
319 		    execute ();
320 		    break;
321 		  }
322 		break;
323 
324 	      case '\n':  /* Ignore the newlines */
325 		break;
326 
327 	      default:   /* Anything else */
328 		addbyte (*str);
329 	      }
330 	    str++;
331 	  }
332     }
333 }
334