Logo Search packages:      
Sourcecode: ksh version File versions  Download package

pplex.c

/***********************************************************************
*                                                                      *
*               This software is part of the ast package               *
*          Copyright (c) 1986-2007 AT&T Intellectual Property          *
*                      and is licensed under the                       *
*                  Common Public License, Version 1.0                  *
*                    by AT&T Intellectual Property                     *
*                                                                      *
*                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 lexical analyzer
 * standalone and tokenizing lexer combined in one source
 * define CPP=1 for standalone
 */

#include "pplib.h"
#include "ppfsm.h"

#if CPP

/*
 * standalone entry point
 */

#define PPCPP_T         void

#define START           QUICK
#define INMACRO(x)      INQMACRO(x)
#define DOSTRIP() (st&STRIP)

#if DEBUG & TRACE_debug
static int        hit[LAST-TERMINAL+2];
#endif

#define BACKIN()  (ip--)
#define BACKOUT() (op=tp)
#define CACHE()         do{CACHEINX();CACHEOUTX();st=pp.state;if(!pp.hidden)spliced=0;}while(0)
#define CACHEIN() do{CACHEINX();st=pp.state;if(!pp.hidden)spliced=0;}while(0)
#define CACHEINX()      do{ip=pp.in->nextchr;}while(0)
#define CACHEOUT()      do{CACHEOUTX();st=pp.state;if(!pp.hidden)spliced=0;}while(0)
#define CACHEOUTX()     do{tp=op=pp.outp;xp=pp.oute;if(sp)sp=op;}while(0)
#define GETCHR()  (*(unsigned char*)ip++)
#define LASTCHR() (*(ip-1))
#define LASTOUT() ((op>pp.outbuf)?*(op-1):pp.lastout)
#define SKIPIN()  (ip++)
#define PUTCHR(c) (*op++=(c))
#define SETCHR(c) (*op=(c))
#define SYNC()          do{SYNCINX();SYNCOUTX();pp.state=st;}while(0)
#define SYNCIN()  do{SYNCINX();pp.state=st;}while(0)
#define SYNCINX() do{pp.in->nextchr=ip;}while(0)
#define SYNCOUT() do{SYNCOUTX();pp.state=st;}while(0)
#define SYNCOUTX()      do{if(sp)op=tp=sp;pp.outp=op;}while(0)
#define UNGETCHR(c)     (*--ip=(c))

#define PPCHECKOUT()    do{if(op>xp){{PPWRITE(PPBUFSIZ);if(pp.outbuf==pp.outb){pp.outbuf+=PPBUFSIZ;xp=pp.oute+=PPBUFSIZ;}else{pp.outbuf-=PPBUFSIZ;memcpy(pp.outbuf,xp,op-xp);xp=pp.oute-=PPBUFSIZ;op-=2*PPBUFSIZ;}}}}while(0)
#define PPCHECKOUTSP()  do{if(op>xp){if(sp)op=sp;else{PPWRITE(PPBUFSIZ);if(pp.outbuf==pp.outb){pp.outbuf+=PPBUFSIZ;xp=pp.oute+=PPBUFSIZ;}else{pp.outbuf-=PPBUFSIZ;memcpy(pp.outbuf,xp,op-xp);xp=pp.oute-=PPBUFSIZ;op-=2*PPBUFSIZ;}}}}while(0)
#define PPCHECKOUTTP()  do{if(op>xp){{PPWRITE(PPBUFSIZ);if(pp.outbuf==pp.outb){pp.outbuf+=PPBUFSIZ;xp=pp.oute+=PPBUFSIZ;}else{pp.outbuf-=PPBUFSIZ;memcpy(pp.outbuf,xp,op-xp);xp=pp.oute-=PPBUFSIZ;op-=2*PPBUFSIZ;}}tp=op;}}while(0)

#define PPSYNCLINE()    do { \
            if ((st & (ADD|HIDDEN)) && !(*pp.control & SKIP)) \
            { \
                if (spliced) \
                { \
                  error_info.line += spliced; \
                  spliced = 0; \
                } \
                else \
                { \
                  if (st & ADD) \
                  { \
                        st &= ~ADD; \
                        m = pp.addp - pp.addbuf; \
                        pp.addp = pp.addbuf; \
                        memcpy(op, pp.addbuf, m); \
                        op += m; \
                        PPCHECKOUT(); \
                  } \
                  if (pp.linesync) \
                  { \
                        if ((st & SYNCLINE) || pp.hidden >= MAXHIDDEN) \
                        { \
                              pp.hidden = 0; \
                              st &= ~(HIDDEN|SYNCLINE); \
                              if (error_info.line) \
                              { \
                                    if (LASTOUT() != '\n') \
                                          PUTCHR('\n'); \
                                    SYNCOUT(); \
                                    (*pp.linesync)(error_info.line, error_info.file); \
                                    CACHEOUT(); \
                              } \
                        } \
                        else \
                        { \
                              m = pp.hidden; \
                              pp.hidden = 0; \
                              st &= ~HIDDEN; \
                              while (m-- > 0) \
                                    PUTCHR('\n'); \
                        } \
                  } \
                  else \
                  { \
                        pp.hidden = 0; \
                        st &= ~HIDDEN; \
                        PUTCHR('\n'); \
                  } \
                } \
            } \
      } while (0)

#if POOL

/*
 * <wait.h> is poison here so pool moved to the end
 */

static void poolstatus(void);
static void pool(void);

#endif

#else

/*
 * return next pp token
 *
 * NOTE: pp.token points to at least MAXTOKEN*2 chars and is
 *       truncated back to MAXTOKEN on EOB
 */

#define PPCPP_T         int
#define ppcpp           pplex

#define START           TOKEN
#define INMACRO(x)      INTMACRO(x)
#define DOSTRIP() ((st&STRIP)||pp.level==1&&(st&(COMPILE|JOINING))==COMPILE&&!(pp.option&PRESERVE))

#define st        pp.state
#define tp        pp.token
#define xp        &pp.token[MAXTOKEN]

#define BACKIN()  (ip--)
#define BACKOUT() (op=pp.token)
#define CACHE()         do{CACHEIN();CACHEOUT();}while(0)
#define CACHEIN() (ip=pp.in->nextchr)
#define CACHEOUT()      (op=pp.token)
#define GETCHR()  (*(unsigned char*)ip++)
#define LASTCHR() (*(ip-1))
#define PUTCHR(c) (*op++=(c))
#define SETCHR(c) (*op=(c))
#define SKIPIN()  (ip++)
#define SYNC()          do{SYNCIN();SYNCOUT();}while(0)
#define SYNCIN()  (pp.in->nextchr=ip)
#define SYNCOUT() (pp.toknxt=op)
#define UNGETCHR(c)     (*--ip=(c))

#endif

