%{

#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"

/*
     This program parses a Coral66 source file, and walks the parse tree
    to output the source with consistent case and indentation.

    The input for this program must come from the "filter" program also
    in this directory.


    The grammar needs to be refactored a little; currently it parses
    anything starting with BEGIN as a single block unit; it needs to
    split those up into separate statements and keep an explicit
    stack of nested constructs.   Note that the language uses ";"
    as a separator, not a terminator, so some statements require
    a terminating semicolon and some don't.  Could make a refactored
    grammar a little tricky.

 */

/* 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 = "c66tohtml";
extern char **argv;
extern int argc;

int verbose = FALSE;

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


void outs(char *line) {
  int i, c;
  static int soft = FALSE, outpos = 0;
  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); outpos = 0;
      while (i-- > 0) {fputc(' ', stdout); outpos++;}
      ilev += delayed_ilev; delayed_ilev = 0;
      soft = TRUE;
    } else {
      if (soft && ((c == ';') || (c == '\n'))) {
      } else {
        if (c == ' ' && (outpos >= 72)/* && (outpos + strlen(line) > 78)*/) {
          fputc('\n', stdout); outpos = 0;
          i = ilev*4; while (i-- > 0) {fputc(' ', stdout); outpos++;}
          fputc(' ', stdout); fputc(' ', stdout); outpos += 2;
        } else {
          fputc(c, stdout); outpos++;
        }
        soft = FALSE;
      }
    }
  }
}



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: c66tohtml 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, "c66tohtml: 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");

    for (;;) {
      stacktop = stackmark();
      if (Statementlist_parse(&subroot)) {
          execute_parsetree(subroot);
      } else {
          return(FALSE);
      }
      stackrelease(stacktop);
      if (exit_flag) return(TRUE);
      //printf("\n");
    }
  }
;

Actual: 
    <Expression> { $$ = $1; }
|   <Wordreference> { $$ = $1; }
|   <Destination> { $$ = $1; }
|   <Name> { $$ = $1; };


Actuallist: 
    <Actual> <RestofActuallist> { $$ = formatf("%s%s", $1, $2); };

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

Addoperator: 
    "+" { /* NOTE: No void choice.  Compare against <sign> ... */ 
       $$ = formatf(" + ");
}
|   "\-" { $$ = formatf(" - "); };


Alternative: 
    <Statement> { $$ = $1; };


Answerspec: 
    <Numbertype> { $$ = $1; }
|   "" {
       /* Void */
       $$ = formatf("");
};


Answerstatement: 
    "ANSWER" <Expression> { $$ = formatf("'ANSWER' %s", $2); };


Arraydec: 
    <Numbertype> "ARRAY" <Arraylist> <Presetlist> { $$ = formatf("%s'ARRAY' %s%s", $1, $3, $4); };


Arrayitem: 
    <Idlist> "\[" <Sizelist> "\]" { $$ = formatf("%s[ %s ]", $1, $3); };


Arraylist: 
    <Arrayitem> <RestofArraylist> { $$ = formatf("%s%s", $1, $2); };

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


Assignmentstatement: 
    <Variable> ":=" <Expression> { $$ = formatf("%s := %s", $1, $3); }
|   <Macrocall> ":=" <Expression> { $$ = formatf("%s := %s", $1, $3); };


Base: 
    "\(" <Id> "\)" { $$ = formatf("(%s)", $2); }
|   <Id> "\[" <Signedinteger> "\]" { $$ = formatf("%s[%s]", $1, $3); };


Bitposition:  <Integer> { $$ = $1; };


Block: 
    "BEGIN" {
       /* <Declist> ";" <Statementlist> "END" */
       $$ = formatf("'BEGIN'");
       delayed_ilev += 1;
};


Booleanword: 
    <Typedprimary> <RestofBooleanexpr> { $$ = formatf("%s%s", $1, $2); };

RestofBooleanexpr:
    <Boolop> <Typedprimary> <RestofBooleanexpr> { $$ = formatf("%s%s%s", $1, $2, $3); }
