sgml/src/SGMLCP.m3


MODULE SGMLCP EXPORTS SGMLC ;
Parser generated by m3coco

IMPORT Rd, Thread ;

IMPORT SGML, SGMLRep, RefSeq, TextSeq, TextRefTbl, Atom, SGMLCScanner, FSM;

CONST
  minErrDist = 2 ;  (* minimal distance (good tokens) between two errors *)

TYPE
  SymSetRange = [0 .. 8] ;

CONST
  SymSet = ARRAY SymSetRange OF SymbolSet {
      SymbolSet{Symbol.Eof},
      SymbolSet{Symbol.AttListTag, Symbol.AttValueData, Symbol.CData,
                        Symbol.CharRef, Symbol.Coma, Symbol.Commenttk,
                        Symbol.DQuote, Symbol.DashImplied, Symbol.DashPCData,
                        Symbol.DashRequired, Symbol.DashFixed, Symbol.DocTypeTag,
                        Symbol.ElementTag, Symbol.EmptyElementEndTag,
                        Symbol.EndElementTag, Symbol.EntityTag,
                        Symbol.EntityValueData, Symbol.Equal, Symbol.HexCharRef,
                        Symbol.IntMark, Symbol.LP, Symbol.LSB, Symbol.Minus,
                        Symbol.NonKeywordName, Symbol.NmToken,
                        Symbol.NotationTag, Symbol.PCDataChunk, Symbol.White,
                        Symbol.PItk, Symbol.PEReference, Symbol.Percent,
                        Symbol.Plus, Symbol.PlusLP, Symbol.Quote, Symbol.RB,
                        Symbol.RP, Symbol.RSB, Symbol.EntityRef,
                        Symbol.StartCSect, Symbol.StartElementTag, Symbol.Star,
                        Symbol.Vertical, Symbol.EMPTYkw, Symbol.ANYkw,
                        Symbol.CDATAkw, Symbol.IDkw, Symbol.IDREFkw,
                        Symbol.IDREFSkw, Symbol.ENTITYkw, Symbol.ENTITIESkw,
                        Symbol.NAMEkw, Symbol.NAMESkw, Symbol.NMTOKENkw,
                        Symbol.NMTOKENSkw, Symbol.NOTATIONkw, Symbol.NUMBERkw,
                        Symbol.NUMBERSkw, Symbol.SYSTEMkw, Symbol.PUBLICkw,
                        Symbol.NDATAkw, Symbol.IGNOREkw, Symbol.INCLUDEkw,
                        Symbol.SGMLDECLkw, Symbol.DOCTYPEkw, Symbol.CATALOGkw,
                        Symbol.Okw, Symbol.Undef},
      SymbolSet{Symbol.AttListTag, Symbol.CData, Symbol.CharRef,
                        Symbol.Commenttk, Symbol.ElementTag,
                        Symbol.EndElementTag, Symbol.EntityTag,
                        Symbol.HexCharRef, Symbol.NotationTag,
                        Symbol.PCDataChunk, Symbol.White, Symbol.PItk,
                        Symbol.EntityRef, Symbol.StartCSect,
                        Symbol.StartElementTag},
      SymbolSet{Symbol.NonKeywordName, Symbol.EMPTYkw, Symbol.ANYkw,
                        Symbol.CDATAkw, Symbol.IDkw, Symbol.IDREFkw,
                        Symbol.IDREFSkw, Symbol.ENTITYkw, Symbol.ENTITIESkw,
                        Symbol.NAMEkw, Symbol.NAMESkw, Symbol.NMTOKENkw,
                        Symbol.NMTOKENSkw, Symbol.NOTATIONkw, Symbol.NUMBERkw,
                        Symbol.NUMBERSkw, Symbol.SYSTEMkw, Symbol.PUBLICkw,
                        Symbol.NDATAkw, Symbol.IGNOREkw, Symbol.INCLUDEkw,
                        Symbol.SGMLDECLkw, Symbol.DOCTYPEkw, Symbol.CATALOGkw,
                        Symbol.Okw},
      SymbolSet{Symbol.DQuote, Symbol.DashFixed, Symbol.NonKeywordName,
                        Symbol.NmToken, Symbol.Quote, Symbol.EMPTYkw,
                        Symbol.ANYkw, Symbol.CDATAkw, Symbol.IDkw,
                        Symbol.IDREFkw, Symbol.IDREFSkw, Symbol.ENTITYkw,
                        Symbol.ENTITIESkw, Symbol.NAMEkw, Symbol.NAMESkw,
                        Symbol.NMTOKENkw, Symbol.NMTOKENSkw, Symbol.NOTATIONkw,
                        Symbol.NUMBERkw, Symbol.NUMBERSkw, Symbol.SYSTEMkw,
                        Symbol.PUBLICkw, Symbol.NDATAkw, Symbol.IGNOREkw,
                        Symbol.INCLUDEkw, Symbol.SGMLDECLkw, Symbol.DOCTYPEkw,
                        Symbol.CATALOGkw, Symbol.Okw},
      SymbolSet{Symbol.IDkw, Symbol.IDREFkw, Symbol.IDREFSkw,
                        Symbol.ENTITYkw, Symbol.ENTITIESkw, Symbol.NAMEkw,
                        Symbol.NAMESkw, Symbol.NMTOKENkw, Symbol.NMTOKENSkw,
                        Symbol.NUMBERkw, Symbol.NUMBERSkw},
      SymbolSet{Symbol.AttListTag, Symbol.Commenttk, Symbol.ElementTag,
                        Symbol.EntityTag, Symbol.NotationTag, Symbol.White,
                        Symbol.PItk, Symbol.StartCSect},
      SymbolSet{Symbol.CData, Symbol.CharRef, Symbol.EndElementTag,
                        Symbol.HexCharRef, Symbol.PCDataChunk, Symbol.EntityRef,
                        Symbol.StartElementTag},
      SymbolSet{Symbol.NonKeywordName, Symbol.NmToken, Symbol.EMPTYkw,
                        Symbol.ANYkw, Symbol.CDATAkw, Symbol.IDkw,
                        Symbol.IDREFkw, Symbol.IDREFSkw, Symbol.ENTITYkw,
                        Symbol.ENTITIESkw, Symbol.NAMEkw, Symbol.NAMESkw,
                        Symbol.NMTOKENkw, Symbol.NMTOKENSkw, Symbol.NOTATIONkw,
                        Symbol.NUMBERkw, Symbol.NUMBERSkw, Symbol.SYSTEMkw,
                        Symbol.PUBLICkw, Symbol.NDATAkw, Symbol.IGNOREkw,
                        Symbol.INCLUDEkw, Symbol.SGMLDECLkw, Symbol.DOCTYPEkw,
                        Symbol.CATALOGkw, Symbol.Okw}
  } ;

  PragmaSet = SymbolSet {  } ;

REVEAL
  Parser = PublicP BRANDED OBJECT
             s       : Scanner ;
             err     : ErrHandler ;
             cur     : ScanSymbol ; (* current symbol *)
             next    : ScanSymbol ; (* next [lookahead] symbol *)
             errDist : CARDINAL     (* number of tokens since last err *)
           OVERRIDES
             init   := Init ;
             error  := SemError ;
             string := GetString ;
             name   := GetName ;
             offset := GetOffset ;
             line   := GetLine ;
             column := GetColumn ;
             length := GetLength ;
             parse  := Parse
           END ;

PROCEDURE SemError(p : Parser ; msg : TEXT) =
BEGIN
  IF (p.errDist >= minErrDist) THEN
    p.err.error(p.cur.line, p.cur.column, msg)
  END ;
  p.errDist := 0
END SemError ;

