home *** CD-ROM | disk | FTP | other *** search
/ ftp.cs.arizona.edu / ftp.cs.arizona.edu.tar / ftp.cs.arizona.edu / icon / historic / v92.tgz / v92.tar / v92 / src / preproc / macro.c < prev    next >
C/C++ Source or Header  |  1996-03-22  |  18KB  |  661 lines

  1. /*
  2.  * This file contains various functions for dealing with macros.
  3.  */
  4. #include "::preproc:preproc.h"
  5. #include "::preproc:ptoken.h"
  6. #include "::preproc:pproto.h"
  7.  
  8. /*
  9.  * Prototypes for static functions.
  10.  */
  11. hidden struct macro     **m_find      Params((char *mname));
  12. hidden int                eq_id_lst   Params((struct id_lst *lst1,
  13.                                         struct id_lst *lst2));
  14. hidden int                eq_tok_lst  Params((struct tok_lst *lst1,
  15.                                         struct tok_lst *lst2));
  16. hidden int                parm_indx   Params((char *id, struct macro *m));
  17. hidden novalue            cpy_str     Params((char *ldelim, char *image,
  18.                                         char *rdelim, struct str_buf *sbuf));
  19. hidden struct token      *stringize   Params((struct token *trigger,
  20.                                         struct mac_expand *me));
  21. hidden struct paste_lsts *paste_parse Params((struct token *t,
  22.                                         struct mac_expand *me));
  23. hidden int               *cpy_image   Params((struct token *t, int *s));
  24.  
  25. #define MacTblSz 149
  26. #define MHash(x) (((unsigned int) x) % MacTblSz)
  27.  
  28. static struct macro *m_table[MacTblSz];    /* hash table of macros */
  29.  
  30. int max_recurse;
  31.  
  32. /*
  33.  * Some string to put in the string table:
  34.  */
  35. static char *line_mac = "__LINE__";
  36. static char *file_mac = "__FILE__";
  37. static char *date_mac = "__DATE__";
  38. static char *time_mac = "__TIME__";
  39. static char *rcrs_mac = "__RCRS__";
  40. static char *defined = "defined";
  41.  
  42. /*
  43.  * m_find - return return location of pointer to where macro belongs in
  44.  *  macro table. If the macro is not in the table, the pointer at the
  45.  *  location is NULL.
  46.  */
  47. static struct macro **m_find(mname)
  48. char *mname;
  49.    {
  50.    struct macro **mpp;
  51.  
  52.    for (mpp = &m_table[MHash(mname)]; *mpp != NULL && (*mpp)->mname != mname;
  53.       mpp = &(*mpp)->next)
  54.       ;
  55.    return mpp;
  56.    }
  57.  
  58. /*
  59.  * eq_id_lst - check to see if two identifier lists contain the same identifiers
  60.  *  in the same order.
  61.  */
  62. static int eq_id_lst(lst1, lst2)
  63. struct id_lst *lst1;
  64. struct id_lst *lst2;
  65.    {
  66.    if (lst1 == lst2)
  67.       return 1;
  68.    if (lst1 == NULL || lst2 == NULL)
  69.       return 0;
  70.    if (lst1->id != lst2->id)
  71.       return 0;
  72.    return eq_id_lst(lst1->next, lst2->next);
  73.    }
  74.  
  75. /*
  76.  * eq_tok_lst - check to see if 2 token lists contain the same tokens
  77.  *  in the same order. All white space tokens are considered equal.
  78.  */
  79. static int eq_tok_lst(lst1, lst2)
  80. struct tok_lst *lst1;
  81. struct tok_lst *lst2;
  82.    {
  83.    if (lst1 == lst2)
  84.       return 1;
  85.    if (lst1 == NULL || lst2 == NULL)
  86.       return 0;
  87.    if (lst1->t->tok_id != lst2->t->tok_id)
  88.       return 0;
  89.    if (lst1->t->tok_id != WhiteSpace && lst1->t->tok_id != PpDirEnd &&
  90.         lst1->t->image != lst2->t->image)
  91.       return 0;
  92.    return eq_tok_lst(lst1->next, lst2->next);
  93.    }
  94.  
  95. /*
  96.  * init_macro - initialize this module, setting up standard macros.
  97.  */
  98. novalue init_macro()
  99.    {
  100.    int i;
  101.    struct macro **mpp;
  102.    struct token *t;
  103.    char *s;
  104.    char time_str[26];
  105.    static char *time_buf;
  106.    static char *date_buf;
  107.    static short first_time = 1;
  108.  
  109.    if (first_time) {
  110.       first_time = 0;
  111.       /*
  112.        * Add names of standard macros to sting table.
  113.        */
  114.       line_mac = spec_str(line_mac);
  115.       file_mac = spec_str(file_mac);
  116.       date_mac = spec_str(date_mac);
  117.       time_mac = spec_str(time_mac);
  118.       rcrs_mac = spec_str(rcrs_mac);
  119.       defined = spec_str(defined);
  120.       }
  121.    else {
  122.       /*
  123.        * Free macro definitions from the file processed.
  124.        */
  125.       for (i = 0; i < MacTblSz; ++i)
  126.          free_m_lst(m_table[i]);
  127.       }
  128.  
  129.    for (i = 0; i < MacTblSz; ++i)
  130.       m_table[i] = NULL;
  131.  
  132.    /*
  133.     * __LINE__ and __FILE__ are macros that require special processing
  134.     *  when they are processed. Indicate that.
  135.     */
  136.    mpp = m_find(line_mac);
  137.    *mpp = new_macro(line_mac, SpecMac, 0, NULL, NULL);
  138.  
  139.    mpp = m_find(file_mac);
  140.    *mpp = new_macro(file_mac, SpecMac, 0, NULL, NULL);
  141.  
  142.    /*
  143.     * __TIME__ and __DATE__ must be initialized to the current time and
  144.     *  date.
  145.     */
  146.    getctime(time_str);
  147.    date_buf = (char *)alloc((unsigned int)12);
  148.    time_buf = (char *)alloc((unsigned int)9);
  149.    s = date_buf;
  150.    for (i = 4; i <= 10; ++i)
  151.       *s++ = time_str[i];
  152.    for (i = 20; i <= 23; ++i)
  153.       *s++ = time_str[i];
  154.    *s = '\0';
  155.    s = time_buf;
  156.    for (i = 11; i <= 18; ++i)
  157.       *s++ = time_str[i];
  158.    *s = '\0';
  159.    date_buf = spec_str(date_buf);
  160.    time_buf = spec_str(time_buf);
  161.  
  162.    t = new_token(StrLit, date_buf, "", 0);
  163.    mpp = m_find(date_mac);
  164.    *mpp = new_macro(date_mac, FixedMac, 0, NULL, new_t_lst(t));
  165.  
  166.    t = new_token(StrLit, time_buf, "", 0);
  167.    mpp = m_find(time_mac);
  168.    *mpp = new_macro(time_mac, FixedMac, 0, NULL, new_t_lst(t));
  169.  
  170.    /*
  171.     * __RCRS__ is a special macro to indicate the allowance of
  172.     *  recursive macros. It is not ANSI-standard. Initialize it
  173.     *  to "1".
  174.     */
  175.    mpp = m_find(rcrs_mac);
  176.    *mpp = new_macro(rcrs_mac, NoArgs, 0, NULL, new_t_lst(copy_t(one_tok)));
  177.    max_recurse = 1;
  178.    }
  179.  
  180. /*
  181.  * m_install - install a macro.
  182.  */
  183. novalue m_install(mname, category, multi_line, prmlst, body)
  184. struct token *mname;    /* name of macro */
  185. int multi_line;        /* flag indicating if this is a multi-line macro */
  186. int category;        /* # parms, or NoArgs if it is object-like macro */
  187. struct id_lst *prmlst;    /* parameter list */
  188. struct tok_lst *body;    /* replacement list */
  189.    {
  190.    struct macro **mpp;
  191.    char *s;
  192.  
  193.    if (mname->image == defined)
  194.       errt1(mname, "'defined' may not be the subject of #define");
  195.  
  196.    /*
  197.     * The special macro __RCRS__ may only be defined as a single integer
  198.     *  token and must be an object-like macro.
  199.     */
  200.    if (mname->image == rcrs_mac) {
  201.       if (body == NULL || body->t->tok_id != PpNumber || body->next != NULL)
  202.          errt1(mname, "__RCRS__ must be a decimal integer");
  203.       if (category != NoArgs)
  204.          errt1(mname, "__RSCS__ may have no arguments");
  205.       max_recurse = 0;
  206.       for (s = body->t->image; *s != '\0'; ++s) {
  207.          if (*s >= '0' && *s <= '9')
  208.             max_recurse = max_recurse * 10 + (*s - '0');
  209.          else
  210.             errt1(mname, "__RCRS__ must be a decimal integer");
  211.          }
  212.       }
  213.  
  214.    mpp = m_find(mname->image);
  215.    if (*mpp == NULL)
  216.       *mpp = new_macro(mname->image, category, multi_line, prmlst, body);
  217.     else {
  218.       /*
  219.        * The macro is already defined. Make sure it is identical (up to
  220.        *  white space) to this definition.
  221.        */
  222.       if (!((*mpp)->category == category && eq_id_lst((*mpp)->prmlst, prmlst) &&
  223.            eq_tok_lst((*mpp)->body, body)))
  224.          errt2(mname, "invalid redefinition of macro ", mname->image);
  225.       free_id_lst(prmlst);
  226.       free_t_lst(body);
  227.       }
  228.    }
  229.  
  230. /*
  231.  * m_delete - delete a macro.
  232.  */
  233. novalue m_delete(mname)
  234. struct token *mname;
  235.    {
  236.    struct macro **mpp, *mp;
  237.  
  238.    if (mname->image == defined)
  239.       errt1(mname, "'defined' may not be the subject of #undef");
  240.  
  241.    /*
  242.     * Undefining __RCRS__ allows unlimited macro recursion (non-ANSI
  243.     *  standard feature.
  244.     */
  245.    if (mname->image == rcrs_mac)
  246.       max_recurse = -1;
  247.  
  248.    /*
  249.     * Make sure undefining this macro is allowed, and free storage
  250.     *  associate with it.
  251.     */
  252.    mpp = m_find(mname->image);
  253.    if (*mpp != NULL) {
  254.       mp = *mpp;
  255.       if (mp->category == FixedMac || mp->category == SpecMac)
  256.          errt2(mname, mname->image, " may not be the subject of #undef");
  257.       *mpp = mp->next;
  258.       free_m(mp);
  259.       }
  260.    }
  261.  
  262. /*
  263.  * m_lookup - lookup a macro name. Return pointer to macro, if it is defined;
  264.  *  return NULL, if it is not. This routine sets the definition for macros
  265.  *  whose definitions various from place to place.
  266.  */
  267. struct macro *m_lookup(id)
  268. struct token *id;
  269.    {
  270.    struct macro *m;
  271.    static char buf[20];
  272.  
  273.    m = *m_find(id->image);
  274.    if (m != NULL && m->category == SpecMac)
  275.       if (m->mname == line_mac) {  /* __LINE___ */
  276.          sprintf(buf, "%d", id->line);
  277.          m->body = new_t_lst(new_token(PpNumber, buf, id->fname,
  278.             id->line));
  279.          }
  280.       else if (m->mname == file_mac) /* __FILE__ */
  281.          m->body = new_t_lst(new_token(StrLit, id->fname, id->fname,
  282.             id->line));
  283.    return m;
  284.    }
  285.  
  286. /*
  287.  * parm_indx - see if a name is a paramter to the given macro.
  288.  */
  289. static int parm_indx(id, m)
  290. char *id;
  291. struct macro *m;
  292.    {
  293.    struct id_lst *idlst;
  294.    int i;
  295.  
  296.    for (i = 0, idlst = m->prmlst; i < m->category; i++, idlst = idlst->next)
  297.       if (id == idlst->id)
  298.          return i;
  299.    return -1;
  300.    }
  301.  
  302. /*
  303.  * cpy_str - copy a string into a string buffer, adding delimiters.
  304.  */
  305. static novalue cpy_str(ldelim, image, rdelim, sbuf)
  306. char *ldelim;
  307. char *image;
  308. char *rdelim;
  309. struct str_buf *sbuf;
  310.    {
  311.    register char *s;
  312.  
  313.    for (s = ldelim; *s != '\0'; ++s) 
  314.       AppChar(*sbuf, *s);
  315.  
  316.    for (s = image; *s != '\0'; ++s) {
  317.       if (*s == '\\' || *s == '"')
  318.          AppChar(*sbuf, '\\');
  319.       AppChar(*sbuf, *s);
  320.       }
  321.  
  322.    for (s = rdelim; *s != '\0'; ++s) 
  323.       AppChar(*sbuf, *s);
  324.    }
  325.  
  326. /*
  327.  * stringize - create a stringized version of a token.
  328.  */
  329. static struct token *stringize(trigger, me)
  330. struct token *trigger;
  331. struct mac_expand *me;
  332.    {
  333.    register struct token *t;
  334.    struct tok_lst *arg;
  335.    struct str_buf *sbuf;
  336.    char *s;
  337.    int indx;
  338.    
  339.    /*
  340.     * Get the next token from the macro body. It must be a macro parameter;
  341.     *  retrieve the raw tokens for the corresponding argument.
  342.     */
  343.    if (me->rest_bdy == NULL)
  344.       errt1(trigger, "the # operator must have an argument"); 
  345.    t = me->rest_bdy->t;
  346.    me->rest_bdy = me->rest_bdy->next;
  347.    if (t->tok_id == Identifier)
  348.       indx = parm_indx(t->image, me->m);
  349.    else
  350.       indx = -1;
  351.    if (indx == -1)
  352.       errt1(t, "the # operator may only be applied to a macro argument"); 
  353.    arg = me->args[indx];
  354.  
  355.    /*
  356.     * Copy the images for the argument tokens into a string buffer. Note
  357.     *  that the images of string and character literals lack quotes; these
  358.     *  must be escaped in the stringized value.
  359.     */
  360.    sbuf = get_sbuf();
  361.    while (arg != NULL) {
  362.       t = arg->t;
  363.       if (t->tok_id == WhiteSpace)
  364.          AppChar(*sbuf, ' ');
  365.       else if (t->tok_id == StrLit)
  366.          cpy_str("\\\"", t->image, "\\\"", sbuf);
  367.       else if (t->tok_id == LStrLit)
  368.          cpy_str("L\\\"", t->image, "\\\"", sbuf);
  369.       else if (t->tok_id == CharConst)
  370.          cpy_str("'", t->image, "'", sbuf);
  371.       else if (t->tok_id == LCharConst)
  372.          cpy_str("L'", t->image, "'", sbuf);
  373.       else
  374.          for (s = t->image; *s != '\0'; ++s)
  375.             AppChar(*sbuf, *s);
  376.       arg = arg->next;
  377.       }
  378.  
  379.    /*
  380.     * Created the token for the stringized argument.
  381.     */
  382.    t = new_token(StrLit, str_install(sbuf), trigger->fname, trigger->line);
  383.    t->flag |= trigger->flag & LineChk;
  384.    rel_sbuf(sbuf);
  385.    return t;
  386.    }
  387.  
  388. /*
  389.  * paste_parse - parse an expression involving token pasting operators (and
  390.  *  stringizing operators). Return a list of token lists. Each token list
  391.  *  is from a token pasting operand, with operands that are macro parameters
  392.  *  replaced by their corresponding argument (this is why a list of tokens
  393.  *  is needed for each operand). Any needed stringizing is done as the list
  394.  *  is created.
  395.  */
  396. static struct paste_lsts *paste_parse(t, me)
  397. struct token *t;
  398. struct mac_expand *me;
  399.    {
  400.    struct token *t1;
  401.    struct token *trigger = NULL;
  402.    struct tok_lst *lst;
  403.    struct paste_lsts *plst;
  404.    int indx;
  405.  
  406.    if (me->rest_bdy == NULL || me->rest_bdy->t->tok_id != PpPaste)
  407.       plst = NULL;  /* we have reached the end of the pasting expression */
  408.    else {
  409.       /*
  410.        * The next token is a pasting operator. Copy it an move on to the
  411.        *  operand.
  412.        */
  413.       trigger = copy_t(me->rest_bdy->t);
  414.       me->rest_bdy = me->rest_bdy->next;
  415.       if (me->rest_bdy == NULL)
  416.          errt1(t, "the ## operator must not appear at the end of a macro");
  417.       t1 = me->rest_bdy->t;
  418.       me->rest_bdy = me->rest_bdy->next;
  419.  
  420.       /*
  421.        * See if the operand is a stringizing operation.
  422.        */
  423.       if (t1->tok_id == '#')
  424.          t1 = stringize(t1, me);
  425.       else
  426.          t1 = copy_t(t1);
  427.       plst = paste_parse(t1, me); /* get any further token pasting */
  428.       }
  429.  
  430.    /*
  431.     * If the operand is a macro parameter, replace it by the corresponding
  432.     *  argument, otherwise make the operand into a 1-element token list.
  433.     */
  434.    indx = -1;
  435.    if (t->tok_id == Identifier)
  436.       indx = parm_indx(t->image, me->m);
  437.    if (indx == -1)
  438.       lst = new_t_lst(t);
  439.    else {
  440.       lst = me->args[indx];
  441.       free_t(t);
  442.       }
  443.  
  444.    /*
  445.     * Ignore emtpy arguments when constructing the pasting list.
  446.     */
  447.    if (lst == NULL)
  448.       return plst;
  449.    else
  450.       return new_plsts(trigger, lst, plst);
  451.    }
  452.  
  453. /*
  454.  * cpy_image - copy the image of a token into a character buffer adding
  455.  *  delimiters if it is a string or character literal.
  456.  */
  457. static int *cpy_image(t, s)
  458. struct token *t;
  459. int *s;          /* the string buffer can contain EOF */
  460.    {
  461.    register char *s1;
  462.  
  463.    switch (t->tok_id) {
  464.       case StrLit:
  465.          *s++ = '"';
  466.          break;
  467.       case LStrLit:
  468.          *s++ = 'L';
  469.          *s++ = '"';
  470.          break;
  471.       case CharConst:
  472.          *s++ = '\'';
  473.          break;
  474.       case LCharConst:
  475.          *s++ = 'L';
  476.          *s++ = '\'';
  477.          break;
  478.       }
  479.  
  480.    s1 = t->image;
  481.    while (*s1 != '\0')
  482.       *s++ = *s1++;
  483.  
  484.    switch (t->tok_id) {
  485.       case StrLit:
  486.       case LStrLit:
  487.          *s++ = '"';
  488.          break;
  489.       case CharConst:
  490.       case LCharConst:
  491.          *s++ = '\'';
  492.          break;
  493.       }
  494.  
  495.    return s;
  496.    }
  497.  
  498. /*
  499.  * paste - return the next token from a source which pastes tokens. The
  500.  *   source may represent a series of token pasting operators.
  501.  */
  502. struct token *paste()
  503.    {
  504.    struct token *t;
  505.    struct token *t1;
  506.    struct token *trigger;
  507.    struct paste_lsts *plst;
  508.    union src_ref ref;
  509.    int i;
  510.    int *s;
  511.  
  512.    plst = src_stack->u.plsts;
  513.  
  514.    /*
  515.     * If the next token of the current list is not the one to be pasted,
  516.     *  just return it.
  517.     */
  518.    t = copy_t(plst->tlst->t);
  519.    plst->tlst = plst->tlst->next;
  520.    if (plst->tlst != NULL)
  521.       return t;
  522.  
  523.    /*
  524.     * We have the last token from the current list. If there is another
  525.     *  list, this token must be pasted to the first token of that list.
  526.     *  Make the next list the current one and get its first token.
  527.     */
  528.    trigger = plst->trigger;
  529.    plst = plst->next;
  530.    free_plsts(src_stack->u.plsts);
  531.    src_stack->u.plsts = plst;
  532.    if (plst == NULL) {
  533.       pop_src();
  534.       return t;
  535.       }
  536.    t1 = next_tok();
  537.  
  538.    /*
  539.     * Paste tokens by creating a character source with the images of the
  540.     *  two tokens concatenated.
  541.     */
  542.    ref.cs = new_cs(trigger->fname, NULL,
  543.       (int)strlen(t->image) + (int)strlen(t1->image) + 7);
  544.    push_src(CharSrc, &ref);
  545.    s = cpy_image(t, ref.cs->char_buf);
  546.    s = cpy_image(t1, s); 
  547.    *s = EOF;
  548.  
  549.    /*
  550.     * Treat all characters of the new source as if they come from the
  551.     *  location of the token pasting.
  552.     */
  553.    for (i = 0; i < (s - ref.cs->char_buf + 1); ++i)
  554.       *(ref.cs->line_buf) = trigger->line;
  555.    ref.cs->last_char = s;
  556.    ref.cs->dir_state = Reset;
  557.    first_char = ref.cs->char_buf;
  558.    next_char = first_char;
  559.    last_char = ref.cs->last_char;
  560.  
  561.    return next_tok(); /* first token from pasted images */
  562.    }
  563.  
  564. /*
  565.  * mac_tok - return the next token from a source which is a macro.
  566.  */
  567. struct token *mac_tok()
  568.    {
  569.    struct mac_expand *me;
  570.    register struct token *t, *t1;
  571.    struct paste_lsts *plst;
  572.    union src_ref ref;
  573.    int line_check;
  574.    int indx;
  575.    int line;
  576.    char *fname;
  577.  
  578.    me = src_stack->u.me; /* macro, current position, and arguments */
  579.  
  580.    /*
  581.     * Get the next token from the macro body.
  582.     */
  583.    if (me->rest_bdy == NULL)
  584.       return NULL;
  585.    t = me->rest_bdy->t;
  586.    me->rest_bdy = me->rest_bdy->next;
  587.  
  588.    /*
  589.     * If this token is a stringizing operator, try stringizing the next
  590.     *  token.
  591.     */
  592.    if (t->tok_id == '#')
  593.       t = stringize(t, me);
  594.    else
  595.       t = copy_t(t);
  596.  
  597.    if (me->rest_bdy != NULL && me->rest_bdy->t->tok_id == PpPaste) {
  598.       /*
  599.        * We have found token pasting. If there is a series of such operators,
  600.        *  make them all into one token pasting source and push it on
  601.        *  the source stack.
  602.        */
  603.       if (t->flag & LineChk) {
  604.          line_check = 1;
  605.          line = t->line;
  606.          fname = t->fname;
  607.          }
  608.       else
  609.          line_check = 0;
  610.       plst = paste_parse(t, me);
  611.       if (plst != NULL) {
  612.          ref.plsts = plst;
  613.          push_src(PasteLsts, &ref);
  614.          }
  615.       t1 = next_tok();
  616.       if (line_check && !(t1->flag & LineChk)) {
  617.          t1->flag |= LineChk;
  618.          t1->line = line;
  619.          t1->fname = fname;
  620.          }
  621.       return t1;
  622.       }
  623.    else if (t->tok_id == Identifier &&
  624.      (indx = parm_indx(t->image, me->m)) != -1) {
  625.       /*
  626.        * We have found a parameter. Push a token source for the corresponding
  627.        *  argument, that is, replace the parameter with its definition.
  628.        */
  629.       ref.tlst = me->exp_args[indx];
  630.       push_src(TokLst, &ref);
  631.       if (t->flag & LineChk) {
  632.          line = t->line;
  633.          fname = t->fname;
  634.          t1 = next_tok();
  635.          if (!(t1->flag & LineChk)) {
  636.             /*
  637.              * The parameter name token is significant with respect to
  638.              *  outputting #line directives but the first argument token
  639.              *  is not. Pretend the argument has the same line number as the
  640.              *  parameter name.
  641.              */
  642.             t1->flag |= LineChk;
  643.             t1->line = line;
  644.             t1->fname = fname;
  645.             }
  646.          free_t(t);
  647.          return t1;
  648.          }
  649.       else {
  650.          free_t(t);
  651.          return next_tok();
  652.          }
  653.       }
  654.    else {
  655.       /*
  656.        * This is an ordinary token, nothing further is needed here.
  657.        */
  658.       return t;
  659.       }
  660.    }
  661.