8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / lib / libpp / common / pplex.c
blob4fd2bbae0b6b19b9d4731da0b32b464eeb256aa9
1 /***********************************************************************
2 * *
3 * This software is part of the ast package *
4 * Copyright (c) 1986-2009 AT&T Intellectual Property *
5 * and is licensed under the *
6 * Common Public License, Version 1.0 *
7 * by AT&T Intellectual Property *
8 * *
9 * A copy of the License is available at *
10 * http://www.opensource.org/licenses/cpl1.0.txt *
11 * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
12 * *
13 * Information and Software Systems Research *
14 * AT&T Research *
15 * Florham Park NJ *
16 * *
17 * Glenn Fowler <gsf@research.att.com> *
18 * *
19 ***********************************************************************/
20 #pragma prototyped
22 * Glenn Fowler
23 * AT&T Research
25 * preprocessor lexical analyzer
26 * standalone and tokenizing lexer combined in one source
27 * define CPP=1 for standalone
30 #include "pplib.h"
31 #include "ppfsm.h"
33 #if CPP
36 * standalone entry point
39 #define PPCPP_T void
41 #define START QUICK
42 #define INMACRO(x) INQMACRO(x)
43 #define DOSTRIP() (st&STRIP)
45 #if DEBUG & TRACE_debug
46 static int hit[LAST-TERMINAL+2];
47 #endif
49 #define BACKIN() (ip--)
50 #define BACKOUT() (op=tp)
51 #define CACHE() do{CACHEINX();CACHEOUTX();st=pp.state;if(!pp.hidden)spliced=0;}while(0)
52 #define CACHEIN() do{CACHEINX();st=pp.state;if(!pp.hidden)spliced=0;}while(0)
53 #define CACHEINX() do{ip=pp.in->nextchr;}while(0)
54 #define CACHEOUT() do{CACHEOUTX();st=pp.state;if(!pp.hidden)spliced=0;}while(0)
55 #define CACHEOUTX() do{tp=op=pp.outp;xp=pp.oute;if(sp)sp=op;}while(0)
56 #define GETCHR() (*(unsigned char*)ip++)
57 #define LASTCHR() (*(ip-1))
58 #define LASTOUT() ((op>pp.outbuf)?*(op-1):pp.lastout)
59 #define SKIPIN() (ip++)
60 #define PUTCHR(c) (*op++=(c))
61 #define SETCHR(c) (*op=(c))
62 #define SYNC() do{SYNCINX();SYNCOUTX();pp.state=st;}while(0)
63 #define SYNCIN() do{SYNCINX();pp.state=st;}while(0)
64 #define SYNCINX() do{pp.in->nextchr=ip;}while(0)
65 #define SYNCOUT() do{SYNCOUTX();pp.state=st;}while(0)
66 #define SYNCOUTX() do{if(sp)op=tp=sp;pp.outp=op;}while(0)
67 #define UNGETCHR(c) (*--ip=(c))
69 #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)
70 #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)
71 #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)
73 #define PPSYNCLINE() do { \
74 if ((st & (ADD|HIDDEN)) && !(*pp.control & SKIP)) \
75 { \
76 if (spliced) \
77 { \
78 error_info.line += spliced; \
79 spliced = 0; \
80 } \
81 else \
82 { \
83 if (st & ADD) \
84 { \
85 st &= ~ADD; \
86 m = pp.addp - pp.addbuf; \
87 pp.addp = pp.addbuf; \
88 memcpy(op, pp.addbuf, m); \
89 op += m; \
90 PPCHECKOUT(); \
91 } \
92 if (pp.linesync) \
93 { \
94 if ((st & SYNCLINE) || pp.hidden >= MAXHIDDEN) \
95 { \
96 pp.hidden = 0; \
97 st &= ~(HIDDEN|SYNCLINE); \
98 if (error_info.line) \
99 { \
100 if (LASTOUT() != '\n') \
101 PUTCHR('\n'); \
102 SYNCOUT(); \
103 (*pp.linesync)(error_info.line, error_info.file); \
104 CACHEOUT(); \
107 else \
109 m = pp.hidden; \
110 pp.hidden = 0; \
111 st &= ~HIDDEN; \
112 while (m-- > 0) \
113 PUTCHR('\n'); \
116 else \
118 pp.hidden = 0; \
119 st &= ~HIDDEN; \
120 PUTCHR('\n'); \
124 } while (0)
126 #if POOL
129 * <wait.h> is poison here so pool moved to the end
132 static void poolstatus(void);
133 static void pool(void);
135 #endif
137 #else
140 * return next pp token
142 * NOTE: pp.token points to at least MAXTOKEN*2 chars and is
143 * truncated back to MAXTOKEN on EOB
146 #define PPCPP_T int
147 #define ppcpp pplex
149 #define START TOKEN
150 #define INMACRO(x) INTMACRO(x)
151 #define DOSTRIP() ((st&STRIP)||pp.level==1&&(st&(COMPILE|JOINING))==COMPILE&&!(pp.option&PRESERVE))
153 #define st pp.state
154 #define tp pp.token
155 #define xp &pp.token[MAXTOKEN]
157 #define BACKIN() (ip--)
158 #define BACKOUT() (op=pp.token)
159 #define CACHE() do{CACHEIN();CACHEOUT();}while(0)
160 #define CACHEIN() (ip=pp.in->nextchr)
161 #define CACHEOUT() (op=pp.token)
162 #define GETCHR() (*(unsigned char*)ip++)
163 #define LASTCHR() (*(ip-1))
164 #define PUTCHR(c) (*op++=(c))
165 #define SETCHR(c) (*op=(c))
166 #define SKIPIN() (ip++)
167 #define SYNC() do{SYNCIN();SYNCOUT();}while(0)
168 #define SYNCIN() (pp.in->nextchr=ip)
169 #define SYNCOUT() (pp.toknxt=op)
170 #define UNGETCHR(c) (*--ip=(c))
172 #endif
174 PPCPP_T
175 ppcpp(void)
177 register short* rp;
178 register char* ip;
179 register int state;
180 register int c;
181 register char* op;
182 char* bp;
183 int n;
184 int m;
185 int quot;
186 int quotquot;
187 int comdelim = 0;
188 int comstart = 0;
189 int comwarn = 0;
190 char* s;
191 struct ppsymbol* sym;
192 #if CPP
193 register long st;
194 char* tp;
195 char* xp;
196 char* sp = 0;
197 int qual = 0;
198 int spliced = 0;
199 #else
200 int qual;
201 #endif
203 #if CPP
204 #if POOL
205 fsm_pool:
206 #endif
207 #else
208 count(pplex);
209 #endif
210 error_info.indent++;
211 pp.level++;
212 CACHE();
213 #if !CPP
214 fsm_top:
215 qual = 0;
216 #endif
217 fsm_start:
218 #if CPP
219 PPCHECKOUTSP();
220 tp = op;
221 #endif
222 state = START;
223 fsm_begin:
224 bp = ip;
227 rp = fsm[state];
228 fsm_get:
229 while (!(state = rp[c = GETCHR()]));
230 fsm_next:
232 } while (state > 0);
233 if (((state = ~state) != S_COMMENT || pp.comment || c == '/' && !INCOMMENT(rp)) && (n = ip - bp - 1) > 0)
235 ip = bp;
236 #if CPP
237 if (op == tp && (st & (ADD|HIDDEN)) && !(st & PASSTHROUGH) && !(pp.option & PRESERVE))
238 switch (TERM(state))
240 case S_SHARP:
241 break;
242 case S_CHRB:
243 case S_NL:
244 if (*ip == '\n')
245 break;
246 /*FALLTHROUGH*/
247 default:
248 if ((pp.option & PRESERVE) && !(st & NEWLINE) && c != '\n')
249 break;
250 PPSYNCLINE();
251 tp = op;
252 break;
254 #endif
255 MEMCPY(op, ip, n);
256 ip++;
258 count(terminal);
259 #if CPP && (DEBUG & TRACE_debug)
260 hit[(state & SPLICE) ? (elementsof(hit) - 1) : (TERM(state) - TERMINAL)]++;
261 #endif
262 fsm_terminal:
263 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)));
264 switch (TERM(state))
267 #if !CPP
268 case S_CHR:
269 PUTCHR(c);
270 break;
271 #endif
273 case S_CHRB:
274 BACKIN();
275 #if CPP
276 st &= ~NEWLINE;
277 pp.in->flags |= IN_tokens;
278 count(token);
279 goto fsm_start;
280 #else
281 c = *tp;
282 break;
283 #endif
285 case S_COMMENT:
286 switch (c)
288 case '\n':
289 if (!INCOMMENTXX(rp))
291 qual = 0;
292 if (!comstart) comstart = comdelim = error_info.line;
293 error_info.line++;
294 if (pp.comment) PUTCHR(c);
295 else BACKOUT();
296 #if CPP
297 rp = fsm[COM2];
298 bp = ip;
299 goto fsm_get;
300 #else
301 state = COM2;
302 goto fsm_begin;
303 #endif
305 else if (comwarn < 0 && !(pp.mode & HOSTED))
306 error(1, "/* appears in // comment");
307 break;
308 case '*':
309 if (!comwarn && !(pp.mode & HOSTED))
311 if (INCOMMENTXX(rp)) comwarn = -1;
312 else if (comstart && comstart != error_info.line)
314 if (qual || comdelim < error_info.line - 1)
316 error(1, "/* appears in /* ... */ comment starting at line %d", comstart);
317 comwarn = 1;
319 else comdelim = error_info.line;
322 fsm_comment:
323 PUTCHR(c);
324 #if CPP
325 rp = fsm[INCOMMENTXX(rp) ? COM5 : COM3];
326 bp = ip;
327 goto fsm_get;
328 #else
329 state = INCOMMENTXX(rp) ? COM5 : COM3;
330 goto fsm_begin;
331 #endif
332 case '/':
333 if (!INCOMMENT(rp))
335 if (!(pp.mode & HOSTED))
336 error(1, "*/ appears outside of comment");
337 BACKIN();
338 #if CPP
339 st &= ~NEWLINE;
340 pp.in->flags |= IN_tokens;
341 count(token);
342 goto fsm_start;
343 #else
344 c = '*';
345 if (!pp.comment) PUTCHR(c);
346 goto fsm_token;
347 #endif
349 else if (INCOMMENTXX(rp))
351 if (!(pp.mode & HOSTED))
353 if (comwarn < 0) comwarn = 0;
354 else if (!comwarn)
356 comwarn = 1;
357 error(1, "*/ appears in // comment");
360 goto fsm_comment;
362 break;
363 case EOF:
364 BACKIN();
365 if (!(pp.mode & HOSTED))
367 if (comstart) error(2, "unterminated /* ... */ comment starting at line %d", comstart);
368 else if (INCOMMENTXX(rp)) error(2, "unterminated // ... comment");
369 else error(2, "unterminated /* ... */ comment");
371 break;
373 #if CPP
374 if (!pp.comment || sp)
376 #if COMPATIBLE
377 if (!(pp.state & COMPATIBILITY) || *bp == ' ' || *bp == '\t')
378 #endif
380 BACKOUT();
381 PUTCHR(' ');
382 tp = op;
385 else if (pp.in->type & IN_TOP)
386 #else
387 if (pp.comment && !(st & (COLLECTING|DIRECTIVE|JOINING)) && !(*pp.control & SKIP) && (pp.in->type & IN_TOP))
388 #endif
390 st &= ~HIDDEN;
391 pp.hidden = 0;
392 *(op - (c != '\n')) = 0;
393 m = (op - (c != '\n') - tp > MAXTOKEN - 6) ? (error_info.line - MAXHIDDEN) : 0;
394 BACKOUT();
395 SYNC();
396 while (*tp != '/') tp++;
397 (*pp.comment)(c == '\n' ? "//" : "/*", tp + 2, c == '\n' ? "" : (st & HEADER) ? "*/\n" : "*/", comstart ? comstart : error_info.line);
398 CACHE();
399 comstart = m;
401 if (comstart)
403 st |= HIDDEN;
404 pp.hidden += error_info.line - comstart;
405 comstart = 0;
407 qual = comwarn = comdelim = 0;
408 BACKOUT();
409 if (c == '\n') goto fsm_newline;
410 if ((st & PASSTHROUGH) && ((st & (HIDDEN|NEWLINE)) || *ip == '\n'))
412 if (*ip == '\n')
413 ip++;
414 goto fsm_newline;
416 #if COMPATIBLE
417 if ((st & (COMPATIBILITY|TRANSITION)) == COMPATIBILITY) st &= ~NEWLINE;
418 #endif
419 #if !CPP
420 if (pp.level > 1 && !(st & (NOSPACE|SKIPCONTROL)))
422 #if COMPATIBLE
423 c = ((st & (COMPATIBILITY|DEFINITION)) == ((COMPATIBILITY|DEFINITION))) ? '\t' : ' ';
424 #else
425 c = ' ';
426 #endif
427 goto fsm_return;
429 #endif
430 goto fsm_start;
432 case S_EOB:
433 if (c)
435 if (state = fsm[TERMINAL][INDEX(rp)+1])
436 goto fsm_terminal;
437 #if CPP
438 #if POOL
439 if (pp.pool.input)
441 BACKIN();
442 SYNC();
443 pool();
444 CACHE();
445 goto fsm_pool;
447 #endif
448 SYNCOUT();
449 return;
450 #else
451 BACKIN();
452 c = 0;
453 goto fsm_return;
454 #endif
457 register struct ppinstk* cur = pp.in;
458 register struct ppinstk* prv = pp.in->prev;
460 #if CPP
461 if (sp) op = sp;
462 #endif
463 switch (cur->type)
465 case IN_BUFFER:
466 case IN_INIT:
467 case IN_RESCAN:
468 #if CPP
469 if (prv)
470 #else
471 if (!(st & PASSEOF) && prv)
472 #endif
474 if (cur->type == IN_RESCAN || cur->type == IN_BUFFER)
476 fsm_pop:
477 #if PROTOTYPE
478 if (cur->flags & IN_prototype)
479 pppclose(cur->buffer + PPBAKSIZ);
480 else
481 #endif
482 if (!(cur->flags & IN_static))
483 free(cur->buffer);
485 while (pp.control-- != cur->control)
486 error(2, "#%s on line %d has no #%s", dirname(IF), GETIFLINE(pp.control+1), dirname(ENDIF));
487 st |= NEWLINE;
488 error_info.file = cur->file;
489 error_info.line = cur->line;
490 pp.hidden = 0;
491 #if CPP
492 spliced = 0;
493 #endif
494 if (cur->flags & IN_hosted)
496 pp.mode |= HOSTED;
497 pp.flags |= PP_hosted;
499 else
501 pp.mode &= ~HOSTED;
502 pp.flags &= ~PP_hosted;
504 #if !CPP && CATSTRINGS
505 if (st & JOINING) st |= HIDDEN|SYNCLINE;
506 else
507 #endif
509 st &= ~(HIDDEN|SYNCLINE);
510 switch (cur->type)
512 case IN_BUFFER:
513 case IN_INIT:
514 if (!prv->prev) break;
515 /*FALLTHROUGH*/
516 case IN_FILE:
517 case IN_RESCAN:
518 if (prv->type == IN_FILE || cur->type == IN_FILE && (prv->type == IN_RESCAN || prv->type == IN_MULTILINE))
520 if (pp.linesync && (cur->type != IN_RESCAN || (cur->flags & IN_sync)))
522 POP();
523 SYNCOUT();
524 (*pp.linesync)(error_info.line, error_info.file);
525 CACHEOUT();
526 prv = pp.in;
529 #if DEBUG
530 else if (!prv->prev)
532 /*UNDENT*/
533 c = 0;
534 #if DEBUG & TRACE_count
535 if (pp.test & TEST_count)
537 c = 1;
538 sfprintf(sfstderr, "\n");
539 sfprintf(sfstderr, "%7d: pplex calls\n", pp.counter.pplex);
540 sfprintf(sfstderr, "%7d: terminal states\n", pp.counter.terminal);
541 sfprintf(sfstderr, "%7d: emitted tokens\n", pp.counter.token);
542 sfprintf(sfstderr, "%7d: input stream pushes\n", pp.counter.push);
543 sfprintf(sfstderr, "%7d: macro candidates\n", pp.counter.candidate);
544 sfprintf(sfstderr, "%7d: macro expansions\n", pp.counter.macro);
545 sfprintf(sfstderr, "%7d: function macros\n", pp.counter.function);
547 #endif
548 #if CPP && (DEBUG & TRACE_debug)
549 if (pp.test & TEST_hit)
551 c = 1;
552 sfprintf(sfstderr, "\n");
553 if (hit[elementsof(hit) - 1])
554 sfprintf(sfstderr, "%7d: SPLICE\n", hit[elementsof(hit) - 1]);
555 for (n = 0; n < elementsof(hit) - 1; n++)
556 if (hit[n])
557 sfprintf(sfstderr, "%7d: %s\n", hit[n], pplexstr(TERMINAL + n));
559 #endif
560 if (pp.test & (TEST_hashcount|TEST_hashdump))
562 c = 1;
563 sfprintf(sfstderr, "\n");
564 hashdump(NiL, (pp.test & TEST_hashdump) ? HASH_BUCKET : 0);
566 if (c) sfprintf(sfstderr, "\n");
567 /*INDENT*/
569 #endif
570 break;
573 #if CHECKPOINT
574 if (cur->index)
576 SYNCOUT();
577 cur->index->end = ppoffset();
578 cur->index = 0;
579 CACHEOUT();
581 #endif
582 POP();
583 bp = ip;
584 tp = op;
585 goto fsm_get;
587 c = EOF;
588 break;
589 case IN_COPY:
590 if (prv)
592 error_info.line = cur->line;
593 if (!(prv->symbol->flags & SYM_MULTILINE))
594 prv->symbol->flags |= SYM_DISABLED;
595 POP();
596 bp = ip;
597 goto fsm_get;
599 c = EOF;
600 break;
601 case IN_EXPAND:
602 if (prv)
604 error_info.line = cur->line;
605 free(cur->buffer);
606 POP();
607 bp = ip;
608 goto fsm_get;
610 c = EOF;
611 break;
612 case IN_FILE:
613 FGET(c, c, tp, xp);
614 if (c == EOB)
616 #if CPP
617 if ((st & (NOTEXT|HIDDEN)) == HIDDEN && LASTOUT() != '\n')
618 PUTCHR('\n');
619 if (prv)
620 #else
621 if (st & EOF2NL)
623 st &= ~EOF2NL;
624 *(ip - 1) = c = '\n';
626 else if (!(st & (FILEPOP|PASSEOF)) && prv)
627 #endif
629 if (!(cur->flags & IN_newline))
631 cur->flags |= IN_newline;
632 if ((pp.mode & (HOSTED|PEDANTIC)) == PEDANTIC && LASTCHR() != '\f' && LASTCHR() != CC_sub)
633 error(1, "file does not end with %s", pptokchr('\n'));
634 *(ip - 1) = c = '\n';
636 else
638 if (!(cur->flags & (IN_noguard|IN_tokens)) && cur->symbol)
639 ppmultiple(ppsetfile(error_info.file), cur->symbol);
640 if (cur->fd >= 0)
641 close(cur->fd);
642 if (pp.incref && !(pp.mode & INIT))
644 SYNCOUT();
645 (*pp.incref)(error_info.file, cur->file, error_info.line - 1, PP_SYNC_POP);
646 CACHEOUT();
648 goto fsm_pop;
651 else
652 c = EOF;
654 break;
655 case IN_MACRO:
656 case IN_MULTILINE:
657 #if !CPP
658 if (!(st & PASSEOF))
659 #endif
660 #if COMPATIBLE
661 if (prv && (!INMACRO(rp) || (st & (COMPATIBILITY|TRANSITION)) == COMPATIBILITY && ppismac(*prv->nextchr)))
662 #else
663 if (prv && !INMACRO(rp))
664 #endif
666 if (cur->type == IN_MULTILINE)
668 while (pp.control-- != cur->control)
669 error(2, "#%s on line %d has no #%s", dirname(IF), GETIFLINE(pp.control+1), dirname(ENDIF));
670 free(cur->buffer);
671 error_info.file = cur->file;
672 error_info.line = cur->line;
673 if (pp.linesync)
675 SYNCOUT();
676 (*pp.linesync)(error_info.line, error_info.file);
677 CACHEOUT();
680 cur->symbol->flags &= ~SYM_DISABLED;
681 if (cur->symbol->flags & SYM_FUNCTION)
682 popframe(pp.macp);
683 POP();
684 #if CPP
685 if (!(st & COMPATIBILITY) && ppisidig(*(op - 1)) && ppisidig(*ip)) UNGETCHR(' ');
686 #endif
687 bp = ip;
688 goto fsm_get;
690 c = EOF;
691 break;
692 case IN_QUOTE:
693 if (prv)
695 error_info.line = cur->line;
696 st &= ~(ESCAPE|QUOTE);
697 POP();
698 c = '"';
700 else c = EOF;
701 break;
702 case IN_SQUOTE:
703 if (prv)
705 error_info.line = cur->line;
706 st &= ~(ESCAPE|SQUOTE);
707 POP();
708 c = '\'';
710 else c = EOF;
711 break;
712 case IN_STRING:
713 #if CPP
714 if (prv)
715 #else
716 if (!(st & PASSEOF) && !(cur->flags & IN_expand) && prv)
717 #endif
719 if (cur->flags & IN_disable) st |= DISABLE;
720 else st &= ~DISABLE;
721 POP();
722 bp = ip;
723 goto fsm_get;
725 c = EOF;
726 break;
727 default:
728 c = EOF;
729 break;
732 bp = ip - 1;
733 if (state = rp[c]) goto fsm_next;
734 goto fsm_get;
736 #if !CPP
737 case S_HUH:
738 if (INOPSPACE(rp))
740 if (c == '=')
742 #if PROTOTYPE
743 if (pp.in->flags & IN_prototype) PUTCHR(c);
744 else
746 #endif
747 while (*(op - 1) == ' ' || *(op - 1) == '\t') op--;
748 PUTCHR(c);
749 if (st & (STRICT|WARN)) error(1, "%-*.*s: space ignored in operator", op - tp, op - tp, tp);
750 #if PROTOTYPE
752 #endif
753 switch (*tp)
755 case '/':
756 c = T_DIVEQ;
757 break;
758 case '%':
759 c = T_MODEQ;
760 break;
761 case '&':
762 c = T_ANDEQ;
763 break;
764 case '*':
765 c = T_MPYEQ;
766 break;
767 case '+':
768 c = T_ADDEQ;
769 break;
770 case '-':
771 c = T_SUBEQ;
772 break;
773 case '^':
774 c = T_XOREQ;
775 break;
776 case '|':
777 c = T_OREQ;
778 break;
779 case '<':
780 c = T_LSHIFTEQ;
781 break;
782 case '>':
783 c = T_RSHIFTEQ;
784 break;
787 else
789 BACKIN();
790 switch (c = *tp)
792 case '<':
793 c = T_LSHIFT;
794 break;
795 case '>':
796 c = T_RSHIFT;
797 break;
801 else if (pp.level > 1 || (pp.option & PRESERVE)) PUTCHR(c);
802 else if (tp == op)
804 if (pp.in->type != IN_BUFFER)
806 if (!(pp.option & ALLPOSSIBLE))
807 error(1, "%s: invalid character ignored", pptokchr(c));
808 goto fsm_top;
810 PUTCHR(c);
812 else if (*tp == ':')
814 PUTCHR(c);
815 if (c == '=') error(2, "real programmers use =");
816 else c = '+';
818 else
820 BACKIN();
821 c = *tp;
823 break;
824 #endif
826 case S_QUAL:
827 if ((state = NEXT(state)) != LIT1)
829 rp = fsm[state];
830 bp = ip;
831 #if CPP
832 qual = 1;
833 #if COMPATIBLE
834 if (!(st & COMPATIBILITY) || c != 'u' && c != 'U')
835 #endif
836 PUTCHR(c);
837 #else
838 switch (c)
840 case 'f':
841 case 'F':
842 qual |= N_FLOAT;
843 #if COMPATIBLE
844 if (!(st & COMPATIBILITY))
845 #endif
846 PUTCHR(c);
847 break;
848 case 'l':
849 case 'L':
850 qual |= N_LONG;
851 PUTCHR(c);
852 break;
853 case 'u':
854 case 'U':
855 qual |= N_UNSIGNED;
856 #if COMPATIBLE
857 if (!(st & COMPATIBILITY))
858 #endif
859 PUTCHR(c);
860 break;
861 default:
862 PUTCHR(c);
863 break;
865 #endif
866 goto fsm_get;
868 #if !CPP
869 qual |= N_WIDE;
870 if (DOSTRIP()) BACKOUT();
871 #endif
872 /*FALLTHROUGH*/
874 case S_LITBEG:
875 #if CPP
876 quot = c;
877 rp = fsm[LIT1];
878 if (op == tp)
880 PPSYNCLINE();
881 tp = op;
883 #else
884 if ((quot = c) == '<')
886 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)
888 PUTCHR(c);
889 bp = ip;
890 rp = fsm[LT1];
891 goto fsm_get;
893 quot = '>';
894 rp = fsm[HDR1];
896 else rp = fsm[LIT1];
897 if (!DOSTRIP())
898 #endif
899 PUTCHR(c);
900 bp = ip;
901 goto fsm_get;
903 case S_LITEND:
904 n = 1;
905 if (c != quot)
907 if (c != '\n' && c != EOF)
909 if (st & (QUOTE|SQUOTE))
911 if (!(st & ESCAPE))
913 st |= ESCAPE;
914 quotquot = c;
916 else if (c == quotquot) st &= ~ESCAPE;
918 PUTCHR(c);
919 bp = ip;
920 goto fsm_get;
922 #if CPP
923 if ((st & PASSTHROUGH) || (pp.option & PRESERVE))
925 if (c == '\n') goto fsm_newline;
926 bp = ip;
927 goto fsm_start;
929 #endif
930 m = (st & SKIPCONTROL) && (pp.mode & HOSTED) ? -1 : 1;
931 if (c == '\n' && quot == '\'' && (pp.option & STRINGSPAN)) n = 0;
932 else
933 #if COMPATIBLE && !CPP
934 if ((st & (COMPATIBILITY|DEFINITION)) != (COMPATIBILITY|DEFINITION))
935 #endif
937 switch (quot)
939 case '"':
940 if (c == '\n')
942 if (!(pp.option & STRINGSPAN) || (st & (COMPATIBILITY|STRICT)) == STRICT)
943 error(m, "%s in string", pptokchr(c));
944 error_info.line++;
945 if (!(pp.option & STRINGSPAN))
947 PUTCHR('\\');
948 c = 'n';
950 else if (pp.option & STRINGSPLIT)
952 PUTCHR('\\');
953 PUTCHR('n');
954 PUTCHR('"');
955 PUTCHR('\n');
956 c = '"';
958 PUTCHR(c);
959 bp = ip;
960 goto fsm_get;
962 error(m, "%s in string", pptokchr(c));
963 c = '\n';
964 break;
965 case '\'':
966 if (!(st & DIRECTIVE) || !(pp.mode & (HOSTED|RELAX)))
967 error(m, "%s in character constant", pptokchr(c));
968 break;
969 case '>':
970 error(m, "%s in header constant", pptokchr(c));
971 break;
972 default:
973 error(m, "%s in %c quote", pptokchr(c), quot);
974 break;
976 #if !CPP
977 if (!DOSTRIP())
978 #endif
979 PUTCHR(quot);
981 if (c == '\n')
983 UNGETCHR(c);
984 c = quot;
987 else if (st & (SQUOTE|QUOTE))
989 if (!(st & ESCAPE))
991 st |= ESCAPE;
992 quotquot = c;
994 else if (c == quotquot) st &= ~ESCAPE;
995 PUTCHR('\\');
996 PUTCHR(c);
997 bp = ip;
998 goto fsm_get;
1000 #if CPP
1001 else PUTCHR(c);
1002 #else
1003 else if (!DOSTRIP()) PUTCHR(c);
1004 #endif
1005 #if CATSTRINGS
1006 #if CPP
1007 if (c == '"' && !(st & (COLLECTING|NOTEXT|PASSTHROUGH|SKIPCONTROL)) && (pp.mode & CATLITERAL))
1008 #else
1009 if (c == '"' && pp.level == 1 && !(st & (COLLECTING|JOINING|NOTEXT|SKIPCONTROL)) && (pp.mode & CATLITERAL))
1010 #endif
1012 char* pptoken;
1013 long ppstate;
1015 pptoken = pp.token;
1016 pp.token = pp.catbuf;
1017 *pp.token++ = 0;
1018 ppstate = (st & STRIP);
1019 if (DOSTRIP())
1020 ppstate |= ADD|QUOTE;
1021 st |= JOINING;
1022 st &= ~(NEWLINE|STRIP);
1025 * revert to the top level since string
1026 * concatenation crosses file boundaries
1027 * (allowing intervening directives)
1030 pp.level = 0;
1031 SYNCIN();
1032 m = n = 0;
1033 for (;;)
1035 switch (c = pplex())
1037 case '\n':
1038 m++;
1039 continue;
1040 case ' ':
1041 *pp.catbuf = ' ';
1042 continue;
1043 case T_WSTRING:
1044 #if !CPP
1045 qual = N_WIDE;
1046 #endif
1047 if (ppstate & ADD)
1048 ppstate &= ~ADD;
1049 else if (m == n || !(st & SPACEOUT))
1050 op--;
1051 else
1053 n = m;
1054 *(op - 1) = '\\';
1055 *op++ = '\n';
1057 STRCOPY(op, pp.token + 2 + (*pp.token == ' '), s);
1058 continue;
1059 case T_STRING:
1060 if (ppstate & ADD)
1061 ppstate &= ~ADD;
1062 else if (m == n || !(st & SPACEOUT))
1063 op--;
1064 else
1066 n = m;
1067 *(op - 1) = '\\';
1068 *op++ = '\n';
1070 STRCOPY(op, pp.token + 1 + (*pp.token == ' '), s);
1071 continue;
1072 case 0:
1073 m = error_info.line ? (error_info.line - 1) : 0;
1074 *pp.token = 0;
1075 /*FALLTHROUGH*/
1076 default:
1077 if (m)
1079 if (--m)
1081 pp.state |= HIDDEN|SYNCLINE;
1082 pp.hidden += m;
1084 #if COMPATIBLE
1085 if ((st & COMPATIBILITY) && c == '#' && *(pp.token - 1))
1087 *(pp.token + 3) = *(pp.token + 2);
1088 *(pp.token + 2) = *(pp.token + 1);
1089 *(pp.token + 1) = *pp.token;
1090 *pp.token = *(pp.token - 1);
1092 error_info.line--;
1093 *--pp.token = '\n';
1094 #endif
1096 else if (*(pp.token - 1))
1097 pp.token--;
1098 if (ppisidig(*pp.token))
1099 *op++ = ' ';
1100 if (pp.in->type == IN_MACRO && (s = strchr(pp.token, MARK)) && !*(s + 1))
1102 *(s + 1) = MARK;
1103 *(s + 2) = 0;
1105 PUSH_STRING(pp.token);
1106 pp.state &= ~(JOINING|NEWLINE);
1107 pp.state |= ppstate & ~(ADD|QUOTE);
1108 if ((ppstate & (ADD|QUOTE)) == QUOTE)
1109 op--;
1110 break;
1112 break;
1114 pp.token = pptoken;
1115 CACHEIN();
1116 pp.level = 1;
1117 #if !CPP
1118 c = T_STRING | qual;
1119 break;
1120 #endif
1122 #endif
1123 #if CPP
1124 if (n && !(st & (PASSTHROUGH|SKIPCONTROL|NOTEXT)) && c == '\'' && (op - tp) <= 2 && !(pp.mode & (HOSTED|RELAX)))
1125 error(1, "empty character constant");
1126 if (pp.option & PRESERVE)
1127 st &= ~ESCAPE;
1128 else
1129 st &= ~(ESCAPE|NEWLINE);
1130 pp.in->flags |= IN_tokens;
1131 count(token);
1132 goto fsm_start;
1133 #else
1134 st &= ~ESCAPE;
1135 switch (quot)
1137 case '\'':
1138 if (n && !(st & NOTEXT) && (op - tp) <= (DOSTRIP() ? 0 : 2) && !(pp.mode & (HOSTED|RELAX)))
1139 error(1, "empty character constant");
1140 c = T_CHARCONST | qual;
1141 break;
1142 case '>':
1143 c = T_HEADER;
1144 break;
1145 default:
1146 if (c == quot)
1147 c = T_STRING | qual;
1148 break;
1150 break;
1151 #endif
1153 case S_LITESC:
1154 if (st & (COLLECTING|DIRECTIVE|QUOTE|SQUOTE))
1156 if (st & ESCAPE)
1158 PUTCHR('\\');
1159 if (c == quot) PUTCHR('\\');
1161 PUTCHR(c);
1163 #if CPP
1164 else if (st & PASSTHROUGH) PUTCHR(c);
1165 #endif
1166 else if (pp.option & PRESERVE) PUTCHR(c);
1167 else switch (c)
1169 case 'b':
1170 case 'f':
1171 case 'n':
1172 case 'r':
1173 case 't':
1174 case '\\':
1175 case '\'':
1176 case '"':
1177 case '?':
1178 PUTCHR(c);
1179 break;
1180 #if COMPATIBLE
1181 case '8':
1182 case '9':
1183 if (!(st & COMPATIBILITY)) goto unknown;
1184 if (st & STRICT) error(1, "%c: invalid character in octal character escape", c);
1185 /*FALLTHROUGH*/
1186 #endif
1187 case '0':
1188 case '1':
1189 case '2':
1190 case '3':
1191 case '4':
1192 case '5':
1193 case '6':
1194 case '7':
1195 n = c - '0';
1196 for (m = 0; m < 2; m++)
1198 GET(c, c, tp, xp);
1199 switch (c)
1201 #if COMPATIBLE
1202 case '8':
1203 case '9':
1204 if (!(st & COMPATIBILITY))
1206 UNGETCHR(c);
1207 break;
1209 if (st & STRICT) error(1, "%c: invalid character in octal character escape", c);
1210 /*FALLTHROUGH*/
1211 #endif
1212 case '0':
1213 case '1':
1214 case '2':
1215 case '3':
1216 case '4':
1217 case '5':
1218 case '6':
1219 case '7':
1220 n = (n << 3) + c - '0';
1221 continue;
1222 default:
1223 UNGETCHR(c);
1224 break;
1226 break;
1228 if (n & ~0777) error(1, "octal character constant too large");
1229 goto octal;
1230 case 'a':
1231 if (pp.option & MODERN)
1233 PUTCHR(c);
1234 break;
1236 #if COMPATIBLE
1237 if (st & COMPATIBILITY) goto unknown;
1238 #endif
1239 n = CC_bel;
1240 goto octal;
1241 case 'v':
1242 if (pp.option & MODERN)
1244 PUTCHR(c);
1245 break;
1247 n = CC_vt;
1248 goto octal;
1249 case 'E':
1250 if (st & (COMPATIBILITY|STRICT)) goto unknown;
1251 n = CC_esc;
1252 goto octal;
1253 case 'x':
1254 #if COMPATIBLE
1255 if (st & COMPATIBILITY) goto unknown;
1256 #endif
1257 n = 0;
1258 for (m = 0; m < 3; m++)
1260 GET(c, c, tp, xp);
1261 switch (c)
1263 case '0':
1264 case '1':
1265 case '2':
1266 case '3':
1267 case '4':
1268 case '5':
1269 case '6':
1270 case '7':
1271 case '8':
1272 case '9':
1273 n = (n << 4) + c - '0';
1274 continue;
1275 case 'a':
1276 case 'b':
1277 case 'c':
1278 case 'd':
1279 case 'e':
1280 case 'f':
1281 n = (n << 4) + c - 'a' + 10;
1282 continue;
1283 case 'A':
1284 case 'B':
1285 case 'C':
1286 case 'D':
1287 case 'E':
1288 case 'F':
1289 n = (n << 4) + c - 'A' + 10;
1290 continue;
1291 default:
1292 if (!m) error(1, "\\x%c: invalid character in hexadecimal character constant", c);
1293 UNGETCHR(c);
1294 break;
1296 break;
1298 if (n & ~0777) error(1, "hexadecimal character constant too large");
1299 octal:
1300 PUTCHR(((n >> 6) & 07) + '0');
1301 PUTCHR(((n >> 3) & 07) + '0');
1302 PUTCHR((n & 07) + '0');
1303 break;
1304 default:
1305 unknown:
1306 if (st & (STRICT|WARN)) error(1, "\\%c: non-standard character constant", c);
1307 PUTCHR(c);
1308 break;
1310 state = LIT1;
1311 goto fsm_begin;
1313 case S_MACRO:
1314 BACKIN();
1315 #if CPP
1316 if (st & (DISABLE|SKIPCONTROL|SKIPMACRO))
1318 if (st & SKIPMACRO)
1319 pp.mode |= MARKMACRO;
1320 st &= ~(NEWLINE|SKIPMACRO);
1321 pp.in->flags |= IN_tokens;
1322 count(token);
1323 goto fsm_start;
1325 count(candidate);
1326 SETCHR(0);
1327 switch (state = INDEX(rp))
1329 case HIT0:
1330 tp = op - 1;
1331 break;
1332 case HITN:
1333 bp = tp;
1334 tp = op - ((pp.truncate && pp.truncate < (HITN - HIT0)) ? (pp.truncate - 1) : (HITN - HIT0));
1335 while (tp > bp && ppisidig(*(tp - 1))) tp--;
1336 break;
1337 default:
1338 bp = tp;
1339 if ((tp = op - (state - HIT0)) > bp && *(tp - 1) == 'L') tp--;
1340 break;
1342 if (sym = ppsymref(pp.symtab, tp))
1344 SYNCIN();
1345 n = ppcall(sym, 0);
1346 CACHEIN();
1347 if (n >= 0)
1349 BACKOUT();
1350 if (!n)
1352 if (sp) op = sp;
1353 else
1355 s = ip;
1356 ip = sym->macro->value;
1357 c = sym->macro->size;
1358 while (c > 0)
1360 if (op + c < xp + PPBUFSIZ) n = c;
1361 else n = xp + PPBUFSIZ - op;
1362 MEMCPY(op, ip, n);
1363 c -= n;
1364 PPCHECKOUT();
1366 ip = s;
1369 else if ((sym->flags & SYM_MULTILINE) && pp.linesync)
1371 SYNCOUT();
1372 if (!(state & NEWLINE))
1373 ppputchar('\n');
1374 (*pp.linesync)(error_info.line, error_info.file);
1375 CACHEOUT();
1379 pp.in->flags |= IN_tokens;
1380 goto fsm_start;
1381 #else
1382 if (st & (COLLECTING|DEFINITION|DISABLE|SKIPCONTROL|SKIPMACRO))
1384 if (st & SKIPMACRO)
1385 pp.mode |= MARKMACRO;
1386 st &= ~(NEWLINE|NOEXPAND|SKIPMACRO);
1387 c = T_ID;
1388 if (pp.level == 1)
1390 pp.in->flags |= IN_tokens;
1391 if (st & NOTEXT)
1393 BACKOUT();
1394 goto fsm_top;
1396 if (st & COMPILE)
1398 SETCHR(0);
1399 if (pp.truncate && (op - tp) > pp.truncate) tp[pp.truncate] = 0;
1400 sym = (pp.option & NOHASH) ? ppsymref(pp.symtab, tp) : ppsymset(pp.symtab, tp);
1401 fsm_noise:
1402 if (pp.symbol = sym)
1404 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)))
1406 c = ((struct ppsymkey*)sym)->lex;
1407 /*UNDENT*/
1409 #define ADVANCE() do{if(pp.toknxt<op)pp.token=pp.toknxt;}while(0)
1411 #define NOISE_BRACE 01
1412 #define NOISE_NOSPACEOUT 02
1413 #define NOISE_PAREN 04
1415 if ((pp.option & NOISE) && ppisnoise(c))
1417 if (c != T_NOISE)
1419 int p;
1420 int f;
1421 char* pptoken;
1422 PPCOMMENT ppcomment;
1424 SYNCIN();
1425 pp.toknxt = op;
1426 f = 0;
1427 if (!(pp.state & SPACEOUT))
1429 pp.state |= SPACEOUT;
1430 f |= NOISE_NOSPACEOUT;
1432 ppcomment = pp.comment;
1433 pp.comment = 0;
1434 op = (pptoken = tp) + MAXTOKEN;
1435 switch (c)
1437 case T_X_GROUP:
1438 m = p = 0;
1439 quot = 1;
1440 for (;;)
1442 ADVANCE();
1443 switch (c = pplex())
1445 case '(':
1446 case '{':
1447 if (!p)
1449 if (c == '(')
1451 if (f & NOISE_PAREN)
1453 ungetchr(c);
1454 *--pp.toknxt = 0;
1455 break;
1457 f |= NOISE_PAREN;
1458 p = ')';
1460 else
1462 f |= NOISE_BRACE|NOISE_PAREN;
1463 p = '}';
1465 n = 1;
1466 m = c;
1468 else if (c == m) n++;
1469 quot = 0;
1470 continue;
1471 case ')':
1472 case '}':
1473 if (c == p && --n <= 0)
1475 if (c == '}') break;
1476 m = '\n';
1477 p = 0;
1479 quot = 0;
1480 continue;
1481 case ' ':
1482 continue;
1483 case '\n':
1484 error_info.line++;
1485 if (!m) m = '\n';
1486 continue;
1487 case 0:
1488 break;
1489 case T_ID:
1490 if (quot) continue;
1491 /*FALLTHROUGH*/
1492 default:
1493 if (m == '\n')
1496 * NOTE: token expanded again
1499 s = pp.toknxt;
1500 while (s > pp.token) ungetchr(*--s);
1501 *(pp.toknxt = s) = 0;
1502 break;
1504 continue;
1506 break;
1508 break;
1509 case T_X_LINE:
1510 for (;;)
1512 ADVANCE();
1513 switch (pplex())
1515 case 0:
1516 break;
1517 case '\n':
1518 error_info.line++;
1519 break;
1520 default:
1521 continue;
1523 break;
1525 break;
1526 case T_X_STATEMENT:
1527 for (;;)
1529 ADVANCE();
1530 switch (pplex())
1532 case 0:
1533 break;
1534 case ';':
1535 ungetchr(';');
1536 *(pp.toknxt = pp.token) = 0;
1537 break;
1538 default:
1539 continue;
1541 break;
1543 break;
1545 pp.comment = ppcomment;
1546 if (f & NOISE_NOSPACEOUT)
1547 pp.state &= ~SPACEOUT;
1548 CACHEIN();
1549 tp = pptoken;
1550 op = pp.toknxt;
1551 c = T_NOISES;
1553 if (pp.option & NOISEFILTER)
1555 BACKOUT();
1556 goto fsm_top;
1560 /*INDENT*/
1562 else if ((pp.option & NOISE) && c == T_ID && strneq(tp, "__builtin_", 10))
1564 hashlook(pp.symtab, tp, HASH_DELETE, NiL);
1565 pp.symbol = sym = (struct ppsymbol*)ppkeyset(pp.symtab, tp);
1566 sym->flags |= SYM_KEYWORD;
1567 c = ((struct ppsymkey*)sym)->lex = T_BUILTIN;
1571 goto fsm_symbol;
1573 goto fsm_check;
1575 if (pp.level == 1)
1577 st &= ~(NEWLINE|PASSEOF);
1578 pp.in->flags |= IN_tokens;
1580 else st &= ~PASSEOF;
1581 count(candidate);
1582 SETCHR(0);
1583 if (sym = ppsymref(pp.symtab, tp))
1585 SYNCIN();
1586 c = ppcall(sym, 1);
1587 CACHEIN();
1588 if (c >= 0)
1590 BACKOUT();
1591 if ((sym->flags & SYM_MULTILINE) && pp.linesync)
1593 SYNCOUT();
1594 (*pp.linesync)(error_info.line, error_info.file);
1595 CACHEOUT();
1597 goto fsm_top;
1600 c = T_ID;
1601 if (pp.level == 1)
1603 if (st & NOTEXT)
1605 BACKOUT();
1606 goto fsm_top;
1608 if (st & COMPILE)
1610 if (pp.truncate && (op - tp) > pp.truncate)
1612 tp[pp.truncate] = 0;
1613 sym = 0;
1615 if (!sym)
1617 if (!(pp.option & NOHASH)) sym = ppsymset(pp.symtab, tp);
1618 else if (!(sym = ppsymref(pp.symtab, tp))) goto fsm_symbol;
1620 goto fsm_noise;
1622 goto fsm_symbol;
1624 goto fsm_check;
1625 #endif
1627 case S_SHARP:
1628 if (c == '(')
1630 pp.in->flags |= IN_tokens;
1631 if ((st & STRICT) && pp.in->type != IN_MACRO && pp.in->type != IN_MULTILINE)
1633 if (!(pp.mode & HOSTED)) error(1, "non-standard reference to #(...)");
1634 if (st & STRICT)
1636 PUTCHR(c);
1637 #if CPP
1638 st &= ~NEWLINE;
1639 count(token);
1640 goto fsm_start;
1641 #else
1642 break;
1643 #endif
1646 if (st & (COLLECTING|DEFINITION|DISABLE|SKIPCONTROL))
1648 PUTCHR(c);
1649 #if CPP
1650 st &= ~NEWLINE;
1651 count(token);
1652 goto fsm_start;
1653 #else
1654 st &= ~NOEXPAND;
1655 break;
1656 #endif
1658 op--;
1659 SYNC();
1660 ppbuiltin();
1661 CACHE();
1662 #if CPP
1663 count(token);
1664 goto fsm_start;
1665 #else
1666 goto fsm_top;
1667 #endif
1669 BACKIN();
1670 #if CPP
1671 if (!(st & NEWLINE) || !(pp.in->type & IN_TOP))
1673 fsm_nondirective:
1674 st &= ~NEWLINE;
1675 pp.in->flags |= IN_tokens;
1676 count(token);
1677 goto fsm_start;
1679 if (*(s = tp) != '#')
1681 #if COMPATIBLE
1682 if ((st & (COMPATIBILITY|TRANSITION)) == COMPATIBILITY) goto fsm_nondirective;
1683 #endif
1684 while (*s == ' ' || *s == '\t') s++;
1685 if (*s != '#') goto fsm_nondirective;
1687 BACKOUT();
1688 #else
1689 if (!(st & NEWLINE) || (st & DEFINITION) || !(pp.in->type & IN_TOP))
1691 if (c == '#')
1693 SKIPIN();
1694 if (!(st & DEFINITION))
1695 PUTCHR(c);
1696 c = T_TOKCAT;
1698 else if (pp.level == 1 && !(st & (JOINING|SPACEOUT)) && !(pp.option & PRESERVE))
1700 char* pptoken;
1701 char* oop;
1702 PPCOMMENT ppcomment;
1704 SYNCIN();
1705 pp.toknxt = oop = op;
1706 pp.state |= SPACEOUT;
1707 ppcomment = pp.comment;
1708 pp.comment = 0;
1709 op = (pptoken = tp) + MAXTOKEN;
1710 for (;;)
1712 ADVANCE();
1713 switch (pplex())
1715 case 0:
1716 break;
1717 case '\n':
1718 error_info.line++;
1719 break;
1720 default:
1721 continue;
1723 break;
1725 pp.comment = ppcomment;
1726 pp.state &= ~SPACEOUT;
1727 CACHEIN();
1728 tp = pptoken;
1729 *--op = 0;
1730 op = oop;
1731 if (pp.pragma && !(st & NOTEXT))
1733 *s = 0;
1734 SYNC();
1735 (*pp.pragma)(NiL, NiL, NiL, tp, 1);
1736 CACHE();
1738 if (!c) BACKIN();
1739 goto fsm_top;
1741 else c = '#';
1742 break;
1744 if ((st & (COLLECTING|STRICT)) == (COLLECTING|STRICT))
1745 error(1, "directives in macro call arguments are not portable");
1746 #endif
1747 if (c == '#' && pp.in->type == IN_RESCAN)
1750 * pass line to pp.pragma VERBATIM
1753 SKIPIN();
1754 s = pp.valbuf;
1755 while ((c = GETCHR()) && c != '\n')
1756 if ((*s++ = c) == MARK) SKIPIN();
1757 if (pp.pragma && !(st & NOTEXT))
1759 *s = 0;
1760 SYNC();
1761 (*pp.pragma)(NiL, NiL, NiL, pp.valbuf, 1);
1762 CACHE();
1764 if (!c) BACKIN();
1765 #if CPP
1766 goto fsm_start;
1767 #else
1768 goto fsm_top;
1769 #endif
1771 SYNC();
1772 ppcontrol();
1773 CACHE();
1774 #if CPP
1775 if (st & (NOTEXT|SKIPCONTROL))
1777 if (!sp)
1779 PPCHECKOUTTP();
1780 sp = tp;
1783 else if (sp)
1785 tp = op = sp;
1786 sp = 0;
1788 goto fsm_start;
1789 #else
1790 goto fsm_top;
1791 #endif
1793 case S_NL:
1794 #if CPP
1795 if (op == tp && !(st & JOINING) && pp.in->type == IN_FILE && !(pp.option & PRESERVE))
1797 st |= NEWLINE|HIDDEN;
1798 pp.hidden++;
1799 error_info.line++;
1800 goto fsm_start;
1802 #endif
1803 fsm_newline:
1804 #if CPP
1805 if (sp)
1806 op = sp;
1807 else if (!(pp.in->flags & IN_noguard))
1809 while (tp < op)
1810 if ((c = *tp++) != ' ' && c != '\t')
1812 pp.in->flags |= IN_tokens;
1813 break;
1815 c = '\n';
1817 st |= NEWLINE;
1818 error_info.line++;
1819 if (*ip == '\n' && *(ip + 1) != '\n' && !pp.macref && !(st & (ADD|HIDDEN)))
1821 ip++;
1822 PUTCHR('\n');
1823 error_info.line++;
1825 if ((st & NOTEXT) && ((pp.mode & FILEDEPS) || (pp.option & (DEFINITIONS|PREDEFINITIONS))))
1826 BACKOUT();
1827 else
1829 debug((-5, "token[%d] %03o = %s [line=%d]", pp.level, c, pptokchr(c), error_info.line));
1830 PUTCHR('\n');
1831 PPSYNCLINE();
1832 if (sp)
1834 PPCHECKOUT();
1835 sp = op;
1838 goto fsm_start;
1839 #else
1840 st |= NEWLINE;
1841 if (pp.level == 1)
1843 error_info.line++;
1844 if (!(st & (JOINING|SPACEOUT)))
1846 debug((-5, "token[%d] %03o = %s [line=%d]", pp.level, c, pptokchr(c), error_info.line));
1847 BACKOUT();
1848 goto fsm_top;
1851 BACKOUT();
1852 if (st & SKIPCONTROL)
1854 error_info.line++;
1855 st |= HIDDEN;
1856 pp.hidden++;
1857 goto fsm_start;
1859 PUTCHR(c = '\n');
1860 goto fsm_return;
1861 #endif
1863 #if !CPP
1864 case S_TOK:
1865 PUTCHR(c);
1866 c = TYPE(state) | qual;
1867 break;
1869 case S_TOKB:
1870 BACKIN();
1871 c = TYPE(state) | qual;
1872 break;
1873 #endif
1875 case S_VS:
1876 PUTCHR(c);
1877 #if !CPP
1878 if (st & NOVERTICAL)
1880 error(1, "%s invalid in directives", pptokchr(c));
1881 st &= ~NOVERTICAL;
1883 #endif
1884 #if COMPATIBLE
1885 if (st & COMPATIBILITY) st |= NEWLINE;
1886 #endif
1887 #if CPP
1888 if (!(pp.in->flags & IN_noguard))
1889 while (tp < op)
1890 if ((c = *tp++) != ' ' && c != '\t')
1892 pp.in->flags |= IN_tokens;
1893 break;
1895 goto fsm_start;
1896 #else
1897 bp = ip;
1898 rp = fsm[WS1];
1899 goto fsm_get;
1900 #endif
1902 #if !CPP
1903 case S_WS:
1904 #if COMPATIBLE
1905 if ((st & (COMPATIBILITY|TRANSITION)) == COMPATIBILITY) st &= ~NEWLINE;
1906 #endif
1907 if (pp.level == 1)
1909 if ((st & (COMPATIBILITY|SPACEOUT)) && !(st & TRANSITION))
1911 if (st & (COMPILE|NOTEXT))
1913 #if CATSTRINGS
1914 if ((st & (JOINING|NOTEXT|SPACEOUT)) != SPACEOUT)
1915 #else
1916 if ((st & (NOTEXT|SPACEOUT)) != SPACEOUT)
1917 #endif
1919 BACKOUT();
1920 bp = ip - 1;
1921 rp = fsm[START];
1922 if (state = rp[c]) goto fsm_next;
1923 goto fsm_get;
1926 else
1927 #if CATSTRINGS
1928 if (!(st & JOINING))
1929 #endif
1931 tp = op;
1932 bp = ip - 1;
1933 rp = fsm[START];
1934 if (state = rp[c]) goto fsm_next;
1935 goto fsm_get;
1937 BACKIN();
1938 c = ' ';
1939 goto fsm_return;
1941 BACKOUT();
1942 bp = ip - 1;
1943 rp = fsm[START];
1944 if (state = rp[c]) goto fsm_next;
1945 goto fsm_get;
1947 if (st & (NOSPACE|SKIPCONTROL))
1949 BACKOUT();
1950 bp = ip - 1;
1951 rp = fsm[START];
1952 if (state = rp[c]) goto fsm_next;
1953 goto fsm_get;
1955 if (c != '\n')
1957 BACKIN();
1958 c = ' ';
1960 if (!(pp.option & PRESERVE))
1962 BACKOUT();
1963 PUTCHR(c);
1965 goto fsm_return;
1966 #endif
1968 default:
1969 if (state & SPLICE)
1971 switch (c)
1973 case MARK:
1975 * internal mark
1978 switch (pp.in->type)
1980 case IN_BUFFER:
1981 case IN_FILE:
1982 #if !CPP
1983 case IN_INIT:
1984 #if CATSTRINGS
1985 if ((st & JOINING) && (!INQUOTE(rp) || quot != '"') || pp.level > 1 && (rp == fsm[START] || INQUOTE(rp)))
1986 #else
1987 if (pp.level > 1 && (rp == fsm[START] || INQUOTE(rp)))
1988 #endif
1989 PUTCHR(c);
1990 #endif
1991 break;
1992 default:
1993 switch (GETCHR())
1995 case 'A':
1996 if (!(st & (DEFINITION|DISABLE)))
1998 c = GETCHR();
1999 SYNCIN();
2000 if (pp.macp->arg[c - ARGOFFSET][-1])
2001 PUSH_EXPAND(pp.macp->arg[c - ARGOFFSET], pp.macp->line);
2002 else
2003 PUSH_COPY(pp.macp->arg[c - ARGOFFSET], pp.macp->line);
2004 CACHEIN();
2005 bp = ip;
2006 goto fsm_get;
2008 /*FALLTHROUGH*/
2009 case 'C':
2010 c = GETCHR() - ARGOFFSET;
2011 if (!*(s = pp.macp->arg[c]) && (pp.in->symbol->flags & SYM_VARIADIC) && pp.in->symbol->macro->arity == (c + 1))
2013 s = ip - 3;
2014 while (--op > tp && --s > bp && ppisidig(*s));
2016 else
2018 SYNCIN();
2019 PUSH_COPY(s, pp.macp->line);
2020 CACHEIN();
2022 bp = ip;
2023 goto fsm_get;
2024 case 'F':
2025 error_info.file = (char*)strtoul(ip, &s, 16);
2026 debug((-6, "actual sync: file = \"%s\"", error_info.file));
2027 bp = ip = s + 1;
2028 goto fsm_get;
2029 case 'L':
2030 error_info.line = strtoul(ip, &s, 16);
2031 debug((-6, "actual sync: line = %d", error_info.line));
2032 bp = ip = s + 1;
2033 goto fsm_get;
2034 case 'Q':
2035 c = GETCHR();
2036 SYNCIN();
2037 PUSH_QUOTE(pp.macp->arg[c - ARGOFFSET], pp.macp->line);
2038 CACHEIN();
2039 *(bp = ip - 1) = '"';
2040 if (st & (COLLECTING|EOF2NL|JOINING)) rp = fsm[START];
2041 if (state = rp[c = '"']) goto fsm_next;
2042 goto fsm_get;
2043 case 'S':
2044 c = GETCHR();
2045 SYNCIN();
2046 PUSH_SQUOTE(pp.macp->arg[c - ARGOFFSET], pp.macp->line);
2047 CACHEIN();
2048 bp = ip - 1;
2049 if (st & COLLECTING) rp = fsm[START];
2050 if (state = rp[c = '\'']) goto fsm_next;
2051 goto fsm_get;
2052 case 'X':
2053 if (pp.in->type != IN_COPY)
2054 st |= SKIPMACRO;
2055 if (pp.level <= 1)
2057 bp = ip;
2058 goto fsm_get;
2060 if (pp.in->type == IN_EXPAND)
2062 st &= ~SKIPMACRO;
2063 PUTCHR(c);
2064 PUTCHR('X');
2066 c = GETCHR();
2067 break;
2068 case 0:
2069 if ((state &= ~SPLICE) >= TERMINAL) goto fsm_terminal;
2070 goto fsm_begin;
2071 default:
2072 #if DEBUG
2073 error(PANIC, "invalid mark op `%c'", LASTCHR());
2074 /*FALLTHROUGH*/
2075 case MARK:
2076 #endif
2077 #if CATSTRINGS
2078 if ((st & (JOINING|QUOTE)) == JOINING)
2080 if (!INQUOTE(rp))
2081 PUTCHR(c);
2083 else
2084 #endif
2085 #if CPP
2086 if (rp != fsm[START] && !INQUOTE(rp))
2087 UNGETCHR(c);
2088 #else
2089 if (rp != fsm[START] && !INQUOTE(rp))
2090 UNGETCHR(c);
2091 else if (pp.level > 1)
2092 PUTCHR(c);
2093 #endif
2094 break;
2096 break;
2098 break;
2099 case '?':
2101 * trigraph
2104 if (pp.in->type == IN_FILE)
2106 GET(c, n, tp, xp);
2107 if (n == '?')
2109 GET(c, n, tp, xp);
2110 if (c = trigraph[n])
2112 if ((st & WARN) && (st & (COMPATIBILITY|TRANSITION)) && !(pp.mode & HOSTED) && !INCOMMENT(rp))
2113 error(1, "trigraph conversion %c%c%c -> %c%s", '?', '?', n, c, (st & TRANSITION) ? "" : " inhibited");
2114 #if COMPATIBLE
2115 if ((st & (COMPATIBILITY|TRANSITION)) != COMPATIBILITY)
2117 #endif
2118 *(bp = ip - 1) = c;
2119 if (state = rp[c]) goto fsm_next;
2120 goto fsm_get;
2121 #if COMPATIBLE
2123 #endif
2125 if (n != EOB) BACKIN();
2126 UNGETCHR(c = '?');
2128 else if (n != EOB) BACKIN();
2130 break;
2131 case '%':
2132 case '<':
2133 case ':':
2135 * digraph = --trigraph
2138 if (pp.in->type == IN_FILE && (pp.option & PLUSPLUS))
2140 m = 0;
2141 GET(c, n, tp, xp);
2142 switch (n)
2144 case '%':
2145 if (c == '<') m = '{';
2146 break;
2147 case '>':
2148 if (c == '%') m = '}';
2149 else if (c == ':') m = ']';
2150 break;
2151 case ':':
2152 if (c == '%') m = '#';
2153 else if (c == '<') m = '[';
2154 break;
2156 if (m)
2158 if ((st & WARN) && (st & (COMPATIBILITY|TRANSITION)) && !(pp.mode & HOSTED) && !INCOMMENT(rp))
2159 error(1, "digraph conversion %c%c -> %c%s", c, n, m, (st & TRANSITION) ? "" : " inhibited");
2160 #if COMPATIBLE
2161 if ((st & (COMPATIBILITY|TRANSITION)) != COMPATIBILITY)
2163 #endif
2164 *(bp = ip - 1) = c = m;
2165 if (state = rp[c]) goto fsm_next;
2166 goto fsm_get;
2167 #if COMPATIBLE
2169 #endif
2171 if (n != EOB) BACKIN();
2173 break;
2174 case '\\':
2176 * line splice
2179 if (pp.in->type == IN_FILE && (!(pp.option & PLUSSPLICE) || !INCOMMENTXX(rp)))
2181 m = 0;
2182 GET(c, n, tp, xp);
2183 if ((pp.option & SPLICESPACE) && !INQUOTE(rp))
2184 while (n == ' ')
2186 GET(c, n, tp, xp);
2187 m = 1;
2189 if (n == '\r')
2191 GET(c, n, tp, xp);
2192 if (n != '\n' && n != EOB)
2193 BACKIN();
2195 if (n == '\n')
2197 #if CPP
2198 if (INQUOTE(rp))
2200 if ((pp.option & STRINGSPLIT) && quot == '"')
2202 PUTCHR(quot);
2203 PUTCHR(n);
2204 PUTCHR(quot);
2206 else if (*pp.lineid)
2208 PUTCHR(c);
2209 PUTCHR(n);
2211 else
2213 st |= HIDDEN;
2214 pp.hidden++;
2217 else
2218 #else
2219 #if COMPATIBLE
2220 if (!INQUOTE(rp) && (st & (COMPATIBILITY|DEFINITION|TRANSITION)) == (COMPATIBILITY|DEFINITION))
2222 if (op == tp)
2224 st |= HIDDEN;
2225 pp.hidden++;
2226 error_info.line++;
2227 if (st & SPACEOUT)
2228 goto fsm_start;
2229 c = (pp.option & SPLICECAT) ? '\t' : ' ';
2230 PUTCHR(c);
2231 goto fsm_check;
2233 UNGETCHR(n);
2234 state &= ~SPLICE;
2235 goto fsm_terminal;
2237 #endif
2238 #endif
2240 st |= HIDDEN;
2241 pp.hidden++;
2243 #if CPP
2244 spliced++;
2245 #else
2246 error_info.line++;
2247 #endif
2248 bp = ip;
2249 goto fsm_get;
2251 else if ((n == 'u' || n == 'U') && !INQUOTE(rp))
2253 PUTCHR(c);
2254 PUTCHR(n);
2255 bp = ip;
2256 goto fsm_get;
2258 #if COMPATIBLE
2259 else if ((st & (COMPATIBILITY|TRANSITION)) == COMPATIBILITY && (n == '"' || n == '\'') && !INQUOTE(rp))
2261 PUTCHR(c);
2262 PUTCHR(n);
2263 bp = ip;
2264 goto fsm_get;
2266 #endif
2267 else if (n != EOB)
2268 BACKIN();
2269 if (m && INSPACE(rp))
2270 UNGETCHR(c);
2272 #if COMPATIBLE
2273 else if ((st & (COMPATIBILITY|TRANSITION)) == COMPATIBILITY && !INQUOTE(rp))
2275 GET(c, n, tp, xp);
2276 if (n == '"' || n == '\'')
2278 PUTCHR(c);
2279 PUTCHR(n);
2280 bp = ip;
2281 goto fsm_get;
2283 if (n != EOB)
2284 BACKIN();
2286 #endif
2287 break;
2288 case '\r':
2290 * barf
2293 if (pp.in->type == IN_FILE)
2295 GET(c, n, tp, xp);
2296 if (n == '\n')
2298 *(bp = ip - 1) = c = n;
2299 if (state = rp[c]) goto fsm_next;
2300 goto fsm_get;
2302 if (n != EOB) BACKIN();
2304 break;
2305 case CC_sub:
2307 * barf & puke
2310 if ((pp.option & ZEOF) && pp.in->type == IN_FILE)
2312 pp.in->flags |= IN_eof;
2313 c = 0;
2314 state = S_EOB;
2315 goto fsm_terminal;
2317 break;
2319 if ((state &= ~SPLICE) >= TERMINAL)
2320 goto fsm_terminal;
2321 PUTCHR(c);
2322 goto fsm_begin;
2324 #if CPP
2325 if (INOPSPACE(rp))
2327 BACKIN();
2328 goto fsm_start;
2330 #endif
2331 PUTCHR(c);
2332 bp = ip;
2333 goto fsm_get;
2335 #if !CPP
2336 fsm_token:
2337 st &= ~NEWLINE;
2338 if (pp.level == 1)
2340 pp.in->flags |= IN_tokens;
2341 if (st & NOTEXT)
2343 BACKOUT();
2344 goto fsm_top;
2346 fsm_symbol:
2347 count(token);
2349 fsm_check:
2350 if (st & SKIPCONTROL)
2352 BACKOUT();
2353 goto fsm_start;
2355 fsm_return:
2356 #if CPP
2357 error_info.line += spliced;
2358 #endif
2359 SETCHR(0);
2360 debug((-5, "token[%d] %03o = %s", pp.level, c, pptokstr(tp, 0)));
2361 SYNC();
2362 pp.level--;
2363 error_info.indent--;
2364 return c;
2365 #endif
2368 #if CPP && POOL
2370 #include <ls.h>
2371 #include <wait.h>
2374 * output pool status on exit
2377 static void
2378 poolstatus(void)
2380 error(ERROR_OUTPUT|0, pp.pool.output, "%d", error_info.errors != 0);
2384 * loop on < input output >
2387 static void
2388 pool(void)
2390 char* ifile;
2391 char* ofile;
2393 ppflushout();
2394 if (!sfnew(sfstdin, NiL, SF_UNBOUND, pp.pool.input, SF_READ))
2395 error(ERROR_SYSTEM|3, "cannot dup pool input");
2398 * kick the -I cache
2401 ppsearch(".", T_STRING, SEARCH_EXISTS);
2404 * loop on < input output >
2407 pp.pool.input = 0;
2408 while (ifile = sfgetr(sfstdin, '\n', 1))
2410 if (!(ofile = strchr(ifile, ' ')))
2411 error(3, "%s: pool output file expected", ifile);
2412 *ofile++ = 0;
2413 waitpid(0, NiL, WNOHANG);
2414 switch (fork())
2416 case -1:
2417 error(ERROR_SYSTEM|3, "cannot fork pool");
2418 case 0:
2419 atexit(poolstatus);
2420 error_info.errors = 0;
2421 error_info.warnings = 0;
2422 close(0);
2423 if (open(ifile, O_RDONLY))
2424 error(ERROR_SYSTEM|3, "%s: cannot read", ifile);
2425 close(1);
2426 if (open(ofile, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH) != 1)
2427 error(ERROR_SYSTEM|3, "%s: cannot create", ofile);
2428 pp.outfile = ofile;
2429 pathcanon(ifile, 0);
2430 ifile = ppsetfile(ifile)->name;
2431 #if CHECKPOINT
2432 if (pp.mode & DUMP)
2434 if (!pp.pragma)
2435 error(3, "#%s must be enabled for checkpoints", dirname(PRAGMA));
2436 (*pp.pragma)(dirname(PRAGMA), pp.pass, keyname(X_CHECKPOINT), pp.checkpoint, 1);
2438 #endif
2439 PUSH_FILE(ifile, 0);
2440 return;
2443 while (wait(NiL) != -1);
2446 #endif