PROCEDURE GetString(p : Parser) : TEXT =
BEGIN
  RETURN p.cur.string
END GetString ;

PROCEDURE GetName(p : Parser) : TEXT =
BEGIN
  RETURN p.cur.name
END GetName ;

PROCEDURE GetOffset(p : Parser) : CARDINAL =
BEGIN
  RETURN p.cur.offset
END GetOffset ;

PROCEDURE GetLine(p : Parser) : CARDINAL =
BEGIN
  RETURN p.cur.line
END GetLine ;

PROCEDURE GetColumn(p : Parser) : CARDINAL =
BEGIN
  RETURN p.cur.column
END GetColumn ;

PROCEDURE GetLength(p : Parser) : CARDINAL =
BEGIN
  RETURN p.cur.length
END GetLength ;

PROCEDURE SynError(p : Parser ; msg : TEXT) =
BEGIN
  IF (p.errDist >= minErrDist) THEN
    p.err.error(p.next.line, p.next.column, msg)
  END ;
  p.errDist := 0
END SynError ;

PROCEDURE Get(p : Parser) RAISES { Rd.Failure, Thread.Alerted } =
BEGIN
  p.cur := p.next ;
  REPEAT
    p.s.get(p.next) ;
    IF (p.next.sym IN PragmaSet) THEN
      VAR tmp := p.cur ;
      BEGIN
        p.cur := p.next ;

        p.cur := tmp
      END
    END
  UNTIL (NOT (p.next.sym IN PragmaSet)) ;
  INC(p.errDist)
END Get ;

PROCEDURE Expect(p : Parser ; sym : Symbol) RAISES { Rd.Failure, Thread.Alerted } =
BEGIN
  IF (p.next.sym = sym) THEN
    Get(p)
  ELSE
    SynError(p, "expected '" & SymbolName[sym] &
                  "', got '" & SymbolName[p.next.sym] & "'")
  END
END Expect ;

PROCEDURE ExpectWeak(p : Parser ; sym : Symbol ; follow : SymSetRange) = BEGIN IF (p.next.sym = sym) THEN Get(p) ELSE SynError(p, expected ' & SymbolName[sym] & ', got ' & SymbolName[p.next.sym] & ') ; WHILE (NOT (p.next.sym IN SymSet[follow])) DO Get(p) END END END ExpectWeak ;

PROCEDURE WeakSeparator(p : Parser ; sym : Symbol ; syFol, repFol : SymSetRange) : BOOLEAN = VAR s : SymbolSet ; BEGIN IF (p.next.sym = sym) THEN Get(p) ; RETURN TRUE ELSIF (p.next.sym IN SymSet[repFol]) THEN RETURN FALSE ELSE s := SymSet[0] + SymSet[syFol] + SymSet[repFol] ; SynError(p, expected ' & SymbolName[sym] & ', got ' & SymbolName[p.next.sym] & ') ; WHILE (NOT (p.next.sym IN s)) DO Get(p) END ; RETURN (p.next.sym IN SymSet[syFol]) END END WeakSeparator ;

PROCEDURE ParseNDataDecl(p : Parser ; VAR name: TEXT) RAISES { Rd.Failure, Thread.Alerted } =
BEGIN
  Expect(p, Symbol.NDATAkw) ;
  ParseName(p, name) ;
END ParseNDataDecl ;

PROCEDURE ParseEntityDef(p : Parser ; parser: SGML.Parser; e: REF SGML.Entity) RAISES { Rd.Failure, Thread.Alerted } =
  VAR name, t1, t2: TEXT := NIL; public := FALSE;
BEGIN
  IF (p.next.sym = Symbol.DQuote) OR
     (p.next.sym = Symbol.Quote) OR
     (p.next.sym = Symbol.CDATAkw) THEN
    IF (p.next.sym = Symbol.CDATAkw) THEN
      Get(p) ;
    END ;
    ParseEntityValue(p, parser,t1) ;
    e.internalText := t1 ;
  ELSIF (p.next.sym = Symbol.SYSTEMkw) OR
        (p.next.sym = Symbol.PUBLICkw) THEN
    ParseExternalId(p, public,t1,t2) ;
    e.externalId := SGML.ExternalId{t1,t2,NIL} ;
    IF (p.next.sym = Symbol.NDATAkw) THEN
      ParseNDataDecl(p, name) ;
      e.notation := SGML.Notation{name,SGML.ExternalId{t1,t2,NIL}};
      e.externalId := SGML.ExternalId{NIL,NIL,NIL}
       ;
    END ;
  ELSE SynError(p, "unexpected '" & SymbolName[p.next.sym] & "' in EntityDef") ;
  END ;
END ParseEntityDef ;

PROCEDURE ParseIgnoreSect(p : Parser ; parser: SGML.Parser) RAISES { Rd.Failure, Thread.Alerted } =
  VAR t, s := ""; startPos, nb := 0;
BEGIN
  Expect(p, Symbol.IGNOREkw) ;
  IF NOT parser.markup THEN
    parser.application.markedSectionStart(SGML.MarkedSectionStartEvent{
        parser.p.cur.offset,SGML.MarkedSectionStatus.Ignore,
        SGMLRep.IgnoreParam});
  END
   ;
  Expect(p, Symbol.LSB) ;
  WHILE (p.next.sym IN SymSet[1]) DO
    Get(p) ;
    t := p.string() ;
    s := s & t; INC(nb);
    IF nb = 0 THEN startPos := parser.p.cur.offset;
    ELSIF nb >= 10 THEN
      IF NOT parser.markup THEN
        parser.application.ignoredChars(SGML.IgnoredCharsEvent{startPos,s});
      END;
      nb := 0;
      s := "";
    END
     ;
  END ;
  Expect(p, Symbol.EndCSect) ;
  IF NOT parser.markup THEN
    parser.application.markedSectionEnd(SGML.MarkedSectionEndEvent{
        parser.p.cur.offset,SGML.MarkedSectionStatus.Ignore});
  END
   ;
END ParseIgnoreSect ;

PROCEDURE ParseIncludeSect(p : Parser ; parser: SGML.Parser) RAISES { Rd.Failure, Thread.Alerted } =
BEGIN
  Expect(p, Symbol.INCLUDEkw) ;
  IF NOT parser.markup THEN
    parser.application.markedSectionStart(SGML.MarkedSectionStartEvent{
        parser.p.cur.offset,SGML.MarkedSectionStatus.Include,
        SGMLRep.IncludeParam});
  END
   ;
  Expect(p, Symbol.LSB) ;
  WHILE (p.next.sym IN SymSet[2]) DO
    IF (p.next.sym = Symbol.AttListTag) OR
       (p.next.sym = Symbol.ElementTag) OR
       (p.next.sym = Symbol.EntityTag) OR
       (p.next.sym = Symbol.NotationTag) THEN
      ParseMarkupDecl(p, parser) ;
    ELSIF (p.next.sym = Symbol.StartCSect) THEN
      ParseConditionalSect(p, parser) ;
    ELSIF (p.next.sym = Symbol.Commenttk) OR
          (p.next.sym = Symbol.White) OR
          (p.next.sym = Symbol.PItk) THEN
      ParseMisc(p, parser) ;
    ELSE
      ParseContent(p, parser) ;
    END ;
  END ;
  Expect(p, Symbol.EndCSect) ;
  IF NOT parser.markup THEN
    parser.application.markedSectionEnd(SGML.MarkedSectionEndEvent{
        parser.p.cur.offset,SGML.MarkedSectionStatus.Include});
  END
   ;
END ParseIncludeSect ;

PROCEDURE ParseEnumeration(p : Parser ; VAR r: REFANY) RAISES { Rd.Failure, Thread.Alerted } =
  VAR t: TEXT; s := NEW(SGMLRep.Enumeration).init();
