
/*  A Bison parser, made from asm_parse.y
 with Bison version GNU/Andrew Bison version A2.2
  */

#define YYBISON 1  /* Identify Bison output.  */

#define	tt_op	258
#define	tt_label	259
#define	tt_id	260
#define	tt_progid	261
#define	tt_oparen	262
#define	tt_cparen	263
#define	tt_am	264
#define	tt_comma	265
#define	tt_name	266
#define	tt_author	267
#define	tt_address	268
#define	tt_eoln	269
#define	tt_nogood	270
#define	tt_add	271
#define	tt_sub	272
#define	tt_mul	273
#define	tt_div	274

#line 1 "asm_parse.y"

#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include "corewar.h"
#include "asm.h"

/*
 * I apologize for how bad this stuff is.  It's the first Bison/Yacc program
 *   I've ever written and the first Flex program I've ever written.
 */

static char  *errstr_end;
static stmt_t  *newprog;
unsigned  asm_line_number;
static char  name_str[STR_MAXLEN], author_str[STR_MAXLEN],
             address_str[STR_MAXLEN], *prog_fname;

#define  INT_BAD  (1 << ((sizeof(int)*8)-1))

static stmt_t  *stail(stmt_t *s), *newstmt(), *stcat(stmt_t *s1, stmt_t *s2);
static ptree_t  *newptree();
static aval_t  pass1(stmt_t *s), pass2(stmt_t *s, core_el_t *listing);
static aval_t  mk_aval(int ival);
static int  fetchaddr(ptree_t *pt, aval_t curaddr);
static int  strfetch(char *str, aval_t curaddr, unsigned line);
static void  clearstmt(stmt_t *s);
static void  clearpt(ptree_t *pt);
static void  yyerror(char *str);
#ifndef YYSTYPE
#define YYSTYPE int
#endif
#include <stdio.h>

#ifndef __cplusplus
#ifndef __STDC__
#define const
#endif
#endif



#define	YYFINAL		48
#define	YYFLAG		-32768
#define	YYNTBASE	20

#define YYTRANSLATE(x) ((unsigned)(x) <= 274 ? yytranslate[x] : 29)

static const char yytranslate[] = {     0,
     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
     2,     2,     2,     2,     2,     1,     2,     3,     4,     5,
     6,     7,     8,     9,    10,    11,    12,    13,    14,    15,
    16,    17,    18,    19
};

#if YYDEBUG != 0
static const short yyprhs[] = {     0,
     0,     4,     7,     8,    10,    16,    20,    23,    25,    27,
    29,    31,    36,    38,    40,    42,    43,    46,    48,    50,
    52,    56,    60,    62,    64,    68,    72,    74,    76,    80,
    84,    86,    89
};

static const short yyrhs[] = {    20,
    21,    14,     0,     1,    14,     0,     0,    23,     0,    23,
     3,    24,    10,    24,     0,    23,     3,    24,     0,    23,
     3,     0,    12,     0,    13,     0,    11,     0,     5,     0,
    23,     3,    24,    22,     0,     9,     0,     5,     0,     4,
     0,     0,     9,    25,     0,    25,     0,    15,     0,    27,
     0,    26,    16,    27,     0,    26,    17,    27,     0,     6,
     0,    27,     0,    26,    16,    27,     0,    26,    17,    27,
     0,     6,     0,    28,     0,    27,    18,    28,     0,    27,
    19,    28,     0,     5,     0,    17,     5,     0,     7,    26,
     8,     0
};

#endif

#if YYDEBUG != 0
static const short yyrline[] = { 0,
    51,    53,    62,    65,    66,    72,    77,    81,    84,    87,
    90,    94,   100,   100,   102,   110,   114,   118,   122,   127,
   128,   133,   138,   145,   146,   151,   156,   162,   163,   168,
   175,   180,   187
};
#endif


#if YYDEBUG != 0

static const char * const yytname[] = {   "$","error","$illegal.","tt_op","tt_label",
"tt_id","tt_progid","tt_oparen","tt_cparen","tt_am","tt_comma","tt_name","tt_author",
"tt_address","tt_eoln","tt_nogood","tt_add","tt_sub","tt_mul","tt_div","program",
"line","bad_newarg","oplab","arg","expr","noid_expr","factor","unit", NULL
};
#endif

static const short yyr1[] = {     0,
    20,    20,    20,    21,    21,    21,    21,    21,    21,    21,
    21,    21,    22,    22,    23,    23,    24,    24,    24,    25,
    25,    25,    25,    26,    26,    26,    26,    27,    27,    27,
    28,    28,    28
};

static const short yyr2[] = {     0,
     3,     2,     0,     1,     5,     3,     2,     1,     1,     1,
     1,     4,     1,     1,     1,     0,     2,     1,     1,     1,
     3,     3,     1,     1,     3,     3,     1,     1,     3,     3,
     1,     2,     3
};

static const short yydefact[] = {     0,
     0,    16,     2,    15,    11,    10,     8,     9,     0,     4,
     1,     7,    31,    23,     0,     0,    19,     0,     6,    18,
     0,    20,    28,    27,     0,    24,    17,    32,    14,    13,
     0,    12,     0,     0,     0,     0,    33,     0,     0,     5,
    21,    22,    29,    30,    25,    26,     0,     0
};

static const short yydefgoto[] = {     2,
     9,    32,    10,    19,    20,    21,    22,    23
};

static const short yypact[] = {     1,
    -3,    16,-32768,-32768,-32768,-32768,-32768,-32768,     8,    43,
-32768,    25,-32768,    -7,    30,    38,-32768,    28,    -2,-32768,
    32,    40,-32768,-32768,     9,    35,-32768,-32768,-32768,-32768,
    25,-32768,    34,    34,    34,    34,-32768,    34,    34,-32768,
    44,    48,-32768,-32768,    35,    35,    50,-32768
};

static const short yypgoto[] = {-32768,
-32768,-32768,-32768,     7,    36,    55,   -15,    33
};


#define	YYLAST		70


