Logo Search packages:      
Sourcecode: ksh version File versions

ppcall.c

/***********************************************************************
*                                                                      *
*               This software is part of the ast package               *
*           Copyright (c) 1986-2007 AT&T Knowledge Ventures            *
*                      and is licensed under the                       *
*                  Common Public License, Version 1.0                  *
*                      by AT&T Knowledge Ventures                      *
*                                                                      *
*                A copy of the License is available at                 *
*            http://www.opensource.org/licenses/cpl1.0.txt             *
*         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
*                                                                      *
*              Information and Software Systems Research               *
*                            AT&T Research                             *
*                           Florham Park NJ                            *
*                                                                      *
*                 Glenn Fowler <gsf@research.att.com>                  *
*                                                                      *
***********************************************************************/
#pragma prototyped
/*
 * Glenn Fowler
 * AT&T Research
 *
 * preprocessor macro call
 */

#include "pplib.h"

#include <ctype.h>

/*
 * call a macro by pushing its value on the input stream
 * only the macro token itself has been consumed
 * -1 returned if macro disabled
 *  0 returned if tok==0 and sym->mac->value to be copied to output by caller
 *  1 returned if value pushed on input
 */

int
ppcall(register struct ppsymbol* sym, int tok)
{
      register int                  c;
      register char*                p;
      register char*                q;
      register struct ppmacro*      mac;
      int                     n;
      int                     m;
      int                     ret;
      int                     old_hidden;
      int                     last_line;
      long                    old_state;
      char*                   last_file;
      char*                   old_token;
      struct ppmacstk*        mp;
      struct ppinstk*               old_in;
      struct ppinstk*               kp;
      struct pptuple*               tp;

      ret = -1;
      sym->flags |= SYM_NOTICED;
      if (mac = sym->macro)
      {
            count(macro);
            if ((sym->flags & SYM_PREDICATE) && (pp.state & (CONDITIONAL|WARN)) == (CONDITIONAL|WARN))
                  error(1, "%s: macro definition overrides assertion: use #%s ...", sym->name, sym->name);
            if (sym->flags & SYM_DISABLED)
#if COMPATIBLE
                  if ((pp.state & (COMPATIBILITY|TRANSITION)) != COMPATIBILITY || !mac->arity)
#endif
            {
                  pp.mode |= MARKMACRO;
#if COMPATIBLE
                  if ((pp.state & (COMPATIBILITY|STRICT)) == (COMPATIBILITY|STRICT))
                        error(1, "%s: macro recursion inhibited", sym->name);
#endif
                  goto disable;
            }
            if ((sym->flags & SYM_PREDEFINED) && !(pp.mode & (HOSTED|INACTIVE)))
            {
#if COMPATIBLE
                  if (*sym->name != '_' && !(pp.state & COMPATIBILITY))
#else
                  if (*sym->name != '_')
#endif
                  {
                        if (pp.state & STRICT)
                        {
                              error(1, "%s: obsolete predefined symbol expansion disabled", sym->name);
                              goto disable;
                        }
                        error(1, "%s: obsolete predefined symbol expanded%s", sym->name, (pp.state & DIRECTIVE) ? "" : " outside of directive");
                  }
                  else if (!(pp.state & DIRECTIVE) && mac->value && (ppisdig(*mac->value) || *mac->value == '#'))
                        error(1, "%s: predefined symbol expanded outside of directive", sym->name);
            }
            debug((-5, "macro %s = %s", sym->name, mac->value));
            if (pp.macref)
                  (*pp.macref)(sym, error_info.file, error_info.line, (pp.state & CONDITIONAL) ? REF_IF : REF_NORMAL, 0L);
            if (tp = mac->tuple)
            {
                  old_state = pp.state;
                  pp.state |= DEFINITION|NOSPACE;
                  old_token = pp.token;
                  n = 2 * MAXTOKEN;
                  pp.token = p = oldof(0, char, 0, n);
                  q = p + MAXTOKEN;
                  *pp.token++ = ' ';
                  old_hidden = pp.hidden;
                  while (c = pplex())
                  {
                        if (c == '\n')
                        {
                              pp.hidden++;
                              pp.state |= HIDDEN|NEWLINE;
                              old_state |= HIDDEN|NEWLINE;
                              error_info.line++;
                        }
                        else if (c == '#')
                        {
                              ungetchr(c);
                              break;
                        }
                        else
                        {
                              for (;;)
                              {
                                    if (streq(pp.token, tp->token))
                                    {
                                          if (!(tp = tp->match))
                                                break;
                                          if (!tp->nomatch)
                                          {
                                                free(p);
                                                pp.state = old_state;
                                                pp.token = old_token;
                                                PUSH_TUPLE(sym, tp->token);
                                                ret = 1;
                                                goto disable;
                                          }
                                    }
                                    else if (!(tp = tp->nomatch))
                                          break;
                              }
                              if (!tp)
                              {
                                    pp.token = pp.toknxt;
                                    break;
                              }
                        }
                        if ((pp.token = pp.toknxt) > q)
                        {
                              c = pp.token - p;
                              p = newof(p, char, n += MAXTOKEN, 0);
                              q = p + n - MAXTOKEN;
                              pp.token = p + c;
                        }
                        *pp.token++ = ' ';
                  }
                  if (pp.token > p && *(pp.token - 1) == ' ')
                        pp.token--;
                  if (pp.hidden != old_hidden)
                        *pp.token++ = '\n';
                  else
                        *pp.token++ = ' ';
                  *pp.token = 0;
                  pp.state = old_state;
                  pp.token = old_token;
                  if (*p)
                        PUSH_RESCAN(p);
                  else
                        free(p);
                  if (!mac->value)
                        goto disable;
            }
            if (sym->flags & SYM_FUNCTION)
            {
                  /*
                   * a quick and dirty '(' peek to avoid possibly
                   * inappropriate ungetchr()'s below
                   */

                  for (p = pp.in->nextchr; isspace(*p); p++);
                  if ((c = *p) != '(' && c != '/' && c != 0 && c != MARK)
                        goto disable;
                  old_token = pp.token;
                  mp = pp.macp->next;
                  if ((pp.token = (char*)&mp->arg[mac->arity + 1]) > pp.maxmac)
                        error(3, "%s: too many nested function-like macros", sym->name);
                  old_hidden = pp.hidden;
                  old_state = pp.state;
                  pp.state |= DEFINITION|FILEPOP|NOSPACE;
                  while ((c = pplex()) == '\n')
                  {
                        pp.hidden++;
                        pp.state |= HIDDEN|NEWLINE;
                        old_state |= HIDDEN|NEWLINE;
                        error_info.line++;
                  }
                  if (c != '(')
                  {
                        pp.state = old_state;
                        if (c)
                        {
                              p = pp.toknxt;
                              while (p > pp.token)
                                    ungetchr(*--p);
#if COMPATIBLE
                              if ((pp.state & (COMPATIBILITY|STRICT)) == (COMPATIBILITY|STRICT))
                                    error(1, "%s: macro arguments omitted", sym->name);
#endif
                              if (c == T_ID && !(pp.state & HIDDEN))
                                    ungetchr(' ');
                        }
                        if (pp.hidden != old_hidden)
                        {
                              ungetchr('\n');
                              error_info.line--;
                              if (pp.hidden && !--pp.hidden)
                                    pp.state &= ~HIDDEN;
                        }
                        pp.token = old_token;
                        goto disable;
                  }
                  pp.state = old_state;

                  /*
                   * arg[i][-1] is an extra char for each actual i
                   * for a possible ungetchr('"') during IN_QUOTE
                   * arg[i][-1]==0 if arg i need not be expanded
                   * arg[0][-2] holds the actual arg count
                   */

                  c = 0;
                  m = 0;
                  n = 0;
                  mp = pp.macp->next;
                  p = pp.token = (char*)&mp->arg[mac->arity + 1];
                  pp.state |= COLLECTING|NOEXPAND;
                  pp.state &= ~FILEPOP;
                  sym->flags |= SYM_ACTIVE;
                  old_in = pp.in;
                  last_line = error_info.line;
                  last_file = error_info.file;
                  mp->line = error_info.line;
#if MACKEYARGS
                  if (pp.option & KEYARGS)
                  {
                        for (c = 0; c < mac->arity; c++)
                              mp->arg[c] = mac->args.key[c].value + 1;
                        mp->arg[0]++;
                  }
                  else
#endif
                  {
                        *++p = ' ';
                        mp->arg[0] = ++p;
                  }
#if MACKEYARGS
            keyarg:
                  if (pp.option & KEYARGS)
                  {
                        pp.state |= NOSPACE;
                        switch (pplex())
                        {
                        case T_ID:
                              break;
                        case ')':   /* no actual key args */
                              if (!(pp.state & NOEXPAND))
                                    pp.state |= NOEXPAND;
                              for (c = 0; c < mac->arity; c++)
                                    mp->arg[c][-1] = 0;
                              c = 0;
                              goto endactuals;
                        default:
                              error(3, "%s: invalid keyword macro argument", pp.token);
                              break;
                        }
                        for (c = 0; c < mac->arity; c++)
                              if (streq(pp.token, mac->args.key[c].name)) break;
                        if (c >= mac->arity)
                              error(2, "%s: invalid macro argument keyword", pp.token);
                        if (pplex() != '=')
                              error(2, "= expected in keyword macro argument");
                        pp.state &= ~NOSPACE;
                        if (!c)
                              p++;
                        pp.token = mp->arg[c] = ++p;
                  }
#endif
                  for (;;)
                  {
                        if ((pp.mactop = pp.token = p) >= pp.maxmac)
                              error(3, "%s: too many nested function-like macros", sym->name);
                        switch (pplex())
                        {
                        case '(':
                              n++;
                              break;
                        case ')':
                              if (!n--)
                              {
                                    if (p > mp->arg[c] && *(p - 1) == ' ')
                                          p--;
                                    if (p > mp->arg[c] && *(p - 1) == '\\')
                                    {
                                          for (q = mp->arg[c]; q < p; q++)
                                                if (*q == '\\')
                                                      q++;
                                          if (q > p)
                                                *p++ = '\\';
                                    }
#if MACKEYARGS
                                    *p = 0;
                                    m++;
#endif
                                    goto endactuals;
                              }
                              break;
                        case ',':
                              if (!n && (m++, (c < mac->arity - 1 || !(sym->flags & SYM_VARIADIC))))
                              {
                                    if (p > mp->arg[c] && *(p - 1) == ' ')
                                          p--;
                                    *p++ = 0;
                                    if (!(pp.state & NOEXPAND))
                                          pp.state |= NOEXPAND;
                                    else
                                          mp->arg[c][-1] = 0;
#if MACKEYARGS
                                    if (pp.option & KEYARGS)
                                    {
                                          pp.token = p + 1;
                                          goto keyarg;
                                    }
#endif
                                    {
                                          if ((pp.state & STRICT) && p == mp->arg[c])
                                                error(1, "%s: macro call argument %d is null", sym->name, c + 1);
                                          if (c < mac->arity)
                                                c++;
                                          *p++ = ' ';
                                    }
                                    pp.toknxt = mp->arg[c] = p;
                              }
                              break;
                        case 0:
                              if (pp.in == old_in)
                                    kp = 0;
                              else
                                    for (kp = pp.in; kp && kp != old_in; kp = kp->prev);
                              if (!kp)
                              {
                                    error(
#if COMPATIBLE
                                          (pp.state & COMPATIBILITY) ? 3 :
#endif
                                          2, "%s: %s in macro argument list", sym->name, pptokchr(0));
                                    goto endactuals;
                              }
                              continue;
                        case '\n':
                              pp.state |= HIDDEN;
                              error_info.line++;
                              pp.hidden++;
                              /*FALLTHROUGH*/
                        case ' ':
                              if (p > mp->arg[c] && *(p - 1) != ' ') *p++ = ' ';
                              continue;
                        }
                        p = pp.toknxt;
                        if (error_info.line != last_line)
                        {
                              SETLINE(p, error_info.line);
                              last_line = error_info.line;
                        }
                        if (error_info.file != last_file)
                        {
                              SETFILE(p, error_info.file);
                              last_file = error_info.file;
                        }
                  }
 endactuals:
                  if (pp.state & NOEXPAND)
                        mp->arg[c][-1] = 0;
                  pp.token = old_token;
                  if (pp.in != old_in)
                  {
                        for (kp = pp.in; kp && kp != old_in; kp = kp->prev);
                        if (kp)
                              error(2, "%s: macro call starts and ends in different files", sym->name);
                  }
                  pp.state &= ~(COLLECTING|FILEPOP|NOEXPAND);
                  sym->flags &= ~SYM_ACTIVE;
#if MACKEYARGS
                  if (!(pp.option & KEYARGS))
#endif
                  {
                        if (p > mp->arg[0] && ++m || (sym->flags & SYM_VARIADIC))
                              c++;
                        if (c != mac->arity && !(sym->flags & SYM_EMPTY))
                        {
                              n = mac->arity;
                              if (!(sym->flags & SYM_VARIADIC))
                                    error(1, "%s: %d actual argument%s expected", sym->name, n, n == 1 ? "" : "s");
                              else if (c < --n)
                                    error(1, "%s: at least %d actual argument%s expected", sym->name, n, n == 1 ? "" : "s");
#if COMPATIBLE
                              if (!c && (pp.state & (COMPATIBILITY|STRICT)) == (COMPATIBILITY|STRICT))
                                    goto disable;
#endif
                        }
                        if (!c)
                              ++c;
                        while (c < mac->arity)
                              mp->arg[c++] = (char*)"\0" + 1;
                  }
                  mp->arg[0][-2] = m;
                  *p++ = 0;
                  nextframe(mp, p);
                  count(function);
            }
            if (!tok && (sym->flags & SYM_NOEXPAND))
            {
                  if (sym->flags & SYM_FUNCTION)
                        popframe(mp);
                  ret = !mac->size;
            }
            else if (!(pp.state & HEADER) || (pp.option & HEADEREXPANDALL)  || pp.in->type != IN_COPY)
            {
                  if (sym->flags & SYM_MULTILINE)
                        PUSH_MULTILINE(sym);
                  else
                        PUSH_MACRO(sym);
                  ret = 1;
            }
      }
 disable:
      if (ret < 0 && sym->hidden && !(pp.mode & EXPOSE) && !(pp.state & HEADER) && (pp.in->type == IN_FILE || pp.in->type == IN_MACRO || pp.in->type == IN_EXPAND))
      {
            struct ppinstk*   inp;

            for (inp = pp.in; inp->type != IN_FILE && inp->prev; inp = inp->prev);
            sfsprintf(pp.hidebuf, MAXTOKEN, "_%d_%s_hIDe", inp->index, sym->name);
            PUSH_STRING(pp.hidebuf);
            ret = 1;
      }
      pp.state &= ~NEWLINE;
      pp.in->flags |= IN_tokens;
      count(token);
      return ret;
}

Generated by  Doxygen 1.6.0   Back to index