diff options
Diffstat (limited to 'usr/src/lib/libpp/common/pplex.c')
-rw-r--r-- | usr/src/lib/libpp/common/pplex.c | 2441 |
1 files changed, 2441 insertions, 0 deletions
diff --git a/usr/src/lib/libpp/common/pplex.c b/usr/src/lib/libpp/common/pplex.c new file mode 100644 index 0000000000..364854d8ae --- /dev/null +++ b/usr/src/lib/libpp/common/pplex.c @@ -0,0 +1,2441 @@ +/*********************************************************************** +* * +* 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 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)) + switch (TERM(state)) + { + case S_SHARP: + break; + case S_CHRB: + case S_NL: + if (*ip == '\n') + break; + /*FALLTHROUGH*/ + default: + 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) + { + 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"); + 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) + { + 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 |