|   "" { $$ = formatf(""); };

Boolop:
    "DIFFER" { $$ = formatf(" 'DIFFER' "); }
|   "UNION" { $$ = formatf(" 'UNION' "); }
|   "MASK" { $$ = formatf(" 'MASK' "); }
|   "SRL" { $$ = formatf(" 'SRL' "); }
|   "SLL" { $$ = formatf(" 'SLL' "); };

OldBooleanword:
    <BooleanwordA> { }
|   <BooleanwordC> "DIFFER" <BooleanwordD> { };


BooleanwordA: 
    <BooleanwordB> { } 
|   <BooleanwordD> "UNION" <BooleanwordE> { };


BooleanwordB: 
    <BooleanwordE> "MASK" <Typedprimary> { };


BooleanwordC: 
    <Booleanword> { } 
|   <Typedprimary> { };


BooleanwordD: 
    <BooleanwordA> { } 
|   <Typedprimary> { }; 


BooleanwordE: 
    <BooleanwordB> { /* Hmmm... 3 and 6 are an infinite loop ... */} 
|   <Typedprimary> { }; 


Bracketedcomment: 
    "\([^\)]*\)" {
       /* (  any sequence of characters in which round brackets are matched  ) */
       /* TO DO: Add nesting. */
      $$ = formatf("%s", @1.text);
}
|   "" { $$ = formatf(""); };

Codesequence: 
    "<[^>]*>" {
       /* defined in a particular implementation */
       /* For example, machine code */
       $$ = formatf("%s", @1.text);
};

Codestatement: 
    "CODE" "BEGIN" <Codesequence> "END" <endtag> { $$ = formatf("'CODE' 'BEGIN' %s 'END'%s", $3, $4); };


Commentsentence: 
    "COMMENT" "[^;]*" {
       /* any sequence of characters not including a semi-colon ; *
       /* TO DO: Allow newlines.  Steal code from Algol60 grammar */
    $$ = formatf("'COMMENT' %s", @2.text);
};
clines:
    "[^;]*" "$" <clines> { $$ = formatf("%s\n%s", @1.text, $3); }
|   "" { $$ = formatf(""); };

Commoncommunicator: 
    <exttype> "\(" <Commonitemlist> "\)" { $$ = formatf("%s(%s)", $1, $3); };
exttype:
    "COMMON" { $$ = formatf("'COMMON' "); }
|   "EXTERNAL" { $$ = formatf("'EXTERNAL' "); };

Commonitem: 
    <Datadec> { $$ = $1; } 
|   <Overlaydec> { $$ = $1; }
|   <Placespec> { $$ = $1; }
|   <Procedurespec> { /* removed Void alternative */ $$ = $1; }
|   <Commentsentence> { $$ = $1; };


Commonitemlist: 
    <Commonitem> ";" <RestofCommonitemlist> { $$ = formatf("%s; %s", $1, $3); };

RestofCommonitemlist:
    <Commonitem> ";" <RestofCommonitemlist> { $$ = formatf("%s; %s", $1, $3); }
|   "" { $$ = formatf(""); };

Comparator: 
    "=" { $$ = formatf(" = "); }
|   ">=" { $$ = formatf(" >= "); }
|   ">" { $$ = formatf(" > "); }
|   "<=" { $$ = formatf(" <= "); }
|   "<>" { $$ = formatf(" <> "); }
|   "<" { $$ = formatf(" < "); };


Comparison: 
    <Simpleexpression> <Comparator> <Simpleexpression> { $$ = formatf("%s%s%s", $1, $2, $3); };


Compoundstatement: 
    "BEGIN" {
       /* <Statementlist> "END" */
       $$ = formatf("'BEGIN'");
       delayed_ilev += 1;
}; 


Condition: 
    <SubCondition> <RestofCondition> { $$ = formatf("%s%s", $1, $2); }; 