static const short yytable[] = {    26,
    -3,     1,    29,    -3,    -3,    -3,    30,    31,   -27,   -27,
     3,    -3,    -3,    -3,    -3,    47,    37,    41,    42,     4,
     5,    11,    45,    46,    38,    39,     6,     7,     8,    13,
    14,    15,    28,    16,    13,    24,    15,    40,    13,    17,
    15,    18,    13,    14,    15,    12,    18,    33,    34,    48,
    18,    27,    35,    36,    18,   -24,   -24,    35,    36,   -25,
   -25,    35,    36,   -26,   -26,    35,    36,    43,    44,    25
};

static const short yycheck[] = {    15,
     0,     1,     5,     3,     4,     5,     9,    10,    16,    17,
    14,    11,    12,    13,    14,     0,     8,    33,    34,     4,
     5,    14,    38,    39,    16,    17,    11,    12,    13,     5,
     6,     7,     5,     9,     5,     6,     7,    31,     5,    15,
     7,    17,     5,     6,     7,     3,    17,    16,    17,     0,
    17,    16,    18,    19,    17,    16,    17,    18,    19,    16,
    17,    18,    19,    16,    17,    18,    19,    35,    36,    15
};
/* -*-C-*-  Note some compilers choke on comments on `#line' lines.  */
#line 3 "/mit/andydevo/texport/6.3/sgi/etc/bison.simple"

/* Skeleton output parser for bison,
   Copyright (C) 1984, 1989, 1990 Bob Corbett and Richard Stallman

   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; either version 1, or (at your option)
   any later version.

   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.  */


#ifndef alloca
#ifdef __GNUC__
#define alloca __builtin_alloca
#else /* not GNU C.  */
#if (!defined (__STDC__) && defined (sparc)) || defined (__sparc__) || defined (__sparc) || defined (__sgi)
#include <alloca.h>
#else /* not sparc */
#if defined (MSDOS) && !defined (__TURBOC__)
#include <malloc.h>
#else /* not MSDOS, or __TURBOC__ */
#if defined(_AIX)
#include <malloc.h>
 #pragma alloca
#else /* not MSDOS, __TURBOC__, or _AIX */
#ifdef __hpux
#ifdef __cplusplus
extern "C" {
void *alloca (unsigned int);
};
#else /* not __cplusplus */
void *alloca ();
#endif /* not __cplusplus */
#endif /* __hpux */
#endif /* not _AIX */
#endif /* not MSDOS, or __TURBOC__ */
#endif /* not sparc.  */
#endif /* not GNU C.  */
#endif /* alloca not defined.  */

/* This is the parser code that is written into each bison parser
  when the %semantic_parser declaration is not specified in the grammar.
  It was written by Richard Stallman by simplifying the hairy parser
  used when %semantic_parser is specified.  */

/* Note: there must be only one dollar sign in this file.
   It is replaced by the list of actions, each action
   as one case of the switch.  */

#define yyerrok		(yyerrstatus = 0)
#define yyclearin	(yychar = YYEMPTY)
#define YYEMPTY		-2
#define YYEOF		0
#define YYACCEPT	return(0)
#define YYABORT 	return(1)
#define YYERROR		goto yyerrlab1
/* Like YYERROR except do call yyerror.
   This remains here temporarily to ease the
   transition to the new meaning of YYERROR, for GCC.
   Once GCC version 2 has supplanted version 1, this can go.  */
#define YYFAIL		goto yyerrlab
#define YYRECOVERING()  (!!yyerrstatus)
#define YYBACKUP(token, value) \
do								\
  if (yychar == YYEMPTY && yylen == 1)				\
    { yychar = (token), yylval = (value);			\
      yychar1 = YYTRANSLATE (yychar);				\
      YYPOPSTACK;						\
      goto yybackup;						\
    }								\
  else								\
    { yyerror ("syntax error: cannot back up"); YYERROR; }	\
while (0)

#define YYTERROR	1
#define YYERRCODE	256

#ifndef YYPURE
#define YYLEX		yylex()
#endif

#ifdef YYPURE
#ifdef YYLSP_NEEDED
#define YYLEX		yylex(&yylval, &yylloc)
#else
#define YYLEX		yylex(&yylval)
#endif
#endif

/* If nonreentrant, generate the variables here */

#ifndef YYPURE

int	yychar;			/*  the lookahead symbol		*/
YYSTYPE	yylval;			/*  the semantic value of the		*/
				/*  lookahead symbol			*/

#ifdef YYLSP_NEEDED
YYLTYPE yylloc;			/*  location data for the lookahead	*/
				/*  symbol				*/
#endif

int yynerrs;			/*  number of parse errors so far       */
#endif  /* not YYPURE */

#if YYDEBUG != 0
int yydebug;			/*  nonzero means print parse trace	*/
/* Since this is uninitialized, it does not stop multiple parsers
   from coexisting.  */
#endif

/*  YYINITDEPTH indicates the initial size of the parser's stacks	*/

#ifndef	YYINITDEPTH
#define YYINITDEPTH 200
#endif

/*  YYMAXDEPTH is the maximum size the stacks can grow to
    (effective only if the built-in stack extension method is used).  */

#if YYMAXDEPTH == 0
#undef YYMAXDEPTH
#endif

#ifndef YYMAXDEPTH
#define YYMAXDEPTH 10000
#endif

/* Prevent warning if -Wstrict-prototypes.  */
#ifdef __GNUC__
int yyparse (void);
#endif

#if __GNUC__ > 1		/* GNU C and GNU C++ define this.  */
#define __yy_bcopy(FROM,TO,COUNT)	__builtin_memcpy(TO,FROM,COUNT)
#else				/* not GNU C or C++ */
#ifndef __cplusplus

/* This is the most reliable way to avoid incompatibilities
   in available built-in functions on various systems.  */
static void
__yy_bcopy (from, to, count)
     char *from;
     char *to;
     int count;
{
  register char *f = from;
  register char *t = to;
  register int i = count;

  while (i-- > 0)
    *t++ = *f++;
}

