/* $Id: $ */

/* Copyright (C) 1998 Sverre Hvammen Johansen,
 * Department of Informatics, University of Oslo.
 *
 * 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; version 2.
 *
 * 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; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */

#include <stdio.h>
#include <obstack.h>

#include "gen.h"

char *xmalloc();
void free();

#define obstack_chunk_alloc xmalloc
#define obstack_chunk_free free

static struct obstack osStack;
static struct obstack osSent;

struct SENT module;

/******************************************************************************
                                                                       SPUSH */

static spush(re)struct EXP *re;
{
#if 0
  obstack_ptr_grow (&osStack, re);
#else
  obstack_grow(&osStack, &re, sizeof (void *));
#endif
}

/******************************************************************************
                                                                        SPOP */

static struct SENT *spop()
{
  struct SENT *rs;
  rs= * ((struct SENT * *)obstack_next_free (&osStack) - 1);
  obstack_blank (&osStack, - sizeof (void *));
  rs->lastLine= lineno;
  return (rs);
}

/******************************************************************************
                                                                       SLOOK */

struct SENT *slook()
{
  return *((struct SENT * *)obstack_next_free (&osStack) - 1);
}

/******************************************************************************
                                                                SBUILDERINIT */

sbuilderInit()
{
  obstack_init(&osStack);
  obstack_init(&osSent);
  module.token= MMODULE;
  spush (&module);
}

char nonetest = ON;
char indextest = ON;
char stripsideeffects = OFF;

/******************************************************************************
                                                                     NEWSENT */

struct SENT *newSent(token) int token;
{
  struct SENT *new;
  new= (struct SENT *)obstack_alloc (&osSent, sizeof (struct SENT));
  memset (new, 0, sizeof (struct SENT));

  new->token= token;
  new->line= lineno;

  return new;
}

/******************************************************************************
                                                                  CREATESENT */

static struct SENT *createSent(token, exp) int token; struct EXP *exp;
{
  struct SENT *new= newSent (token), *parent;

  new->exp= exp;
  new->nonetest= nonetest;
  new->indextest= indextest;
  new->stripsideeffects= stripsideeffects;

  parent= slook ();
  if (parent->first == NULL)
    {
      parent->first= parent->last= new;
    } 
  else
    {
      parent->last->next= new;
      new->prev= parent->last;
      parent->last= new;
    }
  return new;
}

/******************************************************************************
                                                                  INSERTSENT */

void insertAfterSent (parent, after, new) struct SENT *parent, *after, *new;
{
  if (after == NULL)
    {
      if (parent->first == NULL)
	{
	  parent->first= parent->last= new;
	} 
      else
	{
	  parent->first->prev= new;
	  new->next= parent->first;
	  parent->first= new;
	}
    }
  else
    {
      if (after->next == NULL)
	{
	  new->prev= after;
	  after->next= parent->last= new;
	} 
      else
	{
	  after->next->prev= new;
	  new->next= after->next;
	  after->next= new;
	  new->prev= after;
	}
    }
}

void insertBeforeSent (parent, before, new) struct SENT *parent, *before, *new;
{
  if (before == NULL)
    insertAfterSent (parent, parent->last, new);
  else
    insertAfterSent (parent, before->prev, new);
}

/******************************************************************************
                                                                  REMOVESENT */

void removeSent(parent, rem) struct SENT *parent, *rem;
{
  if (rem->next == NULL)
    {
      parent->last= rem->prev;
    }
  else
    {
      rem->next->prev= rem->prev;
    }

  if (rem->prev == NULL)
    {
      parent->first= rem->next;
    }
  else
    {
      rem->prev->next= rem->next;
      rem->prev=NULL;
    }
  rem->next= NULL;
}

/******************************************************************************
                                                                   SETFLAG   */

void setFlag ()
{
  unsigned char token;
  token= min();
  switch (token)
    {
    case MNONETEST:
      nonetest = OFF;
      break;
    case MNONETEST + 1:
      nonetest = ON;
      break;
    case MINDEXTEST:
      indextest = OFF;
      break;
    case MINDEXTEST + 1:
      indextest = ON;
      break;
    case MSTRIPSIDEEFFECTS:
      stripsideeffects = OFF;
      break;
    case MSTRIPSIDEEFFECTS + 1:
      stripsideeffects = ON;
      break;
    }
}



/******************************************************************************
                                                                      SBUILD */

struct SENT *sbuild()
{
  token= min();
  while (1)
    {
      switch (token)
	{
	case MCONST:
	case MGOTO:
	case MENDSWITCH:
	case MENDASSIGN:
	case MENDARRAY:
	case MENDLABEL:
	  createSent (token, elook());
	  break;
	case MPRBLOCK:
	case MFORDO:
	case MWHILE:
	case MINSPECT:
	case MDO:
	case MWHEN:
	  spush (createSent (token, elook()));
	  break;
	case MBLOCK:
	case MPROCEDURE:
	case MCLASS:
	case MOTHERWISE:
	  spush (createSent (token, NULL));
	  break;
	case MENDBLOCK:
	case MENDPRBLOCK:
	case MENDPROCEDURE:
	case MENDCLASS:
	case MENDINSPECT:
	case MENDWHEN:
	case MENDFOR:
	case MENDDO:
	case MENDOTHERWISE:
	case MENDWHILE:
	  spop();
	  break;
	case MIF:
	  spush (createSent (token, elook()));
	  spush (createSent (MTHEN, NULL));
	  break;
	case MELSE:
	  spop ();
	  spush (createSent (token, elook()));
	  break;
	case MENDIF:
	  spop ();
	  spop ();
	  break;
	case MINNER:
	  createSent (token, NULL);
	  break;
	case MSTOP:
	  return &module;
	  break;
	case MERROR:
	  /* NOTTHING */
	  break;
	case MNEWLINE:
	  lineno++;
	  break;
	case MFLAG:
	  setFlag ();
	  break;
	default:
	  {
	    char *p;
	    p= mpointer;
	    ebuild ();
	    if (p == mpointer)
	      serror (71, token);
	    continue;
	  }
	}
      token= min();
    }
}

/******************************************************************************
								INSERT_THUNK */

void insert_thunk (rex, token) struct EXP *rex; int token;
{
  struct SENT *new= newSent (token);
  if (token == MTHUNKSIMPLEVALUE)
    rex->token= MSENDVALUETHUNKTOFORMALPAR;
  else
    rex->token= MSENDADDRESSTHUNKTOFORMALPAR;
  new->exp= rex;
  new->cblock= cblock;
  rex->value.thunk.label= newlabel ();
  
  rex->value.thunk.inthunk= inthunk+1;
  insertBeforeSent (mainSent, NULL, new);
}


syntax highlighted by Code2HTML, v. 0.9.1