RestofCondition:
    "OR" <SubCondition> <RestofCondition> { $$ = formatf(" 'OR' %s%s", $2, $3); }
|   "" { $$ = formatf(""); };


Conditionalexpression: 
    "IF" <Condition> "THEN" <Expression> "ELSE" <Expression> { $$ = formatf("'IF' %s 'THEN' %s 'ELSE' %s", $2, $4, $6); }; 


Conditionalstatement: 
    "IF" <Condition> "THEN" <LabelledStatement> <RestofConditionalstatement> {
       if ((strncmp($4, "'BEGIN'", 7) == 0) || (strncmp($5, "'BEGIN'", 7) == 0)) {
          $$ = formatf("'IF' %s 'THEN' %s%s\n", $2, $4, $5);
       } else {
          $$ = formatf("'IF' %s 'THEN'\n  %s%s", $2, $4, $5);
       }
};

RestofConditionalstatement: 
    "ELSE" <Alternative> { $$ = formatf("\n'ELSE'\n  %s", $2); }
|   "" { $$ = formatf(""); };

Constant: 
    <Number> { $$ = $1; }
|   <Addoperator> <Number> { $$ = formatf("%s%s", $1, $2); }
|   <Expression> { /* ONLY IF ANY <Id>s IN <Expression> ARE ALREADY DEFINED AS CONSTANT SYMBOLS */ $$ = $1; }; 


Constantlist: 
    <Group> <RestofConstantlist> { $$ = formatf("%s%s", $1, $2); };

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

Datadec: 
    <Numberdec> { $$ = $1; }
|   <Arraydec> { $$ = $1; }
|   <Tabledec> { $$ = $1; }; 


Dec: 
    <Datadec> { $$ = $1; }
|   <Overlaydec> { $$ = $1; }
|   <Switchdec> { $$ = $1; }
|   <Proceduredec> { $$ = $1; };


Declist: 
    <Dec> <RestofDeclist> { $$ = formatf("%s%s", $1, $2); };
 
RestofDeclist: 
    ";" <Dec> <RestofDeclist> { $$ = formatf("; %s%s", $2, $3); }
|   "" { $$ = formatf(""); };

Destination: 
    <Label> { $$ = $1; }
|   <Switch> "\[" <Index> "\]" { $$ = formatf("%s[%s]", $1, $3); }; 


Digit:
    "[0-9]" {
       /*  0 1 2 3 4 5 6 7 8 9 */
       $$ = formatf("%s", @1.text);
};

Digitlist: 
    "[0-9][0-9]*" {
       /* <Digit> <RestofDigitlist> */
       $$ = formatf("%s", @1.text);
};
    
Dimension: 
    <Lowerbound> ":" <Upperbound> { $$ = formatf("%s : %s", $1, $3); };


Dummystatement: 
    <?term><!eof> {
       /* void */
       $$ = formatf("");
};
term: ";" { $$ = formatf(";"); }
|     "END" <endtag> { $$ = formatf("'END'%s", $2); }
|     "ELSE" { $$ = formatf("'ELSE'"); };

likesemi:
    ";" { $$ = formatf(";"); }
|   <?term> { /* Don't eat END or ELSE */ $$ = formatf("\n"); };

Elementdec: 
    <Id> <Numbertype> <Wordposition> { $$ = formatf("%s%s%s", $1, $2, $3); }
|   <Id> <Partwordtype> <Wordposition> "," <Bitposition> { $$ = formatf("%s%s%s, %s", $1, $2, $3, $5); }; 


Elementdeclist: 
    <Elementdec> <RestofElementdeclist> { $$ = formatf("%s%s", $1, $2); };

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

Elementpresetlist: 
    "PRESET" <Constantlist> { $$ = formatf("'PRESET' %s", $2); }
|   "" {
       /* Void */
       $$ = formatf("");
};

Elementscale: 
    "\(" <Totalbits> "," <Fractionbits> "\)" { $$ = formatf("(%s, %s)", $2, $4); }
