/* parse.c: -*- C -*-  DESCRIPTIVE TEXT. */

/*  Copyright (c) 1996 Universal Access Inc.
    Author: E. B. Gamble Jr. (ebg@ai.mit.edu) Wed Nov  6 16:27:20 1996.  */

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <assert.h>
#include <ctype.h>

#include "compile.h"

static void
bc_parse_fail (bc_parse_t parse,
	       bc_string_t message)
{
  printf (";; Parse Failure: %s\n", message);
  fail ();
}

/*
 * Primitive BC_PARSE_T Constructors
 *
 */
static bc_parse_t
bc_parse_new (bc_parse_op_t op)
{
  bc_parse_t parse = (bc_parse_t) xmalloc (sizeof (struct bc_parse));
  BC_PARSE_OP   (parse) = op;
  BC_PARSE_NEXT (parse) = BC_PARSE_NULL;
  return (parse);
}

static bc_parse_t
bc_parse_symbol_new (bc_symbol_t symbol, bc_string_t string)
{
  bc_parse_t parse = bc_parse_new (BC_PARSE_OP_SYMBOL);
  BC_PARSE_SYMBOL_SYMBOL (parse) = symbol;
  BC_PARSE_SYMBOL_STRING (parse) = string;
  return (parse);
}

static bc_parse_t
bc_parse_string_new (bc_string_t string)
{
  bc_parse_t parse = bc_parse_new (BC_PARSE_OP_STRING);
  BC_PARSE_STRING (parse) = string;
  return (parse);
}

static bc_parse_t
bc_parse_number_new (bc_number_t number, bc_string_t string)
{
  bc_parse_t parse = bc_parse_new (BC_PARSE_OP_NUMBER);
  BC_PARSE_NUMBER_NUMBER (parse) = number;
  BC_PARSE_NUMBER_STRING (parse) = string;
  return (parse);
}

static bc_parse_t
bc_parse_text_new (bc_format_t format, bc_parse_t tags)
{
  bc_parse_t parse = bc_parse_new (BC_PARSE_OP_TEXT);
  BC_PARSE_TEXT_FORMAT (parse) = format;
  BC_PARSE_TEXT_TAGS   (parse) = tags;
  return (parse);
}

static bc_parse_t
bc_parse_tag_new (bc_format_t format, bc_parse_t  tags)
{
  bc_parse_t parse = bc_parse_new (BC_PARSE_OP_TAG);
  BC_PARSE_TAG_FORMAT (parse) = format;
  BC_PARSE_TAG_TAGS   (parse) = tags;
  return (parse);
}

static bc_parse_t
bc_parse_key_new (bc_format_t format, bc_parse_t  name, bc_parse_t  value)
{
  bc_parse_t parse = bc_parse_new (BC_PARSE_OP_KEY);
  BC_PARSE_KEY_FORMAT (parse) = format;
  BC_PARSE_KEY_NAME   (parse) = name;
  BC_PARSE_KEY_VALUE  (parse) = value;
  return (parse);
}

static bc_parse_t
bc_parse_blk_new (bc_parse_t tag, bc_parse_t body)
{
  bc_parse_t parse = bc_parse_new (BC_PARSE_OP_BLK);
  BC_PARSE_BLK_TAG  (parse) = tag;
  BC_PARSE_BLK_BODY (parse) = body;
  return (parse);
}

static void
bc_parse_append (bc_parse_t parse_1, bc_parse_t parse_2)
{
  /* What if parse_1 is NULL? */

  /* Find the last bc_parse_t in PARSE_1. */
  while (BC_PARSE_NEXT (parse_1))
    parse_1 = BC_PARSE_NEXT (parse_1);

  /* Modify the next bc_parse_t to be PARSE_2. */
  BC_PARSE_NEXT (parse_1) = parse_2;
}

/* Return the number of parses linked from PARSE. */
unsigned int
bc_parse_count (bc_parse_t parse)
{
  unsigned int count;
  for (count = 0; parse; parse = BC_PARSE_NEXT (parse))
    count++;
  return (count);
}

/**************************************************************************
 *
 *  BC_PARSE_SHOW ()
 *
 * Forward Declaration */
static void
bc_parse_show_1 (bc_parse_t parse, unsigned int indent_1,
		 unsigned int indent_2);

/* Print a COUNT spaces */
static void spaces (unsigned int count) { while (count--) putchar (' '); }

/* Print a NEWLINE */
static void newline (void) { putchar ('\n'); }

/* Show a list (via BC_PARSE_NEXT) of PARSES */
static void 
bc_parse_show_list_1 (bc_parse_t parse,
		      unsigned int indent_1, unsigned int indent_2)
{
  for ( ; parse; parse = BC_PARSE_NEXT (parse))
    {
      bc_parse_show_1 (parse, indent_1, indent_2);
      if (BC_PARSE_NEXT (parse))
	newline();
    }
}

