DTDdocument ::=
#continue
#ignore(blanks)
[COMMENT:this.comment]?
["<?" #continue -> "?>"]?
[
[COMMENT:sComment]*
[
DTDelement(sComment)
|
DTDattribute(sComment)
|
DTDentity(sComment)
] => clearVariable(sComment);
]*
#empty;
DTDelement(sComment : value) ::= "<!ELEMENT"
#continue
IDENTIFIER:sElementName
=> {
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) ::=
"<!ATTLIST" #continue IDENTIFIER:sElementName
=> 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) ::=
"<!ENTITY" #continue '%' IDENTIFIER:sEntityName
=> 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 '<!ENTITY %" + sEntityName + " \"" + sConstant + "\">'");
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 ::= "<!--" #!ignore #continue [~"-->"]*: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
;