#include "rtt.h"

/*
 * node0 - create a syntax tree leaf node.
 */
struct node *node0(int id, struct token *tok)
   {
   struct node *n;

   n = NewNode(0);
   n->nd_id = id;
   n->tok = tok;
   return n;
   }

/*
 * node1 - create a syntax tree node with one child.
 */
struct node *node1(int id, struct token *tok, struct node *n1)
   {
   struct node *n;

   n = NewNode(1);
   n->nd_id = id;
   n->tok = tok;
   n->u[0].child = n1;
   return n;
   }

/*
 * node2 - create a syntax tree node with two children.
 */
struct node *node2(int id, struct token *tok, struct node *n1, struct node *n2)
   {
   struct node *n;

   n = NewNode(2);
   n->nd_id = id;
   n->tok = tok;
   n->u[0].child = n1;
   n->u[1].child = n2;
   return n;
   }

/*
 * node3 - create a syntax tree node with three children.
 */
struct node *node3(int id, struct token *tok,
   struct node *n1, struct node *n2, struct node *n3)
   {
   struct node *n;

   n = NewNode(3);
   n->nd_id = id;
   n->tok = tok;
   n->u[0].child = n1;
   n->u[1].child = n2;
   n->u[2].child = n3;
   return n;
   }

/*
 * node4 - create a syntax tree node with four children.
 */
struct node *node4(int id, struct token *tok,
   struct node *n1, struct node *n2, struct node *n3, struct node *n4)
   {
   struct node *n;

   n = NewNode(4);
   n->nd_id = id;
   n->tok = tok;
   n->u[0].child = n1;
   n->u[1].child = n2;
   n->u[2].child = n3;
   n->u[3].child = n4;
   return n;
   }

/*
 * sym_node - create a syntax tree node for a variable. If the identifier
 *  is in the symbol table, create a node that references the entry,
 *  otherwise create a simple leaf node.
 */
struct node *sym_node(struct token *tok)
   {
   struct sym_entry *sym;
   struct node *n;

   sym = sym_lkup(tok->image);
   if (sym != NULL) {
      n = NewNode(1);
      n->nd_id = SymNd;
      n->tok = tok;
      n->u[0].sym = sym;
      ++sym->ref_cnt;
      /*
       * If this is the result location of an operation, note that it
       *  is explicitly referenced.
       */
      if (sym->id_type == RsltLoc)
         sym->u.referenced = 1;
      return n;
      }
   else
      return node0(PrimryNd, tok);
   }

/*
 * comp_nd - create a node for a compound statement.
 */
struct node *comp_nd(struct token *tok, struct node *dcls, struct node *stmts)
   {
   struct node *n;

   n = NewNode(3);
   n->nd_id = CompNd;
   n->tok = tok;
   n->u[0].child = dcls;
   n->u[1].sym = dcl_stk->tended; /* tended declarations are not in dcls */
   n->u[2].child = stmts;
   return n;
   }

/*
 * arith_nd - create a node for an arith_case statement.
 */
struct node *arith_nd(struct token *tok, struct node *p1, struct node *p2,
   struct node *c_int, struct node *ci_act, struct node *intgr,
   struct node *i_act, struct node *dbl, struct node *d_act)
   {
   struct node *n;

   /*
    * Insure the cases are what we expect.
    */
   if (c_int->tok->tok_id != C_Integer)
      errt3(c_int->tok, "expected \"C_integer\", found \"", c_int->tok->image,
         "\"");
   if (intgr->tok->image != icontypes[int_typ].id)
      errt3(intgr->tok, "expected \"integer\", found \"", intgr->tok->image,
         "\"");
   if (dbl->tok->tok_id != C_Double)
      errt3(dbl->tok, "expected \"C_double\", found \"", dbl->tok->image,
         "\"");

   /*
    * Indicate in the symbol table that the arguments are converted to C
    *  values.
    */
   dst_alloc(c_int, p1);
   dst_alloc(c_int, p2);
   dst_alloc(dbl, p1);
   dst_alloc(dbl, p2);

   free_tree(c_int);
   free_tree(intgr);
   free_tree(dbl);

   n = node3(TrnryNd, NULL, ci_act, i_act, d_act);
   return node3(TrnryNd, tok, p1, p2, n);
   }

struct node *dest_node(struct token *tok)
   {
   struct node *n;
   int typcd;

   n = sym_node(tok);
   typcd = n->u[0].sym->u.typ_indx;
   if (typcd != int_typ && typcd != str_typ && typcd != cset_typ &&
      typcd != real_typ)
      errt2(tok, "cannot convert to ", tok->image);
   return n;
   }


/*
 * free_tree - free storage for a syntax tree.
 */
void free_tree(struct node *n)
   {
   struct sym_entry *sym, *sym1;

   if (n == NULL)
      return;

   /*
    * Free any subtrees and other referenced storage.
    */
   switch (n->nd_id) {
      case SymNd:
         free_sym(n->u[0].sym); /* Indicate one less reference to symbol */
         break;

      case CompNd:
         /*
          * Compound node. Free ordinary declarations, tended declarations,
          *  and executable code.
          */
         free_tree(n->u[0].child);
         sym = n->u[1].sym;
         while (sym != NULL) {
            sym1 = sym;
            sym = sym->u.tnd_var.next;
            free_sym(sym1);
            }
         free_tree(n->u[2].child);
         break;

      case QuadNd:
         free_tree(n->u[3].child);
         /* fall thru to next case */
      case TrnryNd:
         free_tree(n->u[2].child);
         /* fall thru to next case */
      case AbstrNd: case BinryNd: case CommaNd: case ConCatNd: case LstNd:
      case StrDclNd:
         free_tree(n->u[1].child);
         /* fall thru to next case */
      case IcnTypNd: case PstfxNd: case PreSpcNd: case PrefxNd:
         free_tree(n->u[0].child);
         /* fall thru to next case */
      case ExactCnv: case PrimryNd:
         break;

      default:
         fprintf(stdout, "rtt internal error: unknown node type\n");
         exit(EXIT_FAILURE);
         }
   free_t(n->tok);             /* free token */
   free((char *)n);
   }