#else /* __cplusplus */

/* This is the most reliable way to avoid incompatibilities
   in available built-in functions on various systems.  */
static void
__yy_bcopy (char *from, char *to, int count)
{
  register char *f = from;
  register char *t = to;
  register int i = count;

  while (i-- > 0)
    *t++ = *f++;
}

#endif
#endif

#line 184 "/mit/andydevo/texport/6.3/sgi/etc/bison.simple"
int
yyparse()
{
  register int yystate;
  register int yyn;
  register short *yyssp;
  register YYSTYPE *yyvsp;
  int yyerrstatus;	/*  number of tokens to shift before error messages enabled */
  int yychar1 = 0;		/*  lookahead token as an internal (translated) token number */

  short	yyssa[YYINITDEPTH];	/*  the state stack			*/
  YYSTYPE yyvsa[YYINITDEPTH];	/*  the semantic value stack		*/

  short *yyss = yyssa;		/*  refer to the stacks thru separate pointers */
  YYSTYPE *yyvs = yyvsa;	/*  to allow yyoverflow to reallocate them elsewhere */

#ifdef YYLSP_NEEDED
  YYLTYPE yylsa[YYINITDEPTH];	/*  the location stack			*/
  YYLTYPE *yyls = yylsa;
  YYLTYPE *yylsp;

#define YYPOPSTACK   (yyvsp--, yyssp--, yylsp--)
#else
#define YYPOPSTACK   (yyvsp--, yyssp--)
#endif

  int yystacksize = YYINITDEPTH;

#ifdef YYPURE
  int yychar;
  YYSTYPE yylval;
  int yynerrs;
#ifdef YYLSP_NEEDED
  YYLTYPE yylloc;
#endif
#endif

  YYSTYPE yyval;		/*  the variable used to return		*/
				/*  semantic values from the action	*/
				/*  routines				*/

  int yylen;

#if YYDEBUG != 0
  if (yydebug)
    fprintf(stderr, "Starting parse\n");
#endif

  yystate = 0;
  yyerrstatus = 0;
  yynerrs = 0;
  yychar = YYEMPTY;		/* Cause a token to be read.  */

  /* Initialize stack pointers.
     Waste one element of value and location stack
     so that they stay on the same level as the state stack.
     The wasted elements are never initialized.  */

  yyssp = yyss - 1;
  yyvsp = yyvs;
#ifdef YYLSP_NEEDED
  yylsp = yyls;
#endif

/* Push a new state, which is found in  yystate  .  */
/* In all cases, when you get here, the value and location stacks
   have just been pushed. so pushing a state here evens the stacks.  */
yynewstate:

  *++yyssp = yystate;

  if (yyssp >= yyss + yystacksize - 1)
    {
      /* Give user a chance to reallocate the stack */
      /* Use copies of these so that the &'s don't force the real ones into memory. */
      YYSTYPE *yyvs1 = yyvs;
      short *yyss1 = yyss;
#ifdef YYLSP_NEEDED
      YYLTYPE *yyls1 = yyls;
#endif

      /* Get the current used size of the three stacks, in elements.  */
      int size = yyssp - yyss + 1;

#ifdef yyoverflow
      /* Each stack pointer address is followed by the size of
	 the data in use in that stack, in bytes.  */
#ifdef YYLSP_NEEDED
      /* This used to be a conditional around just the two extra args,
	 but that might be undefined if yyoverflow is a macro.  */
      yyoverflow("parser stack overflow",
		 &yyss1, size * sizeof (*yyssp),
		 &yyvs1, size * sizeof (*yyvsp),
		 &yyls1, size * sizeof (*yylsp),
		 &yystacksize);
#else
      yyoverflow("parser stack overflow",
		 &yyss1, size * sizeof (*yyssp),
		 &yyvs1, size * sizeof (*yyvsp),
		 &yystacksize);
#endif

      yyss = yyss1; yyvs = yyvs1;
#ifdef YYLSP_NEEDED
      yyls = yyls1;
#endif
#else /* no yyoverflow */
      /* Extend the stack our own way.  */
      if (yystacksize >= YYMAXDEPTH)
	{
	  yyerror("parser stack overflow");
	  return 2;
	}
      yystacksize *= 2;
      if (yystacksize > YYMAXDEPTH)
	yystacksize = YYMAXDEPTH;
      yyss = (short *) alloca (yystacksize * sizeof (*yyssp));
      __yy_bcopy ((char *)yyss1, (char *)yyss, size * sizeof (*yyssp));
      yyvs = (YYSTYPE *) alloca (yystacksize * sizeof (*yyvsp));
      __yy_bcopy ((char *)yyvs1, (char *)yyvs, size * sizeof (*yyvsp));
#ifdef YYLSP_NEEDED
      yyls = (YYLTYPE *) alloca (yystacksize * sizeof (*yylsp));
      __yy_bcopy ((char *)yyls1, (char *)yyls, size * sizeof (*yylsp));
#endif
#endif /* no yyoverflow */

      yyssp = yyss + size - 1;
      yyvsp = yyvs + size - 1;
#ifdef YYLSP_NEEDED
      yylsp = yyls + size - 1;
#endif

#if YYDEBUG != 0
      if (yydebug)
	fprintf(stderr, "Stack size increased to %d\n", yystacksize);
#endif

      if (yyssp >= yyss + yystacksize - 1)
	YYABORT;
    }

#if YYDEBUG != 0
  if (yydebug)
    fprintf(stderr, "Entering state %d\n", yystate);
#endif

  goto yybackup;
 yybackup:

/* Do appropriate processing given the current state.  */
/* Read a lookahead token if we need one and don't already have one.  */
/* yyresume: */

  /* First try to decide what to do without reference to lookahead token.  */

  yyn = yypact[yystate];
  if (yyn == YYFLAG)
    goto yydefault;

  /* Not known => get a lookahead token if don't already have one.  */

  /* yychar is either YYEMPTY or YYEOF
     or a valid token in external form.  */

  if (yychar == YYEMPTY)
    {
#if YYDEBUG != 0
      if (yydebug)
	fprintf(stderr, "Reading a token: ");
#endif
      yychar = YYLEX;
    }

  /* Convert token to internal form (in yychar1) for indexing tables with */

  if (yychar <= 0)		/* This means end of input. */
    {
      yychar1 = 0;
      yychar = YYEOF;		/* Don't call YYLEX any more */

#if YYDEBUG != 0
      if (yydebug)
	fprintf(stderr, "Now at end of input.\n");
#endif
    }
  else
    {
      yychar1 = YYTRANSLATE(yychar);

#if YYDEBUG != 0
      if (yydebug)
	{
	  fprintf (stderr, "Next token is %d (%s", yychar, yytname[yychar1]);
	  /* Give the individual parser a way to print the precise meaning
	     of a token, for further debugging info.  */
#ifdef YYPRINT
	  YYPRINT (stderr, yychar, yylval);
#endif
	  fprintf (stderr, ")\n");
	}
#endif
    }

  yyn += yychar1;
  if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != yychar1)
    goto yydefault;

  yyn = yytable[yyn];

  /* yyn is what to do for this token type in this state.
     Negative => reduce, -yyn is rule number.
     Positive => shift, yyn is new state.
       New state is final state => don't bother to shift,
       just return success.
     0, or most negative number => error.  */

  if (yyn < 0)
    {
      if (yyn == YYFLAG)
	goto yyerrlab;
      yyn = -yyn;
      goto yyreduce;
    }
  else if (yyn == 0)
    goto yyerrlab;

  if (yyn == YYFINAL)
    YYACCEPT;

  /* Shift the lookahead token.  */

