InterfaceDeclaration ParseExternInterfaceDeclaration()
		{
			// inputOnly fieldType inputOnlyId | outputOnly fieldType outputOnlyId |
			// initializeOnly fieldType initializeOnlyId | inputOutput fieldType inputOutputFieldId

			InterfaceDeclaration ret=new InterfaceDeclaration();

			string type=GetNextIDToken();

			switch(type)
			{
				case "eventIn":
				case "inputOnly": ret.InterfaceDeclarationType=InterfaceDeclarationType.EventIn; break;
				case "eventOut":
				case "outputOnly": ret.InterfaceDeclarationType=InterfaceDeclarationType.EventOut; break;
				case "field":
				case "initializeOnly": ret.InterfaceDeclarationType=InterfaceDeclarationType.Field; break;
				case "exposedField":
				case "inputOutput": ret.InterfaceDeclarationType=InterfaceDeclarationType.ExposedField; break;
				default:
					ErrorParsingToken("interface declaration keyword", type, "EXTERNPROTO statement interface declarations");
					return null;
			}

			ret.FieldType=GetNextFieldTypeToken();
			ret.FieldId=GetNextIDToken();

			return ret;
		}
		void ParseScriptBodyElement(X3DNode node, string id)
		{
			// nodeBodyElement | interfaceDeclaration |
			// inputOnly fieldType inputOnlyId IS inputOnlyId |
			// outputOnly fieldType outputOnlyId IS outputOnlyId |
			// initializeOnly fieldType initializeOnlyId IS initializeOnlyId |
			// inputOutput fieldType inputOutputId IS inputOutputId

			IScriptNode script=node as IScriptNode;

			switch(id)
			{
				case "eventIn":
				case "inputOnly":
				case "eventOut":
				case "outputOnly":
					{
						string tokenEvent=GetNextIDToken();
						FieldType fieldType=GetNextFieldTypeToken();
						string eventId=GetNextIDToken();

						InterfaceDeclaration fieldDeclaration=new InterfaceDeclaration();
						fieldDeclaration.FieldId=eventId;
						fieldDeclaration.FieldType=fieldType;
						if(id=="eventIn"||id=="inputOnly")
							fieldDeclaration.InterfaceDeclarationType=InterfaceDeclarationType.EventIn;
						else fieldDeclaration.InterfaceDeclarationType=InterfaceDeclarationType.EventOut;

						if(inPROTO)
						{
							// Check if id is followed by IS Keyword
							object token=PeekNextToken();
							VRMLTokenIdKeywordOrFieldType idToken=token as VRMLTokenIdKeywordOrFieldType;
							if(idToken!=null&&idToken.id=="IS")
							{
								string tokenIS=GetNextIDToken();
								string isID=GetNextIDToken();

								if(node.Substitutions.ContainsKey(eventId))
								{
									if(node.Substitutions[eventId]==isID) ErrorParsing(VRMLReaderError.RedundantISStatement);
									else ErrorParsing(VRMLReaderError.MultipleISStatementForField);
								}
								else node.Substitutions.Add(eventId, isID);
							}
						}

						script.ScriptingInterfaceDeclarations.Add(fieldDeclaration);
					}
					break;
				case "field":
				case "initializeOnly":
				case "exposedField":
				case "inputOutput":
					{
						string tokenEvent=GetNextIDToken();
						FieldType fieldType=GetNextFieldTypeToken();
						string fieldId=GetNextIDToken();

						InterfaceDeclaration fieldDeclaration=new InterfaceDeclaration();
						fieldDeclaration.FieldId=fieldId;
						fieldDeclaration.FieldType=fieldType;
						if(id=="field"||id=="initializeOnly")
							fieldDeclaration.InterfaceDeclarationType=InterfaceDeclarationType.Field;
						else fieldDeclaration.InterfaceDeclarationType=InterfaceDeclarationType.ExposedField;

						// Check if id is followed by IS Keyword
						object token=PeekNextToken();
						VRMLTokenIdKeywordOrFieldType idToken=token as VRMLTokenIdKeywordOrFieldType;
						if(inPROTO&&idToken!=null&&idToken.id=="IS")
						{
							string tokenIS=GetNextIDToken();
							string isID=GetNextIDToken();

							if(node.Substitutions.ContainsKey(fieldId))
							{
								if(node.Substitutions[fieldId]==isID) ErrorParsing(VRMLReaderError.RedundantISStatement);
								else ErrorParsing(VRMLReaderError.MultipleISStatementForField);
							}
							else node.Substitutions.Add(fieldId, isID);
						}
						else fieldDeclaration.DefaultValue=ParseFieldByType(fieldType);

						script.ScriptingInterfaceDeclarations.Add(fieldDeclaration);
					}
					break;
				default: ParseNodeBodyElement(node, id); break;
			}
		}
		InterfaceDeclaration ParseInterfaceDeclaration()
		{
			// inputOnly fieldType inputOnlyId |
			// outputOnly fieldType outputOnlyId |
			// initializeOnly fieldType initializeOnlyId fieldValue |
			// inputOutput fieldType fieldId fieldValue

			string type=GetNextIDToken();

			InterfaceDeclaration ret=new InterfaceDeclaration();

			switch(type)
			{
				case "eventIn":
				case "inputOnly": ret.InterfaceDeclarationType=InterfaceDeclarationType.EventIn; break;
				case "eventOut":
				case "outputOnly": ret.InterfaceDeclarationType=InterfaceDeclarationType.EventOut; break;
				case "field":
				case "initializeOnly": ret.InterfaceDeclarationType=InterfaceDeclarationType.Field; break;
				case "exposedField":
				case "inputOutput": ret.InterfaceDeclarationType=InterfaceDeclarationType.ExposedField; break;
				default:
					ErrorParsingToken("interface declaration keyword", type, "PROTO statement interface declarations");
					return null;
			}

			ret.FieldType=GetNextFieldTypeToken();
			ret.FieldId=GetNextIDToken();

			if(ret.InterfaceDeclarationType==InterfaceDeclarationType.Field||ret.InterfaceDeclarationType==InterfaceDeclarationType.ExposedField)
				ret.DefaultValue=ParseFieldByType(ret.FieldType);

			return ret;
		}