/* block.c */
/* author: Edward A. Green */
/* purpose: read file and generate the BLOCK data structue for containing */
/*          the input program */

#include "proj3.h"

/***************************/
/* SUBROUTINE DECLARATIONS */
/***************************/

LABELS *add_label(LABELS *label_list, char type, char *fld, int line);

char   *strsave(char *subject);
void   parse(char *in_string, char *fld[5]);

LEADS  *make_lead_list(LEADS *lead, LABELS *label_list);

int block_num(LEADS *lead, int line);
int label_line(LABELS *label_list, char *lbl);

BLOCK *make_block(BLOCK *blocks, char *s);
void make_sym(BLOCK *blk, char *s, FILE *f);
void keep_code(BLOCK *blk, char *fld[5], int line_no);
void add_basics(BLOCK *blocks, LEADS *leads);
void connect(int a, int b, CONNECT *bb_connect);

/* GENERATE THE BLOCK DATA STRUCTURE FROM THE CODE IN THE FILE */
BLOCK *block_it(FILE *in_file, CONNECT *connect_table)
{
	LABELS *label_list;

	LEADS  *lead;

	/* INPUT FILE VARIABLES */
	char in_string[200];  /* input record */
	char *fld[5];         /* structure for parsed quad fields */
	int line_no;          /* count of non-comment lines */

	LEADS  *lst;          /* pointer into list of block leaders */
	LABELS *lbl;          /* pointer into list of labels */

	BLOCK  *blk;          /* pointer to the block list */
	BLOCK  *blocks;       /* return value */

	CODE *code;           /* index to code structure for adding basics */

	int current_block;    /* counter for assigning block numbers */
	int i;

	label_list=NULL;
	lead=NULL;
	blk=NULL;
	blocks=NULL;
	line_no=0;

	/* READ THE ENTIRE FILE: KEEP TRACK OF THE QUAD LINE NUMBERS */
	while (fgets(in_string,195,in_file)!=NULL)
	  {
	  /* Break code down starting here (non-* in 1st character) */
	  if (in_string[0]!='*')
	    {
	    line_no++;

	    /* FIELDS ARE SEPARATED WITH TABS */
	    parse(in_string,fld);

	    /* Retain the code in the block structure */
	    keep_code(blk,fld,line_no);

	    /* Keep track of Labeled statements (destination of gotos) */
	    if  ( fld[0][0]!='\0')
		    label_list=add_label(label_list,'L',fld[0],line_no);

	    /* Keep track of all Conditional gotos and calls*/
	    if (( fld[1][0]=='J' && fld[1][1]!='M')
	       || fld[1][0]=='C')
		    label_list=add_label(label_list,'C',fld[4],line_no);

	    /* Keep track of all Unconditional gotos and returns */
	    if (( fld[1][0]=='J' && fld[1][1]=='M')
	       || fld[1][0]=='R')
		    label_list=add_label(label_list,'U',fld[4],line_no);
	    }

	  /* keep symbol table as reference */
	  else
	    {
	    /* start of a new block */
	    if (in_string[1]=='B')
	      {
	      blk=make_block(blocks, in_string);
	      if (blocks==NULL) blocks=blk;
	      }

	    /* other symbols; comment lines start with "**". */
	    else if (in_string[1]!='*')
	      make_sym(blk,in_string,in_file);
	    }
	  }

	/* CALCULATE THE LEADER LINES */
	if (label_list!=NULL) lead=make_lead_list(lead, label_list);

	/* Add leader lines to blocks structure */
	add_basics(blocks,lead);

	/* CALCULATE AND DUMP THE BLOCK CONNECTION TABLE */
	current_block=0;
	lbl=label_list;
	while (lbl!=NULL)
	  {
	  if (lbl->next!=NULL)
	    {
	    if (block_num(lead, lbl->next->line)>current_block)
	      {
	      if (lbl->field!='U')
		connect(current_block, current_block+1, connect_table);
	      if (lbl->field!='L')
	        if (block_num(lead,label_line(label_list,lbl->label))>=0)
		  connect(current_block,
		       block_num(lead,label_line(label_list,lbl->label)),
		       connect_table);
	      current_block++;
	      }
	    }
	  lbl=lbl->next;
	  }

	return(blocks);
}



/*********************************************/
/* Routine to break up the quads into fields */
/*********************************************/

void parse(char *in_string, char *fld[5])
{
	int i,j;

	for (i=1; i<5; i++) fld[i]=NULL;

	fld[0]=in_string;
	for (i=0,j=1; j<6; i++)
	  {
	  if (in_string[i]=='\t')
	    {
	    in_string[i]='\0';
	    if (j<5) fld[j]=&in_string[i+1];
	    j++;
	    }
	  if (in_string[i]=='\n')
	    {
	    in_string[i]='\0';
	    if (j<5) fld[j]=&in_string[i+1];
	    j=6;
	    }
	  }
	return;
}



/****************************************************/
/* DEBUGGING ROUTINE */
/*********************/

void dump_blocks(BLOCK *blocks)
{
	CODE *code;
	SYMTBL *symtbl, *parms;
	BLOCK *blk;
	int i;

	blocks->last->next=NULL;
	for (blk=blocks; blk!=NULL; blk=blk->next)
	  {
	  printf("** Symbol table **\n");
	  printf("**name\toffset\ttype\t\tarray dim\tproc params\n");
	  printf("**----\t------\t----\t\t---------\t-----------\n");
	  for (symtbl=blk->table; symtbl!=NULL; symtbl=symtbl->next)
	    {
	    printf("**%s\t%d\t%c\t%c\t[%d %d]\t\t%d",
		    symtbl->symbol, symtbl->offset,
		    symtbl->stype, symtbl->ctype,
		    symtbl->from, symtbl->to, symtbl->nparms);
	    if (symtbl->mem!=NULL) printf("\t\"%s\"",symtbl->mem);
	    printf("\n");
	    for (parms=symtbl->parms; parms!=NULL; parms=parms->parms)
	      {
	      printf("**--->parms:\toff.=%d\t%c\t%c [%d %d]\n",
		      parms->offset, parms->stype, parms->ctype,
		      parms->from, parms->to);
	      }
	    }

	  printf("\n************************\n");

/*	  printf("** Quads **\n");
	  blk->lead->last->next=NULL;
	  for (code=blk->lead; code!=NULL; code=code->next)
	    {
	    printf("** statement number %d in block %d.\n",
	      code->line, code->basic);
	    for (i=0; i<5; i++) printf("%s\t",code->flds[i]);
	    printf("\n");
	    }
	  printf("************************\n");
*/
	  blk->lead->last->next=blk->lead;
	  }
	blocks->last->next=blocks;
	printf("\n\n");
}
