Initial import of the CDE 2.1.30 sources from the Open Group.
[oweals/cde.git] / cde / programs / nsgmls / parseDecl.C
1 /* $XConsortium: parseDecl.C /main/1 1996/07/29 17:09:16 cde-hp $ */
2 // Copyright (c) 1994, 1995 James Clark
3 // See the file COPYING for copying permission.
4
5 // Prolog, dtd and declaration parsing.
6
7 #include "splib.h"
8 #include "Parser.h"
9 #include "Param.h"
10 #include "Markup.h"
11 #include "ParserMessages.h"
12 #include "MessageArg.h"
13 #include "TokenMessageArg.h"
14 #include "token.h"
15 #include "macros.h"
16
17 #ifdef SP_NAMESPACE
18 namespace SP_NAMESPACE {
19 #endif
20
21 static const AllowedParams allowMdc(Param::mdc);
22 static const AllowedParams allowName(Param::name);
23 static const AllowedParams allowParamLiteral(Param::paramLiteral);
24 static const AllowedParams allowNameNameGroup(Param::name, Param::nameGroup);
25 static const AllowedParams allowDsoMdc(Param::dso, Param::mdc);
26 static AllowedParams allowNameMdc(Param::name, Param::mdc);
27 static AllowedParams
28   allowExplicitLinkRuleMdc(Param::mdc,
29                            Param::name,
30                            Param::nameGroup,
31                            Param::indicatedReservedName + Syntax::rIMPLIED);
32 static AllowedParams
33   allowNameNameGroupMdc(Param::name, Param::nameGroup, Param::mdc);
34
35 static const AllowedParams
36   allowLinkSetSpec(Param::name,
37                    Param::indicatedReservedName + Syntax::rINITIAL,
38                    Param::indicatedReservedName + Syntax::rEMPTY,
39                    Param::indicatedReservedName + Syntax::rRESTORE);
40
41 void Parser::doProlog()
42 {
43   const unsigned maxTries = 10;
44   unsigned tries = 0;
45   do {
46     if (cancelled()) {
47       allDone();
48       return;
49     }
50     Token token = getToken(proMode);
51     switch (token) {
52     case tokenUnrecognized:
53       if (reportNonSgmlCharacter())
54         break;
55       if (hadDtd()) {
56         currentInput()->ungetToken();
57         endProlog();
58         return;
59       }
60       {
61         StringC gi;
62         if (lookingAtStartTag(gi)) {
63           currentInput()->ungetToken();
64           if (!implyDtd(gi)) {
65             message(ParserMessages::noDtd);
66             giveUp();
67           }
68           return;
69         }
70       }
71             
72       if (++tries >= maxTries) {
73         message(ParserMessages::noDtd);
74         giveUp();
75         return;
76       }
77       message(ParserMessages::prologCharacter, StringMessageArg(currentToken()));
78       prologRecover();
79       break;
80     case tokenEe:
81       if (hadDtd()) {
82         endProlog();
83         return;
84       }
85       message(ParserMessages::documentEndProlog);
86       allDone();
87       return;
88     case tokenMdoMdc:
89       // empty comment
90       emptyCommentDecl();
91       break;
92     case tokenMdoCom:
93       if (!parseCommentDecl())
94         prologRecover();
95       break;
96     case tokenMdoNameStart:
97       setPass2Start();
98       if (startMarkup(eventsWanted().wantPrologMarkup(), currentLocation()))
99         currentMarkup()->addDelim(Syntax::dMDO);
100       Syntax::ReservedName name;
101       if (parseDeclarationName(&name)) {
102         switch (name) {
103         case Syntax::rDOCTYPE:
104           if (!parseDoctypeDeclStart())
105             giveUp();
106           return;
107         case Syntax::rLINKTYPE:
108           if (!parseLinktypeDeclStart())
109             giveUp();
110           return;
111         case Syntax::rELEMENT:
112         case Syntax::rATTLIST:
113         case Syntax::rENTITY:
114         case Syntax::rNOTATION:
115         case Syntax::rSHORTREF:
116         case Syntax::rUSEMAP:
117         case Syntax::rUSELINK:
118         case Syntax::rLINK:
119         case Syntax::rIDLINK:
120           message(ParserMessages::prologDeclaration,
121                   StringMessageArg(syntax().reservedName(name)));
122           if (!hadDtd())
123             tries++;
124           prologRecover();
125           break;
126         default:
127           message(ParserMessages::noSuchDeclarationType,
128                   StringMessageArg(syntax().reservedName(name)));
129           prologRecover();
130           break;
131         }
132       }
133       else
134         prologRecover();
135       break;
136     case tokenPio:
137       if (!parseProcessingInstruction())
138         prologRecover();
139       break;
140     case tokenS:
141       if (eventsWanted().wantPrologMarkup()) {
142         extendS();
143         eventHandler().sSep(new (eventAllocator())
144                             SSepEvent(currentInput()->currentTokenStart(),
145                                       currentInput()->currentTokenLength(),
146                                       currentLocation(),
147                                       1));
148       }
149       break;
150     default:
151       CANNOT_HAPPEN();
152     }
153   } while (eventQueueEmpty());
154 }
155
156 void Parser::endProlog()
157 {
158   if (baseDtd().isNull()
159       || baseDtd()->documentElementType()->definition()->undefined()) {
160     // We could continue, but there's not a lot of point.
161     giveUp();
162     return;
163   }
164   if (maybeStartPass2())
165     setPhase(prologPhase);
166   else {
167     if (inputLevel() == 0) {
168       allDone();
169       return;
170     }
171     if (pass2())
172       checkEntityStability();
173     setPhase(instanceStartPhase);
174     startInstance();
175     ConstPtr<ComplexLpd> lpd;
176     Vector<AttributeList> simpleLinkAtts;
177     Vector<StringC> simpleLinkNames;
178     for (size_t i = 0; i < nActiveLink(); i++)
179       if (activeLpd(i).type() == Lpd::simpleLink) {
180         const SimpleLpd &lpd = (SimpleLpd &)activeLpd(i);
181         simpleLinkNames.push_back(lpd.name());
182         simpleLinkAtts.resize(simpleLinkAtts.size() + 1);
183         simpleLinkAtts.back().init(lpd.attributeDef());
184         simpleLinkAtts.back().finish(*this);
185       }
186       else 
187         lpd = (ComplexLpd *)&activeLpd(i);
188     eventHandler().endProlog(new (eventAllocator())
189                              EndPrologEvent(baseDtd(),
190                                             lpd,
191                                             simpleLinkNames,
192                                             simpleLinkAtts,
193                                             currentLocation()));
194   }
195 }
196
197 void Parser::prologRecover()
198 {
199   unsigned skipCount = 0;
200   const unsigned skipMax = 250;
201   for (;;) {
202     Token token = getToken(proMode);
203     skipCount++;
204     if (token == tokenUnrecognized) {
205       token = getToken(mdMode);
206       if (token == tokenMdc) {
207         token = getToken(proMode);
208         if (token == tokenS)
209           return;
210       }
211     }
212     switch (token) {
213     case tokenUnrecognized:
214       (void)getChar();
215       break;
216     case tokenEe:
217       return;
218     case tokenMdoMdc:
219     case tokenMdoCom:
220     case tokenMdoNameStart:
221     case tokenPio:
222       currentInput()->ungetToken();
223       return;
224     case tokenS:
225       if (currentChar() == syntax().standardFunction(Syntax::fRE)
226           && skipCount >= skipMax)
227         return;
228     default:
229       break;
230     }
231   }
232 }
233
234 void Parser::doDeclSubset()
235 {
236   do {
237     if (cancelled()) {
238       allDone();
239       return;
240     }
241     Token token = getToken(currentMode());
242     unsigned startLevel = inputLevel();
243     Boolean inDtd = !haveDefLpd();
244     switch (token) {
245     case tokenUnrecognized:
246       if (reportNonSgmlCharacter())
247         break;
248       message(ParserMessages::declSubsetCharacter, StringMessageArg(currentToken()));
249       declSubsetRecover(startLevel);
250       break;
251     case tokenEe:
252       if (inputLevel() == specialParseInputLevel()) {
253         // FIXME have separate messages for each type of special parse
254         message(ParserMessages::specialParseEntityEnd);
255       }
256       if (eventsWanted().wantPrologMarkup())
257         eventHandler().entityEnd(new (eventAllocator())
258                                  EntityEndEvent(currentLocation()));
259       if (inputLevel() == 2) {
260         ConstPtr<Entity> e
261           = currentLocation().origin()->asEntityOrigin()->entity();
262         if (!e.isNull()
263             && (e->declType() == Entity::doctype
264                 || e->declType() == Entity::linktype)) {
265           popInputStack();
266           if (!(inDtd
267                 ? parseDoctypeDeclEnd(e->defLocation().origin().isNull())
268                 : parseLinktypeDeclEnd()))
269             ;                   // FIXME recover
270           setPhase(prologPhase);
271           return;
272         }
273       }
274       if (inputLevel() == 1) {
275         if (finalPhase() == declSubsetPhase) {
276           checkDtd(defDtd());
277           endDtd();
278         }
279         else
280           // Give message before popping stack.
281           message(inDtd
282                   ? ParserMessages::documentEndDtdSubset
283                   : ParserMessages::documentEndLpdSubset);
284         popInputStack();
285         allDone();
286       }
287       else
288         popInputStack();
289       return;
290     case tokenDsc:              // end of declaration subset
291       // FIXME what's the right location?
292       if (!referenceDsEntity(currentLocation())) {
293         if (!(inDtd ? parseDoctypeDeclEnd() : parseLinktypeDeclEnd()))
294           ;                     // FIXME recover
295         setPhase(prologPhase);
296       }
297       return;
298     case tokenMdoNameStart:     // named markup declaration
299       if (startMarkup(eventsWanted().wantPrologMarkup(), currentLocation()))
300         currentMarkup()->addDelim(Syntax::dMDO);
301       Syntax::ReservedName name;
302       Boolean result;
303       if (parseDeclarationName(&name,
304                                inDtd && !options().errorAfdr)) {
305         switch (name) {
306         case Syntax::rANY:      // used for <!AFDR
307           result = parseAfdrDecl();
308           break;
309         case Syntax::rELEMENT:
310           if (inDtd)
311             result = parseElementDecl();
312           else {
313             message(ParserMessages::lpdSubsetDeclaration,
314                     StringMessageArg(syntax().reservedName(name)));
315             result = 0;
316           }
317           break;
318         case Syntax::rATTLIST:
319           result = parseAttlistDecl();
320           break;
321         case Syntax::rENTITY:
322           result = parseEntityDecl();
323           break;
324         case Syntax::rNOTATION:
325           result = parseNotationDecl();
326           if (!inDtd && options().errorLpdNotation)
327             message(ParserMessages::lpdSubsetDeclaration,
328                     StringMessageArg(syntax().reservedName(name)));
329           break;
330         case Syntax::rSHORTREF:
331           if (inDtd)
332             result = parseShortrefDecl();
333           else {
334             message(ParserMessages::lpdSubsetDeclaration,
335                     StringMessageArg(syntax().reservedName(name)));
336             result = 0;
337           }
338           break;
339         case Syntax::rUSEMAP:
340           if (inDtd)
341             result = parseUsemapDecl();
342           else {
343             message(ParserMessages::lpdSubsetDeclaration,
344                     StringMessageArg(syntax().reservedName(name)));
345             result = 0;
346           }
347           break;
348         case Syntax::rLINK:
349           if (inDtd) {
350             message(ParserMessages::dtdSubsetDeclaration,
351                     StringMessageArg(syntax().reservedName(name)));
352             result = 0;
353           }
354           else
355             result = parseLinkDecl();
356           break;
357         case Syntax::rIDLINK:
358           if (inDtd) {
359             message(ParserMessages::dtdSubsetDeclaration,
360                     StringMessageArg(syntax().reservedName(name)));
361             result = 0;
362           }
363           else
364             result = parseIdlinkDecl();
365           break;
366         case Syntax::rDOCTYPE:
367         case Syntax::rLINKTYPE:
368         case Syntax::rUSELINK:
369           result = 0;
370           message(inDtd
371                   ? ParserMessages::dtdSubsetDeclaration
372                   : ParserMessages::lpdSubsetDeclaration,
373                   StringMessageArg(syntax().reservedName(name)));
374           break;
375         default:
376           result = 0;
377           message(ParserMessages::noSuchDeclarationType,
378                   StringMessageArg(syntax().reservedName(name)));
379           break;
380         }
381       }
382       else
383         result = 0;
384       if (!result)
385         declSubsetRecover(startLevel);
386       break;
387     case tokenMdoMdc:           // empty comment declaration
388       // empty comment
389       emptyCommentDecl();
390       break;
391     case tokenMdoCom:           // comment declaration
392       if (!parseCommentDecl())
393         declSubsetRecover(startLevel);
394       break;
395     case tokenMdoDso:           // marked section declaration
396       if (!parseMarkedSectionDeclStart())
397         declSubsetRecover(startLevel);
398       break;
399     case tokenMscMdc:
400       handleMarkedSectionEnd();
401       break;
402     case tokenPeroGrpo:         // parameter entity reference with name group
403       message(ParserMessages::peroGrpoProlog);
404       // fall through
405     case tokenPeroNameStart:    // parameter entity reference
406       {
407         ConstPtr<Entity> entity;
408         Ptr<EntityOrigin> origin;
409         if (parseEntityReference(1, token == tokenPeroGrpo, entity, origin)) {
410           if (!entity.isNull())
411             entity->dsReference(*this, origin);
412         }
413         else
414           declSubsetRecover(startLevel);
415       }
416       break;
417     case tokenPio:              // processing instruction
418       if (!parseProcessingInstruction())
419         declSubsetRecover(startLevel);
420       break;
421     case tokenS:                // white space
422       if (eventsWanted().wantPrologMarkup()) {
423         extendS();
424         eventHandler().sSep(new (eventAllocator())
425                             SSepEvent(currentInput()->currentTokenStart(),
426                                       currentInput()->currentTokenLength(),
427                                       currentLocation(),
428                                       1));
429       }
430       break;
431     case tokenIgnoredChar:
432       // from an ignored marked section
433       if (eventsWanted().wantPrologMarkup())
434         eventHandler().ignoredChars(new (eventAllocator())
435                                     IgnoredCharsEvent(currentInput()->currentTokenStart(),
436                                                       currentInput()->currentTokenLength(),
437                                                       currentLocation(),
438                                                       1));
439       break;
440     case tokenRe:
441     case tokenRs:
442     case tokenCroDigit:
443     case tokenCroNameStart:
444     case tokenEroNameStart:
445     case tokenEroGrpo:
446     case tokenChar:
447       // these can occur in a cdata or rcdata marked section
448       message(ParserMessages::dataMarkedSectionDeclSubset);
449       declSubsetRecover(startLevel);
450       break;
451     default:
452       CANNOT_HAPPEN();
453     }
454   } while (eventQueueEmpty());
455 }
456
457 void Parser::declSubsetRecover(unsigned startLevel)
458 {
459   for (;;) {
460     Token token = getToken(currentMode());
461     switch (token) {
462     case tokenUnrecognized:
463       (void)getChar();
464       break;
465     case tokenEe:
466       if (inputLevel() <= startLevel)
467         return;
468       popInputStack();
469       break;
470     case tokenMdoCom:
471     case tokenDsc:
472     case tokenMdoNameStart:
473     case tokenMdoMdc:
474     case tokenMdoDso:
475     case tokenMscMdc:
476     case tokenPio:
477       if (inputLevel() == startLevel) {
478         currentInput()->ungetToken();
479         return;
480       }
481       break;
482     default:
483       break;
484     }
485   }
486 }
487
488 Boolean Parser::lookingAtStartTag(StringC &gi)
489 {
490   // This is harder than might be expected since we may not have compiled
491   // the recognizers for the instance yet.
492   const StringC &stago = instanceSyntax().delimGeneral(Syntax::dSTAGO);
493   for (size_t i = currentInput()->currentTokenLength();
494        i < stago.size();
495        i++)
496     if (currentInput()->tokenChar(messenger()) == InputSource::eE)
497       return 0;
498   StringC delim;
499   getCurrentToken(instanceSyntax().generalSubstTable(), delim);
500   if (delim != stago)
501     return 0;
502   Xchar c = currentInput()->tokenChar(messenger());
503   if (!instanceSyntax().isNameStartCharacter(c))
504     return 0;
505   do {
506     gi += Char(c);
507     c = currentInput()->tokenChar(messenger());
508   } while (instanceSyntax().isNameCharacter(c));
509   return 1;
510 }
511
512 Boolean Parser::parseDeclarationName(Syntax::ReservedName *result,
513                                      Boolean allowAfdr)
514 {
515   currentInput()->discardInitial();
516   extendNameToken(syntax().namelen(), ParserMessages::nameLength);
517   StringC &name = nameBuffer();
518   getCurrentToken(syntax().generalSubstTable(), name);
519   if (!syntax().lookupReservedName(name, result)) {
520     if (allowAfdr && name == sd().execToDoc("AFDR")) {
521       *result = Syntax::rANY;
522       if (currentMarkup())
523         currentMarkup()->addName(currentInput());
524     }
525     else {
526       message(ParserMessages::noSuchDeclarationType, StringMessageArg(name));
527       return 0;
528     }
529   }
530   else if (currentMarkup())
531     currentMarkup()->addReservedName(*result, currentInput());
532   return 1;
533 }
534
535 Boolean Parser::parseElementDecl()
536 {
537   unsigned declInputLevel = inputLevel();
538   Param parm;
539   if (!parseParam(allowNameNameGroup, declInputLevel, parm))
540     return 0;
541   Vector<NameToken> nameVector;
542   if (parm.type == Param::nameGroup)
543     parm.nameTokenVector.swap(nameVector);
544   else {
545     nameVector.resize(1);
546     parm.token.swap(nameVector[0].name);
547   }
548   static AllowedParams
549     allowRankOmissionContent(Param::number,
550                              Param::reservedName + Syntax::rO,
551                              Param::minus,
552                              Param::reservedName + Syntax::rCDATA,
553                              Param::reservedName + Syntax::rRCDATA,
554                              Param::reservedName + Syntax::rEMPTY,
555                              Param::reservedName + Syntax::rANY,
556                              Param::modelGroup);
557   if (!parseParam(allowRankOmissionContent, declInputLevel, parm))
558     return 0;
559   StringC rankSuffix;
560   Vector<ElementType *> elements(nameVector.size());
561   Vector<RankStem *> rankStems;
562   Vector<const RankStem *> constRankStems;
563   size_t i;
564   if (parm.type == Param::number) {
565     parm.token.swap(rankSuffix);
566     rankStems.resize(nameVector.size());
567     constRankStems.resize(nameVector.size());
568     for (i = 0; i < elements.size(); i++) {
569       StringC name(nameVector[i].name);
570       name += rankSuffix;
571       if (name.size() > syntax().namelen()
572           && nameVector[i].name.size() <= syntax().namelen())
573         message(ParserMessages::genericIdentifierLength,
574                 NumberMessageArg(syntax().namelen()));
575       elements[i] = lookupCreateElement(name);
576       rankStems[i] = lookupCreateRankStem(nameVector[i].name);
577       constRankStems[i] = rankStems[i];
578     }
579     static AllowedParams
580       allowOmissionContent(Param::reservedName + Syntax::rO,
581                            Param::minus,
582                            Param::reservedName + Syntax::rCDATA,
583                            Param::reservedName + Syntax::rRCDATA,
584                            Param::reservedName + Syntax::rEMPTY,
585                            Param::reservedName + Syntax::rANY,
586                            Param::modelGroup);
587     Token token = getToken(mdMinusMode);
588     if (token == tokenNameStart)
589       message(ParserMessages::psRequired);
590     currentInput()->ungetToken();
591     if (!parseParam(allowOmissionContent, declInputLevel, parm))
592       return 0;
593   }
594   else {
595     for (i = 0; i < elements.size(); i++)
596       elements[i] = lookupCreateElement(nameVector[i].name);
597   }
598   for (i = 0; i < elements.size(); i++)
599     if (defDtd().lookupRankStem(elements[i]->name()))
600       message(ParserMessages::rankStemGenericIdentifier,
601               StringMessageArg(elements[i]->name()));
602   unsigned char omitFlags = 0;
603   if (parm.type == Param::minus
604       || parm.type == Param::reservedName + Syntax::rO) {
605     omitFlags |= ElementDefinition::omitSpec;
606     if (parm.type != Param::minus)
607       omitFlags |= ElementDefinition::omitStart;
608     static AllowedParams allowOmission(Param::reservedName + Syntax::rO,
609                                        Param::minus);
610     if (!parseParam(allowOmission, declInputLevel, parm))
611       return 0;
612     if (parm.type != Param::minus)
613       omitFlags |= ElementDefinition::omitEnd;
614     static AllowedParams allowContent(Param::reservedName + Syntax::rCDATA,
615                                       Param::reservedName + Syntax::rRCDATA,
616                                       Param::reservedName + Syntax::rEMPTY,
617                                       Param::reservedName + Syntax::rANY,
618                                       Param::modelGroup);
619     if (!parseParam(allowContent, declInputLevel, parm))
620       return 0;
621   }
622   else {
623     if (sd().omittag())
624       message(ParserMessages::missingTagMinimization);
625   }
626   Ptr<ElementDefinition> def;
627   switch (parm.type) {
628   case Param::reservedName + Syntax::rCDATA:
629     def = new ElementDefinition(markupLocation(),
630                                 defDtd().allocElementDefinitionIndex(),
631                                 omitFlags,
632                                 ElementDefinition::cdata);
633     if (!parseParam(allowMdc, declInputLevel, parm))
634       return 0;
635     break;
636   case Param::reservedName + Syntax::rRCDATA:
637     def = new ElementDefinition(markupLocation(),
638                                 defDtd().allocElementDefinitionIndex(),
639                                 omitFlags,
640                                 ElementDefinition::rcdata);
641     if (!parseParam(allowMdc, declInputLevel, parm))
642       return 0;
643     break;
644   case Param::reservedName + Syntax::rEMPTY:
645     def = new ElementDefinition(markupLocation(),
646                                 defDtd().allocElementDefinitionIndex(),
647                                 omitFlags,
648                                 ElementDefinition::empty);
649     if ((omitFlags & ElementDefinition::omitSpec)
650         && !(omitFlags & ElementDefinition::omitEnd)
651         && options().warnShould)
652       message(ParserMessages::emptyOmitEndTag);
653     if (!parseParam(allowMdc, declInputLevel, parm))
654       return 0;
655     break;
656   case Param::reservedName + Syntax::rANY:
657     def = new ElementDefinition(markupLocation(),
658                                 defDtd().allocElementDefinitionIndex(),
659                                 omitFlags,
660                                 ElementDefinition::any);
661     if (!parseExceptions(declInputLevel, def))
662       return 0;
663     break;
664   case Param::modelGroup:
665     {
666       unsigned long cnt = parm.modelGroupPtr->grpgtcnt();
667       // The outermost model group isn't formally a content token.
668       if (cnt - 1 > syntax().grpgtcnt())
669         message(ParserMessages::grpgtcnt, NumberMessageArg(syntax().grpgtcnt()));
670       Owner<CompiledModelGroup>
671         modelGroup(new CompiledModelGroup(parm.modelGroupPtr));
672       Vector<ContentModelAmbiguity> ambiguities;
673       Boolean pcdataUnreachable;
674       modelGroup->compile(currentDtd().nElementTypeIndex(), ambiguities,
675                           pcdataUnreachable);
676       if (pcdataUnreachable && options().warnMixedContent)
677         message(ParserMessages::pcdataUnreachable);
678       for (i = 0; i < ambiguities.size(); i++) {
679         const ContentModelAmbiguity &a = ambiguities[i];
680         reportAmbiguity(a.from, a.to1, a.to2, a.andDepth);
681       }
682       def = new ElementDefinition(markupLocation(),
683                                   defDtd().allocElementDefinitionIndex(),
684                                   omitFlags,
685                                   ElementDefinition::modelGroup,
686                                   modelGroup);
687       if (!parseExceptions(declInputLevel, def))
688         return 0;
689     }
690     break;
691   }
692   if (rankSuffix.size() > 0)
693     def->setRank(rankSuffix, constRankStems);
694   ConstPtr<ElementDefinition> constDef(def);
695   for (i = 0; i < elements.size(); i++) {
696     if (elements[i]->definition() != 0)
697       message(ParserMessages::duplicateElementDefinition,
698               StringMessageArg(elements[i]->name()));
699     else {
700       elements[i]->setElementDefinition(constDef, i);
701       if (!elements[i]->attributeDef().isNull())
702         checkElementAttribute(elements[i]);
703     }
704     if (rankStems.size() > 0)
705       rankStems[i]->addDefinition(constDef);
706   }
707   if (currentMarkup()) {
708     Vector<const ElementType *> v(elements.size());
709     for (i = 0; i < elements.size(); i++)
710       v[i] = elements[i];
711     eventHandler().elementDecl(new (eventAllocator())
712                                ElementDeclEvent(v, currentDtdPointer(),
713                                                 markupLocation(),
714                                                 currentMarkup()));
715   }
716   return 1;
717 }
718
719 void Parser::reportAmbiguity(const LeafContentToken *from,
720                              const LeafContentToken *to1,
721                              const LeafContentToken *to2,
722                              unsigned ambigAndDepth)
723 {
724   StringC toName;
725   const ElementType *toType = to1->elementType();
726   if (toType)
727     toName = toType->name();
728   else {
729     toName = syntax().delimGeneral(Syntax::dRNI);
730     toName += syntax().reservedName(Syntax::rPCDATA);
731   }
732   unsigned to1Index = to1->typeIndex() + 1;
733   unsigned to2Index = to2->typeIndex() + 1;
734   if (from->isInitial())
735     message(ParserMessages::ambiguousModelInitial,
736             StringMessageArg(toName),
737             OrdinalMessageArg(to1Index),
738             OrdinalMessageArg(to2Index));
739   else {
740     StringC fromName;
741     const ElementType *fromType = from->elementType();
742     if (fromType)
743       fromName = fromType->name();
744     else {
745       fromName = syntax().delimGeneral(Syntax::dRNI);
746       fromName += syntax().reservedName(Syntax::rPCDATA);
747     }
748     unsigned fromIndex = from->typeIndex() + 1;
749     unsigned andMatches = from->andDepth() - ambigAndDepth;
750     if (andMatches == 0)
751       message(ParserMessages::ambiguousModel,
752               StringMessageArg(fromName),
753               OrdinalMessageArg(fromIndex),
754               StringMessageArg(toName),
755               OrdinalMessageArg(to1Index),
756               OrdinalMessageArg(to2Index));
757     else if (andMatches == 1)
758       message(ParserMessages::ambiguousModelSingleAnd,
759               StringMessageArg(fromName),
760               OrdinalMessageArg(fromIndex),
761               StringMessageArg(toName),
762               OrdinalMessageArg(to1Index),
763               OrdinalMessageArg(to2Index));
764     else
765       message(ParserMessages::ambiguousModelMultipleAnd,
766               StringMessageArg(fromName),
767               OrdinalMessageArg(fromIndex),
768               NumberMessageArg(andMatches),
769               StringMessageArg(toName),
770               OrdinalMessageArg(to1Index),
771               OrdinalMessageArg(to2Index));
772   }
773 }
774
775
776 // Check the compatibility of the attribute definition with
777 // the element definition.
778
779 void Parser::checkElementAttribute(const ElementType *e, size_t checkFrom)
780 {
781   const AttributeDefinitionList *attDef = e->attributeDef().pointer();
782   Boolean conref = 0;
783   ASSERT(e != 0);
784   const ElementDefinition *edef = e->definition();
785   ASSERT(edef != 0);
786   ASSERT(attDef != 0);
787   size_t attDefLength = attDef->size();
788   for (size_t i = checkFrom; i < attDefLength; i++) {
789     const AttributeDefinition *p = attDef->def(i);
790     if (p->isConref())
791       conref = 1;
792     if (p->isNotation()
793         && edef->declaredContent() == ElementDefinition::empty)
794       message(ParserMessages::notationEmpty, StringMessageArg(e->name()));
795   }
796   if (conref) {
797 #if 0
798     if (edef->omittedTagSpec() && !edef->canOmitEndTag()
799         && options().warnShould)
800       message(ParserMessages::conrefOmitEndTag, StringMessageArg(e->name()));
801 #endif
802     if (edef->declaredContent() == ElementDefinition::empty)
803       message(ParserMessages::conrefEmpty, StringMessageArg(e->name()));
804   }
805 }
806
807 ElementType *Parser::lookupCreateElement(const StringC &name)
808 {
809   ElementType *e = defDtd().lookupElementType(name);
810   if (!e) {
811     if (haveDefLpd()) 
812       message(ParserMessages::noSuchSourceElement, StringMessageArg(name));
813     else {
814       e = new ElementType(name, defDtd().nElementTypeIndex());
815       defDtd().insertElementType(e);
816     }
817   }
818   return e;
819 }
820
821 RankStem *Parser::lookupCreateRankStem(const StringC &name)
822 {
823   RankStem *r = defDtd().lookupRankStem(name);
824   if (!r) {
825     r = new RankStem(name, defDtd().nRankStem());
826     defDtd().insertRankStem(r);
827     const ElementType *e = defDtd().lookupElementType(name);
828     if (e && e->definition() != 0)
829       message(ParserMessages::rankStemGenericIdentifier, StringMessageArg(name));
830   }
831   return r;
832 }
833
834 Boolean Parser::parseExceptions(unsigned declInputLevel,
835                                 Ptr<ElementDefinition> &def)
836 {
837   Param parm;
838   static AllowedParams
839     allowExceptionsMdc(Param::mdc, Param::exclusions, Param::inclusions);
840   if (!parseParam(allowExceptionsMdc, declInputLevel, parm))
841     return 0;
842   if (parm.type == Param::exclusions) {
843     def->setExclusions(parm.elementVector);
844     static AllowedParams allowInclusionsMdc(Param::mdc, Param::inclusions);
845     if (!parseParam(allowInclusionsMdc, declInputLevel, parm))
846       return 0;
847   }
848   if (parm.type == Param::inclusions) {
849     def->setInclusions(parm.elementVector);
850     size_t nI = def->nInclusions();
851     size_t nE = def->nExclusions();
852     if (nE) {
853       for (size_t i = 0; i < nI; i++) {
854         const ElementType *e = def->inclusion(i);
855         for (size_t j = 0; j < nE; j++)
856           if (def->exclusion(j) == e)
857             message(ParserMessages::excludeIncludeSame,
858                     StringMessageArg(e->name()));
859       }
860     }
861     if (!parseParam(allowMdc, declInputLevel, parm))
862       return 0;
863   }
864   return 1;
865 }
866
867 Boolean Parser::parseAttlistDecl()
868 {
869   unsigned declInputLevel = inputLevel();
870   Param parm;
871   size_t attcnt = 0;
872   size_t idIndex = size_t(-1);
873   size_t notationIndex = size_t(-1);
874   Boolean anyCurrent = 0;
875   
876   Boolean isNotation;
877   Vector<Attributed *> attributed;
878   if (!parseAttributed(declInputLevel, parm, attributed, isNotation))
879     return 0;
880   Vector<CopyOwner<AttributeDefinition> > defs;
881   if (!parseParam(allowName, declInputLevel, parm))
882     return 0;
883   do {
884     StringC attributeName;
885     parm.token.swap(attributeName);
886     attcnt++;
887     Boolean duplicate = 0;
888     size_t i;
889     for (i = 0; i < defs.size(); i++)
890       if (defs[i]->name() == attributeName) {
891         message(ParserMessages::duplicateAttributeDef,
892                 StringMessageArg(attributeName));
893         duplicate = 1;
894         break;
895       }
896     Owner<DeclaredValue> declaredValue;
897     if (!parseDeclaredValue(declInputLevel, isNotation, parm, declaredValue))
898       return 0;
899     if (!duplicate) {
900       if (declaredValue->isId()) {
901         if (idIndex != size_t(-1))
902           message(ParserMessages::multipleIdAttributes,
903                   StringMessageArg(defs[idIndex]->name()));
904         idIndex = defs.size();
905       }
906       else if (declaredValue->isNotation()) {
907         if (notationIndex != size_t(-1))
908           message(ParserMessages::multipleNotationAttributes,
909                   StringMessageArg(defs[notationIndex]->name()));
910         notationIndex = defs.size();
911       }
912     }
913     const Vector<StringC> *tokensPtr = declaredValue->getTokens();
914     if (tokensPtr) {
915       size_t nTokens = tokensPtr->size();
916       Vector<StringC>::const_iterator tokens = tokensPtr->begin();
917       for (i = 0; i < nTokens; i++) {
918         for (size_t j = 0; j < defs.size(); j++)
919           if (defs[j]->containsToken(tokens[i])) {
920             message(ParserMessages::duplicateAttributeToken,
921                     StringMessageArg(tokens[i]));
922             break;
923           }
924       }
925       attcnt += nTokens;
926     }
927     Owner<AttributeDefinition> def;
928     if (!parseDefaultValue(declInputLevel, isNotation, parm, attributeName,
929                            declaredValue, def, anyCurrent))
930       return 0;
931     if (haveDefLpd() && defLpd().type() == Lpd::simpleLink && !def->isFixed())
932       message(ParserMessages::simpleLinkFixedAttribute);
933     if (!duplicate) {
934       defs.resize(defs.size() + 1);
935       defs.back() = def.extract();
936     }
937     static AllowedParams allowNameMdc(Param::name, Param::mdc);
938     if (!parseParam(allowNameMdc, declInputLevel, parm))
939       return 0;
940   } while (parm.type != Param::mdc);
941   if (attcnt > syntax().attcnt())
942     message(ParserMessages::attcnt,
943             NumberMessageArg(attcnt),
944             NumberMessageArg(syntax().attcnt()));
945   if (haveDefLpd() && !isNotation) {
946     if (defLpd().type() == Lpd::simpleLink) {
947       for (size_t i = 0; i < attributed.size(); i++) {
948         const ElementType *e = (const ElementType *)attributed[i];
949         if (e) {
950           if (e->name() == defLpd().sourceDtd()->name()) {
951             SimpleLpd &lpd = (SimpleLpd &)defLpd();
952             if (lpd.attributeDef().isNull())
953               lpd.setAttributeDef(new AttributeDefinitionList(defs, 0));
954             else
955               message(ParserMessages::duplicateAttlistElement,
956                       StringMessageArg(e->name()));
957           }
958           else
959             message(ParserMessages::simpleLinkAttlistElement,
960                     StringMessageArg(e->name()));
961         }
962       }
963     }
964     else {
965       Ptr<AttributeDefinitionList>
966         adl(new AttributeDefinitionList(defs,
967                                         defComplexLpd()
968                                         .allocAttributeDefinitionListIndex()));
969       for (size_t i = 0; i < attributed.size(); i++) {
970         const ElementType *e = (const ElementType *)attributed[i];
971         if (e) {
972           if (defComplexLpd().attributeDef(e).isNull())
973             defComplexLpd().setAttributeDef(e, adl);
974           else
975             message(ParserMessages::duplicateAttlistElement,
976                     StringMessageArg(e->name()));
977         }
978       }
979     }
980   }
981   else {
982     Ptr<AttributeDefinitionList>
983       adl(new AttributeDefinitionList(defs,
984                                       defDtd()
985                                       .allocAttributeDefinitionListIndex(),
986                                       anyCurrent,
987                                       idIndex,
988                                       notationIndex));
989     for (size_t i = 0; i < attributed.size(); i++) {
990       if (attributed[i]->attributeDef().isNull()) {
991         attributed[i]->setAttributeDef(adl);
992         if (!isNotation) {
993           ElementType *e = (ElementType *)attributed[i];
994           if (e->definition() != 0)
995             checkElementAttribute(e);
996         }
997       }
998       else if (options().errorAfdr) {
999         if (!hadAfdrDecl()) {
1000           message(ParserMessages::missingAfdrDecl);
1001           setHadAfdrDecl();
1002         }
1003         if (isNotation)
1004           message(ParserMessages::duplicateAttlistNotation,
1005                   StringMessageArg(((Notation *)attributed[i])->name()));
1006         else
1007           message(ParserMessages::duplicateAttlistElement,
1008                   StringMessageArg(((ElementType *)attributed[i])->name()));
1009       }
1010       else {
1011         AttributeDefinitionList *curAdl;
1012         {
1013           // Use block to make sure temporary gets destroyed.
1014           curAdl = attributed[i]->attributeDef().pointer();
1015         }
1016         size_t oldSize = curAdl->size();
1017         if (curAdl->count() != 1) {
1018           Vector<CopyOwner<AttributeDefinition> > copy(oldSize);
1019           for (size_t j = 0; j < oldSize; j++)
1020             copy[j] = curAdl->def(j)->copy();
1021           Ptr<AttributeDefinitionList> adlCopy
1022             = new AttributeDefinitionList(copy,
1023                                           defDtd().allocAttributeDefinitionListIndex(),
1024                                           curAdl->anyCurrent(),
1025                                           curAdl->idIndex(),
1026                                           curAdl->notationIndex());
1027           attributed[i]->setAttributeDef(adlCopy);
1028           curAdl = adlCopy.pointer();
1029         }
1030         // FIXME check for multiple ID and NOTATION attributes
1031         for (size_t j = 0; j < adl->size(); j++) {
1032           unsigned tem;
1033           if (!curAdl->attributeIndex(adl->def(j)->name(), tem))
1034             curAdl->append(adl->def(j)->copy());
1035         }
1036         if (!isNotation) {
1037           ElementType *e = (ElementType *)attributed[i];
1038           if (e->definition() != 0)
1039             checkElementAttribute(e, oldSize);
1040         }
1041       }
1042     }
1043   }
1044   if (currentMarkup()) {
1045     if (isNotation) {
1046       Vector<ConstPtr<Notation> > v(attributed.size());
1047       for (size_t i = 0; i < attributed.size(); i++)
1048         v[i] = (Notation *)attributed[i];
1049       eventHandler()
1050         .attlistNotationDecl(new (eventAllocator())
1051                              AttlistNotationDeclEvent(v,
1052                                                       markupLocation(),
1053                                                       currentMarkup()));
1054     }
1055     else {
1056       Vector<const ElementType *> v(attributed.size());
1057       for (size_t i = 0; i < attributed.size(); i++)
1058         v[i] = (ElementType *)attributed[i];
1059       if (haveDefLpd())
1060         eventHandler()
1061           .linkAttlistDecl(new (eventAllocator())
1062                            LinkAttlistDeclEvent(v,
1063                                                 defLpdPointer(),
1064                                                 markupLocation(),
1065                                                 currentMarkup()));
1066       else
1067         eventHandler().attlistDecl(new (eventAllocator())
1068                                    AttlistDeclEvent(v,
1069                                                     currentDtdPointer(),
1070                                                     markupLocation(),
1071                                                     currentMarkup()));
1072     }
1073   }
1074   if (isNotation) {
1075     Dtd::EntityIter entityIter(defDtd().generalEntityIter());
1076     for (;;) {
1077       Ptr<Entity> entity(entityIter.next());
1078       if (entity.isNull())
1079         break;
1080       const ExternalDataEntity *external = entity->asExternalDataEntity();
1081       if (external) {
1082         const Notation *entityNotation = external->notation();
1083         for (size_t  i = 0; i < attributed.size(); i++)
1084           if ((Notation *)attributed[i] == entityNotation) {
1085             AttributeList attributes(entityNotation->attributeDef());
1086             attributes.finish(*this);
1087             ((ExternalDataEntity *)entity.pointer())
1088               ->setNotation((Notation *)attributed[i], attributes);
1089           }
1090       }
1091     }
1092   }
1093   return 1;
1094 }
1095
1096
1097 Boolean Parser::parseAttributed(unsigned declInputLevel,
1098                                 Param &parm,
1099                                 Vector<Attributed *> &attributed,
1100                                 Boolean &isNotation)
1101 {
1102   // There's a hack in getIndicatedReservedName allows #ALL as #ANY.
1103   static AllowedParams
1104     allowNameGroupNotation(Param::name,
1105                            Param::nameGroup,
1106                            Param::indicatedReservedName + Syntax::rNOTATION);
1107   static AllowedParams
1108     allowNameGroupNotationAll(Param::name,
1109                               Param::nameGroup,
1110                               Param::indicatedReservedName
1111                               + Syntax::rNOTATION,
1112                               Param::indicatedReservedName
1113                               + Syntax::rANY);
1114   if (!parseParam(options().errorAfdr || haveDefLpd()
1115                   ? allowNameGroupNotation
1116                   : allowNameGroupNotationAll,
1117                   declInputLevel, parm))
1118     return 0;
1119   if (parm.type == Param::indicatedReservedName + Syntax::rNOTATION) {
1120     isNotation = 1;
1121     static AllowedParams
1122       allowNameGroupAll(Param::name,
1123                         Param::nameGroup,
1124                         Param::indicatedReservedName + Syntax::rANY);
1125     if (!parseParam(options().errorAfdr || haveDefLpd()
1126                     ? allowNameNameGroup
1127                     : allowNameGroupAll,
1128                     declInputLevel, parm))
1129       return 0;
1130     if (parm.type == Param::nameGroup) {
1131       attributed.resize(parm.nameTokenVector.size());
1132       for (size_t i = 0; i < attributed.size(); i++)
1133         attributed[i] = lookupCreateNotation(parm.nameTokenVector[i].name);
1134     }
1135     else {
1136       if (parm.type != Param::name && !hadAfdrDecl()) {
1137         message(ParserMessages::missingAfdrDecl);
1138         setHadAfdrDecl();
1139       }
1140       attributed.resize(1);
1141       attributed[0]
1142         = lookupCreateNotation(parm.type == Param::name
1143                                ? parm.token
1144                                : syntax().rniReservedName(Syntax::rANY));
1145     }
1146   }
1147   else {
1148     isNotation = 0;
1149     if (parm.type == Param::nameGroup) {
1150       attributed.resize(parm.nameTokenVector.size());
1151       for (size_t i = 0; i < attributed.size(); i++)
1152         attributed[i] = lookupCreateElement(parm.nameTokenVector[i].name);
1153     }
1154     else {
1155       if (parm.type != Param::name && !hadAfdrDecl()) {
1156         message(ParserMessages::missingAfdrDecl);
1157         setHadAfdrDecl();
1158       }
1159       attributed.resize(1);
1160       attributed[0]
1161         = lookupCreateElement(parm.type == Param::name
1162                               ? parm.token
1163                               : syntax().rniReservedName(Syntax::rANY));
1164     }
1165   }
1166   return 1;
1167 }
1168
1169 Boolean Parser::parseDeclaredValue(unsigned declInputLevel,
1170                                    Boolean isNotation,
1171                                    Param &parm,
1172                                    Owner<DeclaredValue> &declaredValue)
1173 {
1174   static Param::Type declaredValues[] = {
1175     Param::reservedName + Syntax::rCDATA,
1176     Param::reservedName + Syntax::rENTITY,
1177     Param::reservedName + Syntax::rENTITIES,
1178     Param::reservedName + Syntax::rID,
1179     Param::reservedName + Syntax::rIDREF,
1180     Param::reservedName + Syntax::rIDREFS,
1181     Param::reservedName + Syntax::rNAME,
1182     Param::reservedName + Syntax::rNAMES,
1183     Param::reservedName + Syntax::rNMTOKEN,
1184     Param::reservedName + Syntax::rNMTOKENS,
1185     Param::reservedName + Syntax::rNUMBER,
1186     Param::reservedName + Syntax::rNUMBERS,
1187     Param::reservedName + Syntax::rNUTOKEN,
1188     Param::reservedName + Syntax::rNUTOKENS,
1189     Param::reservedName + Syntax::rNOTATION,
1190     Param::nameTokenGroup
1191     };
1192   static AllowedParams allowDeclaredValue(declaredValues,
1193                                           SIZEOF(declaredValues));
1194   if (!parseParam(allowDeclaredValue, declInputLevel, parm))
1195     return 0;
1196   enum { asDataAttribute = 01, asLinkAttribute = 02 };
1197   unsigned allowedFlags = asDataAttribute|asLinkAttribute;
1198   switch (parm.type) {
1199   case Param::reservedName + Syntax::rCDATA:
1200     declaredValue = new CdataDeclaredValue;
1201     break;
1202   case Param::reservedName + Syntax::rENTITY:
1203     declaredValue = new EntityDeclaredValue(0);
1204     allowedFlags = asLinkAttribute;
1205     break;
1206   case Param::reservedName + Syntax::rENTITIES:
1207     declaredValue = new EntityDeclaredValue(1);
1208     allowedFlags = asLinkAttribute;
1209     break;
1210   case Param::reservedName + Syntax::rID:
1211     declaredValue = new IdDeclaredValue;
1212     allowedFlags = 0;
1213     break;
1214   case Param::reservedName + Syntax::rIDREF:
1215     declaredValue = new IdrefDeclaredValue(0);
1216     allowedFlags = 0;
1217     break;
1218   case Param::reservedName + Syntax::rIDREFS:
1219     declaredValue = new IdrefDeclaredValue(1);
1220     allowedFlags = 0;
1221     break;
1222   case Param::reservedName + Syntax::rNAME:
1223     declaredValue
1224       = new TokenizedDeclaredValue(TokenizedDeclaredValue::name, 0);
1225     break;
1226   case Param::reservedName + Syntax::rNAMES:
1227     declaredValue
1228       = new TokenizedDeclaredValue(TokenizedDeclaredValue::name, 1);
1229     break;
1230   case Param::reservedName + Syntax::rNMTOKEN:
1231     declaredValue
1232       = new TokenizedDeclaredValue(TokenizedDeclaredValue::nameToken, 0);
1233     break;
1234   case Param::reservedName + Syntax::rNMTOKENS:
1235     declaredValue
1236       = new TokenizedDeclaredValue(TokenizedDeclaredValue::nameToken, 1);
1237     break;
1238   case Param::reservedName + Syntax::rNUMBER:
1239     declaredValue
1240       = new TokenizedDeclaredValue(TokenizedDeclaredValue::number, 0);
1241     break;
1242   case Param::reservedName + Syntax::rNUMBERS:
1243     declaredValue
1244       = new TokenizedDeclaredValue(TokenizedDeclaredValue::number, 1);
1245     break;
1246   case Param::reservedName + Syntax::rNUTOKEN:
1247     declaredValue
1248       = new TokenizedDeclaredValue(TokenizedDeclaredValue::numberToken, 0);
1249     break;
1250   case Param::reservedName + Syntax::rNUTOKENS:
1251     declaredValue
1252       = new TokenizedDeclaredValue(TokenizedDeclaredValue::numberToken, 1);
1253     break;
1254   case Param::reservedName + Syntax::rNOTATION:
1255     {
1256       static AllowedParams allowNameGroup(Param::nameGroup);
1257       if (!parseParam(allowNameGroup, declInputLevel, parm))
1258         return 0;
1259       Vector<StringC> group(parm.nameTokenVector.size());
1260       for (size_t i = 0; i < group.size(); i++)
1261         parm.nameTokenVector[i].name.swap(group[i]);
1262       declaredValue = new NotationDeclaredValue(group);
1263       allowedFlags = 0;
1264     }
1265     break;
1266   case Param::nameTokenGroup:
1267     {
1268       Vector<StringC> group(parm.nameTokenVector.size());
1269       for (size_t i = 0; i < group.size(); i++)
1270         parm.nameTokenVector[i].name.swap(group[i]);
1271       declaredValue = new NameTokenGroupDeclaredValue(group);
1272     }
1273     break;
1274   default:
1275     CANNOT_HAPPEN();
1276   }
1277   if (isNotation) {
1278     if (!(allowedFlags & asDataAttribute))
1279       message(ParserMessages::dataAttributeDeclaredValue);
1280   }
1281   else if (haveDefLpd() && !isNotation && !(allowedFlags & asLinkAttribute))
1282     message(ParserMessages::linkAttributeDeclaredValue);
1283   return 1;
1284 }
1285
1286 Boolean Parser::parseDefaultValue(unsigned declInputLevel,
1287                                   Boolean isNotation,
1288                                   Param &parm,
1289                                   const StringC &attributeName,
1290                                   Owner<DeclaredValue> &declaredValue,
1291                                   Owner<AttributeDefinition> &def,
1292                                   Boolean &anyCurrent)
1293 {
1294   // default value
1295   static AllowedParams
1296     allowDefaultValue(Param::indicatedReservedName + Syntax::rFIXED,
1297                       Param::indicatedReservedName + Syntax::rREQUIRED,
1298                       Param::indicatedReservedName + Syntax::rCURRENT,
1299                       Param::indicatedReservedName + Syntax::rCONREF,
1300                       Param::indicatedReservedName + Syntax::rIMPLIED,
1301                       Param::attributeValue,
1302                       Param::attributeValueLiteral);
1303   static AllowedParams
1304     allowTokenDefaultValue(Param::indicatedReservedName + Syntax::rFIXED,
1305                       Param::indicatedReservedName + Syntax::rREQUIRED,
1306                       Param::indicatedReservedName + Syntax::rCURRENT,
1307                       Param::indicatedReservedName + Syntax::rCONREF,
1308                       Param::indicatedReservedName + Syntax::rIMPLIED,
1309                       Param::attributeValue,
1310                       Param::tokenizedAttributeValueLiteral);
1311   if (!parseParam(declaredValue->tokenized()
1312                   ? allowTokenDefaultValue
1313                   : allowDefaultValue, declInputLevel, parm))
1314     return 0;
1315   switch (parm.type) {
1316   case Param::indicatedReservedName + Syntax::rFIXED:
1317     {
1318       static AllowedParams allowValue(Param::attributeValue,
1319                                       Param::attributeValueLiteral);
1320       static AllowedParams
1321         allowTokenValue(Param::attributeValue,
1322                         Param::tokenizedAttributeValueLiteral);
1323       if (!parseParam(declaredValue->tokenized()
1324                       ? allowTokenValue
1325                       : allowValue, declInputLevel, parm))
1326         return 0;
1327       unsigned specLength = 0;
1328       AttributeValue *value = declaredValue->makeValue(parm.literalText,
1329                                                        *this,
1330                                                        attributeName,
1331                                                        specLength);
1332       if (declaredValue->isId())
1333         message(ParserMessages::idDeclaredValue);
1334       def = new FixedAttributeDefinition(attributeName,
1335                                          declaredValue.extract(),
1336                                          value);
1337     }
1338     break;
1339   case Param::attributeValue:
1340   case Param::attributeValueLiteral:
1341   case Param::tokenizedAttributeValueLiteral:
1342     {
1343       unsigned specLength = 0;
1344       AttributeValue *value = declaredValue->makeValue(parm.literalText,
1345                                                        *this,
1346                                                        attributeName,
1347                                                        specLength);
1348       if (declaredValue->isId())
1349         message(ParserMessages::idDeclaredValue);
1350       def = new DefaultAttributeDefinition(attributeName,
1351                                            declaredValue.extract(),
1352                                            value);
1353     }
1354     break;
1355   case Param::indicatedReservedName + Syntax::rREQUIRED:
1356     def = new RequiredAttributeDefinition(attributeName,
1357                                           declaredValue.extract());
1358     break;
1359   case Param::indicatedReservedName + Syntax::rCURRENT:
1360     anyCurrent = 1;            
1361     if (declaredValue->isId())
1362       message(ParserMessages::idDeclaredValue);
1363     def = new CurrentAttributeDefinition(attributeName,
1364                                          declaredValue.extract(),
1365                                          defDtd().allocCurrentAttributeIndex());
1366     if (isNotation)
1367       message(ParserMessages::dataAttributeDefaultValue);
1368     else if (haveDefLpd())
1369       message(ParserMessages::linkAttributeDefaultValue);
1370     break;
1371   case Param::indicatedReservedName + Syntax::rCONREF:
1372     if (declaredValue->isId())
1373       message(ParserMessages::idDeclaredValue);
1374     def = new ConrefAttributeDefinition(attributeName,
1375                                         declaredValue.extract());
1376     if (isNotation)
1377       message(ParserMessages::dataAttributeDefaultValue);
1378     else if (haveDefLpd())
1379       message(ParserMessages::linkAttributeDefaultValue);
1380     break;
1381   case Param::indicatedReservedName + Syntax::rIMPLIED:
1382     def = new ImpliedAttributeDefinition(attributeName,
1383                                          declaredValue.extract());
1384     break;
1385   default:
1386     CANNOT_HAPPEN();
1387   }
1388   return 1;
1389 }
1390
1391 // parm contains either system or public
1392
1393 Boolean Parser::parseExternalId(const AllowedParams &sysidAllow,
1394                                 const AllowedParams &endAllow,
1395                                 unsigned declInputLevel,
1396                                 Param &parm,
1397                                 ExternalId &id)
1398 {
1399   id.setLocation(currentLocation());
1400   if (parm.type == Param::reservedName + Syntax::rPUBLIC) {
1401     static AllowedParams allowMinimumLiteral(Param::minimumLiteral);
1402     if (!parseParam(allowMinimumLiteral, declInputLevel, parm))
1403       return 0;
1404     const MessageType1 *err;
1405     if (!id.setPublic(parm.literalText, sd().docCharset(), syntax().space(),
1406                       err)
1407         && sd().formal())
1408       message(*err,
1409               StringMessageArg(*id.publicIdString()));
1410   }
1411   if (!parseParam(sysidAllow, declInputLevel, parm))
1412     return 0;
1413   if (parm.type == Param::systemIdentifier) {
1414     id.setSystem(parm.literalText);
1415     if (!parseParam(endAllow, declInputLevel, parm))
1416       return 0;
1417   }
1418   return 1;
1419 }
1420
1421 Boolean Parser::parseNotationDecl()
1422 {
1423   unsigned declInputLevel = inputLevel();
1424   Param parm;
1425   if (!parseParam(allowName, declInputLevel, parm))
1426     return 0;
1427   Notation *nt = lookupCreateNotation(parm.token);
1428   if (nt->defined())
1429     message(ParserMessages::duplicateNotationDeclaration,
1430             StringMessageArg(parm.token));
1431   static AllowedParams
1432     allowPublicSystem(Param::reservedName + Syntax::rPUBLIC,
1433                       Param::reservedName + Syntax::rSYSTEM);
1434   if (!parseParam(allowPublicSystem, declInputLevel, parm))
1435     return 0;
1436
1437
1438   static AllowedParams allowSystemIdentifierMdc(Param::systemIdentifier,
1439                                                 Param::mdc);
1440
1441   ExternalId id;
1442   if (!parseExternalId(allowSystemIdentifierMdc, allowMdc,
1443                        declInputLevel, parm, id))
1444     return 0;
1445   if (sd().formal()) {
1446     PublicId::TextClass textClass;
1447     const PublicId *publicId = id.publicId();
1448     if (publicId
1449         && publicId->getTextClass(textClass)
1450         && textClass != PublicId::NOTATION)
1451       message(ParserMessages::notationIdentifierTextClass);
1452   }
1453   if (!nt->defined()) {
1454     nt->setExternalId(id, markupLocation());
1455     nt->generateSystemId(*this);
1456     if (currentMarkup())
1457       eventHandler().notationDecl(new (eventAllocator())
1458                                   NotationDeclEvent(nt, markupLocation(),
1459                                                     currentMarkup()));
1460   }
1461   return 1;
1462 }
1463
1464 Boolean Parser::parseEntityDecl()
1465 {
1466   unsigned declInputLevel = inputLevel();
1467   Param parm;
1468
1469   static AllowedParams
1470     allowEntityNamePero(Param::entityName,
1471                         Param::indicatedReservedName + Syntax::rDEFAULT,
1472                         Param::pero);
1473
1474   if (!parseParam(allowEntityNamePero, declInputLevel, parm))
1475     return 0;
1476
1477   Entity::DeclType declType;
1478   StringC name;                 // empty for default entity
1479   if (parm.type == Param::pero) {
1480     declType = Entity::parameterEntity;
1481     static AllowedParams allowParamEntityName(Param::paramEntityName);
1482     if (!parseParam(allowParamEntityName, declInputLevel, parm))
1483       return 0;
1484     parm.token.swap(name);
1485   }
1486   else {
1487     declType = Entity::generalEntity;
1488     if (parm.type == Param::entityName)
1489       parm.token.swap(name);
1490   }
1491   static AllowedParams
1492     allowEntityTextType(Param::paramLiteral,
1493                         Param::reservedName + Syntax::rCDATA,
1494                         Param::reservedName + Syntax::rSDATA,
1495                         Param::reservedName + Syntax::rPI,
1496                         Param::reservedName + Syntax::rSTARTTAG,
1497                         Param::reservedName + Syntax::rENDTAG,
1498                         Param::reservedName + Syntax::rMS,
1499                         Param::reservedName + Syntax::rMD,
1500                         Param::reservedName + Syntax::rSYSTEM,
1501                         Param::reservedName + Syntax::rPUBLIC);
1502
1503   if (!parseParam(allowEntityTextType, declInputLevel, parm))
1504     return 0;
1505   Location typeLocation(currentLocation());
1506   Entity::DataType dataType = Entity::sgmlText;
1507   InternalTextEntity::Bracketed bracketed = InternalTextEntity::none;
1508   switch (parm.type) {
1509   case Param::reservedName + Syntax::rSYSTEM:
1510   case Param::reservedName + Syntax::rPUBLIC:
1511     return parseExternalEntity(name, declType, declInputLevel, parm);
1512   case Param::reservedName + Syntax::rCDATA:
1513     dataType = Entity::cdata;
1514     break;
1515   case Param::reservedName + Syntax::rSDATA:
1516     dataType = Entity::sdata;
1517     break;
1518   case Param::reservedName + Syntax::rPI:
1519     dataType = Entity::pi;
1520     break;
1521   case Param::reservedName + Syntax::rSTARTTAG:
1522     bracketed = InternalTextEntity::starttag;
1523     break;
1524   case Param::reservedName + Syntax::rENDTAG:
1525     bracketed = InternalTextEntity::endtag;
1526     break;
1527   case Param::reservedName + Syntax::rMS:
1528     bracketed = InternalTextEntity::ms;
1529     break;
1530   case Param::reservedName + Syntax::rMD:
1531     bracketed = InternalTextEntity::md;
1532     break;
1533   }
1534   if (parm.type != Param::paramLiteral) {
1535     if (!parseParam(allowParamLiteral, declInputLevel, parm))
1536       return 0;
1537   }
1538   Text text;
1539   parm.literalText.swap(text);
1540   if (bracketed != InternalTextEntity::none) {
1541     StringC open;
1542     StringC close;
1543     switch (bracketed) {
1544     case InternalTextEntity::starttag:
1545       open = syntax().delimGeneral(Syntax::dSTAGO);
1546       close = syntax().delimGeneral(Syntax::dTAGC);
1547       break;
1548     case InternalTextEntity::endtag:
1549       open = syntax().delimGeneral(Syntax::dETAGO);
1550       close = syntax().delimGeneral(Syntax::dTAGC);
1551       break;
1552     case InternalTextEntity::ms:
1553       open = syntax().delimGeneral(Syntax::dMDO);
1554       open += syntax().delimGeneral(Syntax::dDSO);
1555       close = syntax().delimGeneral(Syntax::dMSC);
1556       close += syntax().delimGeneral(Syntax::dMDC);
1557       break;
1558     case InternalTextEntity::md:
1559       open = syntax().delimGeneral(Syntax::dMDO);
1560       close = syntax().delimGeneral(Syntax::dMDC);
1561       break;
1562     default:
1563       CANNOT_HAPPEN();
1564     }
1565     text.insertChars(open, Location(new BracketOrigin(typeLocation,
1566                                                       BracketOrigin::open),
1567                                     0));
1568     text.addChars(close, Location(new BracketOrigin(typeLocation,
1569                                                     BracketOrigin::close),
1570                                   0));
1571     if (text.size() > syntax().litlen()
1572         && text.size() - open.size() - close.size() <= syntax().litlen())
1573       message(ParserMessages::bracketedLitlen,
1574               NumberMessageArg(syntax().litlen()));
1575   }
1576   if (!parseParam(allowMdc, declInputLevel, parm))
1577     return 0;
1578   if (declType == Entity::parameterEntity
1579       && (dataType == Entity::cdata || dataType == Entity::sdata)) {
1580     message(ParserMessages::internalParameterDataEntity,
1581             StringMessageArg(name));
1582     return 1;
1583   }
1584   Ptr<Entity> entity;
1585   switch (dataType) {
1586   case Entity::cdata:
1587     entity = new InternalCdataEntity(name, markupLocation(), text);
1588     break;
1589   case Entity::sdata:
1590     entity = new InternalSdataEntity(name, markupLocation(), text);
1591     break;
1592   case Entity::pi:
1593     entity = new PiEntity(name, declType, markupLocation(), text);
1594     break;
1595   case Entity::sgmlText:
1596     entity = new InternalTextEntity(name, declType, markupLocation(), text, bracketed);
1597     break;
1598   default:
1599     CANNOT_HAPPEN();
1600     break;
1601   }
1602   maybeDefineEntity(entity);
1603   return 1;
1604 }
1605
1606 Boolean Parser::parseExternalEntity(StringC &name,
1607                                     Entity::DeclType declType,
1608                                     unsigned declInputLevel,
1609                                     Param &parm)
1610 {
1611   static AllowedParams
1612     allowSystemIdentifierEntityTypeMdc(Param::systemIdentifier,
1613                                        Param::reservedName + Syntax::rSUBDOC,
1614                                        Param::reservedName + Syntax::rCDATA,
1615                                        Param::reservedName + Syntax::rSDATA,
1616                                        Param::reservedName + Syntax::rNDATA,
1617                                        Param::mdc);
1618   static AllowedParams
1619     allowEntityTypeMdc(Param::reservedName + Syntax::rSUBDOC,
1620                        Param::reservedName + Syntax::rCDATA,
1621                        Param::reservedName + Syntax::rSDATA,
1622                        Param::reservedName + Syntax::rNDATA,
1623                        Param::mdc);
1624   
1625   ExternalId id;
1626   if (!parseExternalId(allowSystemIdentifierEntityTypeMdc, allowEntityTypeMdc,
1627                        declInputLevel, parm, id))
1628     return 0;
1629   if (parm.type == Param::mdc) {
1630     maybeDefineEntity(new ExternalTextEntity(name, declType, markupLocation(),
1631                                              id));
1632     return 1;
1633   }
1634   Ptr<Entity> entity;
1635   if (parm.type == Param::reservedName + Syntax::rSUBDOC) {
1636     if (sd().subdoc() == 0)
1637       message(ParserMessages::subdocEntity, StringMessageArg(name));
1638     if (!parseParam(allowMdc, declInputLevel, parm))
1639       return 0;
1640     entity = new SubdocEntity(name, markupLocation(), id);
1641   }
1642   else {
1643     Entity::DataType dataType;
1644     switch (parm.type) {
1645     case Param::reservedName + Syntax::rCDATA:
1646       dataType = Entity::cdata;
1647       break;
1648     case Param::reservedName + Syntax::rSDATA:
1649       dataType = Entity::sdata;
1650       break;
1651     case Param::reservedName + Syntax::rNDATA:
1652       dataType = Entity::ndata;
1653       break;
1654     default:
1655       CANNOT_HAPPEN();
1656     }
1657     if (!parseParam(allowName, declInputLevel, parm))
1658       return 0;
1659     ConstPtr<Notation> notation(lookupCreateNotation(parm.token));
1660     if (!parseParam(allowDsoMdc, declInputLevel, parm))
1661       return 0;
1662     AttributeList attributes(notation->attributeDef());
1663     if (parm.type == Param::dso) {
1664       if (attributes.size() == 0)
1665         message(ParserMessages::notationNoAttributes,
1666                 StringMessageArg(notation->name()));
1667       Boolean netEnabling;
1668       if (!parseAttributeSpec(1, attributes, netEnabling))
1669         return 0;
1670       if (attributes.nSpec() == 0)
1671         message(ParserMessages::emptyDataAttributeSpec);
1672       if (!parseParam(allowMdc, declInputLevel, parm))
1673         return 0;
1674     }
1675     else
1676       attributes.finish(*this);
1677     entity = new ExternalDataEntity(name, dataType, markupLocation(), id, notation,
1678                                     attributes);
1679   }
1680   if (declType == Entity::parameterEntity) {
1681     message(ParserMessages::externalParameterDataSubdocEntity,
1682             StringMessageArg(name));
1683     return 1;
1684   }
1685   maybeDefineEntity(entity);
1686   return 1;
1687 }
1688
1689 Notation *Parser::lookupCreateNotation(const StringC &name)
1690 {
1691   Ptr<Notation> nt = defDtd().lookupNotation(name);
1692   if (nt.isNull()) {
1693     nt = new Notation(name, defDtd().namePointer(), defDtd().isBase());
1694     defDtd().insertNotation(nt);
1695   }
1696   return nt.pointer();
1697 }
1698
1699 void Parser::maybeDefineEntity(const Ptr<Entity> &entity)
1700 {
1701   Dtd &dtd = defDtd();
1702   if (haveDefLpd())
1703     entity->setDeclIn(dtd.namePointer(),
1704                       dtd.isBase(),
1705                       defLpd().namePointer(),
1706                       defLpd().active());
1707   else
1708     entity->setDeclIn(dtd.namePointer(), dtd.isBase());
1709   Boolean ignored = 0;
1710   if (entity->name().size() == 0) {
1711     const Entity *oldEntity = dtd.defaultEntity().pointer();
1712     if (oldEntity == 0
1713         || (!oldEntity->declInActiveLpd() && entity->declInActiveLpd()))
1714       dtd.setDefaultEntity(entity, *this);
1715     else {
1716       ignored = 1;
1717       if (options().warnDuplicateEntity)
1718         message(ParserMessages::duplicateEntityDeclaration,
1719                 StringMessageArg(syntax().rniReservedName(Syntax::rDEFAULT)));
1720     }
1721   }
1722   else {
1723     Ptr<Entity> oldEntity = dtd.insertEntity(entity);
1724     if (oldEntity.isNull())
1725       entity->generateSystemId(*this);
1726     else if (oldEntity->defaulted()) {
1727       dtd.insertEntity(entity, 1);
1728       message(ParserMessages::defaultedEntityDefined,
1729               StringMessageArg(entity->name()));
1730       entity->generateSystemId(*this);
1731     }
1732     else {
1733       if (entity->declInActiveLpd() && !oldEntity->declInActiveLpd()) {
1734         dtd.insertEntity(entity, 1);
1735         entity->generateSystemId(*this);
1736       }
1737       else {
1738         ignored = 1;
1739         if (options().warnDuplicateEntity)
1740           message(entity->declType() == Entity::parameterEntity
1741                   ? ParserMessages::duplicateParameterEntityDeclaration
1742                   : ParserMessages::duplicateEntityDeclaration,
1743                   StringMessageArg(entity->name()));
1744       }
1745     }
1746   }
1747   if (currentMarkup())
1748     eventHandler().entityDecl(new (eventAllocator())
1749                               EntityDeclEvent(entity, ignored,
1750                                               markupLocation(),
1751                                               currentMarkup()));
1752 }
1753
1754 Boolean Parser::parseShortrefDecl()
1755 {
1756   if (!defDtd().isBase())
1757     message(ParserMessages::shortrefOnlyInBaseDtd);
1758
1759   unsigned declInputLevel = inputLevel();
1760   Param parm;
1761
1762   if (!parseParam(allowName, declInputLevel, parm))
1763     return 0;
1764   ShortReferenceMap *map = lookupCreateMap(parm.token);
1765   int valid = 1;
1766   if (map->defined()) {
1767     message(ParserMessages::duplicateShortrefDeclaration,
1768             StringMessageArg(parm.token),
1769             map->defLocation());
1770     valid = 0;
1771   }
1772   else
1773     map->setDefLocation(markupLocation());
1774   if (!parseParam(allowParamLiteral, declInputLevel, parm))
1775     return 0;
1776   Vector<StringC> vec;
1777   do {
1778     StringC delim(parm.literalText.string());
1779     const SubstTable<Char> *table = instanceSyntax().generalSubstTable();
1780     for (size_t i = 0; i < delim.size(); i++)
1781       table->subst(delim[i]);
1782     size_t srIndex;
1783     if (!defDtd().shortrefIndex(delim, instanceSyntax(), srIndex)) {
1784       message(ParserMessages::unknownShortrefDelim,
1785               StringMessageArg(prettifyDelim(delim)));
1786       valid = 0;
1787     }
1788     static AllowedParams allowEntityName(Param::entityName);
1789     if (!parseParam(allowEntityName, declInputLevel, parm))
1790       return 0;
1791     if (valid) {
1792       if (srIndex >= vec.size())
1793         vec.resize(srIndex + 1);
1794       if (vec[srIndex].size() > 0) {
1795         message(ParserMessages::delimDuplicateMap,
1796                 StringMessageArg(prettifyDelim(delim)));
1797         valid = 0;
1798       }
1799       else
1800         parm.token.swap(vec[srIndex]);
1801     }
1802     static AllowedParams allowParamLiteralMdc(Param::paramLiteral, Param::mdc);
1803     if (!parseParam(allowParamLiteralMdc, declInputLevel, parm))
1804       return 0;
1805   } while (parm.type != Param::mdc);
1806   if (valid) {
1807     map->setNameMap(vec);
1808     if (currentMarkup())
1809       eventHandler().shortrefDecl(new (eventAllocator())
1810                                   ShortrefDeclEvent(map,
1811                                                     currentDtdPointer(),
1812                                                     markupLocation(),
1813                                                     currentMarkup()));
1814   }
1815   return 1;
1816 }
1817
1818 StringC Parser::prettifyDelim(const StringC &delim)
1819 {
1820   StringC prettyDelim;
1821   for (size_t i = 0; i < delim.size(); i++) {
1822     const StringC *nameP;
1823     if (syntax().charFunctionName(delim[i], nameP)) {
1824       prettyDelim += syntax().delimGeneral(Syntax::dCRO);
1825       prettyDelim += *nameP;
1826       prettyDelim += syntax().delimGeneral(Syntax::dREFC);
1827     }
1828     else
1829       prettyDelim += delim[i];
1830   }
1831   return prettyDelim;
1832 }
1833
1834 ShortReferenceMap *Parser::lookupCreateMap(const StringC &name)
1835 {
1836   ShortReferenceMap *map = defDtd().lookupShortReferenceMap(name);
1837   if (!map) {
1838     map = new ShortReferenceMap(name);
1839     defDtd().insertShortReferenceMap(map);
1840   }
1841   return map;
1842 }
1843
1844 Boolean Parser::parseUsemapDecl()
1845 {
1846   if (!inInstance() && !defDtd().isBase())
1847     message(ParserMessages::usemapOnlyInBaseDtd);
1848
1849   unsigned declInputLevel = inputLevel();
1850   Param parm;
1851   static AllowedParams
1852     allowNameEmpty(Param::name,
1853                    Param::indicatedReservedName + Syntax::rEMPTY);
1854   if (!parseParam(allowNameEmpty, declInputLevel, parm))
1855     return 0;
1856   const ShortReferenceMap *map;
1857   if (parm.type == Param::name) {
1858     if (inInstance()) {
1859       map = currentDtd().lookupShortReferenceMap(parm.token);
1860       if (!map)
1861         message(ParserMessages::undefinedShortrefMapInstance,
1862                 StringMessageArg(parm.token));
1863     }
1864     else {
1865       ShortReferenceMap *tem = lookupCreateMap(parm.token);
1866       tem->setUsed();
1867       map = tem;
1868     }
1869   }
1870   else
1871     map = &theEmptyMap;
1872   static AllowedParams
1873     allowNameNameGroupMdc(Param::name, Param::nameGroup, Param::mdc);
1874   if (!parseParam(allowNameNameGroupMdc, declInputLevel, parm))
1875     return 0;
1876   if (parm.type != Param::mdc) {
1877     if (inInstance()) {
1878       message(ParserMessages::usemapAssociatedElementTypeInstance);
1879       if (!parseParam(allowMdc, declInputLevel, parm))
1880         return 0;
1881     }
1882     else {
1883       Vector<const ElementType *> v;
1884       if (parm.type == Param::name) {
1885         ElementType *e = lookupCreateElement(parm.token);
1886         v.push_back(e);
1887         if (!e->map())
1888           e->setMap(map);
1889       }
1890       else {
1891         v.resize(parm.nameTokenVector.size());
1892         for (size_t i = 0; i < parm.nameTokenVector.size(); i++) {
1893           ElementType *e
1894             = lookupCreateElement(parm.nameTokenVector[i].name);
1895           v[i] = e;
1896           if (!e->map())
1897             e->setMap(map);
1898         }
1899       }
1900       if (!parseParam(allowMdc, declInputLevel, parm))
1901         return 0;
1902       if (currentMarkup())
1903         eventHandler().usemap(new (eventAllocator())
1904                               UsemapEvent(map, v,
1905                                           currentDtdPointer(),
1906                                           markupLocation(),
1907                                           currentMarkup()));
1908     }
1909   }
1910   else {
1911     if (!inInstance())
1912       message(ParserMessages::usemapAssociatedElementTypeDtd);
1913     else if (map) {
1914       if (map != &theEmptyMap && !map->defined())
1915         message(ParserMessages::undefinedShortrefMapInstance,
1916                 StringMessageArg(map->name()));
1917       else {
1918         if (currentMarkup()) {
1919           Vector<const ElementType *> v;
1920           eventHandler().usemap(new (eventAllocator())
1921                                 UsemapEvent(map, v,
1922                                             currentDtdPointer(),
1923                                             markupLocation(),
1924                                             currentMarkup()));
1925         }
1926         currentElement().setMap(map);
1927       }
1928     }
1929   }
1930   return 1;
1931 }
1932
1933 Boolean Parser::parseDoctypeDeclStart()
1934 {
1935   if (hadDtd() && !sd().concur() && !sd().explicitLink())
1936     message(ParserMessages::multipleDtds);
1937   if (hadLpd())
1938     message(ParserMessages::dtdAfterLpd);
1939   unsigned declInputLevel = inputLevel();
1940   Param parm;
1941   
1942   if (!parseParam(allowName, declInputLevel, parm))
1943     return 0;
1944   StringC name;
1945   parm.token.swap(name);
1946   if (!lookupDtd(name).isNull())
1947     message(ParserMessages::duplicateDtd, StringMessageArg(name));
1948   static AllowedParams
1949     allowPublicSystemDsoMdc(Param::reservedName + Syntax::rPUBLIC,
1950                             Param::reservedName + Syntax::rSYSTEM,
1951                             Param::dso,
1952                             Param::mdc);
1953   if (!parseParam(allowPublicSystemDsoMdc, declInputLevel, parm))
1954     return 0;
1955   ConstPtr<Entity> entity;
1956   if (parm.type == Param::reservedName + Syntax::rPUBLIC
1957       || parm.type == Param::reservedName + Syntax::rSYSTEM) {
1958     static AllowedParams allowSystemIdentifierDsoMdc(Param::systemIdentifier,
1959                                                      Param::dso, Param::mdc);
1960     ExternalId id;
1961     if (!parseExternalId(allowSystemIdentifierDsoMdc, allowDsoMdc,
1962                          declInputLevel, parm, id))
1963       return 0;
1964     Ptr<Entity> tem
1965       = new ExternalTextEntity(name, Entity::doctype, markupLocation(), id);
1966     tem->generateSystemId(*this);
1967     entity = tem;
1968 #if 0
1969     eventHandler()
1970       .externalEntityDecl(new (eventAllocator())
1971                           ExternalEntityDeclEvent(entity, 0));
1972 #endif
1973   }
1974   else if (parm.type == Param::mdc) {
1975     message(ParserMessages::noDtdSubset, StringMessageArg(name));
1976     return 1;
1977   }
1978   // Discard mdc or dso
1979   if (currentMarkup())
1980     currentMarkup()->resize(currentMarkup()->size() - 1);
1981   eventHandler().startDtd(new (eventAllocator())
1982                           StartDtdEvent(name, entity, parm.type == Param::dso,
1983                                         markupLocation(),
1984                                         currentMarkup()));
1985   startDtd(name);
1986   if (parm.type == Param::mdc) {
1987     // unget the mdc
1988     currentInput()->ungetToken();
1989     // reference the entity
1990     Ptr<EntityOrigin> origin
1991       = new (internalAllocator()) EntityOrigin(entity, currentLocation());
1992     entity->dsReference(*this, origin);
1993     if (inputLevel() == 1) {    // reference failed
1994       (void)parseDoctypeDeclEnd();
1995       return 1;
1996     }
1997   }
1998   else if (!entity.isNull())
1999     setDsEntity(entity);
2000   setPhase(declSubsetPhase);
2001   return 1;
2002 }
2003
2004 Boolean Parser::implyDtd(const StringC &gi)
2005 {
2006   ExternalId id;
2007   // The null location indicates that this is a fake entity.
2008   ConstPtr<Entity> entity(new ExternalTextEntity(gi,
2009                                                  Entity::doctype,
2010                                                  Location(),
2011                                                  id));
2012   // Don't use Entity::generateSystemId because we don't want an error
2013   // if it fails.
2014   StringC str;
2015   StringC name;
2016   if (!entityCatalog().lookup(*entity, syntax(), sd().docCharset(),
2017                               messenger(), str)) {
2018     if (!entityCatalog().defaultDoctype(sd().docCharset(),
2019                                         messenger(),
2020                                         name,
2021                                         str))
2022       return 0;
2023     for (size_t i = 0; i < name.size(); i++)
2024       syntax().generalSubstTable()->subst(name[i]);
2025   }
2026   else
2027     name = gi;
2028   id.setEffectiveSystem(str);
2029   entity = new ExternalTextEntity(name,
2030                                   Entity::doctype,
2031                                   Location(),
2032                                   id);
2033   StringC declStr;
2034   declStr += syntax().delimGeneral(Syntax::dMDO);
2035   declStr += syntax().reservedName(Syntax::rDOCTYPE);
2036   declStr += syntax().space();
2037   declStr += name;
2038   declStr += syntax().space();
2039   declStr += syntax().reservedName(Syntax::rSYSTEM);
2040   declStr += syntax().delimGeneral(Syntax::dMDC);
2041   message(ParserMessages::implyingDtd, StringMessageArg(declStr));
2042   Ptr<EntityOrigin> origin
2043     = new (internalAllocator()) EntityOrigin(entity, currentLocation());
2044   startMarkup(eventsWanted().wantPrologMarkup(), Location());
2045   if (currentMarkup()) {
2046     currentMarkup()->addDelim(Syntax::dMDO);
2047     currentMarkup()->addReservedName(Syntax::rDOCTYPE,
2048                                      syntax().reservedName(Syntax::rDOCTYPE));
2049     currentMarkup()->addS(syntax().space());
2050     currentMarkup()->addName(name.data(), name.size());
2051     currentMarkup()->addS(syntax().space());
2052     currentMarkup()->addReservedName(Syntax::rSYSTEM,
2053                                      syntax().reservedName(Syntax::rSYSTEM));
2054   }
2055   eventHandler().startDtd(new (eventAllocator())
2056                           StartDtdEvent(name, entity, 0,
2057                                         markupLocation(),
2058                                         currentMarkup()));
2059   startDtd(name);
2060   entity->dsReference(*this, origin);
2061   if (inputLevel() == 1) {
2062     parseDoctypeDeclEnd(1);
2063     return 1;
2064   }
2065   setPhase(declSubsetPhase);
2066   return 1;
2067 }
2068
2069 Boolean Parser::parseDoctypeDeclEnd(Boolean fake)
2070 {
2071   checkDtd(defDtd());
2072   Ptr<Dtd> tem(defDtdPointer());
2073   endDtd();
2074   if (fake) {
2075     startMarkup(eventsWanted().wantPrologMarkup(), Location());
2076     if (currentMarkup())
2077       currentMarkup()->addDelim(Syntax::dMDC);
2078   }
2079   else {
2080     startMarkup(eventsWanted().wantPrologMarkup(), currentLocation());
2081     Param parm;
2082     // End DTD before parsing final param so parameter entity reference
2083     // not allowed between ] and >.
2084     if (!parseParam(allowMdc, inputLevel(), parm))
2085       return 0;
2086   }
2087   eventHandler().endDtd(new (eventAllocator()) EndDtdEvent(tem,
2088                                                            markupLocation(),
2089                                                            currentMarkup()));
2090   if (fake) {
2091     Char c = syntax().standardFunction(Syntax::fRE);
2092     eventHandler().sSep(new (eventAllocator())
2093                         SSepEvent(&c, 1, Location(), 1));
2094   }
2095   return 1;
2096 }
2097
2098 void Parser::checkDtd(Dtd &dtd)
2099 {
2100   if (dtd.isBase())
2101     addNeededShortrefs(dtd, instanceSyntax());
2102   if (!options().errorAfdr)
2103     addCommonAttributes(dtd);
2104   Dtd::ElementTypeIter elementIter(dtd.elementTypeIter());
2105   ElementType *p;
2106   ConstPtr<ElementDefinition> def;
2107   int i = 0;
2108   while ((p = elementIter.next()) != 0) {
2109     if (p->definition() == 0) {
2110       if (p->name() == dtd.name())
2111         message(ParserMessages::documentElementUndefined);
2112       else if (options().warnUndefinedElement)
2113         message(ParserMessages::dtdUndefinedElement, StringMessageArg(p->name()));
2114       if (def.isNull())
2115         def = new ElementDefinition(currentLocation(),
2116                                     ElementDefinition::undefinedIndex,
2117                                     (ElementDefinition::omitStart
2118                                      |ElementDefinition::omitEnd),
2119                                     ElementDefinition::any);
2120       p->setElementDefinition(def, i++);
2121     }
2122     const ShortReferenceMap *map = p->map();
2123     if (map != 0 && map != &theEmptyMap && !map->defined()) {
2124       message(ParserMessages::undefinedShortrefMapDtd,
2125               StringMessageArg(map->name()),
2126               StringMessageArg(p->name()));
2127       p->setMap(0);
2128     }
2129   }
2130   Dtd::ConstEntityIter entityIter(((const Dtd &)dtd).generalEntityIter());
2131   for (;;) {
2132     ConstPtr<Entity> entity(entityIter.next());
2133     if (entity.isNull())
2134       break;
2135     const ExternalDataEntity *external = entity->asExternalDataEntity();
2136     if (external) {
2137       const Notation *notation = external->notation();
2138       if (!notation->defined()) {
2139         setNextLocation(external->defLocation());
2140         message(ParserMessages::entityNotationUndefined,
2141                 StringMessageArg(notation->name()),
2142                 StringMessageArg(external->name()));
2143       }
2144     }
2145   }
2146   Dtd::NotationIter notationIter(dtd.notationIter());
2147   for (;;) {
2148     ConstPtr<Notation> notation(notationIter.next());
2149     if (notation.isNull())
2150       break;
2151     if (!notation->defined() && !notation->attributeDef().isNull())
2152       message(ParserMessages::attlistNotationUndefined,
2153               StringMessageArg(notation->name()));
2154   }
2155   Dtd::ShortReferenceMapIter mapIter(dtd.shortReferenceMapIter());
2156   int nShortref = dtd.nShortref();
2157   for (;;) {
2158     ShortReferenceMap *map = mapIter.next();
2159     if (!map)
2160       break;
2161     Vector<ConstPtr<Entity> > entityMap(nShortref);
2162     for (i = 0; i < nShortref; i++) {
2163       const StringC *entityName = map->entityName(i);
2164       if (entityName) {
2165         ConstPtr<Entity> entity
2166           = lookupEntity(0, *entityName, map->defLocation(), 0);
2167         if (entity.isNull()) {
2168           setNextLocation(map->defLocation());
2169           message(ParserMessages::mapEntityUndefined,
2170                   StringMessageArg(*entityName),
2171                   StringMessageArg(map->name()));
2172         }
2173         else {
2174           if (entity->defaulted() && options().warnDefaultEntityReference) {
2175             setNextLocation(map->defLocation());
2176             message(ParserMessages::mapDefaultEntity,
2177                     StringMessageArg(*entityName),
2178                     StringMessageArg(map->name()));
2179           }
2180           entityMap[i] = entity;
2181         }
2182       }
2183     }
2184     map->setEntityMap(entityMap);
2185     if (options().warnUnusedMap && !map->used()) {
2186       setNextLocation(map->defLocation());
2187       message(ParserMessages::unusedMap, StringMessageArg(map->name()));
2188     }
2189   }
2190   if (options().warnUnusedParam) {
2191     Dtd::ConstEntityIter entityIter(((const Dtd &)dtd).parameterEntityIter());
2192     for (;;) {
2193       ConstPtr<Entity> entity(entityIter.next());
2194       if (entity.isNull())
2195         break;
2196       if (!entity->used() && !maybeStatusKeyword(*entity)) {
2197         setNextLocation(entity->defLocation());
2198         message(ParserMessages::unusedParamEntity,
2199                 StringMessageArg(entity->name()));
2200       }
2201     }
2202   }
2203 }
2204
2205 void Parser::addCommonAttributes(Dtd &dtd)
2206 {
2207   Ptr<AttributeDefinitionList> commonAdl[2];
2208   {
2209     ElementType *e = dtd.removeElementType(syntax()
2210                                            .rniReservedName(Syntax::rANY));
2211     if (e) {
2212       commonAdl[0] = e->attributeDef();
2213       delete e;
2214     }
2215   }
2216   {
2217     Ptr<Notation> allNotation
2218       = dtd.removeNotation(syntax().rniReservedName(Syntax::rANY));
2219     if (!allNotation.isNull())
2220       commonAdl[1] = allNotation->attributeDef();
2221   }
2222   Dtd::ElementTypeIter elementIter(dtd.elementTypeIter());
2223   Dtd::NotationIter notationIter(dtd.notationIter());
2224   Vector<PackedBoolean> doneAdl(dtd.nAttributeDefinitionList(),
2225                                 PackedBoolean(0));
2226   for (int isNotation = 0; isNotation < 2; isNotation++) {
2227     if (!commonAdl[isNotation].isNull()) {
2228       doneAdl[commonAdl[isNotation]->index()] = 1;
2229       for (;;) {
2230         Attributed *a;
2231         if (!isNotation)
2232           a = elementIter.next();
2233         else
2234           a = notationIter.next().pointer();
2235         if (!a)
2236           break;
2237         Ptr<AttributeDefinitionList> adl = a->attributeDef();
2238         if (adl.isNull())
2239           a->setAttributeDef(commonAdl[isNotation]);
2240         else if (!doneAdl[adl->index()]) {
2241           doneAdl[adl->index()] = 1;
2242           for (size_t j = 0; j < commonAdl[isNotation]->size(); j++) {
2243             unsigned tem;
2244             if (!adl->attributeIndex(commonAdl[isNotation]->def(j)->name(),
2245                                      tem))
2246               adl->append(commonAdl[isNotation]->def(j)->copy());
2247           }
2248         }
2249       }
2250     }
2251   }
2252 }
2253
2254 Boolean Parser::maybeStatusKeyword(const Entity &entity)
2255 {
2256   const InternalEntity *internal = entity.asInternalEntity();
2257   if (!internal)
2258     return 0;
2259   const StringC &text = internal->string();
2260   static const Syntax::ReservedName statusKeywords[] = {
2261     Syntax::rINCLUDE, Syntax::rIGNORE
2262     };
2263   for (size_t i = 0; i < SIZEOF(statusKeywords); i++) {
2264     const StringC &keyword = instanceSyntax().reservedName(statusKeywords[i]);
2265     size_t j = 0;
2266     while (j < text.size() && instanceSyntax().isS(text[j]))
2267       j++;
2268     size_t k = 0;
2269     while (j < text.size()
2270            && k < keyword.size()
2271            && ((*instanceSyntax().generalSubstTable())[text[j]]
2272                == keyword[k]))
2273       j++, k++;
2274     if (k == keyword.size()) {
2275       while (j < text.size() && instanceSyntax().isS(text[j]))
2276         j++;
2277       if (j == text.size())
2278         return 1;
2279     }
2280   }
2281   return 0;
2282 }
2283
2284 Boolean Parser::parseLinktypeDeclStart()
2285 {
2286   if (baseDtd().isNull())
2287     message(ParserMessages::lpdBeforeBaseDtd);
2288   unsigned declInputLevel = inputLevel();
2289   Param parm;
2290   
2291   if (!parseParam(allowName, declInputLevel, parm))
2292     return 0;
2293   StringC name;
2294   parm.token.swap(name);
2295   if (!lookupDtd(name).isNull())
2296     message(ParserMessages::duplicateDtdLpd, StringMessageArg(name));
2297   else if (!lookupLpd(name).isNull())
2298     message(ParserMessages::duplicateLpd, StringMessageArg(name));
2299   static AllowedParams
2300     allowSimpleName(Param::indicatedReservedName + Syntax::rSIMPLE,
2301                     Param::name);
2302   if (!parseParam(allowSimpleName, declInputLevel, parm))
2303     return 0;
2304   Boolean simple;
2305   Ptr<Dtd> sourceDtd;
2306   if (parm.type == Param::indicatedReservedName + Syntax::rSIMPLE) {
2307     simple = 1;
2308     sourceDtd = baseDtd();
2309     if (sourceDtd.isNull())
2310       sourceDtd = new Dtd(StringC(), 1);
2311   }
2312   else {
2313     simple = 0;
2314     sourceDtd = lookupDtd(parm.token);
2315     if (sourceDtd.isNull()) {
2316       message(ParserMessages::noSuchDtd, StringMessageArg(parm.token));
2317       sourceDtd = new Dtd(parm.token, 0);
2318     }
2319   }
2320   static AllowedParams
2321     allowImpliedName(Param::indicatedReservedName + Syntax::rIMPLIED,
2322                      Param::name);
2323   if (!parseParam(allowImpliedName, declInputLevel, parm))
2324     return 0;
2325   Ptr<Dtd> resultDtd;
2326   Boolean implied = 0;
2327   if (parm.type == Param::indicatedReservedName + Syntax::rIMPLIED) {
2328     if (simple) {
2329       if (!sd().simpleLink())
2330         message(ParserMessages::simpleLinkFeature);
2331     }
2332     else {
2333       implied = 1;
2334       if (!sd().implicitLink())
2335         message(ParserMessages::implicitLinkFeature);
2336     }
2337   }
2338   else {
2339     if (simple)
2340       message(ParserMessages::simpleLinkResultNotImplied);
2341     else {
2342       if (!sd().explicitLink())
2343         message(ParserMessages::explicitLinkFeature);
2344       resultDtd = lookupDtd(parm.token);
2345       if (resultDtd.isNull())
2346         message(ParserMessages::noSuchDtd, StringMessageArg(parm.token));
2347     }
2348   }
2349   static AllowedParams
2350     allowPublicSystemDsoMdc(Param::reservedName + Syntax::rPUBLIC,
2351                             Param::reservedName + Syntax::rSYSTEM,
2352                             Param::dso,
2353                             Param::mdc);
2354   if (!parseParam(allowPublicSystemDsoMdc, declInputLevel, parm))
2355     return 0;
2356   ConstPtr<Entity> entity;
2357   if (parm.type == Param::reservedName + Syntax::rPUBLIC
2358       || parm.type == Param::reservedName + Syntax::rSYSTEM) {
2359     static AllowedParams allowSystemIdentifierDsoMdc(Param::systemIdentifier,
2360                                                      Param::dso, Param::mdc);
2361     ExternalId id;
2362     if (!parseExternalId(allowSystemIdentifierDsoMdc, allowDsoMdc,
2363                          declInputLevel, parm, id))
2364       return 0;
2365     Ptr<Entity> tem
2366       = new ExternalTextEntity(name, Entity::linktype, markupLocation(), id);
2367     tem->generateSystemId(*this);
2368     entity = tem;
2369 #if 0
2370     eventHandler()
2371       .externalEntityDecl(new (eventAllocator())
2372                           ExternalEntityDeclEvent(entity, 0));
2373 #endif
2374   }
2375   Ptr<Lpd> lpd;
2376   if (simple)
2377     lpd = new SimpleLpd(name, markupLocation(), sourceDtd);
2378   else
2379     lpd = new ComplexLpd(name,
2380                          implied ? Lpd::implicitLink : Lpd::explicitLink,
2381                          markupLocation(),
2382                          syntax(),
2383                          sourceDtd,
2384                          resultDtd);
2385   if (!baseDtd().isNull() && shouldActivateLink(name)) {
2386     size_t nActive = nActiveLink();
2387     if (simple) {
2388       size_t nSimple = 0;
2389       for (size_t i = 0; i < nActive; i++)
2390         if (activeLpd(i).type() == Lpd::simpleLink)
2391           nSimple++;
2392       if (nSimple == sd().simpleLink())
2393         message(ParserMessages::simpleLinkCount,
2394                 NumberMessageArg(sd().simpleLink()));
2395       lpd->activate();
2396     }
2397     else {
2398       Boolean haveImplicit = 0;
2399       Boolean haveExplicit = 0;
2400       size_t i;
2401       for (i = 0; i < nActive; i++) {
2402         if (activeLpd(i).type() == Lpd::implicitLink)
2403           haveImplicit = 1;
2404         else if (activeLpd(i).type() == Lpd::explicitLink)
2405           haveExplicit = 1;
2406       }
2407       const Dtd *sourceDtd = lpd->sourceDtd().pointer();
2408       if (implied && haveImplicit)
2409         message(ParserMessages::oneImplicitLink);
2410       else if (sd().explicitLink() <= 1 && sourceDtd != baseDtd().pointer())
2411         message(sd().explicitLink() == 0
2412                 ? ParserMessages::explicitNoRequiresSourceTypeBase
2413                 : ParserMessages::explicit1RequiresSourceTypeBase,
2414                 StringMessageArg(lpd->name()));
2415       else if (sd().explicitLink() == 1 && haveExplicit && !implied)
2416         message(ParserMessages::duplicateExplicitChain);
2417       else if (haveExplicit || haveImplicit
2418                || sourceDtd != baseDtd().pointer())
2419         message(ParserMessages::sorryLink, StringMessageArg(lpd->name()));
2420       else
2421         lpd->activate();
2422     }
2423   }
2424   // Discard mdc or dso
2425   if (currentMarkup())
2426     currentMarkup()->resize(currentMarkup()->size() - 1);
2427   eventHandler().startLpd(new (eventAllocator())
2428                           StartLpdEvent(lpd->active(),
2429                                         name,
2430                                         entity,
2431                                         parm.type == Param::dso,
2432                                         markupLocation(),
2433                                         currentMarkup()));
2434   startLpd(lpd);
2435   if (parm.type == Param::mdc) {
2436     // unget the mdc
2437     currentInput()->ungetToken();
2438     if (entity.isNull()) {
2439       message(ParserMessages::noLpdSubset, StringMessageArg(name));
2440       (void)parseLinktypeDeclEnd();
2441       return 1;
2442     }
2443     // reference the entity
2444     Ptr<EntityOrigin> origin
2445       = new (internalAllocator()) EntityOrigin(entity, currentLocation());
2446     entity->dsReference(*this, origin);
2447     if (inputLevel() == 1) {    // reference failed
2448       (void)parseLinktypeDeclEnd();
2449       return 1;
2450     }
2451   }
2452   else if (!entity.isNull())
2453     setDsEntity(entity);
2454   setPhase(declSubsetPhase);
2455   return 1;
2456 }
2457
2458 Boolean Parser::parseLinktypeDeclEnd()
2459 {
2460
2461   if (defLpd().type() != Lpd::simpleLink) {
2462     if (!defComplexLpd().initialLinkSet()->defined())
2463       message(ParserMessages::noInitialLinkSet,
2464               StringMessageArg(defLpd().name()));
2465     ComplexLpd::ConstLinkSetIter iter = defComplexLpd().linkSetIter();
2466     const LinkSet *linkSet;
2467     while ((linkSet = iter.next()) != 0)
2468       if (!linkSet->defined())
2469         message(ParserMessages::undefinedLinkSet, StringMessageArg(linkSet->name()));
2470   }
2471   ConstPtr<Lpd> tem(defLpdPointer());
2472   endLpd();
2473   startMarkup(eventsWanted().wantPrologMarkup(), currentLocation());
2474   Param parm;
2475   Boolean result = parseParam(allowMdc, inputLevel(), parm);
2476   eventHandler().endLpd(new (eventAllocator()) EndLpdEvent(tem,
2477                                                            markupLocation(),
2478                                                            currentMarkup()));
2479   return result;
2480 }
2481
2482 Boolean Parser::parseLinkDecl()
2483 {
2484   return parseLinkSet(0);
2485 }
2486
2487 Boolean Parser::parseIdlinkDecl()
2488 {
2489   return parseLinkSet(1);
2490 }
2491
2492 // This will only get called if we're defining a complex lpd.
2493
2494 Boolean Parser::parseLinkSet(Boolean idlink)
2495 {
2496   if (defLpd().type() == Lpd::simpleLink) {
2497     message(idlink ? ParserMessages::idlinkDeclSimple : ParserMessages::linkDeclSimple);
2498     return 0;
2499   }
2500   if (idlink) {
2501     if (defComplexLpd().hadIdLinkSet())
2502       message(ParserMessages::duplicateIdLinkSet);
2503     else
2504       defComplexLpd().setHadIdLinkSet();
2505   }
2506   unsigned declInputLevel = inputLevel();
2507   Param parm;
2508   
2509   Boolean isExplicit = (defLpd().type() == Lpd::explicitLink);
2510   LinkSet *linkSet;
2511   if (idlink) {
2512     if (!parseParam(allowName, declInputLevel, parm))
2513       return 0;
2514     linkSet = 0;
2515   }
2516   else {
2517     static AllowedParams
2518       allowNameInitial(Param::name,
2519                        Param::indicatedReservedName + Syntax::rINITIAL);
2520     if (!parseParam(allowNameInitial, declInputLevel, parm))
2521       return 0;
2522     if (parm.type == Param::name)
2523       linkSet = lookupCreateLinkSet(parm.token);
2524     else
2525       linkSet = defComplexLpd().initialLinkSet();
2526     if (linkSet->defined())
2527       message(ParserMessages::duplicateLinkSet, StringMessageArg(linkSet->name()));
2528     static AllowedParams
2529       allowExplicitLinkRule(Param::name,
2530                             Param::nameGroup,
2531                             Param::indicatedReservedName + Syntax::rIMPLIED);
2532     if (!parseParam(isExplicit ? allowExplicitLinkRule : allowNameNameGroup,
2533                     declInputLevel, parm))
2534       return 0;
2535   }
2536
2537   do {
2538     StringC id;
2539     if (idlink) {
2540       parm.token.swap(id);
2541       if (!parseParam(isExplicit ? allowExplicitLinkRuleMdc : allowNameNameGroupMdc,
2542                       declInputLevel, parm))
2543         return 0;
2544     }
2545     if (parm.type == Param::indicatedReservedName + Syntax::rIMPLIED) {
2546       if (!parseParam(allowName, declInputLevel, parm))
2547         return 0;
2548       Boolean resultImplied;
2549       const ElementType *resultType;
2550       AttributeList resultAttributes;
2551       if (!parseResultElementSpec(declInputLevel,
2552                                   parm,
2553                                   idlink,
2554                                   resultImplied,
2555                                   resultType,
2556                                   resultAttributes))
2557         return 0;
2558       if (resultType) {
2559         const AttributeList *dummy;
2560         if (linkSet->impliedResultAttributes(resultType, dummy))
2561           message(ParserMessages::duplicateImpliedResult,
2562                   StringMessageArg(resultType->name()));
2563         else
2564           linkSet->addImplied(resultType, resultAttributes);
2565       }
2566     }
2567     else {
2568       SourceLinkRule *linkRule = 0;
2569       IdLinkRule idLinkRule;
2570       Ptr<SourceLinkRuleResource> linkRuleResource;
2571       if (idlink)
2572         linkRule = &idLinkRule;
2573       else {
2574         linkRuleResource = new SourceLinkRuleResource;
2575         linkRule = linkRuleResource.pointer();
2576       }
2577       Vector<const ElementType *> assocElementTypes;
2578       if (parm.type == Param::name) {
2579         assocElementTypes.resize(1);
2580         assocElementTypes[0] = lookupCreateElement(parm.token);
2581       }
2582       else {
2583         assocElementTypes.resize(parm.nameTokenVector.size());
2584         for (size_t i = 0; i < assocElementTypes.size(); i++)
2585           assocElementTypes[i]
2586             = lookupCreateElement(parm.nameTokenVector[i].name);
2587       }
2588       static AllowedParams
2589         allow2i(Param::indicatedReservedName + Syntax::rUSELINK,
2590                 Param::indicatedReservedName + Syntax::rPOSTLINK,
2591                 Param::dso,
2592                 Param::mdc,
2593                 Param::name,
2594                 Param::nameGroup);
2595       static AllowedParams
2596         allow2id(Param::indicatedReservedName + Syntax::rUSELINK,
2597                  Param::indicatedReservedName + Syntax::rPOSTLINK,
2598                  Param::dso,
2599                  Param::mdc,
2600                  Param::name);
2601       static AllowedParams
2602         allow2e(Param::indicatedReservedName + Syntax::rUSELINK,
2603                 Param::indicatedReservedName + Syntax::rPOSTLINK,
2604                 Param::dso,
2605                 Param::name,
2606                 Param::indicatedReservedName + Syntax::rIMPLIED);
2607
2608       if (!parseParam(isExplicit
2609                       ? allow2e
2610                       : (idlink ? allow2id : allow2i), declInputLevel, parm))
2611         return 0;
2612       if (parm.type == Param::indicatedReservedName + Syntax::rUSELINK) {
2613         static AllowedParams
2614           allowLinkSetEmpty(Param::name,
2615                             Param::indicatedReservedName + Syntax::rINITIAL,
2616                             Param::indicatedReservedName + Syntax::rEMPTY);
2617         if (!parseParam(allowLinkSetEmpty, declInputLevel, parm))
2618           return 0;
2619         const LinkSet *uselink;
2620         if (parm.type == Param::name)
2621           uselink = lookupCreateLinkSet(parm.token);
2622         else if (parm.type == Param::indicatedReservedName + Syntax::rINITIAL)
2623           uselink = defComplexLpd().initialLinkSet();
2624         else
2625           uselink = defComplexLpd().emptyLinkSet();
2626         linkRule->setUselink(uselink);
2627         static AllowedParams
2628           allow3i(Param::indicatedReservedName + Syntax::rPOSTLINK,
2629                   Param::dso,
2630                   Param::mdc,
2631                   Param::name,
2632                   Param::nameGroup);
2633         static AllowedParams
2634           allow3id(Param::indicatedReservedName + Syntax::rPOSTLINK,
2635                    Param::dso,
2636                    Param::mdc,
2637                    Param::name);
2638         static AllowedParams
2639           allow3e(Param::indicatedReservedName + Syntax::rPOSTLINK,
2640                   Param::dso,
2641                   Param::name,
2642                   Param::indicatedReservedName + Syntax::rIMPLIED);
2643         
2644         if (!parseParam(isExplicit
2645                         ? allow3e
2646                         : (idlink ? allow3id : allow3i),
2647                         declInputLevel, parm))
2648           return 0;
2649       }
2650       if (parm.type == Param::indicatedReservedName + Syntax::rPOSTLINK) {
2651         if (!parseParam(allowLinkSetSpec, declInputLevel, parm))
2652           return 0;
2653         const LinkSet *postlink;
2654         if (parm.type == Param::indicatedReservedName + Syntax::rRESTORE)
2655           linkRule->setPostlinkRestore();
2656         else {
2657           if (parm.type == Param::name)
2658             postlink = lookupCreateLinkSet(parm.token);
2659           else if (parm.type
2660                    == Param::indicatedReservedName + Syntax::rINITIAL)
2661             postlink = defComplexLpd().initialLinkSet();
2662           else
2663             postlink = defComplexLpd().emptyLinkSet();
2664           linkRule->setPostlink(postlink);
2665         }
2666         static AllowedParams
2667           allow4i(Param::dso,
2668                   Param::mdc,
2669                   Param::name,
2670                   Param::nameGroup);
2671         static AllowedParams
2672           allow4id(Param::dso,
2673                    Param::mdc,
2674                    Param::name);
2675         static AllowedParams
2676           allow4e(Param::dso,
2677                   Param::name,
2678                   Param::indicatedReservedName + Syntax::rIMPLIED);
2679         if (!parseParam(isExplicit
2680                         ? allow4e
2681                         : (idlink ? allow4id : allow4i),
2682                         declInputLevel, parm))
2683           return 0;
2684       }
2685       AttributeList attributes;
2686       ConstPtr<AttributeDefinitionList> attDef;
2687       for (size_t i = 0; i < assocElementTypes.size(); i++) {
2688         const ElementType *e = assocElementTypes[i];
2689         if (e) {
2690           if (i == 0)
2691             attDef = defComplexLpd().attributeDef(e);
2692           else if (attDef != defComplexLpd().attributeDef(e))
2693             message(ParserMessages::assocElementDifferentAtts);
2694           // FIXME recover from this
2695         }
2696       }
2697       attributes.init(attDef);
2698       
2699       if (parm.type == Param::dso) {
2700         Boolean netEnabling;
2701         if (!parseAttributeSpec(1, attributes, netEnabling))
2702           return 0;
2703         static AllowedParams
2704           allow5e(Param::name,
2705                   Param::indicatedReservedName + Syntax::rIMPLIED);
2706         if (!parseParam(isExplicit
2707                         ? allow5e
2708                         : (idlink ? allowNameMdc : allowNameNameGroupMdc),
2709                         declInputLevel, parm))
2710           return 0;
2711       }
2712       else
2713         attributes.finish(*this);
2714       linkRule->setLinkAttributes(attributes);
2715       if (isExplicit) {
2716         Boolean resultImplied;
2717         const ElementType *resultType;
2718         AttributeList resultAttributes;
2719         if (!parseResultElementSpec(declInputLevel,
2720                                     parm,
2721                                     idlink,
2722                                     resultImplied,
2723                                     resultType,
2724                                     resultAttributes))
2725           return 0;
2726         if (!resultImplied)
2727           linkRule->setResult(resultType, resultAttributes);
2728       }
2729       // Install the link rule.
2730       if (idlink) {
2731         idLinkRule.setAssocElementTypes(assocElementTypes);
2732         addIdLinkRule(id, idLinkRule);
2733       }
2734       else {
2735         if (!linkSet->defined()) {
2736           for (size_t i = 0; i < assocElementTypes.size(); i++)
2737             if (assocElementTypes[i])
2738               addLinkRule(linkSet, assocElementTypes[i], linkRuleResource);
2739         }
2740       }
2741     }
2742   } while (parm.type != Param::mdc);
2743   if (linkSet)
2744     linkSet->setDefined();
2745   if (currentMarkup()) {
2746     if (idlink)
2747       eventHandler().idLinkDecl(new (eventAllocator())
2748                                 IdLinkDeclEvent(defComplexLpdPointer(),
2749                                                 markupLocation(),
2750                                                 currentMarkup()));
2751     else
2752       eventHandler().linkDecl(new (eventAllocator())
2753                               LinkDeclEvent(linkSet,
2754                                             defComplexLpdPointer(),
2755                                             markupLocation(),
2756                                             currentMarkup()));
2757   }
2758   return 1;
2759 }
2760
2761 void Parser::addIdLinkRule(const StringC &id,
2762                            IdLinkRule &rule)
2763 {
2764   IdLinkRuleGroup *group = defComplexLpd().lookupCreateIdLink(id);
2765   size_t nRules = group->nLinkRules();
2766   if ((nRules == 1 && group->linkRule(0).attributes().nSpec() == 0)
2767       || nRules >= 1 && rule.attributes().nSpec() == 0)
2768     message(ParserMessages::multipleIdLinkRuleAttribute,
2769             StringMessageArg(id));
2770   group->addLinkRule(rule);
2771 }
2772
2773 void Parser::addLinkRule(LinkSet *linkSet,
2774                          const ElementType *sourceElement,
2775                          const ConstPtr<SourceLinkRuleResource> &linkRule)
2776 {
2777   size_t nRules = linkSet->nLinkRules(sourceElement);
2778   if ((nRules == 1
2779        && linkSet->linkRule(sourceElement, 0).attributes().nSpec() == 0)
2780       || nRules >= 1 && linkRule->attributes().nSpec() == 0)
2781     message(ParserMessages::multipleLinkRuleAttribute,
2782             StringMessageArg(sourceElement->name()));
2783   linkSet->addLinkRule(sourceElement, linkRule);
2784 }
2785
2786 class ResultAttributeSpecModeSetter {
2787 public:
2788   ResultAttributeSpecModeSetter(ParserState *state) : state_(state) {
2789     state_->setResultAttributeSpecMode();
2790   }
2791   ~ResultAttributeSpecModeSetter() { clear(); }
2792   void clear() {
2793     if (state_) {
2794       state_->clearResultAttributeSpecMode();
2795       state_ = 0;
2796     }
2797   }
2798 private:
2799   ParserState *state_;
2800 };
2801
2802 Boolean Parser::parseResultElementSpec(unsigned declInputLevel,
2803                                        Param &parm,
2804                                        Boolean idlink,
2805                                        Boolean &implied,
2806                                        const ElementType *&resultType,
2807                                        AttributeList &attributes)
2808 {
2809   if (parm.type == Param::indicatedReservedName + Syntax::rIMPLIED) {
2810     if (!parseParam(idlink ? allowNameMdc : allowExplicitLinkRuleMdc,
2811                     declInputLevel, parm))
2812       return 0;
2813     implied = 1;
2814   }
2815   else {
2816     implied = 0;
2817     resultType = lookupResultElementType(parm.token);
2818     static AllowedParams
2819       allow(Param::dso,
2820             Param::mdc,
2821             Param::name,
2822             Param::nameGroup,
2823             Param::indicatedReservedName + Syntax::rIMPLIED);
2824     static AllowedParams
2825       allowNameDsoMdc(Param::dso,
2826                       Param::mdc,
2827                       Param::name);
2828     if (!parseParam(idlink ? allowNameDsoMdc : allow,
2829                     declInputLevel, parm))
2830       return 0;
2831     ConstPtr<AttributeDefinitionList> attDef;
2832     if (resultType)
2833       attDef = resultType->attributeDef();
2834     attributes.init(attDef);
2835     if (parm.type == Param::dso) {
2836       ResultAttributeSpecModeSetter modeSetter(this);
2837       Boolean netEnabling;
2838       if (!parseAttributeSpec(1, attributes, netEnabling))
2839         return 0;
2840       modeSetter.clear();
2841       if (attributes.nSpec() == 0)
2842         message(ParserMessages::emptyResultAttributeSpec);
2843       if (!parseParam(idlink ? allowNameMdc : allowExplicitLinkRuleMdc,
2844                       declInputLevel, parm))
2845         return 0;
2846     }
2847     else {
2848       // For entity and notation attributes.
2849       ResultAttributeSpecModeSetter modeSetter(this);
2850       attributes.finish(*this);
2851       modeSetter.clear();
2852     }
2853   }
2854   return 1;
2855 }
2856
2857 const ElementType *Parser::lookupResultElementType(const StringC &name)
2858 {
2859   const Dtd *dtd = defComplexLpd().resultDtd().pointer();
2860   if (!dtd)
2861     return 0;
2862   const ElementType *e = dtd->lookupElementType(name);
2863   if (!e)
2864     message(ParserMessages::noSuchResultElement, StringMessageArg(name));
2865   return e;
2866 }
2867
2868 Boolean Parser::parseUselinkDecl()
2869 {
2870   unsigned declInputLevel = inputLevel();
2871   Param parm;
2872   if (!parseParam(allowLinkSetSpec, declInputLevel, parm))
2873     return 0;
2874   Param parm2;
2875   if (!parseParam(allowName, declInputLevel, parm2))
2876     return 0;
2877   StringC linkType;
2878   parm2.token.swap(linkType);
2879   if (!parseParam(allowMdc, declInputLevel, parm2))
2880     return 0;
2881   ConstPtr<Lpd> lpd = lookupLpd(linkType);
2882   if (lpd.isNull()) 
2883     message(ParserMessages::uselinkBadLinkType, StringMessageArg(linkType));
2884   else if (lpd->type() == Lpd::simpleLink)
2885     message(ParserMessages::uselinkSimpleLpd, StringMessageArg(linkType));
2886   else {
2887     const ComplexLpd *complexLpd = (const ComplexLpd *)lpd.pointer();
2888     const LinkSet *linkSet;
2889     Boolean restore = 0;
2890     if (parm.type == Param::name) {
2891       linkSet = complexLpd->lookupLinkSet(parm.token);
2892       if (!linkSet) {
2893         message(ParserMessages::uselinkBadLinkSet,
2894                 StringMessageArg(complexLpd->name()),
2895                 StringMessageArg(parm.token));
2896         return 1;
2897       }
2898     }
2899     else if (parm.type == Param::indicatedReservedName + Syntax::rINITIAL)
2900       linkSet = complexLpd->initialLinkSet();
2901     else if (parm.type == Param::indicatedReservedName + Syntax::rEMPTY)
2902       linkSet = complexLpd->emptyLinkSet();
2903     else {
2904       linkSet = 0;
2905       restore = 1;
2906     }
2907     if (lpd->active())
2908       eventHandler().uselink(new (eventAllocator())
2909                              UselinkEvent(lpd, linkSet,
2910                                           restore, markupLocation(),
2911                                           currentMarkup()));
2912     else
2913       eventHandler().ignoredMarkup(new (eventAllocator())
2914                                    IgnoredMarkupEvent(markupLocation(),
2915                                                       currentMarkup()));
2916   }
2917   return 1;
2918 }
2919
2920 LinkSet *Parser::lookupCreateLinkSet(const StringC &name)
2921 {
2922   LinkSet *linkSet = defComplexLpd().lookupLinkSet(name);
2923   if (!linkSet) {
2924     linkSet = new LinkSet(name, defComplexLpd().sourceDtd().pointer());
2925     defComplexLpd().insertLinkSet(linkSet);
2926   }
2927   return linkSet;
2928 }
2929
2930 Boolean Parser::parseMarkedSectionDeclStart()
2931 {
2932   if (markedSectionLevel() == syntax().taglvl())
2933     message(ParserMessages::markedSectionLevel,
2934             NumberMessageArg(syntax().taglvl()));
2935   if (markedSectionSpecialLevel() > 0) {
2936     startMarkedSection(markupLocation());
2937     if (inInstance()
2938         ? eventsWanted().wantMarkedSections()
2939         : eventsWanted().wantPrologMarkup())
2940       eventHandler().ignoredChars(new (eventAllocator())
2941                                   IgnoredCharsEvent(currentInput()->currentTokenStart(),
2942                                                     currentInput()->currentTokenLength(),
2943                                                     currentLocation(),
2944                                                     0));
2945                                   
2946     return 1;
2947   }
2948   if (startMarkup(inInstance()
2949                   ? eventsWanted().wantMarkedSections()
2950                   : eventsWanted().wantPrologMarkup(),
2951                   currentLocation())) {
2952     currentMarkup()->addDelim(Syntax::dMDO);
2953     currentMarkup()->addDelim(Syntax::dDSO);
2954   }
2955   unsigned declInputLevel = inputLevel();
2956   static AllowedParams allowStatusDso(Param::dso,
2957                                       Param::reservedName + Syntax::rCDATA,
2958                                       Param::reservedName + Syntax::rRCDATA,
2959                                       Param::reservedName + Syntax::rIGNORE,
2960                                       Param::reservedName + Syntax::rINCLUDE,
2961                                       Param::reservedName + Syntax::rTEMP);
2962   Param parm;
2963   MarkedSectionEvent::Status status = MarkedSectionEvent::include;
2964   for (;;) {
2965     if (!parseParam(allowStatusDso, declInputLevel, parm))
2966       return 0;
2967     if (parm.type == Param::dso)
2968       break;
2969     switch (parm.type) {
2970     case Param::reservedName + Syntax::rCDATA:
2971       if (status < MarkedSectionEvent::cdata)
2972         status = MarkedSectionEvent::cdata;
2973       break;
2974     case Param::reservedName + Syntax::rRCDATA:
2975       if (status < MarkedSectionEvent::rcdata)
2976         status = MarkedSectionEvent::rcdata;
2977       break;
2978     case Param::reservedName + Syntax::rIGNORE:
2979       if (status < MarkedSectionEvent::ignore)
2980         status = MarkedSectionEvent::ignore;
2981       break;
2982     }
2983   }
2984   // FIXME this disallows
2985   // <!entity % e "include [ stuff ">
2986   // ...
2987   // <![ %e; ]]>
2988   // which I think is legal.
2989
2990   if (inputLevel() > declInputLevel)
2991     message(ParserMessages::parameterEntityNotEnded);
2992   switch (status) {
2993   case MarkedSectionEvent::include:
2994     startMarkedSection(markupLocation());
2995     break;
2996   case MarkedSectionEvent::cdata:
2997     startSpecialMarkedSection(cmsMode, markupLocation());
2998     break;
2999   case MarkedSectionEvent::rcdata:
3000     startSpecialMarkedSection(rcmsMode, markupLocation());
3001     break;
3002   case MarkedSectionEvent::ignore:
3003     startSpecialMarkedSection(imsMode, markupLocation());
3004     break;
3005   }
3006   if (currentMarkup())
3007     eventHandler().markedSectionStart(new (eventAllocator())
3008                                       MarkedSectionStartEvent(status,
3009                                                               markupLocation(),
3010                                                               currentMarkup()));
3011   return 1;
3012 }
3013
3014 void Parser::handleMarkedSectionEnd()
3015 {
3016   if (markedSectionLevel() == 0)
3017     message(ParserMessages::markedSectionEnd);
3018   else {
3019     if (inInstance()
3020         ? eventsWanted().wantMarkedSections()
3021         : eventsWanted().wantPrologMarkup()) {
3022       if (markedSectionSpecialLevel() > 1)
3023         eventHandler().ignoredChars(new (eventAllocator())
3024                                     IgnoredCharsEvent(currentInput()->currentTokenStart(),
3025                                                       currentInput()->currentTokenLength(),
3026                                                       currentLocation(),
3027                                                       0));
3028       else {
3029         MarkedSectionEvent::Status status;
3030         switch (currentMode()) {
3031         case cmsMode:
3032           status = MarkedSectionEvent::cdata;
3033           break;
3034         case rcmsMode:
3035           status = MarkedSectionEvent::rcdata;
3036           break;
3037         case imsMode:
3038           status = MarkedSectionEvent::ignore;
3039           break;
3040         default:
3041           status = MarkedSectionEvent::include;
3042           break;
3043         }
3044         startMarkup(1, currentLocation());
3045         currentMarkup()->addDelim(Syntax::dMSC);
3046         currentMarkup()->addDelim(Syntax::dMDC);
3047         eventHandler().markedSectionEnd(new (eventAllocator())
3048                                         MarkedSectionEndEvent(status,
3049                                                               markupLocation(),
3050                                                               currentMarkup()));
3051       }
3052     }
3053     endMarkedSection();
3054   }
3055 }
3056
3057 void Parser::emptyCommentDecl()
3058 {
3059   if (startMarkup(eventsWanted().wantCommentDecls(), currentLocation())) {
3060     currentMarkup()->addDelim(Syntax::dMDO);
3061     currentMarkup()->addDelim(Syntax::dMDC);
3062     eventHandler().commentDecl(new (eventAllocator())
3063                                CommentDeclEvent(markupLocation(),
3064                                                 currentMarkup()));
3065   }
3066 }
3067
3068 Boolean Parser::parseCommentDecl()
3069 {
3070   if (startMarkup(inInstance()
3071                   ? eventsWanted().wantCommentDecls()
3072                   : eventsWanted().wantPrologMarkup(),
3073                   currentLocation()))
3074     currentMarkup()->addDelim(Syntax::dMDO);
3075   if (!parseComment(comMode))
3076     return 0;
3077   for (;;) {
3078     Token token = getToken(mdMode);
3079     switch (token) {
3080     case tokenS:
3081       if (currentMarkup())
3082         currentMarkup()->addS(currentChar());
3083       break;
3084     case tokenCom:
3085       if (!parseComment(comMode))
3086         return 0;
3087       break;
3088     case tokenMdc:
3089       if (currentMarkup())
3090         currentMarkup()->addDelim(Syntax::dMDC);
3091       goto done;
3092     case tokenEe:
3093       message(ParserMessages::declarationLevel);
3094       return 0;
3095     case tokenUnrecognized:
3096       if (reportNonSgmlCharacter())
3097         break;
3098       // braces to work round Sun C++ 4.0 bug
3099       {
3100         message(ParserMessages::commentDeclarationCharacter,
3101                 StringMessageArg(currentToken()),
3102                 markupLocation());
3103       }
3104       return 0;
3105     default:
3106       // braces to work round Sun C++ 4.0 bug
3107       {
3108         message(ParserMessages::commentDeclInvalidToken,
3109                 TokenMessageArg(token, mdMode, syntaxPointer(), sdPointer()),
3110                 markupLocation());
3111       }
3112       return 0;
3113     }
3114   }
3115  done:
3116   if (currentMarkup())
3117     eventHandler().commentDecl(new (eventAllocator())
3118                                CommentDeclEvent(markupLocation(),
3119                                                 currentMarkup()));
3120   return 1;
3121 }
3122
3123 Boolean Parser::parseAfdrDecl()
3124 {
3125   unsigned declInputLevel = inputLevel();
3126   static AllowedParams allowMinimumLiteral(Param::minimumLiteral);
3127   Param parm;
3128   setHadAfdrDecl();
3129   if (!parseParam(allowMinimumLiteral, declInputLevel, parm))
3130     return 0;
3131   if (parm.literalText.string() != sd().execToDoc("ISO/IEC 10744:1992"))
3132     message(ParserMessages::afdrVersion,
3133             StringMessageArg(parm.literalText.string()));
3134   if (!parseParam(allowMdc, declInputLevel, parm))
3135     return 0;
3136   eventHandler().ignoredMarkup(new (eventAllocator())
3137                                IgnoredMarkupEvent(markupLocation(),
3138                                                   currentMarkup()));
3139   return 1;
3140 }
3141
3142 #ifdef SP_NAMESPACE
3143 }
3144 #endif