%{

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

#include "log.h"
#include "taccutil.h"
#include "sscanr.h"
#include "debug.h"
#include "mmalloc.h"

/*



    The hack for EXPR vs BEXPR is now getting too messy.  Remove it, add
    a symbol table, and check properly.  I gave up patching the parser
    with guards when I got to this example: I:=ifI=0thenifJ=0then1else2else3;

-----------------------------------------------------------------------------

     This program parses an Algol60 source file, and walks the parse tree
    to output the source with consistent case and indentation.  It is
    roughly equivalent to the original Algol60 SOAP program, but not as clever.

    This is not yet released for prime time!  It was written solely as an
    excuse to use the Algol60 grammar and see how it worked.

    The input for this program must come from the "filter" program also
    in this directory.  Note different manufacturers' compilers use slightly
    different concrete syntax and therefore require a different filter program
    to do line reconstruction.  There appears to be a major problem in
    the grammar relating to strings of the form <string>, which is ambiguous
    due to '<' and '>' relation operators.  Stripping spaces and converting
    keywords within such a string may not be wanted.

 */

/* This is the type of objects passed around as $1, $$ etc. */
#define USERTYPE char

#define RBRACE '}'
  /* Bug in tacc translation  - } skipped OK in strings but not int consts */
#define SQUOTE 39
#define DQUOTE 34


int exit_flag = FALSE;
int printing = TRUE;
int ilev = 0; /* nested begin/end for now.  Later use a stack */
int delayed_ilev = 0;
extern int _debug; /* set to true for parser diags */
int label = FALSE;

char *ProgName = "algolps9";
extern char **argv;
extern int argc;

int verbose = FALSE;

void indent(int ilev)
{
  while (ilev-- > 0) printf("   ");
}

char *doubleup(char *text, int c)
{
   char *s, *t;
   int ccount = 0;
   s = text;
   while (*s != '\0') if (*s++ == c) ccount += 1;
   t = s = stackmalloc(strlen(text)+ccount+1);
   if (s == NULL) {
      fprintf(stderr, "copyof: malloc fails - not enough room.\n");
      exit(EXIT_FAILURE);
   }
   for (;;) {
     if (*text == c) *s++ = c;
     if ((*s++ = *text++) == '\0') break;
   }
   return(t);
}

char *formatf(char *s, ...)
{
  /* Size the string by vfprint'ing it to /dev/null... */
  /* then heapmalloc an appropriate area                */
  char *APPROPRIATE_STRING;
  va_list ap;          

  va_start(ap, s);
  
  {
    static FILE *nullfile = NULL;
    int string_length;
    
    if (nullfile == NULL) nullfile = fopen("/dev/null", "w");
    if (nullfile == NULL) {
      fprintf(stderr, "Major error - cannot open /dev/null\n");
      fflush(stderr);
      exit(1);
    }
    string_length = vfprintf(nullfile, s, ap);
    /* fclose(nullfile); */
    APPROPRIATE_STRING = tempheapmalloc(string_length+1);
    vsprintf(APPROPRIATE_STRING, s, ap);
  }
  va_end(ap);
  return(APPROPRIATE_STRING);
}

char *strlwr(char *orig)
{
  char *s = orig;
  for (;;) {
    if (*s == '\0') break;
    if ((isalpha(*s)) && (isupper(*s))) *s = tolower(*s);
    s++;
  }
  return(orig);
}

             
%}

/* Main cheats - it invokes the parsing routines explicitly,
   in order to reduce the size of the parse tree for a whole
   file.  Also allows recovery of errors at useful boundaries */

main: ""
  {
    YYTYPE *subroot;
    void *stacktop;
    int i;

    if (strcmp(argv[argc-1], "-v") == 0) {
      argc -= 1;
      verbose = TRUE;
    }
    if (strcmp(argv[argc-1], "-d") == 0) {
      argc -= 1;
      _debug = TRUE;
    }
    if (strcmp(argv[argc-1], "-vd") == 0) {
      argc -= 1;
      _debug = TRUE;
      verbose = TRUE;
    }


    if (argc == 1) {
       yyin = fopen("test.ii", "r");
    } else if (argc != 2) {
       fprintf(stderr, "syntax: algolps9 infile.ii\n");
       /* Let's just resume for now... */
       yyin = fopen(argv[1], "r");
    } else {
       yyin = fopen(argv[1], "r");
    }
    if (yyin == NULL) {
       fprintf(stderr, "algolps9: cannot open input\n");
       exit(EXIT_FAILURE);
    }

    fprintf(stderr, "%s: processing %s\n", argv[0], argv[1] == NULL ? "test.ii" : argv[1]);

    if (verbose) fprintf(stderr, "Starting\n");
    fprintf(stdout, "<HTML><HEAD></HEAD><BODY><PRE>");
    for (;;) {
      stacktop = stackmark();
      if (SS_parse(&subroot)) {
          execute_parsetree(subroot);
      } else {
          fprintf(stdout, "</PRE></BODY>\n");
          return(FALSE);
      }
      stackrelease(stacktop);
      if (exit_flag) {
          return(TRUE);
      }
      printf("\n");
      ilev += delayed_ilev; delayed_ilev = 0;
    }
  }
;