static void
bc_parse_show_format_1 (bc_format_t  format,
			unsigned int indent_1,
			unsigned int indent_2)
{
  spaces (indent_1);
  printf ("<FMT");
  for (; format; format = BC_FORMAT_NEXT (format))
    switch (BC_FORMAT_TYPE (format))
      {
      case BC_INDEX_TYPE:
	printf (" %d", (bc_index_t) BC_FORMAT_OBJECT (format));
	break;
      case BC_STRING_TYPE:
	printf (" \"%s\"", (bc_string_t) BC_FORMAT_OBJECT (format));
	break;
      default:
	printf (" ???");
	break;
      }
  printf (">");
}
	      
/* Show a single PARSE */
static void
bc_parse_show_1 (bc_parse_t parse,
		 unsigned int indent_1,
		 unsigned int indent_2)
{
  spaces (indent_1);
  switch (BC_PARSE_OP (parse))
    {
    case BC_PARSE_OP_SYMBOL:
      printf ("<SYM %s>", BC_PARSE_SYMBOL_STRING (parse));
      break;
    case BC_PARSE_OP_STRING:
      printf ("\"%s\"", BC_PARSE_STRING (parse));
      break;
    case BC_PARSE_OP_NUMBER:
      printf ("%s", BC_PARSE_NUMBER_STRING (parse));
      break;
    case BC_PARSE_OP_TEXT:
      printf ("<TEXT");
      bc_parse_show_format_1 (BC_PARSE_TEXT_FORMAT (parse), 1, 7 + indent_1);
      newline();
      spaces (indent_2);
      bc_parse_show_list_1 (BC_PARSE_TEXT_TAGS (parse), 1, 7 + indent_1);
      printf (">");
      break;
    case BC_PARSE_OP_TAG:
      printf ("<TAG");
      bc_parse_show_format_1 (BC_PARSE_TAG_FORMAT (parse), 1, 5 + indent_1);
      newline ();
      bc_parse_show_1 (BC_PARSE_TAG_OPERATOR (parse),
		       5 + indent_1,
		       5 + indent_1);
      newline ();
      bc_parse_show_list_1 (BC_PARSE_TAG_OPERANDS (parse),
			    5 + indent_1,
			    5 + indent_1);
      printf (">");
      break;
    case BC_PARSE_OP_KEY:
      printf ("<KEY");
      bc_parse_show_format_1 (BC_PARSE_KEY_FORMAT (parse), 1, 5 + indent_1);
      newline ();
      bc_parse_show_1 (BC_PARSE_KEY_NAME (parse),
		       5 + indent_1,
		       5 + indent_1);
      newline ();
      bc_parse_show_1 (BC_PARSE_KEY_VALUE (parse),
		       5 + indent_1,
		       5 + indent_1);
      printf (">");
      break;

    case BC_PARSE_OP_BLK:
      printf ("<BLK");
      bc_parse_show_1 (BC_PARSE_BLK_TAG (parse), 1, 5 + indent_1);
      newline ();
      bc_parse_show_1 (BC_PARSE_BLK_BODY (parse),
		       5 + indent_1,
		       5 + indent_1);
      printf (">");
      break;
    default:
      break;
    }
}

/* Show a single PARSE */
extern void
bc_parse_show (bc_parse_t parse)
{
  bc_parse_show_1 (parse, 0, 0);
  fflush (stdout);
}

  
/*************************************************************************
 *
 * Ignore These....
 *
 */
static void
bc_parse_whitespace (bc_string_t *str_ptr)
{
  bc_string_t str = *str_ptr;
  /* Advance STR_PTR over whitespace */
  while (isspace (*str))
    str++;
  *str_ptr = str;
  return;
}

static bc_string_t
bc_string_new (unsigned int size)
{
  return (malloc (size));
}

static bc_string_t
bc_parse_string (bc_string_t string, size_t length)
{
  bc_string_t new = bc_string_new (1 + length);
  strncat (new, string, length);
  new[length] = '\0';
  return (new);
}

static bc_parse_t
bc_parse_symbol (bc_string_t *str_ptr)
{
  bc_string_t string, str = *str_ptr;
  bc_symbol_t symbol;
  bc_parse_t  parse;
  
  /* Advance STR_PTR over alphanumerics */
  while (isalnum (*str))
    str++;

  /* Build a bc_parse_t STRING */
  string = bc_parse_string (*str_ptr, str - *str_ptr);

  /* Don't forget this */
  *str_ptr = str;

  /* Lookup/Intern a Symbol */
  symbol = bc_symbol_intern (string);
    
  /* Fill out PARSE */
  parse  = bc_parse_new (BC_PARSE_OP_SYMBOL);
  BC_PARSE_NEXT (parse) = (bc_parse_t) NULL;
  BC_PARSE_SYMBOL_STRING (parse) = string;
  BC_PARSE_SYMBOL_SYMBOL (parse) = symbol;

  return (parse);
}

static bc_parse_t
bc_parse_tag (bc_string_t string)
{
  return ((bc_parse_t) NULL);
}

