334 lines
7.2 KiB
C
334 lines
7.2 KiB
C
|
/* load.c: This code "loads" code into the code segments. */
|
||
|
|
||
|
/* This file is part of bc written for MINIX.
|
||
|
Copyright (C) 1991, 1992 Free Software Foundation, Inc.
|
||
|
|
||
|
This program is free software; you can redistribute it and/or modify
|
||
|
it under the terms of the GNU General Public License as published by
|
||
|
the Free Software Foundation; either version 2 of the License , or
|
||
|
(at your option) any later version.
|
||
|
|
||
|
This program is distributed in the hope that it will be useful,
|
||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
GNU General Public License for more details.
|
||
|
|
||
|
You should have received a copy of the GNU General Public License
|
||
|
along with this program; see the file COPYING. If not, write to
|
||
|
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||
|
|
||
|
You may contact the author by:
|
||
|
e-mail: phil@cs.wwu.edu
|
||
|
us-mail: Philip A. Nelson
|
||
|
Computer Science Department, 9062
|
||
|
Western Washington University
|
||
|
Bellingham, WA 98226-9062
|
||
|
|
||
|
*************************************************************************/
|
||
|
|
||
|
#include "bcdefs.h"
|
||
|
#include "global.h"
|
||
|
#include "proto.h"
|
||
|
|
||
|
/* Load variables. */
|
||
|
|
||
|
program_counter load_adr;
|
||
|
char load_str;
|
||
|
char load_const;
|
||
|
|
||
|
/* Initialize the load sequence. */
|
||
|
void
|
||
|
init_load ()
|
||
|
{
|
||
|
clear_func(0);
|
||
|
load_adr.pc_func = 0;
|
||
|
load_adr.pc_addr = 0;
|
||
|
load_str = FALSE;
|
||
|
load_const = FALSE;
|
||
|
}
|
||
|
|
||
|
/* addbyte adds one BYTE to the current code segment. */
|
||
|
void
|
||
|
addbyte (byte)
|
||
|
char byte;
|
||
|
{
|
||
|
int seg, offset, func;
|
||
|
|
||
|
/* If there was an error, don't continue. */
|
||
|
if (had_error) return;
|
||
|
|
||
|
/* Calculate the segment and offset. */
|
||
|
seg = load_adr.pc_addr >> BC_SEG_LOG;
|
||
|
offset = load_adr.pc_addr++ % BC_SEG_SIZE;
|
||
|
func = load_adr.pc_func;
|
||
|
|
||
|
if (seg >= BC_MAX_SEGS)
|
||
|
{
|
||
|
yyerror ("Function too big.");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (functions[func].f_body[seg] == NULL)
|
||
|
functions[func].f_body[seg] = (char *) bc_malloc (BC_SEG_SIZE);
|
||
|
|
||
|
/* Store the byte. */
|
||
|
functions[func].f_body[seg][offset] = byte;
|
||
|
functions[func].f_code_size++;
|
||
|
}
|
||
|
|
||
|
|
||
|
/* Define a label LAB to be the current program counter. */
|
||
|
|
||
|
void
|
||
|
def_label (lab)
|
||
|
long lab;
|
||
|
{
|
||
|
bc_label_group *temp;
|
||
|
int group, offset, func;
|
||
|
|
||
|
/* Get things ready. */
|
||
|
group = lab >> BC_LABEL_LOG;
|
||
|
offset = lab % BC_LABEL_GROUP;
|
||
|
func = load_adr.pc_func;
|
||
|
|
||
|
/* Make sure there is at least one label group. */
|
||
|
if (functions[func].f_label == NULL)
|
||
|
{
|
||
|
functions[func].f_label =
|
||
|
(bc_label_group *) bc_malloc (sizeof(bc_label_group));
|
||
|
functions[func].f_label->l_next = NULL;
|
||
|
}
|
||
|
|
||
|
/* Add the label group. */
|
||
|
temp = functions[func].f_label;
|
||
|
while (group > 0)
|
||
|
{
|
||
|
if (temp->l_next == NULL)
|
||
|
{
|
||
|
temp->l_next = (bc_label_group *) bc_malloc (sizeof(bc_label_group));
|
||
|
temp->l_next->l_next = NULL;
|
||
|
}
|
||
|
temp = temp->l_next;
|
||
|
group --;
|
||
|
}
|
||
|
|
||
|
/* Define it! */
|
||
|
temp->l_adrs [offset] = load_adr.pc_addr;
|
||
|
}
|
||
|
|
||
|
/* Several instructions have integers in the code. They
|
||
|
are all known to be legal longs. So, no error code
|
||
|
is added. STR is the pointer to the load string and
|
||
|
must be moved to the last non-digit character. */
|
||
|
|
||
|
long
|
||
|
long_val (str)
|
||
|
char **str;
|
||
|
{ int val = 0;
|
||
|
char neg = FALSE;
|
||
|
|
||
|
if (**str == '-')
|
||
|
{
|
||
|
neg = TRUE;
|
||
|
(*str)++;
|
||
|
}
|
||
|
while (isdigit(**str))
|
||
|
val = val*10 + *(*str)++ - '0';
|
||
|
|
||
|
if (neg)
|
||
|
return -val;
|
||
|
else
|
||
|
return val;
|
||
|
}
|
||
|
|
||
|
|
||
|
/* load_code loads the CODE into the machine. */
|
||
|
|
||
|
void
|
||
|
load_code (code)
|
||
|
char *code;
|
||
|
{
|
||
|
char *str;
|
||
|
long ap_name; /* auto or parameter name. */
|
||
|
long label_no;
|
||
|
long vaf_name; /* variable, array or function number. */
|
||
|
long func;
|
||
|
program_counter save_adr;
|
||
|
|
||
|
/* Initialize. */
|
||
|
str = code;
|
||
|
|
||
|
/* Scan the code. */
|
||
|
while (*str != 0)
|
||
|
{
|
||
|
/* If there was an error, don't continue. */
|
||
|
if (had_error) return;
|
||
|
|
||
|
if (load_str)
|
||
|
{
|
||
|
if (*str == '"') load_str = FALSE;
|
||
|
addbyte (*str++);
|
||
|
}
|
||
|
else
|
||
|
if (load_const)
|
||
|
{
|
||
|
if (*str == '\n')
|
||
|
str++;
|
||
|
else
|
||
|
{
|
||
|
if (*str == ':')
|
||
|
{
|
||
|
load_const = FALSE;
|
||
|
addbyte (*str++);
|
||
|
}
|
||
|
else
|
||
|
if (*str == '.')
|
||
|
addbyte (*str++);
|
||
|
else
|
||
|
if (*str >= 'A')
|
||
|
addbyte (*str++ + 10 - 'A');
|
||
|
else
|
||
|
addbyte (*str++ - '0');
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
switch (*str)
|
||
|
{
|
||
|
|
||
|
case '"': /* Starts a string. */
|
||
|
load_str = TRUE;
|
||
|
break;
|
||
|
|
||
|
case 'N': /* A label */
|
||
|
str++;
|
||
|
label_no = long_val (&str);
|
||
|
def_label (label_no);
|
||
|
break;
|
||
|
|
||
|
case 'B': /* Branch to label. */
|
||
|
case 'J': /* Jump to label. */
|
||
|
case 'Z': /* Branch Zero to label. */
|
||
|
addbyte(*str++);
|
||
|
label_no = long_val (&str);
|
||
|
if (label_no > 65535L)
|
||
|
{ /* Better message? */
|
||
|
fprintf (stderr,"Program too big.\n");
|
||
|
exit(1);
|
||
|
}
|
||
|
addbyte ( (char) label_no & 0xFF);
|
||
|
addbyte ( (char) label_no >> 8);
|
||
|
break;
|
||
|
|
||
|
case 'F': /* A function, get the name and initialize it. */
|
||
|
str++;
|
||
|
func = long_val (&str);
|
||
|
clear_func (func);
|
||
|
#if DEBUG > 2
|
||
|
printf ("Loading function number %d\n", func);
|
||
|
#endif
|
||
|
/* get the parameters */
|
||
|
while (*str++ != '.')
|
||
|
{
|
||
|
if (*str == '.')
|
||
|
{
|
||
|
str++;
|
||
|
break;
|
||
|
}
|
||
|
ap_name = long_val (&str);
|
||
|
#if DEBUG > 2
|
||
|
printf ("parameter number %d\n", ap_name);
|
||
|
#endif
|
||
|
functions[(int)func].f_params =
|
||
|
nextarg (functions[(int)func].f_params, ap_name);
|
||
|
}
|
||
|
|
||
|
/* get the auto vars */
|
||
|
while (*str != '[')
|
||
|
{
|
||
|
if (*str == ',') str++;
|
||
|
ap_name = long_val (&str);
|
||
|
#if DEBUG > 2
|
||
|
printf ("auto number %d\n", ap_name);
|
||
|
#endif
|
||
|
functions[(int)func].f_autos =
|
||
|
nextarg (functions[(int)func].f_autos, ap_name);
|
||
|
}
|
||
|
save_adr = load_adr;
|
||
|
load_adr.pc_func = func;
|
||
|
load_adr.pc_addr = 0;
|
||
|
break;
|
||
|
|
||
|
case ']': /* A function end */
|
||
|
functions[load_adr.pc_func].f_defined = TRUE;
|
||
|
load_adr = save_adr;
|
||
|
break;
|
||
|
|
||
|
case 'C': /* Call a function. */
|
||
|
addbyte (*str++);
|
||
|
func = long_val (&str);
|
||
|
if (func < 128)
|
||
|
addbyte ( (char) func);
|
||
|
else
|
||
|
{
|
||
|
addbyte ((func >> 8) & 0xff | 0x80);
|
||
|
addbyte (func & 0xff);
|
||
|
}
|
||
|
if (*str == ',') str++;
|
||
|
while (*str != ':')
|
||
|
addbyte (*str++);
|
||
|
addbyte (':');
|
||
|
break;
|
||
|
|
||
|
case 'c': /* Call a special function. */
|
||
|
addbyte (*str++);
|
||
|
addbyte (*str);
|
||
|
break;
|
||
|
|
||
|
case 'K': /* A constant.... may have an "F" in it. */
|
||
|
addbyte (*str);
|
||
|
load_const = TRUE;
|
||
|
break;
|
||
|
|
||
|
case 'd': /* Decrement. */
|
||
|
case 'i': /* Increment. */
|
||
|
case 'l': /* Load. */
|
||
|
case 's': /* Store. */
|
||
|
case 'A': /* Array Increment */
|
||
|
case 'M': /* Array Decrement */
|
||
|
case 'L': /* Array Load */
|
||
|
case 'S': /* Array Store */
|
||
|
addbyte (*str++);
|
||
|
vaf_name = long_val (&str);
|
||
|
if (vaf_name < 128)
|
||
|
addbyte (vaf_name);
|
||
|
else
|
||
|
{
|
||
|
addbyte ((vaf_name >> 8) & 0xff | 0x80);
|
||
|
addbyte (vaf_name & 0xff);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case '@': /* A command! */
|
||
|
switch (*(++str))
|
||
|
{
|
||
|
case 'i':
|
||
|
init_load ();
|
||
|
break;
|
||
|
case 'r':
|
||
|
execute ();
|
||
|
break;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case '\n': /* Ignore the newlines */
|
||
|
break;
|
||
|
|
||
|
default: /* Anything else */
|
||
|
addbyte (*str);
|
||
|
}
|
||
|
str++;
|
||
|
}
|
||
|
}
|
||
|
}
|