1/* load.c:  This code "loads" code into the code segments. */
2
3/*  This file is part of GNU bc.
4    Copyright (C) 1991-1994, 1997, 2000 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, Inc.
19      59 Temple Place, Suite 330
20      Boston, MA 02111 USA
21
22    You may contact the author by:
23       e-mail:  philnelson@acm.org
24      us-mail:  Philip A. Nelson
25                Computer Science Department, 9062
26                Western Washington University
27                Bellingham, WA 98226-9062
28
29*************************************************************************/
30
31#include "bcdefs.h"
32#include "global.h"
33#include "proto.h"
34
35/* Load variables. */
36
37program_counter load_adr;
38char load_str;
39char load_const;
40
41/* Initialize the load sequence. */
42void
43init_load ()
44{
45  clear_func(0);
46  load_adr.pc_func = 0;
47  load_adr.pc_addr = 0;
48  load_str = FALSE;
49  load_const = FALSE;
50}
51
52/* addbyte adds one BYTE to the current code segment. */
53void
54addbyte (byte)
55     char byte;
56{
57  int pc;
58  bc_function *f;
59  char *new_body;
60
61  /* If there was an error, don't continue. */
62  if (had_error) return;
63
64  /* Calculate the segment and offset. */
65  pc = load_adr.pc_addr++;
66  f = &functions[load_adr.pc_func];
67
68  if (pc >= f->f_body_size)
69    {
70      f->f_body_size *= 2;
71      new_body = (char *) bc_malloc (f->f_body_size);
72      memcpy(new_body, f->f_body, f->f_body_size/2);
73      free (f->f_body);
74      f->f_body = new_body;
75    }
76
77  /* Store the byte. */
78  f->f_body[pc] = byte;
79  f->f_code_size++;
80}
81
82
83/* Define a label LAB to be the current program counter. */
84
85void
86def_label (lab)
87     long lab;
88{
89  bc_label_group *temp;
90  int group, offset, func;
91
92  /* Get things ready. */
93  group = lab >> BC_LABEL_LOG;
94  offset = lab % BC_LABEL_GROUP;
95  func = load_adr.pc_func;
96
97  /* Make sure there is at least one label group. */
98  if (functions[func].f_label == NULL)
99    {
100      functions[func].f_label =
101	(bc_label_group *) bc_malloc (sizeof(bc_label_group));
102      functions[func].f_label->l_next = NULL;
103    }
104
105  /* Add the label group. */
106  temp = functions[func].f_label;
107  while (group > 0)
108    {
109      if (temp->l_next == NULL)
110	{
111	  temp->l_next = (bc_label_group *) bc_malloc (sizeof(bc_label_group));
112	  temp->l_next->l_next = NULL;
113	}
114      temp = temp->l_next;
115      group --;
116    }
117
118  /* Define it! */
119  temp->l_adrs [offset] = load_adr.pc_addr;
120}
121
122/* Several instructions have integers in the code.  They
123   are all known to be legal longs.  So, no error code
124   is added.  STR is the pointer to the load string and
125   must be moved to the last non-digit character. */
126
127long
128long_val (str)
129     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
150void
151load_code (code)
152     char *code;
153{
154  char *str;
155  long  ap_name;	/* auto or parameter name. */
156  long  label_no;
157  long  vaf_name;	/* variable, array or function number. */
158  long  func;
159  program_counter save_adr;
160
161  /* Initialize. */
162  str = code;
163
164  /* Scan the code. */
165  while (*str != 0)
166    {
167      /* If there was an error, don't continue. */
168      if (had_error) return;
169
170      if (load_str)
171	{
172	  if (*str == '"') load_str = FALSE;
173	  addbyte (*str++);
174	}
175      else
176	if (load_const)
177	  {
178	    if (*str == '\n')
179	      str++;
180	    else
181	      {
182		if (*str == ':')
183		  {
184		    load_const = FALSE;
185		    addbyte (*str++);
186		  }
187		else
188		  if (*str == '.')
189		    addbyte (*str++);
190		  else
191		    if (*str >= 'A')
192		      addbyte (*str++ + 10 - 'A');
193		    else
194		      addbyte (*str++ - '0');
195	      }
196	  }
197	else
198	  {
199	    switch (*str)
200	      {
201
202	      case '"':	/* Starts a string. */
203		load_str = TRUE;
204		break;
205
206	      case 'N': /* A label */
207		str++;
208		label_no = long_val (&str);
209		def_label (label_no);
210		break;
211
212	      case 'B':  /* Branch to label. */
213	      case 'J':  /* Jump to label. */
214	      case 'Z':  /* Branch Zero to label. */
215		addbyte(*str++);
216		label_no = long_val (&str);
217		if (label_no > 65535L)
218		  {  /* Better message? */
219		    fprintf (stderr,"Program too big.\n");
220		    exit(1);
221		  }
222		addbyte ( (char) (label_no & 0xFF));
223		addbyte ( (char) (label_no >> 8));
224		break;
225
226	      case 'F':  /* A function, get the name and initialize it. */
227		str++;
228		func = long_val (&str);
229		clear_func (func);
230#if DEBUG > 2
231		printf ("Loading function number %d\n", func);
232#endif
233		/* get the parameters */
234		while (*str++ != '.')
235		  {
236		    if (*str == '.')
237		      {
238			str++;
239			break;
240		      }
241		    if (*str == '*')
242		      {
243			str++;
244			ap_name = long_val (&str);
245#if DEBUG > 2
246			printf ("var parameter number %d\n", ap_name);
247#endif
248			functions[(int)func].f_params =
249			  nextarg (functions[(int)func].f_params, ap_name,
250				   TRUE);
251		      }
252		    else
253		      {
254			ap_name = long_val (&str);
255#if DEBUG > 2
256			printf ("parameter number %d\n", ap_name);
257#endif
258			functions[(int)func].f_params =
259			  nextarg (functions[(int)func].f_params, ap_name,
260				   FALSE);
261		      }
262		  }
263
264		/* get the auto vars */
265		while (*str != '[')
266		  {
267		    if (*str == ',') str++;
268		    ap_name = long_val (&str);
269#if DEBUG > 2
270		    printf ("auto number %d\n", ap_name);
271#endif
272		    functions[(int)func].f_autos =
273		      nextarg (functions[(int)func].f_autos, ap_name, FALSE);
274		  }
275		save_adr = load_adr;
276		load_adr.pc_func = func;
277		load_adr.pc_addr = 0;
278		break;
279
280	      case ']':  /* A function end */
281		functions[load_adr.pc_func].f_defined = TRUE;
282		load_adr = save_adr;
283		break;
284
285	      case 'C':  /* Call a function. */
286		addbyte (*str++);
287		func = long_val (&str);
288		if (func < 128)
289		  addbyte ( (char) func);
290		else
291		  {
292		    addbyte (((func >> 8) & 0xff) | 0x80);
293		    addbyte (func & 0xff);
294		  }
295		if (*str == ',') str++;
296		while (*str != ':')
297		  addbyte (*str++);
298		addbyte (':');
299		break;
300
301	      case 'c':  /* Call a special function. */
302		addbyte (*str++);
303		addbyte (*str);
304		break;
305
306	      case 'K':  /* A constant.... may have an "F" in it. */
307		addbyte (*str);
308		load_const = TRUE;
309		break;
310
311	      case 'd':  /* Decrement. */
312	      case 'i':  /* Increment. */
313	      case 'l':  /* Load. */
314	      case 's':  /* Store. */
315	      case 'A':  /* Array Increment */
316	      case 'M':  /* Array Decrement */
317	      case 'L':  /* Array Load */
318	      case 'S':  /* Array Store */
319		addbyte (*str++);
320		vaf_name = long_val (&str);
321		if (vaf_name < 128)
322		  addbyte (vaf_name);
323		else
324		  {
325		    addbyte (((vaf_name >> 8) & 0xff) | 0x80);
326		    addbyte (vaf_name & 0xff);
327		  }
328		break;
329
330	      case '@':  /* A command! */
331		switch (*(++str))
332		  {
333		  case 'i':
334		    init_load ();
335		    break;
336		  case 'r':
337		    execute ();
338		    break;
339		  }
340		break;
341
342	      case '\n':  /* Ignore the newlines */
343		break;
344
345	      default:   /* Anything else */
346		addbyte (*str);
347	      }
348	    str++;
349	  }
350    }
351}
352