static bc_parse_t
bc_parse_text (bc_string_t str)
{
  while (*str)
    {
      switch (*str)
	{
	case '<':
	  /* Close off str, add to CAT */
	  {
	    unsigned int next_index = 0;
	    /*	    bc_parse_t tag = bc_parse_tag (str);*/  /* & index */
	    
	    /* Add TAG to TEXT */
	    str += next_index;
	  }
	  break;

	default:
	  str++;
	  break;
	}
    }
  return ((bc_parse_t) NULL);
}

static bc_parse_t
bc_parse_both (bc_string_t string)
{
  return ((bc_parse_t) NULL);
}

bc_parse_t 
bc_parse (bc_string_t string)
{
  /*  unsigned int index = 0; */

  bc_parse_t parse =
    (('<' == *string)
     ? bc_parse_tag (string)
     : bc_parse_text (string));

  return (parse);
}


/*************************************************************************
 *
 *
 *
 */
#if defined (TEST)

/************************************************************************
 *
 * If
 *
 */
static struct bc_format format_if_1 [5] =
{
  { BC_STRING_TYPE, (bc_object_t) "<if ", BC_FORMAT_NULL },
  { BC_INDEX_TYPE,  (bc_object_t) 1,      BC_FORMAT_NULL },
  { BC_STRING_TYPE, (bc_object_t) " ",    BC_FORMAT_NULL },
  { BC_INDEX_TYPE,  (bc_object_t) 2,      BC_FORMAT_NULL },
  { BC_STRING_TYPE, (bc_object_t) ">",    BC_FORMAT_NULL }
};

static struct bc_format format_if_2 =
{
  BC_STRING_TYPE, (bc_object_t) "<get-var xyz>", BC_FORMAT_NULL
};

static bc_parse_t
parse_if_test (void)
{
  /* <if "abc" <get-var xyz>> */

  /* {TAG (CAT "<if " 1 " " 2 ">")
          {SYM if}
          (STR "abc"}
	  {TAG (CAT "<get-var xyz>"
	       (SYM get-var)
	       (SYM xyz))))
	       */
  bc_parse_t
    sym_if  = bc_parse_symbol_new (bc_symbol_intern ("if"), "if"),
    sym_get = bc_parse_symbol_new (bc_symbol_intern ("get-var"), "get-var"),
    sym_xyz = bc_parse_symbol_new (bc_symbol_intern ("xyz"), "xyz"),
    str_abc = bc_parse_string_new ("abc");

  bc_parse_t tag_1, cat_2, tag_2;

  BC_PARSE_NEXT (sym_get) = sym_xyz;
  tag_2 = bc_parse_tag_new (& format_if_2, sym_get);
  
  /* Link together format_if_1 */
  BC_FORMAT_NEXT (& format_if_1 [0]) = & format_if_1 [1];
  BC_FORMAT_NEXT (& format_if_1 [1]) = & format_if_1 [2];
  BC_FORMAT_NEXT (& format_if_1 [2]) = & format_if_1 [3];
  BC_FORMAT_NEXT (& format_if_1 [3]) = & format_if_1 [4];
  
  BC_PARSE_NEXT (str_abc) = tag_2;
  BC_PARSE_NEXT (sym_if)  = str_abc;
  tag_1 = bc_parse_tag_new (& format_if_1 [0], sym_if);
  return (tag_1);
}

/************************************************************************
 *
 * NOT
 *
 */
static struct bc_format format_not_1 [5] =
{
  { BC_STRING_TYPE, (bc_object_t) "<if ", BC_FORMAT_NULL },
  { BC_INDEX_TYPE,  (bc_object_t) 1,      BC_FORMAT_NULL },
  { BC_STRING_TYPE, (bc_object_t) " ",    BC_FORMAT_NULL },
  { BC_INDEX_TYPE,  (bc_object_t) 2,      BC_FORMAT_NULL },
  { BC_STRING_TYPE, (bc_object_t) ">",    BC_FORMAT_NULL }
};

static struct bc_format format_not_2 =
{
  BC_STRING_TYPE, (bc_object_t) "<not xyz>", BC_FORMAT_NULL
};

static bc_parse_t
parse_not_test (void)
{
  /* <if "abc" <not xyz>> */

  /* {TAG (CAT "<if " 1 " " 2 ">")
          {SYM if}
          (STR "abc"}
	  {TAG (CAT "<not xyz>"
	       (SYM not)
	       (SYM xyz))))
	       */
  bc_parse_t
    sym_if  = bc_parse_symbol_new (bc_symbol_intern ("if"), "if"),
    sym_get = bc_parse_symbol_new (bc_symbol_intern ("not"), "not"),
    sym_xyz = bc_parse_symbol_new (bc_symbol_intern ("xyz"), "xyz"),
    str_abc = bc_parse_string_new ("abc");

  bc_parse_t tag_1, tag_2;

  BC_PARSE_NEXT (sym_get) = sym_xyz;
  tag_2 = bc_parse_tag_new (& format_not_2, sym_get);
  
  /* Link together format_not_1 */
  BC_FORMAT_NEXT (& format_not_1 [0]) = & format_not_1 [1];
  BC_FORMAT_NEXT (& format_not_1 [1]) = & format_not_1 [2];
  BC_FORMAT_NEXT (& format_not_1 [2]) = & format_not_1 [3];
  BC_FORMAT_NEXT (& format_not_1 [3]) = & format_not_1 [4];
  
  BC_PARSE_NEXT (str_abc) = tag_2;
  BC_PARSE_NEXT (sym_if)  = str_abc;
  tag_1 = bc_parse_tag_new (& format_not_1[0], sym_if);
  return (tag_1);
}

