Mercurial > ~dholland > hg > ag > index.cgi
view tests/agcl/parsifal/xmlp8.syn @ 17:12171da8943f
Don't refer to CVS.
author | David A. Holland |
---|---|
date | Tue, 31 May 2022 01:56:37 -0400 |
parents | 13d2b8934445 |
children |
line wrap: on
line source
{/* * XML Syntax * Transcribed from * Extensible Markup Language (XML) 1.0 * W3C Recommendation 10-February-1998 * http://www.w3.org/TR/1998/REC-xml-19980210 * * Transcription Copyright © Parsifal Software, 1999. * * Revision 1 fixed definition of [4] NameChar * * Revision 2, begun 1/24/00 * * Fixed problem with mixed content declaration [51] * Fixed missing S in [52] * Removed unnecessary "sticky" statement */ #include "xmldef8.h" #include <stdio.h> } [ reserve keywords {"--", "?>", "]]>"} test file mask = "*.xml" parser file name = "#.cpp" parser name = parse reentrant parser //line numbers event driven context type = Context extend pcb { AgStack<AgString> tagStack; AgStack<Symtab> mapStack; AgString textStack; AgString spaceStack; enum TokenType { none, spaceType, textType, commentType, startType, endType, emptyType, entityRefType, //charRefType, errorType } tokenType; AgString currentTagName; AgString currentEntityName; //int currentCharRef; AgString commentString; Symtab currentMap; AgStack<Warning> warningList; AgBaseMapString<Element> elementMap; int dtdPresent; parse_pcb_struct(); parse(char *input, AgString *); void spaceChar(int); void textChar(int); void startTag(const Context &, const AgString &, AttvalList &); void emptyTag(const Context &, const AgString &, AttvalList &); void endTag(const AgString &); void registerAttributes(const AgString &name, const AgBaseStack<Attribute> &AttributeList); void checkAttributes(const Context &, const AgString &name, Symtab &map); int warnAttval(const Context &context, const char *, const AttvalPair &p); static void normalize(AgString &s); } wrapper {AttvalPair, AgString, AttvalList, Attribute, AttributeList, Default} ] // Document // [1] document $ -> prolog, element, Misc?..., eof // For completeness eof = -1 // Character Range // [2] //Char = 0x9 + 0xA + 0x20..0xd7ff + 0xe000..0xfffd + 0x0000-0x10ffff Char = 0x9 + 0xA + 0x20..0xff // 8 bit characters only pro tem // White Space // [3] SpaceChar = 0x20 + 0x9 + 0xd + 0xa S -> SpaceChar... // Names and Tokens // [4] NameChar = Letter + Digit + '.' + '-' + '_' + ':' + Extender // + CombiningChar // [5] (AgString) Name -> Letter + '_' + ':':c =AgString().concat(c); -> Name:s, NameChar:c =s.concat(c); // [6] Names -> Name -> Names, S, Name // [7] Nmtoken -> NameChar... // [8] Nmtokens -> Nmtoken, [S, Nmtoken]... // Literals // [9] EntityValue -> '"', [~(eof + '%' + '&' + '"') | PEReference | Reference]..., '"' -> '\'', [~(eof + '%' + '&' + '\'') | PEReference | Reference]..., '\'' // [10] (AgString) AttValue -> '"', dq AttValString:s, '"' =s; -> '\'', sq AttValString:s, '\'' =s; (AgString) dq AttValString -> =AgString(); -> dq AttValString:s, ~(eof + '%' + '&' + '"' + SpaceChar):c =s.concat(c); -> dq AttValString:s, SpaceChar =s.concat(' '); //-> dq AttValString:s, CharRef =s; -> dq AttValString:s, CharRef:c =s.concat(c); -> dq AttValString:s, EntityRef =s; (AgString) sq AttValString -> =AgString(); -> sq AttValString:s, ~(eof + '%' + '&' + '\'' + SpaceChar):c =s.concat(c); -> sq AttValString:s, SpaceChar =s.concat(' '); -> sq AttValString:s, CharRef:c =s.concat(c); -> sq AttValString:s, EntityRef =s; // [11] SystemLiteral -> '"', ~(eof + '"')?..., '"' -> '\'', ~(eof + '\'')?..., '\'' // [12] PubidLiteral -> '"', PubidChar?..., '"' -> '\'', PubidChar-'\''?..., '\'' // [13] PubidChar = 0x20 + 0xd + 0xa + 'a-z' + 'A-Z' + '0-9' + '-' + '\'' + '(' + ')' + '+' + ',' + '.' + '/' + ':' + '?' + ';' + '!' + '*' + '#' + '@' + '$' + '_' + '%' // Character Data // [14] CharData = ~(eof + '<' + '&') // Note that the iteration is in the usage // Note that use of keyword "]]>" will take care of CDATA problem // Comments // [15] Comment -> "<!--", comment text:t, "--", '>' =PCB.tokenType = Pcb::commentType, PCB.commentString = t; (AgString) comment text -> =AgString(); ->comment text:s, Char:c =s.concat(c); // Processing Instructions // [16] PI -> "<?", PITarget, [S, [Char-SpaceChar, Char?...]], "?>" // [17] PITarget -> Name // Name lookup mechanism should reject "xml" // CDATA Sections // [18] CDSect -> CDStart, CData, CDEnd // [19] CDStart -> "<![CDATA[" // [20] CData -> [Char - SpaceChar:c =PCB.textChar(c); | "\r\n" =PCB.spaceChar('\n'); | SpaceChar:c =PCB.spaceChar(c);]... // Keyword recognition logic overrides character recognition // [21] CDEnd -> "]]>" // Prolog // [22] prolog -> XMLDecl?, Misc?..., [doctypedecl, Misc?...] // [23] XMLDecl // -> "<?xml", VersionInfo, EncodingDecl?, SDDecl?, S?, "?>" -> "<?xml", S, VersionInfo, VersionDecl, "?>" VersionDecl -> S? -> S, EncodingDecl, S? -> S, EncodingDecl, S, SDDecl, S? -> S, SDDecl, S? // [24] VersionInfo -> "version", Eq, {'\'', VersionNum, '\'' | '"', VersionNum, '"'} // [25] Eq -> S?, '=', S? // [26] VersionNum -> 'a-z' + 'A-Z' + '0-9' + '_' + '.' + ':' + '-'... // [27] Misc // -> Comment | PI | S -> Comment | PI | SpaceChar // Avoid double recursion // Document Type Definition // [28] doctypedecl -> "<!DOCTYPE", S, Name:n, [S, [ExternalID, S?]], [ '[', [markupdecl | PEReference | SpaceChar]..., ']', S?], '>' =PCB.dtdPresent=1; // [29] markupdecl -> elementdecl -> AttlistDecl -> EntityDecl -> NotationDecl -> PI -> Comment // External Subset // [30] extSubset -> TextDecl?, extSubsetDecl // [31] extSubsetDecl -> [markupdecl | conditionalSect | PEReference | SpaceChar]... // Standalone Document Declaration // [32] SDDecl -> "standalone", Eq, "'yes'" | "\"yes\"" | "'no'" | "\"no\"" // Language Identification // [33] LanguageId -> Langcode, ['-', Subcode]... // [34] Langcode -> ISO639Code | IanaCode | UserCode // [35] ISO639Code -> 'a-z' + 'A-Z' -('i' + 'I' + 'x' + 'X'), 'a-z' + 'A-Z' // [36] IanaCode -> 'i' + 'I', '-', 'a-z' + 'A-Z'... // [37] UserCode -> 'x' + 'X', '-', 'a-z' + 'A-Z'... // [38] Subcode -> 'a-z' + 'A-Z'... // Element // [39] element -> EmptyElementTag -> STag, content, ETag // Start-Tags, End-Tags, and Empty-Element Tags // Start-tag // [40] STag -> '<', Name:n, AttributeList:l, S?, '>' =PCB.startTag(CONTEXT, n, l); (AttvalList) AttributeList -> =AttvalList(); -> AttributeList:list, S, Attribute:a =list.push(a); // [41] (AttvalPair) Attribute -> Name:n, Eq, AttValue:s =AttvalPair(n, s, CONTEXT); // End-tag // [42] ETag -> "</", Name:n, S?, '>' =PCB.endTag(n); // Content of Elements // [43] content -> content unit... content unit -> element -> CharData - SpaceChar:c =PCB.textChar(c); -> CharRef:c =PCB.textChar(c); -> EntityRef -> SpaceChar:c =PCB.spaceChar(c); -> "\r\n" =PCB.spaceChar('\n'); -> CDSect -> PI -> Comment // Tags for Empty Elements // [44] EmptyElementTag -> '<', Name:n, AttributeList:l, S?, "/>" =PCB.emptyTag(CONTEXT, n, l); // Element Type Declaration // [45] elementdecl -> "<!ELEMENT", S, Name, S, contentspec, S?, '>' // [46] contentspec -> "EMPTY" | "ANY" | Mixed | Children // Element-content Models // [47] Children -> {choice | seq}, ['?' | '*' | '+'] // [48] cp -> {Name | choice | seq}, ['?' | '*' | '+'] // [49] choice -> '(', S?, cp, S?, ['|', S?, cp, S?]..., ')' // [50] seq -> '(', S?, cp, S?, {',', S?, cp, S?}..., ')' // Mixed-content Declaration // [51] Mixed -> '(', S?, "#PCDATA", ['|', S?, Name | S]/..., ")*" -> '(', S?, "#PCDATA", S?, ')' // Attribute-list Declaration // [52] AttlistDecl -> "<!ATTLIST", S, Name:n, AttDefs:l, S?, '>' =PCB.registerAttributes(n, l); (AttributeList) AttDefs -> AttDef:a =AttributeList().push(a); -> AttDefs:l, AttDef:a =l.push(a); // [53] (Attribute) AttDef -> S, Name:n, S, AttType:t, S, DefaultDecl:d =Attribute(RULE_CONTEXT[1], n, t, d); // Attribute Types // [54] (Attribute::Type) AttType -> StringType -> TokenizedType -> EnumeratedType // [55] (Attribute::Type) StringType -> "CDATA" =Attribute::CDATA; // [56] (Attribute::Type) TokenizedType -> "ID" =Attribute::ID; -> "IDREF" =Attribute::IDREF; -> "IDREFS" =Attribute::IDREFS; -> "ENTITY" =Attribute::ENTITY; -> "ENTITIES" =Attribute::ENTITIES; -> "NMTOKEN" =Attribute::NMTOKEN; -> "NMTOKENS" =Attribute::NMTOKENS; // [57] (Attribute::Type) EnumeratedType -> NotationType =Attribute::NOTATION; -> Enumeration =Attribute::ENUMERATION; // [58] NotationType -> "NOTATION", S, '(', Name, S?, ['|', S?, Name, S?]..., ')' // [59] Enumeration -> '(', Nmtoken, S?, ['|', S?, Nmtoken, S?]..., ')' // Attribute Defaults // [60] (Default) DefaultDecl -> "#REQUIRED" =Default(Default::REQUIRED); -> "#IMPLIED" =Default(); -> AttValue:v =Default(v); -> "#FIXED", S, AttValue:v =Default(v,1); // Conditional Section // [61] conditionalSect -> includeSect | ignoreSect // [62] includeSect -> "<![", S?, "INCLUDE", S?, '[', extSubsetDecl, "]]>" // [63] ignoreSect -> "<![", S?, "IGNORE", S?, '[', ignoreSectContents?..., "]]>" // [64] ignoreSectContents -> Ignore, ["<![", ignoreSectContents, "]]>", Ignore]... // [65] Ignore -> Char?... //Character Reference // [66] (int) CharRef //-> "&#", '0-9'..., ';' //-> "&#x", '0-9' + 'a-f' + 'A-F'..., ';' //-> decimal CharRef:c, ';' =PCB.currentCharRef = c, PCB.tokenType = Pcb::charRefType; -> decimal CharRef, ';' //-> hex CharRef:c, ';' =PCB.currentCharRef = c, PCB.tokenType = Pcb::charRefType; -> hex CharRef, ';' (int) decimal CharRef -> "&#", '0-9':d =d-'0'; -> decimal CharRef:n, '0-9':d =10*n + d-'0'; (int) hex CharRef -> "&#x", '0-9':d =d-'0'; -> hex CharRef:n, '0-9':d =16*n + d; -> hex CharRef:n, 'a-f' + 'A-F':d =16*n + (d&7) + 9; //Entity Reference // [67] (int) Reference -> EntityRef | CharRef // [68] (int) EntityRef -> '&', Name:s, ';' =PCB.currentEntityName = s, PCB.tokenType = Pcb::entityRefType; // [69] PEReference -> '%', Name, ';' // Entity Declaration // [70] EntityDecl -> GEDecl | PEDecl // [71] GEDecl -> "<!ENTITY", S, Name, S, EntityDef, '>' // [72] PEDecl -> "<!ENTITY", S, '%', S, Name, S, PEDef, S?, '>' // [73] EntityDef -> EntityValue, S? | ExternalID, [NDataDecl | S] // [74] PEDef -> EntityValue | ExternalID // External Entity Declaration // [75] ExternalID -> "SYSTEM", S, SystemLiteral -> "PUBLIC", S, PubidLiteral, S, SystemLiteral // [76] NDataDecl -> S, "NDATA", S, Name // Text Declaration // [77] TextDecl -> "<?xml", S, [VersionInfo, S], EncodingDecl, S?, "?>" // Well-Formed External Parsed Entity // [78] extParsedEnt -> TextDecl?, content // [79] extPE -> TextDecl?, extSubsetDecl // Encoding Declaration // [80] EncodingDecl -> "encoding", Eq, {'"', EncName, '"' | '\'', EncName, '\''} // [81] EncName -> 'a-z' + 'A-Z', ['a-z'+'A-Z'+'0-9'+'_' | '-']... // Notation Declarations // [82] NotationDecl -> "<!NOTATION", S, Name, S, {ExternalID, S? | PublicID}, '>' // [83] PublicID -> "PUBLIC", S, PubidLiteral, S? // Characters // [84] Letter = BaseChar // | Ideographic // No ideographs for now // [85] BaseChar = // only 8 bit characters for now 0x41..0x5a + 0x61..0x7a + 0xc0..0xd6 + 0xd8..0xf6 + 0xf8..0xff // [86] // Ideographic = // [87] // CombiningChar = // [88] Digit = 0x30..0x39 // [89] Extender = 0xb7 { #define GET_CONTEXT CONTEXT = Context(PCB.line, PCB.column) typedef parse_pcb_struct Pcb; parse_pcb_struct::parse_pcb_struct() : tokenType(Pcb::none), dtdPresent(0) { // Nothing to do } void parse_pcb_struct::spaceChar(int c) { if (c == '\r') c = '\n'; if (textStack.size()) tokenType = textType; spaceStack.concat(c); } void parse_pcb_struct::textChar(int c) { if (spaceStack.size()) tokenType=spaceType; textStack.concat((char)c); } void parse_pcb_struct::normalize(AgString &s) { char *readPointer = s; char *writePointer = readPointer; if (readPointer == NULL) return; while (*readPointer && strchr("\t\r\n ",*readPointer)) readPointer++; while (*readPointer) { while (*readPointer && strchr("\t\r\n ",*readPointer) == NULL) *writePointer++ = *readPointer++; while (*readPointer && strchr("\t\r\n ",*readPointer)) readPointer++; if (*readPointer) *writePointer++ = ' '; } *writePointer = 0; } void parse_pcb_struct::checkAttributes(const Context &context, const AgString &name, Symtab &map) { if (!dtdPresent) return; Element &element = elementMap[name]; AgBaseStack<Attribute> &attributeList = element.attributeList; int i; for (i = 0; i < attributeList.size(); i++) { Attribute &attribute = attributeList[i]; switch (attribute.def.presence) { case Default::REQUIRED: { const char *value = map.findValue(attribute.name); if (value) continue; map[attribute.name] = "VALUE NOT SPECIFIED"; char buf[200]; sprintf(buf, "Required attribute '%s' is missing", (const char *)attribute.name); warningList.push(Warning(context, buf)); break; } case Default::DEFAULT: { const char *value = map[attribute.name]; if (value == 0) value = attribute.def.value; if (attribute.def.fixed && attribute.def.value == value) continue; char buf[200]; sprintf(buf, "Value of fixed attribute '%s' does not match default value ", (const char *) attribute.name); warningList.push(Warning(context, buf)); break; } } } for (i = 0; i < attributeList.size(); i++) { Attribute &attribute = attributeList[i]; if (attribute.type != Attribute::CDATA) normalize(map[attribute.name]); } } int parse_pcb_struct::warnAttval(const Context &context, const char *value, const AttvalPair &p) { if (value == NULL) return 0; char buf[200]; sprintf(buf, "Value of '%s' ignored. Previously specified as '%s'", (const char *) p.name, value); warningList.push(Warning(context, buf)); return 1; } void parse_pcb_struct::startTag(const Context &context, const AgString &name, AttvalList &list) { Symtab map; for (int i = 0; i < list.size(); i++) { AgString &value = map[list[i].name]; if (warnAttval(context, value, list[i])) continue; value = list[i].value; } currentTagName = name; checkAttributes(context, name, map); currentMap = map; tagStack.push(name); mapStack.push(map); tokenType = startType; } void parse_pcb_struct::emptyTag(const Context &context, const AgString &name, AttvalList &list) { Symtab map; for (int i = 0; i < list.size(); i++) { AgString &value = map[list[i].name]; if (warnAttval(context, value, list[i])) continue; map[list[i].name] = list[i].value; } checkAttributes(context, name, map); currentTagName = name; currentMap = map; tokenType = emptyType; } void parse_pcb_struct::endTag(const AgString &name) { currentTagName = name; currentMap = mapStack.pop(); if (name != tagStack.pop()) { error_message = "Element nesting error"; exit_flag = AG_SEMANTIC_ERROR_CODE; tokenType = errorType; return; } tokenType = endType; } void parse_pcb_struct::registerAttributes(const AgString &name, const AgBaseStack<Attribute> &attributeList) { Element &element = elementMap[name]; if (element.name.size() == 0) element.name = name; int i; for (i = 0; i < attributeList.size(); i++) { AgString attributeName = attributeList[i].name; int &index = element.attributeIndex[attributeName]; if (index != -1) { Attribute &attribute = element.attributeList[index]; Context previous = attribute.context; char buf[200]; sprintf(buf, "Redefinition of '%s::%s' ignored. Defined at line %d, column %d", (const char *) name, (const char *) attributeName, previous.line, previous.column); warningList.push(Warning(attributeList[i].context, buf)); continue; } index = element.attributeList.size(); element.attributeList.push(attributeList[i]); } } }