|   "\(" <Totalbits> "\)" { $$ = formatf("(%s)", $2); };


Endcomment: 
    <Id> { $$ = $1; }; 


Expression: 
    <Unconditionalexpression> { $$ = $1; }
|   <Conditionalexpression> { $$ = $1; };


Factor: 
    <Primary> <!Boolop> { $$ = $1; }
|   <Booleanword> { $$ = $1; }; 


Forelement: 
    <Expression> "WHILE" <Condition> { $$ = formatf("%s 'WHILE' %s", $1, $3); }
|   <Expression> "STEP" <Expression> "UNTIL" <Expression> { $$ = formatf("%s 'STEP' %s 'UNTIL' %s", $1, $3, $5); }
|   <Expression> { /* re-factor this! */ $$ = $1; };


Forlist: 
    <Forelement> <RestofForlist> { $$ = formatf("%s%s", $1, $2); };

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

Formalpair: 
    <Id> ":" <Id> { $$ = formatf("%s:%s", $1, $3); }; 

Formalpairlist: 
    <Formalpair> <RestofFormalpairlist> { $$ = formatf("%s%s", $1, $2); };

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

Forstatement: 
    "FOR" <Wordreference> ":=" <Forlist> "DO" <Statement> { $$ = formatf("'FOR' %s := %s 'DO' %s", $2, $4, $6); };


Fractionbits:
    <Signedinteger> { $$ = $1; };


Gotostatement: 
    "GOTO" <Destination> { $$ = formatf("'GOTO' %s", $2); };


Group: 
    <Constant> { $$ = $1; }
|   "\(" <Constantlist> "\)" { $$ = formatf("(%s)", $2); }
|   "" {
       /* Void */
       $$ = formatf("");
};

Id: 
    "[a-z][_a-z0-9]*" {
       /* <Letter> <Letterdigitstring> */
       $$ = formatf("%s", @1.text);
};

Idlist: 
    <Id> <RestofIdlist> { $$ = formatf("%s%s", $1, $2); };

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

Index: 
    <Expression> { $$ = $1; };


Integer: 
    <Digitlist> { $$ = $1; }
|   "HEX" "\(" <Hexlist> "\)" { $$ = formatf("'HEX'(%s)", $3); }
|   "OCTAL" "\(" <Octallist> "\)" { $$ = formatf("'OCTAL'(%s)", $3);}
|   "LITERAL" "\(" "." "\)" {
       /* printing character */
       $$ = formatf("'LITERAL'(%s)", @3.text);
};

Hexlist: 
    "[a-f0-9][a-f0-9]*" {
    $$ = formatf("%s", @1.text);
};


Label:
    <Id> { $$ = $1; }; 


Labellist: 
    <Label> <RestofLabellist> { $$ = formatf("%s%s", $1, $2); };

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

Length:
    <Integer> { $$ = $1; };


Letter:
    "[a-z]" {
       /* a b c d e f g h i j k l m n o p q r s t u v w x y z */
       $$ = formatf("%s", @1.text);
};

Letterdigitstring: 
    "[a-z0-9]*" {
       /* not needed now - see <Id> */
       /* <Letter> <Letterdigitstring> */
       /* <Digit> <Letterdigitstring> */
       /* Void */
       $$ = formatf("%s", @1.text);
};

Lowerbound: 
    <Signedinteger> { $$ = $1; };


Macrobody: 
    "[^\"]*" {
       /* any sequence of characters in which string quotes are matched */
       /* TO DO: match string quotes */
       $$ = formatf("%s", @1.text);
};

Macrocall: 
    <Macroname> "\(" <Macrostringlist> "\)" { 
       $$ = formatf("%s(%s)", $1, $3); // MACRO!!! EXPAND IT!!!
}
|   <Macroname> <!lbrack> { $$ = $1; }; 


Macrodefinition: 
    "DEFINE" <Macroname> "\"" <Macrobody> "\"" ";" { $$ = formatf("'DEFINE' %s %c%s%c;", $2, DQUOTE, $4, DQUOTE); }
