Blame bc/load.c

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