xref: /netbsd-src/external/bsd/bc/dist/load.c (revision ed857e95db3fec367bb6764523110eb0ac99cb49)
1 /*	$NetBSD: load.c,v 1.1 2017/04/10 02:28:23 phil Exp $ */
2 
3 /*
4  * Copyright (C) 1991-1994, 1997, 2006, 2008, 2012-2017 Free Software Foundation, Inc.
5  * Copyright (C) 2016-2017 Philip A. Nelson.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. The names Philip A. Nelson and Free Software Foundation may not be
18  *    used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY PHILIP A. NELSON ``AS IS'' AND ANY EXPRESS OR
22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24  * IN NO EVENT SHALL PHILIP A. NELSON OR THE FREE SOFTWARE FOUNDATION BE
25  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
31  * THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 /* load.c:  This code "loads" code into the code segments. */
35 
36 #include "bcdefs.h"
37 #include "proto.h"
38 
39 /* Load variables. */
40 
41 program_counter load_adr;
42 char load_str;
43 char load_const;
44 
45 /* Initialize the load sequence. */
46 void
init_load(void)47 init_load (void)
48 {
49   clear_func(0);
50   load_adr.pc_func = 0;
51   load_adr.pc_addr = 0;
52   load_str = FALSE;
53   load_const = FALSE;
54 }
55 
56 /* addbyte adds one BYTE to the current code segment. */
57 void
addbyte(unsigned char thebyte)58 addbyte (unsigned char thebyte)
59 {
60   unsigned long prog_addr;
61   bc_function *f;
62   char *new_body;
63 
64   /* If there was an error, don't continue. */
65   if (had_error) return;
66 
67   /* Calculate the segment and offset. */
68   prog_addr = load_adr.pc_addr++;
69   f = &functions[load_adr.pc_func];
70 
71   if (prog_addr >= f->f_body_size)
72     {
73       f->f_body_size *= 2;
74       new_body = bc_malloc (f->f_body_size);
75       memcpy(new_body, f->f_body, f->f_body_size/2);
76       free (f->f_body);
77       f->f_body = new_body;
78     }
79 
80   /* Store the thebyte. */
81   f->f_body[prog_addr] = (char) (thebyte & 0xff);
82   f->f_code_size++;
83 }
84 
85 
86 /* Define a label LAB to be the current program counter. */
87 
88 void
def_label(unsigned long lab)89 def_label (unsigned long lab)
90 {
91   bc_label_group *temp;
92   unsigned long group, offset, func;
93 
94   /* Get things ready. */
95   group = lab >> BC_LABEL_LOG;
96   offset = lab % BC_LABEL_GROUP;
97   func = load_adr.pc_func;
98 
99   /* Make sure there is at least one label group. */
100   if (functions[func].f_label == NULL)
101     {
102       functions[func].f_label = bc_malloc (sizeof(bc_label_group));
103       functions[func].f_label->l_next = NULL;
104     }
105 
106   /* Add the label group. */
107   temp = functions[func].f_label;
108   while (group > 0)
109     {
110       if (temp->l_next == NULL)
111 	{
112 	  temp->l_next = bc_malloc (sizeof(bc_label_group));
113 	  temp->l_next->l_next = NULL;
114 	}
115       temp = temp->l_next;
116       group --;
117     }
118 
119   /* Define it! */
120   temp->l_adrs [offset] = load_adr.pc_addr;
121 }
122 
123 /* Several instructions have integers in the code.  They
124    are all known to be legal longs.  So, no error code
125    is added.  STR is the pointer to the load string and
126    must be moved to the last non-digit character. */
127 
128 long
long_val(const char ** str)129 long_val (const char **str)
130 { int  val = 0;
131   char neg = FALSE;
132 
133   if (**str == '-')
134     {
135       neg = TRUE;
136       (*str)++;
137     }
138   while (isdigit((int)(**str)))
139     val = val*10 + *(*str)++ - '0';
140 
141   if (neg)
142     return -val;
143   else
144     return val;
145 }
146 
147 
148 /* load_code loads the CODE into the machine. */
149 
150 void
load_code(const char * code)151 load_code (const char *code)
152 {
153   const char *str;
154   unsigned long  ap_name;	/* auto or parameter name. */
155   unsigned long  label_no;
156   unsigned long  vaf_name;	/* variable, array or function number. */
157   unsigned long  func;
158   static program_counter save_adr;
159 
160   /* Initialize. */
161   str = code;
162 
163   /* Scan the code. */
164   while (*str != 0)
165     {
166       /* If there was an error, don't continue. */
167       if (had_error) return;
168 
169       if (load_str)
170 	{
171 	  if (*str == '"') load_str = FALSE;
172 	  addbyte (*str++);
173 	}
174       else
175 	if (load_const)
176 	  {
177 	    if (*str == '\n')
178 	      str++;
179 	    else
180 	      {
181 		if (*str == ':')
182 		  {
183 		    load_const = FALSE;
184 		    addbyte (*str++);
185 		  }
186 		else
187 		  if (*str == '.')
188 		    addbyte (*str++);
189 		  else
190                     {
191 		      if (*str > 'F' && (warn_not_std || std_only))
192                         {
193                           if (std_only)
194                             yyerror ("Error in numeric constant");
195                           else
196                             ct_warn ("Non-standard base in numeric constant");
197                         }
198 		      if (*str >= 'A')
199 		        addbyte (*str++ + 10 - 'A');
200 		      else
201 		        addbyte (*str++ - '0');
202                     }
203 	      }
204 	  }
205 	else
206 	  {
207 	    switch (*str)
208 	      {
209 
210 	      case '"':	/* Starts a string. */
211 		load_str = TRUE;
212 		break;
213 
214 	      case 'N': /* A label */
215 		str++;
216 		label_no = long_val (&str);
217 		def_label (label_no);
218 		break;
219 
220 	      case 'B':  /* Branch to label. */
221 	      case 'J':  /* Jump to label. */
222 	      case 'Z':  /* Branch Zero to label. */
223 		addbyte(*str++);
224 		label_no = long_val (&str);
225 		if (label_no > 65535L)
226 		  {  /* Better message? */
227 		    fprintf (stderr,"Program too big.\n");
228 		    bc_exit(1);
229 		  }
230 		addbyte ( (char) (label_no & 0xFF));
231 		addbyte ( (char) (label_no >> 8));
232 		break;
233 
234 	      case 'F':  /* A function, get the name and initialize it. */
235 		str++;
236 		func = long_val (&str);
237 		clear_func (func);
238 #if DEBUG > 2
239 		printf ("Loading function number %d\n", func);
240 #endif
241 		/* get the parameters */
242 		while (*str++ != '.')
243 		  {
244 		    if (*str == '.')
245 		      {
246 			str++;
247 			break;
248 		      }
249 		    if (*str == '*')
250 		      {
251 			str++;
252 			ap_name = long_val (&str);
253 #if DEBUG > 2
254 			printf ("var parameter number %d\n", ap_name);
255 #endif
256 			functions[(int)func].f_params =
257 			  nextarg (functions[(int)func].f_params, ap_name,
258 				   TRUE);
259 		      }
260 		    else
261 		      {
262 			ap_name = long_val (&str);
263 #if DEBUG > 2
264 			printf ("parameter number %d\n", ap_name);
265 #endif
266 			functions[(int)func].f_params =
267 			  nextarg (functions[(int)func].f_params, ap_name,
268 				   FALSE);
269 		      }
270 		  }
271 
272 		/* get the auto vars */
273 		while (*str != '[')
274 		  {
275 		    if (*str == ',') str++;
276 		    ap_name = long_val (&str);
277 #if DEBUG > 2
278 		    printf ("auto number %d\n", ap_name);
279 #endif
280 		    functions[(int)func].f_autos =
281 		      nextarg (functions[(int)func].f_autos, ap_name, FALSE);
282 		  }
283 		save_adr = load_adr;
284 		load_adr.pc_func = func;
285 		load_adr.pc_addr = 0;
286 		break;
287 
288 	      case ']':  /* A function end */
289 		functions[load_adr.pc_func].f_defined = TRUE;
290 		load_adr = save_adr;
291 		break;
292 
293 	      case 'C':  /* Call a function. */
294 		addbyte (*str++);
295 		func = long_val (&str);
296 		if (func < 128)
297 		  addbyte ( (char) func);
298 		else
299 		  {
300 		    addbyte (((func >> 8) & 0xff) | 0x80);
301 		    addbyte (func & 0xff);
302 		  }
303 		if (*str == ',') str++;
304 		while (*str != ':')
305 		  addbyte (*str++);
306 		addbyte (':');
307 		break;
308 
309 	      case 'c':  /* Call a special function. */
310 		addbyte (*str++);
311 		addbyte (*str);
312 		break;
313 
314 	      case 'K':  /* A constant.... may have an "F" in it. */
315 		addbyte (*str);
316 		load_const = TRUE;
317 		break;
318 
319 	      case 'd':  /* Decrement. */
320 	      case 'i':  /* Increment. */
321 	      case 'l':  /* Load. */
322 	      case 's':  /* Store. */
323 	      case 'A':  /* Array Increment */
324 	      case 'M':  /* Array Decrement */
325 	      case 'L':  /* Array Load */
326 	      case 'S':  /* Array Store */
327 		addbyte (*str++);
328 		vaf_name = long_val (&str);
329 		if (vaf_name < 128)
330 		  addbyte (vaf_name);
331 		else
332 		  {
333 		    addbyte (((vaf_name >> 8) & 0xff) | 0x80);
334 		    addbyte (vaf_name & 0xff);
335 		  }
336 		break;
337 
338 	      case '@':  /* A command! */
339 		switch (*(++str))
340 		  {
341 		  case 'i':
342 		    init_load ();
343 		    break;
344 		  case 'r':
345 		    execute ();
346 		    break;
347 		  }
348 		break;
349 
350 	      case '\n':  /* Ignore the newlines */
351 		break;
352 
353 	      default:   /* Anything else */
354 		addbyte (*str);
355 	      }
356 	    str++;
357 	  }
358     }
359 }
360