/*description: { Parses a \samp{DTD} (Document Type Description) file. The parse tree conforms to the following logic structure: \begin{itemize} \item \textit{comment} (optional) holds the last comment block found into the DTD before the first DTD element, if any. This comment is interpreted as an explanation on what the DTD is for. \item \textit{listOfElements}[] contains the list of all \samp{" "?>"]? [ [COMMENT:sComment]* [ DTDelement(sComment) | DTDattribute(sComment) | DTDentity(sComment) ] => clearVariable(sComment); ]* #empty; DTDelement(sComment : value) ::= " { insert this.listOfElements[sElementName] = sElementName; insert this.listOfElements[sElementName].comment = sComment; } [ composite_element_content(this.listOfElements[sElementName]) | element_category:this.listOfElements[sElementName].category ] '>'; element_category ::= "EMPTY" | "ANY"; composite_element_content(myContent : node) ::= '(' #continue element_content(myContent.composite[getArraySize(myContent.composite)]) [[',' | '|']:myContent.composite[sub(getArraySize(myContent.composite), 1)].operator #continue element_content(myContent.composite[getArraySize(myContent.composite)])]* ')' ['?' | '*' | '+']?:myContent.composite.multiplicity; element_content(myContent : node) ::= constant_element_content:myContent.constant | IDENTIFIER:myContent.element ['?' | '*' | '+']?:myContent.element.multiplicity | composite_element_content(myContent); constant_element_content ::= "#PCDATA"; DTDattribute(myComment : value) ::= " insert this.listOfElements[sElementName]; => localref elt = this.listOfElements[sElementName]; [ IDENTIFIER:sAttributeName #continue => insert elt.listOfAttributes[sAttributeName] = sAttributeName; attribute_type(elt.listOfAttributes[sAttributeName]) attribute_default_value(elt.listOfAttributes[sAttributeName]) ]+ '>'; attribute_type(myAttribute : node) ::= #readIdentifier:{"CDATA", "ID", "IDREF", "IDREFS", "NMTOKEN", "NMTOKENS", "ENTITY", "ENTITIES", "NOTATION"}:myAttribute.type | attribute_enum_type(myAttribute); attribute_enum_type(myAttribute : node) ::= '(' #continue VALUE:sEnum => insert myAttribute.listOfEnums[sEnum] = sEnum; [ '|' #continue VALUE:sEnum => insert myAttribute.listOfEnums[sEnum] = sEnum; ]* ')'; attribute_default_value(myAttribute : node) ::= "#IMPLIED":myAttribute.value | "#REQUIRED":myAttribute.value | ["#DEFAULT" | "#FIXED"]?:myAttribute.value STRING_LITERAL:myAttribute.constant ; DTDentity(sComment : value) ::= " insert this.listOfEntities[sEntityName] = sEntityName; => insert this.listOfEntities[sEntityName].comment = sComment; ["SYSTEM":this.listOfEntities[sEntityName].external]? STRING_LITERAL:sConstant => { local iIndex = $findString(sConstant, "%") + 1$; while $iIndex > 0$ { local iSemiComma = findNextString(sConstant, ";", iIndex); if $iSemiComma < 0$ error("';' expected in the value of ''"); local sEmbeddedEntity = midString(sConstant, iIndex, $iSemiComma - iIndex$); if !findElement(sEmbeddedEntity, this.listOfEntities) error("entity %" + sEntityName + " refers to entity '%" + sEmbeddedEntity + ";' that doesn't exist"); local sEmbeddedConstant = this.listOfEntities[sEmbeddedEntity].constant; set sConstant = leftString(sConstant, $iIndex - 1$) + sEmbeddedConstant + subString(sConstant, $iSemiComma + 1$); set iIndex = $iIndex + lengthString(sEmbeddedConstant) - 1$; set iIndex = $findNextString(sConstant, "%", iIndex) + 1$; } insert this.listOfEntities[sEntityName].constant = sConstant; } '>'; COMMENT : value ::= ""]*:COMMENT "-->"; IDENTIFIER : value ::= #!ignore #readIdentifier:IDENTIFIER [['-' | '.'] #readIdentifier]*:sIdentifier => set IDENTIFIER += sIdentifier; ; STRING_LITERAL:value ::= '"' #!ignore #continue ->(:STRING_LITERAL)'"' | "'" #!ignore #continue ->(:STRING_LITERAL)"'"; VALUE ::= STRING_LITERAL | #readNumeric | IDENTIFIER ;