BEGIN
  Expect(p, Symbol.LP) ;
  IF (p.next.sym IN SymSet[3]) THEN
    ParseName(p, t) ;
  ELSIF (p.next.sym = Symbol.NmToken) THEN
    Get(p) ;
    t := p.string() ;
  ELSE SynError(p, "unexpected '" & SymbolName[p.next.sym] & "' in Enumeration") ;
  END ;
  r := s; s.addhi(t) ;
  WHILE (p.next.sym = Symbol.Vertical) DO
    Get(p) ;
    IF (p.next.sym IN SymSet[3]) THEN
      ParseName(p, t) ;
    ELSIF (p.next.sym = Symbol.NmToken) THEN
      Get(p) ;
      t := p.string() ;
    ELSE SynError(p, "unexpected '" & SymbolName[p.next.sym] & "' in Enumeration") ;
    END ;
    s.addhi(t) ;
  END ;
  Expect(p, Symbol.RP) ;
END ParseEnumeration ;

PROCEDURE ParseNotationType(p : Parser ; VAR r: REFANY) RAISES { Rd.Failure, Thread.Alerted } =
  VAR t: TEXT; s := NEW(SGMLRep.NotationType).init();
BEGIN
  Expect(p, Symbol.NOTATIONkw) ;
  Expect(p, Symbol.LP) ;
  ParseName(p, t) ;
  r := s; s.addhi(t) ;
  WHILE (p.next.sym = Symbol.Vertical) DO
    Get(p) ;
    ParseName(p, t) ;
    s.addhi(t) ;
  END ;
  Expect(p, Symbol.RP) ;
END ParseNotationType ;

PROCEDURE ParseEnumeratedType(p : Parser ; VAR r: REFANY) RAISES { Rd.Failure, Thread.Alerted } =
BEGIN
  IF (p.next.sym = Symbol.NOTATIONkw) THEN
    ParseNotationType(p, r) ;
  ELSIF (p.next.sym = Symbol.LP) THEN
    ParseEnumeration(p, r) ;
  ELSE SynError(p, "unexpected '" & SymbolName[p.next.sym] & "' in EnumeratedType") ;
  END ;
END ParseEnumeratedType ;

PROCEDURE ParseTokenizedType(p : Parser ; VAR r: REFANY) RAISES { Rd.Failure, Thread.Alerted } =
  VAR t: TEXT;
BEGIN
  CASE p.next.sym OF
    Symbol.IDkw =>
      Get(p) ;
      t := p.string() ;
  | Symbol.IDREFkw =>
      Get(p) ;
      t := p.string() ;
  | Symbol.IDREFSkw =>
      Get(p) ;
      t := p.string() ;
  | Symbol.ENTITYkw =>
      Get(p) ;
      t := p.string() ;
  | Symbol.ENTITIESkw =>
      Get(p) ;
      t := p.string() ;
  | Symbol.NAMEkw =>
      Get(p) ;
      t := p.string() ;
  | Symbol.NAMESkw =>
      Get(p) ;
      t := p.string() ;
  | Symbol.NMTOKENkw =>
      Get(p) ;
      t := p.string() ;
  | Symbol.NMTOKENSkw =>
      Get(p) ;
      t := p.string() ;
  | Symbol.NUMBERkw =>
      Get(p) ;
      t := p.string() ;
  | Symbol.NUMBERSkw =>
      Get(p) ;
      t := p.string() ;
  ELSE SynError(p, "unexpected '" & SymbolName[p.next.sym] & "' in TokenizedType") ;
  END ;
  r:= Atom.FromText(t) ;
END ParseTokenizedType ;

PROCEDURE ParseStringType(p : Parser ; VAR r: REFANY) RAISES { Rd.Failure, Thread.Alerted } =
BEGIN
  Expect(p, Symbol.CDATAkw) ;
  r := Atom.FromText(p.string()) ;
END ParseStringType ;

PROCEDURE ParseDefault(p : Parser ; parser: SGML.Parser; a: SGMLRep.AttributeDesc) RAISES { Rd.Failure, Thread.Alerted } =
BEGIN
  IF (p.next.sym = Symbol.DashRequired) THEN
    Get(p) ;
    a.required := TRUE ;
  ELSIF (p.next.sym = Symbol.DashImplied) THEN
    Get(p) ;
    a.implied := TRUE ;
  ELSIF (p.next.sym IN SymSet[4]) THEN
    IF (p.next.sym = Symbol.DashFixed) THEN
      Get(p) ;
      a.fixed := TRUE ;
    END ;
    ParseAttValue(p, parser) ;
    a.default := NEW(REF ARRAY OF SGML.CdataChunk,parser.nbData);
    a.default^ := SUBARRAY(parser.dataChunks^,0,parser.nbData)
     ;
  ELSE SynError(p, "unexpected '" & SymbolName[p.next.sym] & "' in Default") ;
  END ;
END ParseDefault ;

PROCEDURE ParseAttType(p : Parser ; VAR r: REFANY) RAISES { Rd.Failure, Thread.Alerted } =
BEGIN
  IF (p.next.sym = Symbol.CDATAkw) THEN
    ParseStringType(p, r) ;
  ELSIF (p.next.sym IN SymSet[5]) THEN
    ParseTokenizedType(p, r) ;
  ELSIF (p.next.sym = Symbol.LP) OR
        (p.next.sym = Symbol.NOTATIONkw) THEN
    ParseEnumeratedType(p, r) ;
  ELSE SynError(p, "unexpected '" & SymbolName[p.next.sym] & "' in AttType") ;
  END ;
END ParseAttType ;

PROCEDURE ParseAttDef(p : Parser ; parser: SGML.Parser; a: SGMLRep.AttributeDesc) RAISES { Rd.Failure, Thread.Alerted } =
  VAR t: TEXT; type: REFANY;
BEGIN
  ParseCIName(p, t) ;
  ParseAttType(p, type) ;
  ParseDefault(p, parser,a) ;
  a.name := t; a.content := type ;
END ParseAttDef ;

PROCEDURE ParseCP(p : Parser ; VAR r: REFANY; VAR m: FSM.T;) RAISES { Rd.Failure, Thread.Alerted } =
  VAR t: TEXT; m1, m2: FSM.T;
BEGIN
  IF (p.next.sym IN SymSet[3]) THEN
    ParseCIName(p, t) ;
    r := t; FSM.New(m,Atom.FromText(t)) ;
  ELSIF (p.next.sym = Symbol.LP) THEN
    ParseChoiceSeq(p, r,m) ;
  ELSIF (p.next.sym = Symbol.DashPCData) THEN
    Get(p) ;
    r := SGMLRep.PCDataAtom; FSM.New(m,SGMLRep.PCDataAtom) ;
  ELSE SynError(p, "unexpected '" & SymbolName[p.next.sym] & "' in CP") ;
  END ;
  IF (p.next.sym = Symbol.IntMark) OR
     (p.next.sym = Symbol.Plus) OR
     (p.next.sym = Symbol.Star) THEN
    IF (p.next.sym = Symbol.IntMark) THEN
      Get(p) ;
      r := NEW(SGMLRep.Optional, r := r);
      FSM.Optional(m,m1); m := m1
       ;
    ELSIF (p.next.sym = Symbol.Star) THEN
      Get(p) ;
      r := NEW(SGMLRep.Repeat, r := r);
      FSM.Repeat(m,m1); m := m1
       ;
    ELSE
      Get(p) ;
      r := NEW(SGMLRep.RepeatPlus, r := r);
      FSM.Copy(m,m1);
      FSM.Repeat(m,m2);
      FSM.Sequence(m1,m2,m)
       ;
    END ;
  END ;
