%{
/****************************************************************************
 *
 * VRML 2.0 to RW3.0 Converter
 * Copyright (C) 1997 Criterion Technologies
 *
 * Author   : Damian Scallan
 *
 * Based on original parser code by Gavin Bell & 
 * Daniel Woods (first port) of Silicon Graphics, Inc.
 *
 ****************************************************************************/

/****************************************************************************
 Includes
 */

#include <stdio.h>
#include <malloc.h>
#include <assert.h>
#include <string.h>

#include "abstractnode.h"
#include "parser.h"
#include "symtable.h"
#include "route.h"

void yyerror(const char *);
int  yylex(void);
extern void yyResetLineNumber();

/****************************************************************************
 Local (Static) Prototypes
 */

/****************************************************************************
 Local Defines
 */

/****************************************************************************
 Globals (across program)
 */

LLStack	currentField; /* of FieldRec */
int parsing_proto = FALSE;
int parsing_script = FALSE;

/*
 *  This is used when the parser knows what kind of token it expects
 *  to get next-- used when parsing field values (whose types are declared
 *  and read by the parser) and at certain other places:
 */
extern int expectToken;
/* Current line number (set by lexer) */
extern int currentLineNumber;
extern FILE *yyin, *yyout;
extern int yy_flex_debug;

/****************************************************************************
 Local (static) Globals
 */

/****************************************************************************
Bison Voodoo
*/

%}

%union {
	char *string;
	AbstractNode *aNode;
};

%type <string> IDENTIFIER
%type <aNode> node

/*
 * And types that will be needed by a true VRML implementation:
 * %type <nodeList> vrmlscene declarations
 */

%token IDENTIFIER DEF USE PROTO EXTERNPROTO TO IS ROUTE SFN_NULL
%token EVENTIN EVENTOUT UNEXPOSEDFIELD EXPOSEDFIELD
%token SFBOOL SFCOLOR SFFLOAT SFIMAGE SFINT32 SFNODE SFROTATION
%token SFSTRING SFTIME SFVEC2F SFVEC3F
%token MFCOLOR MFFLOAT MFINT32 MFROTATION MFSTRING MFVEC2F MFVEC3F
%token MFNODE

%%

vrmlscene:	declarations		{}
	;

declarations:
		/* Empty is OK */
	|	declarations declaration
    ;

declaration:
		nodeDeclaration
	|	protoDeclaration
	|	routeDeclaration
    ;

nodeDeclaration:				
		node					{} /* override default action */
	|	DEF IDENTIFIER node		{ SymTab_AddEntry($2, $3); free($2); }
    |	USE IDENTIFIER			{ enterUse($2); free($2); }
    ;

protoDeclaration:
		proto
	|	externproto
    ;

proto:
		 PROTO IDENTIFIER			{ beginProto($2); }						
	     	'[' interfaceDeclarations ']'
            '{' declarations '}'	{ endProto();  free($2);}
	;

externproto:
		 EXTERNPROTO IDENTIFIER			{ beginProto($2); }						
	     	'[' externInterfaceDeclarations ']' 
            							{ expect(MFSTRING); 
                                          enterExternProtoUrlField($2); }
            fieldValue					{ exitExternProtoUrlField(); endProto();  free($2); }
	;
interfaceDeclarations:
		/* Empty is OK */
	|	interfaceDeclarations interfaceDeclaration
    ;

interfaceDeclaration:
		EVENTIN IDENTIFIER IDENTIFIER		{ addEventIn($2, $3);
        									  free($2); free($3); }
    |   EVENTOUT IDENTIFIER IDENTIFIER		{ addEventOut($2, $3);
        									  free($2); free($3); }
    |   UNEXPOSEDFIELD IDENTIFIER IDENTIFIER			{ int type = addField($2, $3);
    										  expect(type);
                                              enterProtoField($3); }
    	    fieldValue        				{ exitProtoField(); free($2); free($3); }
	|	EXPOSEDFIELD IDENTIFIER	IDENTIFIER	{ int type = addExposedField($2, $3);
    										  expect(type); 
                                              enterProtoField($3); }
    		fieldValue                      { exitProtoField(); free($2); free($3); }
    ;

externInterfaceDeclarations:
		/* Empty is OK */
     |  externInterfaceDeclarations externInterfaceDeclaration
     ;

externInterfaceDeclaration:
		EVENTIN IDENTIFIER IDENTIFIER		{ addEventIn($2, $3);
        									  free($2); free($3); }
    |   EVENTOUT IDENTIFIER IDENTIFIER		{ addEventOut($2, $3);
        									  free($2); free($3); }
    |	UNEXPOSEDFIELD IDENTIFIER IDENTIFIER			{ addField($2, $3);
        									  free($2); free($3); }
    |	EXPOSEDFIELD IDENTIFIER IDENTIFIER	{ addExposedField($2, $3);
        									  free($2); free($3); }
    ;

routeDeclaration:
		ROUTE IDENTIFIER '.' IDENTIFIER TO IDENTIFIER '.' IDENTIFIER
        { Route_Set($2, $4, $6, $8); 
          free($2); free($4);
          free($6); free($8); }
    ; 

node:
		IDENTIFIER  				{ enterNode($1); }
        	'{' nodeGuts '}'		{ $$ = exitNode(); free($1);}
    ;

nodeGuts:
		/* Empty is OK */
    | 	nodeGuts nodeGut
    ;

nodeGut:
		IDENTIFIER 					{ enterField($1); }
        		fieldValue			{ exitField(); free($1); }
    |	routeDeclaration
    |	protoDeclaration

    	/* The following are only valid for Script nodes: */
	|   EVENTIN IDENTIFIER IDENTIFIER		{ enterScript(); free($2); free($3); exitScript()}
    |   EVENTOUT IDENTIFIER IDENTIFIER		{ enterScript(); free($2); free($3); exitScript()}
    |   UNEXPOSEDFIELD IDENTIFIER IDENTIFIER			{ int type;
                                              enterScript();
    										  type = fieldType($2);
    										  expect(type); }
    	    fieldValue                      { free($2); free($3); exitScript()}
    |	EVENTIN IDENTIFIER IDENTIFIER IS IDENTIFIER
    			{ enterScript(); free($2); free($3); free($5); exitScript()}
    |	EVENTOUT IDENTIFIER IDENTIFIER IS IDENTIFIER
    			{ enterScript(); free($2); free($3); free($5); exitScript()}
   ;

fieldValue:
		SFBOOL
    |   SFCOLOR
    |	MFCOLOR
    |   SFFLOAT
    |	MFFLOAT		
    |	SFIMAGE
    |	SFINT32
    |	MFINT32		
    |	SFROTATION
    |	MFROTATION
    |	SFSTRING
    |	MFSTRING
    |	SFTIME
    |	SFVEC2F
    |	MFVEC2F
    |	SFVEC3F
    |	MFVEC3F
    
    |	SFNODE nodeDeclaration
    |	SFNODE SFN_NULL
    |	MFNODE mfnodeValue
    |	IS IDENTIFIER				{ instanceIs($2); free($2); }
    ;

mfnodeValue:
		'[' nodes ']'
     |  nodeDeclaration
     ;

nodes:
		/* Empty is OK */
     |  nodes nodeDeclaration
     ;

%%

void
yyerror(const char *msg)
{
    RWFUNCTION("yyerror");

    RWERROR((E_RP_VRML_PARSER, currentLineNumber + 1, msg));
    expect(0);

    RWRETURNVOID();
}