DECLIST:     <NAME> <NOTENAME> <RESTOFDECLIST> {
               $$ = formatf("%s%s%s", $1, $2, $3);
};

RESTOFDECLIST: "," <NAME> <NOTENAME> <RESTOFDECLIST> {
               $$ = formatf(", %s%s%s", $2, $3, $4);
}
|            "" {
               $$ = formatf("");
};

OPERAND:     <NAME><TYPENOTBOOLEAN><APP> {
               $$ = formatf("%s%s%s", $1, $2, $3);
}
|            <CONST> {
               $$ = $1;
}
|            "\("<EXPR>"\)" {
               $$ = formatf("(%s)", $2);
};

EXPR:        "if" <BEXPR> "then"  <PLUSopt> <OPERAND> <RESTOFEXPR>
             "else" <EXPR> {
               $$ = formatf("<u><b>if</b></u> %s <u><b>then</b></u> %s%s%s <u><b>else</b></u> %s", $2, $4, $5, $6, $8);
}
|            <PLUSopt> <OPERAND> <RESTOFEXPR> {
               $$ = formatf("%s%s%s", $1, $2, $3);
};

RESTOFEXPR:  <OP> <OPERAND> <RESTOFEXPR> {
               $$ = formatf(" %s %s%s", $1, $2, $3);
}
|            "" {
               $$ = formatf("");
};

APP:         <TYPEeqARR> <LHSQBR> <EXPR> <RESTOFAPP> <RHSQBR> {
               $$ = formatf("%s[%s%s]", $1, $3, $4);
}
|            "\(" <RTP> <RESTOFRTPLIST> "\)" {
               $$ = formatf("(%s%s)", $2, $3);
}
|            "" {
               $$ = formatf("");
};

RESTOFAPP:   "," <EXPR> <RESTOFAPP> {
               $$ = formatf(", %s%s", $2, $3);
}
|            "" {
               $$ = formatf("");
};

LABAPP:      <LHSQBR> <EXPR> <RESTOFAPP> <RHSQBR> {
               $$ = formatf("[%s%s]", $2, $3);
}
|            "\(" <RTP> <RESTOFRTPLIST> "\)" {
               $$ = formatf("(%s%s)", $2, $3);
}
|            "" {
               $$ = formatf("");
};

BCONST:      "true" {
               $$ = formatf("<u><b>true</b></u>");
}
|            "false" {
               $$ = formatf("<u><b>false</b></u>");
};

BOP:         "and" {
               $$ = formatf(" %s ", (TRUE?"<IMG SRC=\"and.gif\" WIDTH=8 HEIGHT=9 ALT=\"IMPL\">":"<u><b>and</b></u>"));
}
|            "\&" {
               $$ = formatf(" %s ", (TRUE?"<IMG SRC=\"and.gif\" WIDTH=8 HEIGHT=9 ALT=\"IMPL\">":"&amp;"));
}
|            "or" {
               $$ = formatf(" %s ", (TRUE?"<IMG SRC=\"or.gif\" WIDTH=8 HEIGHT=9 ALT=\"OR\">":"<u><b>or</b></u>"));
}
|            "impl" {
               $$ = formatf(" %s ", (TRUE?"<IMG SRC=\"impl.gif\" WIDTH=8 HEIGHT=9 ALT=\"IMPL\">":"<u><b>impl</b></u>"));
}
|            "equiv" {
               $$ = formatf(" %s ", (TRUE?"<IMG SRC=\"equiv.gif\" WIDTH=8 HEIGHT=9 ALT=\"EQUIV\">":"<u><b>eqv</b></u>"));
}
|            "eqv" {
               $$ = formatf(" %s ", (TRUE?"<IMG SRC=\"equiv.gif\" WIDTH=8 HEIGHT=9 ALT=\"EQUIV\">":"<u><b>eqv</b></u>"));
};

BTERM:       "not" <BOPERAND> {
               $$ = formatf("%s%s", (TRUE?"&not;":"<u><b>not</b></u> "), $2);
}
|            <BOPERAND> {
               $$ = $1;
};

SBEXPR:      <BTERM> <RESTOFSBEXPR> {
               $$ = formatf("%s%s", $1, $2);
};

RESTOFSBEXPR: <BOP> <BTERM> <RESTOFSBEXPR> {
               $$ = formatf("%s%s%s", $1, $2, $3);
}
|             "" {
               $$ = formatf("");
};

BEXPR:        "if" <BEXPR> "then" <SBEXPR> "else" <BEXPR> {
               $$ = formatf("<u><b>if</b></u> %s <u><b>then</b></u> %s <u><b>else</b></u> %s", $2, $4, $6);
}
|             <SBEXPR> {
               $$ = $1;
};

BOPERAND:    <EXPR> <COMP> <EXPR> {
               $$ = formatf("%s %s %s", $1, $2, $3);
}
|            <NAME> <TYPENOTARITH> <APP> {
               $$ = formatf("%s%s%s", $1, $2, $3);
}
|            <BCONST> {
               $$ = $1;
}
|            "\(" <BEXPR> "\)" {
               $$ = formatf("(%s)", $2);
};