END ParseCP ;

PROCEDURE ParseChoiceSeq(p : Parser ; VAR r: REFANY; VAR m: FSM.T) RAISES { Rd.Failure, Thread.Alerted } =
  VAR r1, r2, r3: REFANY; s: RefSeq.T; m1, m2: FSM.T;
BEGIN
  Expect(p, Symbol.LP) ;
  ParseCP(p, r1,m1) ;
  IF (p.next.sym = Symbol.RP) THEN
    Get(p) ;
    r := r1; m := m1 ;
  ELSIF (p.next.sym = Symbol.Vertical) THEN
    Get(p) ;
    ParseCP(p, r2,m2) ;
    s := NEW(SGMLRep.Choice).init();
    r := s;
    s.addhi(r2);
    FSM.Or(m1,m2,m);
    m1 := m
     ;
    WHILE (p.next.sym = Symbol.Vertical) DO
      Get(p) ;
      ParseCP(p, r3,m2) ;
      s.addhi(r3); FSM.Or(m1,m2,m); m1 := m ;
    END ;
    Expect(p, Symbol.RP) ;
  ELSIF (p.next.sym = Symbol.Coma) THEN
    Get(p) ;
    ParseCP(p, r2,m2) ;
    s := NEW(SGMLRep.Seq).init();
    r := s;
    s.addhi(r2);
    FSM.Sequence(m1,m2,m);
    m1 := m
     ;
    WHILE (p.next.sym = Symbol.Coma) DO
      Get(p) ;
      ParseCP(p, r3,m2) ;
      s.addhi(r3); FSM.Sequence(m1,m2,m); m1 := m ;
    END ;
    Expect(p, Symbol.RP) ;
  ELSE SynError(p, "unexpected '" & SymbolName[p.next.sym] & "' in ChoiceSeq") ;
  END ;
END ParseChoiceSeq ;

PROCEDURE ParseElements(p : Parser ; VAR r: REFANY; VAR m: FSM.T;) RAISES { Rd.Failure, Thread.Alerted } =
  VAR m1, m2: FSM.T;
BEGIN
  ParseChoiceSeq(p, r,m) ;
  IF (p.next.sym = Symbol.IntMark) OR
     (p.next.sym = Symbol.Plus) OR
     (p.next.sym = Symbol.Star) THEN
    IF (p.next.sym = Symbol.IntMark) THEN
      Get(p) ;
      r := NEW(SGMLRep.Optional, r := r);
      FSM.Optional(m,m1); m := m1
       ;
    ELSIF (p.next.sym = Symbol.Star) THEN
      Get(p) ;
      r := NEW(SGMLRep.Repeat, r := r);
      FSM.Repeat(m,m1); m := m1
       ;
    ELSE
      Get(p) ;
      r := NEW(SGMLRep.RepeatPlus, r := r);
      FSM.Copy(m,m1);
      FSM.Repeat(m,m2);
      FSM.Sequence(m1,m2,m)
       ;
    END ;
  END ;
END ParseElements ;

PROCEDURE ParseContentSpec(p : Parser ; VAR r: REFANY; VAR m: FSM.T;) RAISES { Rd.Failure, Thread.Alerted } =
  VAR t: TEXT; m1: FSM.T;
BEGIN
  IF (p.next.sym = Symbol.EMPTYkw) THEN
    Get(p) ;
    r := SGMLRep.EmptyAtom; FSM.New(m,NIL) ;
  ELSIF (p.next.sym = Symbol.ANYkw) THEN
    Get(p) ;
    r := Atom.FromText("ANY"); FSM.NewElse(m1); FSM.Repeat(m1,m) ;
  ELSIF (p.next.sym = Symbol.LP) THEN
    ParseElements(p, r,m) ;
    IF (p.next.sym = Symbol.Minus) THEN
      Get(p) ;
      Expect(p, Symbol.LP) ;
      ParseCIName(p, t) ;
      WHILE (p.next.sym = Symbol.Vertical) DO
        Get(p) ;
        ParseCIName(p, t) ;
      END ;
      Expect(p, Symbol.RP) ;
    END ;
    IF (p.next.sym = Symbol.PlusLP) THEN
      Get(p) ;
      ParseCIName(p, t) ;
      WHILE (p.next.sym = Symbol.Vertical) DO
        Get(p) ;
        ParseCIName(p, t) ;
      END ;
      Expect(p, Symbol.RP) ;
    END ;
  ELSE SynError(p, "unexpected '" & SymbolName[p.next.sym] & "' in ContentSpec") ;
  END ;
END ParseContentSpec ;

PROCEDURE ParseNameChoice(p : Parser ; VAR c: REFANY) RAISES { Rd.Failure, Thread.Alerted } =
  VAR t: TEXT; s: TextSeq.T;
BEGIN
  IF (p.next.sym IN SymSet[3]) THEN
    ParseCIName(p, t) ;
    c := t ;
  ELSIF (p.next.sym = Symbol.LP) THEN
    Get(p) ;
    ParseCIName(p, t) ;
    s := NEW(TextSeq.T).init(); s.addhi(t); c := s ;
    WHILE (p.next.sym = Symbol.Vertical) DO
      Get(p) ;
      ParseCIName(p, t) ;
      s.addhi(t) ;
    END ;
    Expect(p, Symbol.RP) ;
  ELSE SynError(p, "unexpected '" & SymbolName[p.next.sym] & "' in NameChoice") ;
  END ;
END ParseNameChoice ;

PROCEDURE ParseStartElement(p : Parser ; parser: SGML.Parser) RAISES { Rd.Failure, Thread.Alerted } =
  VAR name: TEXT; e: SGML.StartElementEvent;
BEGIN
  Expect(p, Symbol.StartElementTag) ;
  ParseCIName(p, name) ;
  parser.nbAttr := 0 ;
  WHILE (p.next.sym IN SymSet[3]) DO
    ParseAttribute(p, parser) ;
    SGMLRep.IncAttr(parser) ;
  END ;
  IF (p.next.sym = Symbol.RB) THEN
    Get(p) ;
    e.pos := parser.p.cur.offset;
    e.gi := name;
    e.contentType := SGML.ElementContentType.Mixed;
    e.included := FALSE;
    e.attributes := NEW(REF ARRAY OF SGML.Attribute, parser.nbAttr);
    e.attributes^ := SUBARRAY(parser.attributes^, 0, parser.nbAttr);
    SGMLRep.StartElement(parser,e);
    parser.application.startElement(e)
     ;
  ELSIF (p.next.sym = Symbol.EmptyElementEndTag) THEN
    Get(p) ;
    e.pos := parser.p.cur.offset;
    e.gi := name;
    e.contentType := SGML.ElementContentType.Empty;
    e.included := FALSE;
    e.attributes := NEW(REF ARRAY OF SGML.Attribute, parser.nbAttr);
    e.attributes^ := SUBARRAY(parser.attributes^, 0, parser.nbAttr);
    SGMLRep.StartElement(parser,e);
    parser.application.startElement(e);
    parser.application.endElement(SGML.EndElementEvent{parser.p.cur.offset,
        name})
     ;
  ELSE SynError(p, "unexpected '" & SymbolName[p.next.sym] & "' in StartElement") ;
  END ;
END ParseStartElement ;

PROCEDURE ParseEndElement(p : Parser ; parser: SGML.Parser) RAISES { Rd.Failure, Thread.Alerted } =
  VAR name: TEXT;
BEGIN
  Expect(p, Symbol.EndElementTag) ;
  ParseCIName(p, name) ;
  Expect(p, Symbol.RB) ;
  SGMLRep.EndElement(parser,name);
  parser.application.endElement(SGML.EndElementEvent{parser.p.cur.offset,
      name})
   ;
