xref: /titanic_41/usr/src/lib/libpp/common/pplex.c (revision 8e22821528b08c6dba4e8176351560f316f6d0de)
1 /***********************************************************************
2 *                                                                      *
3 *               This software is part of the ast package               *
4 *           Copyright (c) 1986-2007 AT&T Knowledge Ventures            *
5 *                      and is licensed under the                       *
6 *                  Common Public License, Version 1.0                  *
7 *                      by AT&T Knowledge Ventures                      *
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
21 /*
22  * Glenn Fowler
23  * AT&T Research
24  *
25  * preprocessor lexical analyzer
26  * standalone and tokenizing lexer combined in one source
27  * define CPP=1 for standalone
28  */
29 
30 #include "pplib.h"
31 #include "ppfsm.h"
32 
33 #if CPP
34 
35 /*
36  * standalone entry point
37  */
38 
39 #define PPCPP_T		void
40 
41 #define START		QUICK
42 #define INMACRO(x)	INQMACRO(x)
43 #define DOSTRIP()	(st&STRIP)
44 
45 #if DEBUG & TRACE_debug
46 static int		hit[LAST-TERMINAL+2];
47 #endif
48 
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))
68 
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)
72 
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(); \
105 					} \
106 				} \
107 				else \
108 				{ \
109 					m = pp.hidden; \
110 					pp.hidden = 0; \
111 					st &= ~HIDDEN; \
112 					while (m-- > 0) \
113 						PUTCHR('\n'); \
114 				} \
115 			} \
116 			else \
117 			{ \
118 				pp.hidden = 0; \
119 				st &= ~HIDDEN; \
120 				PUTCHR('\n'); \
121 			} \
122 		    } \
123 		} \
124 	} while (0)
125 
126 #if POOL
127 
128 /*
129  * <wait.h> is poison here so pool moved to the end
130  */
131 
132 static void	poolstatus(void);
133 static void	pool(void);
134 
135 #endif
136 
137 #else
138 
139 /*
140  * return next pp token
141  *
142  * NOTE: pp.token points to at least MAXTOKEN*2 chars and is
143  *       truncated back to MAXTOKEN on EOB
144  */
145 
146 #define PPCPP_T		int
147 #define ppcpp		pplex
148 
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))
152 
153 #define st		pp.state
154 #define tp		pp.token
155 #define xp		&pp.token[MAXTOKEN]
156 
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))
171 
172 #endif
173 
174 PPCPP_T
175 ppcpp(void)
176 {
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
202 
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;
225 	do
226 	{
227 		rp = fsm[state];
228  fsm_get:
229 		while (!(state = rp[c = GETCHR()]));
230  fsm_next:
231 		;
232 	} while (state > 0);
233 	if (((state = ~state) != S_COMMENT || pp.comment || c == '/' && !INCOMMENT(rp)) && (n = ip - bp - 1) > 0)
234 	{
235 		ip = bp;
236 #if CPP
237 		if (op == tp && (st & (ADD|HIDDEN)) && !(st & PASSTHROUGH))
238 			switch (TERM(state))
239 			{
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 				PPSYNCLINE();
249 				tp = op;
250 				break;
251 			}
252 #endif
253 		MEMCPY(op, ip, n);
254 		ip++;
255 	}
256 	count(terminal);
257 #if CPP && (DEBUG & TRACE_debug)
258 	hit[(state & SPLICE) ? (elementsof(hit) - 1) : (TERM(state) - TERMINAL)]++;
259 #endif
260  fsm_terminal:
261 	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)));
262 	switch (TERM(state))
263 	{
264 
265 #if !CPP
266 	case S_CHR:
267 		PUTCHR(c);
268 		break;
269 #endif
270 
271 	case S_CHRB:
272 		BACKIN();
273 #if CPP
274 		st &= ~NEWLINE;
275 		pp.in->flags |= IN_tokens;
276 		count(token);
277 		goto fsm_start;
278 #else
279 		c = *tp;
280 		break;
281 #endif
282 
283 	case S_COMMENT:
284 		switch (c)
285 		{
286 		case '\n':
287 			if (!INCOMMENTXX(rp))
288 			{
289 				qual = 0;
290 				if (!comstart) comstart = comdelim = error_info.line;
291 				error_info.line++;
292 				if (pp.comment) PUTCHR(c);
293 				else BACKOUT();
294 #if CPP
295 				rp = fsm[COM2];
296 				bp = ip;
297 				goto fsm_get;
298 #else
299 				state = COM2;
300 				goto fsm_begin;
301 #endif
302 			}
303 			else if (comwarn < 0 && !(pp.mode & HOSTED))
304 				error(1, "/* appears in // comment");
305 			break;
306 		case '*':
307 			if (!comwarn && !(pp.mode & HOSTED))
308 			{
309 				if (INCOMMENTXX(rp)) comwarn = -1;
310 				else if (comstart && comstart != error_info.line)
311 				{
312 					if (qual || comdelim < error_info.line - 1)
313 					{
314 						error(1, "/* appears in /* ... */ comment starting at line %d", comstart);
315 						comwarn = 1;
316 					}
317 					else comdelim = error_info.line;
318 				}
319 			}
320  fsm_comment:
321 			PUTCHR(c);
322 #if CPP
323 			rp = fsm[INCOMMENTXX(rp) ? COM5 : COM3];
324 			bp = ip;
325 			goto fsm_get;
326 #else
327 			state = INCOMMENTXX(rp) ? COM5 : COM3;
328 			goto fsm_begin;
329 #endif
330 		case '/':
331 			if (!INCOMMENT(rp))
332 			{
333 				if (!(pp.mode & HOSTED))
334 					error(1, "*/ appears outside of comment");
335 				BACKIN();
336 #if CPP
337 				st &= ~NEWLINE;
338 				pp.in->flags |= IN_tokens;
339 				count(token);
340 				goto fsm_start;
341 #else
342 				c = '*';
343 				if (!pp.comment) PUTCHR(c);
344 				goto fsm_token;
345 #endif
346 			}
347 			else if (INCOMMENTXX(rp))
348 			{
349 				if (!(pp.mode & HOSTED))
350 				{
351 					if (comwarn < 0) comwarn = 0;
352 					else if (!comwarn)
353 					{
354 						comwarn = 1;
355 						error(1, "*/ appears in // comment");
356 					}
357 				}
358 				goto fsm_comment;
359 			}
360 			break;
361 		case EOF:
362 			BACKIN();
363 			if (!(pp.mode & HOSTED))
364 			{
365 				if (comstart) error(2, "unterminated /* ... */ comment starting at line %d", comstart);
366 				else if (INCOMMENTXX(rp)) error(2, "unterminated // ... comment");
367 				else error(2, "unterminated /* ... */ comment");
368 			}
369 			break;
370 		}
371 #if CPP
372 		if (!pp.comment || sp)
373 		{
374 #if COMPATIBLE
375 			if (!(pp.state & COMPATIBILITY) || *bp == ' ' || *bp == '\t')
376 #endif
377 			{
378 				BACKOUT();
379 				PUTCHR(' ');
380 				tp = op;
381 			}
382 		}
383 		else if (pp.in->type & IN_TOP)
384 #else
385 		if (pp.comment && !(st & (COLLECTING|DIRECTIVE|JOINING)) && !(*pp.control & SKIP) && (pp.in->type & IN_TOP))
386 #endif
387 		{
388 			st &= ~HIDDEN;
389 			pp.hidden = 0;
390 			*(op - (c != '\n')) = 0;
391 			m = (op - (c != '\n') - tp > MAXTOKEN - 6) ? (error_info.line - MAXHIDDEN) : 0;
392 			BACKOUT();
393 			SYNC();
394 			while (*tp != '/') tp++;
395 			(*pp.comment)(c == '\n' ? "//" : "/*", tp + 2, c == '\n' ? "" : (st & HEADER) ? "*/\n" : "*/", comstart ? comstart : error_info.line);
396 			CACHE();
397 			comstart = m;
398 		}
399 		if (comstart)
400 		{
401 			st |= HIDDEN;
402 			pp.hidden += error_info.line - comstart;
403 			comstart = 0;
404 		}
405 		qual = comwarn = comdelim = 0;
406 		BACKOUT();
407 		if (c == '\n') goto fsm_newline;
408 		if ((st & PASSTHROUGH) && ((st & (HIDDEN|NEWLINE)) || *ip == '\n'))
409 		{
410 			if (*ip == '\n')
411 				ip++;
412 			goto fsm_newline;
413 		}
414 #if COMPATIBLE
415 		if ((st & (COMPATIBILITY|TRANSITION)) == COMPATIBILITY) st &= ~NEWLINE;
416 #endif
417 #if !CPP
418 		if (pp.level > 1 && !(st & (NOSPACE|SKIPCONTROL)))
419 		{
420 #if COMPATIBLE
421 			c = ((st & (COMPATIBILITY|DEFINITION)) == ((COMPATIBILITY|DEFINITION))) ? '\t' : ' ';
422 #else
423 			c = ' ';
424 #endif
425 			goto fsm_return;
426 		}
427 #endif
428 		goto fsm_start;
429 
430 	case S_EOB:
431 		if (c)
432 		{
433 			if (state = fsm[TERMINAL][INDEX(rp)+1])
434 				goto fsm_terminal;
435 #if CPP
436 #if POOL
437 			if (pp.pool.input)
438 			{
439 				BACKIN();
440 				SYNC();
441 				pool();
442 				CACHE();
443 				goto fsm_pool;
444 			}
445 #endif
446 			SYNCOUT();
447 			return;
448 #else
449 			BACKIN();
450 			c = 0;
451 			goto fsm_return;
452 #endif
453 		}
454 		{
455 			register struct ppinstk*	cur = pp.in;
456 			register struct ppinstk*	prv = pp.in->prev;
457 
458 #if CPP
459 			if (sp) op = sp;
460 #endif
461 			switch (cur->type)
462 			{
463 			case IN_BUFFER:
464 			case IN_INIT:
465 			case IN_RESCAN:
466 #if CPP
467 				if (prv)
468 #else
469 				if (!(st & PASSEOF) && prv)
470 #endif
471 				{
472 					if (cur->type == IN_RESCAN || cur->type == IN_BUFFER)
473 					{
474  fsm_pop:
475 #if PROTOTYPE
476 						if (cur->flags & IN_prototype)
477 							pppclose(cur->buffer + PPBAKSIZ);
478 						else
479 #endif
480 						if (!(cur->flags & IN_static))
481 							free(cur->buffer);
482 					}
483 					while (pp.control-- != cur->control)
484 						error(2, "#%s on line %d has no #%s", dirname(IF), GETIFLINE(pp.control+1), dirname(ENDIF));
485 					st |= NEWLINE;
486 					error_info.file = cur->file;
487 					error_info.line = cur->line;
488 					pp.hidden = 0;
489 #if CPP
490 					spliced = 0;
491 #endif
492 					if (cur->flags & IN_hosted)
493 					{
494 						pp.mode |= HOSTED;
495 						pp.flags |= PP_hosted;
496 					}
497 					else
498 					{
499 						pp.mode &= ~HOSTED;
500 						pp.flags &= ~PP_hosted;
501 					}
502 #if !CPP && CATSTRINGS
503 					if (st & JOINING) st |= HIDDEN|SYNCLINE;
504 					else
505 #endif
506 					{
507 						st &= ~(HIDDEN|SYNCLINE);
508 						switch (cur->type)
509 						{
510 						case IN_BUFFER:
511 						case IN_INIT:
512 							if (!prv->prev) break;
513 							/*FALLTHROUGH*/
514 						case IN_FILE:
515 						case IN_RESCAN:
516 							if (prv->type == IN_FILE || cur->type == IN_FILE && (prv->type == IN_RESCAN || prv->type == IN_MULTILINE))
517 							{
518 								if (pp.linesync && (cur->type != IN_RESCAN || (cur->flags & IN_sync)))
519 								{
520 									POP();
521 									SYNCOUT();
522 									(*pp.linesync)(error_info.line, error_info.file);
523 									CACHEOUT();
524 									prv = pp.in;
525 								}
526 							}
527 #if DEBUG
528 							else if (!prv->prev)
529 							{
530 								/*UNDENT*/
531 	c = 0;
532 #if DEBUG & TRACE_count
533 	if (pp.test & TEST_count)
534 	{
535 		c = 1;
536 		sfprintf(sfstderr, "\n");
537 		sfprintf(sfstderr, "%7d: pplex calls\n", pp.counter.pplex);
538 		sfprintf(sfstderr, "%7d: terminal states\n", pp.counter.terminal);
539 		sfprintf(sfstderr, "%7d: emitted tokens\n", pp.counter.token);
540 		sfprintf(sfstderr, "%7d: input stream pushes\n", pp.counter.push);
541 		sfprintf(sfstderr, "%7d: macro candidates\n", pp.counter.candidate);
542 		sfprintf(sfstderr, "%7d: macro expansions\n", pp.counter.macro);
543 		sfprintf(sfstderr, "%7d: function macros\n", pp.counter.function);
544 	}
545 #endif
546 #if CPP && (DEBUG & TRACE_debug)
547 	if (pp.test & TEST_hit)
548 	{
549 		c = 1;
550 		sfprintf(sfstderr, "\n");
551 		if (hit[elementsof(hit) - 1])
552 			sfprintf(sfstderr, "%7d: SPLICE\n", hit[elementsof(hit) - 1]);
553 		for (n = 0; n < elementsof(hit) - 1; n++)
554 			if (hit[n])
555 				sfprintf(sfstderr, "%7d: %s\n", hit[n], pplexstr(TERMINAL + n));
556 	}
557 #endif
558 	if (pp.test & (TEST_hashcount|TEST_hashdump))
559 	{
560 		c = 1;
561 		sfprintf(sfstderr, "\n");
562 		hashdump(NiL, (pp.test & TEST_hashdump) ? HASH_BUCKET : 0);
563 	}
564 	if (c) sfprintf(sfstderr, "\n");
565 								/*INDENT*/
566 							}
567 #endif
568 							break;
569 						}
570 					}
571 #if CHECKPOINT
572 					if (cur->index)
573 					{
574 						SYNCOUT();
575 						cur->index->end = ppoffset();
576 						cur->index = 0;
577 						CACHEOUT();
578 					}
579 #endif
580 					POP();
581 					bp = ip;
582 					tp = op;
583 					goto fsm_get;
584 				}
585 				c = EOF;
586 				break;
587 			case IN_COPY:
588 				if (prv)
589 				{
590 					error_info.line = cur->line;
591 					if (!(prv->symbol->flags & SYM_MULTILINE))
592 						prv->symbol->flags |= SYM_DISABLED;
593 					POP();
594 					bp = ip;
595 					goto fsm_get;
596 				}
597 				c = EOF;
598 				break;
599 			case IN_EXPAND:
600 				if (prv)
601 				{
602 					error_info.line = cur->line;
603 					free(cur->buffer);
604 					POP();
605 					bp = ip;
606 					goto fsm_get;
607 				}
608 				c = EOF;
609 				break;
610 			case IN_FILE:
611 				FGET(c, c, tp, xp);
612 				if (c == EOB)
613 				{
614 #if CPP
615 					if ((st & (NOTEXT|HIDDEN)) == HIDDEN && LASTOUT() != '\n')
616 						PUTCHR('\n');
617 					if (prv)
618 #else
619 					if (st & EOF2NL)
620 					{
621 						st &= ~EOF2NL;
622 						*(ip - 1) = c = '\n';
623 					}
624 					else if (!(st & (FILEPOP|PASSEOF)) && prv)
625 #endif
626 					{
627 						if (!(cur->flags & IN_newline))
628 						{
629 							cur->flags |= IN_newline;
630 							if ((pp.mode & (HOSTED|PEDANTIC)) == PEDANTIC && LASTCHR() != '\f' && LASTCHR() != CC_sub)
631 								error(1, "file does not end with %s", pptokchr('\n'));
632 							*(ip - 1) = c = '\n';
633 						}
634 						else
635 						{
636 							if (!(cur->flags & (IN_noguard|IN_tokens)) && cur->symbol)
637 								ppmultiple(ppsetfile(error_info.file), cur->symbol);
638 							if (cur->fd >= 0)
639 								close(cur->fd);
640 							if (pp.incref && !(pp.mode & INIT))
641 							{
642 								SYNCOUT();
643 								(*pp.incref)(error_info.file, cur->file, error_info.line - 1, PP_SYNC_POP);
644 								CACHEOUT();
645 							}
646 							goto fsm_pop;
647 						}
648 					}
649 					else
650 						c = EOF;
651 				}
652 				break;
653 			case IN_MACRO:
654 			case IN_MULTILINE:
655 #if !CPP
656 				if (!(st & PASSEOF))
657 #endif
658 #if COMPATIBLE
659 				if (prv && (!INMACRO(rp) || (st & (COMPATIBILITY|TRANSITION)) == COMPATIBILITY && ppismac(*prv->nextchr)))
660 #else
661 				if (prv && !INMACRO(rp))
662 #endif
663 				{
664 					if (cur->type == IN_MULTILINE)
665 					{
666 						while (pp.control-- != cur->control)
667 							error(2, "#%s on line %d has no #%s", dirname(IF), GETIFLINE(pp.control+1), dirname(ENDIF));
668 						free(cur->buffer);
669 						error_info.file = cur->file;
670 						error_info.line = cur->line;
671 						if (pp.linesync)
672 						{
673 							SYNCOUT();
674 							(*pp.linesync)(error_info.line, error_info.file);
675 							CACHEOUT();
676 						}
677 					}
678 					cur->symbol->flags &= ~SYM_DISABLED;
679 					if (cur->symbol->flags & SYM_FUNCTION)
680 						popframe(pp.macp);
681 					POP();
682 #if CPP
683 					if (!(st & COMPATIBILITY) && ppisidig(*(op - 1)) && ppisidig(*ip)) UNGETCHR(' ');
684 #endif
685 					bp = ip;
686 					goto fsm_get;
687 				}
688 				c = EOF;
689 				break;
690 			case IN_QUOTE:
691 				if (prv)
692 				{
693 					error_info.line = cur->line;
694 					st &= ~(ESCAPE|QUOTE);
695 					POP();
696 					c = '"';
697 				}
698 				else c = EOF;
699 				break;
700 			case IN_SQUOTE:
701 				if (prv)
702 				{
703 					error_info.line = cur->line;
704 					st &= ~(ESCAPE|SQUOTE);
705 					POP();
706 					c = '\'';
707 				}
708 				else c = EOF;
709 				break;
710 			case IN_STRING:
711 #if CPP
712 				if (prv)
713 #else
714 				if (!(st & PASSEOF) && !(cur->flags & IN_expand) && prv)
715 #endif
716 				{
717 					if (cur->flags & IN_disable) st |= DISABLE;
718 					else st &= ~DISABLE;
719 					POP();
720 					bp = ip;
721 					goto fsm_get;
722 				}
723 				c = EOF;
724 				break;
725 			default:
726 				c = EOF;
727 				break;
728 			}
729 		}
730 		bp = ip - 1;
731 		if (state = rp[c]) goto fsm_next;
732 		goto fsm_get;
733 
734 #if !CPP
735 	case S_HUH:
736 		if (INOPSPACE(rp))
737 		{
738 			if (c == '=')
739 			{
740 #if PROTOTYPE
741 				if (pp.in->flags & IN_prototype) PUTCHR(c);
742 				else
743 				{
744 #endif
745 					while (*(op - 1) == ' ' || *(op - 1) == '\t') op--;
746 					PUTCHR(c);
747 					if (st & (STRICT|WARN)) error(1, "%-*.*s: space ignored in operator", op - tp, op - tp, tp);
748 #if PROTOTYPE
749 				}
750 #endif
751 				switch (*tp)
752 				{
753 				case '/':
754 					c = T_DIVEQ;
755 					break;
756 				case '%':
757 					c = T_MODEQ;
758 					break;
759 				case '&':
760 					c = T_ANDEQ;
761 					break;
762 				case '*':
763 					c = T_MPYEQ;
764 					break;
765 				case '+':
766 					c = T_ADDEQ;
767 					break;
768 				case '-':
769 					c = T_SUBEQ;
770 					break;
771 				case '^':
772 					c = T_XOREQ;
773 					break;
774 				case '|':
775 					c = T_OREQ;
776 					break;
777 				case '<':
778 					c = T_LSHIFTEQ;
779 					break;
780 				case '>':
781 					c = T_RSHIFTEQ;
782 					break;
783 				}
784 			}
785 			else
786 			{
787 				BACKIN();
788 				switch (c = *tp)
789 				{
790 				case '<':
791 					c = T_LSHIFT;
792 					break;
793 				case '>':
794 					c = T_RSHIFT;
795 					break;
796 				}
797 			}
798 		}
799 		else if (pp.level > 1 || (pp.option & PRESERVE)) PUTCHR(c);
800 		else if (tp == op)
801 		{
802 			if (pp.in->type != IN_BUFFER)
803 			{
804 				if (!(pp.option & ALLPOSSIBLE))
805 					error(1, "%s: invalid character ignored", pptokchr(c));
806 				goto fsm_top;
807 			}
808 			PUTCHR(c);
809 		}
810 		else if (*tp == ':')
811 		{
812 			PUTCHR(c);
813 			if (c == '=') error(2, "real programmers use =");
814 			else c = '+';
815 		}
816 		else
817 		{
818 			BACKIN();
819 			c = *tp;
820 		}
821 		break;
822 #endif
823 
824 	case S_QUAL:
825 		if ((state = NEXT(state)) != LIT1)
826 		{
827 			rp = fsm[state];
828 			bp = ip;
829 #if CPP
830 			qual = 1;
831 #if COMPATIBLE
832 			if (!(st & COMPATIBILITY) || c != 'u' && c != 'U')
833 #endif
834 				PUTCHR(c);
835 #else
836 			switch (c)
837 			{
838 			case 'f':
839 			case 'F':
840 				qual |= N_FLOAT;
841 #if COMPATIBLE
842 				if (!(st & COMPATIBILITY))
843 #endif
844 				PUTCHR(c);
845 				break;
846 			case 'l':
847 			case 'L':
848 				qual |= N_LONG;
849 				PUTCHR(c);
850 				break;
851 			case 'u':
852 			case 'U':
853 				qual |= N_UNSIGNED;
854 #if COMPATIBLE
855 				if (!(st & COMPATIBILITY))
856 #endif
857 				PUTCHR(c);
858 				break;
859 			default:
860 				PUTCHR(c);
861 				break;
862 			}
863 #endif
864 			goto fsm_get;
865 		}
866 #if !CPP
867 		qual |= N_WIDE;
868 		if (DOSTRIP()) BACKOUT();
869 #endif
870 		/*FALLTHROUGH*/
871 
872 	case S_LITBEG:
873 #if CPP
874 		quot = c;
875 		rp = fsm[LIT1];
876 		if (op == tp)
877 		{
878 			PPSYNCLINE();
879 			tp = op;
880 		}
881 #else
882 		if ((quot = c) == '<')
883 		{
884 			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)
885 			{
886 				PUTCHR(c);
887 				bp = ip;
888 				rp = fsm[LT1];
889 				goto fsm_get;
890 			}
891 			quot = '>';
892 			rp = fsm[HDR1];
893 		}
894 		else rp = fsm[LIT1];
895 		if (!DOSTRIP())
896 #endif
897 		PUTCHR(c);
898 		bp = ip;
899 		goto fsm_get;
900 
901 	case S_LITEND:
902 		n = 1;
903 		if (c != quot)
904 		{
905 			if (c != '\n' && c != EOF)
906 			{
907 				if (st & (QUOTE|SQUOTE))
908 				{
909 					if (!(st & ESCAPE))
910 					{
911 						st |= ESCAPE;
912 						quotquot = c;
913 					}
914 					else if (c == quotquot) st &= ~ESCAPE;
915 				}
916 				PUTCHR(c);
917 				bp = ip;
918 				goto fsm_get;
919 			}
920 #if CPP
921 			if (st & PASSTHROUGH)
922 			{
923 				if (c == '\n') goto fsm_newline;
924 				bp = ip;
925 				goto fsm_start;
926 			}
927 #endif
928 			m = (st & SKIPCONTROL) && (pp.mode & HOSTED) ? -1 : 1;
929 			if (c == '\n' && quot == '\'' && (pp.option & STRINGSPAN)) n = 0;
930 			else
931 #if COMPATIBLE && !CPP
932 			if ((st & (COMPATIBILITY|DEFINITION)) != (COMPATIBILITY|DEFINITION))
933 #endif
934 			{
935 				switch (quot)
936 				{
937 				case '"':
938 					if (c == '\n')
939 					{
940 						if (!(pp.option & STRINGSPAN) || (st & (COMPATIBILITY|STRICT)) == STRICT)
941 							error(m, "%s in string", pptokchr(c));
942 						error_info.line++;
943 						if (!(pp.option & STRINGSPAN))
944 						{
945 							PUTCHR('\\');
946 							c = 'n';
947 						}
948 						else if (pp.option & STRINGSPLIT)
949 						{
950 							PUTCHR('\\');
951 							PUTCHR('n');
952 							PUTCHR('"');
953 							PUTCHR('\n');
954 							c = '"';
955 						}
956 						PUTCHR(c);
957 						bp = ip;
958 						goto fsm_get;
959 					}
960 					error(m, "%s in string", pptokchr(c));
961 					c = '\n';
962 					break;
963 				case '\'':
964 					if (!(st & DIRECTIVE) || !(pp.mode & (HOSTED|RELAX)))
965 						error(m, "%s in character constant", pptokchr(c));
966 					break;
967 				case '>':
968 					error(m, "%s in header constant", pptokchr(c));
969 					break;
970 				default:
971 					error(m, "%s in %c quote", pptokchr(c), quot);
972 					break;
973 				}
974 #if !CPP
975 				if (!DOSTRIP())
976 #endif
977 				PUTCHR(quot);
978 			}
979 			if (c == '\n')
980 			{
981 				UNGETCHR(c);
982 				c = quot;
983 			}
984 		}
985 		else if (st & (SQUOTE|QUOTE))
986 		{
987 			if (!(st & ESCAPE))
988 			{
989 				st |= ESCAPE;
990 				quotquot = c;
991 			}
992 			else if (c == quotquot) st &= ~ESCAPE;
993 			PUTCHR('\\');
994 			PUTCHR(c);
995 			bp = ip;
996 			goto fsm_get;
997 		}
998 #if CPP
999 		else PUTCHR(c);
1000 #else
1001 		else if (!DOSTRIP()) PUTCHR(c);
1002 #endif
1003 #if CATSTRINGS
1004 #if CPP
1005 		if (c == '"' && !(st & (COLLECTING|NOTEXT|PASSTHROUGH|SKIPCONTROL)) && (pp.mode & CATLITERAL))
1006 #else
1007 		if (c == '"' && pp.level == 1 && !(st & (COLLECTING|JOINING|NOTEXT|SKIPCONTROL)) && (pp.mode & CATLITERAL))
1008 #endif
1009 		{
1010 			char*	pptoken;
1011 			long	ppstate;
1012 
1013 			pptoken = pp.token;
1014 			pp.token = pp.catbuf;
1015 			*pp.token++ = 0;
1016 			ppstate = (st & STRIP);
1017 			if (DOSTRIP())
1018 				ppstate |= ADD|QUOTE;
1019 			st |= JOINING;
1020 			st &= ~(NEWLINE|STRIP);
1021 
1022 			/*
1023 			 * revert to the top level since string
1024 			 * concatenation crosses file boundaries
1025 			 * (allowing intervening directives)
1026 			 */
1027 
1028 			pp.level = 0;
1029 			SYNCIN();
1030 			m = n = 0;
1031 			for (;;)
1032 			{
1033 				switch (c = pplex())
1034 				{
1035 				case '\n':
1036 					m++;
1037 					continue;
1038 				case ' ':
1039 					*pp.catbuf = ' ';
1040 					continue;
1041 				case T_WSTRING:
1042 #if !CPP
1043 					qual = N_WIDE;
1044 #endif
1045 					if (ppstate & ADD)
1046 						ppstate &= ~ADD;
1047 					else if (m == n || !(st & SPACEOUT))
1048 						op--;
1049 					else
1050 					{
1051 						n = m;
1052 						*(op - 1) = '\\';
1053 						*op++ = '\n';
1054 					}
1055 					STRCOPY(op, pp.token + 2 + (*pp.token == ' '), s);
1056 					continue;
1057 				case T_STRING:
1058 					if (ppstate & ADD)
1059 						ppstate &= ~ADD;
1060 					else if (m == n || !(st & SPACEOUT))
1061 						op--;
1062 					else
1063 					{
1064 						n = m;
1065 						*(op - 1) = '\\';
1066 						*op++ = '\n';
1067 					}
1068 					STRCOPY(op, pp.token + 1 + (*pp.token == ' '), s);
1069 					continue;
1070 				case 0:
1071 					m = error_info.line ? (error_info.line - 1) : 0;
1072 					*pp.token = 0;
1073 					/*FALLTHROUGH*/
1074 				default:
1075 					if (m)
1076 					{
1077 						if (--m)
1078 						{
1079 							pp.state |= HIDDEN|SYNCLINE;
1080 							pp.hidden += m;
1081 						}
1082 #if COMPATIBLE
1083 						if ((st & COMPATIBILITY) && c == '#' && *(pp.token - 1))
1084 						{
1085 							*(pp.token + 3) = *(pp.token + 2);
1086 							*(pp.token + 2) = *(pp.token + 1);
1087 							*(pp.token + 1) = *pp.token;
1088 							*pp.token = *(pp.token - 1);
1089 						}
1090 						error_info.line--;
1091 						*--pp.token = '\n';
1092 #endif
1093 					}
1094 					else if (*(pp.token - 1))
1095 						pp.token--;
1096 					if (ppisidig(*pp.token))
1097 						*op++ = ' ';
1098 					if (pp.in->type == IN_MACRO && (s = strchr(pp.token, MARK)) && !*(s + 1))
1099 					{
1100 						*(s + 1) = MARK;
1101 						*(s + 2) = 0;
1102 					}
1103 					PUSH_STRING(pp.token);
1104 					pp.state &= ~(JOINING|NEWLINE);
1105 					pp.state |= ppstate & ~(ADD|QUOTE);
1106 					if ((ppstate & (ADD|QUOTE)) == QUOTE)
1107 						op--;
1108 					break;
1109 				}
1110 				break;
1111 			}
1112 			pp.token = pptoken;
1113 			CACHEIN();
1114 			pp.level = 1;
1115 #if !CPP
1116 			c = T_STRING | qual;
1117 			break;
1118 #endif
1119 		}
1120 #endif
1121 #if CPP
1122 		if (n && !(st & (PASSTHROUGH|SKIPCONTROL|NOTEXT)) && c == '\'' && (op - tp) <= 2 && !(pp.mode & (HOSTED|RELAX)))
1123 			error(1, "empty character constant");
1124 		st &= ~(ESCAPE|NEWLINE);
1125 		pp.in->flags |= IN_tokens;
1126 		count(token);
1127 		goto fsm_start;
1128 #else
1129 		st &= ~ESCAPE;
1130 		switch (quot)
1131 		{
1132 		case '\'':
1133 			if (n && !(st & NOTEXT) && (op - tp) <= (DOSTRIP() ? 0 : 2) && !(pp.mode & (HOSTED|RELAX)))
1134 				error(1, "empty character constant");
1135 			c = T_CHARCONST | qual;
1136 			break;
1137 		case '>':
1138 			c = T_HEADER;
1139 			break;
1140 		default:
1141 			if (c == quot)
1142 				c = T_STRING | qual;
1143 			break;
1144 		}
1145 		break;
1146 #endif
1147 
1148 	case S_LITESC:
1149 		if (st & (COLLECTING|DIRECTIVE|QUOTE|SQUOTE))
1150 		{
1151 			if (st & ESCAPE)
1152 			{
1153 				PUTCHR('\\');
1154 				if (c == quot) PUTCHR('\\');
1155 			}
1156 			PUTCHR(c);
1157 		}
1158 #if CPP
1159 		else if (st & PASSTHROUGH) PUTCHR(c);
1160 #endif
1161 		else if (pp.option & PRESERVE) PUTCHR(c);
1162 		else switch (c)
1163 		{
1164 		case 'b':
1165 		case 'f':
1166 		case 'n':
1167 		case 'r':
1168 		case 't':
1169 		case '\\':
1170 		case '\'':
1171 		case '"':
1172 		case '?':
1173 			PUTCHR(c);
1174 			break;
1175 #if COMPATIBLE
1176 		case '8':
1177 		case '9':
1178 			if (!(st & COMPATIBILITY)) goto unknown;
1179 			if (st & STRICT) error(1, "%c: invalid character in octal character escape", c);
1180 			/*FALLTHROUGH*/
1181 #endif
1182 		case '0':
1183 		case '1':
1184 		case '2':
1185 		case '3':
1186 		case '4':
1187 		case '5':
1188 		case '6':
1189 		case '7':
1190 			n = c - '0';
1191 			for (m = 0; m < 2; m++)
1192 			{
1193 				GET(c, c, tp, xp);
1194 				switch (c)
1195 				{
1196 #if COMPATIBLE
1197 				case '8':
1198 				case '9':
1199 					if (!(st & COMPATIBILITY))
1200 					{
1201 						UNGETCHR(c);
1202 						break;
1203 					}
1204 					if (st & STRICT) error(1, "%c: invalid character in octal character escape", c);
1205 					/*FALLTHROUGH*/
1206 #endif
1207 				case '0':
1208 				case '1':
1209 				case '2':
1210 				case '3':
1211 				case '4':
1212 				case '5':
1213 				case '6':
1214 				case '7':
1215 					n = (n << 3) + c - '0';
1216 					continue;
1217 				default:
1218 					UNGETCHR(c);
1219 					break;
1220 				}
1221 				break;
1222 			}
1223 			if (n & ~0777) error(1, "octal character constant too large");
1224 			goto octal;
1225 		case 'a':
1226 			if (pp.option & MODERN)
1227 			{
1228 				PUTCHR(c);
1229 				break;
1230 			}
1231 #if COMPATIBLE
1232 			if (st & COMPATIBILITY) goto unknown;
1233 #endif
1234 			n = CC_bel;
1235 			goto octal;
1236 		case 'v':
1237 			if (pp.option & MODERN)
1238 			{
1239 				PUTCHR(c);
1240 				break;
1241 			}
1242 			n = CC_vt;
1243 			goto octal;
1244 		case 'E':
1245 			if (st & (COMPATIBILITY|STRICT)) goto unknown;
1246 			n = CC_esc;
1247 			goto octal;
1248 		case 'x':
1249 #if COMPATIBLE
1250 			if (st & COMPATIBILITY) goto unknown;
1251 #endif
1252 			n = 0;
1253 			for (m = 0; m < 3; m++)
1254 			{
1255 				GET(c, c, tp, xp);
1256 				switch (c)
1257 				{
1258 				case '0':
1259 				case '1':
1260 				case '2':
1261 				case '3':
1262 				case '4':
1263 				case '5':
1264 				case '6':
1265 				case '7':
1266 				case '8':
1267 				case '9':
1268 					n = (n << 4) + c - '0';
1269 					continue;
1270 				case 'a':
1271 				case 'b':
1272 				case 'c':
1273 				case 'd':
1274 				case 'e':
1275 				case 'f':
1276 					n = (n << 4) + c - 'a' + 10;
1277 					continue;
1278 				case 'A':
1279 				case 'B':
1280 				case 'C':
1281 				case 'D':
1282 				case 'E':
1283 				case 'F':
1284 					n = (n << 4) + c - 'A' + 10;
1285 					continue;
1286 				default:
1287 					if (!m) error(1, "\\x%c: invalid character in hexadecimal character constant", c);
1288 					UNGETCHR(c);
1289 					break;
1290 				}
1291 				break;
1292 			}
1293 			if (n & ~0777) error(1, "hexadecimal character constant too large");
1294 		octal:
1295 			PUTCHR(((n >> 6) & 07) + '0');
1296 			PUTCHR(((n >> 3) & 07) + '0');
1297 			PUTCHR((n & 07) + '0');
1298 			break;
1299 		default:
1300 		unknown:
1301 			if (st & (STRICT|WARN)) error(1, "\\%c: non-standard character constant", c);
1302 			PUTCHR(c);
1303 			break;
1304 		}
1305 		state = LIT1;
1306 		goto fsm_begin;
1307 
1308 	case S_MACRO:
1309 		BACKIN();
1310 #if CPP
1311 		if (st & (DISABLE|SKIPCONTROL|SKIPMACRO))
1312 		{
1313 			if (st & SKIPMACRO)
1314 				pp.mode |= MARKMACRO;
1315 			st &= ~(NEWLINE|SKIPMACRO);
1316 			pp.in->flags |= IN_tokens;
1317 			count(token);
1318 			goto fsm_start;
1319 		}
1320 		count(candidate);
1321 		SETCHR(0);
1322 		switch (state = INDEX(rp))
1323 		{
1324 		case HIT0:
1325 			tp = op - 1;
1326 			break;
1327 		case HITN:
1328 			bp = tp;
1329 			tp = op - ((pp.truncate && pp.truncate < (HITN - HIT0)) ? (pp.truncate - 1) : (HITN - HIT0));
1330 			while (tp > bp && ppisidig(*(tp - 1))) tp--;
1331 			break;
1332 		default:
1333 			bp = tp;
1334 			if ((tp = op - (state - HIT0)) > bp && *(tp - 1) == 'L') tp--;
1335 			break;
1336 		}
1337 		if (sym = ppsymref(pp.symtab, tp))
1338 		{
1339 			SYNCIN();
1340 			n = ppcall(sym, 0);
1341 			CACHEIN();
1342 			if (n >= 0)
1343 			{
1344 				BACKOUT();
1345 				if (!n)
1346 				{
1347 					if (sp) op = sp;
1348 					else
1349 					{
1350 						s = ip;
1351 						ip = sym->macro->value;
1352 						c = sym->macro->size;
1353 						while (c > 0)
1354 						{
1355 							if (op + c < xp + PPBUFSIZ) n = c;
1356 							else n = xp + PPBUFSIZ - op;
1357 							MEMCPY(op, ip, n);
1358 							c -= n;
1359 							PPCHECKOUT();
1360 						}
1361 						ip = s;
1362 					}
1363 				}
1364 				else if ((sym->flags & SYM_MULTILINE) && pp.linesync)
1365 				{
1366 					SYNCOUT();
1367 					if (!(state & NEWLINE))
1368 						ppputchar('\n');
1369 					(*pp.linesync)(error_info.line, error_info.file);
1370 					CACHEOUT();
1371 				}
1372 			}
1373 		}
1374 		pp.in->flags |= IN_tokens;
1375 		goto fsm_start;
1376 #else
1377 		if (st & (COLLECTING|DEFINITION|DISABLE|SKIPCONTROL|SKIPMACRO))
1378 		{
1379 			if (st & SKIPMACRO)
1380 				pp.mode |= MARKMACRO;
1381 			st &= ~(NEWLINE|NOEXPAND|SKIPMACRO);
1382 			c = T_ID;
1383 			if (pp.level == 1)
1384 			{
1385 				pp.in->flags |= IN_tokens;
1386 				if (st & NOTEXT)
1387 				{
1388 					BACKOUT();
1389 					goto fsm_top;
1390 				}
1391 				if (st & COMPILE)
1392 				{
1393 					SETCHR(0);
1394 					if (pp.truncate && (op - tp) > pp.truncate) tp[pp.truncate] = 0;
1395 					sym = (pp.option & NOHASH) ? ppsymref(pp.symtab, tp) : ppsymset(pp.symtab, tp);
1396  fsm_noise:
1397 					if (pp.symbol = sym)
1398 					{
1399 						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)))
1400 						{
1401 							c = ((struct ppsymkey*)sym)->lex;
1402 							/*UNDENT*/
1403 
1404 #define ADVANCE()	do{if(pp.toknxt<op)pp.token=pp.toknxt;}while(0)
1405 
1406 #define NOISE_BRACE		01
1407 #define NOISE_NOSPACEOUT	02
1408 #define NOISE_PAREN		04
1409 
1410 	if ((pp.option & NOISE) && ppisnoise(c))
1411 	{
1412 		if (c != T_NOISE)
1413 		{
1414 			int		p;
1415 			int		f;
1416 			char*		pptoken;
1417 			PPCOMMENT	ppcomment;
1418 
1419 			SYNCIN();
1420 			pp.toknxt = op;
1421 			f = 0;
1422 			if (!(pp.state & SPACEOUT))
1423 			{
1424 				pp.state |= SPACEOUT;
1425 				f |= NOISE_NOSPACEOUT;
1426 			}
1427 			ppcomment = pp.comment;
1428 			pp.comment = 0;
1429 			op = (pptoken = tp) + MAXTOKEN;
1430 			switch (c)
1431 			{
1432 			case T_X_GROUP:
1433 				m = p = 0;
1434 				quot = 1;
1435 				for (;;)
1436 				{
1437 					ADVANCE();
1438 					switch (c = pplex())
1439 					{
1440 					case '(':
1441 					case '{':
1442 						if (!p)
1443 						{
1444 							if (c == '(')
1445 							{
1446 								if (f & NOISE_PAREN)
1447 								{
1448 									ungetchr(c);
1449 									*--pp.toknxt = 0;
1450 									break;
1451 								}
1452 								f |= NOISE_PAREN;
1453 								p = ')';
1454 							}
1455 							else
1456 							{
1457 								f |= NOISE_BRACE|NOISE_PAREN;
1458 								p = '}';
1459 							}
1460 							n = 1;
1461 							m = c;
1462 						}
1463 						else if (c == m) n++;
1464 						quot = 0;
1465 						continue;
1466 					case ')':
1467 					case '}':
1468 						if (c == p && --n <= 0)
1469 						{
1470 							if (c == '}') break;
1471 							m = '\n';
1472 							p = 0;
1473 						}
1474 						quot = 0;
1475 						continue;
1476 					case ' ':
1477 						continue;
1478 					case '\n':
1479 						error_info.line++;
1480 						if (!m) m = '\n';
1481 						continue;
1482 					case 0:
1483 						break;
1484 					case T_ID:
1485 						if (quot) continue;
1486 						/*FALLTHROUGH*/
1487 					default:
1488 						if (m == '\n')
1489 						{
1490 							/*
1491 							 * NOTE: token expanded again
1492 							 */
1493 
1494 							s = pp.toknxt;
1495 							while (s > pp.token) ungetchr(*--s);
1496 							*(pp.toknxt = s) = 0;
1497 							break;
1498 						}
1499 						continue;
1500 					}
1501 					break;
1502 				}
1503 				break;
1504 			case T_X_LINE:
1505 				for (;;)
1506 				{
1507 					ADVANCE();
1508 					switch (pplex())
1509 					{
1510 					case 0:
1511 						break;
1512 					case '\n':
1513 						error_info.line++;
1514 						break;
1515 					default:
1516 						continue;
1517 					}
1518 					break;
1519 				}
1520 				break;
1521 			case T_X_STATEMENT:
1522 				for (;;)
1523 				{
1524 					ADVANCE();
1525 					switch (pplex())
1526 					{
1527 					case 0:
1528 						break;
1529 					case ';':
1530 						ungetchr(';');
1531 						*(pp.toknxt = pp.token) = 0;
1532 						break;
1533 					default:
1534 						continue;
1535 					}
1536 					break;
1537 				}
1538 				break;
1539 			}
1540 			pp.comment = ppcomment;
1541 			if (f & NOISE_NOSPACEOUT)
1542 				pp.state &= ~SPACEOUT;
1543 			CACHEIN();
1544 			tp = pptoken;
1545 			op = pp.toknxt;
1546 			c = T_NOISES;
1547 		}
1548 		if (pp.option & NOISEFILTER)
1549 		{
1550 			BACKOUT();
1551 			goto fsm_top;
1552 		}
1553 	}
1554 
1555 							/*INDENT*/
1556 						}
1557 						else if ((pp.option & NOISE) && c == T_ID && strneq(tp, "__builtin_", 10))
1558 						{
1559 							hashlook(pp.symtab, tp, HASH_DELETE, NiL);
1560 							pp.symbol = sym = (struct ppsymbol*)ppkeyset(pp.symtab, tp);
1561 							sym->flags |= SYM_KEYWORD;
1562 							c = ((struct ppsymkey*)sym)->lex = T_BUILTIN;
1563 						}
1564 					}
1565 				}
1566 				goto fsm_symbol;
1567 			}
1568 			goto fsm_check;
1569 		}
1570 		if (pp.level == 1)
1571 		{
1572 			st &= ~(NEWLINE|PASSEOF);
1573 			pp.in->flags |= IN_tokens;
1574 		}
1575 		else st &= ~PASSEOF;
1576 		count(candidate);
1577 		SETCHR(0);
1578 		if (sym = ppsymref(pp.symtab, tp))
1579 		{
1580 			SYNCIN();
1581 			c = ppcall(sym, 1);
1582 			CACHEIN();
1583 			if (c >= 0)
1584 			{
1585 				BACKOUT();
1586 				if ((sym->flags & SYM_MULTILINE) && pp.linesync)
1587 				{
1588 					SYNCOUT();
1589 					(*pp.linesync)(error_info.line, error_info.file);
1590 					CACHEOUT();
1591 				}
1592 				goto fsm_top;
1593 			}
1594 		}
1595 		c = T_ID;
1596 		if (pp.level == 1)
1597 		{
1598 			if (st & NOTEXT)
1599 			{
1600 				BACKOUT();
1601 				goto fsm_top;
1602 			}
1603 			if (st & COMPILE)
1604 			{
1605 				if (pp.truncate && (op - tp) > pp.truncate)
1606 				{
1607 					tp[pp.truncate] = 0;
1608 					sym = 0;
1609 				}
1610 				if (!sym)
1611 				{
1612 					if (!(pp.option & NOHASH)) sym = ppsymset(pp.symtab, tp);
1613 					else if (!(sym = ppsymref(pp.symtab, tp))) goto fsm_symbol;
1614 				}
1615 				goto fsm_noise;
1616 			}
1617 			goto fsm_symbol;
1618 		}
1619 		goto fsm_check;
1620 #endif
1621 
1622 	case S_SHARP:
1623 		if (c == '(')
1624 		{
1625 			pp.in->flags |= IN_tokens;
1626 			if ((st & STRICT) && pp.in->type != IN_MACRO && pp.in->type != IN_MULTILINE)
1627 			{
1628 				if (!(pp.mode & HOSTED)) error(1, "non-standard reference to #(...)");
1629 				if (st & STRICT)
1630 				{
1631 					PUTCHR(c);
1632 #if CPP
1633 					st &= ~NEWLINE;
1634 					count(token);
1635 					goto fsm_start;
1636 #else
1637 					break;
1638 #endif
1639 				}
1640 			}
1641 			if (st & (COLLECTING|DEFINITION|DISABLE|SKIPCONTROL))
1642 			{
1643 				PUTCHR(c);
1644 #if CPP
1645 				st &= ~NEWLINE;
1646 				count(token);
1647 				goto fsm_start;
1648 #else
1649 				st &= ~NOEXPAND;
1650 				break;
1651 #endif
1652 			}
1653 			op--;
1654 			SYNC();
1655 			ppbuiltin();
1656 			CACHE();
1657 #if CPP
1658 			count(token);
1659 			goto fsm_start;
1660 #else
1661 			goto fsm_top;
1662 #endif
1663 		}
1664 		BACKIN();
1665 #if CPP
1666 		if (!(st & NEWLINE) || !(pp.in->type & IN_TOP))
1667 		{
1668  fsm_nondirective:
1669 			st &= ~NEWLINE;
1670 			pp.in->flags |= IN_tokens;
1671 			count(token);
1672 			goto fsm_start;
1673 		}
1674 		if (*(s = tp) != '#')
1675 		{
1676 #if COMPATIBLE
1677 			if ((st & (COMPATIBILITY|TRANSITION)) == COMPATIBILITY) goto fsm_nondirective;
1678 #endif
1679 			while (*s == ' ' || *s == '\t') s++;
1680 			if (*s != '#') goto fsm_nondirective;
1681 		}
1682 		BACKOUT();
1683 #else
1684 		if (!(st & NEWLINE) || (st & DEFINITION) || !(pp.in->type & IN_TOP))
1685 		{
1686 			if (c == '#')
1687 			{
1688 				SKIPIN();
1689 				if (!(st & DEFINITION))
1690 					PUTCHR(c);
1691 				c = T_TOKCAT;
1692 			}
1693 			else if (pp.level == 1 && !(st & (JOINING|SPACEOUT)) && !(pp.option & PRESERVE))
1694 			{
1695 				char*		pptoken;
1696 				char*		oop;
1697 				PPCOMMENT	ppcomment;
1698 
1699 				SYNCIN();
1700 				pp.toknxt = oop = op;
1701 				pp.state |= SPACEOUT;
1702 				ppcomment = pp.comment;
1703 				pp.comment = 0;
1704 				op = (pptoken = tp) + MAXTOKEN;
1705 				for (;;)
1706 				{
1707 					ADVANCE();
1708 					switch (pplex())
1709 					{
1710 					case 0:
1711 						break;
1712 					case '\n':
1713 						error_info.line++;
1714 						break;
1715 					default:
1716 						continue;
1717 					}
1718 					break;
1719 				}
1720 				pp.comment = ppcomment;
1721 				pp.state &= ~SPACEOUT;
1722 				CACHEIN();
1723 				tp = pptoken;
1724 				*--op = 0;
1725 				op = oop;
1726 				if (pp.pragma && !(st & NOTEXT))
1727 				{
1728 					*s = 0;
1729 					SYNC();
1730 					(*pp.pragma)(NiL, NiL, NiL, tp, 1);
1731 					CACHE();
1732 				}
1733 				if (!c) BACKIN();
1734 				goto fsm_top;
1735 			}
1736 			else c = '#';
1737 			break;
1738 		}
1739 		if ((st & (COLLECTING|STRICT)) == (COLLECTING|STRICT))
1740 			error(1, "directives in macro call arguments are not portable");
1741 #endif
1742 		if (c == '#' && pp.in->type == IN_RESCAN)
1743 		{
1744 			/*
1745 			 * pass line to pp.pragma VERBATIM
1746 			 */
1747 
1748 			SKIPIN();
1749 			s = pp.valbuf;
1750 			while ((c = GETCHR()) && c != '\n')
1751 				if ((*s++ = c) == MARK) SKIPIN();
1752 			if (pp.pragma && !(st & NOTEXT))
1753 			{
1754 				*s = 0;
1755 				SYNC();
1756 				(*pp.pragma)(NiL, NiL, NiL, pp.valbuf, 1);
1757 				CACHE();
1758 			}
1759 			if (!c) BACKIN();
1760 #if CPP
1761 			goto fsm_start;
1762 #else
1763 			goto fsm_top;
1764 #endif
1765 		}
1766 		SYNC();
1767 		ppcontrol();
1768 		CACHE();
1769 #if CPP
1770 		if (st & (NOTEXT|SKIPCONTROL))
1771 		{
1772 			if (!sp)
1773 			{
1774 				PPCHECKOUTTP();
1775 				sp = tp;
1776 			}
1777 		}
1778 		else if (sp)
1779 		{
1780 			tp = op = sp;
1781 			sp = 0;
1782 		}
1783 		goto fsm_start;
1784 #else
1785 		goto fsm_top;
1786 #endif
1787 
1788 	case S_NL:
1789 #if CPP
1790 		if (op == tp && !(st & JOINING) && pp.in->type == IN_FILE)
1791 		{
1792 			st |= NEWLINE|HIDDEN;
1793 			pp.hidden++;
1794 			error_info.line++;
1795 			goto fsm_start;
1796 		}
1797 #endif
1798  fsm_newline:
1799 #if CPP
1800 		if (sp)
1801 			op = sp;
1802 		else if (!(pp.in->flags & IN_noguard))
1803 		{
1804 			while (tp < op)
1805 				if ((c = *tp++) != ' ' && c != '\t')
1806 				{
1807 					pp.in->flags |= IN_tokens;
1808 					break;
1809 				}
1810 			c = '\n';
1811 		}
1812 		st |= NEWLINE;
1813 		error_info.line++;
1814 		if (*ip == '\n' && *(ip + 1) != '\n' && !pp.macref && !(st & (ADD|HIDDEN)))
1815 		{
1816 			ip++;
1817 			PUTCHR('\n');
1818 			error_info.line++;
1819 		}
1820 		if ((st & NOTEXT) && ((pp.mode & FILEDEPS) || (pp.option & (DEFINITIONS|PREDEFINITIONS))))
1821 			BACKOUT();
1822 		else
1823 		{
1824 			debug((-5, "token[%d] %03o = %s [line=%d]", pp.level, c, pptokchr(c), error_info.line));
1825 			PUTCHR('\n');
1826 			PPSYNCLINE();
1827 			if (sp)
1828 			{
1829 				PPCHECKOUT();
1830 				sp = op;
1831 			}
1832 		}
1833 		goto fsm_start;
1834 #else
1835 		st |= NEWLINE;
1836 		if (pp.level == 1)
1837 		{
1838 			error_info.line++;
1839 			if (!(st & (JOINING|SPACEOUT)))
1840 			{
1841 				debug((-5, "token[%d] %03o = %s [line=%d]", pp.level, c, pptokchr(c), error_info.line));
1842 				BACKOUT();
1843 				goto fsm_top;
1844 			}
1845 		}
1846 		BACKOUT();
1847 		if (st & SKIPCONTROL)
1848 		{
1849 			error_info.line++;
1850 			st |= HIDDEN;
1851 			pp.hidden++;
1852 			goto fsm_start;
1853 		}
1854 		PUTCHR(c = '\n');
1855 		goto fsm_return;
1856 #endif
1857 
1858 #if !CPP
1859 	case S_TOK:
1860 		PUTCHR(c);
1861 		c = TYPE(state) | qual;
1862 		break;
1863 
1864 	case S_TOKB:
1865 		BACKIN();
1866 		c = TYPE(state) | qual;
1867 		break;
1868 #endif
1869 
1870 	case S_VS:
1871 		PUTCHR(c);
1872 #if !CPP
1873 		if (st & NOVERTICAL)
1874 		{
1875 			error(1, "%s invalid in directives", pptokchr(c));
1876 			st &= ~NOVERTICAL;
1877 		}
1878 #endif
1879 #if COMPATIBLE
1880 		if (st & COMPATIBILITY) st |= NEWLINE;
1881 #endif
1882 #if CPP
1883 		if (!(pp.in->flags & IN_noguard))
1884 			while (tp < op)
1885 				if ((c = *tp++) != ' ' && c != '\t')
1886 				{
1887 					pp.in->flags |= IN_tokens;
1888 					break;
1889 				}
1890 		goto fsm_start;
1891 #else
1892 		bp = ip;
1893 		rp = fsm[WS1];
1894 		goto fsm_get;
1895 #endif
1896 
1897 #if !CPP
1898 	case S_WS:
1899 #if COMPATIBLE
1900 		if ((st & (COMPATIBILITY|TRANSITION)) == COMPATIBILITY) st &= ~NEWLINE;
1901 #endif
1902 		if (pp.level == 1)
1903 		{
1904 			if ((st & (COMPATIBILITY|SPACEOUT)) && !(st & TRANSITION))
1905 			{
1906 				if (st & (COMPILE|NOTEXT))
1907 				{
1908 #if CATSTRINGS
1909 					if ((st & (JOINING|NOTEXT|SPACEOUT)) != SPACEOUT)
1910 #else
1911 					if ((st & (NOTEXT|SPACEOUT)) != SPACEOUT)
1912 #endif
1913 					{
1914 						BACKOUT();
1915 						bp = ip - 1;
1916 						rp = fsm[START];
1917 						if (state = rp[c]) goto fsm_next;
1918 						goto fsm_get;
1919 					}
1920 				}
1921 				else
1922 #if CATSTRINGS
1923 				if (!(st & JOINING))
1924 #endif
1925 				{
1926 					tp = op;
1927 					bp = ip - 1;
1928 					rp = fsm[START];
1929 					if (state = rp[c]) goto fsm_next;
1930 					goto fsm_get;
1931 				}
1932 				BACKIN();
1933 				c = ' ';
1934 				goto fsm_return;
1935 			}
1936 			BACKOUT();
1937 			bp = ip - 1;
1938 			rp = fsm[START];
1939 			if (state = rp[c]) goto fsm_next;
1940 			goto fsm_get;
1941 		}
1942 		if (st & (NOSPACE|SKIPCONTROL))
1943 		{
1944 			BACKOUT();
1945 			bp = ip - 1;
1946 			rp = fsm[START];
1947 			if (state = rp[c]) goto fsm_next;
1948 			goto fsm_get;
1949 		}
1950 		if (c != '\n')
1951 		{
1952 			BACKIN();
1953 			c = ' ';
1954 		}
1955 		if (!(pp.option & PRESERVE))
1956 		{
1957 			BACKOUT();
1958 			PUTCHR(c);
1959 		}
1960 		goto fsm_return;
1961 #endif
1962 
1963 	default:
1964 		if (state & SPLICE)
1965 		{
1966 			switch (c)
1967 			{
1968 			case MARK:
1969 				/*
1970 				 * internal mark
1971 				 */
1972 
1973 				switch (pp.in->type)
1974 				{
1975 				case IN_BUFFER:
1976 				case IN_FILE:
1977 #if !CPP
1978 				case IN_INIT:
1979 #if CATSTRINGS
1980 					if ((st & JOINING) && (!INQUOTE(rp) || quot != '"') || pp.level > 1 && (rp == fsm[START] || INQUOTE(rp)))
1981 #else
1982 					if (pp.level > 1 && (rp == fsm[START] || INQUOTE(rp)))
1983 #endif
1984 						PUTCHR(c);
1985 #endif
1986 					break;
1987 				default:
1988 					switch (GETCHR())
1989 					{
1990 					case 'A':
1991 						if (!(st & (DEFINITION|DISABLE)))
1992 						{
1993 							c = GETCHR();
1994 							SYNCIN();
1995 							if (pp.macp->arg[c - ARGOFFSET][-1])
1996 								PUSH_EXPAND(pp.macp->arg[c - ARGOFFSET], pp.macp->line);
1997 							else
1998 								PUSH_COPY(pp.macp->arg[c - ARGOFFSET], pp.macp->line);
1999 							CACHEIN();
2000 							bp = ip;
2001 							goto fsm_get;
2002 						}
2003 						/*FALLTHROUGH*/
2004 					case 'C':
2005 						c = GETCHR() - ARGOFFSET;
2006 						if (!*(s = pp.macp->arg[c]) && (pp.in->symbol->flags & SYM_VARIADIC) && pp.in->symbol->macro->arity == (c + 1))
2007 						{
2008 							s = ip - 3;
2009 							while (--op > tp && --s > bp && ppisidig(*s));
2010 						}
2011 						else
2012 						{
2013 							SYNCIN();
2014 							PUSH_COPY(s, pp.macp->line);
2015 							CACHEIN();
2016 						}
2017 						bp = ip;
2018 						goto fsm_get;
2019 					case 'F':
2020 						error_info.file = (char*)strtoul(ip, &s, 16);
2021 						debug((-6, "actual sync: file = \"%s\"", error_info.file));
2022 						bp = ip = s + 1;
2023 						goto fsm_get;
2024 					case 'L':
2025 						error_info.line = strtoul(ip, &s, 16);
2026 						debug((-6, "actual sync: line = %d", error_info.line));
2027 						bp = ip = s + 1;
2028 						goto fsm_get;
2029 					case 'Q':
2030 						c = GETCHR();
2031 						SYNCIN();
2032 						PUSH_QUOTE(pp.macp->arg[c - ARGOFFSET], pp.macp->line);
2033 						CACHEIN();
2034 						bp = ip - 1;
2035 						if (st & (COLLECTING|EOF2NL|JOINING)) rp = fsm[START];
2036 						if (state = rp[c = '"']) goto fsm_next;
2037 						goto fsm_get;
2038 					case 'S':
2039 						c = GETCHR();
2040 						SYNCIN();
2041 						PUSH_SQUOTE(pp.macp->arg[c - ARGOFFSET], pp.macp->line);
2042 						CACHEIN();
2043 						bp = ip - 1;
2044 						if (st & COLLECTING) rp = fsm[START];
2045 						if (state = rp[c = '\'']) goto fsm_next;
2046 						goto fsm_get;
2047 					case 'X':
2048 						if (pp.in->type != IN_COPY)
2049 							st |= SKIPMACRO;
2050 						if (pp.level <= 1)
2051 						{
2052 							bp = ip;
2053 							goto fsm_get;
2054 						}
2055 						if (pp.in->type == IN_EXPAND)
2056 						{
2057 							st &= ~SKIPMACRO;
2058 							PUTCHR(c);
2059 							PUTCHR('X');
2060 						}
2061 						c = GETCHR();
2062 						break;
2063 					case 0:
2064 						if ((state &= ~SPLICE) >= TERMINAL) goto fsm_terminal;
2065 						goto fsm_begin;
2066 					default:
2067 #if DEBUG
2068 						error(PANIC, "invalid mark op `%c'", LASTCHR());
2069 						/*FALLTHROUGH*/
2070 					case MARK:
2071 #endif
2072 #if CATSTRINGS
2073 						if ((st & (JOINING|QUOTE)) == JOINING)
2074 						{
2075 							if (!INQUOTE(rp))
2076 								PUTCHR(c);
2077 						}
2078 						else
2079 #endif
2080 #if CPP
2081 						if (rp != fsm[START] && !INQUOTE(rp))
2082 							UNGETCHR(c);
2083 #else
2084 						if (rp != fsm[START] && !INQUOTE(rp))
2085 							UNGETCHR(c);
2086 						else if (pp.level > 1)
2087 							PUTCHR(c);
2088 #endif
2089 						break;
2090 					}
2091 					break;
2092 				}
2093 				break;
2094 			case '?':
2095 				/*
2096 				 * trigraph
2097 				 */
2098 
2099 				if (pp.in->type == IN_FILE)
2100 				{
2101 					GET(c, n, tp, xp);
2102 					if (n == '?')
2103 					{
2104 						GET(c, n, tp, xp);
2105 						if (c = trigraph[n])
2106 						{
2107 							if ((st & WARN) && (st & (COMPATIBILITY|TRANSITION)) && !(pp.mode & HOSTED) && !INCOMMENT(rp))
2108 								error(1, "trigraph conversion %c%c%c -> %c%s", '?', '?', n, c, (st & TRANSITION) ? "" : " inhibited");
2109 #if COMPATIBLE
2110 							if ((st & (COMPATIBILITY|TRANSITION)) != COMPATIBILITY)
2111 							{
2112 #endif
2113 							*(bp = ip - 1) = c;
2114 							if (state = rp[c]) goto fsm_next;
2115 							goto fsm_get;
2116 #if COMPATIBLE
2117 							}
2118 #endif
2119 						}
2120 						if (n != EOB) BACKIN();
2121 						UNGETCHR(c = '?');
2122 					}
2123 					else if (n != EOB) BACKIN();
2124 				}
2125 				break;
2126 			case '%':
2127 			case '<':
2128 			case ':':
2129 				/*
2130 				 * digraph = --trigraph
2131 				 */
2132 
2133 				if (pp.in->type == IN_FILE && (pp.option & PLUSPLUS))
2134 				{
2135 					m = 0;
2136 					GET(c, n, tp, xp);
2137 					switch (n)
2138 					{
2139 					case '%':
2140 						if (c == '<') m = '{';
2141 						break;
2142 					case '>':
2143 						if (c == '%') m = '}';
2144 						else if (c == ':') m = ']';
2145 						break;
2146 					case ':':
2147 						if (c == '%') m = '#';
2148 						else if (c == '<') m = '[';
2149 						break;
2150 					}
2151 					if (m)
2152 					{
2153 						if ((st & WARN) && (st & (COMPATIBILITY|TRANSITION)) && !(pp.mode & HOSTED) && !INCOMMENT(rp))
2154 							error(1, "digraph conversion %c%c -> %c%s", c, n, m, (st & TRANSITION) ? "" : " inhibited");
2155 #if COMPATIBLE
2156 						if ((st & (COMPATIBILITY|TRANSITION)) != COMPATIBILITY)
2157 						{
2158 #endif
2159 						*(bp = ip - 1) = c = m;
2160 						if (state = rp[c]) goto fsm_next;
2161 						goto fsm_get;
2162 #if COMPATIBLE
2163 						}
2164 #endif
2165 					}
2166 					if (n != EOB) BACKIN();
2167 				}
2168 				break;
2169 			case '\\':
2170 				/*
2171 				 * line splice
2172 				 */
2173 
2174 				if (pp.in->type == IN_FILE && (!(pp.option & PLUSSPLICE) || !INCOMMENTXX(rp)))
2175 				{
2176 					m = 0;
2177 					GET(c, n, tp, xp);
2178 					if ((pp.option & SPLICESPACE) && !INQUOTE(rp))
2179 						while (n == ' ')
2180 						{
2181 							GET(c, n, tp, xp);
2182 							m = 1;
2183 						}
2184 					if (n == '\r')
2185 					{
2186 						GET(c, n, tp, xp);
2187 						if (n != '\n' && n != EOB)
2188 							BACKIN();
2189 					}
2190 					if (n == '\n')
2191 					{
2192 #if CPP
2193 						if (INQUOTE(rp))
2194 						{
2195 							if ((pp.option & STRINGSPLIT) && quot == '"')
2196 							{
2197 								PUTCHR(quot);
2198 								PUTCHR(n);
2199 								PUTCHR(quot);
2200 							}
2201 							else if (*pp.lineid)
2202 							{
2203 								PUTCHR(c);
2204 								PUTCHR(n);
2205 							}
2206 							else
2207 							{
2208 								st |= HIDDEN;
2209 								pp.hidden++;
2210 							}
2211 						}
2212 						else
2213 #else
2214 #if COMPATIBLE
2215 						if (!INQUOTE(rp) && (st & (COMPATIBILITY|DEFINITION|TRANSITION)) == (COMPATIBILITY|DEFINITION))
2216 						{
2217 							if (op == tp)
2218 							{
2219 								st |= HIDDEN;
2220 								pp.hidden++;
2221 								error_info.line++;
2222 								if (st & SPACEOUT)
2223 									goto fsm_start;
2224 								c = (pp.option & SPLICECAT) ? '\t' : ' ';
2225 								PUTCHR(c);
2226 								goto fsm_check;
2227 							}
2228 							UNGETCHR(n);
2229 							state &= ~SPLICE;
2230 							goto fsm_terminal;
2231 						}
2232 #endif
2233 #endif
2234 						{
2235 							st |= HIDDEN;
2236 							pp.hidden++;
2237 						}
2238 #if CPP
2239 						spliced++;
2240 #else
2241 						error_info.line++;
2242 #endif
2243 						bp = ip;
2244 						goto fsm_get;
2245 					}
2246 					else if ((n == 'u' || n == 'U') && !INQUOTE(rp))
2247 					{
2248 						PUTCHR(c);
2249 						PUTCHR(n);
2250 						bp = ip;
2251 						goto fsm_get;
2252 					}
2253 #if COMPATIBLE
2254 					else if ((st & (COMPATIBILITY|TRANSITION)) == COMPATIBILITY && (n == '"' || n == '\'') && !INQUOTE(rp))
2255 					{
2256 						PUTCHR(c);
2257 						PUTCHR(n);
2258 						bp = ip;
2259 						goto fsm_get;
2260 					}
2261 #endif
2262 					else if (n != EOB)
2263 						BACKIN();
2264 					if (m && INSPACE(rp))
2265 						UNGETCHR(c);
2266 				}
2267 #if COMPATIBLE
2268 				else if ((st & (COMPATIBILITY|TRANSITION)) == COMPATIBILITY && !INQUOTE(rp))
2269 				{
2270 					GET(c, n, tp, xp);
2271 					if (n == '"' || n == '\'')
2272 					{
2273 						PUTCHR(c);
2274 						PUTCHR(n);
2275 						bp = ip;
2276 						goto fsm_get;
2277 					}
2278 					if (n != EOB)
2279 						BACKIN();
2280 				}
2281 #endif
2282 				break;
2283 			case '\r':
2284 				/*
2285 				 * barf
2286 				 */
2287 
2288 				if (pp.in->type == IN_FILE)
2289 				{
2290 					GET(c, n, tp, xp);
2291 					if (n == '\n')
2292 					{
2293 						*(bp = ip - 1) = c = n;
2294 						if (state = rp[c]) goto fsm_next;
2295 						goto fsm_get;
2296 					}
2297 					if (n != EOB) BACKIN();
2298 				}
2299 				break;
2300 			case CC_sub:
2301 				/*
2302 				 * barf & puke
2303 				 */
2304 
2305 				if ((pp.option & ZEOF) && pp.in->type == IN_FILE)
2306 				{
2307 					pp.in->flags |= IN_eof;
2308 					c = 0;
2309 					state = S_EOB;
2310 					goto fsm_terminal;
2311 				}
2312 				break;
2313 			}
2314 			if ((state &= ~SPLICE) >= TERMINAL)
2315 				goto fsm_terminal;
2316 			PUTCHR(c);
2317 			goto fsm_begin;
2318 		}
2319 #if CPP
2320 		if (INOPSPACE(rp))
2321 		{
2322 			BACKIN();
2323 			goto fsm_start;
2324 		}
2325 #endif
2326 		PUTCHR(c);
2327 		bp = ip;
2328 		goto fsm_get;
2329 	}
2330 #if !CPP
2331  fsm_token:
2332 	st &= ~NEWLINE;
2333 	if (pp.level == 1)
2334 	{
2335 		pp.in->flags |= IN_tokens;
2336 		if (st & NOTEXT)
2337 		{
2338 			BACKOUT();
2339 			goto fsm_top;
2340 		}
2341  fsm_symbol:
2342 		count(token);
2343 	}
2344  fsm_check:
2345 	if (st & SKIPCONTROL)
2346 	{
2347 		BACKOUT();
2348 		goto fsm_start;
2349 	}
2350  fsm_return:
2351 #if CPP
2352 	error_info.line += spliced;
2353 #endif
2354 	SETCHR(0);
2355 	debug((-5, "token[%d] %03o = %s", pp.level, c, pptokstr(tp, 0)));
2356 	SYNC();
2357 	pp.level--;
2358 	error_info.indent--;
2359 	return c;
2360 #endif
2361 }
2362 
2363 #if CPP && POOL
2364 
2365 #include <ls.h>
2366 #include <wait.h>
2367 
2368 /*
2369  * output pool status on exit
2370  */
2371 
2372 static void
2373 poolstatus(void)
2374 {
2375 	error(ERROR_OUTPUT|0, pp.pool.output, "%d", error_info.errors != 0);
2376 }
2377 
2378 /*
2379  * loop on < input output >
2380  */
2381 
2382 static void
2383 pool(void)
2384 {
2385 	char*	ifile;
2386 	char*	ofile;
2387 
2388 	ppflushout();
2389 	if (!sfnew(sfstdin, NiL, SF_UNBOUND, pp.pool.input, SF_READ))
2390 		error(ERROR_SYSTEM|3, "cannot dup pool input");
2391 
2392 	/*
2393 	 * kick the -I cache
2394 	 */
2395 
2396 	ppsearch(".", T_STRING, SEARCH_EXISTS);
2397 
2398 	/*
2399 	 * loop on < input output >
2400 	 */
2401 
2402 	pp.pool.input = 0;
2403 	while (ifile = sfgetr(sfstdin, '\n', 1))
2404 	{
2405 		if (!(ofile = strchr(ifile, ' ')))
2406 			error(3, "%s: pool output file expected", ifile);
2407 		*ofile++ = 0;
2408 		waitpid(0, NiL, WNOHANG);
2409 		switch (fork())
2410 		{
2411 		case -1:
2412 			error(ERROR_SYSTEM|3, "cannot fork pool");
2413 		case 0:
2414 			atexit(poolstatus);
2415 			error_info.errors = 0;
2416 			error_info.warnings = 0;
2417 			close(0);
2418 			if (open(ifile, O_RDONLY))
2419 				error(ERROR_SYSTEM|3, "%s: cannot read", ifile);
2420 			close(1);
2421 			if (open(ofile, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH) != 1)
2422 				error(ERROR_SYSTEM|3, "%s: cannot create", ofile);
2423 			pp.outfile = ofile;
2424 			pathcanon(ifile, 0);
2425 			ifile = ppsetfile(ifile)->name;
2426 #if CHECKPOINT
2427 			if (pp.mode & DUMP)
2428 			{
2429 				if (!pp.pragma)
2430 					error(3, "#%s must be enabled for checkpoints", dirname(PRAGMA));
2431 				(*pp.pragma)(dirname(PRAGMA), pp.pass, keyname(X_CHECKPOINT), pp.checkpoint, 1);
2432 			}
2433 #endif
2434 			PUSH_FILE(ifile, 0);
2435 			return;
2436 		}
2437 	}
2438 	while (wait(NiL) != -1);
2439 }
2440 
2441 #endif
2442