TYPEopt:     "integer"
{
               $$ = formatf("<u><b>integer</b></u> ");
}
|            "real" {
               $$ = formatf("<u><b>real</b></u> ");
}
|            "boolean" {
               $$ = formatf("<u><b>Boolean</b></u> ");
}
|            "" {
               $$ = formatf("");
};

VALUEq:      <semi> <OPTCOM> "value" <NOTELINE> <ONAMELIST> <VALUEq> { /* was * missing in grammar? */
               $$ = formatf("; %s\n  <u><b>value</b></u> %s%s", $2, $4, $5);
}
|            "" {
               $$ = formatf("");
};

FPDEL:       "label" <LABTYPE> <DECLIST> {
               $$ = formatf("<u><b>label</b></u> %s%s", $2, $3);
}
|            "switch" <SWBYNAME> <DECLIST> {
               $$ = formatf("<u><b>switch</b></u> %s%s", $2, $3);
}
|            "string" <STRTYPE> <DECLIST> {
               $$ = formatf("<u><b>string</b></u> %s%s", $2, $3);
}
|            <TYPEopt> <PDECLN> {
               $$ = formatf("%s%s", $1, $2);
};

PDECLN:      "array" <ARRAYTYPE> <DECLIST> {
               $$ = formatf("<u><b>array</b></u> %s%s", $2, $3);
}
|            "procedure" <PROCTYPE> <DECLIST> <PARCOM> {
               $$ = formatf("<u><b>procedure</b></u> %s%s%s", $2, $3, $4);
}
|             <SCALARTYPE> <DECLIST> <?semi> { /* Added by GT to disambiguate I := I+1; from typless "I" decln. */
               $$ = formatf("%s%s", $1, $2);
};

FPP:         "\(" <NAME> <RESTOFFPLIST> "\)" {
               $$ = formatf("(%s%s)", $2, $3);
}
|            "" {
               $$ = formatf("");
};

RESTOFFPLIST: <FPSEP> <NAME> <RESTOFFPLIST> {
               $$ = formatf("%s%s%s", $1, $2, $3);
}
|            "" {
               $$ = formatf("");
};

FPSEP:       "," {
               $$ = formatf(", ");
}
|            "\)" <LETTERSTRING> ":\(" {
               $$ = formatf(", "); /* SIMPLIFY FOR NOW */
};

OPTCOM:      "comment" <COMTEXT> <OPTCOM> { // Not sure about the * here...
               $$ = formatf("<u><b>comment</b></u> %s", $2);
}
|            "" {
               $$ = formatf("");
};

FPSPEC:      <semi> <OPTCOM> <NOTELINE> <FPDEL> <FPSPEC> {
               $$ = formatf(";\n  %s%s%s%s", $2, $3, $4, $5);
}
|            "" {
               $$ = formatf("");
};

PARCOM:      <semi> "comment" "\(" <NAME> <RESTOFFPLIST> "\)"
                   <COMVAL> <COMFP> <CHECKSC> {
               $$ = formatf(";\n  <u><b>comment</b></u> (%s%s)%s%s%s", $4, $5, $7, $8, $9);
}
|            "" {
               $$ = formatf("");
};

COLONq:      ":" { /* One orthography allows ".." for ":"  */
                   /* (also ".=" for ":=" and ".," for ";" */
                   /*  - the latter causing problems in comments) */
               $$ = formatf(": ");
}
|            "" {
               $$ = formatf("");
};

COMVAL:      <COLONq> "value" <NOTELINE> <ONAMELIST> {
               $$ = formatf("%s<u><b>value</b></u> %s%s", $3, $4); /* Is <NOTELINE> a dummy? */
}
|            "" {
               $$ = formatf("");
};

COMFP:       <COLONq> <NOTELINE> <COMDEL> <COMFP> {
               $$ = formatf("%s%s%s%s", $1, $2, $3, $4); /* Is <NOTELINE> a dummy? */
}
|            "" {
               $$ = formatf("");
};

COMDEL:      "label" <CNLIST> {
               $$ = formatf("<u><b>label</b></u> %s", $2);
}
|            "switch" <CNLIST> {
               $$ = formatf("<u><b>switch</b></u> %s", $2);
}
|            "string" <CNLIST> {
               $$ = formatf("<u><b>string</b></u> %s", $2);
}
|            <TYPEopt> <COMDECLN> {
               $$ = formatf("%s%s", $1, $2);
};

COMDECLN:    "array" <CNLIST> {
               $$ = formatf("<u><b>array</b></u> %s", $2);
}
|            "procedure" <CNLIST> {
               $$ = formatf("<u><b>procedure</b></u> %s", $2);
}
|             <SCALARTYPE> <CNLIST> {
               $$ = formatf("%s%s", $1, $2);
};

CNLIST:      <NAME> <RESTOFCNLIST> {
               $$ = formatf("%s%s", $1, $2);
};

RESTOFCNLIST: "," <NAME> <RESTOFCNLIST> {
               $$ = formatf(", %s%s", $2, $3);
}
|            "" {
               $$ = formatf("");
};

GENSDE:      <NAME> <LABAPP> {
               $$ = formatf("%s%s", $1, $2);
}
|            "\(" <GENDE> "\)" {
               $$ = formatf("(%s)", $2);
};