END ParseEndElement ;

PROCEDURE ParseAttribute(p : Parser ; parser: SGML.Parser) RAISES { Rd.Failure, Thread.Alerted } =
  VAR name: TEXT;
BEGIN
  ParseCIName(p, name) ;
  parser.nbData := 0 ;
  IF (p.next.sym = Symbol.Equal) THEN
    Get(p) ;
    ParseAttValue(p, parser) ;
  END ;
  WITH a = parser.attributes[parser.nbAttr] DO
    a := SGML.Attribute{name, SGML.AttributeType.CData,
        SGML.AttributeDefaulted.Specified,
        NEW(REF ARRAY OF SGML.CdataChunk,parser.nbData), NIL, FALSE,
        FALSE, NIL, SGML.Notation{NIL, SGML.ExternalId{NIL,NIL,NIL}}};
    a.cdataChunks^ := SUBARRAY(parser.dataChunks^,0,parser.nbData);
  END
   ;
END ParseAttribute ;

PROCEDURE ParseNotationDecl(p : Parser ; parser: SGML.Parser) RAISES { Rd.Failure, Thread.Alerted } =
  VAR name, t1, t2: TEXT := NIL; public := FALSE;
BEGIN
  Expect(p, Symbol.NotationTag) ;
  ParseName(p, name) ;
  ParseExternalId(p, public,t1,t2) ;
  Expect(p, Symbol.RB) ;
  SGMLRep.AddNotation(parser, NEW(REF SGML.Notation, name := name,
      externalId := SGML.ExternalId{t1,t2,NIL}))
   ;
END ParseNotationDecl ;

PROCEDURE ParseEntityDecl(p : Parser ; parser: SGML.Parser) RAISES { Rd.Failure, Thread.Alerted } =
  VAR e := NEW(REF SGML.Entity); name: TEXT;
BEGIN
  Expect(p, Symbol.EntityTag) ;
  IF (p.next.sym IN SymSet[3]) THEN
    ParseName(p, name) ;
    ParseEntityDef(p, parser,e) ;
    e.declType := SGML.EntityDeclType.General
     ;
  ELSIF (p.next.sym = Symbol.Percent) THEN
    Get(p) ;
    ParseName(p, name) ;
    ParseEntityDef(p, parser,e) ;
    e.declType := SGML.EntityDeclType.Parameter
     ;
  ELSE SynError(p, "unexpected '" & SymbolName[p.next.sym] & "' in EntityDecl") ;
  END ;
  e.name := name;
  e.dataType := SGML.EntityDataType.Sgml;
  SGMLRep.AddEntity(parser,e)
   ;
  Expect(p, Symbol.RB) ;
END ParseEntityDecl ;

PROCEDURE ParseAttListDecl(p : Parser ; parser: SGML.Parser) RAISES { Rd.Failure, Thread.Alerted } =
  VAR
  names: REFANY;
  name: TEXT;
  s: TextSeq.T;
  a: SGMLRep.AttributeDesc;
  attributes := NEW(TextRefTbl.Default).init();

BEGIN
  Expect(p, Symbol.AttListTag) ;
  ParseNameChoice(p, names) ;
  WHILE (p.next.sym IN SymSet[3]) DO
    a := NEW(SGMLRep.AttributeDesc) ;
    ParseAttDef(p, parser,a) ;
    EVAL attributes.put(a.name,a) ;
  END ;
  Expect(p, Symbol.RB) ;
  IF ISTYPE(names,TEXT) THEN
    name := NARROW(names,TEXT);
    SGMLRep.AddAttributes(parser,name,attributes);
  ELSE
    s := NARROW(names,TextSeq.T);
    FOR i := 0 TO s.size() - 1 DO
      name := s.get(i);
      SGMLRep.AddAttributes(parser,name,SGMLRep.CopyTextRefTbl(attributes));
    END;
  END
   ;
END ParseAttListDecl ;

PROCEDURE ParseElementDecl(p : Parser ; parser: SGML.Parser) RAISES { Rd.Failure, Thread.Alerted } =
  VAR c, r: REFANY; name: TEXT; s: TextSeq.T; omitS, omitE := FALSE;
  m: FSM.T;
BEGIN
  Expect(p, Symbol.ElementTag) ;
  ParseNameChoice(p, c) ;
  IF (p.next.sym = Symbol.Minus) OR
     (p.next.sym = Symbol.Okw) THEN
    IF (p.next.sym = Symbol.Minus) THEN
      Get(p) ;
    ELSE
      Get(p) ;
      omitS := TRUE ;
    END ;
    IF (p.next.sym = Symbol.Minus) THEN
      Get(p) ;
    ELSIF (p.next.sym = Symbol.Okw) THEN
      Get(p) ;
      omitE := TRUE ;
    ELSE SynError(p, "unexpected '" & SymbolName[p.next.sym] & "' in ElementDecl") ;
    END ;
  END ;
  ParseContentSpec(p, r,m) ;
  Expect(p, Symbol.RB) ;
  TRY FSM.Wrap(m);
  EXCEPT
  | FSM.Error(e) =>
      parser.application.error(SGML.ErrorEvent{parser.p.cur.offset,
          SGML.ErrorType.OtherError,e & " in content specification"});
  END;
  IF ISTYPE(c,TEXT) THEN
    name := NARROW(c,TEXT);
    SGMLRep.AddElement(parser,name,r,m,omitS,omitE);

  (* several elements are declared together *)
  ELSE
    s := NARROW(c,TextSeq.T);
    FOR i := 0 TO s.size() - 1 DO
      name := s.get(i);
      SGMLRep.AddElement(parser,name,r,m,omitS,omitE);
    END;
  END
   ;
END ParseElementDecl ;

PROCEDURE ParseExternalId(p : Parser ; VAR public: BOOLEAN; VAR t1, t2: TEXT) RAISES { Rd.Failure, Thread.Alerted } =
BEGIN
  IF (p.next.sym = Symbol.SYSTEMkw) THEN
    Get(p) ;
    public := FALSE ;
    ParsePubidLiteral(p, t1) ;
  ELSIF (p.next.sym = Symbol.PUBLICkw) THEN
    Get(p) ;
    public := TRUE ;
    ParsePubidLiteral(p, t2) ;
    IF (p.next.sym = Symbol.DQuote) OR
       (p.next.sym = Symbol.Quote) THEN
      ParsePubidLiteral(p, t1) ;
    END ;
  ELSE SynError(p, "unexpected '" & SymbolName[p.next.sym] & "' in ExternalId") ;
  END ;
END ParseExternalId ;

PROCEDURE ParseMarkupDecl(p : Parser ; parser: SGML.Parser) RAISES { Rd.Failure, Thread.Alerted } =
BEGIN
  IF (p.next.sym = Symbol.ElementTag) THEN
    IF NOT parser.markup THEN
      parser.application.error(SGML.ErrorEvent{0,SGML.ErrorType.OtherError,
          "Misplaced markup declarations"});
    END
     ;
    ParseElementDecl(p, parser) ;
  ELSIF (p.next.sym = Symbol.AttListTag) THEN
    ParseAttListDecl(p, parser) ;
  ELSIF (p.next.sym = Symbol.EntityTag) THEN
    ParseEntityDecl(p, parser) ;
  ELSIF (p.next.sym = Symbol.NotationTag) THEN
    ParseNotationDecl(p, parser) ;
  ELSE SynError(p, "unexpected '" & SymbolName[p.next.sym] & "' in MarkupDecl") ;
  END ;
END ParseMarkupDecl ;

