334 lines
		
	
	
		
			7.2 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			334 lines
		
	
	
		
			7.2 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
| /* 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++;
 | |
| 	  }
 | |
|     }
 | |
| }
 | 