GENDE:       "if" <BEXPR> "then" <GENSDE> "else" <GENDE> {
               $$ = formatf("<u><b>if</b></u> %s <u><b>then</b></u> %s <u><b>else</b></u> %s", $2, $4, $6);
}
|            <GENSDE> {
               $$ = $1;
};

SDE:         <NAME> <APP> {
               $$ = formatf("%s%s", $1, $2);
}
|            "\(" <DE> "\)" {
               $$ = formatf("(%s)", $2);
};

DE:          "if" <BEXPR> "then" <SDE> "else" <DE> {
               $$ = formatf("<u><b>if</b></u> %s <u><b>then</b></u> %s <u><b>else</b></u> %s", $2, $4, $6);
}
|            <SDE> {
               $$ = $1;
};

RESTOFGENDELIST: "," <GENDE> <RESTOFGENDELIST> {
               $$ = formatf(", %s%s", $2, $3);
}
|            "" {
               $$ = formatf("");
};

RTP:         <TEXTTEXT> {
               $$ = $1;
}
|            <NAME> <APP> <NOMORE> { /* Nomore is true if next char is , or ) */
               $$ = formatf("%s%s", $1, $2);
}
|            <EXPR> <NOMORE> {/* <NOMORE> */
               $$ = formatf("%s", $1);
}
|            <BEXPR> <NOMORE> {/* <NOMORE> */
               $$ = formatf("%s", $1);
}
|            <DE> <NOMORE> {/* <NOMORE> */
               $$ = formatf("%s", $1);
};

RESTOFRTPLIST: <FPSEP> <RTP> <RESTOFRTPLIST> {
               $$ = formatf("%s%s%s", $1, $2, $3);
}
|            "" {
               $$ = formatf("");
};

RESTOFASS:   <APP> ":=" <RESTOFABLP> <abEXPR> {
               $$ = formatf("%s := %s%s", $1, $3, $4);
};

abEXPR:      <EXPR> <?closer> {
               $$ = $1;
}
|            <BEXPR> <?closer> {
               $$ = $1;
};

RESTOFABLP:   <CHKLPL> <ONAME> <APP> ":=" <RESTOFABLP> {
               $$ = formatf("%s%s%s := %s", $1, $2, $3, $5);
}
|            "" {
               $$ = formatf("");
};


oldRESTOFASS:   <TYPEeqA> <APP> ":=" <oldRESTOFALP> <EXPR> {

/* problem with the parsing algorithm: if we get a successful parse
   here, e.g I := I, then this returns TRUE and does not try the
   second alternative of I := I+1 because the PARENT of this
   phrase moves on to *his* second alternative.  The semantic
   guard here from the original parser would have avoided that
   trap, but at this stage I do not know if my variable is a Boolean
   or not because I have not been building a symbol table.  In
   order to do it properly I either need a symbol table, *or*
   a major revamp of the parser to retry from the last successful
   option rather than the last failed one. :-/
   In the mean time, parsing the Arithmetic assignment first seems
   to succeed more often than parsing the Boolean one, so I
   have swapped the order of the two phrases below.  Originally
   it was Boolean then Arithmetic.
 */

               $$ = formatf("%s%s := %s%s", $1, $2, $4, $5);
}
|            <TYPEeqB> <APP> ":=" <oldRESTOFBLP> <BEXPR> { /* ORDER SWAPPED TO TEST A HYPOTHESIS */
               $$ = formatf("%s%s := %s%s", $1, $2, $4, $5);
};

oldRESTOFBLP:   <CHKLPL> <ONAME> <TYPEeqB> <APP> ":=" <oldRESTOFBLP> {
               $$ = formatf("%s%s%s%s := %s", $1, $2, $3, $4, $6);
}
|            "" {
               $$ = formatf("");
};

oldRESTOFALP:   <CHKLPL> <ONAME> <TYPEeqA> <APP> ":=" <oldRESTOFALP> {
               $$ = formatf("%s%s%s%s := %s", $1, $2, $3, $4, $6);
}
|            "" {
               $$ = formatf("");
};

RESTOFFLE:   "step" <EXPR> "until" <EXPR> {
               $$ = formatf(" <u><b>step</b></u> %s <u><b>until</b></u> %s", $2, $4);
}
|            "while" <BEXPR> {
               $$ = formatf(" <u><b>while</b></u> %s", $2);
}
|            "" {
               $$ = formatf("");
};

RESTOFFORLIST: "," <EXPR> <RESTOFFLE> <RESTOFFORLIST> {
               $$ = formatf(",\n      %s%s%s", $2, $3, $4);
}
|            "" {
               $$ = formatf("");
};

RESTOFBPLIST: "," <EXPR> ":" <EXPR> <RESTOFBPLIST> {
               $$ = formatf(", %s : %s%s", $2, $4, $5);
}
|            "" {
               $$ = formatf("");
};

DECLN:       <SCALARTYPE> <DECLIST> {
               $$ = formatf("%s%s", $1, $2);
}
|            "array" <ARRAYTYPE> <OADECLN> {
               $$ = formatf("<u><b>array</b></u> %s%s", $2, $3);
};

ADECLN:      <DECLIST> <BPAIR> <RESTOFARRAYLIST> {
               $$ = formatf("%s%s%s", $1, $2, $3);
};

