/* The geo2bog Yacc/Bison spesification file */
%{
#define YYPARSER /* distinguishes yacc output from other code files */

#include "globals.h"
#include "parse.h"
#include "util.h"

#define YYSTYPE TreeNode_t *

static TreeNode_t * savedTree; /* Stores syntax tree for later return */

%}

%token GEO FILEVERSION GEOMETRY VERTEXLIST NORMALLIST TEXCOORDLIST POLYGON
%token TYPE MATERIAL VERTEX NORMAL TEXCOORD NAME
%token TRIANGLES QUADS QUAD_STRIP TRIANGLE_STRIP TRIANGLE_FAN
%token ASSIGN FLOAT NUM STRING
%token ERROR

%%

goeFile:	geoHead geometry_seq
			{ savedTree = newFile($1,$2); }
		| geometry_seq
			{ savedTree = newFile(NULL,$1); }
		;
geoHead:	GEO '(' FILEVERSION ASSIGN float_num ')'
			{ $$ = newHead($5); }
		;
geometry_seq:	geometry_seq geometry
			{ $$ = linkNode($1,$2); }
		| geometry
			{ $$ = $1; }
		;
geometry:	GEOMETRY '{' list_seq poly_seq '}' 
			{ $$ = newGeometry($3,$4); }
		| GEOMETRY '(' NAME ASSIGN STRING ')' '{' list_seq poly_seq '}' 
			{ $$ = newGeometry($8,$9); }
		;
list_seq:	list_seq list
			{ $$ = linkNode($1,$2); }
		| list
			{ $$ = $1; }
		;
list:		vertexlist ';'
			{ $$ = $1; }
		| normallist ';'
			{ $$ = $1; }
		| texcoordlist ';'
			{ $$ = $1; }
		;
vertexlist:	VERTEXLIST ASSIGN '[' vertex_seq ']'
			{ $$ = newVertexList($4); }
		;
vertex_seq:	vertex_seq ',' vertex
			{ $$ = linkNode($1,$3); }
		| vertex
			{ $$ = $1; }
		;
vertex:		'(' float_num ',' float_num ',' float_num ')'
			{ $$ = newVertex($2,$4,$6); }
		;
float_num:	FLOAT
			{ $$ = newFloat((float)atof(tokenString)); }
		| NUM
			{ $$ = newFloat((float)atof(tokenString)); }
		;
normallist:	NORMALLIST ASSIGN '[' normal_seq ']'
			{ $$ = newNormalList($4); }
		;
normal_seq:	normal_seq ',' normal
			{ $$ = linkNode($1,$3); }
		| normal
			{ $$ = $1; }
		;
normal:		'(' float_num ',' float_num ',' float_num ')'
			{ $$ = newNormal($2,$4,$6); }
		;
texcoordlist:	TEXCOORDLIST ASSIGN '[' texcoord_seq ']'
			{ $$ = newTexCoordList($4); }
		;
texcoord_seq:	texcoord_seq ',' texcoord
			{ $$ = linkNode($1,$3); }
		| texcoord
			{ $$ = $1; }
		;
texcoord:	'(' float_num ',' float_num ')'
			{ $$ = newTexCoord($2,$4); }
		;
poly_seq:	poly_seq poly
			{ $$ = linkNode($1,$2); }
		| poly
			{ $$ = $1; }
		;
poly:		POLYGON '{' polyattrib_seq '}' 
			{ $$ = newPoly($3); }
		;		
polyattrib_seq	: polyattrib_seq polyattrib
			{ $$ = linkNode($1,$2); }
		| polyattrib
			{ $$ = $1; }
		;
polyattrib:	type ';'
			{ $$ = $1; }
		| material ';'
			{ $$ = $1; }
		| vertexindexlst ';'
			{ $$ = $1; }
		| normalindexlst ';'
			{ $$ = $1; }
		| texindexlst ';'
			{ $$ = $1; }
		;
type:		TYPE ASSIGN polytype
			{ $$ = $3; }
		;
polytype:	POLYGON
			{ $$ = newPolyType(PT_Polygon); }
		| TRIANGLES
			{ $$ = newPolyType(PT_Triangles); }
		| QUADS
			{ $$ = newPolyType(PT_Quads); }
		| QUAD_STRIP
			{ $$ = newPolyType(PT_Quad_strip); }
		| TRIANGLE_STRIP
			{ $$ = newPolyType(PT_Triangle_strip); }
		| TRIANGLE_FAN
			{ $$ = newPolyType(PT_Triangle_fan); }
		;
material:	MATERIAL ASSIGN STRING
			{
			  tokenString[strlen(tokenString)-1] = '\0';
			  $$ = newMaterial(copyString(tokenString+1));
			}
		;
vertexindexlst:	VERTEX ASSIGN '[' vertexindexseq ']'
			{ $$ = newVertexIndexList($4); }
		;
vertexindexseq:	vertexindexseq ',' vertexindex
			{ $$ = linkNode($1,$3); }
		| vertexindex
			{ $$ = $1; }
		;
vertexindex:	index
			{ $$ = $1; }
		;
normalindexlst:	NORMAL ASSIGN '[' normalindexseq ']'
			{ $$ = newNormalIndexList($4); }
		;
normalindexseq:	normalindexseq ',' normalindex
			{ $$ = linkNode($1,$3); }
		| normalindex
			{ $$ = $1; }
		;
normalindex:	index
			{ $$ = $1; }
		;
texindexlst:	TEXCOORD ASSIGN '[' texindexseq ']'
			{ $$ = newTexCoordIndexList($4); }
		;
texindexseq:	texindexseq ',' texindex
			{ $$ = linkNode($1,$3); }
		| texindex
			{ $$ = $1; }
		;
texindex:	index
			{ $$ = $1; }
		;
index:		NUM
			{ $$ = newIndex(atoi(tokenString)); }
		;
%%

static TokenType yylex(){
  return getToken();
}

int yyerror(char * message){
  printf("Syntax error at line %d: %s\n",lineno,message);
  return 0;
}

TreeNode_t * parse(){
  yyparse();
  return savedTree;
}