// This file is regenerated on every build.  It builds the concrete syntax tree, embedding code from the grammar file.
// To be honest the whole parse/cst/ast thing is a bit muddled and at a minimum needs to be documented if indeed not rewritten.
// Note that the code in a .g file can only walk the CST.  A user-built AST can be expected to have a totally different structure
// from the grammar, so embedding code in the grammar to walk the AST make no sense.

#define X_AST 1
//\\ B<EOF> = 0;
//\\#
//\\ B<ch> = 1;
//\\#
//\\ B<bnl> = 2;
//\\#
//\\ P<nl> =
   case G_nl:
#if defined(NOT_SURE) || defined(BUILDING_CST)

#endif
                                    //\\    <bnl>;
     T[++phrases] = BIP(CST(P++), B_bnl);
     return T[0] = G_mktuple(G_nl, alt, phrases, T);

//\\ P<int> =
   case G_int:
#if defined(NOT_SURE) || defined(BUILDING_CST)


#endif
                                    //\\    «[0-9][0-9]*»;
     T[++phrases] = reg(CST(P++), "[0-9][0-9]*");
     return T[0] = G_mktuple(G_int, alt, phrases, T);

//\\ P<opt-exponent> =
   case G_opt_exponent:
#if defined(NOT_SURE) || defined(BUILDING_CST)


#endif
     if (alt == 0)               {  //\\    'e' «[\-]?» <int>,
       T[++phrases] = ch(CST(P++), 'e');
       T[++phrases] = reg(CST(P++), "[\\-]?");
       T[++phrases] = build_ast(CST(P++) /* G_int */);
     } else                      {  //\\    ;
     }
     return T[0] = G_mktuple(G_opt_exponent, alt, phrases, T);

//\\ P<float> =
   case G_float:
#if defined(NOT_SURE) || defined(BUILDING_CST)


#endif
                                    //\\    «[\-]?[0-9]*[\.][0-9]*» <opt_exponent>;
     T[++phrases] = reg(CST(P++), "[\\-]?[0-9]*[\\.][0-9]*");
     T[++phrases] = build_ast(CST(P++) /* G_opt_exponent */);
     return T[0] = G_mktuple(G_float, alt, phrases, T);

//\\ P<SS> =
   case G_SS:
#if defined(NOT_SURE) || defined(BUILDING_CST)


#endif
                                    //\\    <item> <nl> <more_items> <EOF>;
     T[++phrases] = build_ast(CST(P++) /* G_item */);
     T[++phrases] = build_ast(CST(P++) /* G_nl */);
     T[++phrases] = build_ast(CST(P++) /* G_more_items */);
     T[++phrases] = BIP(CST(P++), B_EOF);
     return T[0] = G_mktuple(G_SS, alt, phrases, T);

//\\ P<item> =
   case G_item:
#if defined(NOT_SURE) || defined(BUILDING_CST)

#endif
     if (alt == 0)               {  //\\    <comment>,
       T[++phrases] = build_ast(CST(P++) /* G_comment */);
     } else if (alt == 1)        {  //\\    <usemtl>,
       T[++phrases] = build_ast(CST(P++) /* G_usemtl */);
     } else if (alt == 2)        {  //\\    <mtllib>,
       T[++phrases] = build_ast(CST(P++) /* G_mtllib */);
     } else if (alt == 3)        {  //\\    <v>,
       T[++phrases] = build_ast(CST(P++) /* G_v */);
     } else if (alt == 4)        {  //\\    <vt>,
       T[++phrases] = build_ast(CST(P++) /* G_vt */);
     } else if (alt == 5)        {  //\\    <vn>,
       T[++phrases] = build_ast(CST(P++) /* G_vn */);
     } else if (alt == 6)        {  //\\    <f>,
       T[++phrases] = build_ast(CST(P++) /* G_f */);
     } else if (alt == 7)        {  //\\    <g>,
       T[++phrases] = build_ast(CST(P++) /* G_g */);
     } else if (alt == 8)        {  //\\    <s>,
       T[++phrases] = build_ast(CST(P++) /* G_s */);
     } else if (alt == 9)        {  //\\    <vp>,
       T[++phrases] = build_ast(CST(P++) /* G_vp */);
     } else if (alt == 10)        {  //\\    <o>,
       T[++phrases] = build_ast(CST(P++) /* G_o */);
     } else if (alt == 11)        {  //\\    <l>,
       T[++phrases] = build_ast(CST(P++) /* G_l */);
     } else                      {  //\\    <EOF>;
       T[++phrases] = BIP(CST(P++), B_EOF);
     }
     return T[0] = G_mktuple(G_item, alt, phrases, T);

//\\ P<more_items> =
   case G_more_items:
#if defined(NOT_SURE) || defined(BUILDING_CST)

#endif
     if (alt == 0)               {  //\\    <item> <nl> <more_items>,
       T[++phrases] = build_ast(CST(P++) /* G_item */);
       T[++phrases] = build_ast(CST(P++) /* G_nl */);
       T[++phrases] = build_ast(CST(P++) /* G_more_items */);
     } else                      {  //\\    ;
     }
     return T[0] = G_mktuple(G_more_items, alt, phrases, T);