RESTOFARRAYLIST: "," <ADECLN> {
               $$ = formatf(", %s", $2);
}
|            "" {
               $$ = formatf("");
};

BPAIR:       <CBPAIR> {
               $$ = $1;
}
|            <LHSQBR> <EXPR> ":" <EXPR> <RESTOFBPLIST> <RHSQBR> {
               $$ = formatf("[%s : %s%s]", $2, $4, $5);
};

CBPAIR:      <LHSQBR> <PLUSopt> <ICONST> ":"
                      <PLUSopt> <ICONST> <RESTOFCBP> <RHSQBR> {
               $$ = formatf("[%s%s : %s%s%s]", $2, $3, $5, $6, $7);
};

RESTOFCBP:   "," <PLUSopt> <ICONST> ":" <PLUSopt> <ICONST> <RESTOFCBP> {
               $$ = formatf(", %s%s : %s%s%s", $2, $3, $5, $6, $7);
}
|            "" {
               $$ = formatf("");
};

OADECLN:     <DECLIST> <CBPAIR> <RESTOFOADEC> {
               $$ = formatf("%s%s%s", $1, $2, $3);
};

RESTOFOADEC: "," <OADECLN> {
               $$ = formatf(", %s", $2);
}
|            "" {
               $$ = formatf("");
};

VDECLNa:     "procedure" <PROCTYPE> <LINKPROC> <NAME> <NOTENAME> <FPP> <DOWN> {
               $$ = formatf("<u><b>procedure</b></u> %s%s%s%s%s%s", $2, $3, $4, $5, $6, $7); /* NOTENAME and DOWN are dummies? */
};

VDECLNb:     <VALUEq> <FPSPEC> <semi> <OPTCOM> <OLABEL> <PROCSTMT> { /* params, then procedure body */
               $$ = formatf("%s%s;\n%s%s%s", $1, $2, $4, $5, $6);
};

VDECLN:      <VDECLNa><VDECLNb> { /* tacc limitation of $0-$9 */
               $$ = formatf("%s%s", $1, $2);
}
|            "array" <ARRAYTYPE> <LINKARR> <ADECLN> {
               $$ = formatf("<u><b>array</b></u> %s%s%s", $2, $3, $4);
}
|            <SCALARTYPE> <LINKSCAL> <DECLIST> {
               $$ = formatf("%s%s%s", $1, $2, $3);
};

COMP:        "=" {
               $$ = formatf("%s", @1.text);
}
|            ">=" {
               $$ = formatf((TRUE?"<IMG SRC=\"ge.gif\" WIDTH=9 HEIGHT=9 ALT=\"NOTLESS\">":"&gt;="));
}
|            ">" {
               $$ = formatf("&gt;");
}
|            "<>" {
               $$ = formatf((TRUE?"<IMG SRC=\"ne.gif\" WIDTH=9 HEIGHT=9 ALT=\"NOTEQUAL\">":"&lt;&gt;"));
}
|            "|=" { // does | have to be escaped?  Should we handle this in wfilter.c instead?  Along with |< and |>
               $$ = formatf((TRUE?"<IMG SRC=\"ne.gif\" WIDTH=9 HEIGHT=9 ALT=\"NOTEQUAL\">":@1.text));
}
|            "<=" {
               $$ = formatf((TRUE?"<IMG SRC=\"le.gif\" WIDTH=9 HEIGHT=9 ALT=\"NOTLESS\">":"&lt;="));
}
|            "<" {
               $$ = formatf("&lt;");
}
|            "#" {
               $$ = formatf((TRUE?"<IMG SRC=\"ne.gif\" WIDTH=9 HEIGHT=9 ALT=\"NOTEQUAL\">":"#"));
}
|            "equal" {
               $$ = formatf((TRUE?"=":"<u><b>equal</b></u>"));
}
|            "eq" {
               $$ = formatf((TRUE?"=":"<u><b>eq</b></u>"));
}
|            "ge" {
               $$ = formatf((TRUE?"<IMG SRC=\"ge.gif\" WIDTH=9 HEIGHT=9 ALT=\"NOTLESS\">":"<u><b>ge</b></u>"));
}
|            "gt" {
               $$ = formatf((TRUE?"&gt;":"<u><b>gt/em>"));
}
|            "ne" {
               $$ = formatf((TRUE?"<IMG SRC=\"ne.gif\" WIDTH=9 HEIGHT=9 ALT=\"NOTEQUAL\">":"<u><b>ne</b></u>"));
}
|            "notequal" {
               $$ = formatf((TRUE?"<IMG SRC=\"ne.gif\" WIDTH=9 HEIGHT=9 ALT=\"NOTEQUAL\">":"<u><b>notequal</b></u>"));
}
|            "less" {
               $$ = formatf((TRUE?"&lt;":"<u><b>lt</b></u>" /* alternative orthography */));
}
|            "le" {
               $$ = formatf((TRUE?"<IMG SRC=\"le.gif\" WIDTH=9 HEIGHT=9 ALT=\"NOTLESS\">":"<u><b>le</b></u>"));
}
|            "notgreater" {
               $$ = formatf((TRUE?"<IMG SRC=\"le.gif\" WIDTH=9 HEIGHT=9 ALT=\"NOTLESS\">":"<u><b>notgreater</b></u>"));
}
|            "lt" {
               $$ = formatf((TRUE?"&lt;":"<u><b>lt</b></u>"));
}
|            "!=" {
               $$ = formatf((TRUE?"<IMG SRC=\"ne.gif\" WIDTH=9 HEIGHT=9 ALT=\"NOTEQUAL\">":@1.text));
}
|            "\\=" { // escaped \
               $$ = formatf((TRUE?"<IMG SRC=\"ne.gif\" WIDTH=9 HEIGHT=9 ALT=\"NOTEQUAL\">":@1.text));
};