PROCEDURE ParseConditionalSect(p : Parser ; parser: SGML.Parser) RAISES { Rd.Failure, Thread.Alerted } =
BEGIN
  Expect(p, Symbol.StartCSect) ;
  IF (p.next.sym = Symbol.INCLUDEkw) THEN
    ParseIncludeSect(p, parser) ;
  ELSIF (p.next.sym = Symbol.IGNOREkw) THEN
    ParseIgnoreSect(p, parser) ;
  ELSE SynError(p, "unexpected '" & SymbolName[p.next.sym] & "' in ConditionalSect") ;
  END ;
END ParseConditionalSect ;

PROCEDURE ParseContent(p : Parser ; parser: SGML.Parser) RAISES { Rd.Failure, Thread.Alerted } =
  VAR t: TEXT; r: SGMLRep.RefType; e: REF SGML.Entity;
  sdata: SGML.SdataEvent;
BEGIN
  IF parser.markup THEN
    parser.application.error(SGML.ErrorEvent{0,SGML.ErrorType.OtherError,
        "Misplaced document content, in markup declarations"});
  END
   ;
  IF (p.next.sym = Symbol.StartElementTag) THEN
    ParseStartElement(p, parser) ;
  ELSIF (p.next.sym = Symbol.EndElementTag) THEN
    ParseEndElement(p, parser) ;
  ELSIF (p.next.sym = Symbol.CData) THEN
    Get(p) ;
    parser.application.markedSectionStart(SGML.MarkedSectionStartEvent{
        parser.p.cur.offset,SGML.MarkedSectionStatus.CData,
        SGMLRep.CDataParam});
    SGMLRep.StartData(parser);
    parser.application.data(SGML.DataEvent{parser.p.cur.offset,
        p.string()});
    parser.application.markedSectionEnd(SGML.MarkedSectionEndEvent{
        parser.p.cur.offset,SGML.MarkedSectionStatus.CData})
     ;
  ELSIF (p.next.sym = Symbol.PCDataChunk) THEN
    Get(p) ;
    SGMLRep.StartData(parser);
    parser.application.data(SGML.DataEvent{parser.p.cur.offset,
        p.string()})
     ;
  ELSIF (p.next.sym = Symbol.CharRef) OR
        (p.next.sym = Symbol.HexCharRef) OR
        (p.next.sym = Symbol.EntityRef) THEN
    ParseReference(p, t,r) ;
    sdata.pos := parser.p.cur.offset;
    sdata.entityName := t;

    (* An "sdata" event is delivered to the application for character,
       hexadecimal and other internal entity references. An
       ExternalDataEntityRef event is delivered for external references.*)

    IF r = SGMLRep.RefType.Char THEN
      sdata.text := "&" & t & ";"; (* SGMLRep.CharToText(t); *)
      SGMLRep.StartData(parser);
      parser.application.sdata(sdata);
    ELSIF r = SGMLRep.RefType.Hex THEN
      sdata.text := "&" & t & ";"; (*SGMLRep.HexToText(t); *)
      SGMLRep.StartData(parser);
      parser.application.sdata(sdata);
    ELSE
      e := SGMLRep.GetEntity(parser,t,SGML.EntityDeclType.General);
      IF e # NIL THEN
        IF e.internalText # NIL THEN
          sdata.text := e.internalText;
          SGMLRep.StartData(parser);
          parser.application.sdata(sdata);
        ELSE
          parser.application.externalDataEntityRef(
              SGML.ExternalDataEntityRefEvent{parser.p.cur.offset,e^});
        END;
      ELSE
        parser.application.error(SGML.ErrorEvent{parser.p.cur.offset,
            SGML.ErrorType.OtherError,"Reference to undefined entity " &
            t});
      END;
    END
     ;
  ELSE SynError(p, "unexpected '" & SymbolName[p.next.sym] & "' in Content") ;
  END ;
END ParseContent ;

PROCEDURE ParseDocTypeDecl(p : Parser ; parser: SGML.Parser) RAISES { Rd.Failure, Thread.Alerted } =
  VAR name: TEXT;
  public: BOOLEAN := FALSE; t1, t2: TEXT := NIL;
  e: REF SGML.Entity;

BEGIN
  Expect(p, Symbol.DocTypeTag) ;
  ParseCIName(p, name) ;
  IF (p.next.sym = Symbol.SYSTEMkw) OR
     (p.next.sym = Symbol.PUBLICkw) THEN
    ParseExternalId(p, public,t1,t2) ;
    e := NEW(REF SGML.Entity);
    e.name := name;
    e.declType := SGML.EntityDeclType.Doctype;
    e.dataType := SGML.EntityDataType.Sgml;
    e.internalText := NIL;
    e.externalId := SGML.ExternalId{t1,t2,NIL};
    SGMLRep.AddEntity(parser,e)
     ;
  END ;
  parser.doctype := name;
  SGMLRep.ParseDtd(parser,SGML.ExternalId{t1,t2,NIL})
   ;
  IF (p.next.sym = Symbol.LSB) THEN
    parser.markup := TRUE;
    parser.s.inMarkupDecl(TRUE)
     ;
    Get(p) ;
    WHILE (p.next.sym IN SymSet[6]) DO
      IF (p.next.sym = Symbol.AttListTag) OR
         (p.next.sym = Symbol.ElementTag) OR
         (p.next.sym = Symbol.EntityTag) OR
         (p.next.sym = Symbol.NotationTag) THEN
        ParseMarkupDecl(p, parser) ;
      ELSIF (p.next.sym = Symbol.StartCSect) THEN
        ParseConditionalSect(p, parser) ;
      ELSE
        ParseMisc(p, parser) ;
      END ;
    END ;
    Expect(p, Symbol.RSB) ;
    parser.markup := FALSE;
    parser.s.inMarkupDecl(FALSE)
     ;
  END ;
  Expect(p, Symbol.RB) ;
END ParseDocTypeDecl ;

PROCEDURE ParseSGMLC(p : Parser) RAISES { Rd.Failure, Thread.Alerted } =
  VAR parser := NARROW(p,SGMLRep.ParserPlus).parser;
BEGIN
  WHILE (p.next.sym = Symbol.Commenttk) OR
        (p.next.sym = Symbol.White) OR
        (p.next.sym = Symbol.PItk) DO
    ParseMisc(p, parser) ;
  END ;
  IF (p.next.sym = Symbol.DocTypeTag) THEN
    ParseDocTypeDecl(p, parser) ;
    WHILE (p.next.sym = Symbol.Commenttk) OR
          (p.next.sym = Symbol.White) OR
          (p.next.sym = Symbol.PItk) DO
      ParseMisc(p, parser) ;
    END ;
  END ;
  (* Found some content before any document type declaration.
     ParseDtd is called with a NIL doctype and will select a default
     document type. *)

  IF parser.doctype = NIL THEN
    SGMLRep.ParseDtd(parser,SGML.ExternalId{NIL,NIL,NIL});
  END;

  IF NOT parser.markup THEN
    parser.application.endProlog(SGML.EndPrologEvent{parser.p.cur.
        offset});
    SGMLRep.StartContent(parser);
  END
   ;
  IF (p.next.sym IN SymSet[7]) THEN
    ParseContent(p, parser) ;
  ELSIF (p.next.sym = Symbol.StartCSect) THEN
    ParseConditionalSect(p, parser) ;
  ELSIF (p.next.sym = Symbol.AttListTag) OR
        (p.next.sym = Symbol.ElementTag) OR
        (p.next.sym = Symbol.EntityTag) OR
        (p.next.sym = Symbol.NotationTag) THEN
    ParseMarkupDecl(p, parser) ;
  ELSE SynError(p, "unexpected '" & SymbolName[p.next.sym] & "' in SGMLC") ;
  END ;
  WHILE (p.next.sym IN SymSet[2]) DO
    IF (p.next.sym IN SymSet[7]) THEN
      ParseContent(p, parser) ;
    ELSIF (p.next.sym = Symbol.Commenttk) OR
          (p.next.sym = Symbol.White) OR
          (p.next.sym = Symbol.PItk) THEN
      ParseMisc(p, parser) ;
    ELSIF (p.next.sym = Symbol.StartCSect) THEN
      ParseConditionalSect(p, parser) ;
    ELSE
      ParseMarkupDecl(p, parser) ;
    END ;
  END ;
  IF NOT parser.markup THEN SGMLRep.EndContent(parser); END
   ;