//\\ P<non-empty-content> =
   case G_non_empty_content:
#if defined(NOT_SURE) || defined(BUILDING_CST)


#endif
     if (alt == 0)               {  //\\    <!nl> <ch> <non_empty_content>,
       T[++phrases] = -1 +(0 * P++);
       T[++phrases] = BIP(CST(P++), B_ch);
       T[++phrases] = build_ast(CST(P++) /* G_non_empty_content */);
     } else                      {  //\\    ;
     }
     return T[0] = G_mktuple(G_non_empty_content, alt, phrases, T);

//\\ P<filename> =
   case G_filename:
#if defined(NOT_SURE) || defined(BUILDING_CST)


#endif
                                    //\\    <non_empty_content>;
     T[++phrases] = build_ast(CST(P++) /* G_non_empty_content */);
     return T[0] = G_mktuple(G_filename, alt, phrases, T);

//\\ P<comment> =
   case G_comment:
#if defined(NOT_SURE) || defined(BUILDING_CST)

  // 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[++phrases] = reg(CST(P++), "#");
     T[++phrases] = build_ast(CST(P++) /* G_non_empty_content */);
     return T[0] = G_mktuple(G_comment, alt, phrases, T);

//\\ P<usemtl_options> =
   case G_usemtl_options:
#if defined(NOT_SURE) || defined(BUILDING_CST)


#endif
     if (alt == 0)               {  //\\    ',' «[1-9][0-9]*»,
       T[++phrases] = ch(CST(P++), ',');
       T[++phrases] = reg(CST(P++), "[1-9][0-9]*");
     } else                      {  //\\    ;
     }
     return T[0] = G_mktuple(G_usemtl_options, alt, phrases, T);

//\\ P<usemtl> =
   case G_usemtl:
#if defined(NOT_SURE) || defined(BUILDING_CST)

  // 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[++phrases] = reg(CST(P++), "usemtl");
     T[++phrases] = build_ast(CST(P++) /* G_filename */);
     T[++phrases] = build_ast(CST(P++) /* G_usemtl_options */);
     return T[0] = G_mktuple(G_usemtl, alt, phrases, T);

//\\ P<mtllib> =
   case G_mtllib:
#if defined(NOT_SURE) || defined(BUILDING_CST)

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

#endif
                                    //\\    «mtllib» <filename>;
     T[++phrases] = reg(CST(P++), "mtllib");
     T[++phrases] = build_ast(CST(P++) /* G_filename */);
     return T[0] = G_mktuple(G_mtllib, alt, phrases, T);

//\\ P<v> =
   case G_v:
#if defined(NOT_SURE) || defined(BUILDING_CST)

  // 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> <opt_float>;
     T[++phrases] = reg(CST(P++), "v");
     T[++phrases] = build_ast(CST(P++) /* G_float */);
     T[++phrases] = build_ast(CST(P++) /* G_float */);
     T[++phrases] = build_ast(CST(P++) /* G_float */);
     T[++phrases] = build_ast(CST(P++) /* G_opt_float */);
     return T[0] = G_mktuple(G_v, alt, phrases, T);

//\\ P<opt-float> =
   case G_opt_float:
#if defined(NOT_SURE) || defined(BUILDING_CST)


#endif
     if (alt == 0)               {  //\\    <float>,
       T[++phrases] = build_ast(CST(P++) /* G_float */);
     } else                      {  //\\    ;
     }
     return T[0] = G_mktuple(G_opt_float, alt, phrases, T);

//\\ P<vt> =
   case G_vt:
#if defined(NOT_SURE) || defined(BUILDING_CST)

  // 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> <opt_float>;
     T[++phrases] = reg(CST(P++), "vt");
     T[++phrases] = build_ast(CST(P++) /* G_float */);
     T[++phrases] = build_ast(CST(P++) /* G_float */);
     T[++phrases] = build_ast(CST(P++) /* G_opt_float */);
     return T[0] = G_mktuple(G_vt, alt, phrases, T);

//\\ P<vn> =
   case G_vn:
#if defined(NOT_SURE) || defined(BUILDING_CST)

  // 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[++phrases] = reg(CST(P++), "vn");
     T[++phrases] = build_ast(CST(P++) /* G_float */);
     T[++phrases] = build_ast(CST(P++) /* G_float */);
     T[++phrases] = build_ast(CST(P++) /* G_float */);
     return T[0] = G_mktuple(G_vn, alt, phrases, T);

//\\ P<vp> =
   case G_vp:
#if defined(NOT_SURE) || defined(BUILDING_CST)

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

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

#endif
                                    //\\    «vn» <non_empty_content>;
     T[++phrases] = reg(CST(P++), "vn");
     T[++phrases] = build_ast(CST(P++) /* G_non_empty_content */);
     return T[0] = G_mktuple(G_vp, alt, phrases, T);

//\\ P<vn-index> =
   case G_vn_index:
#if defined(NOT_SURE) || defined(BUILDING_CST)


