// parser.H: VRML parser class: 

#ifndef _VRML2_UTF8_PARSER_H_
#define _VRML2_UTF8_PARSER_H_

#include "xrmlP.H"
#include "Stack.H"
#include "../importer.H"
#include "scanner.H"

namespace vrml2_utf8 {
  using namespace xrml;

// VRML parser context, a VRML file has a root context + a context
// for each Proto. A stack of such contexts is used to deal with nested
// Proto's (member of vrml2_utf8_parser class). */
class context {
public:
  PoolDecl(context, "vrml2_utf8::context")

  SFNode *master;	        // contains master interface of the PROTO 
				// for which the context is created (null
				// for root context)

  MFNode *sceneGraph;	        // root nodes within the context 
  namedNodeTable namedNodes;    // DEF'ed nodes within the context
  protoTable protos;            // PROTO and EXTERNPROTO nodes within the context

  stack<SFNode *> nodeStack;    // ancestors of current node being parsed
  SFNode *curnode;		// current node being parsed

  context();

  // adds/looks up Proto/named node (in this context only)
  int add_proto(class Proto* proto);
  int add_namedNode(char *nameId, class SFNode* node);
  Proto *lookup_proto(char *typeId);
  SFNode *lookup_namedNode(char *nameId);
};

// vrml2_utf8::parser is a sub-class of a vrml2_utf8::scanner 
// in order to have direct access to and private copies of 
// the vrml2_utf8::scanner members yylineno, scanfp, yylex(), ... */
class parser: public xrml::importer, public scanner {
public:
  PoolDecl(parser, "vrml2_utf8::parser")

protected:
  stack<class context *> contextStack;	// context stack
  class context *ctx, *rootctx;	// current and root context

  int errlev;	/* error level for error recovery during parsing */

  /* interface declarations currently being parsed (PROTO/EXTERNPROTO/Script) */
  array<class interfaceMember *> interface;
  /* for temporarily storing field type, Id and value while parsing */
  fieldValue curValue;
  char *curId;

  // see parser2.C
  void Start(void);
  class Proto *LookupProto(char *typeId);
  void AppendNode(class SFNode* node);	
  void DefineNamedNode(char *nodeNameId, class SFNode *node);
  void AppendNamedNode(char *nodeNameId, class SFNode *node);
  class SFNode* UseNamedNode(char *nodeNameId);
  void BeginProto(char *typeId);
  void EndProto(void);
  void NewExternProto(char *typeId, MFString* URLList);
  void BeginNodeInstance(char *typeId);
  class SFNode* EndNodeInstance(void);
  void 	BeginScript(void);
  class SFNode* EndScript(void);
  void AppendMember(class interfaceMember *member);
  void MakeLink(char *dstId, char *srcId);
  class interfaceMember *GetField(char *Id);
  void NonNodeFieldIdValuePair(char *fieldId);
  void NodeFieldIdValuePair(char *fieldId, class fieldValue value);
  void AddRoute(char *srcNodeNameId, char *srcEventOutId, char *destNodeNameId, char * dstEventInId);
  void SkipFieldValue(void);
  class fieldValueBase ParseValue(fieldType type, int cachedtoken =0);

  // needed by SkipFieldValue():
  int IsFieldValueAtomOrSquareBracket(int token);

  // needed by ParseValue() - need to be member functions because 
  // these routine need access to yylval.
  double ParseFloat(int cachedtoken =0);
  long ParseInt(int cachedtoken =0);
  SFBool ParseSFBool(int cachedtoken =0);
  SFColor ParseSFColor(int cachedtoken =0); 
  SFFloat ParseSFFloat(int cachedtoken =0);
  SFInt32 ParseSFInt32(int cachedtoken =0);
  SFImage *ParseSFImage(int cachedtoken =0);
  SFNode *ParseSFNode(int cachedtoken =0);
  SFRotation ParseSFRotation(int cachedtoken =0);
  SFString ParseSFString(int cachedtoken =0);
  SFTime ParseSFTime(int cachedtoken =0);
  SFVec2f ParseSFVec2f(int cachedtoken =0);
  SFVec3f ParseSFVec3f(int cachedtoken =0);
  MFColor *ParseMFColor(int cachedtoken =0);
  MFFloat *ParseMFFloat(int cachedtoken =0);
  MFInt32 *ParseMFInt32(int cachedtoken =0);
  MFNode *ParseMFNode(int cachedtoken =0);
  MFRotation *ParseMFRotation(int cachedtoken =0);
  MFString *ParseMFString(int cachedtoken =0);
  MFTime *ParseMFTime(int cachedtoken =0);
  MFVec2f *ParseMFVec2f(int cachedtoken =0);
  MFVec3f *ParseMFVec3f(int cachedtoken =0);

  void yyerror(char *s);// parser error reporting routine
  int yyparse(void);	// bison generated parser

  YYSTYPE yylval;	// bison generated "global" variables
  int yychar;
  int yynerrs;

  inline int yylex(YYSTYPE *lvalp)
  {
    int token = scanner::yylex(lvalp);
    xrml::current_linenr = yylineno;	// keep track of line number
    return token;
  }

  // by default, yylex fills in yylval "global" variable.
  inline int yylex(void)
  {
    return yylex(&yylval);
  }

public:
  class world *world;	// the world being parsed

  // see importer.H
  bool parse(class world *world, char **strpool);
  class xrml::importer* instantiate(class file* file_handle =0);
};

} // namespace vrml2_utf8

#endif /*_VRML2_UTF8_PARSER_H_*/