#if YYDEBUG != 0
  if (yydebug)
    fprintf(stderr, "Shifting token %d (%s), ", yychar, yytname[yychar1]);
#endif

  /* Discard the token being shifted unless it is eof.  */
  if (yychar != YYEOF)
    yychar = YYEMPTY;

  *++yyvsp = yylval;
#ifdef YYLSP_NEEDED
  *++yylsp = yylloc;
#endif

  /* count tokens shifted since error; after three, turn off error status.  */
  if (yyerrstatus) yyerrstatus--;

  yystate = yyn;
  goto yynewstate;

/* Do the default action for the current state.  */
yydefault:

  yyn = yydefact[yystate];
  if (yyn == 0)
    goto yyerrlab;

/* Do a reduction.  yyn is the number of a rule to reduce with.  */
yyreduce:
  yylen = yyr2[yyn];
  if (yylen > 0)
    yyval = yyvsp[1-yylen]; /* implement default value of the action */

#if YYDEBUG != 0
  if (yydebug)
    {
      int i;

      fprintf (stderr, "Reducing via rule %d (line %d), ",
	       yyn, yyrline[yyn]);

      /* Print the symbols being reduced, and their result.  */
      for (i = yyprhs[yyn]; yyrhs[i] > 0; i++)
	fprintf (stderr, "%s ", yytname[yyrhs[i]]);
      fprintf (stderr, " -> %s\n", yytname[yyr1[yyn]]);
    }
