
/* 
 * $Copyright:	$
 * Copyright (c) 1984, 1985, 1986, 1987, 1988, 1989, 1990 
 * Sequent Computer Systems, Inc.   All rights reserved.
 *  
 * This software is furnished under a license and may be used
 * only in accordance with the terms of that license and with the
 * inclusion of the above copyright notice.   This software may not
 * be provided or otherwise made available to, or used by, any
 * other person.  No title to or ownership of the software is
 * hereby transferred.
 */

/*	Copyright (c) 1984 AT&T	*/
/*	  All Rights Reserved  	*/

/*	THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T	*/
/*	The copyright notice above does not evidence any   	*/
/*	actual or intended publication of such source code.	*/
#ident "$Header: body.c 1.1 90/01/19 $@(#)body.c	1.1 89/12/01"
#include "xs.h"
#include "names.h"
#include "stack.h"
#include "types.h"
#include "anal.h"
#include "body.h"
#include "catalog.h"
#include "string.h"
#include "xdefs.h"
#include "act.h"

extern char *gettxt();
/*
 * Maintain list of identifiers to be initialized dynamically
 * Scan them and generate replacement expressions
 * Maintain list of sizeof replacements variables, declare and initialize
 * them.
 * Must maintain a stack since scanning is executed at block end
 * and that nested blocks can appear meanwhile.
 *
 * Use two pointers on each list, to keep last entry and append easily
 */
typedef struct repl {
  TYPEP repl_id;
  struct repl *repl_next;
} REPL;

static struct repl_buf {
  struct repl_buf *repl_next;
} *repl_start;

static REPL *repl_glob, *nrepl_glob;
static REPL *repl_stat, *nrepl_stat;
static REPL *repl_loc, *nrepl_loc;
static REPL *repl_siz_glob, *nrepl_siz_glob;
static REPL *repl_siz_loc, *nrepl_siz_loc;
static STACK *st_repl;

void
repl_push()
{
  st_push(st_repl, (char *)repl_stat);
  st_push(st_repl, (char *)nrepl_stat);
  st_push(st_repl, (char *)repl_loc);
  st_push(st_repl, (char *)nrepl_loc);
  st_push(st_repl, (char *)repl_siz_loc);
  st_push(st_repl, (char *)nrepl_siz_loc);
  repl_stat = nrepl_stat = 0;
  repl_loc = nrepl_loc = 0;
  repl_siz_loc = nrepl_siz_loc = 0;
}

repl_pop()
{
  nrepl_siz_loc = (REPL *)st_pop(st_repl);
  repl_siz_loc = (REPL *)st_pop(st_repl);
  nrepl_loc = (REPL *)st_pop(st_repl);
  repl_loc = (REPL *)st_pop(st_repl);
  nrepl_stat = (REPL *)st_pop(st_repl);
  repl_stat = (REPL *)st_pop(st_repl);
}

repl_creat()
{
  st_repl = st_creat();
}

repl_end()
{
  st_free(st_repl);
  st_repl = 0;
}

/*
 * Common routine for replace list adding
 */
static void
repl_add(id, repl, nrepl)
  TYPEP id;
  REPL **repl, **nrepl;
{
  REPL *new, *ptr;

  if (!is_null_type(re_next(id_re(id))))
    /*
     * More than one element : already in the list
     */
    return;
    
  if (repl_start != 0){
    new = (REPL *)repl_start;
    repl_start = repl_start->repl_next;
  } else {
    new = (REPL *)malloc(sizeof(REPL));

    if (new == 0)
      fatal(gettxt("xs:24","Out of memory (body.c (1))"));
  }
  new->repl_next = 0;
  new->repl_id = id;

  if (*repl == 0)
    *repl = new;
  else
    (*nrepl)->repl_next = new;
  *nrepl = new;
}

/*
 * Generate code for initialization expressions.
 */
