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