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 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 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 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 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 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