|   "DEFINE" <Macroname> "\(" <Idlist> "\)" "\"" <Macrobody> "\"" ";" {
       $$ = formatf("'DEFINE' %s(%s) %c%s%c;", $2, $4, DQUOTE, $7, DQUOTE);
};


Macrodeletion: 
    "DELETE" <Macroname> ";" { $$ = formatf("'DELETE' %s;", $2); };


Macroname: 
    <Id> { $$ = $1; };


Macrostring: 
    "[^\)]*" {
       /* any sequence of characters in which commas are protected by 
          round or square brackets and in which such brackets are properly
          matched and nested */
       /* TO DO: just about everything ... */
       $$ = formatf("%s", @1.text);
};

Macrostringlist: 
    <Macrostring> <RestofMacrostringlist> { $$ = formatf("%s%s", $1, $2); };

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

Multoperator: 
    "\*" { $$ = formatf(" * "); }
|   "/" { $$ = formatf(" / "); };


Name: 
    <Id> { $$ = $1; };


Number: 
    <Real> { $$ = $1; }
|   <Integer> { $$ = $1; };


Numberdec: 
    <Numbertype> <Idlist> <Presetlist> { $$ = formatf("%s%s%s", $1, $2, $3); }; 


Numbertype: 
    "FLOATING" { $$ = formatf("'FLOATING' "); }
|   "FIXED" <Scale> { $$ = formatf("'FIXED' %s", $2); }
|   "LONGINTEGER" { $$ = formatf("'LONG' 'INTEGER' "); }
|   "INTEGER" { $$ = formatf("'INTEGER' "); }
|   "CONSTANT" { $$ = formatf("'CONSTANT' "); }
|   "BYTE" { $$ = formatf("'BYTE' ");};

Octaldigit:
    "[0-7]" {
       /* 0 1 2 3 4 5 6 7 */
    $$ = formatf("%s", @1.text);
};

Octallist: 
    "[0-7][0-7]*" {
       /* Octaldigit Octalist */
       /* Octaldigit */
       $$ = formatf("%s", @1.text);
};

Overlaydec: 
    "OVERLAY" <Base> "WITH" <Datadec> { $$ = formatf("'OVERLAY' %s 'WITH' %s", $2, $4); }; 


Parameterspec: 
    "VALUE" <Formalpairlist> { $$ = formatf("'VALUE' %s", $2); }
|   "LOCATION" <Formalpairlist> { $$ = formatf("'LOCATION' %s", $2); }
|   <Specifier> <Idlist> { $$ = formatf("%s%s", $1, $2); }
|   <Tablespec> { $$ = $1; }
|   <Procedurespec> { $$ = $1; }; 


Parameterspeclist: 
    <Parameterspec> <RestofParameterspeclist> { $$ = formatf("%s%s", $1, $2);};

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

Partword: 
    <Id> "\[" <Index> "\]" { $$ = formatf("%s[%s]", $1, $3); }
|   "BITS" "\[" <Totalbits> "," <Bitposition> "\]" <Typedprimary> { $$ = formatf("'BITS'[%s, %s]%s", $3, $5, $7); }; 


Partwordreference: 
    <Id> "\[" <Index> "\]" { $$ = formatf("%s[%s]", $1, $3); }
|   "BITS" "\[" <Totalbits> "," <Bitposition> "\]" <Wordreference> { $$ = formatf("'BITS'[%s, %s]%s", $3, $5, $7); }; 


Partwordtype: 
    <Elementscale> { $$ = $1; }
|   "UNSIGNED" <Elementscale> { $$ = formatf("'UNSIGNED' %s", $2); }; 


Placespec: 
    "LABEL" <Idlist> { $$ = formatf("'LABEL' %s", $2); } 
|   "SWITCH" <Idlist> { $$ = formatf("'SWITCH' %s", $2); }; 


