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