/* memory.c */
/* author: Edward A. Green */
/* purpose: memory calculation routines */

#include "proj3.h"


void fill_local_addrs(BLOCK *blks)
{
	SYMTBL *parms;
	SYMTBL *formal;
	SYMTBL *sym_look_up(BLOCK *blk, char *var);
	SYMTBL *self;
	BLOCK  *hold_blk;
	char   *strsave(char *);
	char   *s;
	char   c_loc[30];
	int    i_loc;


	hold_blk=blks->last;
	blks->last->next=NULL;
	while (blks!=NULL)
	  {

	  /* 1: FILL IN GLOBAL ADDRESSES */
	  /*   1a) FIND GLOBAL DEFINITIONS */
	  formal=blks->table->next;

	  /* skip over local definitions (_ indicates main block) */
	  if (blks->lead->flds[0][0]!='_')
	    {
	    parms=formal;
	    while (parms!=NULL)
	      {
	      if (parms->ctype=='p') parms=NULL;
	      else                   formal=formal->next;
	      if (parms!=NULL)       parms=formal;
	      }
	    }

	  /* skip over procedure definitions */
	  parms=formal;
	  while (parms!=NULL)
	    {
	    if (formal->ctype=='p') formal=formal->next;
	    else parms=NULL;
	    }

	  /* now positioned at globals for this block. */
	  /*   1b) MARK THEIR SYMBOLIC ADDRESSES */
	  parms=formal;
	  while (parms!=NULL)
	    {
	    if (parms->ctype=='p') parms=NULL;  /* main prog def */
	    else
	      {
	      formal->mem=strsave(formal->symbol);
	      formal=formal->next;
	      if (parms!=NULL) parms=formal;
	      }
	    }

	  /* 2: FILL IN FORMAL PARAMETER ADDRESSES */
	  /* look for the definition of the current procedure */
	  s=strsave(blks->table->symbol);
	  s[strlen(s)-1]='\0';
	  parms=sym_look_up(blks,s);
	  free(s);

	  self=parms; /* save for later filling in of return data addr */

	  /* first offset of input parms relative to fp */
	  i_loc=4+4*parms->nparms;
	  parms=parms->parms;

	  /* look up all local variables declared in the parameter list */
	  while (parms!=NULL)
	    {
	    /* consider passing only integers or reals */
	    if (parms->stype=='i' || parms->stype=='r')
	      {
	      /* map parameters to variables by offset */
	      formal=blks->table;
	      while (parms->offset!=formal->offset) formal=formal->next;
	      /* construct address */
	      sprintf(c_loc,"0(%d(fp))",i_loc);
	      formal->mem=strsave(c_loc);
	      if (formal->from<=formal->to)
		i_loc = i_loc - 4;
	      else
		i_loc = i_loc - 4;
	      }
	    parms=parms->parms;
	    }

	  /* 3: FILL IN OTHER LOCAL ADDRESSES */
	  i_loc=0; /* first offset of local variables relative to fp */
	  formal=blks->table;
	  while (formal!=NULL)
	    {
	    if ((formal->ctype=='a' || formal->ctype=='s')
		& formal->mem==NULL
		& formal->stype!='u')
	      {
	      if (formal->from<=formal->to)
		i_loc=i_loc-4*(1+formal->to-formal->from);
	      else
		i_loc=i_loc-4*(1+formal->from-formal->to);
	      sprintf(c_loc,"%d(fp)",i_loc);
	      formal->mem=strsave(c_loc);
	      }
	    formal=formal->next;
	    }

	  /* 4: FILL IN RETURN ADDRESS FOR FUNCTION PROCEDURES */
	  if (self!=NULL)
	    {
	    if (self->stype>'a')
	      {
	      i_loc=i_loc-4;
	      sprintf(c_loc,"%d(fp)",i_loc);
	      parms=sym_look_up(blks,blks->lead->flds[0]);
	      parms->mem=strsave(c_loc);
	      blks->table->mem=parms->mem;
	      }
	    }

	  blks=blks->next;
	  }
	hold_blk->next=blks;

}


/* find memory size requirements of block (for ENTER command ) */
void find_memory_size(BLOCK *blocks)
{
	int    size;
	int    max;
	int    i;
	int    frm, to;
	MOD    *temp_list;   /* list of active temps */
	MOD    *temp_hold;
	BLOCK  *blk;
	CODE   *code;
	SYMTBL *symtbl;
	MOD *remove_const_list(char *varname, MOD *list);
	MOD *insert_const_list (char *varname, char *value, MOD *list);
	MOD *find_const_list(char *varname, MOD *list);


	blocks->last->next=NULL;
	for (blk=blocks; blk!=NULL; blk=blk->next)
	  {
	  /* calculate the maximum amount of space temps will take */
	  size=0;
	  max=0;
	  temp_list=NULL;

	  /* count up temps used; keep count of maximum temps active */
	  blk->lead->last->next=NULL;
	  for (code=blk->lead; code!=NULL; code=code->next)
	    {
	    /* []= defines fields differently relative to mod and use */
	    frm=4;
	    if (!strcmp(code->flds[1],"[]=")) frm=2;
	    if (code->flds[frm][0]=='T')
	      {
	      if (NULL==find_const_list(code->flds[frm],temp_list))
		{
		size++;
		temp_list=
		   insert_const_list(code->flds[frm],"X",temp_list);
		}
	      }

	    if (max<size) max=size;

	    /* temp destruction */
	    frm=2; to=3;
	    if (!strcmp(code->flds[1],"[]="))  { frm=3; to=4; }
	    for (i=frm; i<=to; i++)
	      {
	      if (code->flds[i][0]=='T')
		{
		size--;
		temp_list=remove_const_list(code->flds[i],temp_list);
		}
	      }
	    }

	  /* clear up residual temp_list usage */
	  while (temp_list!=NULL)
	    {
	    temp_hold=temp_list->next;
	    free(temp_list->var);
	    free(temp_list);
	    temp_list=temp_hold;
	    }

	  size=max;

	  /* calculate space locals will take */
	  max=0;
	  blk->lead->last->next=blk->lead;
	  for (symtbl=blk->table; symtbl!=NULL; symtbl=symtbl->next)
	    {
	    /* find last address of local memory */
            if (symtbl->mem!=NULL)
	      {
	      if (symtbl->mem[0]=='-')
	        {
	        i=atoi(&symtbl->mem[1]);
	        if (i>max) max=i;
	        }
	      }
	    }

	  blk->memsize=4*size+max;

	  }
	blocks->last->next=blocks;

}