#endif


  switch (yyn) {

case 1:
#line 51 "asm_parse.y"
{
		yyval.stmt = (newprog = stcat(yyvsp[-2].stmt, yyvsp[-1].stmt)); ;
    break;}
case 2:
#line 53 "asm_parse.y"
{
		yyval.stmt = newstmt();
		/*
		 * OK, this is a LAME error message, but it only happens when something
		 *   goes wrong and none of the other, useful error messages cover it.
		 */
		strcat(cwerrstr, "Invalid assembly code.");
		asm_error_loc(asm_line_number);
		YYABORT; ;
    break;}
case 3:
#line 62 "asm_parse.y"
{ yyval.stmt = newstmt(); ;
    break;}
case 4:
#line 65 "asm_parse.y"
{ yyval.stmt = yyvsp[0].stmt; ;
    break;}
case 5:
#line 66 "asm_parse.y"
{
		stmt_t  *temp = yyvsp[-4].stmt;
		yyval.stmt = yyvsp[-4].stmt;
		temp->op = yyvsp[-3].op;
		temp->a = yyvsp[-2].argtop;
		temp->b = yyvsp[0].argtop; ;
    break;}
case 6:
#line 72 "asm_parse.y"
{
		stmt_t  *temp = yyvsp[-2].stmt;
		yyval.stmt = yyvsp[-2].stmt;
		temp->op = yyvsp[-1].op;
		temp->a = yyvsp[0].argtop; ;
    break;}
case 7:
#line 77 "asm_parse.y"
{
		stmt_t  *temp = yyvsp[-1].stmt;
		yyval.stmt = yyvsp[-1].stmt;
		temp->op = yyvsp[0].op; ;
    break;}
case 8:
#line 81 "asm_parse.y"
{
		yyval.stmt = newstmt();
		strncpy(author_str, yytext, STR_MAXLEN - 1); ;
    break;}
case 9:
#line 84 "asm_parse.y"
{
		yyval.stmt = newstmt();
		strncpy(address_str, yytext, STR_MAXLEN - 1); ;
    break;}
case 10:
#line 87 "asm_parse.y"
{
		yyval.stmt = newstmt();
		strncpy(name_str, yytext, STR_MAXLEN - 1); ;
    break;}
case 11:
#line 90 "asm_parse.y"
{
		sprintf(cwerrstr, "Id \"%s\" must be preceded by an operator.", yytext);
		asm_error_loc(asm_line_number);
		YYABORT; ;
    break;}
case 12:
#line 94 "asm_parse.y"
{
		sprintf(cwerrstr, "A \",\" is needed between arguments.");
		asm_error_loc(asm_line_number);
		YYABORT; ;
    break;}
case 15:
#line 102 "asm_parse.y"
{
		char  *tcp;

		yyval.stmt = newstmt();
		strcat(tcp = (yyval.stmt)->str, yytext);
		while ((*tcp != ':') && (*tcp != '\0'))
			++tcp;
		*tcp = '\0';  /* Strip off the colon. */ ;
    break;}
case 16:
#line 110 "asm_parse.y"
{
		yyval.stmt = newstmt(); ;
    break;}
case 17:
#line 114 "asm_parse.y"
{
		yyval.argtop = (argtop_t *)tmalloc(sizeof(argtop_t));
		(yyval.argtop)->mode = yyvsp[-1].am;
		(yyval.argtop)->pt = yyvsp[0].ptree; ;
    break;}
case 18:
#line 118 "asm_parse.y"
{
		yyval.argtop = (argtop_t *)tmalloc(sizeof(argtop_t));
		(yyval.argtop)->mode = am_dir;
		(yyval.argtop)->pt = yyvsp[0].ptree; ;
    break;}
case 19:
#line 122 "asm_parse.y"
{
		asm_error_loc(asm_line_number);
		YYABORT; ;
    break;}
case 20:
#line 127 "asm_parse.y"
{ yyval.ptree = yyvsp[0].ptree; ;
    break;}
case 21:
#line 128 "asm_parse.y"
{
		yyval.ptree = newptree();
		(yyval.ptree)->parsetype = pt_add;
		(yyval.ptree)->left = yyvsp[-2].ptree;
		(yyval.ptree)->right = yyvsp[0].ptree; ;
    break;}
case 22:
#line 133 "asm_parse.y"
{
		yyval.ptree = newptree();
		(yyval.ptree)->parsetype = pt_sub;
		(yyval.ptree)->left = yyvsp[-2].ptree;
		(yyval.ptree)->right = yyvsp[0].ptree; ;
    break;}
case 23:
#line 138 "asm_parse.y"
{
		yyval.ptree = newptree();
		(yyval.ptree)->parsetype = pt_end;
		(yyval.ptree)->val = AVAL_PROGID;
	;
    break;}
case 24:
#line 145 "asm_parse.y"
{ yyval.ptree = yyvsp[0].ptree; ;
    break;}
case 25:
#line 146 "asm_parse.y"
{
		yyval.ptree = newptree();
		(yyval.ptree)->parsetype = pt_add;
		(yyval.ptree)->left = yyvsp[-2].ptree;
		(yyval.ptree)->right = yyvsp[0].ptree; ;
    break;}
case 26:
#line 151 "asm_parse.y"
{
		yyval.ptree = newptree();
		(yyval.ptree)->parsetype = pt_sub;
		(yyval.ptree)->left = yyvsp[-2].ptree;
		(yyval.ptree)->right = yyvsp[0].ptree; ;
    break;}
case 27:
#line 156 "asm_parse.y"
{
		sprintf(cwerrstr, "The \"id\" value cannot be used in expressions.\n");
		asm_error_loc(asm_line_number);
		YYABORT;	;
    break;}
case 28:
#line 162 "asm_parse.y"
{ yyval.ptree = yyvsp[0].ptree; ;
    break;}
case 29:
#line 163 "asm_parse.y"
{
		yyval.ptree = newptree();
		(yyval.ptree)->parsetype = pt_mul;
		(yyval.ptree)->left = yyvsp[-2].ptree;
		(yyval.ptree)->right = yyvsp[0].ptree; ;
    break;}
case 30:
#line 168 "asm_parse.y"
{
		yyval.ptree = newptree();
		(yyval.ptree)->parsetype = pt_div;
		(yyval.ptree)->left = yyvsp[-2].ptree;
		(yyval.ptree)->right = yyvsp[0].ptree; ;
    break;}
case 31:
#line 175 "asm_parse.y"
{
		yyval.ptree = newptree();
		(yyval.ptree)->parsetype = pt_end;
		(yyval.ptree)->val = yyvsp[0].val;
		strcpy((yyval.ptree)->str, yytext); ;
    break;}
case 32:
#line 180 "asm_parse.y"
{
		yyval.ptree = newptree();
		(yyval.ptree)->parsetype = pt_uminus;
		(yyval.ptree)->left = newptree();
		(yyval.ptree)->left->parsetype = pt_end;
		(yyval.ptree)->left->val = yyvsp[0].val;
		strcpy((yyval.ptree)->left->str, yytext); ;
    break;}
case 33:
#line 187 "asm_parse.y"
{ yyval.ptree = yyvsp[-1].ptree; ;
    break;}
}
   /* the action file gets copied in in place of this dollarsign */
#line 465 "/mit/andydevo/texport/6.3/sgi/etc/bison.simple"

  yyvsp -= yylen;
  yyssp -= yylen;
#ifdef YYLSP_NEEDED
  yylsp -= yylen;
#endif

#if YYDEBUG != 0
  if (yydebug)
    {
      short *ssp1 = yyss - 1;
      fprintf (stderr, "state stack now");
      while (ssp1 != yyssp)
	fprintf (stderr, " %d", *++ssp1);
      fprintf (stderr, "\n");
    }
#endif

  *++yyvsp = yyval;

#ifdef YYLSP_NEEDED
  yylsp++;
  if (yylen == 0)
    {
      yylsp->first_line = yylloc.first_line;
      yylsp->first_column = yylloc.first_column;
      yylsp->last_line = (yylsp-1)->last_line;
      yylsp->last_column = (yylsp-1)->last_column;
      yylsp->text = 0;
    }
  else
    {
      yylsp->last_line = (yylsp+yylen-1)->last_line;
      yylsp->last_column = (yylsp+yylen-1)->last_column;
    }
#endif

  /* Now "shift" the result of the reduction.
     Determine what state that goes to,
     based on the state we popped back to
     and the rule number reduced by.  */

  yyn = yyr1[yyn];

  yystate = yypgoto[yyn - YYNTBASE] + *yyssp;
  if (yystate >= 0 && yystate <= YYLAST && yycheck[yystate] == *yyssp)
    yystate = yytable[yystate];
  else
    yystate = yydefgoto[yyn - YYNTBASE];

  goto yynewstate;