PPCPP_T
ppcpp(void)
{
      register short*         rp;
      register char*          ip;
      register int            state;
      register int            c;
      register char*          op;
      char*             bp;
      int               n;
      int               m;
      int               quot;
      int               quotquot;
      int               comdelim = 0;
      int               comstart = 0;
      int               comwarn = 0;
      char*             s;
      struct ppsymbol*  sym;
#if CPP
      register long           st;
      char*             tp;
      char*             xp;
      char*             sp = 0;
      int               qual = 0;
      int               spliced = 0;
#else
      int               qual;
#endif

#if CPP
#if POOL
 fsm_pool:
#endif
#else
      count(pplex);
#endif
      error_info.indent++;
      pp.level++;
      CACHE();
#if !CPP
 fsm_top:
      qual = 0;
#endif
 fsm_start:
#if CPP
      PPCHECKOUTSP();
      tp = op;
#endif
      state = START;
 fsm_begin:
      bp = ip;
      do
      {
            rp = fsm[state];
 fsm_get:
            while (!(state = rp[c = GETCHR()]));
 fsm_next:
            ;
      } while (state > 0);
      if (((state = ~state) != S_COMMENT || pp.comment || c == '/' && !INCOMMENT(rp)) && (n = ip - bp - 1) > 0)
      {
            ip = bp;
#if CPP
            if (op == tp && (st & (ADD|HIDDEN)) && !(st & PASSTHROUGH) && !(pp.option & PRESERVE))
                  switch (TERM(state))
                  {
                  case S_SHARP:
                        break;
                  case S_CHRB:
                  case S_NL:
                        if (*ip == '\n')
                              break;
                        /*FALLTHROUGH*/
                  default:
                        if ((pp.option & PRESERVE) && !(st & NEWLINE) && c != '\n')
                              break;
                        PPSYNCLINE();
                        tp = op;
                        break;
                  }
#endif
            MEMCPY(op, ip, n);
            ip++;
      }
      count(terminal);
#if CPP && (DEBUG & TRACE_debug)
      hit[(state & SPLICE) ? (elementsof(hit) - 1) : (TERM(state) - TERMINAL)]++;
#endif
 fsm_terminal:
      debug((-9, "TERM %s > %s%s%s |%-*.*s|%s|", pplexstr(INDEX(rp)), pplexstr(state), (st & NEWLINE) ? "|NEWLINE" : "", (st & SKIPCONTROL) ? "|SKIP" : "", op - tp, op - tp, tp, pptokchr(c)));
      switch (TERM(state))
      {

#if !CPP
      case S_CHR:
            PUTCHR(c);
            break;
#endif

      case S_CHRB:
            BACKIN();
#if CPP
            st &= ~NEWLINE;
            pp.in->flags |= IN_tokens;
            count(token);
            goto fsm_start;
#else
            c = *tp;
            break;
#endif

      case S_COMMENT:
            switch (c)
            {
            case '\n':
                  if (!INCOMMENTXX(rp))
                  {
                        qual = 0;
                        if (!comstart) comstart = comdelim = error_info.line;
                        error_info.line++;
                        if (pp.comment) PUTCHR(c);
                        else BACKOUT();
#if CPP
                        rp = fsm[COM2];
                        bp = ip;
                        goto fsm_get;
#else
                        state = COM2;
                        goto fsm_begin;
#endif
                  }
                  else if (comwarn < 0 && !(pp.mode & HOSTED))
                        error(1, "/* appears in // comment");
                  break;
            case '*':
                  if (!comwarn && !(pp.mode & HOSTED))
                  {
                        if (INCOMMENTXX(rp)) comwarn = -1;
                        else if (comstart && comstart != error_info.line)
                        {
                              if (qual || comdelim < error_info.line - 1)
                              {
                                    error(1, "/* appears in /* ... */ comment starting at line %d", comstart);
                                    comwarn = 1;
                              }
                              else comdelim = error_info.line;
                        }
                  }
 fsm_comment:
                  PUTCHR(c);
#if CPP
                  rp = fsm[INCOMMENTXX(rp) ? COM5 : COM3];
                  bp = ip;
                  goto fsm_get;
#else
                  state = INCOMMENTXX(rp) ? COM5 : COM3;
                  goto fsm_begin;
#endif
            case '/':
                  if (!INCOMMENT(rp))
                  {
                        if (!(pp.mode & HOSTED))
                              error(1, "*/ appears outside of comment");
                        BACKIN();
#if CPP
                        st &= ~NEWLINE;
                        pp.in->flags |= IN_tokens;
                        count(token);
                        goto fsm_start;
#else
                        c = '*';
                        if (!pp.comment) PUTCHR(c);
                        goto fsm_token;
#endif
                  }
                  else if (INCOMMENTXX(rp))
                  {
                        if (!(pp.mode & HOSTED))
                        {
                              if (comwarn < 0) comwarn = 0;
                              else if (!comwarn)
                              {
                                    comwarn = 1;
                                    error(1, "*/ appears in // comment");
                              }
                        }
                        goto fsm_comment;
                  }
                  break;
            case EOF:
                  BACKIN();
                  if (!(pp.mode & HOSTED))
                  {
                        if (comstart) error(2, "unterminated /* ... */ comment starting at line %d", comstart);
                        else if (INCOMMENTXX(rp)) error(2, "unterminated // ... comment");
                        else error(2, "unterminated /* ... */ comment");
                  }
                  break;
            }
#if CPP
            if (!pp.comment || sp)
            {
#if COMPATIBLE
                  if (!(pp.state & COMPATIBILITY) || *bp == ' ' || *bp == '\t')
#endif
                  {
                        BACKOUT();
                        PUTCHR(' ');
                        tp = op;
                  }
            }
            else if (pp.in->type & IN_TOP)
#else
            if (pp.comment && !(st & (COLLECTING|DIRECTIVE|JOINING)) && !(*pp.control & SKIP) && (pp.in->type & IN_TOP))
#endif
            {
                  st &= ~HIDDEN;
                  pp.hidden = 0;
                  *(op - (c != '\n')) = 0;
                  m = (op - (c != '\n') - tp > MAXTOKEN - 6) ? (error_info.line - MAXHIDDEN) : 0;
                  BACKOUT();
                  SYNC();
                  while (*tp != '/') tp++;
                  (*pp.comment)(c == '\n' ? "//" : "/*", tp + 2, c == '\n' ? "" : (st & HEADER) ? "*/\n" : "*/", comstart ? comstart : error_info.line);
                  CACHE();
                  comstart = m;
            }
            if (comstart)
            {
                  st |= HIDDEN;
                  pp.hidden += error_info.line - comstart;
                  comstart = 0;
            }
            qual = comwarn = comdelim = 0;
            BACKOUT();
            if (c == '\n') goto fsm_newline;
            if ((st & PASSTHROUGH) && ((st & (HIDDEN|NEWLINE)) || *ip == '\n'))
            {
                  if (*ip == '\n')
                        ip++;
                  goto fsm_newline;
            }
#if COMPATIBLE
            if ((st & (COMPATIBILITY|TRANSITION)) == COMPATIBILITY) st &= ~NEWLINE;
#endif
#if !CPP
            if (pp.level > 1 && !(st & (NOSPACE|SKIPCONTROL)))
            {
#if COMPATIBLE
                  c = ((st & (COMPATIBILITY|DEFINITION)) == ((COMPATIBILITY|DEFINITION))) ? '\t' : ' ';
#else
                  c = ' ';
#endif
                  goto fsm_return;
            }
#endif
            goto fsm_start;

      case S_EOB:
            if (c)
            {
                  if (state = fsm[TERMINAL][INDEX(rp)+1])
                        goto fsm_terminal;
#if CPP
#if POOL
                  if (pp.pool.input)
                  {
                        BACKIN();
                        SYNC();
                        pool();
                        CACHE();
                        goto fsm_pool;
                  }
#endif
                  SYNCOUT();
                  return;
#else
                  BACKIN();
                  c = 0;
                  goto fsm_return;
#endif
            }
            {
                  register struct ppinstk*      cur = pp.in;
                  register struct ppinstk*      prv = pp.in->prev;

#if CPP
                  if (sp) op = sp;
#endif
                  switch (cur->type)
                  {
                  case IN_BUFFER:
                  case IN_INIT:
                  case IN_RESCAN:
#if CPP
                        if (prv)
#else
                        if (!(st & PASSEOF) && prv)
#endif
                        {
                              if (cur->type == IN_RESCAN || cur->type == IN_BUFFER)
                              {
 fsm_pop:
#if PROTOTYPE
                                    if (cur->flags & IN_prototype)
                                          pppclose(cur->buffer + PPBAKSIZ);
                                    else
#endif
                                    if (!(cur->flags & IN_static))
                                          free(cur->buffer);
                              }
                              while (pp.control-- != cur->control)
                                    error(2, "#%s on line %d has no #%s", dirname(IF), GETIFLINE(pp.control+1), dirname(ENDIF));
                              st |= NEWLINE;
                              error_info.file = cur->file;
                              error_info.line = cur->line;
                              pp.hidden = 0;
#if CPP
                              spliced = 0;
#endif
                              if (cur->flags & IN_hosted)
                              {
                                    pp.mode |= HOSTED;
                                    pp.flags |= PP_hosted;
                              }
                              else
                              {
                                    pp.mode &= ~HOSTED;
                                    pp.flags &= ~PP_hosted;
                              }
#if !CPP && CATSTRINGS
                              if (st & JOINING) st |= HIDDEN|SYNCLINE;
                              else
#endif
                              {
                                    st &= ~(HIDDEN|SYNCLINE);
                                    switch (cur->type)
                                    {
                                    case IN_BUFFER:
                                    case IN_INIT:
                                          if (!prv->prev) break;
                                          /*FALLTHROUGH*/
                                    case IN_FILE:
                                    case IN_RESCAN:
                                          if (prv->type == IN_FILE || cur->type == IN_FILE && (prv->type == IN_RESCAN || prv->type == IN_MULTILINE))
                                          {
                                                if (pp.linesync && (cur->type != IN_RESCAN || (cur->flags & IN_sync)))
                                                {
                                                      POP();
                                                      SYNCOUT();
                                                      (*pp.linesync)(error_info.line, error_info.file);
                                                      CACHEOUT();
                                                      prv = pp.in;
                                                }
                                          }
#if DEBUG
                                          else if (!prv->prev)
                                          {
                                                /*UNDENT*/
      c = 0;
#if DEBUG & TRACE_count
      if (pp.test & TEST_count)
      {
            c = 1;
            sfprintf(sfstderr, "\n");
            sfprintf(sfstderr, "%7d: pplex calls\n", pp.counter.pplex);
            sfprintf(sfstderr, "%7d: terminal states\n", pp.counter.terminal);
            sfprintf(sfstderr, "%7d: emitted tokens\n", pp.counter.token);
            sfprintf(sfstderr, "%7d: input stream pushes\n", pp.counter.push);
            sfprintf(sfstderr, "%7d: macro candidates\n", pp.counter.candidate);
            sfprintf(sfstderr, "%7d: macro expansions\n", pp.counter.macro);
            sfprintf(sfstderr, "%7d: function macros\n", pp.counter.function);
      }
#endif
#if CPP && (DEBUG & TRACE_debug)
      if (pp.test & TEST_hit)
      {
            c = 1;
            sfprintf(sfstderr, "\n");
            if (hit[elementsof(hit) - 1])
                  sfprintf(sfstderr, "%7d: SPLICE\n", hit[elementsof(hit) - 1]);
            for (n = 0; n < elementsof(hit) - 1; n++)
                  if (hit[n])
                        sfprintf(sfstderr, "%7d: %s\n", hit[n], pplexstr(TERMINAL + n));
      }
#endif
      if (pp.test & (TEST_hashcount|TEST_hashdump))
      {
            c = 1;
            sfprintf(sfstderr, "\n");
            hashdump(NiL, (pp.test & TEST_hashdump) ? HASH_BUCKET : 0);
      }
      if (c) sfprintf(sfstderr, "\n");
                                                /*INDENT*/
                                          }
#endif
                                          break;
                                    }
                              }
#if CHECKPOINT
                              if (cur->index)
                              {
                                    SYNCOUT();
                                    cur->index->end = ppoffset();
                                    cur->index = 0;
                                    CACHEOUT();
                              }
#endif
                              POP();
                              bp = ip;
                              tp = op;
                              goto fsm_get;
                        }
                        c = EOF;
                        break;
                  case IN_COPY:
                        if (prv)
                        {
                              error_info.line = cur->line;
                              if (!(prv->symbol->flags & SYM_MULTILINE))
                                    prv->symbol->flags |= SYM_DISABLED;
                              POP();
                              bp = ip;
                              goto fsm_get;
                        }
                        c = EOF;
                        break;
                  case IN_EXPAND:
                        if (prv)
                        {
                              error_info.line = cur->line;
                              free(cur->buffer);
                              POP();
                              bp = ip;
                              goto fsm_get;
                        }
                        c = EOF;
                        break;
                  case IN_FILE:
                        FGET(c, c, tp, xp);
                        if (c == EOB)
                        {
#if CPP
                              if ((st & (NOTEXT|HIDDEN)) == HIDDEN && LASTOUT() != '\n')
                                    PUTCHR('\n');
                              if (prv)
#else
                              if (st & EOF2NL)
                              {
                                    st &= ~EOF2NL;
                                    *(ip - 1) = c = '\n';
                              }
                              else if (!(st & (FILEPOP|PASSEOF)) && prv)
#endif
                              {
                                    if (!(cur->flags & IN_newline))
                                    {
                                          cur->flags |= IN_newline;
                                          if ((pp.mode & (HOSTED|PEDANTIC)) == PEDANTIC && LASTCHR() != '\f' && LASTCHR() != CC_sub)
                                                error(1, "file does not end with %s", pptokchr('\n'));
                                          *(ip - 1) = c = '\n';
                                    }
                                    else
                                    {
                                          if (!(cur->flags & (IN_noguard|IN_tokens)) && cur->symbol)
                                                ppmultiple(ppsetfile(error_info.file), cur->symbol);
                                          if (cur->fd >= 0)
                                                close(cur->fd);
                                          if (pp.incref && !(pp.mode & INIT))
                                          {
                                                SYNCOUT();
                                                (*pp.incref)(error_info.file, cur->file, error_info.line - 1, PP_SYNC_POP);
                                                CACHEOUT();
                                          }
                                          goto fsm_pop;
                                    }
                              }
                              else
                                    c = EOF;
                        }
                        break;
                  case IN_MACRO:
                  case IN_MULTILINE:
#if !CPP
                        if (!(st & PASSEOF))
#endif
#if COMPATIBLE
                        if (prv && (!INMACRO(rp) || (st & (COMPATIBILITY|TRANSITION)) == COMPATIBILITY && ppismac(*prv->nextchr)))
#else
                        if (prv && !INMACRO(rp))
#endif
                        {
                              if (cur->type == IN_MULTILINE)
                              {
                                    while (pp.control-- != cur->control)
                                          error(2, "#%s on line %d has no #%s", dirname(IF), GETIFLINE(pp.control+1), dirname(ENDIF));
                                    free(cur->buffer);
                                    error_info.file = cur->file;
                                    error_info.line = cur->line;
                                    if (pp.linesync)
                                    {
                                          SYNCOUT();
                                          (*pp.linesync)(error_info.line, error_info.file);
                                          CACHEOUT();
                                    }
                              }
                              cur->symbol->flags &= ~SYM_DISABLED;
                              if (cur->symbol->flags & SYM_FUNCTION)
                                    popframe(pp.macp);
                              POP();
#if CPP
                              if (!(st & COMPATIBILITY) && ppisidig(*(op - 1)) && ppisidig(*ip)) UNGETCHR(' ');
#endif
                              bp = ip;
                              goto fsm_get;
                        }
                        c = EOF;
                        break;
                  case IN_QUOTE:
                        if (prv)
                        {
                              error_info.line = cur->line;
                              st &= ~(ESCAPE|QUOTE);
                              POP();
                              c = '"';
                        }
                        else c = EOF;
                        break;
                  case IN_SQUOTE:
                        if (prv)
                        {
                              error_info.line = cur->line;
                              st &= ~(ESCAPE|SQUOTE);
                              POP();
                              c = '\'';
                        }
                        else c = EOF;
                        break;
                  case IN_STRING:
#if CPP
                        if (prv)
#else
                        if (!(st & PASSEOF) && !(cur->flags & IN_expand) && prv)
#endif
                        {
                              if (cur->flags & IN_disable) st |= DISABLE;
                              else st &= ~DISABLE;
                              POP();
                              bp = ip;
                              goto fsm_get;
                        }
                        c = EOF;
                        break;
                  default:
                        c = EOF;
                        break;
                  }
            }
            bp = ip - 1;
            if (state = rp[c]) goto fsm_next;
            goto fsm_get;

#if !CPP
      case S_HUH:
            if (INOPSPACE(rp))
            {
                  if (c == '=')
                  {
#if PROTOTYPE
                        if (pp.in->flags & IN_prototype) PUTCHR(c);
                        else
                        {
#endif
                              while (*(op - 1) == ' ' || *(op - 1) == '\t') op--;
                              PUTCHR(c);
                              if (st & (STRICT|WARN)) error(1, "%-*.*s: space ignored in operator", op - tp, op - tp, tp);
#if PROTOTYPE
                        }
#endif
                        switch (*tp)
                        {
                        case '/':
                              c = T_DIVEQ;
                              break;
                        case '%':
                              c = T_MODEQ;
                              break;
                        case '&':
                              c = T_ANDEQ;
                              break;
                        case '*':
                              c = T_MPYEQ;
                              break;
                        case '+':
                              c = T_ADDEQ;
                              break;
                        case '-':
                              c = T_SUBEQ;
                              break;
                        case '^':
                              c = T_XOREQ;
                              break;
                        case '|':
                              c = T_OREQ;
                              break;
                        case '<':
                              c = T_LSHIFTEQ;
                              break;
                        case '>':
                              c = T_RSHIFTEQ;
                              break;
                        }
                  }
                  else
                  {
                        BACKIN();
                        switch (c = *tp)
                        {
                        case '<':
                              c = T_LSHIFT;
                              break;
                        case '>':
                              c = T_RSHIFT;
                              break;
                        }
                  }
            }
            else if (pp.level > 1 || (pp.option & PRESERVE)) PUTCHR(c);
            else if (tp == op)
            {
                  if (pp.in->type != IN_BUFFER)
                  {
                        if (!(pp.option & ALLPOSSIBLE))
                              error(1, "%s: invalid character ignored", pptokchr(c));
                        goto fsm_top;
                  }
                  PUTCHR(c);
            }
            else if (*tp == ':')
            {
                  PUTCHR(c);
                  if (c == '=') error(2, "real programmers use =");
                  else c = '+';
            }
            else
            {
                  BACKIN();
                  c = *tp;
            }
            break;
#endif

      case S_QUAL:
            if ((state = NEXT(state)) != LIT1)
            {
                  rp = fsm[state];
                  bp = ip;
#if CPP
                  qual = 1;
#if COMPATIBLE
                  if (!(st & COMPATIBILITY) || c != 'u' && c != 'U')
#endif
                        PUTCHR(c);
#else
                  switch (c)
                  {
                  case 'f':
                  case 'F':
                        qual |= N_FLOAT;
#if COMPATIBLE
                        if (!(st & COMPATIBILITY))
#endif
                        PUTCHR(c);
                        break;
                  case 'l':
                  case 'L':
                        qual |= N_LONG;
                        PUTCHR(c);
                        break;
                  case 'u':
                  case 'U':
                        qual |= N_UNSIGNED;
#if COMPATIBLE
                        if (!(st & COMPATIBILITY))
#endif
                        PUTCHR(c);
                        break;
                  default:
                        PUTCHR(c);
                        break;
                  }
#endif
                  goto fsm_get;
            }
#if !CPP
            qual |= N_WIDE;
            if (DOSTRIP()) BACKOUT();
#endif
            /*FALLTHROUGH*/

      case S_LITBEG:
#if CPP
            quot = c;
            rp = fsm[LIT1];
            if (op == tp)
            {
                  PPSYNCLINE();
                  tp = op;
            }
#else
            if ((quot = c) == '<')
            {
                  if (!(st & HEADER) || (pp.option & (HEADEREXPAND|HEADEREXPANDALL)) && pp.in->type != IN_FILE && pp.in->type != IN_BUFFER && pp.in->type != IN_INIT && pp.in->type != IN_RESCAN)
                  {
                        PUTCHR(c);
                        bp = ip;
                        rp = fsm[LT1];
                        goto fsm_get;
                  }
                  quot = '>';
                  rp = fsm[HDR1];
            }
            else rp = fsm[LIT1];
            if (!DOSTRIP())
#endif
            PUTCHR(c);
            bp = ip;
            goto fsm_get;

      case S_LITEND:
            n = 1;
            if (c != quot)
            {
                  if (c != '\n' && c != EOF)
                  {
                        if (st & (QUOTE|SQUOTE))
                        {
                              if (!(st & ESCAPE))
                              {
                                    st |= ESCAPE;
                                    quotquot = c;
                              }
                              else if (c == quotquot) st &= ~ESCAPE;
                        }
                        PUTCHR(c);
                        bp = ip;
                        goto fsm_get;
                  }
#if CPP
                  if ((st & PASSTHROUGH) || (pp.option & PRESERVE))
                  {
                        if (c == '\n') goto fsm_newline;
                        bp = ip;
                        goto fsm_start;
                  }
#endif
                  m = (st & SKIPCONTROL) && (pp.mode & HOSTED) ? -1 : 1;
                  if (c == '\n' && quot == '\'' && (pp.option & STRINGSPAN)) n = 0;
                  else
#if COMPATIBLE && !CPP
                  if ((st & (COMPATIBILITY|DEFINITION)) != (COMPATIBILITY|DEFINITION))
#endif
                  {
                        switch (quot)
                        {
                        case '"':
                              if (c == '\n')
                              {
                                    if (!(pp.option & STRINGSPAN) || (st & (COMPATIBILITY|STRICT)) == STRICT)
                                          error(m, "%s in string", pptokchr(c));
                                    error_info.line++;
                                    if (!(pp.option & STRINGSPAN))
                                    {
                                          PUTCHR('\\');
                                          c = 'n';
                                    }
                                    else if (pp.option & STRINGSPLIT)
                                    {
                                          PUTCHR('\\');
                                          PUTCHR('n');
                                          PUTCHR('"');
                                          PUTCHR('\n');
                                          c = '"';
                                    }
                                    PUTCHR(c);
                                    bp = ip;
                                    goto fsm_get;
                              }
                              error(m, "%s in string", pptokchr(c));
                              c = '\n';
                              break;
                        case '\'':
                              if (!(st & DIRECTIVE) || !(pp.mode & (HOSTED|RELAX)))
                                    error(m, "%s in character constant", pptokchr(c));
                              break;
                        case '>':
                              error(m, "%s in header constant", pptokchr(c));
                              break;
                        default:
                              error(m, "%s in %c quote", pptokchr(c), quot);
                              break;
                        }
#if !CPP
                        if (!DOSTRIP())
#endif
                        PUTCHR(quot);
                  }
                  if (c == '\n')
                  {
                        UNGETCHR(c);
                        c = quot;
                  }
            }
            else if (st & (SQUOTE|QUOTE))
            {
                  if (!(st & ESCAPE))
                  {
                        st |= ESCAPE;
                        quotquot = c;
                  }
                  else if (c == quotquot) st &= ~ESCAPE;
                  PUTCHR('\\');
                  PUTCHR(c);
                  bp = ip;
                  goto fsm_get;
            }
#if CPP
            else PUTCHR(c);
#else
            else if (!DOSTRIP()) PUTCHR(c);
#endif
#if CATSTRINGS
#if CPP
            if (c == '"' && !(st & (COLLECTING|NOTEXT|PASSTHROUGH|SKIPCONTROL)) && (pp.mode & CATLITERAL))
#else
            if (c == '"' && pp.level == 1 && !(st & (COLLECTING|JOINING|NOTEXT|SKIPCONTROL)) && (pp.mode & CATLITERAL))
#endif
            {
                  char* pptoken;
                  long  ppstate;

                  pptoken = pp.token;
                  pp.token = pp.catbuf;
                  *pp.token++ = 0;
                  ppstate = (st & STRIP);
                  if (DOSTRIP())
                        ppstate |= ADD|QUOTE;
                  st |= JOINING;
                  st &= ~(NEWLINE|STRIP);

                  /*
                   * revert to the top level since string
                   * concatenation crosses file boundaries
                   * (allowing intervening directives)
                   */

                  pp.level = 0;
                  SYNCIN();
                  m = n = 0;
                  for (;;)
                  {
                        switch (c = pplex())
                        {
                        case '\n':
                              m++;
                              continue;
                        case ' ':
                              *pp.catbuf = ' ';
                              continue;
                        case T_WSTRING:
#if !CPP
                              qual = N_WIDE;
#endif
                              if (ppstate & ADD)
                                    ppstate &= ~ADD;
                              else if (m == n || !(st & SPACEOUT))
                                    op--;
                              else
                              {
                                    n = m;
                                    *(op - 1) = '\\';
                                    *op++ = '\n';
                              }
                              STRCOPY(op, pp.token + 2 + (*pp.token == ' '), s);
                              continue;
                        case T_STRING:
                              if (ppstate & ADD)
                                    ppstate &= ~ADD;
                              else if (m == n || !(st & SPACEOUT))
                                    op--;
                              else
                              {
                                    n = m;
                                    *(op - 1) = '\\';
                                    *op++ = '\n';
                              }
                              STRCOPY(op, pp.token + 1 + (*pp.token == ' '), s);
                              continue;
                        case 0:
                              m = error_info.line ? (error_info.line - 1) : 0;
                              *pp.token = 0;
                              /*FALLTHROUGH*/
                        default:
                              if (m)
                              {
                                    if (--m)
                                    {
                                          pp.state |= HIDDEN|SYNCLINE;
                                          pp.hidden += m;
                                    }
#if COMPATIBLE
                                    if ((st & COMPATIBILITY) && c == '#' && *(pp.token - 1))
                                    {
                                          *(pp.token + 3) = *(pp.token + 2);
                                          *(pp.token + 2) = *(pp.token + 1);
                                          *(pp.token + 1) = *pp.token;
                                          *pp.token = *(pp.token - 1);
                                    }
                                    error_info.line--;
                                    *--pp.token = '\n';
#endif
                              }
                              else if (*(pp.token - 1))
                                    pp.token--;
                              if (ppisidig(*pp.token))
                                    *op++ = ' ';
                              if (pp.in->type == IN_MACRO && (s = strchr(pp.token, MARK)) && !*(s + 1))
                              {
                                    *(s + 1) = MARK;
                                    *(s + 2) = 0;
                              }
                              PUSH_STRING(pp.token);
                              pp.state &= ~(JOINING|NEWLINE);
                              pp.state |= ppstate & ~(ADD|QUOTE);
                              if ((ppstate & (ADD|QUOTE)) == QUOTE)
                                    op--;
                              break;
                        }
                        break;
                  }
                  pp.token = pptoken;
                  CACHEIN();
                  pp.level = 1;
#if !CPP
                  c = T_STRING | qual;
                  break;
#endif
            }
#endif
#if CPP
            if (n && !(st & (PASSTHROUGH|SKIPCONTROL|NOTEXT)) && c == '\'' && (op - tp) <= 2 && !(pp.mode & (HOSTED|RELAX)))
                  error(1, "empty character constant");
            if (pp.option & PRESERVE)
                  st &= ~ESCAPE;
            else
                  st &= ~(ESCAPE|NEWLINE);
            pp.in->flags |= IN_tokens;
            count(token);
            goto fsm_start;
#else
            st &= ~ESCAPE;
            switch (quot)
            {
            case '\'':
                  if (n && !(st & NOTEXT) && (op - tp) <= (DOSTRIP() ? 0 : 2) && !(pp.mode & (HOSTED|RELAX)))
                        error(1, "empty character constant");
                  c = T_CHARCONST | qual;
                  break;
            case '>':
                  c = T_HEADER;
                  break;
            default:
                  if (c == quot)
                        c = T_STRING | qual;
                  break;
            }
            break;
#endif

      case S_LITESC:
            if (st & (COLLECTING|DIRECTIVE|QUOTE|SQUOTE))
            {
                  if (st & ESCAPE)
                  {
                        PUTCHR('\\');
                        if (c == quot) PUTCHR('\\');
                  }
                  PUTCHR(c);
            }
#if CPP
            else if (st & PASSTHROUGH) PUTCHR(c);
#endif
            else if (pp.option & PRESERVE) PUTCHR(c);
            else switch (c)
            {
            case 'b':
            case 'f':
            case 'n':
            case 'r':
            case 't':
            case '\\':
            case '\'':
            case '"':
            case '?':
                  PUTCHR(c);
                  break;
#if COMPATIBLE
            case '8':
            case '9':
                  if (!(st & COMPATIBILITY)) goto unknown;
                  if (st & STRICT) error(1, "%c: invalid character in octal character escape", c);
                  /*FALLTHROUGH*/
#endif
            case '0':
            case '1':
            case '2':
            case '3':
            case '4':
            case '5':
            case '6':
            case '7':
                  n = c - '0';
                  for (m = 0; m < 2; m++)
                  {
                        GET(c, c, tp, xp);
                        switch (c)
                        {
#if COMPATIBLE
                        case '8':
                        case '9':
                              if (!(st & COMPATIBILITY))
                              {
                                    UNGETCHR(c);
                                    break;
                              }
                              if (st & STRICT) error(1, "%c: invalid character in octal character escape", c);
                              /*FALLTHROUGH*/
#endif
                        case '0':
                        case '1':
                        case '2':
                        case '3':
                        case '4':
                        case '5':
                        case '6':
                        case '7':
                              n = (n << 3) + c - '0';
                              continue;
                        default:
                              UNGETCHR(c);
                              break;
                        }
                        break;
                  }
                  if (n & ~0777) error(1, "octal character constant too large");
                  goto octal;
            case 'a':
                  if (pp.option & MODERN)
                  {
                        PUTCHR(c);
                        break;
                  }
#if COMPATIBLE
                  if (st & COMPATIBILITY) goto unknown;
#endif
                  n = CC_bel;
                  goto octal;
            case 'v':
                  if (pp.option & MODERN)
                  {
                        PUTCHR(c);
                        break;
                  }
                  n = CC_vt;
                  goto octal;
            case 'E':
                  if (st & (COMPATIBILITY|STRICT)) goto unknown;
                  n = CC_esc;
                  goto octal;
            case 'x':
#if COMPATIBLE
                  if (st & COMPATIBILITY) goto unknown;
#endif
                  n = 0;
                  for (m = 0; m < 3; m++)
                  {
                        GET(c, c, tp, xp);
                        switch (c)
                        {
                        case '0':
                        case '1':
                        case '2':
                        case '3':
                        case '4':
                        case '5':
                        case '6':
                        case '7':
                        case '8':
                        case '9':
                              n = (n << 4) + c - '0';
                              continue;
                        case 'a':
                        case 'b':
                        case 'c':
                        case 'd':
                        case 'e':
                        case 'f':
                              n = (n << 4) + c - 'a' + 10;
                              continue;
                        case 'A':
                        case 'B':
                        case 'C':
                        case 'D':
                        case 'E':
                        case 'F':
                              n = (n << 4) + c - 'A' + 10;
                              continue;
                        default:
                              if (!m) error(1, "\\x%c: invalid character in hexadecimal character constant", c);
                              UNGETCHR(c);
                              break;
                        }
                        break;
                  }
                  if (n & ~0777) error(1, "hexadecimal character constant too large");
            octal:
                  PUTCHR(((n >> 6) & 07) + '0');
                  PUTCHR(((n >> 3) & 07) + '0');
                  PUTCHR((n & 07) + '0');
                  break;
            default:
            unknown:
                  if (st & (STRICT|WARN)) error(1, "\\%c: non-standard character constant", c);
                  PUTCHR(c);
                  break;
            }
            state = LIT1;
            goto fsm_begin;

      case S_MACRO:
            BACKIN();
#if CPP
            if (st & (DISABLE|SKIPCONTROL|SKIPMACRO))
            {
                  if (st & SKIPMACRO)
                        pp.mode |= MARKMACRO;
                  st &= ~(NEWLINE|SKIPMACRO);
                  pp.in->flags |= IN_tokens;
                  count(token);
                  goto fsm_start;
            }
            count(candidate);
            SETCHR(0);
            switch (state = INDEX(rp))
            {
            case HIT0:
                  tp = op - 1;
                  break;
            case HITN:
                  bp = tp;
                  tp = op - ((pp.truncate && pp.truncate < (HITN - HIT0)) ? (pp.truncate - 1) : (HITN - HIT0));
                  while (tp > bp && ppisidig(*(tp - 1))) tp--;
                  break;
            default:
                  bp = tp;
                  if ((tp = op - (state - HIT0)) > bp && *(tp - 1) == 'L') tp--;
                  break;
            }
            if (sym = ppsymref(pp.symtab, tp))
            {
                  SYNCIN();
                  n = ppcall(sym, 0);
                  CACHEIN();
                  if (n >= 0)
                  {
                        BACKOUT();
                        if (!n)
                        {
                              if (sp) op = sp;
                              else
                              {
                                    s = ip;
                                    ip = sym->macro->value;
                                    c = sym->macro->size;
                                    while (c > 0)
                                    {
                                          if (op + c < xp + PPBUFSIZ) n = c;
                                          else n = xp + PPBUFSIZ - op;
                                          MEMCPY(op, ip, n);
                                          c -= n;
                                          PPCHECKOUT();
                                    }
                                    ip = s;
                              }
                        }
                        else if ((sym->flags & SYM_MULTILINE) && pp.linesync)
                        {
                              SYNCOUT();
                              if (!(state & NEWLINE))
                                    ppputchar('\n');
                              (*pp.linesync)(error_info.line, error_info.file);
                              CACHEOUT();
                        }
                  }
            }
            pp.in->flags |= IN_tokens;
            goto fsm_start;
#else
            if (st & (COLLECTING|DEFINITION|DISABLE|SKIPCONTROL|SKIPMACRO))
            {
                  if (st & SKIPMACRO)
                        pp.mode |= MARKMACRO;
                  st &= ~(NEWLINE|NOEXPAND|SKIPMACRO);
                  c = T_ID;
                  if (pp.level == 1)
                  {
                        pp.in->flags |= IN_tokens;
                        if (st & NOTEXT)
                        {
                              BACKOUT();
                              goto fsm_top;
                        }
                        if (st & COMPILE)
                        {
                              SETCHR(0);
                              if (pp.truncate && (op - tp) > pp.truncate) tp[pp.truncate] = 0;
                              sym = (pp.option & NOHASH) ? ppsymref(pp.symtab, tp) : ppsymset(pp.symtab, tp);
 fsm_noise:
                              if (pp.symbol = sym)
                              {
                                    if ((sym->flags & SYM_KEYWORD) && (!pp.truncate || (op - tp) <= pp.truncate || (tp[pp.truncate] = '_', tp[pp.truncate + 1] = 0, pp.symbol = sym = (pp.option & NOHASH) ? ppsymref(pp.symtab, tp) : ppsymset(pp.symtab, tp), 0)))
                                    {
                                          c = ((struct ppsymkey*)sym)->lex;
                                          /*UNDENT*/

#define ADVANCE() do{if(pp.toknxt<op)pp.token=pp.toknxt;}while(0)

#define NOISE_BRACE           01
#define NOISE_NOSPACEOUT      02
#define NOISE_PAREN           04

      if ((pp.option & NOISE) && ppisnoise(c))
      {
            if (c != T_NOISE)
            {
                  int         p;
                  int         f;
                  char*       pptoken;
                  PPCOMMENT   ppcomment;

                  SYNCIN();
                  pp.toknxt = op;
                  f = 0;
                  if (!(pp.state & SPACEOUT))
                  {
                        pp.state |= SPACEOUT;
                        f |= NOISE_NOSPACEOUT;
                  }
                  ppcomment = pp.comment;
                  pp.comment = 0;
                  op = (pptoken = tp) + MAXTOKEN;
                  switch (c)
                  {
                  case T_X_GROUP:
                        m = p = 0;
                        quot = 1;
                        for (;;)
                        {
                              ADVANCE();
                              switch (c = pplex())
                              {
                              case '(':
                              case '{':
                                    if (!p)
                                    {
                                          if (c == '(')
                                          {
                                                if (f & NOISE_PAREN)
                                                {
                                                      ungetchr(c);
                                                      *--pp.toknxt = 0;
                                                      break;
                                                }
                                                f |= NOISE_PAREN;
                                                p = ')';
                                          }
                                          else
                                          {
                                                f |= NOISE_BRACE|NOISE_PAREN;
                                                p = '}';
                                          }
                                          n = 1;
                                          m = c;
                                    }
                                    else if (c == m) n++;
                                    quot = 0;
                                    continue;
                              case ')':
                              case '}':
                                    if (c == p && --n <= 0)
                                    {
                                          if (c == '}') break;
                                          m = '\n';
                                          p = 0;
                                    }
                                    quot = 0;
                                    continue;
                              case ' ':
                                    continue;
                              case '\n':
                                    error_info.line++;
                                    if (!m) m = '\n';
                                    continue;
                              case 0:
                                    break;
                              case T_ID:
                                    if (quot) continue;
                                    /*FALLTHROUGH*/
                              default:
                                    if (m == '\n')
                                    {
                                          /*
                                           * NOTE: token expanded again
                                           */

                                          s = pp.toknxt;
                                          while (s > pp.token) ungetchr(*--s);
                                          *(pp.toknxt = s) = 0;
                                          break;
                                    }
                                    continue;
                              }
                              break;
                        }
                        break;
                  case T_X_LINE:
                        for (;;)
                        {
                              ADVANCE();
                              switch (pplex())
                              {
                              case 0:
                                    break;
                              case '\n':
                                    error_info.line++;
                                    break;
                              default:
                                    continue;
                              }
                              break;
                        }
                        break;
                  case T_X_STATEMENT:
                        for (;;)
                        {
                              ADVANCE();
                              switch (pplex())
                              {
                              case 0:
                                    break;
                              case ';':
                                    ungetchr(';');
                                    *(pp.toknxt = pp.token) = 0;
                                    break;
                              default:
                                    continue;
                              }
                              break;
                        }
                        break;
                  }
                  pp.comment = ppcomment;
                  if (f & NOISE_NOSPACEOUT)
                        pp.state &= ~SPACEOUT;
                  CACHEIN();
                  tp = pptoken;
                  op = pp.toknxt;
                  c = T_NOISES;
            }
            if (pp.option & NOISEFILTER)
            {
                  BACKOUT();
                  goto fsm_top;
            }
      }

                                          /*INDENT*/
                                    }
                                    else if ((pp.option & NOISE) && c == T_ID && strneq(tp, "__builtin_", 10))
                                    {
                                          hashlook(pp.symtab, tp, HASH_DELETE, NiL);
                                          pp.symbol = sym = (struct ppsymbol*)ppkeyset(pp.symtab, tp);
                                          sym->flags |= SYM_KEYWORD;
                                          c = ((struct ppsymkey*)sym)->lex = T_BUILTIN;
                                    }
                              }
                        }
                        goto fsm_symbol;
                  }
                  goto fsm_check;
            }
            if (pp.level == 1)
            {
                  st &= ~(NEWLINE|PASSEOF);
                  pp.in->flags |= IN_tokens;
            }
            else st &= ~PASSEOF;
            count(candidate);
            SETCHR(0);
            if (sym = ppsymref(pp.symtab, tp))
            {
                  SYNCIN();
                  c = ppcall(sym, 1);
                  CACHEIN();
                  if (c >= 0)
                  {
                        BACKOUT();
                        if ((sym->flags & SYM_MULTILINE) && pp.linesync)
                        {
                              SYNCOUT();
                              (*pp.linesync)(error_info.line, error_info.file);
                              CACHEOUT();
                        }
                        goto fsm_top;
                  }
            }
            c = T_ID;
            if (pp.level == 1)
            {
                  if (st & NOTEXT)
                  {
                        BACKOUT();
                        goto fsm_top;
                  }
                  if (st & COMPILE)
                  {
                        if (pp.truncate && (op - tp) > pp.truncate)
                        {
                              tp[pp.truncate] = 0;
                              sym = 0;
                        }
                        if (!sym)
                        {
                              if (!(pp.option & NOHASH)) sym = ppsymset(pp.symtab, tp);
                              else if (!(sym = ppsymref(pp.symtab, tp))) goto fsm_symbol;
                        }
                        goto fsm_noise;
                  }
                  goto fsm_symbol;
            }
            goto fsm_check;
#endif

      case S_SHARP:
            if (c == '(')
            {
                  pp.in->flags |= IN_tokens;
                  if ((st & STRICT) && pp.in->type != IN_MACRO && pp.in->type != IN_MULTILINE)
                  {
                        if (!(pp.mode & HOSTED)) error(1, "non-standard reference to #(...)");
                        if (st & STRICT)
                        {
                              PUTCHR(c);
#if CPP
                              st &= ~NEWLINE;
                              count(token);
                              goto fsm_start;
#else
                              break;
#endif
                        }
                  }
                  if (st & (COLLECTING|DEFINITION|DISABLE|SKIPCONTROL))
                  {
                        PUTCHR(c);
#if CPP
                        st &= ~NEWLINE;
                        count(token);
                        goto fsm_start;
#else
                        st &= ~NOEXPAND;
                        break;
#endif
                  }
                  op--;
                  SYNC();
                  ppbuiltin();
                  CACHE();
#if CPP
                  count(token);
                  goto fsm_start;
#else
                  goto fsm_top;
#endif
            }
            BACKIN();
#if CPP
            if (!(st & NEWLINE) || !(pp.in->type & IN_TOP))
            {
 fsm_nondirective:
                  st &= ~NEWLINE;
                  pp.in->flags |= IN_tokens;
                  count(token);
                  goto fsm_start;
            }
            if (*(s = tp) != '#')
            {
#if COMPATIBLE
                  if ((st & (COMPATIBILITY|TRANSITION)) == COMPATIBILITY) goto fsm_nondirective;
#endif
                  while (*s == ' ' || *s == '\t') s++;
                  if (*s != '#') goto fsm_nondirective;
            }
            BACKOUT();
#else
            if (!(st & NEWLINE) || (st & DEFINITION) || !(pp.in->type & IN_TOP))
            {
                  if (c == '#')
                  {
                        SKIPIN();
                        if (!(st & DEFINITION))
                              PUTCHR(c);
                        c = T_TOKCAT;
                  }
                  else if (pp.level == 1 && !(st & (JOINING|SPACEOUT)) && !(pp.option & PRESERVE))
                  {
                        char*       pptoken;
                        char*       oop;
                        PPCOMMENT   ppcomment;

                        SYNCIN();
                        pp.toknxt = oop = op;
                        pp.state |= SPACEOUT;
                        ppcomment = pp.comment;
                        pp.comment = 0;
                        op = (pptoken = tp) + MAXTOKEN;
                        for (;;)
                        {
                              ADVANCE();
                              switch (pplex())
                              {
                              case 0:
                                    break;
                              case '\n':
                                    error_info.line++;
                                    break;
                              default:
                                    continue;
                              }
                              break;
                        }
                        pp.comment = ppcomment;
                        pp.state &= ~SPACEOUT;
                        CACHEIN();
                        tp = pptoken;
                        *--op = 0;
                        op = oop;
                        if (pp.pragma && !(st & NOTEXT))
                        {
                              *s = 0;
                              SYNC();
                              (*pp.pragma)(NiL, NiL, NiL, tp, 1);
                              CACHE();
                        }
                        if (!c) BACKIN();
                        goto fsm_top;
                  }
                  else c = '#';
                  break;
            }
            if ((st & (COLLECTING|STRICT)) == (COLLECTING|STRICT))
                  error(1, "directives in macro call arguments are not portable");
#endif
            if (c == '#' && pp.in->type == IN_RESCAN)
            {
                  /*
                   * pass line to pp.pragma VERBATIM
                   */
                  
                  SKIPIN();
                  s = pp.valbuf;
                  while ((c = GETCHR()) && c != '\n')
                        if ((*s++ = c) == MARK) SKIPIN();
                  if (pp.pragma && !(st & NOTEXT))
                  {
                        *s = 0;
                        SYNC();
                        (*pp.pragma)(NiL, NiL, NiL, pp.valbuf, 1);
                        CACHE();
                  }
                  if (!c) BACKIN();
#if CPP
                  goto fsm_start;
#else
                  goto fsm_top;
#endif
            }
            SYNC();
            ppcontrol();
            CACHE();
#if CPP
            if (st & (NOTEXT|SKIPCONTROL))
            {
                  if (!sp)
                  {
                        PPCHECKOUTTP();
                        sp = tp;
                  }
            }
            else if (sp)
            {
                  tp = op = sp;
                  sp = 0;
            }
            goto fsm_start;
#else
            goto fsm_top;
#endif

      case S_NL:
#if CPP
            if (op == tp && !(st & JOINING) && pp.in->type == IN_FILE && !(pp.option & PRESERVE))
            {
                  st |= NEWLINE|HIDDEN;
                  pp.hidden++;
                  error_info.line++;
                  goto fsm_start;
            }
#endif
 fsm_newline:
#if CPP
            if (sp)
                  op = sp;
            else if (!(pp.in->flags & IN_noguard))
            {
                  while (tp < op)
                        if ((c = *tp++) != ' ' && c != '\t')
                        {
                              pp.in->flags |= IN_tokens;
                              break;
                        }
                  c = '\n';
            }
            st |= NEWLINE;
            error_info.line++;
            if (*ip == '\n' && *(ip + 1) != '\n' && !pp.macref && !(st & (ADD|HIDDEN)))
            {
                  ip++;
                  PUTCHR('\n');
                  error_info.line++;
            }
            if ((st & NOTEXT) && ((pp.mode & FILEDEPS) || (pp.option & (DEFINITIONS|PREDEFINITIONS))))
                  BACKOUT();
            else
            {
                  debug((-5, "token[%d] %03o = %s [line=%d]", pp.level, c, pptokchr(c), error_info.line));
                  PUTCHR('\n');
                  PPSYNCLINE();
                  if (sp)
                  {
                        PPCHECKOUT();
                        sp = op;
                  }
            }
            goto fsm_start;
#else
            st |= NEWLINE;
            if (pp.level == 1)
            {
                  error_info.line++;
                  if (!(st & (JOINING|SPACEOUT)))
                  {
                        debug((-5, "token[%d] %03o = %s [line=%d]", pp.level, c, pptokchr(c), error_info.line));
                        BACKOUT();
                        goto fsm_top;
                  }
            }
            BACKOUT();
            if (st & SKIPCONTROL)
            {
                  error_info.line++;
                  st |= HIDDEN;
                  pp.hidden++;
                  goto fsm_start;
            }
            PUTCHR(c = '\n');
            goto fsm_return;
#endif

#if !CPP
      case S_TOK:
            PUTCHR(c);
            c = TYPE(state) | qual;
            break;

      case S_TOKB:
            BACKIN();
            c = TYPE(state) | qual;
            break;
#endif

      case S_VS:
            PUTCHR(c);
#if !CPP
            if (st & NOVERTICAL)
            {
                  error(1, "%s invalid in directives", pptokchr(c));
                  st &= ~NOVERTICAL;
            }
#endif
#if COMPATIBLE
            if (st & COMPATIBILITY) st |= NEWLINE;
#endif
#if CPP
            if (!(pp.in->flags & IN_noguard))
                  while (tp < op)
                        if ((c = *tp++) != ' ' && c != '\t')
                        {
                              pp.in->flags |= IN_tokens;
                              break;
                        }
            goto fsm_start;
#else
            bp = ip;
            rp = fsm[WS1];
            goto fsm_get;
#endif

#if !CPP
      case S_WS:
#if COMPATIBLE
            if ((st & (COMPATIBILITY|TRANSITION)) == COMPATIBILITY) st &= ~NEWLINE;
#endif
            if (pp.level == 1)
            {
                  if ((st & (COMPATIBILITY|SPACEOUT)) && !(st & TRANSITION))
                  {
                        if (st & (COMPILE|NOTEXT))
                        {
#if CATSTRINGS
                              if ((st & (JOINING|NOTEXT|SPACEOUT)) != SPACEOUT)
#else
                              if ((st & (NOTEXT|SPACEOUT)) != SPACEOUT)
#endif
                              {
                                    BACKOUT();
                                    bp = ip - 1;
                                    rp = fsm[START];
                                    if (state = rp[c]) goto fsm_next;
                                    goto fsm_get;
                              }
                        }
                        else
#if CATSTRINGS
                        if (!(st & JOINING))
#endif
                        {
                              tp = op;
                              bp = ip - 1;
                              rp = fsm[START];
                              if (state = rp[c]) goto fsm_next;
                              goto fsm_get;
                        }
                        BACKIN();
                        c = ' ';
                        goto fsm_return;
                  }
                  BACKOUT();
                  bp = ip - 1;
                  rp = fsm[START];
                  if (state = rp[c]) goto fsm_next;
                  goto fsm_get;
            }
            if (st & (NOSPACE|SKIPCONTROL))
            {
                  BACKOUT();
                  bp = ip - 1;
                  rp = fsm[START];
                  if (state = rp[c]) goto fsm_next;
                  goto fsm_get;
            }
            if (c != '\n')
            {
                  BACKIN();
                  c = ' ';
            }
            if (!(pp.option & PRESERVE))
            {
                  BACKOUT();
                  PUTCHR(c);
            }
            goto fsm_return;
#endif

      default:
            if (state & SPLICE)
            {
                  switch (c)
                  {
                  case MARK:
                        /*
                         * internal mark
                         */

                        switch (pp.in->type)
                        {
                        case IN_BUFFER:
                        case IN_FILE:
#if !CPP
                        case IN_INIT:
#if CATSTRINGS
                              if ((st & JOINING) && (!INQUOTE(rp) || quot != '"') || pp.level > 1 && (rp == fsm[START] || INQUOTE(rp)))
#else
                              if (pp.level > 1 && (rp == fsm[START] || INQUOTE(rp)))
#endif
                                    PUTCHR(c);
#endif
                              break;
                        default:
                              switch (GETCHR())
                              {
                              case 'A':
                                    if (!(st & (DEFINITION|DISABLE)))
                                    {
                                          c = GETCHR();
                                          SYNCIN();
                                          if (pp.macp->arg[c - ARGOFFSET][-1])
                                                PUSH_EXPAND(pp.macp->arg[c - ARGOFFSET], pp.macp->line);
                                          else
                                                PUSH_COPY(pp.macp->arg[c - ARGOFFSET], pp.macp->line);
                                          CACHEIN();
                                          bp = ip;
                                          goto fsm_get;
                                    }
                                    /*FALLTHROUGH*/
                              case 'C':
                                    c = GETCHR() - ARGOFFSET;
                                    if (!*(s = pp.macp->arg[c]) && (pp.in->symbol->flags & SYM_VARIADIC) && pp.in->symbol->macro->arity == (c + 1))
                                    {
                                          s = ip - 3;
                                          while (--op > tp && --s > bp && ppisidig(*s));
                                    }
                                    else
                                    {
                                          SYNCIN();
                                          PUSH_COPY(s, pp.macp->line);
                                          CACHEIN();
                                    }
                                    bp = ip;
                                    goto fsm_get;
                              case 'F':
                                    error_info.file = (char*)strtoul(ip, &s, 16);
                                    debug((-6, "actual sync: file = \"%s\"", error_info.file));
                                    bp = ip = s + 1;
                                    goto fsm_get;
                              case 'L':
                                    error_info.line = strtoul(ip, &s, 16);
                                    debug((-6, "actual sync: line = %d", error_info.line));
                                    bp = ip = s + 1;
                                    goto fsm_get;
                              case 'Q':
                                    c = GETCHR();
                                    SYNCIN();
                                    PUSH_QUOTE(pp.macp->arg[c - ARGOFFSET], pp.macp->line);
                                    CACHEIN();
                                    bp = ip - 1;
                                    if (st & (COLLECTING|EOF2NL|JOINING)) rp = fsm[START];
                                    if (state = rp[c = '"']) goto fsm_next;
                                    goto fsm_get;
                              case 'S':
                                    c = GETCHR();
                                    SYNCIN();
                                    PUSH_SQUOTE(pp.macp->arg[c - ARGOFFSET], pp.macp->line);
                                    CACHEIN();
                                    bp = ip - 1;
                                    if (st & COLLECTING) rp = fsm[START];
                                    if (state = rp[c = '\'']) goto fsm_next;
                                    goto fsm_get;
                              case 'X':
                                    if (pp.in->type != IN_COPY)
                                          st |= SKIPMACRO;
                                    if (pp.level <= 1)
                                    {
                                          bp = ip;
                                          goto fsm_get;
                                    }
                                    if (pp.in->type == IN_EXPAND)
                                    {
                                          st &= ~SKIPMACRO;
                                          PUTCHR(c);
                                          PUTCHR('X');
                                    }
                                    c = GETCHR();
                                    break;
                              case 0:
                                    if ((state &= ~SPLICE) >= TERMINAL) goto fsm_terminal;
                                    goto fsm_begin;
                              default:
#if DEBUG
                                    error(PANIC, "invalid mark op `%c'", LASTCHR());
                                    /*FALLTHROUGH*/
                              case MARK:
#endif
#if CATSTRINGS
                                    if ((st & (JOINING|QUOTE)) == JOINING)
                                    {
                                          if (!INQUOTE(rp))
                                                PUTCHR(c);
                                    }
                                    else
#endif
#if CPP
                                    if (rp != fsm[START] && !INQUOTE(rp))
                                          UNGETCHR(c);
#else
                                    if (rp != fsm[START] && !INQUOTE(rp))
                                          UNGETCHR(c);
                                    else if (pp.level > 1)
                                          PUTCHR(c);
#endif
                                    break;
                              }
                              break;
                        }
                        break;
                  case '?':
                        /*
                         * trigraph
                         */

                        if (pp.in->type == IN_FILE)
                        {
                              GET(c, n, tp, xp);
                              if (n == '?')
                              {
                                    GET(c, n, tp, xp);
                                    if (c = trigraph[n])
                                    {
                                          if ((st & WARN) && (st & (COMPATIBILITY|TRANSITION)) && !(pp.mode & HOSTED) && !INCOMMENT(rp))
                                                error(1, "trigraph conversion %c%c%c -> %c%s", '?', '?', n, c, (st & TRANSITION) ? "" : " inhibited");
#if COMPATIBLE
                                          if ((st & (COMPATIBILITY|TRANSITION)) != COMPATIBILITY)
                                          {
#endif
                                          *(bp = ip - 1) = c;
                                          if (state = rp[c]) goto fsm_next;
                                          goto fsm_get;
#if COMPATIBLE
                                          }
#endif
                                    }
                                    if (n != EOB) BACKIN();
                                    UNGETCHR(c = '?');
                              }
                              else if (n != EOB) BACKIN();
                        }
                        break;
                  case '%':
                  case '<':
                  case ':':
                        /*
                         * digraph = --trigraph
                         */

                        if (pp.in->type == IN_FILE && (pp.option & PLUSPLUS))
                        {
                              m = 0;
                              GET(c, n, tp, xp);
                              switch (n)
                              {
                              case '%':
                                    if (c == '<') m = '{';
                                    break;
                              case '>':
                                    if (c == '%') m = '}';
                                    else if (c == ':') m = ']';
                                    break;
                              case ':':
                                    if (c == '%') m = '#';
                                    else if (c == '<') m = '[';
                                    break;
                              }
                              if (m)
                              {
                                    if ((st & WARN) && (st & (COMPATIBILITY|TRANSITION)) && !(pp.mode & HOSTED) && !INCOMMENT(rp))
                                          error(1, "digraph conversion %c%c -> %c%s", c, n, m, (st & TRANSITION) ? "" : " inhibited");
#if COMPATIBLE
                                    if ((st & (COMPATIBILITY|TRANSITION)) != COMPATIBILITY)
                                    {
#endif
                                    *(bp = ip - 1) = c = m;
                                    if (state = rp[c]) goto fsm_next;
                                    goto fsm_get;
#if COMPATIBLE
                                    }
#endif
                              }
                              if (n != EOB) BACKIN();
                        }
                        break;
                  case '\\':
                        /*
                         * line splice
                         */

                        if (pp.in->type == IN_FILE && (!(pp.option & PLUSSPLICE) || !INCOMMENTXX(rp)))
                        {
                              m = 0;
                              GET(c, n, tp, xp);
                              if ((pp.option & SPLICESPACE) && !INQUOTE(rp))
                                    while (n == ' ')
                                    {
                                          GET(c, n, tp, xp);
                                          m = 1;
                                    }
                              if (n == '\r')
                              {
                                    GET(c, n, tp, xp);
                                    if (n != '\n' && n != EOB)
                                          BACKIN();
                              }
                              if (n == '\n')
                              {
#if CPP
                                    if (INQUOTE(rp))
                                    {
                                          if ((pp.option & STRINGSPLIT) && quot == '"')
                                          {
                                                PUTCHR(quot);
                                                PUTCHR(n);
                                                PUTCHR(quot);
                                          }
                                          else if (*pp.lineid)
                                          {
                                                PUTCHR(c);
                                                PUTCHR(n);
                                          }
                                          else
                                          {
                                                st |= HIDDEN;
                                                pp.hidden++;
                                          }
                                    }
                                    else
#else
#if COMPATIBLE
                                    if (!INQUOTE(rp) && (st & (COMPATIBILITY|DEFINITION|TRANSITION)) == (COMPATIBILITY|DEFINITION))
                                    {
                                          if (op == tp)
                                          {
                                                st |= HIDDEN;
                                                pp.hidden++;
                                                error_info.line++;
                                                if (st & SPACEOUT)
                                                      goto fsm_start;
                                                c = (pp.option & SPLICECAT) ? '\t' : ' ';
                                                PUTCHR(c);
                                                goto fsm_check;
                                          }
                                          UNGETCHR(n);
                                          state &= ~SPLICE;
                                          goto fsm_terminal;
                                    }
#endif
#endif
                                    {
                                          st |= HIDDEN;
                                          pp.hidden++;
                                    }
#if CPP
                                    spliced++;
#else
                                    error_info.line++;
#endif
                                    bp = ip;
                                    goto fsm_get;
                              }
                              else if ((n == 'u' || n == 'U') && !INQUOTE(rp))
                              {
                                    PUTCHR(c);
                                    PUTCHR(n);
                                    bp = ip;
                                    goto fsm_get;
                              }
#if COMPATIBLE
                              else if ((st & (COMPATIBILITY|TRANSITION)) == COMPATIBILITY && (n == '"' || n == '\'') && !INQUOTE(rp))
                              {
                                    PUTCHR(c);
                                    PUTCHR(n);
                                    bp = ip;
                                    goto fsm_get;
                              }
#endif
                              else if (n != EOB)
                                    BACKIN();
                              if (m && INSPACE(rp))
                                    UNGETCHR(c);
                        }
#if COMPATIBLE
                        else if ((st & (COMPATIBILITY|TRANSITION)) == COMPATIBILITY && !INQUOTE(rp))
                        {
                              GET(c, n, tp, xp);
                              if (n == '"' || n == '\'')
                              {
                                    PUTCHR(c);
                                    PUTCHR(n);
                                    bp = ip;
                                    goto fsm_get;
                              }
                              if (n != EOB)
                                    BACKIN();
                        }
#endif
                        break;
                  case '\r':
                        /*
                         * barf
                         */

                        if (pp.in->type == IN_FILE)
                        {
                              GET(c, n, tp, xp);
                              if (n == '\n')
                              {
                                    *(bp = ip - 1) = c = n;
                                    if (state = rp[c]) goto fsm_next;
                                    goto fsm_get;
                              }
                              if (n != EOB) BACKIN();
                        }
                        break;
                  case CC_sub:
                        /*
                         * barf & puke
                         */

                        if ((pp.option & ZEOF) && pp.in->type == IN_FILE)
                        {
                              pp.in->flags |= IN_eof;
                              c = 0;
                              state = S_EOB;
                              goto fsm_terminal;
                        }
                        break;
                  }
                  if ((state &= ~SPLICE) >= TERMINAL)
                        goto fsm_terminal;
                  PUTCHR(c);
                  goto fsm_begin;
            }
#if CPP
            if (INOPSPACE(rp))
            {
                  BACKIN();
                  goto fsm_start;
            }
#endif
            PUTCHR(c);
            bp = ip;
            goto fsm_get;
      }
#if !CPP
 fsm_token:
      st &= ~NEWLINE;
      if (pp.level == 1)
      {
            pp.in->flags |= IN_tokens;
            if (st & NOTEXT)
            {
                  BACKOUT();
                  goto fsm_top;
            }
 fsm_symbol:
            count(token);
      }
 fsm_check:
      if (st & SKIPCONTROL)
      {
            BACKOUT();
            goto fsm_start;
      }
 fsm_return:
#if CPP
      error_info.line += spliced;
#endif
      SETCHR(0);
      debug((-5, "token[%d] %03o = %s", pp.level, c, pptokstr(tp, 0)));
      SYNC();
      pp.level--;
      error_info.indent--;
      return c;
#endif
}