void
repl_init(off, repl, nrepl)
  long off;
  REPL **repl, **nrepl;
{
  REPL *ptr;
  TYPEP id, re;
  struct repl_buf *ptr2;
  
  while (*repl != 0){
    id = (*repl)->repl_id;
    re = id_re(id);
    while (!is_null_type(re)){
      if (re_flag(re) == REPL_ARRAY || re_flag(re) == REPL_SCALAR){
        /*
         * Replacement for unsized arrays or pointers
         */
        if (re_flag(re) == REPL_ARRAY)
          /*
           * one parameter for (len address) is missing.
           * replace by 0 or by the address sizeof replacement variable
           */
          act_e_insert(re_zero(re), (re_si(re) != 0) ? 
          	       "&%s, " : "(int *)0, ", re_si(re));
        act_e_append(off, "%s =", re_na(re));
        act_i_append(off, re_off(re), re_len(re));
        act_e_append(off, ";\n");
      } else
        /*
         * Replacement for sized arrays
         * replace assign expression by a function call
         */
        size_string(off, re);
      re = re_next(re);
    }
    ptr = *repl;
    *repl = (*repl)->repl_next;
    /*
     * insert repl in free list
     */
    ptr2 = (struct repl_buf *)ptr;
    ptr2->repl_next = repl_start;
    repl_start = ptr2;
  }
  *nrepl = 0;
}

/*
 * Declare sizeof replacement variables
 * if not local (if global), must insert at begin of file, else append
 * after left brace.
 */
void
decl_sizeof(off, repl, nrepl, local)
  long off;
  REPL **repl, **nrepl;
  bool local;
{
  REPL *ptr;
  struct repl_buf *ptr2;

  (*(local?act_e_append:act_e_insert))(off, "static int ");
  while (*repl != 0){
    if ((*repl)->repl_next != 0){
      (*(local?act_e_append:act_e_insert))(off, "%s,",
                                           re_si(id_re((*repl)->repl_id)));
      ptr = *repl;
      *repl = (*repl)->repl_next;
      ptr2 = (struct repl_buf *)ptr;
      ptr2->repl_next = repl_start;
      repl_start = ptr2;
      continue;
    } else {
      (*(local?act_e_append:act_e_insert))(off, "%s;\n",
                                           re_si(id_re((*repl)->repl_id)));
      ptr2 = (struct repl_buf *)*repl;
      ptr2->repl_next = repl_start;
      repl_start = ptr2;
      break;
    }
  }
  *nrepl = 0;
}

void
repl_add_global(id)
  TYPEP id;
{
  repl_add(id, &repl_glob, &nrepl_glob);
}

/*
 * Local lists are on stack and new list must be put back on stack
 */
void
repl_add_static(lev, id)
  int lev;
  TYPEP id;
{
  REPL *save_repl, *save_nrepl;
  bool save = FALSE;
  if (lev != -1 && lev * 6 != st_nelem(st_repl)){
    save = TRUE;
    save_repl = repl_stat;
    save_nrepl = nrepl_stat;
    repl_stat = (REPL *)st_elem(st_repl, lev * 6);
    nrepl_stat = (REPL *)st_elem(st_repl, lev * 6 + 1);
  }
  repl_add(id, &repl_stat, &nrepl_stat);
  if (save){
    st_set_elem(st_repl, lev * 6, (char *)repl_stat);
    st_set_elem(st_repl, lev * 6 + 1, (char *)nrepl_stat);
    repl_stat = save_repl;
    nrepl_stat = save_nrepl;
  }
}

void
repl_add_local(lev, id)
  int lev;
  TYPEP id;
  
