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

#include "obj.h"

#define X_APP 1
#include <stdio.h>

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

//int AST(int idx) {
//}

//int wlit(int P) {
//}

//int P(int P_) {
//}
int compile(int Ph, int depth) {

  // AST format not properly designed yet.  These are placeholders:
#define P(x) (x) // TEMP
#define A(x) (x) // TEMP
#define wlit(x) (x)

  int AST_index = Ph&AST_idx_mask;
  int AST_type  = Ph & (AST_type_mask << AST_type_shift);
  int op    = A(AST_index+1);
  int alt   = A(AST_index+2);
  int count = A(AST_index+3);
  int t[LARGEST_ALT];
  int r = 0;

  fprintf(stderr, "Ph=%d AST_type = %d  AST_index = %d  op=%d  alt=%d  count=%d\n", Ph, AST_type>>AST_type_shift, AST_index, op, alt, count);

  switch (op) {
    // 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

//\\ B<EOF> = 0;
//\\#
//\\ B<ch> = 1;
//\\#
//\\ B<bnl> = 2;
//\\#
//\\ P<nl> =
   case P_nl:
#ifdef IN_PARSER

#endif
     {                              //\\    <bnl>;
     t[1] = wlit(P(1) /*, L"bnl" */);
     return t[0] = P_mktuple(P_nl, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<int> =
   case P_int:
#ifdef IN_PARSER


#endif
     {                              //\\    «[1-9][0-9]*»;
     t[1] = wlit(P(1));
     return t[0] = P_mktuple(P_int, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<float> =
   case P_float:
#ifdef IN_PARSER


#endif
     {                              //\\    «[\-]?[0-9]*[\.][0-9]*»;
     t[1] = wlit(P(1));
     return t[0] = P_mktuple(P_float, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<SS> =
   case P_SS:
#ifdef IN_PARSER


#endif
     {                              //\\    <item> <nl> <more_items> <EOF>;
     t[1] = compile(P(1), depth+1 /* P_item */);
     t[2] = compile(P(2), depth+1 /* P_nl */);
     t[3] = compile(P(3), depth+1 /* P_more_items */);
     t[4] = wlit(P(4) /*, L"EOF" */);
     return t[0] = P_mktuple(P_SS, alt, 4/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<item> =
   case P_item:
#ifdef IN_PARSER

#endif
     if (alt == 0)               {  //\\    <comment>,
       t[1] = compile(P(1), depth+1 /* P_comment */);
       return t[0] = P_mktuple(P_item, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 1)        {  //\\    <usemtl>,
       t[1] = compile(P(1), depth+1 /* P_usemtl */);
       return t[0] = P_mktuple(P_item, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 2)        {  //\\    <mtllib>,
       t[1] = compile(P(1), depth+1 /* P_mtllib */);
       return t[0] = P_mktuple(P_item, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 3)        {  //\\    <v>,
       t[1] = compile(P(1), depth+1 /* P_v */);
       return t[0] = P_mktuple(P_item, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 4)        {  //\\    <vt>,
       t[1] = compile(P(1), depth+1 /* P_vt */);
       return t[0] = P_mktuple(P_item, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 5)        {  //\\    <vn>,
       t[1] = compile(P(1), depth+1 /* P_vn */);
       return t[0] = P_mktuple(P_item, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 6)        {  //\\    <f>,
       t[1] = compile(P(1), depth+1 /* P_f */);
       return t[0] = P_mktuple(P_item, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 7)        {  //\\    <g>,
       t[1] = compile(P(1), depth+1 /* P_g */);
       return t[0] = P_mktuple(P_item, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 8)        {  //\\    <s>,
       t[1] = compile(P(1), depth+1 /* P_s */);
       return t[0] = P_mktuple(P_item, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 9)        {  //\\    <vp>,
       t[1] = compile(P(1), depth+1 /* P_vp */);
       return t[0] = P_mktuple(P_item, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 10)        {  //\\    <o>,
       t[1] = compile(P(1), depth+1 /* P_o */);
       return t[0] = P_mktuple(P_item, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     } else if (alt == 11)        {  //\\    <l>,
       t[1] = compile(P(1), depth+1 /* P_l */);
       return t[0] = P_mktuple(P_item, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     } else                      {  //\\    <EOF>;
       t[1] = wlit(P(1) /*, L"EOF" */);
       return t[0] = P_mktuple(P_item, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<more_items> =
   case P_more_items:
#ifdef IN_PARSER

#endif
     if (alt == 0)               {  //\\    <item> <nl> <more_items>,
       t[1] = compile(P(1), depth+1 /* P_item */);
       t[2] = compile(P(2), depth+1 /* P_nl */);
       t[3] = compile(P(3), depth+1 /* P_more_items */);
       return t[0] = P_mktuple(P_more_items, alt, 3/*phrases*/, t); /* (note t[], not T[]) */

     } else                      {  //\\    ;

       return t[0] = P_mktuple(P_more_items, alt, 0/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<filename> =
   case P_filename:
#ifdef IN_PARSER


#endif
     {                              //\\    «[A-Za-z0-9\.][A-Za-z0-9_\.]*»;
     t[1] = wlit(P(1));
     return t[0] = P_mktuple(P_filename, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<non-empty-content> =
   case P_non_empty_content:
#ifdef IN_PARSER


#endif
     if (alt == 0)               {  //\\    <!nl> <ch> <non-empty-content>,
       t[1] = -1; /* ignore negative guard */;
       t[2] = wlit(P(2) /*, L"ch" */);
       t[3] = compile(P(3), depth+1 /* P_non_empty_content */);
       return t[0] = P_mktuple(P_non_empty_content, alt, 3/*phrases*/, t); /* (note t[], not T[]) */

     } else                      {  //\\    ;

       return t[0] = P_mktuple(P_non_empty_content, alt, 0/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<comment> =
   case P_comment:
#ifdef IN_PARSER

  // Some comments may be worth parsing...

  // # Vertices: 30
  // # Texture vertices: 59
  // # Normals: 30
  // # Faces: 16
      
  //fwprintf(stdout, L"COMMENT\n");

#endif
     {                              //\\    «#» <non-empty-content>;
     t[1] = wlit(P(1));
     t[2] = compile(P(2), depth+1 /* P_non_empty_content */);
     return t[0] = P_mktuple(P_comment, alt, 2/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<usemtl_options> =
   case P_usemtl_options:
#ifdef IN_PARSER


#endif
     if (alt == 0)               {  //\\    ',' «[1-9][0-9]*»,
       t[1] = wlit(P(1) /*, L',' */);
       t[2] = wlit(P(2));
       return t[0] = P_mktuple(P_usemtl_options, alt, 2/*phrases*/, t); /* (note t[], not T[]) */

     } else                      {  //\\    ;

       return t[0] = P_mktuple(P_usemtl_options, alt, 0/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<usemtl> =
   case P_usemtl:
#ifdef IN_PARSER

  // usemtl [material name]
  // usemtl NoName,1001
  // Lines starting with "usemtl" specify which material to apply to a set of faces, and are often used in conjunction with .mtl files.

  //fwprintf(stdout, L"USEMTL\n");

#endif
     {                              //\\    «usemtl» <filename> <usemtl_options>;
     t[1] = wlit(P(1));
     t[2] = compile(P(2), depth+1 /* P_filename */);
     t[3] = compile(P(3), depth+1 /* P_usemtl_options */);
     return t[0] = P_mktuple(P_usemtl, alt, 3/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<mtllib> =
   case P_mtllib:
#ifdef IN_PARSER

  // mtllib [external .mtl file name]
  // mtllib supertank2.mtl
      
  //fwprintf(stdout, L"MTLLIB\n");

#endif
     {                              //\\    «mtllib» <filename>;
     t[1] = wlit(P(1));
     t[2] = compile(P(2), depth+1 /* P_filename */);
     return t[0] = P_mktuple(P_mtllib, alt, 2/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<v> =
   case P_v:
#ifdef IN_PARSER

  // List of geometric vertices, with (x, y, z, [w]) coordinates, w is optional and defaults to 1.0.
  // v -0.002424 1.919356 -2.225567

  //fwprintf(stdout, L"V ...\n");

#endif
     {                              //\\    «v» <float> <float> <float>;
     t[1] = wlit(P(1));
     t[2] = compile(P(2), depth+1 /* P_float */);
     t[3] = compile(P(3), depth+1 /* P_float */);
     t[4] = compile(P(4), depth+1 /* P_float */);
     return t[0] = P_mktuple(P_v, alt, 4/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<vt> =
   case P_vt:
#ifdef IN_PARSER

  // List of texture coordinates, in (u, [v, w]) coordinates, these will vary between 0 and 1. v, w are optional and default to 0.
  // vt 0.000000 0.000000
  // vt 1.000000 1.000000
  // vt 1.000000 0.002445

  //fwprintf(stdout, L"VT ...\n");

#endif
     {                              //\\    «vt» <float> <float>;
     t[1] = wlit(P(1));
     t[2] = compile(P(2), depth+1 /* P_float */);
     t[3] = compile(P(3), depth+1 /* P_float */);
     return t[0] = P_mktuple(P_vt, alt, 3/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<vn> =
   case P_vn:
#ifdef IN_PARSER

  // Normals (normals might not be unit vectors)
  // vn 0.000000 0.000000 1.000000
  // vn -0.542794 0.689214 -0.479957

  //fwprintf(stdout, L"VN ...\n");

#endif
     {                              //\\    «vn» <float> <float> <float>;
     t[1] = wlit(P(1));
     t[2] = compile(P(2), depth+1 /* P_float */);
     t[3] = compile(P(3), depth+1 /* P_float */);
     t[4] = compile(P(4), depth+1 /* P_float */);
     return t[0] = P_mktuple(P_vn, alt, 4/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<vp> =
   case P_vp:
#ifdef IN_PARSER

  // Parameter space vertices in (u, [v, w]) form; free form geometry statement

  //fwprintf(stdout, L"VP ...\n");

#endif
     {                              //\\    «vn» <non-empty-content>;
     t[1] = wlit(P(1));
     t[2] = compile(P(2), depth+1 /* P_non_empty_content */);
     return t[0] = P_mktuple(P_vp, alt, 2/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<vn-index> =
   case P_vn_index:
#ifdef IN_PARSER


#endif
     {                              //\\    <int>;
     t[1] = compile(P(1), depth+1 /* P_int */);
     return t[0] = P_mktuple(P_vn_index, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<opt-f-vn> =
   case P_opt_f_vn:
#ifdef IN_PARSER


#endif
     if (alt == 0)               {  //\\    "/" <vn-index>,
       t[1] = wlit(P(1));
       t[2] = compile(P(2), depth+1 /* P_vn_index */);
       return t[0] = P_mktuple(P_opt_f_vn, alt, 2/*phrases*/, t); /* (note t[], not T[]) */

     } else                      {  //\\    ;

       return t[0] = P_mktuple(P_opt_f_vn, alt, 0/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<opt-vt-index> =
   case P_opt_vt_index:
#ifdef IN_PARSER


#endif
     if (alt == 0)               {  //\\    <int>,
       t[1] = compile(P(1), depth+1 /* P_int */);
       return t[0] = P_mktuple(P_opt_vt_index, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     } else                      {  //\\    ;

       return t[0] = P_mktuple(P_opt_vt_index, alt, 0/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<f-vt-vn-indices> =
   case P_f_vt_vn_indices:
#ifdef IN_PARSER


#endif
     if (alt == 0)               {  //\\    "/" <opt-vt-index> <opt-f-vn>,
       t[1] = wlit(P(1));
       t[2] = compile(P(2), depth+1 /* P_opt_vt_index */);
       t[3] = compile(P(3), depth+1 /* P_opt_f_vn */);
       return t[0] = P_mktuple(P_f_vt_vn_indices, alt, 3/*phrases*/, t); /* (note t[], not T[]) */

     } else                      {  //\\    ;

       return t[0] = P_mktuple(P_f_vt_vn_indices, alt, 0/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<v-index> =
   case P_v_index:
#ifdef IN_PARSER


#endif
     {                              //\\    <int>;
     t[1] = compile(P(1), depth+1 /* P_int */);
     return t[0] = P_mktuple(P_v_index, alt, 1/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<more-f-groups> =
   case P_more_f_groups:
#ifdef IN_PARSER


#endif
     if (alt == 0)               {  //\\    <v-index> <f-vt-vn-indices> <more-f-groups>,
       t[1] = compile(P(1), depth+1 /* P_v_index */);
       t[2] = compile(P(2), depth+1 /* P_f_vt_vn_indices */);
       t[3] = compile(P(3), depth+1 /* P_more_f_groups */);
       return t[0] = P_mktuple(P_more_f_groups, alt, 3/*phrases*/, t); /* (note t[], not T[]) */

     } else                      {  //\\    ;

       return t[0] = P_mktuple(P_more_f_groups, alt, 0/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<f-groups> =
   case P_f_groups:
#ifdef IN_PARSER


/*
      From https://en.wikipedia.org/wiki/Wavefront_.obj_file


      Relative and absolute indices

      OBJ files, due to their list structure, are able to reference vertices,
      normals, etc. either by their absolute position (1 represents the first
      defined vertex, N representing the Nth defined vertex), or by their relative
      position (-1 represents the latest defined vertex). However, not all software
      supports the latter approach, and conversely some software inherently writes
      only the latter form (due to the convenience of appending elements without
      needing to recalculate vertex offsets, etc.), leading to occasional incompatibilities.


      Vertex indices

      A valid vertex index matches the corresponding vertex elements of a previously
      defined vertex list. If an index is positive then it refers to the offset
      in that vertex list, starting at 1. If an index is negative then it relatively
      refers to the end of the vertex list, -1 referring to the last element.

      Each face can contain three or more vertices.

      f v1 v2 v3 ....


      Vertex texture coordinate indices

      Optionally, texture coordinate indices can be used to specify texture coordinates
      when defining a face. To add a texture coordinate index to a vertex index when
      defining a face, one must put a slash immediately after the vertex index and then
      put the texture coordinate index. No spaces are permitted before or after the slash.
      A valid texture coordinate index starts from 1 and matches the corresponding element
      in the previously defined list of texture coordinates. Each face can contain three
      or more elements.

      f v1/vt1 v2/vt2 v3/vt3 ...


      Vertex normal indices

      Optionally, normal indices can be used to specify normal vectors for vertices when
      defining a face. To add a normal index to a vertex index when defining a face, one
      must put a second slash after the texture coordinate index and then put the normal
      index. A valid normal index starts from 1 and matches the corresponding element in
      the previously defined list of normals. Each face can contain three or more elements.

      f v1/vt1/vn1 v2/vt2/vn2 v3/vt3/vn3 ...


      Vertex normal indices without texture coordinate indices

      As texture coordinates are optional, one can define geometry without them, but one
      must put two slashes after the vertex index before putting the normal index.

      f v1//vn1 v2//vn2 v3//vn3 ...
      
*/

#endif
     {                              //\\    <v-index> <f-vt-vn-indices> <more-f-groups>;
     t[1] = compile(P(1), depth+1 /* P_v_index */);
     t[2] = compile(P(2), depth+1 /* P_f_vt_vn_indices */);
     t[3] = compile(P(3), depth+1 /* P_more_f_groups */);
     return t[0] = P_mktuple(P_f_groups, alt, 3/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<f> =
   case P_f:
#ifdef IN_PARSER

  // Polygonal face element:  Vertex/Texture/Normal
  // f 6/11/6 7/12/7 8/14/8 5/8/5 ...
  // Add 1 to face_count (face_count++) for each group of triangles in the line.  

  //fwprintf(stdout, L"F ...\n");

#endif
     {                              //\\    «f» <f-groups>;
     t[1] = wlit(P(1));
     t[2] = compile(P(2), depth+1 /* P_f_groups */);
     return t[0] = P_mktuple(P_f, alt, 2/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<g> =
   case P_g:
#ifdef IN_PARSER

  // g [polygon group name]
  // g Default

  //fwprintf(stdout, L"G ...\n");

#endif
     {                              //\\    «g» <non-empty-content>;
     t[1] = wlit(P(1));
     t[2] = compile(P(2), depth+1 /* P_non_empty_content */);
     return t[0] = P_mktuple(P_g, alt, 2/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<s> =
   case P_s:
#ifdef IN_PARSER

  // Smoothing groups (or turn off)
  // s 2
  // usemtl NoName,1001
  // ...
  // s 1
  // usemtl NoName,1000
  // ...
  // s off

  //fwprintf(stdout, L"S ...\n");

#endif
     {                              //\\    «s» «[1-9][0-9]*»;
     t[1] = wlit(P(1));
     t[2] = wlit(P(2));
     return t[0] = P_mktuple(P_s, alt, 2/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<o> =
   case P_o:
#ifdef IN_PARSER

  // o [object name]

  //fwprintf(stdout, L"O ...\n");

#endif
     {                              //\\    «o» <filename>;
     t[1] = wlit(P(1));
     t[2] = compile(P(2), depth+1 /* P_filename */);
     return t[0] = P_mktuple(P_o, alt, 2/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ P<l> =
   case P_l:
#ifdef IN_PARSER

  // Polygonal line element
  // l 5 8 1 2 4 9

  //fwprintf(stdout, L"L ...\n");

#endif
     {                              //\\    «l» <non-empty-content>;
     t[1] = wlit(P(1));
     t[2] = compile(P(2), depth+1 /* P_non_empty_content */);
     return t[0] = P_mktuple(P_l, alt, 2/*phrases*/, t); /* (note t[], not T[]) */

     }
//\\ E
   default:
     return r;
  }
}
