2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
6 * These libraries and programs are free software; you can
7 * redistribute them and/or modify them under the terms of the GNU
8 * Lesser General Public License as published by the Free Software
9 * Foundation; either version 2 of the License, or (at your option)
12 * These libraries and programs are distributed in the hope that
13 * they will be useful, but WITHOUT ANY WARRANTY; without even the
14 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU Lesser General Public License for more
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these libraries and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
23 /* $XConsortium: parseInstance.C /main/2 1996/08/12 14:05:40 mgreess $ */
24 // Copyright (c) 1994 James Clark
25 // See the file COPYING for copying permission.
29 #include "ParserMessages.C"
30 #include "MessageArg.h"
31 #include "TokenMessageArg.h"
32 #include "StringVectorMessageArg.h"
37 namespace SP_NAMESPACE {
40 void Parser::doInstanceStart()
46 // FIXME check here that we have a valid dtd
47 compileInstanceModes();
48 setPhase(contentPhase);
49 Token token = getToken(currentMode());
52 case tokenStagoNameStart:
55 case tokenEtagoNameStart:
61 unsigned startImpliedCount = 0;
62 unsigned attributeListIndex = 0;
64 IList<Event> eventList;
65 if (!tryImplyTag(currentLocation(),
71 queueElementEvents(eventList);
74 message(ParserMessages::instanceStartOmittag);
76 currentInput()->ungetToken();
79 void Parser::endInstance()
81 // Do checking before popping entity stack so that there's a
82 // current location for error messages.
84 while (markedSectionLevel() > 0) {
85 message(ParserMessages::unclosedMarkedSection,
86 currentMarkedSectionStartLocation());
94 void Parser::checkIdrefs()
96 IdTableIter iter(idTableIter());
98 while ((id = iter.next()) != 0) {
99 for (size_t i = 0; i < id->pendingRefs().size(); i++) {
100 Messenger::setNextLocation(id->pendingRefs()[i]);
101 message(ParserMessages::missingId, StringMessageArg(id->name()));
106 void Parser::doContent()
113 Token token = getToken(currentMode());
116 if (inputLevel() == 1) {
120 if (inputLevel() == specialParseInputLevel()) {
121 // FIXME have separate messages for each type of special parse
122 // perhaps force end of marked section or element
123 message(ParserMessages::specialParseEntityEnd);
125 if (eventsWanted().wantInstanceMarkup())
126 eventHandler().entityEnd(new (eventAllocator())
127 EntityEndEvent(currentLocation()));
128 if (afterDocumentElement())
129 message(ParserMessages::afterDocumentElementEntityEnd);
134 if (afterDocumentElement())
135 message(ParserMessages::characterReferenceAfterDocumentElement);
138 if (parseNumericCharRef(ch, loc)) {
141 eventHandler().data(new (eventAllocator())
142 ImmediateDataEvent(Event::characterData,
148 case tokenCroNameStart:
149 if (afterDocumentElement())
150 message(ParserMessages::characterReferenceAfterDocumentElement);
154 case tokenEroNameStart:
156 if (afterDocumentElement())
157 message(ParserMessages::entityReferenceAfterDocumentElement);
158 ConstPtr<Entity> entity;
159 Ptr<EntityOrigin> origin;
160 if (parseEntityReference(0, token == tokenEroGrpo, entity, origin)) {
161 if (!entity.isNull()) {
162 if (entity->isCharacterData())
163 acceptPcdata(Location(origin.pointer(), 0));
164 if (inputLevel() == specialParseInputLevel())
165 entity->rcdataReference(*this, origin);
167 entity->contentReference(*this, origin);
173 case tokenEtagoNameStart:
182 case tokenMdoNameStart:
183 if (startMarkup(eventsWanted().wantInstanceMarkup(), currentLocation()))
184 currentMarkup()->addDelim(Syntax::dMDO);
185 Syntax::ReservedName name;
188 startLevel = inputLevel();
189 if (parseDeclarationName(&name)) {
191 case Syntax::rUSEMAP:
192 if (afterDocumentElement())
193 message(ParserMessages::declarationAfterDocumentElement,
194 StringMessageArg(syntax().reservedName(name)));
195 result = parseUsemapDecl();
197 case Syntax::rUSELINK:
198 if (afterDocumentElement())
199 message(ParserMessages::declarationAfterDocumentElement,
200 StringMessageArg(syntax().reservedName(name)));
201 result = parseUselinkDecl();
203 case Syntax::rDOCTYPE:
204 case Syntax::rLINKTYPE:
205 case Syntax::rELEMENT:
206 case Syntax::rATTLIST:
207 case Syntax::rENTITY:
208 case Syntax::rNOTATION:
209 case Syntax::rSHORTREF:
211 case Syntax::rIDLINK:
212 message(ParserMessages::instanceDeclaration,
213 StringMessageArg(syntax().reservedName(name)));
217 message(ParserMessages::noSuchDeclarationType,
218 StringMessageArg(syntax().reservedName(name)));
226 skipDeclaration(startLevel);
239 if (afterDocumentElement())
240 message(ParserMessages::markedSectionAfterDocumentElement);
241 parseMarkedSectionDeclStart();
245 handleMarkedSectionEnd();
252 parseProcessingInstruction();
254 case tokenStagoNameStart:
258 parseEmptyStartTag();
261 parseGroupStartTag();
264 acceptPcdata(currentLocation());
265 queueRe(currentLocation());
268 acceptPcdata(currentLocation());
270 if (eventsWanted().wantInstanceMarkup())
271 eventHandler().ignoredRs(new (eventAllocator())
272 IgnoredRsEvent(currentChar(),
277 if (eventsWanted().wantInstanceMarkup())
278 eventHandler().sSep(new (eventAllocator())
279 SSepEvent(currentInput()->currentTokenStart(),
280 currentInput()->currentTokenLength(),
284 case tokenIgnoredChar:
286 if (eventsWanted().wantMarkedSections())
287 eventHandler().ignoredChars(new (eventAllocator())
288 IgnoredCharsEvent(currentInput()->currentTokenStart(),
289 currentInput()->currentTokenLength(),
293 case tokenUnrecognized:
294 reportNonSgmlCharacter();
300 ASSERT(token >= tokenFirstShortref);
301 handleShortref(token - tokenFirstShortref);
304 } while (eventQueueEmpty());
307 void Parser::skipDeclaration(unsigned startLevel)
309 const unsigned skipMax = 250;
310 unsigned skipCount = 0;
312 Token token = getToken(mdMode);
313 if (inputLevel() == startLevel)
316 case tokenUnrecognized:
320 if (inputLevel() <= startLevel)
325 if (inputLevel() == startLevel)
329 if (inputLevel() == startLevel && skipCount >= skipMax
330 && currentChar() == syntax().standardFunction(Syntax::fRE))
339 void Parser::handleShortref(int index)
341 const ConstPtr<Entity> &entity
342 = currentElement().map()->entity(index);
343 if (!entity.isNull()) {
344 Owner<Markup> markupPtr;
345 if (eventsWanted().wantInstanceMarkup()) {
346 markupPtr = new Markup;
347 markupPtr->addShortref(currentInput());
349 Ptr<EntityOrigin> origin
350 = new (internalAllocator())
353 currentInput()->currentTokenLength(),
355 entity->contentReference(*this, origin);
358 InputSource *in = currentInput();
359 size_t length = in->currentTokenLength();
360 const Char *s = in->currentTokenStart();
362 if (currentMode() == econMode || currentMode() == econnetMode) {
363 // FIXME do this in advance (what about B sequence?)
364 for (i = 0; i < length && syntax().isS(s[i]); i++)
366 if (i > 0 && eventsWanted().wantInstanceMarkup())
367 eventHandler().sSep(new (eventAllocator())
368 SSepEvent(s, i, currentLocation(), 0));
371 Location location(currentLocation());
375 acceptPcdata(location);
376 // FIXME speed this up
377 for (; length > 0; location += 1, length--, s++) {
378 if (*s == syntax().standardFunction(Syntax::fRS)) {
380 if (eventsWanted().wantInstanceMarkup())
381 eventHandler().ignoredRs(new (eventAllocator())
382 IgnoredRsEvent(*s, location));
384 else if (*s == syntax().standardFunction(Syntax::fRE))
388 eventHandler().data(new (eventAllocator())
389 ImmediateDataEvent(Event::characterData, s, 1,
396 void Parser::parsePcdata()
399 acceptPcdata(currentLocation());
401 eventHandler().data(new (eventAllocator())
402 ImmediateDataEvent(Event::characterData,
403 currentInput()->currentTokenStart(),
404 currentInput()->currentTokenLength(),
409 void Parser::parseStartTag()
411 InputSource *in = currentInput();
412 Markup *markup = startMarkup(eventsWanted().wantInstanceMarkup(),
413 in->currentLocation());
414 in->discardInitial();
415 extendNameToken(syntax().namelen(), ParserMessages::nameLength);
417 markup->addDelim(Syntax::dSTAGO);
420 StringC &name = nameBuffer();
421 getCurrentToken(syntax().generalSubstTable(), name);
422 const ElementType *e = currentDtd().lookupElementType(name);
425 e = completeRankStem(name);
426 else if (e->isRankedElement())
427 handleRankedElement(e);
430 e = lookupCreateUndefinedElement(name, currentLocation());
432 AttributeList *attributes = allocAttributeList(e->attributeDef(), 0);
433 Token closeToken = getToken(tagMode);
434 if (closeToken == tokenTagc) {
435 if (name.size() > syntax().taglen())
436 checkTaglen(markupLocation().index());
437 attributes->finish(*this);
440 markup->addDelim(Syntax::dTAGC);
444 if (parseAttributeSpec(0, *attributes, netEnabling)) {
445 // The difference between the indices will be the difference
446 // in offsets plus 1 for each named character reference.
447 if (in->currentLocation().index() - markupLocation().index()
449 checkTaglen(markupLocation().index());
455 new (eventAllocator())
464 const ElementType *Parser::completeRankStem(const StringC &name)
466 const RankStem *rankStem = currentDtd().lookupRankStem(name);
468 StringC name(rankStem->name());
469 if (!appendCurrentRank(name, rankStem))
470 message(ParserMessages::noCurrentRank, StringMessageArg(name));
472 return currentDtd().lookupElementType(name);
477 void Parser::handleRankedElement(const ElementType *e)
479 StringC rankSuffix(e->definition()->rankSuffix());
480 const RankStem *rankStem = e->rankedElementRankStem();
481 for (size_t i = 0; i < rankStem->nDefinitions(); i++) {
482 const ElementDefinition *def = rankStem->definition(i);
483 for (size_t j = 0; j < def->nRankStems(); j++)
484 setCurrentRank(def->rankStem(j), rankSuffix);
488 void Parser::checkTaglen(Index tagStartIndex)
490 const InputSourceOrigin *origin
491 = currentLocation().origin()->asInputSourceOrigin();
493 if (origin->startOffset(currentLocation().index())
494 - origin->startOffset(tagStartIndex
495 + syntax().delimGeneral(Syntax::dSTAGO).size())
497 message(ParserMessages::taglen, NumberMessageArg(syntax().taglen()));
500 void Parser::parseEmptyStartTag()
502 if (options().warnEmptyTag)
503 message(ParserMessages::emptyStartTag);
504 // FIXME error if not in base.
505 const ElementType *e = 0;
507 e = lastEndedElementType();
508 else if (tagLevel() > 0)
509 e = currentElement().type();
511 e = currentDtd().documentElementType();
512 AttributeList *attributes = allocAttributeList(e->attributeDef(), 0);
513 attributes->finish(*this);
514 Markup *markup = startMarkup(eventsWanted().wantInstanceMarkup(),
517 markup->addDelim(Syntax::dSTAGO);
518 markup->addDelim(Syntax::dTAGC);
521 new (eventAllocator())
530 void Parser::parseGroupStartTag()
532 if (startMarkup(eventsWanted().wantInstanceMarkup(), currentLocation())) {
533 currentMarkup()->addDelim(Syntax::dSTAGO);
534 currentMarkup()->addDelim(Syntax::dGRPO);
537 if (!parseTagNameGroup(active))
539 InputSource *in = currentInput();
540 // Location startLocation = in->currentLocation();
542 Xchar c = in->tokenChar(messenger());
543 if (!syntax().isNameStartCharacter(c)) {
544 message(ParserMessages::startTagMissingName);
547 in->discardInitial();
548 extendNameToken(syntax().namelen(), ParserMessages::nameLength);
550 currentMarkup()->addName(currentInput());
553 eventHandler().ignoredMarkup(new (eventAllocator())
554 IgnoredMarkupEvent(markupLocation(),
559 void Parser::parseGroupEndTag()
561 if (startMarkup(eventsWanted().wantInstanceMarkup(), currentLocation())) {
562 currentMarkup()->addDelim(Syntax::dSTAGO);
563 currentMarkup()->addDelim(Syntax::dGRPO);
566 if (!parseTagNameGroup(active))
568 InputSource *in = currentInput();
569 // Location startLocation = in->currentLocation();
571 Xchar c = in->tokenChar(messenger());
572 if (!syntax().isNameStartCharacter(c)) {
573 message(ParserMessages::endTagMissingName);
576 in->discardInitial();
577 extendNameToken(syntax().namelen(), ParserMessages::nameLength);
579 currentMarkup()->addName(currentInput());
582 eventHandler().ignoredMarkup(new (eventAllocator())
583 IgnoredMarkupEvent(markupLocation(),
588 void Parser::acceptPcdata(const Location &startLocation)
590 if (currentElement().tryTransitionPcdata())
592 // Need to test here since implying tags may turn off pcdataRecovering.
593 if (pcdataRecovering())
595 IList<Undo> undoList;
596 IList<Event> eventList;
597 unsigned startImpliedCount = 0;
598 unsigned attributeListIndex = 0;
600 while (tryImplyTag(startLocation, startImpliedCount, attributeListIndex,
601 undoList, eventList))
602 if (currentElement().tryTransitionPcdata()) {
603 queueElementEvents(eventList);
606 discardKeptMessages();
608 message(ParserMessages::pcdataNotAllowed);
612 void Parser::acceptStartTag(const ElementType *e,
613 StartElementEvent *event,
616 if (e->definition()->undefined()) {
617 message(ParserMessages::undefinedElement, StringMessageArg(e->name()));
618 pushElementCheck(e, event, netEnabling);
621 if (elementIsExcluded(e)) {
626 if (currentElement().tryTransition(e)) {
627 pushElementCheck(e, event, netEnabling);
630 if (elementIsIncluded(e)) {
631 event->setIncluded();
632 pushElementCheck(e, event, netEnabling);
637 IList<Undo> undoList;
638 IList<Event> eventList;
639 unsigned startImpliedCount = 0;
640 unsigned attributeListIndex = 1;
641 while (tryImplyTag(event->location(), startImpliedCount,
642 attributeListIndex, undoList, eventList))
643 if (tryStartTag(e, event, netEnabling, eventList))
645 discardKeptMessages();
647 handleBadStartTag(e, event, netEnabling);
650 void Parser::undo(IList<Undo> &undoList)
652 while (!undoList.empty()) {
653 Undo *p = undoList.get();
659 void Parser::queueElementEvents(IList<Event> &events)
661 releaseKeptMessages();
662 // FIXME provide IList<T>::reverse function
665 while (!events.empty())
666 tem.insert(events.get());
667 while (!tem.empty()) {
668 Event *e = tem.get();
669 if (e->type() == Event::startElement) {
670 noteStartElement(((StartElementEvent *)e)->included());
671 eventHandler().startElement((StartElementEvent *)e);
674 noteEndElement(((EndElementEvent *)e)->included());
675 eventHandler().endElement((EndElementEvent *)e);
681 void Parser::checkExclusion(const ElementType *e)
683 const LeafContentToken *token = currentElement().invalidExclusion(e);
685 message(ParserMessages::invalidExclusion,
686 OrdinalMessageArg(token->typeIndex() + 1),
687 StringMessageArg(token->elementType()->name()),
688 StringMessageArg(currentElement().type()->name()));
691 Boolean Parser::tryStartTag(const ElementType *e,
692 StartElementEvent *event,
694 IList<Event> &impliedEvents)
696 if (elementIsExcluded(e)) {
700 if (currentElement().tryTransition(e)) {
701 queueElementEvents(impliedEvents);
702 pushElementCheck(e, event, netEnabling);
705 if (elementIsIncluded(e)) {
706 queueElementEvents(impliedEvents);
707 event->setIncluded();
708 pushElementCheck(e, event, netEnabling);
714 Boolean Parser::tryImplyTag(const Location &loc,
715 unsigned &startImpliedCount,
716 unsigned &attributeListIndex,
718 IList<Event> &eventList)
722 if (currentElement().isFinished()) {
726 const ElementDefinition *def = currentElement().type()->definition();
727 if (def && !def->canOmitEndTag())
731 if (startImpliedCount > 0) {
732 message(ParserMessages::startTagEmptyElement,
733 StringMessageArg(currentElement().type()->name()));
737 const ElementDefinition *def = currentElement().type()->definition();
738 if (def && !def->canOmitEndTag())
739 message(ParserMessages::omitEndTagDeclare,
740 StringMessageArg(currentElement().type()->name()),
741 currentElement().startLocation());
743 EndElementEvent *event
744 = new (eventAllocator()) EndElementEvent(currentElement().type(),
748 eventList.insert(event);
749 undo.insert(new (internalAllocator()) UndoEndTag(popSaveElement()));
752 const LeafContentToken *token = currentElement().impliedStartTag();
755 const ElementType *e = token->elementType();
756 if (elementIsExcluded(e))
757 message(ParserMessages::requiredElementExcluded,
758 OrdinalMessageArg(token->typeIndex() + 1),
759 StringMessageArg(e->name()),
760 StringMessageArg(currentElement().type()->name()));
762 undo.insert(new (internalAllocator())
763 UndoTransition(currentElement().matchState()));
764 currentElement().doRequiredTransition();
765 const ElementDefinition *def = e->definition();
766 if (def->declaredContent() != ElementDefinition::modelGroup
767 && def->declaredContent() != ElementDefinition::any)
768 message(ParserMessages::omitStartTagDeclaredContent,
769 StringMessageArg(e->name()));
770 if (def->undefined())
771 message(ParserMessages::undefinedElement, StringMessageArg(e->name()));
772 else if (!def->canOmitStartTag())
773 message(ParserMessages::omitStartTagDeclare, StringMessageArg(e->name()));
774 AttributeList *attributes
775 = allocAttributeList(e->attributeDef(),
776 attributeListIndex++);
777 // this will give an error if the element has a required attribute
778 attributes->finish(*this);
780 StartElementEvent *event
781 = new (eventAllocator()) StartElementEvent(e,
786 pushElementCheck(e, event, undo, eventList);
787 const int implyCheckLimit = 30; // this is fairly arbitrary
788 if (startImpliedCount > implyCheckLimit
789 && !checkImplyLoop(startImpliedCount))
794 void Parser::pushElementCheck(const ElementType *e, StartElementEvent *event,
797 if (tagLevel() == syntax().taglvl())
798 message(ParserMessages::taglvlOpenElements, NumberMessageArg(syntax().taglvl()));
799 noteStartElement(event->included());
800 if (event->mustOmitEnd()) {
802 = new (eventAllocator()) EndElementEvent(e,
806 if (event->included()) {
812 eventHandler().startElement(event);
813 eventHandler().endElement(end);
816 const ShortReferenceMap *map = e->map();
818 map = currentElement().map();
819 pushElement(new (internalAllocator()) OpenElement(e,
824 // Can't access event after it's passed to the event handler.
825 eventHandler().startElement(event);
829 void Parser::pushElementCheck(const ElementType *e, StartElementEvent *event,
830 IList<Undo> &undoList,
831 IList<Event> &eventList)
833 if (tagLevel() == syntax().taglvl())
834 message(ParserMessages::taglvlOpenElements, NumberMessageArg(syntax().taglvl()));
835 eventList.insert(event);
836 if (event->mustOmitEnd()) {
838 = new (eventAllocator()) EndElementEvent(e,
842 if (event->included())
844 eventList.insert(end);
847 undoList.insert(new (internalAllocator()) UndoStartTag);
848 const ShortReferenceMap *map = e->map();
850 map = currentElement().map();
851 pushElement(new (internalAllocator()) OpenElement(e,
859 void Parser::parseEndTag()
861 Markup *markup = startMarkup(eventsWanted().wantInstanceMarkup(),
863 currentInput()->discardInitial();
864 extendNameToken(syntax().namelen(), ParserMessages::nameLength);
866 markup->addDelim(Syntax::dETAGO);
867 markup->addName(currentInput());
869 StringC &name = nameBuffer();
870 getCurrentToken(syntax().generalSubstTable(), name);
871 const ElementType *e = currentDtd().lookupElementType(name);
874 e = completeRankStem(name);
877 e = lookupCreateUndefinedElement(name, currentLocation());
880 new (eventAllocator())
887 void Parser::parseEndTagClose()
890 Token token = getToken(tagMode);
892 case tokenUnrecognized:
893 if (!reportNonSgmlCharacter())
894 message(ParserMessages::endTagCharacter, StringMessageArg(currentToken()));
897 message(ParserMessages::endTagEntityEnd);
901 if (!sd().shorttag())
902 message(ParserMessages::minimizedEndTag);
903 else if (options().warnUnclosedTag)
904 message(ParserMessages::unclosedEndTag);
905 currentInput()->ungetToken();
909 currentMarkup()->addDelim(Syntax::dTAGC);
913 currentMarkup()->addS(currentChar());
916 message(ParserMessages::endTagInvalidToken,
917 TokenMessageArg(token, tagMode, syntaxPointer(), sdPointer()));
923 void Parser::parseEmptyEndTag()
925 if (options().warnEmptyTag)
926 message(ParserMessages::emptyEndTag);
927 // FIXME what to do if not in base
929 message(ParserMessages::emptyEndTagNoOpenElements);
931 Markup *markup = startMarkup(eventsWanted().wantInstanceMarkup(),
934 markup->addDelim(Syntax::dETAGO);
935 markup->addDelim(Syntax::dTAGC);
937 acceptEndTag(currentElement().type(),
938 new (eventAllocator()) EndElementEvent(currentElement().type(),
945 void Parser::parseNullEndTag()
947 if (options().warnNet)
948 message(ParserMessages::nullEndTag);
949 // If a null end tag was recognized, then there must be a net enabling
950 // element on the stack.
952 ASSERT(tagLevel() > 0);
953 if (currentElement().netEnabling())
955 if (!currentElement().isFinished())
956 message(ParserMessages::elementNotFinished,
957 StringMessageArg(currentElement().type()->name()));
958 implyCurrentElementEnd(currentLocation());
960 if (!currentElement().isFinished())
961 message(ParserMessages::elementEndTagNotFinished,
962 StringMessageArg(currentElement().type()->name()));
963 Markup *markup = startMarkup(eventsWanted().wantInstanceMarkup(),
966 markup->addDelim(Syntax::dNET);
967 acceptEndTag(currentElement().type(),
968 new (eventAllocator()) EndElementEvent(currentElement().type(),
974 void Parser::endAllElements()
976 while (tagLevel() > 0) {
977 if (!currentElement().isFinished())
978 message(ParserMessages::elementNotFinishedDocumentEnd,
979 StringMessageArg(currentElement().type()->name()));
980 implyCurrentElementEnd(currentLocation());
982 if (!currentElement().isFinished())
983 message(ParserMessages::noDocumentElement);
986 void Parser::acceptEndTag(const ElementType *e,
987 EndElementEvent *event)
989 if (!elementIsOpen(e)) {
990 message(ParserMessages::elementNotOpen, StringMessageArg(e->name()));
995 if (currentElement().type() == e)
997 if (!currentElement().isFinished())
998 message(ParserMessages::elementNotFinished,
999 StringMessageArg(currentElement().type()->name()));
1000 implyCurrentElementEnd(event->location());
1002 if (!currentElement().isFinished())
1003 message(ParserMessages::elementEndTagNotFinished,
1004 StringMessageArg(currentElement().type()->name()));
1005 if (currentElement().included())
1006 event->setIncluded();
1007 noteEndElement(event->included());
1008 eventHandler().endElement(event);
1012 void Parser::implyCurrentElementEnd(const Location &loc)
1014 if (!sd().omittag())
1015 message(ParserMessages::omitEndTagOmittag,
1016 StringMessageArg(currentElement().type()->name()),
1017 currentElement().startLocation());
1019 const ElementDefinition *def = currentElement().type()->definition();
1020 if (def && !def->canOmitEndTag())
1021 message(ParserMessages::omitEndTagDeclare,
1022 StringMessageArg(currentElement().type()->name()),
1023 currentElement().startLocation());
1025 EndElementEvent *event
1026 = new (eventAllocator()) EndElementEvent(currentElement().type(),
1027 currentDtdPointer(),
1030 if (currentElement().included())
1031 event->setIncluded();
1032 noteEndElement(event->included());
1033 eventHandler().endElement(event);
1037 void Parser::extendData()
1039 XcharMap<PackedBoolean> isNormal(normalMap());
1040 InputSource *in = currentInput();
1041 size_t length = in->currentTokenLength();
1042 // This is one of the parser's inner loops, so it needs to be fast.
1043 while (isNormal[in->tokenChar(messenger())])
1045 in->endToken(length);
1048 void Parser::extendContentS()
1050 InputSource *in = currentInput();
1051 size_t length = in->currentTokenLength();
1052 XcharMap<PackedBoolean> isNormal(normalMap());
1054 Xchar ch = in->tokenChar(messenger());
1055 if (!syntax().isS(ch) || !isNormal[ch])
1059 in->endToken(length);
1062 void Parser::handleBadStartTag(const ElementType *e,
1063 StartElementEvent *event,
1064 Boolean netEnabling)
1066 IList<Undo> undoList;
1067 IList<Event> eventList;
1070 Vector<const ElementType *> missing;
1071 findMissingTag(e, missing);
1072 if (missing.size() == 1) {
1073 queueElementEvents(eventList);
1074 const ElementType *m = missing[0];
1075 message(ParserMessages::missingElementInferred,
1076 StringMessageArg(e->name()),
1077 StringMessageArg(m->name()));
1078 AttributeList *attributes
1079 = allocAttributeList(m->attributeDef(), 1);
1080 // this will give an error if the element has a required attribute
1081 attributes->finish(*this);
1082 StartElementEvent *inferEvent
1083 = new (eventAllocator()) StartElementEvent(m,
1084 currentDtdPointer(),
1088 if (!currentElement().tryTransition(m))
1089 inferEvent->setIncluded();
1090 pushElementCheck(m, inferEvent, 0);
1091 if (!currentElement().tryTransition(e))
1092 event->setIncluded();
1093 pushElementCheck(e, event, netEnabling);
1096 if (missing.size() > 0) {
1097 queueElementEvents(eventList);
1098 Vector<StringC> missingNames;
1099 for (size_t i = 0; i < missing.size(); i++)
1100 missingNames.push_back(missing[i]->name());
1101 message(ParserMessages::missingElementMultiple,
1102 StringMessageArg(e->name()),
1103 StringVectorMessageArg(missingNames));
1104 pushElementCheck(e, event, netEnabling);
1108 || !currentElement().isFinished()
1110 || !currentElement().type()->definition()->canOmitEndTag())
1112 EndElementEvent *endEvent
1113 = new (eventAllocator()) EndElementEvent(currentElement().type(),
1114 currentDtdPointer(),
1117 eventList.insert(endEvent);
1118 undoList.insert(new (internalAllocator()) UndoEndTag(popSaveElement()));
1120 discardKeptMessages();
1122 message(ParserMessages::elementNotAllowed, StringMessageArg(e->name()));
1123 // If element couldn't occur because it was excluded, then
1124 // do the transition here.
1125 (void)currentElement().tryTransition(e);
1126 pushElementCheck(e, event, netEnabling);
1129 void Parser::findMissingTag(const ElementType *e,
1130 Vector<const ElementType *> &v)
1134 if (!currentElement().currentPosition()) {
1136 v.push_back((const ElementType *)0);
1139 if (elementIsExcluded(e))
1142 currentElement().matchState().possibleTransitions(v);
1143 // FIXME also get currentInclusions
1144 for (i = 0; i < v.size(); i++) {
1145 if (v[i] && !elementIsExcluded(v[i])) {
1146 Boolean success = 0;
1147 switch (v[i]->definition()->declaredContent()) {
1148 case ElementDefinition::modelGroup:
1150 const CompiledModelGroup *grp
1151 = v[i]->definition()->compiledModelGroup();
1152 MatchState state(grp);
1154 if (state.tryTransitionPcdata())
1158 if (state.tryTransition(e))
1161 for (size_t j = 0; j < v[i]->definition()->nInclusions(); j++)
1162 if (v[i]->definition()->inclusion(j) == e) {
1168 for (size_t j = 0; j < v[i]->definition()->nExclusions(); j++)
1169 if (v[i]->definition()->exclusion(j) == e) {
1178 case ElementDefinition::any:
1182 case ElementDefinition::cdata:
1183 case ElementDefinition::rcdata:
1191 v[newSize++] = v[i];
1195 // Sort them according to the order of their occurrence in the DTD.
1196 // Do an insertion sort.
1197 for (i = 1; i < v.size(); i++) {
1198 const ElementType *tem = v[i];
1200 for (j = i; j > 0 && v[j - 1]->index() > tem->index(); j--)
1207 // This produces messages that are too verbose
1208 // This doesn't try to be very efficient.
1211 void Parser::getAllowedElementTypes(Vector<const ElementType *> &v)
1214 // FIXME get a list of all inclusions first
1215 // getCurrentInclusions(v);
1216 // x says whether each element of v was excluded
1217 Vector<PackedBoolean> x(v.size(), 0);
1218 unsigned startImpliedCount = 0;
1219 IList<Undo> undoList;
1221 if (currentElement().currentPosition()) {
1222 // have a model group
1223 size_t i = v.size();
1224 currentElement().matchState().possibleTransitions(v);
1226 for (size_t j = i; j < v.size(); j++)
1227 x[j] = (v[j] && elementIsExcluded(v[j]));
1228 if (!sd().omittag())
1230 // Try to imply a tag
1231 if (currentElement().isFinished()) {
1232 if (tagLevel() == 0)
1234 if (startImpliedCount)
1236 const ElementDefinition *def = currentElement().type()->definition();
1237 if (def && def->canOmitEndTag())
1238 undoList.insert(new (internalAllocator())
1239 UndoEndTag(popSaveElement()));
1244 const LeafContentToken *token = currentElement().impliedStartTag();
1247 const ElementType *e = token->elementType();
1248 if (elementIsExcluded(e))
1250 const ElementDefinition *def = e->definition();
1253 || (def->declaredContent() != ElementDefinition::modelGroup
1254 && def->declaredContent() != ElementDefinition::any)
1255 || !def->canOmitStartTag())
1257 undoList.insert(new (internalAllocator()) UndoStartTag);
1258 startImpliedCount++;
1259 pushElement(new (internalAllocator()) OpenElement(e,
1264 if (checkImplyLoop(startImpliedCount))
1266 for (size_t i = 0; i < def->nInclusions(); i++)
1267 if (!elementIsExcluded(def->inclusion(i))) {
1268 v.push_back(def->inclusion(i));
1274 // must be allowed #pcdata
1275 v.push_back((const ElementType *)0);
1276 x.push_back((PackedBoolean)0);
1281 // Remove exclusions and duplicates and undefined
1283 for (size_t i = 0; i < v.size(); i++)
1284 if (!x[i] && (!v[i] || !v[i]->definition()->undefined())) {
1286 for (size_t j = 0; j < newSize; j++)
1292 v[newSize++] = v[i];