OLABEL:      <CHKLAB> <NAME> <!ass> ":" <LINKLAB> <OLABEL> {
               $$ = formatf("%s%s: %s%s", $1, $2, $5, $6);
}
|            "" {
               $$ = formatf("");
};

NSTMT:       <UI> {
               $$ = $1;
}
|            "for" <FORSTMNT> {
               $$ = formatf("<u><b>for</b></u> %s", $2);
}
|            "if" <BEXPR> "then" <OLABEL> <USTMT> {
               $$ = formatf("<u><b>if</b></u> %s <u><b>then</b></u> %s%s", $2, $4, $5);
}
|            <CHECKSC> { /* Is this perhaps 'check semi'? replacable by <?semi>  ??? */
               $$ = $1;
};

FORSTMNT:    <ONAME> <APP> ":=" <EXPR> <RESTOFFLE>
               <RESTOFFORLIST> "do" <OLABEL> <FSTMT> {
               if ((strlen($8)+strlen($9)) > 10) {
                 $$ = formatf("%s%s := %s%s%s <u><b>do</b></u>\n  %s%s", $1, $2, $4, $5, $6, 
                              $8, $9);
               } else {
                 $$ = formatf("%s%s := %s%s%s <u><b>do</b></u>%s%s%s", $1, $2, $4, $5, $6, 
                              ((((*$8) == '\0') && ((*$9) == ';')) ? "" : " "),
                              $8, $9);
               }
};

STMT:        <UI> {
               $$ = $1;
}
|            "for" <FORSTMNT> {
               $$ = formatf("<u><b>for</b></u> %s", $2);
}
|            "if" <BEXPR> "then" <OLABEL> <USTMT> {
               $$ = formatf("<u><b>if</b></u> %s <u><b>then</b></u> %s%s", $2, $4, $5);
}
|            "" {
               $$ = formatf("");
};

BLKORCS:     <OPTCOM> <OLABEL> <NSTMT> <CMPND> {
               $$ = formatf("%s%s%s%s", $1, $2, $3, $4);
}
|            <DOWN> {
               $$ = $1;
};

FSTMT:       "begin" <DOWN> {
               $$ = formatf("<u><b>begin</b></u>"); delayed_ilev += 1;
}
|            <STMT> {
               $$ = $1;
};

USTMT:       "begin" <BLKORCS> {
               $$ = formatf("<u><b>begin</b></u>"); delayed_ilev += 1;
}
|            "for" <FORSTMNT> {
               $$ = formatf("<u><b>for</b></u> %s", $2);
}
|            <UI> <ELSEq> {
               $$ = formatf("%s%s", $1, $2);
}
|            <ELSEq> {
               $$ = $1;
};

EPNAME:      <NAME> {
               $$ = $1;
}
|            "" {
               $$ = formatf("");
};

PROCSTMT:    "algol" <EPNAME> <UP> {
               $$ = formatf("<u><b>algol</b></u> %s", $2);
}
|            "external" <EPNAME> <UP> {
               $$ = formatf("<u><b>external</b></u> %s", $2);
}
|            "fortran" <EPNAME> <UP> {
               $$ = formatf("<u><b>fortran</b></u> %s", $2);
}
|            "begin" {
               $$ = formatf("<u><b>begin</b></u>"); delayed_ilev += 1;
}
|            <UPATSEP> <NOTELINE> <STMT> {
               $$ = formatf("%s%s%s", $1, $2, $3);
};

ELSEq:       "else" <NOTELINE> <OLABEL> <ELSESTMNT> {
               $$ = formatf(" <u><b>else</b></u> %s%s", $3, $4);
}
|            "" {
               $$ = formatf("");
};

ELSESTMNT:   "begin" <BLKORCS> {
               $$ = formatf("<u><b>begin</b></u>%s", $2); delayed_ilev += 1;;
}
|            <STMT> {
               $$ = $1;
};

UI:          <CHKLPL> <ONAME> <RESTOFASS> {
               $$ = formatf("%s%s%s", $1, $2, $3);
}
|            <NAME> <APP> {
               $$ = formatf("%s%s", $1, $2);
}
|            "goto" <DE> {
               $$ = formatf("<u><b>goto</b></u> %s", $2);
};

SS:          <eof> { exit_flag = TRUE; } |
             <STMNT> {
               int i, c;
               char *line = $1;
               i = ilev*4;
               while (i-- > 0) fputc(' ', stdout);
               for (;;) {
                 c = (*line++)&255; if (c == '\0') break;
                 if (c == '\n') {
                   i = ilev*4;
                   fputc('\n', stdout);
                   while (i-- > 0) fputc(' ', stdout);
                 } else fputc(c, stdout);
               }
               /* indent(ilev); */
               /* fprintf(stdout, "%s", $1); fflush(stdout); */
}
|            "[^;]*;" {
               fprintf(stdout, "\n* Syntax error at: %s\n", @1.text);
};