/************************************************************************
 *
 * prog
 *
 */
static struct bc_format format_prog_1 [5] =
{
  { BC_STRING_TYPE, (bc_object_t) "<prog ", BC_FORMAT_NULL },
  { BC_INDEX_TYPE,  (bc_object_t) 1,      BC_FORMAT_NULL },
  { BC_STRING_TYPE, (bc_object_t) " ",    BC_FORMAT_NULL },
  { BC_INDEX_TYPE,  (bc_object_t) 2,      BC_FORMAT_NULL },
  { BC_STRING_TYPE, (bc_object_t) ">",    BC_FORMAT_NULL }
};

static struct bc_format format_prog_2 =
{
  BC_STRING_TYPE, (bc_object_t) "<not xyz>", BC_FORMAT_NULL
};

static bc_parse_t
parse_prog_test (void)
{
  /* <prog "abc" <not xyz>> */

  /* {TAG (CAT "<prog " 1 " " 2 ">")
          {SYM prog}
          (STR "abc"}
	  {TAG (CAT "<not xyz>"
	       (SYM not)
	       (SYM xyz))))
	       */
  bc_parse_t
    sym_if  = bc_parse_symbol_new (bc_symbol_intern ("prog"), "prog"),
    sym_get = bc_parse_symbol_new (bc_symbol_intern ("not"),  "not"),
    sym_xyz = bc_parse_symbol_new (bc_symbol_intern ("xyz"),  "xyz"),
    str_abc = bc_parse_string_new ("abc");

  bc_parse_t tag_1, tag_2;

  BC_PARSE_NEXT (sym_get) = sym_xyz;
  tag_2 = bc_parse_tag_new (& format_prog_2, sym_get);
  
  /* Link together format_prog_1 */
  BC_FORMAT_NEXT (& format_prog_1 [0]) = & format_prog_1 [1];
  BC_FORMAT_NEXT (& format_prog_1 [1]) = & format_prog_1 [2];
  BC_FORMAT_NEXT (& format_prog_1 [2]) = & format_prog_1 [3];
  BC_FORMAT_NEXT (& format_prog_1 [3]) = & format_prog_1 [4];
  
  BC_PARSE_NEXT (str_abc) = tag_2;
  BC_PARSE_NEXT (sym_if)  = str_abc;
  tag_1 = bc_parse_tag_new (& format_prog_1[0], sym_if);
  return (tag_1);
}

/************************************************************************
 *
 * And
 *
 */
static struct bc_format format_and_1 [5] =
{
  { BC_STRING_TYPE, (bc_object_t) "<and ", BC_FORMAT_NULL },
  { BC_INDEX_TYPE,  (bc_object_t) 1,      BC_FORMAT_NULL },
  { BC_STRING_TYPE, (bc_object_t) " ",    BC_FORMAT_NULL },
  { BC_INDEX_TYPE,  (bc_object_t) 2,      BC_FORMAT_NULL },
  { BC_STRING_TYPE, (bc_object_t) ">",    BC_FORMAT_NULL }
};

static struct bc_format format_and_2 =
{
  BC_STRING_TYPE, (bc_object_t) "<get-var xyz>", BC_FORMAT_NULL
};

static bc_parse_t
parse_and_test (void)
{
  /* <and "abc" <get-var xyz>> */

  /* {TAG (CAT "<and " 1 " " 2 ">")
          {SYM and}
          (STR "abc"}
	  {TAG (CAT "<get-var xyz>"
	       (SYM get-var)
	       (SYM xyz))))
	       */
  bc_parse_t
    sym_and  = bc_parse_symbol_new (bc_symbol_intern ("and"), "and"),
    sym_get = bc_parse_symbol_new (bc_symbol_intern ("get-var"), "get-var"),
    sym_xyz = bc_parse_symbol_new (bc_symbol_intern ("xyz"), "xyz"),
    str_abc = bc_parse_string_new ("abc");

  bc_parse_t tag_1, tag_2;

  BC_PARSE_NEXT (sym_get) = sym_xyz;
  tag_2 = bc_parse_tag_new (& format_and_2, sym_get);
  
  /* Link together format_and_1 */
  BC_FORMAT_NEXT (& format_and_1 [0]) = & format_and_1 [1];
  BC_FORMAT_NEXT (& format_and_1 [1]) = & format_and_1 [2];
  BC_FORMAT_NEXT (& format_and_1 [2]) = & format_and_1 [3];
  BC_FORMAT_NEXT (& format_and_1 [3]) = & format_and_1 [4];
  
  BC_PARSE_NEXT (str_abc) = tag_2;
  BC_PARSE_NEXT (sym_and) = str_abc;
  tag_1 = bc_parse_tag_new (& format_and_1[0], sym_and);
  return (tag_1);
}

