home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume24 / mkid2 / part04 / scan-c.c < prev    next >
C/C++ Source or Header  |  1991-10-09  |  8KB  |  372 lines

  1. /* Copyright (c) 1986, Greg McGary */
  2. /* Vhil scanning mods added Jan 7th, 1988 by Tom Horsley */
  3. static char sccsid[] = "@(#)scan-c.c    1.1 86/10/09";
  4.  
  5. #include    <bool.h>
  6. #include    <stdio.h>
  7. #include    <string.h>
  8. #include    <id.h>
  9.  
  10. char *getCId();
  11. char *getVhilId();
  12. void setCArgs();
  13.  
  14. static void clrCtype();
  15. static void setCtype();
  16.  
  17. #define    I1    0x0001    /* 1st char of an identifier [a-zA-Z_] */
  18. #define    DG    0x0002    /* decimal digit [0-9] */
  19. #define    NM    0x0004    /* extra chars in a hex or long number [a-fA-FxXlL] */
  20. #define    C1    0x0008    /* C comment introduction char: / */
  21. #define    C2    0x0010    /* C comment termination  char: * */
  22. #define    Q1    0x0020    /* single quote: ' */
  23. #define    Q2    0x0040    /* double quote: " */
  24. #define    ES    0x0080    /* escape char: \ */
  25. #define    NL    0x0100    /* newline: \n */
  26. #define    EF    0x0200    /* EOF */
  27. #define    SK    0x0400    /* Make these chars valid for names within strings */
  28. #define    VH    0x0800    /* VHIL comment introduction char: # */
  29. #define    WS    0x1000    /* White space characters */
  30.  
  31. /*
  32.     character class membership macros:
  33. */
  34. #define    ISDIGIT(c)    ((rct)[c]&(DG))        /* digit */
  35. #define    ISNUMBER(c)    ((rct)[c]&(DG|NM))    /* legal in a number */
  36. #define    ISEOF(c)    ((rct)[c]&(EF))        /* EOF */
  37. #define    ISID1ST(c)    ((rct)[c]&(I1))        /* 1st char of an identifier */
  38. #define    ISIDREST(c)    ((rct)[c]&(I1|DG))    /* rest of an identifier */
  39. #define    ISSTRKEEP(c)    ((rct)[c]&(I1|DG|SK))    /* keep contents of string */
  40. #define    ISSPACE(c)    ((rct)[c]&(WS))        /* white space character */
  41. /*
  42.     The `BORING' classes should be skipped over
  43.     until something interesting comes along...
  44. */
  45. #define    ISBORING(c)    (!((rct)[c]&(EF|NL|I1|DG|Q1|Q2|C1|VH)))    /* fluff */
  46. #define    ISCBORING(c)    (!((rct)[c]&(EF|C2)))    /* comment fluff */
  47. #define    ISVBORING(c)    (!((rct)[c]&(EF|NL)))    /* vhil comment fluff */
  48. #define    ISQ1BORING(c)    (!((rct)[c]&(EF|NL|Q1|ES)))    /* char const fluff */
  49. #define    ISQ2BORING(c)    (!((rct)[c]&(EF|NL|Q2|ES)))    /* quoted str fluff */
  50.  
  51. static short idctype[] = {
  52.  
  53.     EF,
  54.  
  55.     /*      0       1       2       3       4       5       6       7   */
  56.     /*    -----   -----   -----   -----   -----   -----   -----   ----- */
  57.  
  58.     /*000*/    0,    0,    0,    0,    0,    0,    0,    0,
  59.     /*010*/    0,    0,    NL,    0,    0,    0,    0,    0,
  60.     /*020*/    0,    0,    0,    0,    0,    0,    0,    0,
  61.     /*030*/    0,    0,    0,    0,    0,    0,    0,    0,
  62.     /*040*/    0,    0,    Q2,    0,    0,    0,    0,    Q1,
  63.     /*050*/    0,    0,    C2,    0,    0,    0,    0,    C1,
  64.     /*060*/    DG,    DG,    DG,    DG,    DG,    DG,    DG,    DG,    
  65.     /*070*/    DG,    DG,    0,    0,    0,    0,    0,    0,
  66.     /*100*/    0,    I1|NM,    I1|NM,    I1|NM,    I1|NM,    I1|NM,    I1|NM,    I1,
  67.     /*110*/    I1,    I1,    I1,    I1,    I1|NM,    I1,    I1,    I1,
  68.     /*120*/    I1,    I1,    I1,    I1,    I1,    I1,    I1,    I1,
  69.     /*130*/    I1|NM,    I1,    I1,    0,    ES,    0,    0,    I1,
  70.     /*140*/    0,    I1|NM,    I1|NM,    I1|NM,    I1|NM,    I1|NM,    I1|NM,    I1,
  71.     /*150*/    I1,    I1,    I1,    I1,    I1|NM,    I1,    I1,    I1,
  72.     /*160*/    I1,    I1,    I1,    I1,    I1,    I1,    I1,    I1,
  73.     /*170*/    I1|NM,    I1,    I1,    0,    0,    0,    0,    0,
  74.  
  75.     /*200*/    0,    0,    0,    0,    0,    0,    0,    0,
  76.     /*210*/    0,    0,    0,    0,    0,    0,    0,    0,
  77.     /*220*/    0,    0,    0,    0,    0,    0,    0,    0,
  78.     /*230*/    0,    0,    0,    0,    0,    0,    0,    0,
  79.     /*240*/    0,    0,    0,    0,    0,    0,    0,    0,
  80.     /*250*/    0,    0,    0,    0,    0,    0,    0,    0,
  81.     /*260*/    0,    0,    0,    0,    0,    0,    0,    0,
  82.     /*270*/    0,    0,    0,    0,    0,    0,    0,    0,
  83.     /*300*/    0,    0,    0,    0,    0,    0,    0,    0,
  84.     /*310*/    0,    0,    0,    0,    0,    0,    0,    0,
  85.     /*320*/    0,    0,    0,    0,    0,    0,    0,    0,
  86.     /*330*/    0,    0,    0,    0,    0,    0,    0,    0,
  87.     /*340*/    0,    0,    0,    0,    0,    0,    0,    0,
  88.     /*350*/    0,    0,    0,    0,    0,    0,    0,    0,
  89.     /*360*/    0,    0,    0,    0,    0,    0,    0,    0,
  90.     /*370*/    0,    0,    0,    0,    0,    0,    0,    0,
  91.  
  92. };
  93.  
  94. static bool eatUnder = TRUE;
  95. static bool scanVhil = FALSE;
  96.  
  97. /*
  98. */
  99. char *
  100. getVhilId(inFILE, flagP)
  101. {
  102.     if (! scanVhil) {
  103.         setCArgs("vhil",'+',"v");
  104.     }
  105.     return(getCId(inFILE, flagP));
  106. }
  107.  
  108. /*
  109.     Grab the next identifier the C source
  110.     file opened with the handle `inFILE'.
  111.     This state machine is built for speed, not elegance.
  112. */
  113. char *
  114. getCId(inFILE, flagP)
  115.     FILE        *inFILE;
  116.     int        *flagP;
  117. {
  118.     static char    idBuf[BUFSIZ];
  119.     static bool    newLine = TRUE;
  120.     register short    *rct = &idctype[1];
  121.     register int    c;
  122.     register char    *id = idBuf;
  123.  
  124. top:
  125.     c = getc(inFILE);
  126.     if (newLine) {
  127.         newLine = FALSE;
  128.         if (c == '.') {
  129.             /* Auto-recognize vhil code when you see a . in column 1.
  130.              * also ignore lines that start with a .
  131.              */
  132.             if (! scanVhil) {
  133.                 setCArgs("vhil",'+',"v");
  134.             }
  135.             while (ISVBORING(c))
  136.                 c = getc(inFILE);
  137.             newLine = TRUE;
  138.             goto top;
  139.         }
  140.         if (c != '#')
  141.             goto next;
  142.         c = getc(inFILE);
  143.         if (scanVhil && ISSPACE(c)) {
  144.             while (ISVBORING(c))
  145.                 c = getc(inFILE);
  146.             newLine = TRUE;
  147.             goto top;
  148.         }
  149.         while (ISBORING(c))
  150.             c = getc(inFILE);
  151.         if (!ISID1ST(c))
  152.             goto next;
  153.         id = idBuf;
  154.         *id++ = c;
  155.         while (ISIDREST(c = getc(inFILE)))
  156.             *id++ = c;
  157.         *id = '\0';
  158.         if (strequ(idBuf, "include")) {
  159.             while (c == ' ' || c == '\t') c = getc(inFILE) ;
  160.             if (c == '\n') {newLine = TRUE; goto top;}
  161.             id = idBuf;
  162.             if (c == '"') {
  163.                 c = getc(inFILE);
  164.                 while (c != '\n' && c != EOF && c != '"') {
  165.                     *id++ = c;
  166.                     c = getc(inFILE);
  167.                 }
  168.                 *flagP = IDN_STRING;
  169.             } else if (c == '<') {
  170.                 c = getc(inFILE);
  171.                 while (c != '\n' && c != EOF && c != '>') {
  172.                     *id++ = c;
  173.                     c = getc(inFILE);
  174.                 }
  175.                 *flagP = IDN_STRING;
  176.             } else if (ISID1ST(c)) {
  177.                 *id++ = c ;
  178.                 while (ISIDREST(c = getc(inFILE))) *id++ = c;
  179.                 *flagP = IDN_NAME;
  180.             } else {
  181.                 while (c != '\n' && c != EOF) c = getc(inFILE);
  182.                 newLine = TRUE;
  183.                 goto top;
  184.             }
  185.             while (c != '\n' && c != EOF) c = getc(inFILE) ;
  186.             newLine = TRUE;
  187.             *id = '\0';
  188.             return idBuf;
  189.         }
  190.         if (strnequ(idBuf, "if", 2)
  191.         || strequ(idBuf, "define")
  192.         || strequ(idBuf, "elif")         /* ansi C */
  193.         || (scanVhil && strequ(idBuf, "elsif"))
  194.         || strequ(idBuf, "undef"))
  195.             goto next;
  196.         while ((c != '\n') && (c != EOF))
  197.             c = getc(inFILE);
  198.         newLine = TRUE;
  199.         goto top;
  200.     }
  201.  
  202. next:
  203.     while (ISBORING(c))
  204.         c = getc(inFILE);
  205.  
  206.     switch (c)
  207.     {
  208.     case '"':
  209.         id = idBuf;
  210.         *id++ = c = getc(inFILE);
  211.         for (;;) {
  212.             while (ISQ2BORING(c))
  213.                 *id++ = c = getc(inFILE);
  214.             if (c == '\\') {
  215.                 *id++ = c = getc(inFILE);
  216.                 continue;
  217.             } else if (c != '"')
  218.                 goto next;
  219.             break;
  220.         }
  221.         *--id = '\0';
  222.         id = idBuf;
  223.         while (ISSTRKEEP(*id))
  224.             id++;
  225.         if (*id || id == idBuf) {
  226.             c = getc(inFILE);
  227.             goto next;
  228.         }
  229.         *flagP = IDN_STRING;
  230.         if (eatUnder && idBuf[0] == '_' && idBuf[1])
  231.             return &idBuf[1];
  232.         else
  233.             return idBuf;
  234.         
  235.     case '\'':
  236.         c = getc(inFILE);
  237.         for (;;) {
  238.             while (ISQ1BORING(c))
  239.                 c = getc(inFILE);
  240.             if (c == '\\') {
  241.                 c = getc(inFILE);
  242.                 continue;
  243.             } else if (c == '\'')
  244.                 c = getc(inFILE);
  245.             goto next;
  246.         }
  247.  
  248.     case '/':
  249.         if ((c = getc(inFILE)) != '*')
  250.             goto next;
  251.         c = getc(inFILE);
  252.         for (;;) {
  253.             while (ISCBORING(c))
  254.                 c = getc(inFILE);
  255.             if ((c = getc(inFILE)) == '/') {
  256.                 c = getc(inFILE);
  257.                 goto next;
  258.             } else if (ISEOF(c)) {
  259.                 newLine = TRUE;
  260.                 return NULL;
  261.             }
  262.         }
  263.  
  264.     case '\n':
  265.         newLine = TRUE;
  266.         goto top;
  267.  
  268.     case '#':
  269.         if (! scanVhil) {
  270.             /* Auto-recognize vhil when find a # in the middle of a line.
  271.              */
  272.             setCArgs("vhil",'+',"v");
  273.         }
  274.         c = getc(inFILE);
  275.         while (ISVBORING(c))
  276.             c = getc(inFILE);
  277.         newLine = TRUE;
  278.         goto top;
  279.     default:
  280.         if (ISEOF(c)) {
  281.             newLine = TRUE;
  282.             return NULL;
  283.         }
  284.     name:
  285.         id = idBuf;
  286.         *id++ = c;
  287.         if (ISID1ST(c)) {
  288.             *flagP = IDN_NAME;
  289.             while (ISIDREST(c = getc(inFILE)))
  290.                 *id++ = c;
  291.         } else if (ISDIGIT(c)) {
  292.             *flagP = IDN_NUMBER;
  293.             while (ISNUMBER(c = getc(inFILE)))
  294.                 *id++ = c;
  295.         } else
  296.             fprintf(stderr, "junk: `\\%3o'", c);
  297.         ungetc(c, inFILE);
  298.         *id = '\0';
  299.         *flagP |= IDN_LITERAL;
  300.         return idBuf;
  301.     }
  302. }
  303.  
  304. static void
  305. setCtype(chars, type)
  306.     char        *chars;
  307.     int        type;
  308. {
  309.     short        *rct = &idctype[1];
  310.  
  311.     while (*chars)
  312.         rct[*chars++] |= type;
  313. }
  314. static void
  315. clrCtype(chars, type)
  316.     char        *chars;
  317.     int        type;
  318. {
  319.     short        *rct = &idctype[1];
  320.  
  321.     while (*chars)
  322.         rct[*chars++] &= ~type;
  323. }
  324.  
  325. extern char    *MyName;
  326. static void
  327. usage(lang)
  328.     char        *lang;
  329. {
  330.     fprintf(stderr, "Usage: %s does not accept %s scanner arguments\n", MyName, lang);
  331.     exit(1);
  332. }
  333. static char *cDocument[] =
  334. {
  335. "The C scanner arguments take the form -Sc<arg>, where <arg>",
  336. "is one of the following: (<cc> denotes one or more characters)",
  337. "  (+|-)u . . . . (Do|Don't) strip a leading `_' from ids in strings.",
  338. "  -s<cc> . . . . Allow <cc> in string ids.",
  339. "  -v . . . . . . Skip vhil comments.",
  340. NULL
  341. };
  342. void
  343. setCArgs(lang, op, arg)
  344.     char        *lang;
  345.     int        op;
  346.     char        *arg;
  347. {
  348.     if (op == '?') {
  349.         document(cDocument);
  350.         return;
  351.     }
  352.     switch (*arg++)
  353.     {
  354.     case 'u':
  355.         eatUnder = (op == '+');
  356.         break;
  357.     case 's':
  358.         setCtype(arg, SK);
  359.         break;
  360.     case 'v':
  361.         setCtype("$", I1);
  362.         setCtype("#", VH);
  363.         setCtype(" \t", WS);
  364.         scanVhil = TRUE;
  365.         break;
  366.     default:
  367.         if (lang)
  368.             usage(lang);
  369.         break;
  370.     }
  371. }
  372.