I have to specify SCRIPTSNAME too, otherwise bsd.prog.mk strips the extension.
[dragonfly.git] / contrib / bc / bc / load.c
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
37 program_counter load_adr;
38 char load_str;
39 char load_const;
40
41 /* Initialize the load sequence. */
42 void
43 init_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. */
53 void
54 addbyte (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
85 void
86 def_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
127 long
128 long_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
150 void
151 load_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   static 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 }