home *** CD-ROM | disk | FTP | other *** search
/ Otherware / Otherware_1_SB_Development.iso / mac / misc / compsci / arcsgm.cpt / ARC SGML 1.0 / sgmlc / context.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-12-17  |  20.6 KB  |  454 lines

  1. #ifdef applec
  2. #pragma segment SegA
  3. #endif
  4. /******************************************************************************/
  5. #include "sgmlincl.h"         /* #INCLUDE statements for SGML parser. */
  6. /******************************************************************************/
  7. #define GI (tags[ts].tetd->etdgi+1)              /* GI of current element. */
  8. #define NEWGI (newetd->etdgi+1)                  /* GI of new tag. */
  9. /******************************************************************************/
  10. #define STATUS (*statuspt)    /* Token status: RCHIT RCMISS RCEND RCREQ RCNREQ*/
  11. #define RCEND    1            /* No more tokens: end element and retry GI. */
  12. #define RCREQ    2            /* Required GI must precede proposed GI. */
  13. #define RCMISS   3            /* GI invalid: not element end; no required GI. */
  14. #define RCHIT    4            /* GI is the one expected next. */
  15. #define RCMEX    5            /* GI invalid: minus exception. */
  16. #define RCHITMEX 6            /* RCMEX with invalid attempted minus exclusion.*/
  17. #define RCPEX    7            /* GI is valid solely because of plus exclusion.*/
  18. #define RCNREQ   8            /* Token is not required; can retry invalid GI. */
  19. #define PEX     -1            /* GI is a plus exception and not a minus. */
  20. #define M      pos[0].g       /* Index of current token in model. */
  21. #define P      pos[0].t       /* Index of current group in pos. */
  22. #define G      pos[P].g       /* Index of current group in model. */
  23. #define T      pos[P].t       /* Index of current token in its group. */
  24. #define H      pos[P].h       /* Hit bits for current group's tokens (1=hit). */
  25. #define GHDR   mod[G]         /* Current group header. */
  26. #define TOKEN  mod[M]         /* Current token. */
  27. #define TTYPE (GET(TOKEN.ttype, TTMASK))  /* Token type of current token. */
  28. #define TOCC  (GET(TOKEN.ttype, TOREP))   /* Occurrence for current token. */
  29. #define GTYPE (GET(GHDR.ttype, TTMASK))   /* Token type of current group. */
  30. #define GOCC  (GET(GHDR.ttype, TOREP))    /* Occurrence for current group. */
  31. #define GNUM  GHDR.tu.tnum                /* Number of tokens in current grp. */
  32. /******************************************************************************/
  33. static long l1;               /* Intermediate variable for hit selector. */
  34. #define TOKENHIT (l1 = 1L<<(T-1), H&l1) /* 1=current token was hit; 0=not*/
  35. /******************************************************************************/
  36. /* CONTEXT: Determine whether a GI is valid in the present structural context.
  37.             Returns RCHIT if valid, RCEND if element has ended, RCREQ if a
  38.             different element is required, and RCMISS if it is totally invalid.
  39.             On entry, pos points to the model token to be tested against the GI.
  40.             TO DO: Save allowed GIs for an error message on an RCMISS.
  41.                    Support a "query" mode (what is allowed now?) by working
  42.                    with a copy of pos.
  43. */
  44. int context(gi, mod, pos, statuspt, mexts)
  45. struct etd *gi;               /* ETD of new GI. */
  46. struct thdr mod[];            /* Model of current open element. */
  47. struct mpos pos[];            /* Position in open element's model. */
  48. UNCH *statuspt;               /* Token status: RCHIT RCMISS RCEND RCREQ RCNREQ*/
  49. int mexts;                    /* >0=stack level of minus grp; -1=plus; 0=none.*/
  50. {
  51.      UNCH toccsv, gtypesv;    /* Save token's TOCC and GTYPE in case grp ends.*/
  52.  
  53.      Tstart = T;              /* Save starting token for AND group testing. */
  54.      while (STATUS!=RCMISS && STATUS!=RCEND) {
  55. #ifndef FINAL
  56.           if (ctrace) tracegi((UNCH *)"CONTEXT", gi, mod, pos, (int)Tstart);
  57. #endif
  58.           while (TTYPE==TTOR || TTYPE==TTSEQ || TTYPE==TTAND) {
  59.                pos[P+1].g = M++; pos[++P].t = 1; H = 0;
  60.                Tstart = T;    /* Save starting token for AND group testing. */
  61. #ifndef FINAL
  62.                if (ctrace) tracegi((UNCH *)"OPENGRP", gi, mod, pos, (int)Tstart);
  63. #endif
  64.           }
  65.           STATUS = (UNCH)tokenreq(gi, mod, pos);
  66. #ifndef FINAL
  67.           if (ctrace) tracegi((UNCH *)"STATUS", gi, mod, pos, (int)Tstart);
  68. #endif
  69.           if (gi==TOKEN.tu.thetd) {     /* Hit in model. */
  70.                STATUS = (UNCH)RCHIT;
  71.                gtypesv = GTYPE; toccsv = TOCC;
  72.                newtoken(mod, pos, statuspt);
  73.                return(mexts<=0 ? RCHIT : (gtypesv==TTOR || BITON(toccsv, TOPT))
  74.                                        ?  RCMEX : RCHITMEX);
  75.           }
  76.           if (mexts==-1) return((int)(STATUS = RCPEX));  /* Hit in plus grp. */
  77.           if (STATUS==RCREQ) {
  78.                STATUS = RCHIT;
  79.                nextetd = TOKEN.tu.thetd;
  80.                newtoken(mod, pos, statuspt);
  81.                return(RCREQ);
  82.           }
  83.           /* else if (STATUS==RCNREQ) */
  84.                if (mexts>0) return(RCMEX);
  85.                newtoken(mod, pos, statuspt);
  86.      }
  87.      return((int)STATUS);
  88. }
  89. /******************************************************************************/
  90. /* ECONTEXT: Determine whether the current element can be ended, or whether
  91.              non-optional tokens remain at the current level or higher.
  92.              Returns 1 if element can be ended, or 0 if tokens remain.
  93.              On entry, STATUS==RCEND if there are no tokens left; if not,
  94.              pos points to the next model token to be tested.
  95.              TO DO: Support a "query" mode (what is required now?) by working
  96.                     with a copy of pos.
  97. */
  98. int econtext(mod, pos, statuspt)
  99. struct thdr mod[];            /* Model of current open element. */
  100. struct mpos pos[];            /* Position in open element's model. */
  101. UNCH *statuspt;               /* Token status: RCHIT RCMISS RCEND RCREQ RCNREQ*/
  102. {
  103.      unsigned next;           /* Position in AND group of next testable token.*/
  104.  
  105.      Tstart = T;
  106. #ifndef FINAL
  107.      if (ctrace) traceend((UNCH *)"ECONT", mod, pos, 0, 0, (int)Tstart);
  108. #endif
  109.      if (P<=1) {nextetd = 0; return(TOKENHIT || BITON(TOCC, TOPT));}
  110.      else nextetd = TOKEN.tu.thetd;
  111.      while (STATUS!=RCMISS && STATUS!=RCEND) {
  112.           STATUS = (UNCH)testend(mod, pos, 0, 0);
  113. #ifndef FINAL
  114.           if (ctrace) traceend((UNCH *)"ECONTEND", mod, pos, 0, 0, (int)Tstart);
  115. #endif
  116.           nextetd = P<=1 ? 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. #ifndef FINAL
  132.           if (ctrace) traceend((UNCH *)"ECONTNEW", mod, pos, 0, 0, (int)Tstart);
  133. #endif
  134.      }
  135.      if (STATUS==RCMISS) {
  136.           if (BITON(TOCC, TOPT)) nextetd = 0;
  137.           return(0);
  138.      }
  139.      return(1);               /* STATUS==RCEND */
  140. }
  141. /******************************************************************************/
  142. /* NEWTOKEN: Find the next token to test.  Set STATUS to indicate results:
  143.                   RCEND  if element has ended (no more tokens to test);
  144.                   RCREQ  if required new token was found;
  145.                   RCNREQ if non-required new token was found;
  146.                   RCHIT  if a hit token was repeated (now non-required);
  147.               and RCMISS if a new token can't be found because current token
  148.               (which was not hit) was neither unconditionally required nor
  149.               optional.
  150. */
  151. VOID newtoken(mod, pos, statuspt)
  152. struct thdr mod[];            /* Model of current open element. */
  153. struct mpos pos[];            /* Position in open element's model. */
  154. UNCH *statuspt;               /* Token status: RCHIT RCMISS RCEND RCREQ RCNREQ*/
  155. {
  156.      unsigned nextand = 0;    /* Position in AND group of next testable token.*/
  157.      UNCH Psave = 0;          /* For testing whether group ended. */
  158.      int rc = 0;              /* Return code: RCNREQ RCHIT RCMISS RCEND */
  159.      int currhit = (STATUS==RCHIT); /* 1=current GI hit; 0=not. */
  160.  
  161.      /* If the GI was a hit, turn on the hit bit and set the status to
  162.         assume that the token to be tested against the next GI will
  163.         be non-required.  If the current token is repeatable, exit so
  164.         it will stand as the next token to test.
  165.      */
  166.      if (STATUS==RCHIT) {
  167.           BITNON(H, T); STATUS = RCNREQ;
  168.           if (BITON(TOCC, TREP)) return;
  169.      }
  170.      /* At this point, we must determine the next token to test:
  171.         either against the next GI, if this one was a hit, or
  172.         against the same GI if conditions permit a retry.
  173.         To find the next token, we must first end the current group,
  174.         if possible, and any we can that contain it.
  175.         If the outermost group was a hit and is repeatable, or
  176.         if the element has ended, we exit now.
  177.         If it hasn't ended, or was optional and ended with a miss,
  178.         we can retry the GI against the next token.
  179.      */
  180.      if ((STATUS = (UNCH)testend(mod, pos, 1, 1))!=RCNREQ) return;
  181.  
  182.      /* At this point, the "current token" is either the original one,
  183.         or the token for the highest level unhit group that it ended.
  184.         We will retry a missed GI, by testing it against the next
  185.         token, if the current token:
  186.         1. Is optional;
  187.         2. Was hit (i.e., because it is repeatable and was hit by a
  188.            previous GI or because it is a hit group that just ended);
  189.         3. Is in an AND or OR group and is not the last testable token.
  190.  
  191.         It will be the next sequential one (unhit one, in an AND group);
  192.         if there are none left, use the first unhit token in the group.
  193.         In either case, set M to correspond to the new T.
  194.      */
  195.      retest:
  196. #ifndef FINAL
  197.      if (ctrace) traceend((UNCH *)"RETEST", mod, pos, (int)nextand, 1, (int)Tstart);
  198. #endif
  199.      if (GTYPE==TTAND) nextand = offbit(H, (int)T, GNUM);
  200.      if ( BITON(TOCC, TOPT)
  201.        || TOKENHIT
  202.        || GTYPE==TTOR              /* T!=GNUM or group would have ended. */
  203.        || nextand ) {
  204.           if (GTYPE!=TTAND) ++T;   /* T!=GNUM or group would have ended. */
  205.           else T = (UNCH)(nextand ? nextand : offbit(H, 0, GNUM));
  206.           M = G + grpsz(&GHDR, (int)T-1) + 1;
  207.           /* If AND group wrapped, it can end if all non-optionals were hit. */
  208.           if (GTYPE==TTAND && T==Tstart && !currhit) {
  209.                Psave = P;
  210.                rc = testend(mod, pos, 0, 1);
  211.                if (Psave!=P) {if ((STATUS = (UNCH)rc)==RCNREQ) goto retest;}
  212.                else STATUS = RCMISS;
  213.           }
  214.      }
  215.      else STATUS = RCMISS;
  216. #ifndef FINAL
  217.      if (ctrace) traceend((UNCH *)"NEWTOKEN", mod, pos, (int)nextand, 1, (int)Tstart);
  218. #endif
  219.      return;
  220. }
  221. /******************************************************************************/
  222. /* TESTEND: End the current group, if possible, and any that it is nested in.
  223.             The current token will either be a group header, or some token
  224.             that could not end its group.  Return 1 if the (possibly new)
  225.             current token is repeatable; 0 if it is not.
  226. */
  227. int testend(mod, pos, andoptsw, newtknsw)
  228. struct thdr mod[];            /* Model of current open element. */
  229. struct mpos pos[];            /* Position in open element's model. */
  230. int andoptsw;                 /* 1=test optional AND members; 0=ignore. */
  231. int newtknsw;                 /* 1=new token test; 0=end element test. */
  232. {
  233.      int rc = 0;              /* Return code: RCNREQ RCHIT RCMISS RCEND */
  234.  
  235.      while (!rc) {
  236. #ifndef FINAL
  237.           if (ctrace) traceend((UNCH *)"TRACEEND", mod, pos, rc, andoptsw, (int)Tstart);
  238. #endif
  239.           /* TESTMISS:
  240.              If we've hit no tokens yet in the current group, and
  241.              the current token is the last unhit one in the group we can test,
  242.              we will end the group (it may never really have started!)
  243.              because we might be able to try the token that follows it.
  244.              In any group, a token is the last testable unhit token if it
  245.              is the last sequential one, as the GI was already tested against
  246.              the preceding unhit tokens.  In addition,
  247.              in a SEQ group, it is the last testable unhit token if it isn't
  248.              optional, because we can't skip past it to the following ones.
  249.              If we end the group, before popping the level, set M to G, as this
  250.              level`s group header will be the next level's current token.
  251.           */
  252.           if (H==0 && (T==(UNCH)GNUM || GTYPE==TTSEQ && BITOFF(TOCC, TOPT))) {
  253.                M = G; --P; Tstart = T;
  254.                if (P<=1) {
  255.                     if (BITON(TOCC, TOPT) || TOKENHIT) rc = RCEND;
  256.                     else                               rc = RCMISS;
  257.                }
  258.                continue;
  259.           }
  260.           /* TESTHIT:
  261.              See if we've hit all the non-optional tokens in the group.
  262.              If so, pop to the previous level and set the group's hit bit.
  263.              If we were called from NEWTOKEN we are trying to find the token
  264.              to test against the next start-tag, so if the group is repeatable,
  265.              process it again.  (If not, we were called from ECONTEXT and
  266.              are testing whether the element can be ended.)
  267.              Otherwise, if we are at the first level, the element is over.
  268.           */
  269.           if ( GTYPE==TTOR  && TOKENHIT
  270.             || GTYPE==TTSEQ && T==(UNCH)GNUM && (TOKENHIT || BITON(TOCC, TOPT))
  271.             || GTYPE==TTAND && allhit(&GHDR, H, 0, andoptsw) ) {
  272.                M = G; --P; BITNON(H, T); Tstart = T;
  273.                if (newtknsw && BITON(TOCC, TREP)) rc = RCHIT;
  274.                else if (P<=1)                     rc = RCEND;
  275.                /* Else loop to test new outer group. */
  276.           }
  277.           else rc = RCNREQ;   /* No group ended this time, so return. */
  278.      }
  279. #ifndef FINAL
  280.      if (ctrace) traceend((UNCH *)"ENDFOUND", mod, pos, rc, andoptsw, (int)Tstart);
  281. #endif
  282.      return(rc);
  283. }
  284. /******************************************************************************/
  285. /* TOKENOPT: Return 1 if current token is contextually optional;
  286.              otherwise, return 0.
  287. */
  288. int tokenopt(mod, pos)
  289. struct thdr mod[];            /* Model of current open element. */
  290. struct mpos pos[];            /* Position in open element's model. */
  291. {
  292. #ifndef FINAL
  293.      if (ctrace) traceend((UNCH *)"TOKENOPT", mod, pos, 0, 0, (int)Tstart);
  294. #endif
  295.      return( BITON(TOCC, TOPT)/* Inherently optional. */
  296.           || TOKENHIT         /* Was hit (handles "plus" suffix case). */
  297.           || H==0 && groupopt(mod, pos) );/* In optional group with no hits. */
  298. }
  299. /******************************************************************************/
  300. /* GROUPOPT: Temporarily makes the current group be the current token so that
  301.              TOKENOPT() can be applied to it.  Returns the value returned
  302.              by TOKENOPT.
  303. */
  304. int groupopt(mod, pos)
  305. struct thdr mod[];            /* Model of current open element. */
  306. struct mpos pos[];            /* Position in open element's model. */
  307. {
  308.      UNCH saveM;              /* Save M when testing if group is not required.*/
  309.      int rc;                  /* 1=contextually optional; 0=not. */
  310.  
  311.      if (P==1) return(BITON(GOCC, TOPT) || TOKENHIT);
  312.      saveM = M; M = G; --P;
  313.      rc = tokenopt(mod, pos);
  314.      ++P; G = M; M = saveM;
  315.      return(rc);
  316. }
  317. /******************************************************************************/
  318. /* TOKENREQ: Returns RCREQ if the current token is "contextually required".
  319.              That is, it is not contextually optional and
  320.                  1) it is a member of a "seq" group that is either required
  321.                     or has at least 1 hit token.
  322.                  2) it is a member of an "and" group in which all other
  323.                     tokens were hit.
  324.                           Optional tokens are not counted
  325.                           if GI is ETDCDATA, as we are looking for an
  326.                           omitted start-tag.  Otherwise, they are counted,
  327.                           as the GI might match one of them.
  328.              Returns RCNREQ if the current token is "not required".
  329. */
  330. int tokenreq(gi, mod, pos)
  331. struct etd *gi;               /* ETD of new GI. */
  332. struct thdr mod[];            /* Model of current open element. */
  333. struct mpos pos[];            /* Position in open element's model. */
  334. {
  335. #ifndef FINAL
  336.      if (ctrace) tracegi((UNCH *)"TOKENREQ", gi, mod, pos, (int)Tstart);
  337. #endif
  338.      return( tokenopt(mod, pos) ? RCNREQ
  339.             : ( GTYPE==TTSEQ && (H!=0 || groupreq(gi, mod, pos)==RCREQ)
  340.               /*|| GTYPE==TTAND && allhit(&GHDR, H, T, \*gi!=ETDCDATA*\ 1)*/ )
  341.                 ? RCREQ : RCNREQ );
  342. }
  343. /******************************************************************************/
  344. /* GROUPREQ: Temporarily makes the current group be the current token so that
  345.              TOKENREQ() can be applied to it.  Returns the value returned
  346.              by TOKENREQ.
  347. */
  348. int groupreq(gi, mod, pos)
  349. struct etd *gi;               /* ETD of new GI. */
  350. struct thdr mod[];            /* Model of current open element. */
  351. struct mpos pos[];            /* Position in open element's model. */
  352. {
  353.      UNCH saveM;              /* Save M when testing if group is not required.*/
  354.      int rc;                  /* Return code: RCREQ RCNREQ */
  355.  
  356.      if (P==1) return(BITOFF(GOCC, TOPT) ? RCREQ : RCNREQ);
  357.      saveM = M; M = G; --P;
  358.      rc = tokenreq(gi, mod, pos);
  359.      ++P; G = M; M = saveM;
  360.      return(rc);
  361. }
  362. /******************************************************************************/
  363. /* GRPSZ: Returns the number of tokens spanned by a group in the model (M),
  364.           from the group's start (G) to a specified index within the group (T).
  365.           M = 0, plus 1 for each token in the group, plus the size of
  366.           any subgroups (gotten by calling GRPSZ recursively).  On entry,
  367.           M must be equal to G at the current level.
  368. */
  369. int grpsz(g, t)
  370. struct thdr *g;               /* mod[G]: Ptr to group in the model. */
  371. int t;                        /* T: Index of last token in the group. */
  372. {
  373.      struct thdr *p = g;      /* Ptr to current token in the model. */
  374.      int m = 0;               /* Size of group (including nested groups). */
  375.      int i = 0;               /* Number of group members (loop counter). */
  376.      UNS type;                /* Token type (without TOREP bits). */
  377.  
  378.      while (++i<=t) {
  379.           ++p; ++m;
  380.           type = GET(p->ttype, TTMASK);
  381.           if (type==TTOR || type==TTSEQ || type==TTAND) {
  382.                m += grpsz(p, p->tu.tnum);
  383.                p = g+m;
  384.           }
  385.      }
  386.      return(m);
  387. }
  388. /******************************************************************************/
  389. /* ALLHIT: Returns 1 if all hit bits for the specified group are turned on,
  390.            (other than those that correspond to optional tokens if "opt" is
  391.            0) and the "but" bit (all bits if "but" bit is zero).  Otherwise,
  392.            returns 0.  GRPSZ is used to skip past subgroup tokens.
  393. */
  394. int allhit(p, hits, but, opt)
  395. struct thdr *p;               /* mod[G]: Ptr to group in the model. */
  396. long hits;                    /* H: Hit bits to be tested. */
  397. int but;                      /* Index of bit to ignore; 0=test all. */
  398. int opt;                      /* 1=optional tokens must be hit; 0=ignore. */
  399. {
  400.      int b = 0;               /* Index of bit being tested in hits. */
  401.      int e = p->tu.tnum;      /* Ending index (number of bits to test). */
  402.      unsigned type;           /* Token type (without TOREP bits). */
  403.  
  404.      while (++p, ++b<=e) {
  405.           if (BITOFF(hits,1L<<(b-1)) &&(opt || BITOFF(p->ttype,TOPT)) && b!=but)
  406.                return 0;
  407.           if ((type = GET(p->ttype,TTMASK))==TTOR || type==TTSEQ || type==TTAND)
  408.                p += grpsz(p, p->tu.tnum);
  409.      }
  410.      return 1;
  411. }
  412. /******************************************************************************/
  413. /* OFFBIT: Returns the index of the first unset bit after (i.e., not including)
  414.            the caller's "first" bit. If all bits through the
  415.            specified last bit are on, it returns 0.
  416. */
  417. int offbit(bits, first, last)
  418. long bits;                    /* Bits to be tested. */
  419. int first;                    /* Index of first bit to be tested in bits. */
  420. int last;                     /* Index of last bit to be tested in bits. */
  421. {
  422.      while (++first <= last)
  423.           if (BITOFF(bits, 1L<<(first-1))) return first
  424.      ;
  425.      return 0;
  426. }
  427. /******************************************************************************/
  428. #undef GI
  429. #undef NEWGI
  430. #undef STATUS
  431. #undef RCEND
  432. #undef RCREQ
  433. #undef RCMISS
  434. #undef RCHIT
  435. #undef RCMEX
  436. #undef RCHITMEX
  437. #undef RCPEX
  438. #undef RCNREQ
  439. #undef PEX
  440. #undef M
  441. #undef P
  442. #undef G
  443. #undef T
  444. #undef H
  445. #undef GHDR
  446. #undef TOKEN
  447. #undef TTYPE
  448. #undef TOCC
  449. #undef GTYPE
  450. #undef GOCC
  451. #undef GNUM
  452. #undef TOKENHIT
  453. /******************************************************************************/
  454.