home *** CD-ROM | disk | FTP | other *** search
/ Fresh Fish 10 / Fresh_Fish_10_2352.bin / new / dev / lang / sgmls / src / context.c < prev    next >
C/C++ Source or Header  |  1994-07-10  |  19KB  |  452 lines

  1. #include "sgmlincl.h"         /* #INCLUDE statements for SGML parser. */
  2. #include "context.h"
  3.  
  4. #define GI (tags[ts].tetd->etdgi+1)              /* GI of current element. */
  5. #define NEWGI (newetd->etdgi+1)                  /* GI of new tag. */
  6. #define STATUS (*statuspt)    /* Token status: RCHIT RCMISS RCEND RCREQ RCNREQ*/
  7. #define PEX (-1)              /* GI is a plus exception and not a minus. */
  8.  
  9. #define ANYHIT(h) (grplongs == 1 ? ((h)[0] != 0) : anyhit(h))
  10. #define HITSET(h, n) (h[(unsigned)(n-1)>>LONGPOW] \
  11.               |= (1L<<((n-1)&(LONGBITS-1))))
  12. #define HITON(h, n) (h[(unsigned)(n-1)>>LONGPOW] & (1L<<((n-1)&(LONGBITS-1))))
  13.  
  14. #define HITOFF(h, n) (!(HITON(h, n)))
  15.  
  16. #define TOKENHIT HITON(H,T)
  17.  
  18. static
  19. VOID copypos(struct mpos *to, struct mpos *from)
  20.  
  21. {
  22.      int i;
  23.      for (i = 0; i <= (int)from[0].t; i++) {
  24.       to[i].g = from[i].g;
  25.       to[i].t = from[i].t;
  26.       memcpy(to[i].h, from[i].h, grplongs*sizeof(unsigned long));
  27.      }
  28. }
  29.  
  30. /* CONTEXT: Determine whether a GI is valid in the present structural context.
  31.             Returns RCHIT if valid, RCEND if element has ended, RCREQ if a
  32.             different element is required, and RCMISS if it is totally invalid.
  33.             On entry, pos points to the model token to be tested against the GI.
  34.             TO DO: Save allowed GIs for an error message on an RCMISS.
  35.                    Support a "query" mode (what is allowed now?) by working
  36.                    with a copy of pos.
  37. */
  38. int context(gi, mod, pos, statuspt, mexts)
  39. struct etd *gi;               /* ETD of new GI. */
  40. struct thdr mod[];            /* Model of current open element. */
  41. struct mpos pos[];            /* Position in open element's model. */
  42. UNCH *statuspt;               /* Token status: RCHIT RCMISS RCEND RCREQ RCNREQ*/
  43. int mexts;                    /* >0=stack level of minus grp; -1=plus; 0=none.*/
  44. {
  45.      UNCH toccsv, gtypesv;    /* Save token's TOCC and GTYPE in case grp ends.*/
  46.  
  47.      if (mexts != 0) {
  48.       if (mexts == -1 && STATUS == RCEND)
  49.            return RCPEX;
  50.       copypos(savedpos, pos);
  51.      }
  52.      Tstart = T;              /* Save starting token for AND group testing. */
  53.      while (STATUS!=RCMISS && STATUS!=RCEND) {
  54.           TRACEGI("CONTEXT", gi, mod, pos);
  55.           while (TTYPE==TTOR || TTYPE==TTSEQ || TTYPE==TTAND) {
  56.                pos[P+1].g = M++; pos[++P].t = 1; HITCLEAR(H);
  57.                Tstart = T;    /* Save starting token for AND group testing. */
  58.                TRACEGI("OPENGRP", gi, mod, pos);
  59.           }
  60.           STATUS = (UNCH)tokenreq(gi, mod, pos);
  61.           TRACEGI("STATUS", gi, mod, pos);
  62.           if (gi==TOKEN.tu.thetd) {     /* Hit in model. */
  63.                STATUS = (UNCH)RCHIT;
  64.                gtypesv = GTYPE; toccsv = TOCC;
  65.                newtoken(mod, pos, statuspt);
  66.            if (mexts <= 0)
  67.             return RCHIT;
  68.            else if (gtypesv==TTOR || BITON(toccsv, TOPT)) {
  69.             /* restore position */
  70.             copypos(pos, savedpos);
  71.             return RCMEX;
  72.            }
  73.            else
  74.             return RCHITMEX;
  75.           }
  76.           if (STATUS==RCREQ) {
  77.            if (mexts == -1)
  78.             break;
  79.                STATUS = RCHIT;
  80.                nextetd = TOKEN.tu.thetd;
  81.                newtoken(mod, pos, statuspt);
  82.                return(RCREQ);
  83.           }
  84.           /* else if (STATUS==RCNREQ) */
  85.                if (mexts>0) return(RCMEX);
  86.                newtoken(mod, pos, statuspt);
  87.      }
  88.      if (mexts == -1) {
  89.       copypos(pos, savedpos);
  90.       return STATUS = RCPEX;
  91.      }
  92.      return((int)STATUS);
  93. }
  94. /* ECONTEXT: Determine whether the current element can be ended, or whether
  95.              non-optional tokens remain at the current level or higher.
  96.              Returns 1 if element can be ended, or 0 if tokens remain.
  97.              On entry, STATUS==RCEND if there are no tokens left; if not,
  98.              pos points to the next model token to be tested.
  99.              TO DO: Support a "query" mode (what is required now?) by working
  100.                     with a copy of pos.
  101. */
  102. int econtext(mod, pos, statuspt)
  103. struct thdr mod[];            /* Model of current open element. */
  104. struct mpos pos[];            /* Position in open element's model. */
  105. UNCH *statuspt;               /* Token status: RCHIT RCMISS RCEND RCREQ RCNREQ*/
  106. {
  107.      unsigned next;           /* Position in AND group of next testable token.*/
  108.  
  109.      Tstart = T;
  110.      TRACEEND("ECONT", mod, pos, 0, 0);
  111.      if (P<=1) {nextetd = 0; return(TOKENHIT || BITON(TOCC, TOPT));}
  112.      nextetd = TTYPE == TTETD ? TOKEN.tu.thetd : 0;
  113.      while (STATUS!=RCMISS && STATUS!=RCEND) {
  114.           STATUS = (UNCH)testend(mod, pos, 0, 0);
  115.           TRACEEND("ECONTEND", mod, pos, 0, 0);
  116.           nextetd = P<=1 || TTYPE != TTETD ? 0 : TOKEN.tu.thetd;
  117.           if (STATUS==RCEND)       return(1);
  118.           if (P<=1)                return(TOKENHIT || BITON(TOCC, TOPT));
  119.           if (STATUS==RCMISS) {
  120.                if (BITON(TOCC, TOPT)) nextetd = 0;
  121.                return(0);
  122.           }
  123.           if (!tokenopt(mod, pos)) return(0);
  124.  
  125.           STATUS = RCNREQ;
  126.           if (GTYPE!=TTAND) ++T;   /* T!=GNUM or group would have ended. */
  127.           else T = (UNCH)(((next = (UNS)offbit(H, (int)T, GNUM))!=0) ?
  128.                next : offbit(H, 0, GNUM));
  129.  
  130.           M = G + grpsz(&GHDR, (int)T-1) + 1;
  131.           TRACEEND("ECONTNEW", mod, pos, 0, 0);
  132.      }
  133.      if (STATUS==RCMISS) {
  134.           if (BITON(TOCC, TOPT)) nextetd = 0;
  135.           return(0);
  136.      }
  137.      return(1);               /* STATUS==RCEND */
  138. }
  139. /* NEWTOKEN: Find the next token to test.  Set STATUS to indicate results:
  140.                   RCEND  if element has ended (no more tokens to test);
  141.                   RCREQ  if required new token was found;
  142.                   RCNREQ if non-required new token was found;
  143.                   RCHIT  if a hit token was repeated (now non-required);
  144.               and RCMISS if a new token can't be found because current token
  145.               (which was not hit) was neither unconditionally required nor
  146.               optional.
  147. */
  148. VOID newtoken(mod, pos, statuspt)
  149. struct thdr mod[];            /* Model of current open element. */
  150. struct mpos pos[];            /* Position in open element's model. */
  151. UNCH *statuspt;               /* Token status: RCHIT RCMISS RCEND RCREQ RCNREQ*/
  152. {
  153.      unsigned nextand = 0;    /* Position in AND group of next testable token.*/
  154.      int currhit = (STATUS==RCHIT); /* 1=current GI hit; 0=not. */
  155.  
  156.      /* If the GI was a hit, turn on the hit bit and set the status to
  157.         assume that the token to be tested against the next GI will
  158.         be non-required.  If the current token is repeatable, exit so
  159.         it will stand as the next token to test.
  160.      */
  161.      if (STATUS==RCHIT) {
  162.           HITSET(H, T);
  163.       STATUS = RCNREQ;
  164.           if (BITON(TOCC, TREP)) return;
  165.      }
  166.      /* At this point, we must determine the next token to test:
  167.         either against the next GI, if this one was a hit, or
  168.         against the same GI if conditions permit a retry.
  169.         To find the next token, we must first end the current group,
  170.         if possible, and any we can that contain it.
  171.         If the outermost group was a hit and is repeatable, or
  172.         if the element has ended, we exit now.
  173.         If it hasn't ended, or was optional and ended with a miss,
  174.         we can retry the GI against the next token.
  175.      */
  176.      if ((STATUS = (UNCH)testend(mod, pos, 1, 1))!=RCNREQ) return;
  177.  
  178.      /* At this point, the "current token" is either the original one,
  179.         or the token for the highest level unhit group that it ended.
  180.         We will retry a missed GI, by testing it against the next
  181.         token, if the current token:
  182.         1. Is optional;
  183.         2. Was hit (i.e., because it is repeatable and was hit by a
  184.            previous GI or because it is a hit group that just ended);
  185.         3. Is in an AND or OR group and is not the last testable token.
  186.  
  187.         It will be the next sequential one (unhit one, in an AND group);
  188.         if there are none left, use the first unhit token in the group.
  189.         In either case, set M to correspond to the new T.
  190.      */
  191.      retest:
  192.      TRACEEND("RETEST", mod, pos, (int)nextand, 1);
  193.      if (GTYPE==TTAND) {
  194.           nextand = offbit(H, (int)T, GNUM);
  195.       if (!nextand)
  196.