/************************************************************************
 *
 * Or
 *
 */
static struct bc_format format_or_1 [5] =
{
  { BC_STRING_TYPE, (bc_object_t) "<or ", BC_FORMAT_NULL },
  { BC_INDEX_TYPE,  (bc_object_t) 1,      BC_FORMAT_NULL },
  { BC_STRING_TYPE, (bc_object_t) " ",    BC_FORMAT_NULL },
  { BC_INDEX_TYPE,  (bc_object_t) 2,      BC_FORMAT_NULL },
  { BC_STRING_TYPE, (bc_object_t) ">",    BC_FORMAT_NULL }
};

static struct bc_format format_or_2 =
{
  BC_STRING_TYPE, (bc_object_t) "<get-var xyz>", BC_FORMAT_NULL
};

static bc_parse_t
parse_or_test (void)
{
  /* <or "abc" <get-var xyz>> */

  /* {TAG (CAT "<or " 1 " " 2 ">")
          {SYM or}
          (STR "abc"}
	  {TAG (CAT "<get-var xyz>"
	       (SYM get-var)
	       (SYM xyz))))
	       */
  bc_parse_t
    sym_or  = bc_parse_symbol_new (bc_symbol_intern ("or"), "or"),
    sym_get = bc_parse_symbol_new (bc_symbol_intern ("get-var"), "get-var"),
    sym_xyz = bc_parse_symbol_new (bc_symbol_intern ("xyz"), "xyz"),
    str_abc = bc_parse_string_new ("abc");

  bc_parse_t tag_1, tag_2;

  BC_PARSE_NEXT (sym_get) = sym_xyz;
  tag_2 = bc_parse_tag_new (& format_or_2, sym_get);
  
  /* Link together format_or_1 */
  BC_FORMAT_NEXT (& format_or_1 [0]) = & format_or_1 [1];
  BC_FORMAT_NEXT (& format_or_1 [1]) = & format_or_1 [2];
  BC_FORMAT_NEXT (& format_or_1 [2]) = & format_or_1 [3];
  BC_FORMAT_NEXT (& format_or_1 [3]) = & format_or_1 [4];
  
  BC_PARSE_NEXT (str_abc) = tag_2;
  BC_PARSE_NEXT (sym_or)  = str_abc;
  tag_1 = bc_parse_tag_new (& format_or_1[0], sym_or);
  return (tag_1);
}


/************************************************************************
 *
 * While
 *
 */
static struct bc_format format_while_1 [3] =
{
  { BC_STRING_TYPE, (bc_object_t) "<while ", BC_FORMAT_NULL },
  { BC_INDEX_TYPE,  (bc_object_t) 1,      BC_FORMAT_NULL },
  { BC_STRING_TYPE, (bc_object_t) ">",    BC_FORMAT_NULL }
};

static struct bc_format format_while_2 =
{
  BC_STRING_TYPE, (bc_object_t) "<get-var xyz>", BC_FORMAT_NULL
};

static struct bc_format format_while_3 =
{
  BC_STRING_TYPE, (bc_object_t) "<set-var xyz \"false\">", BC_FORMAT_NULL
};

static struct bc_format format_while_4 [2] =
{
  { BC_STRING_TYPE, (bc_object_t) "abc ", BC_FORMAT_NULL },
  { BC_INDEX_TYPE,  (bc_object_t) 0,      BC_FORMAT_NULL },
};

static bc_parse_t
parse_while_test (void)
{
  /* <while <get-var xyz>>abc <set-var xyz "false"></while> 

     =>

     {BLK {TAG {CAT "<while " 1 ">"}
               {SYM while}
	       {TAG {CAT "<get-var xyz>"}
	            {SYM get-var}
		    {SYM xyz}}}
          {TEXT {CAT "abc " 0}
	        {TAG {CAT "<set-var xyz \"false\">"}
		     {SYM set-var}
		     {SYM xyz}
		     {STR "false"}}}}

		    */
  bc_parse_t
    sym_whl  = bc_parse_symbol_new (bc_symbol_intern ("while"), "while"),
    sym_get  = bc_parse_symbol_new (bc_symbol_intern ("get-var"), "get-var"),
    sym_xyz1 = bc_parse_symbol_new (bc_symbol_intern ("xyz"), "xyz"),
    sym_set  = bc_parse_symbol_new (bc_symbol_intern ("set-var"), "set-var"),
    sym_xyz2 = bc_parse_symbol_new (bc_symbol_intern ("xyz"), "xyz"),
    str_fls  = bc_parse_string_new ("false"),
    str_abc  = bc_parse_string_new ("abc");

  bc_parse_t blk, txt, tag_1, tag_2, tag_3;

  /* <get-var xyz> */
  BC_PARSE_NEXT (sym_get) = sym_xyz1;
  tag_2 = bc_parse_tag_new (& format_while_2, sym_get);

  /* <set-var xyz "false"> */
  BC_PARSE_NEXT (sym_xyz2) = str_fls;
  BC_PARSE_NEXT (sym_set)  = sym_xyz2;
  tag_3 = bc_parse_tag_new (& format_while_3, sym_set);

  /* Link together format_while_1 */
  BC_FORMAT_NEXT (& format_while_1 [0]) = & format_while_1 [1];
  BC_FORMAT_NEXT (& format_while_1 [1]) = & format_while_1 [2];
  BC_PARSE_NEXT (sym_whl)  = tag_2;
  tag_1 = bc_parse_tag_new (& format_while_1[0], sym_whl);

  BC_FORMAT_NEXT (& format_while_4 [0]) = & format_while_4 [1];
  txt = bc_parse_text_new (& format_while_4 [0], tag_3);

  blk = bc_parse_blk_new (tag_1, txt);
  
  return (blk);
}