STMNT:       <NSTMT> <S> {
               $$ = formatf("%s;", $1);
}
|            "end" <UP> <ENDTEXT> <ELSEq> <S> {
               $$ = formatf("<u><b>end</b></u>%s%s;", $3, $4); ilev -= 1;
}
|            "end" <UP> <RENDTEXT> { /* final end of program */
               $$ = formatf("<u><b>end</b></u>%s;", $3); ilev -= 1;
}
|            "comment" <COMTEXT> {
               $$ = formatf("<u><b>comment</b></u> %s",/*removed ';'*/ $2 /* unconvert any 'KEYWORDS' in comment text? */ );
}
|            <TYPEopt> <VDECLN> <S> { 
               $$ = formatf("%s%s;", $1, $2);
}
|            "begin" <BLKORCS> <S> {
               $$ = formatf("<u><b>begin</b></u>%s;", $2); delayed_ilev += 1;
}
|            "switch" <SWTYPE> <NAME> <NOTENAME> <LINKSW> ":="
                      <GENDE> <RESTOFGENDELIST> <S> {
               $$ = formatf("<u><b>switch</b></u> %s%s%s%s := %s%s;", $2, $3, $4, $5, $7, $8);
}
|            "own" <LINKOWNS> <TYPEopt> <DECLN> <S> {
               $$ = formatf("<u><b>own</b></u> %s %s;", $3, $4);
}
|            <CHKLAB> <NAME> ":" <LINKLAB> <STMNT> {
               $$ = formatf("%s%s: %s%s", $1, $2, $4, $5);
}
|            <semi> { /* empty statement? - isn't this already caught in NSTMT/STMT/UI?*/
               $$ = formatf(";");
}
|            "codeon" <S> {
               $$ = formatf("'<u><b>codeon</b></u>;");
}
|            "codeoff" <S> {
               $$ = formatf("<u><b>codeoff</b></u>;");
}
|            "program" <NAME> <S> {
               $$ = formatf("<u><b>program</b></u> %s;", $2);
};

/* BIPS */

NOTENAME:    "" { $$ = formatf(""); };
S:           <semi> { $$ = formatf(";"); }
|            <?end> { $$ = formatf(""); }
|            <?else> { $$ = formatf(""); };
UP:          "" { $$ = formatf(""); };
DOWN:        "" { $$ = formatf(""); };
CHKLAB:      "" { $$ = formatf(""); };
ass:         ":=" { $$ = formatf(""); };
LINKOWNS:    "" { $$ = formatf(""); };
ARRAYTYPE:   "" { $$ = formatf(""); };
CHECKSC:     <?semi> { $$ = formatf(""); /* GUESSING!!! */ };
CHKLPL:      "" { $$ = formatf(""); };
CMPND:       <?S> {
               $$ = formatf(""); /* Also need <!LevelLessthanOne> (BIP1036)*/
}
|            <?end> {
               $$ = formatf(""); /* Also need <!LevelLessthanOne> (BIP1036)*/
};

COMTEXT:     "[^;]*" <continuecom> {  /* BREAKS WHEN ".," USED AS SEMI! */
               $$ = formatf("%s%s", @1.text, $2);
               /* WARNING: <COMTEXT> may be multi-line - not yet handled in 'filter.c
... */ 
               /* Also... should we undo 'KEYWORD' translation in comments here? */
};

continuecom: "$" <COMTEXT> {
               $$ = formatf("\n%s", $2);
}
|            "" {
               $$ = formatf("");
};

ENDTEXT:     <RENDTEXT> { $$ = formatf(" %s", $1); };
RENDTEXT:    <!semi> <!end> <!else> <ch> <RENDTEXT> {
               $$ = formatf("%s%s", $4, $5);
}
|            "" { $$ = formatf(""); /* text up to ; or 'end' or 'else' */ };
end:         "end" {};
then:        "then" {};
else:        "else" {};
semi:        ";" {}
|            "\.," { /* alternative orthography */};
ch:          "." { $$ = formatf("%s", @1.text); };
closer:      <semi> { $$ = $1; }
|            <comma> { $$ = $1; }
|            <crb> { $$ = $1; }
|            <else> { $$ = $1; }
|            <then> { $$ = $1; };

ICONST:      <PLUSopt> "[0-9][0-9]*" { $$ = formatf("%s%s", $1, @2.text); };

