home *** CD-ROM | disk | FTP | other *** search
/ rtsi.com / 2014.01.www.rtsi.com.tar / www.rtsi.com / OS9 / TOP / USR / SRC / scpp.t.Z / scpp.t / scpp.c < prev    next >
C/C++ Source or Header  |  2009-11-06  |  14KB  |  668 lines

  1. /*
  2.  * scpp.c - main processing for the selective C preprocessor, scpp.
  3.  *
  4.  * Copyright (c) 1985 by
  5.  * Tektronix, Incorporated Beaverton, Oregon 97077
  6.  * All rights reserved.
  7.  *
  8.  * Permission is hereby granted for personal, non-commercial
  9.  * reproduction and use of this program, provided that this
  10.  * notice and all copyright notices are included in any copy.
  11.  */
  12.  
  13. #define VARS
  14. # include <stdio.h>
  15. # include "scpp.h"
  16. # include "y.tab.h"
  17.  
  18. /*
  19.  * actual[] - the array of actual parameters of the macro currently being
  20.  *  interpreted.
  21.  */
  22.  
  23. struct anactual {
  24.     char *aa_val;    /*
  25.              * the value of this actual (a pointer to the null-
  26.              * terminator.  see amacro.am_val in scpp.h).
  27.              */
  28.     char *aa_mem;    /*
  29.              * points to the beginning of the aa_val string.
  30.              * Used to later free the value's memory.
  31.              */
  32. };
  33. #define ACTSIZ MAXPARMS
  34. struct anactual actual[ACTSIZ];
  35. struct anactual *actp;    /* the next available slot in actual[] */
  36.  
  37.  
  38.  
  39. main(argc, argv)
  40. int argc;
  41. char **argv;
  42. {
  43.     int tok;    /* current token's value    */
  44.     char *cp;
  45.     char *ep;
  46.     char **dp;    /* where within dirlist to put the next directory */
  47.     struct amacro *np;
  48.     char *name;    /* name of the current macro    */
  49.     char *val;    /* value of the current macro    */
  50.     char *defmagic = "defined";    /* name of the 'defined()' macro */
  51.     struct amacro *magmac;    /* (temp) slot for the magic macro */
  52.  
  53.     /*
  54.      * init all the global structures
  55.      */
  56.  
  57.     nxtout = &pend[0];
  58.     curfile = &filestk[-1];
  59.     nxtin = &istk[ISTKSIZ];
  60.     curif = &ifstk[-1];
  61.     
  62.     nxtfile = &catlist[0];
  63.     dp = &dirlist[0];
  64.  
  65.     /*
  66.      * setup the keyword symbols and the special macro, 'defined()'.
  67.      */
  68.  
  69.     ikeywords();
  70.     magmac = findmac(defmagic, defmagic + strlen(defmagic));
  71.     if (magmac->am_name) {
  72.         bomb("INTERNAL: 'defined()' macro slot in use");
  73.     }
  74.     magmac->am_name = defmagic;
  75.     magmac->am_npar = 1;
  76.     magmac->am_val = &magicval;
  77.  
  78.     while (++argv, --argc > 0) {
  79.         cp = *argv;
  80.         if (*cp == '-' && *(cp + 1) != '\0') {
  81.             switch(*++cp) {
  82.             case 'C':
  83.                 savcom = TRUE;
  84.                 break;
  85.             case 'I':
  86.                 *dp++ = cp + 1;
  87.                 break;
  88.             case 'M':
  89.                 /*
  90.                  * for each name in the list of whitespace-
  91.                  *  separated macro names,
  92.                  * Setup a slot for that macro, but leave it
  93.                  *  undefined.
  94.                  */
  95.  
  96.                 while (*cp) {
  97.                     while (*++cp == ' ' || *cp == '\t' ||
  98.                         *cp == '\n')
  99.                         ;
  100.                     if (*cp == '\0') {
  101.                         break;
  102.                     }
  103.                     for (name = cp; *cp != '\0' &&
  104.                       *cp != ' ' && *cp != '\t' &&
  105.                       *cp != '\n'; ++cp)
  106.                         ;
  107.  
  108.                     np = findmac(name, cp);
  109.                     if (np->am_name == (char *) 0) {
  110.                         np->am_name = savtok(name, cp);
  111.                         np->am_npar = -1;
  112.                     }
  113.                     /* am_val is left as zero */
  114.                 }
  115.                 break;
  116.             case 'D':
  117.                 for (name = ++cp; *cp != '\0' && *cp != '=';
  118.                   ++cp)
  119.                     ;
  120.                 if (name == cp) {
  121.                     warn("missing macro name in `%s'",
  122.                       name - 2);
  123.                     break;
  124.                 }
  125.  
  126.                 if (*cp == '\0') {
  127.                     /*
  128.                      * macro name with no definition.
  129.                      * Define the name with no parameters
  130.                      *  and with a value of "1".
  131.                      */
  132.  
  133.                     defmac(name, cp, -1, "1");
  134.                 } else {
  135.                     /* macro + definition */
  136.  
  137.                     for (*cp++ = '\0', val = cp;
  138.                       *cp != '\0'; ++cp)
  139.                         ;
  140.                     defmac(name, name + strlen(name),
  141.                       -1, val);
  142.                 }
  143.                 break;
  144.             default:
  145.                 bomb("unknown switch `%c'", *cp);
  146.             }
  147.         } else {
  148.             *nxtfile++ = cp;
  149.         }
  150.     }
  151.  
  152.     if (nxtfile == &catlist[0]) {
  153.         *nxtfile++ = "-";
  154.     }
  155.     *nxtfile = (char *) 0;
  156.     nxtfile = &catlist[0];
  157.  
  158.     *dp++ = "/h0/DEFS";    /* /usr/include    */
  159.     *dp = (char *) 0;
  160.  
  161.     /*
  162.      * prime the input stack and go,
  163.      * interpreting preprocessor directives along the way.
  164.      */
  165.  
  166.     pushfile(*nxtfile++, PF_NOLOOK, PF_NOHIDE);
  167.     do {
  168.         tok = gintok();
  169.         if (tok == POUNDLINE) {
  170.             tok = doctrl(curtext);
  171.         }
  172.         outpend();    /* even the 0 token needs to be flushed.
  173.                  * Otherwise, incomplete comments at the end
  174.                  * of the file would be destroyed.
  175.                  */
  176.     } while (tok != 0);
  177.     writepend();        /* flush trailing output    */
  178.  
  179.     if (curif >= &ifstk[0]) {
  180.         warnf("missing endif");
  181.     }
  182.  
  183.     exit(sawerror ? 1 : 0);
  184. }
  185.  
  186. int
  187. gintok()    /* get a token, interpreting macro's    */
  188. {
  189.     int tok;        /* the current token's value    */
  190.     struct amacro *mac;    /* the current macro        */
  191.     struct amacro *defsym;    /* the macro being checked for 'defined()' */
  192.     char *mactext;        /*
  193.                  * the start of the invocation of a macro
  194.                  * which has parameters.
  195.                  */
  196.     char *start;        /* the start of the current parameter    */
  197.     int nest;        /*
  198.                  * current nesting level of parentheses.
  199.                  * used to avoid misinterpreting commas within
  200.                  * nested parens as parameter separators.
  201.                  */
  202.     char *defident;        /*
  203.                  * The IDENT parameter for the magic macro,
  204.                  * 'defined()' (dynamically alloc'ed).
  205.                  * If gintok() is interpreting the magic macro,
  206.                  * this variable is marked so that, during the
  207.                  * parameter parsing, the first IDENT is saved
  208.                  * here.
  209.                  */
  210.     int parmgripe;        /*
  211.                  * "an error message about parameters of
  212.                  * this macro has already been printed."
  213.                  */
  214.     int i;            /* an actual-parameter index    */
  215.     char *cp;        /* a temp pointer        */
  216.  
  217.     /*
  218.      * special macro values (see scpp.h: struct amacro, field am_val):
  219.      *  noval == a null macro value;
  220.      *  oneval == a macro value of '1';
  221.      *  zeroval == a macro value of '0';
  222.      */
  223.  
  224.     static char nv[2] = {'\0', '\0'};
  225.     static char *noval = &nv[1];
  226.     static char ov[3] = {'\0', '1', '\0'};
  227.     static char *oneval = &ov[2];
  228.     static char zv[3] = {'\0', '0', '\0'};
  229.     static char *zeroval = &zv[2];
  230.  
  231.  
  232.     tok = OTHER;
  233.     while (tok != DEFMAC && (tok = gtok()) != 0) {
  234.         if (tok == QUOTE || tok == DQUOTE) {
  235.             tok = gstrtok(tok);
  236.         }
  237.         if (tok != IDENT) {
  238.             return(tok);
  239.         }
  240.  
  241.         if ((mac = findmac(curtext, nxtout))->am_name == (char *) 0 ||
  242.             mac->am_val == (char *) 0) {
  243.             /* there is no macro by this name currently defined */
  244.  
  245.             return(tok);
  246.         }
  247.  
  248.         /*
  249.          * tally this interpretation
  250.          */
  251.  
  252.         ++ninterp;
  253.  
  254.         if (mac->am_npar < 0) {
  255.             /*
  256.              * the macro has no formal parameters.
  257.              * pushback the replacement text and continue.
  258.              */
  259.  
  260.             (void) dispose(curtext);
  261.             (void) pushmac(mac->am_val);
  262.             continue;
  263.         }
  264.  
  265.         /* this is a macro with formals */
  266.  
  267.         /*
  268.          * save the starting-point of the macro's text.
  269.          * Used for later disposal.  The text is not disposed
  270.          * here in case the macro is a 'defined()' of some non--M'ed
  271.          * macro.
  272.          */
  273.  
  274.         mactext = curtext;
  275.  
  276.         /*
  277.          * collect the comma-separated actual parameters of the macro,
  278.          * ignoring commas within pairs of parens or within strings.
  279.          */
  280.  
  281.         parmgripe = FALSE;
  282.         actp = &actual[0];
  283.         nest = 0;
  284.         if (mac->am_val == &magicval) {
  285.             defident = &magicval;
  286.         } else {
  287.             defident = (char *) 0;
  288.         }
  289.  
  290.         if ((tok = nonwhite(gtok)) != LP) {
  291.             warnf("missing parenthesis in macro");
  292.             parmgripe = TRUE;
  293.     
  294.             /* pushback the erroneous token    */
  295.             untok();
  296.         } else {
  297.             do {
  298.                 /* collect one parameter */
  299.  
  300.                 start = nxtout;
  301.                 while ((tok = gtok())) {
  302.                     if (tok == CM && nest == 0) {
  303.                         break;
  304.                     } else if (tok == RP) {
  305.                         if (nest > 0) {
  306.                             --nest;
  307.                         } else if (nest == 0) {
  308.                             break;
  309.                         }
  310.                     } else if (tok == LP) {
  311.                         ++nest;
  312.                     } else if (tok == QUOTE ||
  313.                       tok == DQUOTE) {
  314.                         tok = gstrtok(tok);
  315.                     } else if (tok == IDENT &&
  316.                       defident == &magicval) {
  317.                         defident =
  318.                           savtok(curtext, nxtout);
  319.                     }
  320.                 }
  321.  
  322.                 /*
  323.                  * Warn about too many parameters, otherwise,
  324.                  * store the parameter in the format of
  325.                  * a macro value.
  326.                  */
  327.  
  328.                 if ((actp - &actual[0]) >= mac->am_npar) {
  329.                     if (!parmgripe) {
  330.                       warnf("macro parameter mismatch");
  331.                       parmgripe = TRUE;
  332.                     }
  333.                 } else {
  334.                     cp = savtok(start - 1, curtext);
  335.                     *cp = '\0';
  336.                     actp->aa_mem = cp;
  337.                     while (*++cp)
  338.                         ;
  339.                     actp->aa_val = cp;
  340.                     ++actp;
  341.                 }
  342.             } while (tok == CM);
  343.             if (tok != RP) {
  344.                 if (!parmgripe) {
  345.                   warnf("missing parenthesis in macro");
  346.                   parmgripe = TRUE;
  347.                 }
  348.             }
  349.         }
  350.  
  351.         /*
  352.          * If there are too few actual parameters, fill out the
  353.          * list with null values.
  354.          */
  355.  
  356.         while (actp - &actual[0] < mac->am_npar) {
  357.             if (!parmgripe) {
  358.                 warnf("parameter mismatch");
  359.                 parmgripe = TRUE;
  360.             }
  361.             actp->aa_val = noval;
  362.             actp->aa_mem = (char *) 0;
  363.             ++actp;
  364.         }
  365.  
  366.         /*
  367.          * replace the macro invocation with the value of the macro,
  368.          *  replacing formal arguments with the corresponding actual.
  369.          */
  370.  
  371.         if ((cp = mac->am_val) == &magicval) {
  372.             /*
  373.              * This is the magic macro, "defined(x)".
  374.              * Interpret only if the parameter is a -M'ed
  375.              *  macro and we are currently parsing a
  376.              *  #if expression.
  377.              * Lookup the parameter (if any);
  378.              * If the parameter is -M'ed, pushback a '1' or '0',
  379.              * depending on whether the macro is defined.
  380.              */
  381.  
  382.             defsym = findmac(defident, defident + strlen(defident));
  383.             if (!defsym->am_name || !expparse) {
  384.                 /*
  385.                  * Leave the invocation of defined() untouched.
  386.                  */
  387.  
  388.                 curtext = mactext;
  389.                 tok = DEFMAC;
  390.             } else {
  391.                 (void) dispose(mactext);
  392.                 if (defsym->am_val) {
  393.                     (void) pushmac(oneval);
  394.                 } else {
  395.                     (void) pushmac(zeroval);
  396.                 }
  397.             }
  398.             free(defident);
  399.         } else {
  400.             (void) dispose(mactext);
  401.             while (*(cp = pushmac(cp)) == ATTN) {
  402.                 i = (int) (*--cp) - 1;
  403.                 if (i < 0 || i >= mac->am_npar) {
  404.                     warnf(
  405. "INTERNAL: parameter number %d out of bounds", i);
  406.                 } else {
  407.                     (void) pushmac(actual[i].aa_val);
  408.                 }
  409.             }
  410.         }
  411.  
  412.         /*
  413.          * free the actual parameters.
  414.          */
  415.  
  416.         while (--actp >= &actual[0]) {
  417.             if (actp->aa_mem) {
  418.                 free(actp->aa_mem);
  419.             }
  420.         }
  421.     }
  422.     return(tok);
  423. }
  424.  
  425. /*
  426.  * gtok() - get a token without interpreting macros or preprocessor directives.
  427.  *  This is the low-level lexical analyzer.  It exists only because Lex's
  428.  *  analyzer chokes on long comments.
  429.  */
  430.  
  431. int
  432. gtok()
  433. {
  434.     int tok;
  435.  
  436.  
  437.     curtext = nxtout;
  438.     tok = xxlex();
  439.     if (tok == OPENC) {
  440.         while ((tok = xxlex()) != CLOSEC) {
  441.             if (tok == 0) {
  442.                 warnf("unterminated comment");
  443.                 return(0);
  444.             }
  445.         }
  446.         tok = COMMENT;
  447.     }
  448.     return(tok);
  449. }
  450.  
  451. /*
  452.  * gstrtok - get a string token.  Given the token which starts a string
  453.  *  or character constant (I.E. QUOTE or DQUOTE), collect the string token
  454.  *  as if it had been recognised by the lexical analyzer as a single token.
  455.  */
  456.  
  457. int
  458. gstrtok(tok)
  459. int tok;        /* token which started the quoted string    */
  460. {
  461.     int tok2;        /* the next token's value    */
  462.     char *qstrt;        /* start of a string in pend[]    */
  463.  
  464.     /*
  465.      * collect the string without interpreting
  466.      * macros.  Allow \' and \" within strings.
  467.      * Newline or EOF terminate strings.
  468.      * Save and restore curtext so that on returning,
  469.      * curtext points to the beginning of the token.
  470.      */
  471.  
  472.     qstrt = curtext;
  473.     while ((tok2 = gtok()) != tok) {
  474.         if (tok2 == 0) {
  475.             /* unterminated quote    */
  476.             curtext = qstrt;
  477.             return(0);
  478.         }
  479.         if (tok2 == NL) {
  480.             /* unterminated quote. pushback the newline    */
  481.  
  482.             untok();
  483.             break;
  484.         }
  485.         if (tok2 == BACKS) {
  486.             if (gtok() == 0) {
  487.                 /* unterminated quote */
  488.                 curtext = qstrt;
  489.                 return(0);
  490.             }
  491.         }
  492.     }
  493.     curtext = qstrt;
  494.     return(tok == DQUOTE ? STRING : CHARS);
  495. }
  496.  
  497. /*
  498.  * findmac - find a macro
  499.  *  given the bounds of what might be a macro name (possibly containing ATTN
  500.  *   bytes), return a pointer to the symbol table slot
  501.  *  corresponding to that name.
  502.  */
  503.  
  504. struct amacro *
  505. findmac(name, last)
  506. char *name;    /* points to the beginning of the name.            */
  507. char *last;    /* points to the char beyond the end of the name    */
  508. {
  509.     /*
  510.      * hash the first 8 chars of the name (less ATTN bytes) into an index;
  511.      * Use that index as a starting point for a linear search
  512.      *  for either the matching slot or an empty slot.
  513.      */
  514.  
  515.     int idx;
  516.     char *cp;
  517.     char *tp;
  518.     int cnt;
  519.     struct amacro *np, *start;
  520.  
  521.  
  522.     for (idx = 0, cp = name, cnt = 0; cp < last && cnt < 8; ++cp) {
  523.         if (*cp == ATTN) {
  524.             ++cp;
  525.         } else {
  526.             idx += (int) *cp++ & 0xff;
  527.             ++cnt;
  528.         }
  529.     }
  530.     start = np = &sym[idx % SYMSIZ];
  531.  
  532.     while (np->am_name) {
  533.         /*
  534.          * compare the token at 'name' with the macro's name,
  535.          * skipping ATTN bytes and their associated codes.
  536.          */
  537.  
  538.         for (tp = name, cp = np->am_name; tp < last; ++tp) {
  539.             if (*tp == ATTN) {
  540.                 ++tp;
  541.                 continue;
  542.             }
  543.             if (*tp != *cp++) {
  544.                 break;
  545.             }
  546.         }
  547.         if (tp == last) {
  548.             /* the names match */
  549.             break;
  550.         }
  551.  
  552.         if (++np >= &sym[SYMSIZ]) {
  553.             np = &sym[0];
  554.         }
  555.         if (np == start) {
  556.             bombf("symbol table overflow");
  557.         }
  558.     }
  559.     return(np);
  560. }
  561.  
  562. /*
  563.  * defmac - define a macro
  564.  */
  565.  
  566. defmac(name, end, npar, val)
  567. char *name;        /* the start of the macro's name        */
  568. char *end;        /* points to one char beyond the end of the name */
  569. int npar;        /* # of parameters (-1 == none)            */
  570. char *val;        /* the beginning of the value string        */
  571. {
  572.     char *cp;
  573.     struct amacro *np;
  574.     struct akeyword *kp;
  575.     char *malloc();
  576.  
  577.  
  578.     /*
  579.      * find the slot for the macro and give it a name if this is the
  580.      * first occurrence of this name.
  581.      */
  582.  
  583.     np = findmac(name, end);
  584.     if (!np->am_name) {
  585.         np->am_name = savtok(name, end);
  586.     } else {
  587.         /*
  588.          * Don't allow preprocessor keywords to be defined.
  589.          */
  590.  
  591.         if ((kp = findkey(np)) != (struct akeyword *) 0) {
  592.             warnf("redeclaration of keyword \"%s\"", kp->ak_name);
  593.             return;
  594.         }
  595.  
  596.         /*
  597.          * if the macro is currently defined (I.E. has a value),
  598.          *  reject redefinitions of magic macros.
  599.          * compare the new and old values.
  600.          * If the value or number of parameters differs,
  601.          *  print a warning and destroy the old value.
  602.          * If they are the same, do nothing (return).
  603.          */
  604.  
  605.         if (np->am_val) {
  606.             if (np->am_val == &magicval) {
  607.                 warnf("cannot redefine implicit macro");
  608.                 return;
  609.             }
  610.             cp = np->am_val;
  611.             while (*--cp)
  612.                 ;
  613.             if (np->am_npar == npar && strcmp(cp + 1, val) == 0) {
  614.                 return;
  615.             }
  616.  
  617.             warnf("redeclaration of \"%s\"", np->am_name);
  618.             free(cp);
  619.         }
  620.     }
  621.  
  622.     /*
  623.      * Set the new value and number of parameters.
  624.      * Put a null introduction on the value;
  625.      * Remember that am_val points to the *end* of the value.
  626.      */
  627.  
  628.     np->am_npar = npar;
  629.  
  630.     if (!(cp = malloc((unsigned) strlen(val) + 2))) {
  631.         bombf("out of memory");
  632.     }
  633.     *cp++ = '\0';
  634.     strcpy(cp, val);
  635.     np->am_val = cp + strlen(cp);
  636. }
  637.  
  638. /*
  639.  * savtok - given the limits of a token string,
  640.  *  copy that string (less ATTN bytes) into a dynamically allocated buffer
  641.  *  then return the buffer.
  642.  */
  643.  
  644. char *
  645. savtok(s, e)
  646. char *s;    /* first char of token            */
  647. char *e;    /* points beyond the last char of token    */
  648. {
  649.     char *name;    /* the text of the token -- the value to return    */
  650.     char *cp;
  651.     char *malloc();
  652.  
  653.     if (!(name = malloc(e - s + 1))) {
  654.         bombf("out of memory");
  655.     }
  656.  
  657.     for (cp = name; s < e; ++s) {
  658.         if (*s == ATTN) {
  659.             ++s;
  660.         } else {
  661.             *cp++ = *s;
  662.         }
  663.     }
  664.     *cp = '\0';
  665.  
  666.     return(name);
  667. }
  668.