{
  REPL *save_repl, *save_nrepl;
  bool save = FALSE;
  if (lev != -1 && lev * 6 != st_nelem(st_repl)){
    save = TRUE;
    save_repl = repl_loc;
    save_nrepl = nrepl_loc;
    repl_loc = (REPL *)st_elem(st_repl, lev * 6 + 2);
    nrepl_loc = (REPL *)st_elem(st_repl, lev * 6 + 3);
  }
  repl_add(id, &repl_loc, &nrepl_loc);
  if (save){
    st_set_elem(st_repl, lev * 6 + 2, (char *)repl_loc);
    st_set_elem(st_repl, lev * 6 + 3, (char *)nrepl_loc);
    repl_loc = save_repl;
    nrepl_loc = save_nrepl;
  }
}

void
repl_sizeof_global(id)
  TYPEP id;
{
  repl_add(id, &repl_siz_glob, &nrepl_siz_glob);
}

void
repl_sizeof_local(lev, id)
  int lev;
  TYPEP id;
{
  REPL *save_repl, *save_nrepl;
  bool save = FALSE;
  if (lev != -1 && lev  * 6 != st_nelem(st_repl)){
    save = TRUE;
    save_repl = repl_siz_loc;
    save_nrepl = nrepl_siz_loc;
    repl_siz_loc = (REPL *)st_elem(st_repl, lev * 6 + 4);
    nrepl_siz_loc = (REPL *)st_elem(st_repl, lev * 6 + 5);
  }
  repl_add(id, &repl_siz_loc, &nrepl_siz_loc);
  if (save){
    st_set_elem(st_repl, lev * 6 + 4, (char *)repl_siz_loc);
    st_set_elem(st_repl, lev * 6 + 5, (char *)nrepl_siz_loc);
    repl_siz_loc = save_repl;
    nrepl_siz_loc = save_nrepl;
  }
}

/*
 * Process replacements when reaching end of block
 * - Declare a flag variable that will insure that static variables
 *   are only initialized once.
 * - Declare local sizeof variables
 * - generate call to general initialization if routine is "main"
 * - generate initialization expressions, (static ones are flagged by
 *   previously declared variable
 */
void
do_body(begin, dcl_list)
  TOKEN begin, dcl_list;
{
  long off = (dcl_list.t_off == 0) ? begin.t_off +begin.t_len-1:dcl_list.t_off;
  char *statvar;
  
  if (repl_siz_loc != 0)
    decl_sizeof(off, &repl_siz_loc, &nrepl_siz_loc, TRUE);

  if(repl_stat != 0){
    statvar = na_unique();
    act_e_append(off, "static int %s;\n", statvar);
  }

  do_main3(off);  
    
  if (repl_stat != 0){
    act_e_append(off, "if (%s == 0){\n", statvar);
    repl_init(off, &repl_stat, &nrepl_stat);
    act_e_append(off, "%s = 1;\n}\n", statvar);
  }
  if (repl_loc != 0)
    repl_init(off, &repl_loc, &nrepl_loc);
}

/*
 * Processing at end of function
 */
void
do_function()
{
  msg_f_end(fd_msg);
}

/*
 * Global replacement processing
 * - Declare static var that will hold the set number
 * - Declare static sizeof replacements vars (if needed)
 * - Append function at end of file that will receive the current set nr
 *   as a parameter and must assign it to the previously declared variable
 *   and generate replacement expressions for global variables.
 */
void
do_global()
{
  char *name = na_unique();

  act_e_insert(0L, "static int %s;\n", var_set_nr);

  if (repl_siz_glob != 0)
    decl_sizeof(0L, &repl_siz_glob, &nrepl_siz_glob, FALSE);

  act_e_append(lastoff - 1, "%s(%s)\nint %s;\n{", func_name, name, name);
  act_e_append(lastoff - 1, "%s = %s;\n", var_set_nr, name);

  if (repl_glob != 0)
    repl_init(lastoff - 1, &repl_glob, &nrepl_glob);

  act_e_append(lastoff - 1, "}\n");
}

/*
 * Start of file processing
 * - Declare replacement function (char *....()) to avoid warnings and
 *   compiling errors.
 */
void
do_start()
{
  act_e_insert(0L, "char *%s();\n", replace_strings);
  msg_start(fd_msg);
}
