// It is here for incorporating as the basis of a compile() function to do something useful with an AST.
// For example this generated the code that was manually converted into algol60-indent.h

#define X_APP 1
#include <stdio.h>

void xcompile(int P, int depth, char *file, int line) {
#define compile(P, depth) xcompile(P, depth, __FILE__, __LINE__)
  //fprintf(stderr, "\"%s\":%d: compile(%x (%d), %d);\n", file, line, P, PhraseType(P), depth);
  if (P == -1) {
    //fprintf(stderr, "compile(%d,%d);\n", P, depth);
    return;
  }
  int i;
  // avoid runtime error of "left shift of 15 by 28 places":
  int AST_type = P_AST_type(P); //(int)((unsigned int)P&(((unsigned int)AST_type_mask)<<(unsigned int)AST_type_shift));

#ifdef NEVER
#define NEGATED_PHRASE (1U<<24U)
#define GUARD_PHRASE (1U<<25U)
#define WHITESPACE_ALLOWED (1U<<26U)
  #define GRAMMAR_TYPE_SHIFT 27U
  #define GRAMMAR_TYPE_MASK 31U
#define BIP_TYPE (1U <<27U)
#define PHRASE_TYPE (2U <<27U)
#define SEMANTIC_TYPE (3U <<27U)
#define KEYWORD_TYPE (4U <<27U)
#define CHAR_TYPE (5U <<27U)
#define UTF32CHAR_TYPE (6U <<27U)
#define STRING_TYPE (7U <<27U)
#define UTF32STRING_TYPE (8U <<27U)
#define REGEXP_TYPE (9U <<27U)
#define OPTION_TYPE (10U <<27U)
#define COUNT_OF_ALTS (11U <<27U)
#define COUNT_OF_PHRASES (12U <<27U)
#define ALT_NUMBER (13U <<27U)
  #define INDEX_MASK 0x7FFFFFU
  // (We have room for types 1..31U)
#endif  

#ifdef NEVER
#define AST_idx_mask 0x7FFFFFFU
#define AST_type_shift 27U
#define AST_type_mask  31U
#define AST_BIP      (16U << AST_type_shift)
#define AST_PHRASE   (17U << AST_type_shift)
#define AST_ATOM_LIT (18U << AST_type_shift)
#define AST_POOL_LIT (19U << AST_type_shift)
  // Up to 31U is free...

#define SubPhraseIdx(P,N)  AST(((P)&AST_idx_mask)+4+TUPLE_RESULT_FIELDS+(N)-1)
  //                                                ^ reserved + op + alt + count = 4
#define SubPhrase(P,N)    (SubPhraseIdx(P,N)&AST_idx_mask)

  // SubPhraseIdx(P,N) is identical to P(Ph,x) below:
#define P_AST_type(Ph)   ((Ph) & (AST_type_mask << AST_type_shift))
#define P_AST_index(Ph)  ((Ph) & AST_idx_mask)
#define P_op(Ph)         AST(P_AST_index(Ph)+1)
#define P_alt(Ph)        AST(P_AST_index(Ph)+2)
#define P_count(Ph)      AST(P_AST_index(Ph)+3)

#define TUPLE_RESULT_FIELDS 4
#define RESULT_FIELD_TYPEINFO 0
#define P_TYPEINFO(Ph)   AST(P_AST_index(Ph)+4+RESULT_FIELD_TYPEINFO)
#define RESULT_FIELD_ISCONST 1
#define P_ISCONST(Ph)    AST(P_AST_index(Ph)+4+RESULT_FIELD_ISCONST)
#define RESULT_FIELD_SOURCEFILE 2
#define P_FILE(Ph)       AST(P_AST_index(Ph)+4+RESULT_FIELD_SOURCEFILE)
#define RESULT_FIELD_SOURCELINE 3
#define P_LINE(Ph)       AST(P_AST_index(Ph)+4+RESULT_FIELD_SOURCELINE)
#define P_P(Ph,x)        AST(P_AST_index(Ph)+4+TUPLE_RESULT_FIELDS+(x)-1)
#endif
  
  if (PhraseType(P) > PhraseType(AST_POOL_LIT)) {
    fprintf(stderr, "Warning: compile(%08x (%u),%d);\n", P, PhraseType(P), depth);
  }

  if (AST_type == PHRASE_TYPE) {   // DEBUG CHANGED AST_PHRASE TO PHRASE_TYPE
    int AST_index = P_AST_index(P); // P&AST_idx_mask;
    int op = P_op(P); // AST(AST_index+1);
    int count = P_count(P); // AST(AST_index+3);

    // We can use the default code for the majority of the grammar, and
    // intercept the grammar rules here which we want to tweak.  OR we
    // could modify c.g to handle the changed rules in the code that is
    // embedded in the grammar itself.
    
    switch (op) {

    //\\ P<identifier> =
    //case P_identifier:
    case G_identifier:
      //fprintf(stdout, "{");  // Mark variables
      // compiling the guard phrase is causing an error.
      compile(SubPhraseIdx(P,2), depth+1);
      //fprintf(stdout, "}");
      return;

    //\\ P<HACK1> =
    //case P_HACK1:
    case G_HACK1:
      //fprintf(stdout, "/*<FOLD:*/");
      return;

    //\\ P<HACK2> =
    //case P_HACK2:
    case G_HACK2:
      //fprintf(stdout, "/*:FOLD>*/");
      return;

    default: // Use the default output code:
      for (i = 1; i <= count; i++) compile(SubPhraseIdx(P,i), depth+1);
    }

  } else if (AST_type == AST_PHRASE) {   // DEBUG CHANGED AST_PHRASE TO PHRASE_TYPE. So this may now be redundant.
    fprintf(stderr, "Warning: AST_PHRASE being executed\n");
    int AST_index = P_AST_index(P); // P&AST_idx_mask;
    int op = P_op(P); // AST(AST_index+1);
    int count = P_count(P); // AST(AST_index+3);

    switch (op) {
    default: // Use the default output code:
      for (i = 1; i <= count; i++) compile(SubPhraseIdx(P,i), depth+1);
    }

  } else if (AST_type == AST_ATOM_LIT/*ERAL*/) {  // Warning: BIPs might not have AST_BIP embedded in their results for P_mktuple()
    int AST_index = P_AST_index(P); // P&AST_idx_mask;
    PrintAtom(AST_index);

  } else if (AST_type == AST_BIP) {  // Warning: BIPs might not have AST_BIP embedded in their results for P_mktuple()
    int AST_index = P_AST_index(P); // P&AST_idx_mask;
    fprintf(stderr, "AST_BIP at %s, line %d\n", __FILE__, __LINE__);
    fprintf(stdout, "AST_BIP at %s, line %d\n", __FILE__, __LINE__);
    exit(1);
    PrintAtom(AST_index);

  } else {
    fprintf(stderr, "Unknown AST_type %08x (%u) at %s, line %d\n", AST_type, (unsigned int)AST_type>>AST_type_shift, __FILE__, __LINE__);
    fprintf(stdout, "Unknown AST_type %08x (%u) at %s, line %d\n", AST_type, (unsigned int)AST_type>>AST_type_shift, __FILE__, __LINE__);
    exit(1);
    
  }
  fflush(stdout);
}