yyerrlab:   /* here on detecting error */

  if (! yyerrstatus)
    /* If not already recovering from an error, report this error.  */
    {
      ++yynerrs;

#ifdef YYERROR_VERBOSE
      yyn = yypact[yystate];

      if (yyn > YYFLAG && yyn < YYLAST)
	{
	  int size = 0;
	  char *msg;
	  int x, count;

	  count = 0;
	  /* Start X at -yyn if nec to avoid negative indexes in yycheck.  */
	  for (x = (yyn < 0 ? -yyn : 0);
	       x < (sizeof(yytname) / sizeof(char *)); x++)
	    if (yycheck[x + yyn] == x)
	      size += strlen(yytname[x]) + 15, count++;
	  msg = (char *) malloc(size + 15);
	  if (msg != 0)
	    {
	      strcpy(msg, "parse error");

	      if (count < 5)
		{
		  count = 0;
		  for (x = (yyn < 0 ? -yyn : 0);
		       x < (sizeof(yytname) / sizeof(char *)); x++)
		    if (yycheck[x + yyn] == x)
		      {
			strcat(msg, count == 0 ? ", expecting `" : " or `");
			strcat(msg, yytname[x]);
			strcat(msg, "'");
			count++;
		      }
		}
	      yyerror(msg);
	      free(msg);
	    }
	  else
	    yyerror ("parse error; also virtual memory exceeded");
	}
      else
#endif /* YYERROR_VERBOSE */
	yyerror("parse error");
    }

  goto yyerrlab1;
yyerrlab1:   /* here on error raised explicitly by an action */

  if (yyerrstatus == 3)
    {
      /* if just tried and failed to reuse lookahead token after an error, discard it.  */

      /* return failure if at end of input */
      if (yychar == YYEOF)
	YYABORT;

#if YYDEBUG != 0
      if (yydebug)
	fprintf(stderr, "Discarding token %d (%s).\n", yychar, yytname[yychar1]);
#endif

      yychar = YYEMPTY;
    }

  /* Else will try to reuse lookahead token
     after shifting the error token.  */

  yyerrstatus = 3;		/* Each real token shifted decrements this */

  goto yyerrhandle;

yyerrdefault:  /* current state does not do anything special for the error token. */

#if 0
  /* This is wrong; only states that explicitly want error tokens
     should shift them.  */
  yyn = yydefact[yystate];  /* If its default is to accept any token, ok.  Otherwise pop it.*/
  if (yyn) goto yydefault;
#endif

yyerrpop:   /* pop the current state because it cannot handle the error token */

  if (yyssp == yyss) YYABORT;
  yyvsp--;
  yystate = *--yyssp;
#ifdef YYLSP_NEEDED
  yylsp--;
#endif

#if YYDEBUG != 0
  if (yydebug)
    {
      short *ssp1 = yyss - 1;
      fprintf (stderr, "Error: state stack now");
      while (ssp1 != yyssp)
	fprintf (stderr, " %d", *++ssp1);
      fprintf (stderr, "\n");
    }
#endif

yyerrhandle:

  yyn = yypact[yystate];
  if (yyn == YYFLAG)
    goto yyerrdefault;

  yyn += YYTERROR;
  if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != YYTERROR)
    goto yyerrdefault;

  yyn = yytable[yyn];
  if (yyn < 0)
    {
      if (yyn == YYFLAG)
	goto yyerrpop;
      yyn = -yyn;
      goto yyreduce;
    }
  else if (yyn == 0)
    goto yyerrpop;

  if (yyn == YYFINAL)
    YYACCEPT;

#if YYDEBUG != 0
  if (yydebug)
    fprintf(stderr, "Shifting error token, ");
#endif

  *++yyvsp = yylval;
#ifdef YYLSP_NEEDED
  *++yylsp = yylloc;
#endif

  yystate = yyn;
  goto yynewstate;
}
#line 190 "asm_parse.y"


unsigned  assemble(program_t *prog, char *fname)  {
	stmt_t  *s;
	aval_t  plen;
	unsigned  i;
	FILE  *infile;
	static int  firstparse = TRUE;

#if  YYDEBUG
	yydebug = 1;
#endif
	cwerrstr[0] = '\0';
	prog_fname = fname;
	newprog = NULL;
	strcpy(name_str, "x Unknown");
	strcpy(address_str, "x Unknown");
	strcpy(author_str, "x Unknown");
	strcpy(prog->pname, "Unknown");
	strcpy(prog->fname, fname);
	asm_line_number = 1;
	errstr_end = NULL;
	infile = fopen(fname, "r");
	if (infile == NULL)  {
		sprintf(cwerrstr, "Cannot open file \"%s\".", fname);
		return(FALSE);
	}
	if (firstparse)  {
		firstparse = FALSE;
		yyin = infile;
	} else
		yyrestart(infile);
	if (yyparse())  {
		fclose(infile);
		clearstmt(newprog);
		if (errstr_end != NULL)
			*errstr_end = '\0';
		return(FALSE);
	}
	fclose(infile);

	sscanf(address_str, "%*s%s", prog->retaddr);

	for (i = 0;  !isspace(author_str[i]) && author_str[i];  ++i);
	while (isspace(author_str[i]) && author_str[i])
		++i;
	strcpy(prog->author, author_str + i);

	for (i = 0;  !isspace(name_str[i]) && name_str[i];  ++i);
	while (isspace(name_str[i]) && name_str[i])
		++i;
	strcpy(prog->pname, name_str + i);

	s = newprog;
	if ((plen = pass1(s)) == AVAL_NOGOOD)  {
		clearstmt(newprog);
		if (errstr_end != NULL)
			*errstr_end = '\0';
		return(FALSE);
	}
	if (plen > maxprogsize)  {
		clearstmt(newprog);
		sprintf(cwerrstr, "Program is %d words long.  "
						"This exceeds the maximum allowed of %d words.",
						plen, maxprogsize);
		return(FALSE);
	}
	prog->proglen = plen;
	prog->listing = (core_el_t *)tmalloc(plen * sizeof(core_el_t));
	if ((prog->startaddr = pass2(s, prog->listing)) == AVAL_NOGOOD)  {
		clearstmt(newprog);
		if (errstr_end != NULL)
			*errstr_end = '\0';
		return(FALSE);
	}
	clearstmt(newprog);
	return(TRUE);
}