Presetlist: 
    ":=" <Constantlist> { $$ = formatf(" := %s", $2); }
|   "" {
       /* Void */
       $$ = formatf("");
};

Primary: 
    <Untypedprimary> { $$ = $1; }
|   <Typedprimary> { $$ = $1; }; 


Procedurecall: 
    <Id> "\(" <Actuallist> "\)" <!ass> { $$ = formatf("%s(%s)", $1, $3);} 
|   <Id> <!lbrack> <!ass> { $$ = $1; };


Proceduredec: 
    <Answerspec> <Recursive> <Procedureheading> <?term> { /* ";" <Statement> */
       $$ = formatf("%s%s%s", $1, $2, $3);
};

Recursive:
    "RECURSIVE" { $$ = formatf("'RECURSIVE' "); }
|   "PROCEDURE" { $$ = formatf("'PROCEDURE' "); };

Procedureheading: 
   <Id> "\(" <Parameterspeclist> "\)" { $$ = formatf("%s(%s)", $1, $3); }
|  <Id> { $$ = $1; };


Procedurespec: 
    <Answerspec> "PROCEDURE" <Procparamlist> { $$ = formatf("%s'PROCEDURE' %s", $1, $3); /* No RECURSIVE? */}; 


Procparameter: 
    <Id> "\(" <Typelist> "\)" { $$ = formatf("%s(%s)", $1, $3); }
|   <Id> { $$ = $1; };


Procparamlist: 
    <Procparameter> <RestofProcparamlist> { $$ = formatf("%s%s", $1, $2); };

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

Real: 
    <Digitlist> "\." <Digitlist> <subten> <Signedinteger> { $$ = formatf("%s.%s%s%s", $1, $3, $4, $5); }
|   <Digitlist> "\." <Digitlist> { $$ = formatf("%s.%s", $1, $3); }
|   <Digitlist> <subten> <Signedinteger> { $$ = formatf("%s%s%s", $1, $2, $3); }
|   <subten> <Signedinteger> <!Id> <!lbrack> { /* AMBIGUOUS PARSE: "e1" could be <Real> *or* <Id> */
       $$ = formatf("%s%s", $1, $2);
}
|   "OCTAL" "\(" <Octallist> "\." <Octallist> "\)" { $$ = formatf("'OCTAL'(%s.%s)", $3, $5); };

subten:
    "@" { /* subscript 10 */ $$ = formatf("@"); }
|   "e" { $$ = formatf("E"); };

lbrack:
    "\(" { $$ = formatf("("); }
|   "\[" { $$ = formatf("["); };

Scale:
    "\(" <Totalbits> "," <Fractionbits> "\)" { $$ = formatf("(%s, %s)", $2, $4); }; 


Sign: 
    "+" { $$ = formatf("+"); }
|   "\-" { $$ = formatf("-"); }
|   "" {
       /* Void */
       $$ = formatf("");
};

Signedinteger: 
    <Integer> { $$ = $1; }
|   <Addoperator> <Integer> { /* Not <sign>??? */ $$ = formatf("%s%s", $1, $2); }; 


Simpleexpression: 
    <Term> <RestofSimpleexpression> { $$ = formatf("%s%s", $1, $2); }
|   <Addoperator> <Term> <RestofSimpleexpression> { /* note allows initial +/- but not a <sign> ??? */ 
       $$ = formatf("%s%s%s", $1, $2, $3);
};

RestofSimpleexpression:
    <Addoperator> <Term> <RestofSimpleexpression> { $$ = formatf(" %s %s%s", $1, $2, $3); }
|   <!Boolop> "" { $$ = formatf(""); };


Sizelist: 
    <Dimension> "," <Dimension> { $$ = formatf("%s, %s", $1, $3); } 
|   <Dimension> { $$ = $1; };


Specifier: 
    "VALUE" <Numbertype> { $$ = formatf("'VALUE' %s", $2); }