decfract:    "\.[0-9][0-9]*" { $$ = formatf("%s", @1.text); };
expart:      <subten> <ICONST> { $$ = formatf("%s%s", $1, $2); };
decnum:      "[0-9][0-9]*" <decfract> { $$ = formatf("%s%s", @1.text, $2); }
|            <decfract> { $$ = $1; }
|            "[0-9][0-9]*" { $$ = formatf("%s", @1.text); };
unsigned:    <decnum> <expart> { $$ = formatf("%s%s", $1, $2); }
|            <expart> { $$ = $1; }
|            <decnum> { $$ = $1; };
CONST:       <PLUSopt> <unsigned> { $$ = formatf("%s%s", $1, $2); };
subten:      "\&" { $$ = formatf("%s", (TRUE?"<sub>10</sub>":@1.text)); }
|            "@" { $$ = formatf("%s", (TRUE?"<sub>10</sub>":@1.text)); };
LABTYPE:     "" { $$ = formatf(""); };
LETTERSTRING: "[A-Z]*" { $$ = formatf("%s", @1.text); };
LHSQBR:      "\[" { $$ = formatf("[");/* escaped [ */ } | "\(/" { $$ = formatf("["); };
RHSQBR:      "\]" { $$ = formatf("]");/* escaped ] */ } | "/\)" { $$ = formatf("]"); };
LINKARR:     "" { $$ = formatf(""); };
LINKLAB:     "" { $$ = formatf(""); };
LINKPROC:    "" { $$ = formatf(""); };
LINKSCAL:    "" { $$ = formatf(""); };
LINKSW:      "" { $$ = formatf(""); };
NAME:        "[A-Z][A-Z0-9]*" { $$ = formatf("%s", @1.text); };

NOMORE:      <?comma> { $$ = formatf(""); }
|            <?crb> { $$ = formatf(""); /* true if next char is "," or ")" */ };
comma:       "," {};
crb:         "\)" {};

NOTELINE:    "" { $$ = formatf(""); };
ONAME:       "[A-Z][A-Z0-9]*" { $$ = formatf("%s", @1.text); };
ONAMELIST:   <ONAME> <RESTOFONAMELIST> { $$ = formatf("%s%s", $1, $2); };
RESTOFONAMELIST: "," <ONAMELIST> { $$ = formatf(", %s", $2); /* I'm guessing ... */ }
|            "" { $$ = formatf(""); };

OP:          "\^" { $$ = formatf((TRUE?"<IMG SRC=\"power.gif\" WIDTH=7 HEIGHT=9 ALT=\"POWER\">":"^")); }
|            "\*\*" { $$ = formatf((TRUE?"<IMG SRC=\"power.gif\" WIDTH=7 HEIGHT=9 ALT=\"POWER\">":"**")); }
|            "\+" { $$ = formatf("+"); }
|            "\-" { $$ = formatf("-"); }
|            "\*" { $$ = formatf((TRUE?"<IMG SRC=\"times.gif\" WIDTH=7 HEIGHT=9 ALT=\"TIMES\" HSPACE=\"1\">":"*")); }
|            "/" { $$ = formatf((TRUE?"&divide;":"/")); } 
|            "div" { $$ = formatf((TRUE?"&divide;":"<u><b>div</b></u>")); }
|            "mod" { $$ = formatf((FALSE?"%":"<u><b>mod</b></u>")); }
|            "%" { $$ = formatf((FALSE?"%":"<u><b>mod</b></u>"));
               /* BOGUS operator as far as I can see.  Used in the example
                  for jensen's device (jensen3.a60) found at everything2.com */
}
|            "power" { $$ = formatf((TRUE?"<IMG SRC=\"power.gif\" WIDTH=7 HEIGHT=9 ALT=\"POWER\">":"<u><b>power</b></u>")); };

PLUSopt:     "\+" { $$ = formatf("+"); /* Unary ops */ }
|            "\-" { $$ = formatf("-"); }
|            "" { $$ = formatf(""); };
PROCTYPE:    "" { $$ = formatf(""); };
SCALARTYPE:  "" { $$ = formatf(""); };
STRTYPE:     "" { $$ = formatf(""); };
SWBYNAME:    "" { $$ = formatf(""); };
SWTYPE:      "" { $$ = formatf(""); };

TEXTTEXT:    "<" "[^<>]*" <RESTOFTEXTTEXT> {
               $$ = formatf("&lt;%s%s", @2.text, $3);
               /* any keywords need to be expanded back to 'KEYWORDS' */
}
|            "\"[^\"]*\"" { $$ = formatf("%s", @1.text);}
|            "`[^']*'" { $$ = formatf("%s", @1.text);}
;
RESTOFTEXTTEXT: ">" { $$ = formatf(">"); }
|            <TEXTTEXT> "[^<>]*" ">" {
               $$ = formatf("%s%s&gt;", $1, @2.text);
};

TYPEeqA:     "" { $$ = formatf(""); /* Arithmetic */ };
TYPEeqARR:   "" { $$ = formatf(""); /* Array? */ };
TYPEeqB:     "" { $$ = formatf(""); /* Boolean */ };
TYPENOTARITH:"" { $$ = formatf(""); };
TYPENOTBOOLEAN:"" { $$ = formatf(""); };
UPATSEP:     "" { $$ = formatf(""); };

%{

extern int debug(const char *fmt, ...);
extern int debug_enter(const char *fmt, ...);
extern int debug_exit(const char *fmt, ...);

extern FILE *yyin;

int eof_parse(YYTYPE **p)
{
  int c;
  c = fgetc(yyin);
  if (c == EOF) {
    return(TRUE);
  }
  ungetc(c, yyin);
  return(FALSE);
}

int setdebug_parse(YYTYPE **p)
{
  _debug = TRUE;
  return(TRUE);
}

int candebug_parse(YYTYPE **p)
{
  _debug = FALSE;
  return(TRUE);
}

%}