/************************************************************************
 *
 * Add
 *
 */
static struct bc_format format_add_1 =
{
  BC_STRING_TYPE, (bc_object_t) "<add \"1.2\" \"3.8\">", BC_FORMAT_NULL
};

static bc_parse_t
parse_add_test (void)
{
  /* <add "1.2" "3.8"> */

  /* {TAG {CAT "<add \"1.2\" \"3.8\">"}
          {SYM add}
          {STR "1.2"}
	  {STR "3.8"}}
	  */

  bc_parse_t
    sym_add  = bc_parse_symbol_new (bc_symbol_intern ("add"), "add"),
    str_12   = bc_parse_string_new ("1.2"),
    str_38   = bc_parse_string_new ("3.8");

  bc_parse_t tag_1;

  BC_FORMAT_NEXT (str_12)  = str_38;
  BC_FORMAT_NEXT (sym_add) = str_12;
  tag_1 = bc_parse_tag_new (& format_add_1, sym_add);
  return (tag_1);
}

/************************************************************************
 *
 * Random
 *
 */
static struct bc_format format_rnd_1 =
{
  BC_STRING_TYPE,
  (bc_object_t) "<random \"10\">",
  BC_FORMAT_NULL
};

static bc_parse_t
parse_rnd_test (void)
{
  /* <random \"10\"> */

  /* {TAG {CAT "<random \"10\">"}
          {SYM random}
          {STR "10""}}
	  */

  bc_parse_t
    sym_rnd  = bc_parse_symbol_new (bc_symbol_intern ("random"), "random"),
    str_10  = bc_parse_string_new ("10");

  bc_parse_t tag_1;

  BC_FORMAT_NEXT (sym_rnd) = str_10;
  tag_1 = bc_parse_tag_new (& format_rnd_1, sym_rnd);
  return (tag_1);
}


/************************************************************************
 *
 * Downcase
 *
 */
static struct bc_format format_dwn_1 =
{
  BC_STRING_TYPE,
  (bc_object_t) "<downcase \"Ed Gamble Jr.\">",
  BC_FORMAT_NULL
};

static bc_parse_t
parse_dwn_test (void)
{
  /* <downcase \"Ed Gamble Jr.\"> */

  /* {TAG {CAT "<downcase \"Ed Gamble Jr.\">"}
          {SYM downcase}
          {STR "Ed Gamble Jr.""}}
	  */

  bc_parse_t
    sym_dwn  = bc_parse_symbol_new (bc_symbol_intern ("downcase"),
				    "downcase"),
    str_ebg  = bc_parse_string_new ("Ed Gamble Jr.");

  bc_parse_t tag_1;

  BC_FORMAT_NEXT (sym_dwn) = str_ebg;
  tag_1 = bc_parse_tag_new (& format_dwn_1, sym_dwn);
  return (tag_1);
}

/************************************************************************
 *
 * GET-VAR-WHAT
 *
 */
static struct bc_format format_gvw_1 =
{
   BC_STRING_TYPE, (bc_object_t) "<get-var foo bar>", BC_FORMAT_NULL
};

static bc_parse_t
parse_gvw_test (void)
{
  /* <get-var foo bar> */

  /* {TAG {CAT "<get-var foo bar>"}
          {SYM downcase}
          {SYM foo}
	  {SYM bar}}
	  */

  bc_parse_t
    sym_gvw  = bc_parse_symbol_new (bc_symbol_intern ("get-var"), "get-var"),
    sym_foo  = bc_parse_symbol_new (bc_symbol_intern ("foo"), "foo"),
    sym_bar  = bc_parse_symbol_new (bc_symbol_intern ("bar"), "bar");

  bc_parse_t tag_1;

  BC_FORMAT_NEXT (sym_gvw) = sym_foo;
  BC_FORMAT_NEXT (sym_foo) = sym_bar;
  tag_1 = bc_parse_tag_new (& format_gvw_1, sym_gvw);
  return (tag_1);
}

/************************************************************************
 *
 * Defun
 *
 */
static struct bc_format format_defun_1 [3] =
{
  { BC_STRING_TYPE, (bc_object_t) "<defun ", BC_FORMAT_NULL },
  { BC_INDEX_TYPE,  (bc_object_t) 1,      BC_FORMAT_NULL },
  { BC_STRING_TYPE, (bc_object_t) ">",    BC_FORMAT_NULL }
};