|   "LOCATION" <Numbertype> { $$ = formatf("'LOCATION' %s", $2); }
|   <Numbertype> "ARRAY" { $$ = formatf("%s'ARRAY' ", $1); } 
|   "LABEL" { }
|   "SWITCH" { }; 


Specimen: 
    "ALPHA" <Sign> { $$ = formatf("'ALPHA'%s", $2); /* WHERE IS THIS USED??? */ }
|   "BETA" <Sign> { $$ = formatf("'BETA'%s", $2); };


Simplestatement: 
    <Assignmentstatement> { $$ = $1; }
|   <Gotostatement> { $$ = $1; }
|   <Procedurecall> { $$ = $1; }
|   <Answerstatement> { $$ = $1; }
|   <Codestatement> { $$ = $1; }
|   <Compoundstatement> { $$ = $1; }
|   <Block> { /* Removed <Dummystatement> */ $$ = $1; };


LabelledStatement: 
    <Labels> <Simplestatement> { $$ = formatf("%s%s", $1, $2); };

Labels:
    <Label> <!ass> ":"  <Labels> { $$ = formatf("%s: %s", $1, $4); }
|   "" { $$ = formatf(""); };
ass: ":=" { $$ = formatf(" := "); };

Statement: 
    <LabelledStatement> { $$ = $1; }
|   <Conditionalstatement> { $$ = $1; }
|   <Forstatement> { $$ = $1; }
|   <Commentsentence> { $$ = $1; }
;

endtag:
    <!else> "[^;]*" { $$ = formatf(" %s", @2.text); }
|   "" { $$ = formatf(""); };
else: "ELSE" { };

Statementlist: 
    <eof> { exit_flag = TRUE; }
|   "$" {
       $$ = formatf("\n");
       outs($$);
}
|   <Labels> ";" {
       $$ = formatf("%s;\n", $1);
       outs($$);
}
|   "BEGIN" {
       /* Breaking down compound statements... */
       $$ = formatf("'BEGIN'\n");
       delayed_ilev += 1;
       outs($$);
}
|   "END" "ELSE" "BEGIN" {
       $$ = formatf("'END' 'ELSE' 'BEGIN'\n");
       ilev -= 1;
       outs($$);
       ilev += 1;
}
|   "END" "ELSE" <Alternative> {
       $$ = formatf("\n'END' 'ELSE' %s", $3);
       ilev -= 1;
       outs($$);
}
|   "END" <endtag> {
       $$ = formatf("\n'END'%s", $2);
       ilev -= 1;
       outs($$);
}
|   <Macrodefinition> {
       $$ = formatf("%s\n", $1);
       outs($$);
}
|   <Macrodeletion> {
       $$ = formatf("%s\n", $1);
       outs($$);
}
|   "INCLUDE" "\"[^\"]*\";" {
      $$ = formatf("\n'INCLUDE' %s\n", @2.text);
      outs($$);
}
|   <Dec> ";" <Bracketedcomment> {
       $$ = formatf("%s;%s\n", $1, $3);
       outs($$);
}
|   <Statement> <likesemi> <Bracketedcomment> {
       /* break out into C loop to reduce parse-tree size */
       /* <RestofStatementlist> */
       $$ = formatf("%s%s%s\n", $1, $2, $3); outs($$); 
}
|   <Commoncommunicator> {
       /* NOT followed by semi */
       $$ = formatf("%s\n", $1);
}
|   "[^;]*;" {
       fprintf(stdout, "* Syntax?  '%s'\n", @1.text);
}
|   ".*END" {
      fprintf(stdout, "* Syntax?  '%s'\n", @1.text);
}
|   ".*ELSE" {
      fprintf(stdout, "* Syntax?  '%s'\n", @1.text);
}
|   ".*\)" {
      fprintf(stdout, "* Syntax?  '%s'\n", @1.text);
}
|   ".*" <eof> {
      fprintf(stdout, "* Syntax?  '%s'\n", @1.text);
}
|   ".*" {
      fprintf(stdout, "* Syntax?  '%s'\n", @1.text);
};

