private ContentModel ParseContentModel(char ch)
		{
			ContentModel cm = new ContentModel();
			if (ch == '(')
			{
				this.m_current.ReadChar();
				ParseModel(')', cm);
				ch = this.m_current.ReadChar();
				if (ch == '?' || ch == '+' || ch == '*')
				{
					cm.AddOccurrence(ch);
					this.m_current.ReadChar();
				}
			}
			else if (ch == '%')
			{
				Entity e = ParseParameterEntity(SgmlDtd.dcterm);
				PushEntity(this.m_current.ResolvedUri, e);
				cm = ParseContentModel(this.m_current.Lastchar);
				PopEntity(); // bugbug should be at EOF.
			}
			else
			{
				string dc = ScanName(SgmlDtd.dcterm);
				cm.SetDeclaredContent(dc);
			}
			return cm;
		}
		void ParseModel(char cmt, ContentModel cm)
		{
			// Called when part of the model is made up of the contents of a parameter entity
			int depth = cm.CurrentDepth;
			char ch = this.m_current.Lastchar;
			ch = this.m_current.SkipWhitespace();
			while (ch != cmt || cm.CurrentDepth > depth) // the entity must terminate while inside the content model.
			{
				if (ch == Entity.EOF)
				{
					this.m_current.Error("Content Model was not closed");
				}
				if (ch == '%')
				{
					Entity e = ParseParameterEntity(SgmlDtd.cmterm);
					PushEntity(this.m_current.ResolvedUri, e);
					ParseModel(Entity.EOF, cm);
					PopEntity();
					ch = this.m_current.SkipWhitespace();
				}
				else if (ch == '(')
				{
					cm.PushGroup();
					this.m_current.ReadChar();// consume '('
					ch = this.m_current.SkipWhitespace();
				}
				else if (ch == ')')
				{
					ch = this.m_current.ReadChar();// consume ')'
					if (ch == '*' || ch == '+' || ch == '?')
					{
						cm.AddOccurrence(ch);
						ch = this.m_current.ReadChar();
					}
					if (cm.PopGroup() < depth)
					{
						this.m_current.Error("Parameter entity cannot close a paren outside it's own scope");
					}
					ch = this.m_current.SkipWhitespace();
				}
				else if (ch == ',' || ch == '|' || ch == '&')
				{
					cm.AddConnector(ch);
					this.m_current.ReadChar(); // skip connector
					ch = this.m_current.SkipWhitespace();
				}
				else
				{
					string token;
					if (ch == '#')
					{
						ch = this.m_current.ReadChar();
						token = "#" + this.m_current.ScanToken(this.m_sb, SgmlDtd.cmterm, true); // since '#' is not a valid name character.
					}
					else
					{
						token = this.m_current.ScanToken(this.m_sb, SgmlDtd.cmterm, true);
					}

					token = token.ToUpperInvariant();
					ch = this.m_current.Lastchar;
					if (ch == '?' || ch == '+' || ch == '*')
					{
						cm.PushGroup();
						cm.AddSymbol(token);
						cm.AddOccurrence(ch);
						cm.PopGroup();
						this.m_current.ReadChar(); // skip connector
						ch = this.m_current.SkipWhitespace();
					}
					else
					{
						cm.AddSymbol(token);
						ch = this.m_current.SkipWhitespace();
					}
				}
			}
		}
		/// <summary>
		/// Initialises a new element declaration instance.
		/// </summary>
		/// <param name="name">The name of the element.</param>
		/// <param name="sto">Whether the start tag is optional.</param>
		/// <param name="eto">Whether the end tag is optional.</param>
		/// <param name="cm">The <see cref="ContentModel"/> of the element.</param>
		/// <param name="inclusions"></param>
		/// <param name="exclusions"></param>
		public ElementDecl(string name, bool sto, bool eto, ContentModel cm, string[] inclusions, string[] exclusions)
		{
			m_name = name;
			m_startTagOptional = sto;
			m_endTagOptional = eto;
			m_contentModel = cm;
			m_inclusions = inclusions;
			m_exclusions = exclusions;
		}