static struct bc_format format_defun_2 =
{
  BC_STRING_TYPE, (bc_object_t) "<get-var xyz>", BC_FORMAT_NULL
};

static struct bc_format format_defun_3 [2] =
{
  { BC_STRING_TYPE, (bc_object_t) "abc ", BC_FORMAT_NULL },
  { BC_INDEX_TYPE,  (bc_object_t) 0,      BC_FORMAT_NULL },
};

static bc_parse_t
parse_defun_test (void)
{
  /* <defun FOO xyz>abc <get-var xyz></defun>
     =>
     {BLK {TAG {CAT "<defun " 1 ">"}
               {SYM defun}
	       {SYM FOO>}}
	       {SYM xyz>}}
          {TEXT {CAT "abc " 0}
	        {TAG {CAT "<get-var xyz>"}
		     {SYM get-var}
		     {SYM xyz}}}}
		    */
  bc_parse_t
    sym_dfn  = bc_parse_symbol_new (bc_symbol_intern ("defun"), "defun"),
    sym_get  = bc_parse_symbol_new (bc_symbol_intern ("get-var"), "get-var"),
    sym_FOO  = bc_parse_symbol_new (bc_symbol_intern ("FOO"), "FOO"),
    sym_xyz1 = bc_parse_symbol_new (bc_symbol_intern ("xyz"), "xyz"),
    sym_xyz2 = bc_parse_symbol_new (bc_symbol_intern ("xyz"), "xyz"),
    str_abc  = bc_parse_string_new ("abc");

  bc_parse_t blk, txt, cat_1, tag_1, cat_2, tag_2, cat_3, tag_3, cat_4;

  /* Link together format_defun_1 */
  BC_FORMAT_NEXT (& format_defun_1 [0]) = & format_defun_1 [1];
  BC_FORMAT_NEXT (& format_defun_1 [1]) = & format_defun_1 [2];

  BC_FORMAT_NEXT (sym_FOO) = sym_xyz1;
  BC_FORMAT_NEXT (sym_dfn) = sym_FOO;
  tag_1 = bc_parse_tag_new (& format_defun_1[0], sym_dfn);

  /* <get-var xyz> */
  BC_FORMAT_NEXT (sym_get) = sym_xyz2;
  tag_2 = bc_parse_tag_new (& format_defun_2, sym_get);

  BC_FORMAT_NEXT (& format_defun_3 [0]) = & format_defun_3 [1];
  txt = bc_parse_text_new (& format_defun_3 [0], tag_2);

  blk = bc_parse_blk_new (tag_1, txt);
  
  return (blk);
}



/************************************************************************
 *
 * Defun/call
 *
 */
static struct bc_format format_defcal_1 [3] =
{
  { BC_STRING_TYPE, (bc_object_t) "<defun ", BC_FORMAT_NULL },
  { BC_INDEX_TYPE,  (bc_object_t) 1,      BC_FORMAT_NULL },
  { BC_STRING_TYPE, (bc_object_t) ">",    BC_FORMAT_NULL }
};

static struct bc_format format_defcal_2 =
{
  BC_STRING_TYPE, (bc_object_t) "<get-var xyz>", BC_FORMAT_NULL
};

static struct bc_format format_defcal_3 [2] =
{
  { BC_STRING_TYPE, (bc_object_t) "abc ", BC_FORMAT_NULL },
  { BC_INDEX_TYPE,  (bc_object_t) 0,      BC_FORMAT_NULL },
};

static struct bc_format format_defcal_4 [2] =
{
  { BC_INDEX_TYPE,  (bc_object_t) 0,      BC_FORMAT_NULL },
  { BC_INDEX_TYPE,  (bc_object_t) 1,      BC_FORMAT_NULL },
};

static struct bc_format format_defcal_5 =
{
  BC_STRING_TYPE, (bc_object_t) "<FOO \"def\">", BC_FORMAT_NULL
};