RestofStatementlist:
    ";" <Statement> <RestofStatementlist> {
       /* currently this phrase is never used */
       $$ = formatf("; %s%s", $2, $3);
}
|   "" {
       $$ = formatf("");
};

String: 
    "\"[^\"]*\"" {
       /* " sequence of characters with quotes matched " */
       $$ = formatf("%s", @1.text);
};

SubCondition: 
    <Comparison> <RestofSubcondition> { $$ = formatf("%s%s", $1, $2); };

RestofSubcondition: 
    "AND" <Comparison> <RestofSubcondition> { 
       $$ = formatf(" 'AND' %s%s", $2, $3);
}
|   "" { $$ = formatf(""); };

Switch:
    <Id> { $$ = $1; };


Switchdec: 
    "SWITCH" <Switch> ":=" <Labellist> { $$ = formatf("'SWITCH' %s := %s", $2, $4); };


Tabledec: 
    "TABLE" <Id> "\[" <Width> "," <Length> "\]" <Tablerest> {
       /* Careful... TACC limitation of 9 items in phrase */
       $$ = formatf("'TABLE' %s[%s, %s]%s", $2, $5, $7, $8);
}; 
Tablerest:
    "\[" <Elementdeclist> <Elementpresetlist> "\]" <Presetlist> {
       $$ = formatf("[%s%s]%s", $2, $3, $5);
};

Tablespec: 
    "TABLE" <Id> "\[" <Width> "," <Length> "\]\[" <Elementdeclist> "\]" {
       $$ = formatf("'TABLE' %s[%s, %s] [%s]", $2, $4, $6, $8);
}; 


Term: 
    <Factor> <RestofTerm> { $$ = formatf("%s%s", $1, $2); };

RestofTerm:
    <Multoperator> <Factor> <RestofTerm> { $$ = formatf(" %s %s%s", $1, $2, $3); }
|   <!Boolop> "" { $$ = formatf(""); }; 


Totalbits:
    <Integer> { $$ = $1; }; 


Type: 
    <Specifier> { $$ = $1; }
|   "TABLE" { $$ = formatf("'TABLE' "); }
|   <Answerspec> "PROCEDURE" { $$ = formatf("%s'PROCEDURE' ", $1); }; 


Typedprimary: 
    <Procedurecall> { $$ = $1; }
|   <Macrocall> { $$ = $1; }
|   <Wordreference> { $$ = $1; }
|   <Partword> { $$ = $1; }
|   "LOCATION" "\(" <Wordreference> "\)" { $$ = formatf("'LOCATION'(%s)", $3); }
|   <Numbertype> "\(" <Expression> "\)" { $$ = formatf("%s(%s)", $1, $3); }
|   <Integer> { $$ = $1; };


Typelist: 
    <Type> <RestofTypelist> { $$ = formatf("%s%s", $1, $2); };

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

Unconditionalexpression: 
    <Simpleexpression> { $$ = $1; }
|   <String> { $$ = $1; };


Untypedprimary: 
    <Real> { $$ = $1; }
|   "\(" <Expression> "\)" { $$ = formatf("(%s)", $2); };


Upperbound: 
    <Signedinteger> { $$ = $1; }; 


Variable: 
    <Wordreference> { $$ = $1;}
|   <Partwordreference> { $$ = $1; }; 


Width:
    <Integer> { $$ = $1; }; 


Wordposition:
    <Signedinteger> { $$ = $1; }; 


Wordreference: 
    <Id> "\[" <Index> "," <Index> "\]" { /* inefficiently factored grammar */ 
       $$ = formatf("%s[%s, %s]", $1, $3, $5);
}
|   <Id> "\[" <Index> "\]" { 
       $$ = formatf("%s[%s]", $1, $3);
}
|   <Macrocall> { $$ = $1; }
|   <Id> { $$ = $1; }
|   "\["  "\]" { $$ = 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);
}

%}