static aval_t  pass1(stmt_t *s)  {
	aval_t  cur_addr = 0;

	while (s != NULL)  {
		s->addr = cur_addr;
		if (op_realop(s->op))
			++cur_addr;
		s = s->next;
	}
	return(cur_addr);
}


static aval_t  pass2(stmt_t *s, core_el_t *listing)  {
	aval_t  start = AVAL_NOGOOD, cur_addr = 0;
#define  ARG_OPTIONAL  0x8000
	static unsigned  invalid_modes[][2] = {
		{ARG_OPTIONAL|(1<<am_dir)|(1<<am_ind), (1<<am_dir)|(1<<am_ind)}, /* dat */
		{0, 1<<am_imm}, /* mov */
		{0, 1<<am_imm}, /* add */
		{0, 1<<am_imm}, /* sub */
		{1<<am_imm, ARG_OPTIONAL}, /* jmp */
		{1<<am_imm, 0}, /* jmz */
		{1<<am_imm, 0}, /* jmn */
		{1<<am_imm, 0}, /* djn */
		{0, 1<<am_imm}, /* cmp */
		{1<<am_imm, ARG_OPTIONAL}, /* spl */
		{0, 1<<am_imm}};  /* slt */

	while (s != NULL)  {
		switch(s->op)  {
		case op_equ:
			if (!s->str[0])  {
				sprintf(cwerrstr, "An \"EQU\" pseudo-op must have a label.");
				asm_error_loc(s->line);
				return(AVAL_NOGOOD);
			}
			if (s->b != NULL)  {
				sprintf(cwerrstr, "An \"EQU\" pseudo-op can only have one argument.");
				asm_error_loc(s->line);
				return(AVAL_NOGOOD);
			}
			if (s->a == NULL)  {
				sprintf(cwerrstr, "An \"EQU\" pseudo-op must have an argument.");
				asm_error_loc(s->line);
				return(AVAL_NOGOOD);
			}
			if (s->a->mode != am_dir)  {
				sprintf(cwerrstr, "The argument of an \"EQU\" pseudo-op must be "
								"direct mode.");
				asm_error_loc(s->line);
				return(AVAL_NOGOOD);
			}
			break;
		case op_end:
			if (s->b != NULL)  {
				sprintf(cwerrstr, "An \"END\" pseudo-op can only have one argument.");
				asm_error_loc(s->line);
				return(AVAL_NOGOOD);
			}
			if (s->a == NULL)
				start = 0;
			else  {
				if (s->a->mode != am_dir)  {
					sprintf(cwerrstr, "The argument of an \"END\" pseudo-op must be "
									"direct mode.");
					asm_error_loc(s->line);
					return(AVAL_NOGOOD);
				}
				start = mk_aval(fetchaddr(s->a->pt, 0));
				if (start == AVAL_NOGOOD)
					return(AVAL_NOGOOD);
			}
			break;
		case op_nogood:
			break;
		default:
			if (start != AVAL_NOGOOD)  {
				sprintf(cwerrstr, "Program continued after \"END\" pseudo-op.");
				asm_error_loc(s->line);
				return(AVAL_NOGOOD);
			}
			if (s->a == NULL)  {
				if ((invalid_modes[s->op][0] & ARG_OPTIONAL) ||
						(invalid_modes[s->op][1] & ARG_OPTIONAL))
					sprintf(cwerrstr, "The \"%s\" operator needs at least one argument.",
									opnames[s->op]);
				else
					sprintf(cwerrstr, "The \"%s\" operator needs two arguments.",
									opnames[s->op]);
				asm_error_loc(s->line);
				return(AVAL_NOGOOD);
			}
			if ((s->b == NULL) && (invalid_modes[s->op][0] & ARG_OPTIONAL))  {
				s->b = s->a;
				s->a = NULL;
			}
			if (s->a == NULL)  {
				s->a = (argtop_t *)tmalloc(sizeof(argtop_t));
				s->a->mode = am_imm;
				s->a->pt = NULL;
				listing[cur_addr].val1 = 0;
			} else  {
				if (amode_restrict && (invalid_modes[s->op][0] & (1 << s->a->mode)))  {
					sprintf(cwerrstr, "Operator \"%s\" cannot use %s addressing "
									"with argument A.", opnames[s->op], amodenames[s->a->mode]);
					asm_error_loc(s->line);
					return(AVAL_NOGOOD);
				}
				if ((listing[cur_addr].val1 = mk_aval(fetchaddr(s->a->pt, cur_addr)))
						== AVAL_NOGOOD)
					return(AVAL_NOGOOD);
			}
			if (s->b == NULL)  {
				if (!(invalid_modes[s->op][1] & ARG_OPTIONAL))  {
					sprintf(cwerrstr, "The \"%s\" operator needs two arguments.",
									opnames[s->op]);
					asm_error_loc(s->line);
					return(AVAL_NOGOOD);
				}
				s->b = (argtop_t *)tmalloc(sizeof(argtop_t));
				s->b->mode = am_imm;
				s->b->pt = NULL;
				listing[cur_addr].val2 = 0;
			} else  {
				if (amode_restrict && (invalid_modes[s->op][1] & (1 << s->b->mode)))  {
					sprintf(cwerrstr, "Operator \"%s\" cannot use %s addressing "
									"with argument B.", opnames[s->op], amodenames[s->b->mode]);
					asm_error_loc(s->line);
					return(AVAL_NOGOOD);
				}
				if ((listing[cur_addr].val2 = mk_aval(fetchaddr(s->b->pt, cur_addr)))
						== AVAL_NOGOOD)
					return(AVAL_NOGOOD);
			}
			listing[cur_addr].index = JTINDEX(s->op, s->a->mode, s->b->mode);
			listing[cur_addr].instr = jmptable[listing[cur_addr].index];
			++cur_addr;
			break;
		}
		s = s->next;
	}
	if (start == AVAL_NOGOOD)
		return(0);
	return(start);
}