#if CPP && POOL

#include <ls.h>
#include <wait.h>

/*
 * output pool status on exit
 */

static void
poolstatus(void)
{
      error(ERROR_OUTPUT|0, pp.pool.output, "%d", error_info.errors != 0);
}

/*
 * loop on < input output >
 */

static void
pool(void)
{
      char* ifile;
      char* ofile;

      ppflushout();
      if (!sfnew(sfstdin, NiL, SF_UNBOUND, pp.pool.input, SF_READ))
            error(ERROR_SYSTEM|3, "cannot dup pool input");

      /*
       * kick the -I cache
       */

      ppsearch(".", T_STRING, SEARCH_EXISTS);

      /*
       * loop on < input output >
       */

      pp.pool.input = 0;
      while (ifile = sfgetr(sfstdin, '\n', 1))
      {
            if (!(ofile = strchr(ifile, ' ')))
                  error(3, "%s: pool output file expected", ifile);
            *ofile++ = 0;
            waitpid(0, NiL, WNOHANG);
            switch (fork())
            {
            case -1:
                  error(ERROR_SYSTEM|3, "cannot fork pool");
            case 0:
                  atexit(poolstatus);
                  error_info.errors = 0;
                  error_info.warnings = 0;
                  close(0);
                  if (open(ifile, O_RDONLY))
                        error(ERROR_SYSTEM|3, "%s: cannot read", ifile);
                  close(1);
                  if (open(ofile, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH) != 1)
                        error(ERROR_SYSTEM|3, "%s: cannot create", ofile);
                  pp.outfile = ofile;
                  pathcanon(ifile, 0);
                  ifile = ppsetfile(ifile)->name;
#if CHECKPOINT
                  if (pp.mode & DUMP)
                  {
                        if (!pp.pragma)
                              error(3, "#%s must be enabled for checkpoints", dirname(PRAGMA));
                        (*pp.pragma)(dirname(PRAGMA), pp.pass, keyname(X_CHECKPOINT), pp.checkpoint, 1);
                  }
#endif
                  PUSH_FILE(ifile, 0);
                  return;
            }
      }
      while (wait(NiL) != -1);
}

#endif

Generated by  Doxygen 1.6.0   Back to index