END ParseSGMLC ;

PROCEDURE ParseMisc(p : Parser ; parser: SGML.Parser) RAISES { Rd.Failure, Thread.Alerted } =
BEGIN
  IF (p.next.sym = Symbol.Commenttk) THEN
    ParseComment(p, parser) ;
  ELSIF (p.next.sym = Symbol.PItk) THEN
    ParsePI(p, parser) ;
  ELSIF (p.next.sym = Symbol.White) THEN
    Get(p) ;
    IF NOT parser.markup THEN
      (* SGMLRep.StartData(parser); White is not necessarily #PCDATA *)
      parser.application.data(SGML.DataEvent{parser.p.cur.offset,
          p.string()});
    END
     ;
  ELSE SynError(p, "unexpected '" & SymbolName[p.next.sym] & "' in Misc") ;
  END ;
END ParseMisc ;

PROCEDURE ParsePI(p : Parser ; parser: SGML.Parser) RAISES { Rd.Failure, Thread.Alerted } =
BEGIN
  Expect(p, Symbol.PItk) ;
  parser.application.pi(SGML.PiEvent{parser.p.cur.offset,
  p.string(),NIL}) ;
END ParsePI ;

PROCEDURE ParseComment(p : Parser ; parser: SGML.Parser) RAISES { Rd.Failure, Thread.Alerted } =
  VAR c := NEW(REF ARRAY OF TEXT,1);
BEGIN
  Expect(p, Symbol.Commenttk) ;
  c[0] := p.string();
  IF NOT parser.markup THEN
    parser.application.commentDecl(SGML.CommentDeclEvent{parser.p.cur.
        offset,c,NIL});
  END
   ;
END ParseComment ;

PROCEDURE ParseAttValue(p : Parser ; parser: SGML.Parser) RAISES { Rd.Failure, Thread.Alerted } =
  VAR t: TEXT; r: SGMLRep.RefType; e: REF SGML.Entity;
BEGIN
  parser.nbData := 0 ;
  IF (p.next.sym = Symbol.DQuote) OR
     (p.next.sym = Symbol.Quote) THEN
    IF (p.next.sym = Symbol.Quote) THEN
      Get(p) ;
    ELSE
      Get(p) ;
    END ;
    WHILE (p.next.sym = Symbol.AttValueData) OR
          (p.next.sym = Symbol.CharRef) OR
          (p.next.sym = Symbol.HexCharRef) OR
          (p.next.sym = Symbol.EntityRef) DO
      IF (p.next.sym = Symbol.AttValueData) THEN
        Get(p) ;
        t := p.string() ;
        parser.dataChunks[parser.nbData].data := t;
        parser.dataChunks[parser.nbData].entityName := NIL;
        SGMLRep.IncData(parser)
         ;
      ELSE
        ParseReference(p, t,r) ;
        parser.dataChunks[parser.nbData].entityName := t;
        IF r = SGMLRep.RefType.Char THEN
          parser.dataChunks[parser.nbData].data := "&" & t & ";";
              (* SGMLRep.CharToText(t); *)
        ELSIF r = SGMLRep.RefType.Hex THEN
          parser.dataChunks[parser.nbData].data := "&" & t & ";";
              (* SGMLRep.HexToText(t); *)
        ELSE
          e := SGMLRep.GetEntity(parser,t,SGML.EntityDeclType.General);
          IF e # NIL THEN
            parser.dataChunks[parser.nbData].data := e.internalText;
          ELSE
            parser.application.error(SGML.ErrorEvent{parser.p.cur.offset,
                SGML.ErrorType.OtherError,"Reference to undefined entity "
                & t});
          END;
        END;
        SGMLRep.IncData(parser)
         ;
      END ;
    END ;
    IF (p.next.sym = Symbol.Quote) THEN
      Get(p) ;
    ELSIF (p.next.sym = Symbol.DQuote) THEN
      Get(p) ;
    ELSE SynError(p, "unexpected '" & SymbolName[p.next.sym] & "' in AttValue") ;
    END ;
  ELSIF (p.next.sym IN SymSet[8]) THEN
    IF (p.next.sym IN SymSet[3]) THEN
      ParseName(p, t) ;
    ELSE
      Get(p) ;
      t := p.string() ;
    END ;
    parser.dataChunks[parser.nbData].data := t;
    parser.dataChunks[parser.nbData].entityName := NIL;
    SGMLRep.IncData(parser)
     ;
  ELSE SynError(p, "unexpected '" & SymbolName[p.next.sym] & "' in AttValue") ;
  END ;
END ParseAttValue ;

PROCEDURE ParseEntityValue(p : Parser ; parser: SGML.Parser; VAR v: TEXT) RAISES { Rd.Failure, Thread.Alerted } =
  VAR t: TEXT; r: SGMLRep.RefType; e: REF SGML.Entity;
BEGIN
  v := "" ;
  IF (p.next.sym = Symbol.Quote) THEN
    Get(p) ;
  ELSIF (p.next.sym = Symbol.DQuote) THEN
    Get(p) ;
  ELSE SynError(p, "unexpected '" & SymbolName[p.next.sym] & "' in EntityValue") ;
  END ;
  WHILE (p.next.sym = Symbol.CharRef) OR
        (p.next.sym = Symbol.EntityValueData) OR
        (p.next.sym = Symbol.HexCharRef) OR
        (p.next.sym = Symbol.PEReference) OR
        (p.next.sym = Symbol.EntityRef) DO
    IF (p.next.sym = Symbol.EntityValueData) THEN
      Get(p) ;
      t := p.string(); v := v & t ;
    ELSIF (p.next.sym = Symbol.PEReference) THEN
      Get(p) ;
      t := p.string(); v := v & "%" & t & ";" ;
    ELSE
      ParseReference(p, t,r) ;
      IF r = SGMLRep.RefType.Char THEN
        v := v & "&" & t & ";"; (* SGMLRep.CharToText(t); *)
      ELSIF r = SGMLRep.RefType.Hex THEN
        v := v & "&" & t & ";"; (* SGMLRep.HexToText(t); *)
      ELSE
        e := SGMLRep.GetEntity(parser,t,SGML.EntityDeclType.General);
        IF e # NIL THEN
          v := v & e.internalText;
        ELSE
          parser.application.error(SGML.ErrorEvent{parser.p.cur.offset,
              SGML.ErrorType.OtherError,"Reference to undefined entity "
              & t});
        END;
      END
       ;
    END ;
  END ;
  IF (p.next.sym = Symbol.Quote) THEN
    Get(p) ;
  ELSIF (p.next.sym = Symbol.DQuote) THEN
    Get(p) ;
  ELSE SynError(p, "unexpected '" & SymbolName[p.next.sym] & "' in EntityValue") ;
  END ;
END ParseEntityValue ;

PROCEDURE ParseReference(p : Parser ; VAR name: TEXT; VAR type: SGMLRep.RefType) RAISES { Rd.Failure, Thread.Alerted } =
BEGIN
  IF (p.next.sym = Symbol.CharRef) THEN
    Get(p) ;
    name := p.string(); type := SGMLRep.RefType.Char ;
  ELSIF (p.next.sym = Symbol.HexCharRef) THEN
    Get(p) ;
    name := p.string(); type := SGMLRep.RefType.Hex ;
  ELSIF (p.next.sym = Symbol.EntityRef) THEN
    Get(p) ;
    name := p.string(); type := SGMLRep.RefType.Name ;
  ELSE SynError(p, "unexpected '" & SymbolName[p.next.sym] & "' in Reference") ;
  END ;
END ParseReference ;

PROCEDURE ParsePubidLiteral(p : Parser ; VAR v: TEXT) RAISES { Rd.Failure, Thread.Alerted } =
  VAR t: TEXT; r: SGMLRep.RefType;
BEGIN
  v := "" ;
  IF (p.next.sym = Symbol.Quote) THEN
    Get(p) ;
  ELSIF (p.next.sym = Symbol.DQuote) THEN
    Get(p) ;
  ELSE SynError(p, "unexpected '" & SymbolName[p.next.sym] & "' in PubidLiteral") ;
  END ;
  WHILE (p.next.sym = Symbol.CharRef) OR
        (p.next.sym = Symbol.EntityValueData) OR
        (p.next.sym = Symbol.HexCharRef) OR
        (p.next.sym = Symbol.PEReference) OR
        (p.next.sym = Symbol.EntityRef) DO
    IF (p.next.sym = Symbol.EntityValueData) THEN
      Get(p) ;
      t := p.string(); v := v & t ;
    ELSIF (p.next.sym = Symbol.PEReference) THEN
      Get(p) ;
      t := p.string(); v := v & "%" & t & ";" ;
    ELSE
      ParseReference(p, t,r) ;
      v := v & "&" & t & ";" ;
    END ;
  END ;
  IF (p.next.sym = Symbol.Quote) THEN
    Get(p) ;
  ELSIF (p.next.sym = Symbol.DQuote) THEN
    Get(p) ;
  ELSE SynError(p, "unexpected '" & SymbolName[p.next.sym] & "' in PubidLiteral") ;
  END ;
END ParsePubidLiteral ;

PROCEDURE ParseCIName(p : Parser ; VAR t: TEXT) RAISES { Rd.Failure, Thread.Alerted } =
BEGIN
  CASE p.next.sym OF
    Symbol.NonKeywordName =>
      Get(p) ;
      t := p.name() ;
  | Symbol.IGNOREkw =>
      Get(p) ;
      t := p.name() ;
  | Symbol.INCLUDEkw =>
      Get(p) ;
      t := p.name() ;
  | Symbol.EMPTYkw =>
      Get(p) ;
      t := p.name() ;
  | Symbol.ANYkw =>
      Get(p) ;
      t := p.name() ;
  | Symbol.CDATAkw =>
      Get(p) ;
      t := p.name() ;
  | Symbol.IDkw =>
      Get(p) ;
      t := p.name() ;
  | Symbol.IDREFkw =>
      Get(p) ;
      t := p.name() ;
  | Symbol.IDREFSkw =>
      Get(p) ;
      t := p.name() ;
  | Symbol.ENTITYkw =>
      Get(p) ;
      t := p.name() ;
  | Symbol.ENTITIESkw =>
      Get(p) ;
      t := p.name() ;
  | Symbol.NAMEkw =>
      Get(p) ;
      t := p.name() ;
  | Symbol.NAMESkw =>
      Get(p) ;
      t := p.name() ;
  | Symbol.NMTOKENkw =>
      Get(p) ;
      t := p.name() ;
  | Symbol.NMTOKENSkw =>
      Get(p) ;
      t := p.name() ;
  | Symbol.NUMBERkw =>
      Get(p) ;
      t := p.name() ;
  | Symbol.NUMBERSkw =>
      Get(p) ;
      t := p.name() ;
  | Symbol.NOTATIONkw =>
      Get(p) ;
      t := p.name() ;
  | Symbol.SYSTEMkw =>
      Get(p) ;
      t := p.name() ;
  | Symbol.PUBLICkw =>
      Get(p) ;
      t := p.name() ;
  | Symbol.NDATAkw =>
      Get(p) ;
      t := p.name() ;
  | Symbol.SGMLDECLkw =>
      Get(p) ;
      t := p.name() ;
  | Symbol.DOCTYPEkw =>
      Get(p) ;
      t := p.name() ;
  | Symbol.CATALOGkw =>
      Get(p) ;
      t := p.name() ;
  | Symbol.Okw =>
      Get(p) ;
      t := p.name() ;
  ELSE SynError(p, "unexpected '" & SymbolName[p.next.sym] & "' in CIName") ;
  END ;
END ParseCIName ;

PROCEDURE ParseName(p : Parser ; VAR t: TEXT) RAISES { Rd.Failure, Thread.Alerted } =
BEGIN
  CASE p.next.sym OF
    Symbol.NonKeywordName =>
      Get(p) ;
      t := p.string() ;
  | Symbol.IGNOREkw =>
      Get(p) ;
      t := p.string() ;
  | Symbol.INCLUDEkw =>
      Get(p) ;
      t := p.string() ;
  | Symbol.EMPTYkw =>
      Get(p) ;
      t := p.string() ;
  | Symbol.ANYkw =>
      Get(p) ;
      t := p.string() ;
  | Symbol.CDATAkw =>
      Get(p) ;
      t := p.string() ;
  | Symbol.IDkw =>
      Get(p) ;
      t := p.string() ;
  | Symbol.IDREFkw =>
      Get(p) ;
      t := p.string() ;
  | Symbol.IDREFSkw =>
      Get(p) ;
      t := p.string() ;
  | Symbol.ENTITYkw =>
      Get(p) ;
      t := p.string() ;
  | Symbol.ENTITIESkw =>
      Get(p) ;
      t := p.string() ;
  | Symbol.NAMEkw =>
      Get(p) ;
      t := p.string() ;
  | Symbol.NAMESkw =>
      Get(p) ;
      t := p.string() ;
  | Symbol.NMTOKENkw =>
      Get(p) ;
      t := p.string() ;
  | Symbol.NMTOKENSkw =>
      Get(p) ;
      t := p.string() ;
  | Symbol.NUMBERkw =>
      Get(p) ;
      t := p.string() ;
  | Symbol.NUMBERSkw =>
      Get(p) ;
      t := p.string() ;
  | Symbol.NOTATIONkw =>
      Get(p) ;
      t := p.string() ;
  | Symbol.SYSTEMkw =>
      Get(p) ;
      t := p.string() ;
  | Symbol.PUBLICkw =>
      Get(p) ;
      t := p.string() ;
  | Symbol.NDATAkw =>
      Get(p) ;
      t := p.string() ;
  | Symbol.SGMLDECLkw =>
      Get(p) ;
      t := p.string() ;
  | Symbol.DOCTYPEkw =>
      Get(p) ;
      t := p.string() ;
  | Symbol.CATALOGkw =>
      Get(p) ;
      t := p.string() ;
  | Symbol.Okw =>
      Get(p) ;
      t := p.string() ;
  ELSE SynError(p, "unexpected '" & SymbolName[p.next.sym] & "' in Name") ;
  END ;
END ParseName ;

PROCEDURE Parse(p : Parser) RAISES { Rd.Failure, Thread.Alerted } =
BEGIN
  Get(p) ;
  ParseSGMLC(p) ;
END Parse ;

PROCEDURE Init(p : Parser ; s : Scanner ; e : ErrHandler) : Parser =
BEGIN
  p.s       := s ;
  p.err     := e ;
  p.errDist := minErrDist ;
  RETURN p
END Init ;

BEGIN
END SGMLCP.