static bc_parse_t
parse_defcal_test (void)
{
  /* <defun FOO xyz>abc<get-var xyz></defun><FOO "def">
     =>
     {TEXT {CAT 0 1}
	   {BLK {TAG {CAT "<defun " 1 ">"}
		     {SYM defun}
		     {SYM FOO>}
		     {SYM xyz>}}
		{TEXT {CAT "abc" 0}
		      {TAG {CAT "<get-var xyz>"}
			   {SYM get-var}
			   {SYM xyz}}}}
           {TAG {CAT "<FOO def>"}
                {SYM FOO}
                {STR "def"}}}
		*/
  bc_parse_t
    sym_dfn  = bc_parse_symbol_new (bc_symbol_intern ("defun"), "defun"),
    sym_get  = bc_parse_symbol_new (bc_symbol_intern ("get-var"), "get-var"),
    sym_FOO1 = bc_parse_symbol_new (bc_symbol_intern ("FOO"), "FOO"),
    sym_FOO2 = bc_parse_symbol_new (bc_symbol_intern ("FOO"), "FOO"),
    sym_xyz1 = bc_parse_symbol_new (bc_symbol_intern ("xyz"), "xyz"),
    sym_xyz2 = bc_parse_symbol_new (bc_symbol_intern ("xyz"), "xyz"),
    str_def  = bc_parse_string_new ("def"),
    str_abc  = bc_parse_string_new ("abc");

  bc_parse_t blk_1, txt_1, txt_2, tag_1, tag_2, tag_3, tag_4;
  
  /* Link together format_defcal_1 */
  BC_FORMAT_NEXT (& format_defcal_1 [0]) = & format_defcal_1 [1];
  BC_FORMAT_NEXT (& format_defcal_1 [1]) = & format_defcal_1 [2];

  BC_FORMAT_NEXT (sym_FOO1) = sym_xyz1;
  BC_FORMAT_NEXT (sym_dfn)  = sym_FOO1;
  tag_1 = bc_parse_tag_new (& format_defcal_1[0], sym_dfn);

  /* <get-var xyz> */
  BC_FORMAT_NEXT (sym_get)  = sym_xyz2;
  tag_2 = bc_parse_tag_new (& format_defcal_2, sym_get);

  BC_FORMAT_NEXT (& format_defcal_3 [0]) = & format_defcal_3 [1];
  txt_1 = bc_parse_text_new (& format_defcal_3 [0], tag_2);
  blk_1 = bc_parse_blk_new (tag_1, txt_1);

  /* <get-var xyz> */
  BC_FORMAT_NEXT (sym_FOO2) = str_def;
  tag_4 = bc_parse_tag_new (& format_defcal_5, sym_FOO2);

  BC_FORMAT_NEXT (& format_defcal_4 [0]) = & format_defcal_4 [1];
  BC_FORMAT_NEXT (blk_1) = tag_4;
  txt_2 = bc_parse_text_new (& format_defcal_4 [0], blk_1);
  
  return (txt_2);
}

/************************************************************************
 *
 * format
 *
 */
static struct bc_format format_fmt_1 [3] =
{
  { BC_STRING_TYPE, (bc_object_t) "012 ", BC_FORMAT_NULL },
  { BC_INDEX_TYPE,  (bc_object_t) 0,      BC_FORMAT_NULL },
  { BC_STRING_TYPE, (bc_object_t) " 345",  BC_FORMAT_NULL }
};

static struct bc_format format_fmt_2 =
{
  BC_STRING_TYPE, (bc_object_t) "<random \"10\">", BC_FORMAT_NULL
};

static bc_parse_t
parse_fmt_test (void)
{
  /* "abc <random 10> def"
     =>
     {TEXT {CAT "012 " 0 " 345"}
           {TAG {CAT "<random \"10\">"}
                {SYM random}
                {STR "10""}}
		*/
  bc_parse_t
    sym_rnd  = bc_parse_symbol_new (bc_symbol_intern ("random"), "random"),
    str_10   = bc_parse_string_new ("10");

  bc_parse_t tag_1, txt_1;
  
  BC_FORMAT_NEXT (sym_rnd) = str_10;
  tag_1 = bc_parse_tag_new (& format_fmt_2, sym_rnd);
  
  /* Link together format_fmt_1 */
  BC_FORMAT_NEXT (& format_fmt_1 [0]) = & format_fmt_1 [1];
  BC_FORMAT_NEXT (& format_fmt_1 [1]) = & format_fmt_1 [2];
  txt_1 = bc_parse_text_new (& format_fmt_1 [0], tag_1);
  
  return (txt_1);
}

/**************************************************************************
 *
 *
 *
 *
 */  
struct bc_parse_test bc_parse_test_array [] = {
  { parse_if_test,     "IF",     "<if \"abc\" <get-var xyz>>"},
  { parse_not_test,    "NOT",    "<if \"abc\" <not xyz>>"},
  { parse_prog_test,   "PROG",   "<prog \"abc\" <not xyz>>"},
  { parse_and_test,    "AND",    "<and \"abc\" <get-var xyz>>"},
  { parse_or_test,     "OR",     "<or \"abc\" <get-var xyz>>"},
  { parse_while_test,  "WHILE",
    "<while <get-var xyz>>abc <set-var xyz \"false\">" },
  { parse_add_test,    "ADD",    "<add \"1.2\" \"3.8\">" },
  { parse_rnd_test,    "ROUND",  "<random \"10\">" },
  { parse_dwn_test,    "DOWNCASE",    "<downcase \"Ed Gamble Jr.\">" },
  { parse_gvw_test,    "GET-VAR-WHAT","<get-var foo bar>" },
  { parse_defun_test,  "DEFUN",
    "<defun FOO xyz>abc <get-var xyz></defun>" },
  { parse_defcal_test, "DEFUN+CALL",
    "<defun FOO xyz>abc <get-var xyz></defun><FOO \"def\">" },
  { parse_fmt_test,    "FMT", "012 <random \"10\"> 345"},
  { NULL, (bc_string_t) NULL }
};
  
extern void 
bc_parse_install (void)
{
  bc_symbol_t xyz = bc_symbol_intern ("xyz");
  BC_SYMBOL_VALUE (xyz) = "value-of-symbol-'xyz'";
}

#endif /* defined (TEST) */