static void  yyerror(char *str)  {
	if (!cwerrstr[0])  {
		if (str[0] == '\n')  {
			sprintf(cwerrstr, "Error near end of line: %s.", str);
			asm_error_loc(asm_line_number - 1);
		} else  {
			sprintf(cwerrstr, "Error near string \"%s\": %s.",
							yytext, str);
			asm_error_loc(asm_line_number);
		}
	}
}


void  asm_error_loc(unsigned line)  {
	char  tempbuf[200];
	FILE  *f;
	int  c, cline = 1;
	char  *cindex;

	if (errstr_end != NULL)
		return;
	sprintf(tempbuf, "\nError around line %d:\n", line);
	strcat(cwerrstr, tempbuf);
	for (cindex = cwerrstr;  *cindex;  ++cindex);
	f = fopen(prog_fname, "r");
	while (cline < line)  {
		c = getc(f);
		if (c == '\n')
			++cline;
		if (c == EOF)
			break;
	}
	c = getc(f);
	while ((cindex < cwerrstr+sizeof(cwerrstr)-1) &&
				 (c != '\n') && (c != EOF) && (isprint(c) || isspace(c)))  {
		*(cindex++) = c;
		c = getc(f);
	}
	fclose(f);
	*cindex = '\0';
	errstr_end = cindex;
}


static stmt_t  *stail(stmt_t *s)  {
	if (s->next == NULL)
		return(s);
	return(stail(s->next));
}


static stmt_t  *newstmt()  {
	stmt_t  *ns = (stmt_t *)tmalloc(sizeof(stmt_t));

	ns->line = asm_line_number;
	ns->op = op_nogood;
	ns->a = ns->b = NULL;
	ns->marked = FALSE;
	ns->next = NULL;
	ns->str[0] = '\0';
	return(ns);
}

static stmt_t  *stcat(stmt_t *s1, stmt_t *s2)  {
	stail(s1)->next = s2;
	return(s1);
}


static ptree_t  *newptree()  {
	ptree_t  *npt;

	npt = (ptree_t *)tmalloc(sizeof(ptree_t));
	npt->line = asm_line_number;
	npt->str[0] = '\0';
	npt->left = npt->right = NULL;
	return(npt);
}


static int  fetchaddr(ptree_t *pt, aval_t curaddr)  {
	int  l, r, c;

	if (pt->left != NULL)  {
		l = fetchaddr(pt->left, curaddr);
		if (l == INT_BAD)
			return(INT_BAD);
	}
	if (pt->right != NULL)  {
		r = fetchaddr(pt->right, curaddr);
		if (r == INT_BAD)
			return(INT_BAD);
	}
	switch(pt->parsetype)  {
	case pt_uminus:
		return(-l);
		break;
	case pt_add:
		c = l + r;
		if (((l < 0) && (r < 0) && (c > 0)) ||
				((l > 0) && (r > 0) && (c < 0)) ||
				(c == INT_BAD))  {
			sprintf(cwerrstr, "Additive overflow.\n");
			asm_error_loc(pt->line);
			return(INT_BAD);
		}
		return(c);
		break;
	case pt_sub:
		c = l - r;
		if (((l < 0) && (r > 0) && (c > 0)) ||
				((l > 0) && (r < 0) && (c < 0)) ||
				(c == INT_BAD))  {
			sprintf(cwerrstr, "Subtractive overflow.\n");
			asm_error_loc(pt->line);
			return(INT_BAD);
		}
		return(c);
		break;
	case pt_mul:
		c = l * r;
		if (((r != 0) && (c / r != l)) || (c == INT_BAD))  {
			sprintf(cwerrstr, "Multiplicative overflow.\n");
			asm_error_loc(pt->line);
			return(INT_BAD);
		}
		return(c);
		break;
	case pt_div:
		if (r == 0)  {
			sprintf(cwerrstr, "Division by zero.");
			asm_error_loc(pt->line);
			return(AVAL_NOGOOD);
		}
		return(mk_aval(l / r));
		break;
	case pt_end:
		if (pt->val != AVAL_NOGOOD)
			return(pt->val);
		return(strfetch(pt->str, curaddr, pt->line));
		break;
	}
}


static int  strfetch(char *str, aval_t curaddr, unsigned line)  {
	stmt_t  *s = newprog;
	int  result;

	while (s != NULL)  {
		if (!strcmp(str, s->str))  {
			if (s->op != op_equ)
				return(s->addr - curaddr);
			else  {
				if (s->marked)  {
					sprintf(cwerrstr, "Recursive \"EQU\" definition of label \"%s\".",
									str);
					asm_error_loc(s->line);
					return(INT_BAD);
				}
				s->marked = TRUE;
				result = fetchaddr(s->a->pt, curaddr);
				s->marked = FALSE;
				return(result);
			}
		}
		s = s->next;
	}
	sprintf(cwerrstr, "Unknown label \"%s\".", str);
	asm_error_loc(line);
	return(INT_BAD);
}


static void  clearstmt(stmt_t *s)  {
	if (s != NULL)  {
		clearstmt(s->next);
		if (s->a != NULL)  {
			clearpt(s->a->pt);
			free(s->a);
		}
		if (s->b != NULL)  {
			clearpt(s->b->pt);
			free(s->b);
		}
		free(s);
	}
}


static void  clearpt(ptree_t *pt)  {
	if (pt != NULL)  {
		clearpt(pt->left);
		clearpt(pt->right);
		free(pt);
	}
}


/* I'm always kinda hazy on how strict C compilers are about modulus of
 *   negative numbers so I do things extra careful here.
 */
static aval_t  mk_aval(int ival)  {
	if (ival == INT_BAD)
		return(AVAL_NOGOOD);
	if (ival < 0)  {
		ival = -ival % coresize;
		if (ival == 0)
			return(0);
		else
			return(coresize - ival);
	} else
		return(ival % coresize);
}