#endif
                                    //\\    <int>;
     T[++phrases] = build_ast(CST(P++) /* G_int */);
     return T[0] = G_mktuple(G_vn_index, alt, phrases, T);

//\\ P<opt-f-vn> =
   case G_opt_f_vn:
#if defined(NOT_SURE) || defined(BUILDING_CST)


#endif
     if (alt == 0)               {  //\\    "/" <vn_index>,
       T[++phrases] = kw(CST(P++), "/");
       T[++phrases] = build_ast(CST(P++) /* G_vn_index */);
     } else                      {  //\\    ;
     }
     return T[0] = G_mktuple(G_opt_f_vn, alt, phrases, T);

//\\ P<opt-vt-index> =
   case G_opt_vt_index:
#if defined(NOT_SURE) || defined(BUILDING_CST)


#endif
     if (alt == 0)               {  //\\    <int>,
       T[++phrases] = build_ast(CST(P++) /* G_int */);
     } else                      {  //\\    ;
     }
     return T[0] = G_mktuple(G_opt_vt_index, alt, phrases, T);

//\\ P<f-vt-vn-indices> =
   case G_f_vt_vn_indices:
#if defined(NOT_SURE) || defined(BUILDING_CST)


#endif
     if (alt == 0)               {  //\\    "/" <opt_vt_index> <opt_f_vn>,
       T[++phrases] = kw(CST(P++), "/");
       T[++phrases] = build_ast(CST(P++) /* G_opt_vt_index */);
       T[++phrases] = build_ast(CST(P++) /* G_opt_f_vn */);
     } else                      {  //\\    ;
     }
     return T[0] = G_mktuple(G_f_vt_vn_indices, alt, phrases, T);

//\\ P<v-index> =
   case G_v_index:
#if defined(NOT_SURE) || defined(BUILDING_CST)


#endif
                                    //\\    <int>;
     T[++phrases] = build_ast(CST(P++) /* G_int */);
     return T[0] = G_mktuple(G_v_index, alt, phrases, T);

//\\ P<more-f-groups> =
   case G_more_f_groups:
#if defined(NOT_SURE) || defined(BUILDING_CST)


#endif
     if (alt == 0)               {  //\\    <v_index> <f_vt_vn_indices> <more_f_groups>,
       T[++phrases] = build_ast(CST(P++) /* G_v_index */);
       T[++phrases] = build_ast(CST(P++) /* G_f_vt_vn_indices */);
       T[++phrases] = build_ast(CST(P++) /* G_more_f_groups */);
     } else                      {  //\\    ;
     }
     return T[0] = G_mktuple(G_more_f_groups, alt, phrases, T);

//\\ P<f-groups> =
   case G_f_groups:
#if defined(NOT_SURE) || defined(BUILDING_CST)


/*
      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[++phrases] = build_ast(CST(P++) /* G_v_index */);
     T[++phrases] = build_ast(CST(P++) /* G_f_vt_vn_indices */);
     T[++phrases] = build_ast(CST(P++) /* G_more_f_groups */);
     return T[0] = G_mktuple(G_f_groups, alt, phrases, T);

//\\ P<f> =
   case G_f:
#if defined(NOT_SURE) || defined(BUILDING_CST)

  // 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[++phrases] = reg(CST(P++), "f");
     T[++phrases] = build_ast(CST(P++) /* G_f_groups */);
     return T[0] = G_mktuple(G_f, alt, phrases, T);

//\\ P<g> =
   case G_g:
#if defined(NOT_SURE) || defined(BUILDING_CST)

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

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

#endif
                                    //\\    «g» <non_empty_content>;
     T[++phrases] = reg(CST(P++), "g");
     T[++phrases] = build_ast(CST(P++) /* G_non_empty_content */);
     return T[0] = G_mktuple(G_g, alt, phrases, T);

//\\ P<s> =
   case G_s:
#if defined(NOT_SURE) || defined(BUILDING_CST)

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

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

#endif
     if (alt == 0)               {  //\\    «s» «[0-9][0-9]*»,
       T[++phrases] = reg(CST(P++), "s");
       T[++phrases] = reg(CST(P++), "[0-9][0-9]*");
     } else                      {  //\\    «s» «off»;
       T[++phrases] = reg(CST(P++), "s");
       T[++phrases] = reg(CST(P++), "off");
     }
     return T[0] = G_mktuple(G_s, alt, phrases, T);

//\\ P<o> =
   case G_o:
#if defined(NOT_SURE) || defined(BUILDING_CST)

  // o [object name]

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

#endif
                                    //\\    «o» <filename>;
     T[++phrases] = reg(CST(P++), "o");
     T[++phrases] = build_ast(CST(P++) /* G_filename */);
     return T[0] = G_mktuple(G_o, alt, phrases, T);

//\\ P<l> =
   case G_l:
#if defined(NOT_SURE) || defined(BUILDING_CST)

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

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

#endif
                                    //\\    «l» <non_empty_content>;
     T[++phrases] = reg(CST(P++), "l");
     T[++phrases] = build_ast(CST(P++) /* G_non_empty_content */);
     return T[0] = G_mktuple(G_l, alt, phrases, T);

//\\ E
