xref: /illumos-gate/usr/src/contrib/ast/src/lib/libpp/pplex.c (revision b30d193948be5a7794d7ae3ba0ed9c2f72c88e0f)
1 /***********************************************************************
2 *                                                                      *
3 *               This software is part of the ast package               *
4 *          Copyright (c) 1986-2011 AT&T Intellectual Property          *
5 *                      and is licensed under the                       *
6 *                 Eclipse Public License, Version 1.0                  *
7 *                    by AT&T Intellectual Property                     *
8 *                                                                      *
9 *                A copy of the License is available at                 *
10 *          http://www.eclipse.org/org/documents/epl-v10.html           *
11 *         (with md5 checksum b35adb5213ca9657e911e9befb180842)         *
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
ppcpp(void)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) && !(pp.option & PRESERVE))
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 				if ((pp.option & PRESERVE) && !(st & NEWLINE) && c != '\n')
249 					break;
250 				PPSYNCLINE();
251 				tp = op;
252 				break;
253 			}
254 #endif
255 		MEMCPY(op, ip, n);
256 		ip++;
257 	}
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))
265 	{
266 
267 #if !CPP
268 	case S_CHR:
269 		PUTCHR(c);
270 		break;
271 #endif
272 
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
284 
285 	case S_COMMENT:
286 		switch (c)
287 		{
288 		case '\n':
289 			if (!INCOMMENTXX(rp))
290 			{
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
304 			}
305 			else if (comwarn < 0 && !(pp.mode & HOSTED))
306 				error(1, "/* appears in // comment");
307 			break;
308 		case '*':
309 			if (!comwarn && !(pp.mode & HOSTED))
310 			{
311 				if (INCOMMENTXX(rp)) comwarn = -1;
312 				else if (comstart && comstart != error_info.line)
313 				{
314 					if (qual || comdelim < error_info.line - 1)
315 					{
316 						error(1, "/* appears in /* ... */ comment starting at line %d", comstart);
317 						comwarn = 1;
318 					}
319 					else comdelim = error_info.line;
320 				}
321 			}
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))
334 			{
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
348 			}
349 			else if (INCOMMENTXX(rp))
350 			{
351 				if (!(pp.mode & HOSTED))
352 				{
353 					if (comwarn < 0) comwarn = 0;
354 					else if (!comwarn)
355 					{
356 						comwarn = 1;
357 						error(1, "*/ appears in // comment");
358 					}
359 				}
360 				goto fsm_comment;
361 			}
362 			break;
363 		case EOF:
364 			BACKIN();
365 			if (!(pp.mode & HOSTED))
366 			{
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");
370 			}
371 			break;
372 		}
373 #if CPP
374 		if (!pp.comment || sp)
375 		{
376 #if COMPATIBLE
377 			if (!(pp.state & COMPATIBILITY) || *bp == ' ' || *bp == '\t')
378 #endif
379 			{
380 				BACKOUT();
381 				PUTCHR(' ');
382 				tp = op;
383 			}
384 		}
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
389 		{
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;
400 		}
401 		if (comstart)
402 		{
403 			st |= HIDDEN;
404 			pp.hidden += error_info.line - comstart;
405 			comstart = 0;
406 		}
407 		qual = comwarn = comdelim = 0;
408 		BACKOUT();
409 		if (c == '\n') goto fsm_newline;
410 		if ((st & PASSTHROUGH) && ((st & (HIDDEN|NEWLINE)) || *ip == '\n'))
411 		{
412 			if (*ip == '\n')
413 				ip++;
414 			goto fsm_newline;
415 		}
416 #if COMPATIBLE
417 		if ((st & (COMPATIBILITY|TRANSITION)) == COMPATIBILITY) st &= ~NEWLINE;
418 #endif
419 #if !CPP
420 		if (pp.level > 1 && !(st & (NOSPACE|SKIPCONTROL)))
421 		{
422 #if COMPATIBLE
423 			c = ((st & (COMPATIBILITY|DEFINITION)) == ((COMPATIBILITY|DEFINITION))) ? '\t' : ' ';
424 #else
425 			c = ' ';
426 #endif
427 			goto fsm_return;
428 		}
429 #endif
430 		goto fsm_start;
431 
432 	case S_EOB:
433 		if (c)
434 		{
435 			if (state = fsm[TERMINAL][INDEX(rp)+1])
436 				goto fsm_terminal;
437 #if CPP
438 #if POOL
439 			if (pp.pool.input)
440 			{
441 				BACKIN();
442 				SYNC();
443 				pool();
444 				CACHE();
445 				goto fsm_pool;
446 			}
447 #endif
448 			SYNCOUT();
449 			return;
450 #else
451 			BACKIN();
452 			c = 0;
453 			goto fsm_return;
454 #endif
455 		}
456 		{
457 			register struct ppinstk*	cur = pp.in;
458 			register struct ppinstk*	prv = pp.in->prev;
459 
460 #if CPP
461 			if (sp) op = sp;
462 #endif
463 			switch (cur->type)
464 			{
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
473 				{
474 					if (cur->type == IN_RESCAN || cur->type == IN_BUFFER)
475 					{
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);
484 					}
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)
495 					{
496 						pp.mode |= HOSTED;
497 						pp.flags |= PP_hosted;
498 					}
499 					else
500 					{
501 						pp.mode &= ~HOSTED;
502 						pp.flags &= ~PP_hosted;
503 					}
504 #if !CPP && CATSTRINGS
505 					if (st & JOINING) st |= HIDDEN|SYNCLINE;
506 					else
507 #endif
508 					{
509 						st &= ~(HIDDEN|SYNCLINE);
510 						switch (cur->type)
511 						{
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))
519 							{
520 								if (pp.linesync && (cur->type != IN_RESCAN || (cur->flags & IN_sync)))
521 								{
522 									POP();
523 									SYNCOUT();
524 									(*pp.linesync)(error_info.line, error_info.file);
525 									CACHEOUT();
526 									prv = pp.in;
527 								}
528 							}
529 #if DEBUG
530 							else if (!prv->prev)
531 							{
532 								/*UNDENT*/
533 	c = 0;
534 #if DEBUG & TRACE_count
535 	if (pp.test & TEST_count)
536 	{
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);
546 	}
547 #endif
548 #if CPP && (DEBUG & TRACE_debug)
549 	if (pp.test & TEST_hit)
550 	{
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));
558 	}
559 #endif
560 	if (pp.test & (TEST_hashcount|TEST_hashdump))
561 	{
562 		c = 1;
563 		sfprintf(sfstderr, "\n");
564 		hashdump(NiL, (pp.test & TEST_hashdump) ? HASH_BUCKET : 0);
565 	}
566 	if (c) sfprintf(sfstderr, "\n");
567 								/*INDENT*/
568 							}
569 #endif
570 							break;
571 						}
572 					}
573 #if CHECKPOINT
574 					if (cur->index)
575 					{
576 						SYNCOUT();
577 						cur->index->end = ppoffset();
578 						cur->index = 0;
579 						CACHEOUT();
580 					}
581 #endif
582 					POP();
583 					bp = ip;
584 					tp = op;
585 					goto fsm_get;
586 				}
587 				c = EOF;
588 				break;
589 			case IN_COPY:
590 				if (prv)
591 				{
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;
598 				}
599 				c = EOF;
600 				break;
601 			case IN_EXPAND:
602 				if (prv)
603 				{
604 					error_info.line = cur->line;
605 					free(cur->buffer);
606 					POP();
607 					bp = ip;
608 					goto fsm_get;
609 				}
610 				c = EOF;
611 				break;
612 			case IN_FILE:
613 				FGET(c, c, tp, xp);
614 				if (c == EOB)
615 				{
616 #if CPP
617 					if ((st & (NOTEXT|HIDDEN)) == HIDDEN && LASTOUT() != '\n')
618 						PUTCHR('\n');
619 					if (prv)
620 #else
621 					if (st & EOF2NL)
622 					{
623 						st &= ~EOF2NL;
624 						*(ip - 1) = c = '\n';
625 					}
626 					else if (!(st & (FILEPOP|PASSEOF)) && prv)
627 #endif
628 					{
629 						if (!(cur->flags & IN_newline))
630 						{
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';
635 						}
636 						else
637 						{
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))
643 							{
644 								SYNCOUT();
645 								(*pp.incref)(error_info.file, cur->file, error_info.line - 1, PP_SYNC_POP);
646 								CACHEOUT();
647 							}
648 							goto fsm_pop;
649 						}
650 					}
651 					else
652 						c = EOF;
653 				}
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
665 				{
666 					if (cur->type == IN_MULTILINE)
667 					{
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)
674 						{
675 							SYNCOUT();
676 							(*pp.linesync)(error_info.line, error_info.file);
677 							CACHEOUT();
678 						}
679 					}
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;
689 				}
690 				c = EOF;
691 				break;
692 			case IN_QUOTE:
693 				if (prv)
694 				{
695 					error_info.line = cur->line;
696 					st &= ~(ESCAPE|QUOTE);
697 					POP();
698 					c = '"';
699 				}
700 				else c = EOF;
701 				break;
702 			case IN_SQUOTE:
703 				if (prv)
704 				{
705 					error_info.line = cur->line;
706 					st &= ~(ESCAPE|SQUOTE);
707 					POP();
708 					c = '\'';
709 				}
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
718 				{
719 					if (cur->flags & IN_disable) st |= DISABLE;
720 					else st &= ~DISABLE;
721 					POP();
722 					bp = ip;
723 					goto fsm_get;
724 				}
725 				c = EOF;
726 				break;
727 			default:
728 				c = EOF;
729 				break;
730 			}
731 		}
732 		bp = ip - 1;
733 		if (state = rp[c]) goto fsm_next;
734 		goto fsm_get;
735 
736 #if !CPP
737 	case S_HUH:
738 		if (INOPSPACE(rp))
739 		{
740 			if (c == '=')
741 			{
742 #if PROTOTYPE
743 				if (pp.in->flags & IN_prototype) PUTCHR(c);
744 				else
745 				{
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
751 				}
752 #endif
753 				switch (*tp)
754 				{
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;
785 				}
786 			}
787 			else
788 			{
789 				BACKIN();
790 				switch (c = *tp)
791 				{
792 				case '<':
793 					c = T_LSHIFT;
794 					break;
795 				case '>':
796 					c = T_RSHIFT;
797 					break;
798 				}
799 			}
800 		}
801 		else if (pp.level > 1 || (pp.option & PRESERVE)) PUTCHR(c);
802 		else if (tp == op)
803 		{
804 			if (pp.in->type != IN_BUFFER)
805 			{
806 				if (!(pp.option & ALLPOSSIBLE))
807 					error(1, "%s: invalid character ignored", pptokchr(c));
808 				goto fsm_top;
809 			}
810 			PUTCHR(c);
811 		}
812 		else if (*tp == ':')
813 		{
814 			PUTCHR(c);
815 			if (c == '=') error(2, "real programmers use =");
816 			else c = '+';
817 		}
818 		else
819 		{
820 			BACKIN();
821 			c = *tp;
822 		}
823 		break;
824 #endif
825 
826 	case S_QUAL:
827 		if ((state = NEXT(state)) != LIT1)
828 		{
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)
839 			{
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;
864 			}
865 #endif
866 			goto fsm_get;
867 		}
868 #if !CPP
869 		qual |= N_WIDE;
870 		if (DOSTRIP()) BACKOUT();
871 #endif
872 		/*FALLTHROUGH*/
873 
874 	case S_LITBEG:
875 #if CPP
876 		quot = c;
877 		rp = fsm[LIT1];
878 		if (op == tp)
879 		{
880 			PPSYNCLINE();
881 			tp = op;
882 		}
883 #else
884 		if ((quot = c) == '<')
885 		{
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)
887 			{
888 				PUTCHR(c);
889 				bp = ip;
890 				rp = fsm[LT1];
891 				goto fsm_get;
892 			}
893 			quot = '>';
894 			rp = fsm[HDR1];
895 		}
896 		else rp = fsm[LIT1];
897 		if (!DOSTRIP())
898 #endif
899 		PUTCHR(c);
900 		bp = ip;
901 		goto fsm_get;
902 
903 	case S_LITEND:
904 		n = 1;
905 		if (c != quot)
906 		{
907 			if (c != '\n' && c != EOF)
908 			{
909 				if (st & (QUOTE|SQUOTE))
910 				{
911 					if (!(st & ESCAPE))
912 					{
913 						st |= ESCAPE;
914 						quotquot = c;
915 					}
916 					else if (c == quotquot) st &= ~ESCAPE;
917 				}
918 				PUTCHR(c);
919 				bp = ip;
920 				goto fsm_get;
921 			}
922 #if CPP
923 			if ((st & PASSTHROUGH) || (pp.option & PRESERVE))
924 			{
925 				if (c == '\n') goto fsm_newline;
926 				bp = ip;
927 				goto fsm_start;
928 			}
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
936 			{
937 				switch (quot)
938 				{
939 				case '"':
940 					if (c == '\n')
941 					{
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))
946 						{
947 							PUTCHR('\\');
948 							c = 'n';
949 						}
950 						else if (pp.option & STRINGSPLIT)
951 						{
952 							PUTCHR('\\');
953 							PUTCHR('n');
954 							PUTCHR('"');
955 							PUTCHR('\n');
956 							c = '"';
957 						}
958 						PUTCHR(c);
959 						bp = ip;
960 						goto fsm_get;
961 					}
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;
975 				}
976 #if !CPP
977 				if (!DOSTRIP())
978 #endif
979 				PUTCHR(quot);
980 			}
981 			if (c == '\n')
982 			{
983 				UNGETCHR(c);
984 				c = quot;
985 			}
986 		}
987 		else if (st & (SQUOTE|QUOTE))
988 		{
989 			if (!(st & ESCAPE))
990 			{
991 				st |= ESCAPE;
992 				quotquot = c;
993 			}
994 			else if (c == quotquot) st &= ~ESCAPE;
995 			PUTCHR('\\');
996 			PUTCHR(c);
997 			bp = ip;
998 			goto fsm_get;
999 		}
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
1011 		{
1012 			char*	pptoken;
1013 			long	ppstate;
1014 
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);
1023 
1024 			/*
1025 			 * revert to the top level since string
1026 			 * concatenation crosses file boundaries
1027 			 * (allowing intervening directives)
1028 			 */
1029 
1030 			pp.level = 0;
1031 			SYNCIN();
1032 			m = n = 0;
1033 			for (;;)
1034 			{
1035 				switch (c = pplex())
1036 				{
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
1052 					{
1053 						n = m;
1054 						*(op - 1) = '\\';
1055 						*op++ = '\n';
1056 					}
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
1065 					{
1066 						n = m;
1067 						*(op - 1) = '\\';
1068 						*op++ = '\n';
1069 					}
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)
1078 					{
1079 						if (--m)
1080 						{
1081 							pp.state |= HIDDEN|SYNCLINE;
1082 							pp.hidden += m;
1083 						}
1084 #if COMPATIBLE
1085 						if ((st & COMPATIBILITY) && c == '#' && *(pp.token - 1))
1086 						{
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);
1091 						}
1092 						error_info.line--;
1093 						*--pp.token = '\n';
1094 #endif
1095 					}
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))
1101 					{
1102 						*(s + 1) = MARK;
1103 						*(s + 2) = 0;
1104 					}
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;
1111 				}
1112 				break;
1113 			}
1114 			pp.token = pptoken;
1115 			CACHEIN();
1116 			pp.level = 1;
1117 #if !CPP
1118 			c = T_STRING | qual;
1119 			break;
1120 #endif
1121 		}
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)
1136 		{
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;
1149 		}
1150 		break;
1151 #endif
1152 
1153 	case S_LITESC:
1154 		if (st & (COLLECTING|DIRECTIVE|QUOTE|SQUOTE))
1155 		{
1156 			if (st & ESCAPE)
1157 			{
1158 				PUTCHR('\\');
1159 				if (c == quot) PUTCHR('\\');
1160 			}
1161 			PUTCHR(c);
1162 		}
1163 #if CPP
1164 		else if (st & PASSTHROUGH) PUTCHR(c);
1165 #endif
1166 		else if (pp.option & PRESERVE) PUTCHR(c);
1167 		else switch (c)
1168 		{
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 #endif
1186 			/*FALLTHROUGH*/
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++)
1197 			{
1198 				GET(c, c, tp, xp);
1199 				switch (c)
1200 				{
1201 #if COMPATIBLE
1202 				case '8':
1203 				case '9':
1204 					if (!(st & COMPATIBILITY))
1205 					{
1206 						UNGETCHR(c);
1207 						break;
1208 					}
1209 					if (st & STRICT) error(1, "%c: invalid character in octal character escape", c);
1210 #endif
1211 					/*FALLTHROUGH*/
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;
1225 				}
1226 				break;
1227 			}
1228 			if (n & ~0777) error(1, "octal character constant too large");
1229 			goto octal;
1230 		case 'a':
1231 			if (pp.option & MODERN)
1232 			{
1233 				PUTCHR(c);
1234 				break;
1235 			}
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)
1243 			{
1244 				PUTCHR(c);
1245 				break;
1246 			}
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++)
1259 			{
1260 				GET(c, c, tp, xp);
1261 				switch (c)
1262 				{
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;
1295 				}
1296 				break;
1297 			}
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;
1309 		}
1310 		state = LIT1;
1311 		goto fsm_begin;
1312 
1313 	case S_MACRO:
1314 		BACKIN();
1315 #if CPP
1316 		if (st & (DISABLE|SKIPCONTROL|SKIPMACRO))
1317 		{
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;
1324 		}
1325 		count(candidate);
1326 		SETCHR(0);
1327 		switch (state = INDEX(rp))
1328 		{
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;
1341 		}
1342 		if (sym = ppsymref(pp.symtab, tp))
1343 		{
1344 			SYNCIN();
1345 			n = ppcall(sym, 0);
1346 			CACHEIN();
1347 			if (n >= 0)
1348 			{
1349 				BACKOUT();
1350 				if (!n)
1351 				{
1352 					if (sp) op = sp;
1353 					else
1354 					{
1355 						s = ip;
1356 						ip = sym->macro->value;
1357 						c = sym->macro->size;
1358 						while (c > 0)
1359 						{
1360 							if (op + c < xp + PPBUFSIZ) n = c;
1361 							else n = xp + PPBUFSIZ - op;
1362 							MEMCPY(op, ip, n);
1363 							c -= n;
1364 							PPCHECKOUT();
1365 						}
1366 						ip = s;
1367 					}
1368 				}
1369 				else if ((sym->flags & SYM_MULTILINE) && pp.linesync)
1370 				{
1371 					SYNCOUT();
1372 					if (!(state & NEWLINE))
1373 						ppputchar('\n');
1374 					(*pp.linesync)(error_info.line, error_info.file);
1375 					CACHEOUT();
1376 				}
1377 			}
1378 		}
1379 		pp.in->flags |= IN_tokens;
1380 		goto fsm_start;
1381 #else
1382 		if (st & (COLLECTING|DEFINITION|DISABLE|SKIPCONTROL|SKIPMACRO))
1383 		{
1384 			if (st & SKIPMACRO)
1385 				pp.mode |= MARKMACRO;
1386 			st &= ~(NEWLINE|NOEXPAND|SKIPMACRO);
1387 			c = T_ID;
1388 			if (pp.level == 1)
1389 			{
1390 				pp.in->flags |= IN_tokens;
1391 				if (st & NOTEXT)
1392 				{
1393 					BACKOUT();
1394 					goto fsm_top;
1395 				}
1396 				if (st & COMPILE)
1397 				{
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)
1403 					{
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)))
1405 						{
1406 							c = ((struct ppsymkey*)sym)->lex;
1407 							/*UNDENT*/
1408 
1409 #define ADVANCE()	do{if(pp.toknxt<op)pp.token=pp.toknxt;}while(0)
1410 
1411 #define NOISE_BRACE		01
1412 #define NOISE_NOSPACEOUT	02
1413 #define NOISE_PAREN		04
1414 
1415 	if ((pp.option & NOISE) && ppisnoise(c))
1416 	{
1417 		if (c != T_NOISE)
1418 		{
1419 			int		p;
1420 			int		f;
1421 			char*		pptoken;
1422 			PPCOMMENT	ppcomment;
1423 
1424 			SYNCIN();
1425 			pp.toknxt = op;
1426 			f = 0;
1427 			if (!(pp.state & SPACEOUT))
1428 			{
1429 				pp.state |= SPACEOUT;
1430 				f |= NOISE_NOSPACEOUT;
1431 			}
1432 			ppcomment = pp.comment;
1433 			pp.comment = 0;
1434 			op = (pptoken = tp) + MAXTOKEN;
1435 			switch (c)
1436 			{
1437 			case T_X_GROUP:
1438 				m = p = 0;
1439 				quot = 1;
1440 				for (;;)
1441 				{
1442 					ADVANCE();
1443 					switch (c = pplex())
1444 					{
1445 					case '(':
1446 					case '{':
1447 						if (!p)
1448 						{
1449 							if (c == '(')
1450 							{
1451 								if (f & NOISE_PAREN)
1452 								{
1453 									ungetchr(c);
1454 									*--pp.toknxt = 0;
1455 									break;
1456 								}
1457 								f |= NOISE_PAREN;
1458 								p = ')';
1459 							}
1460 							else
1461 							{
1462 								f |= NOISE_BRACE|NOISE_PAREN;
1463 								p = '}';
1464 							}
1465 							n = 1;
1466 							m = c;
1467 						}
1468 						else if (c == m) n++;
1469 						quot = 0;
1470 						continue;
1471 					case ')':
1472 					case '}':
1473 						if (c == p && --n <= 0)
1474 						{
1475 							if (c == '}') break;
1476 							m = '\n';
1477 							p = 0;
1478 						}
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')
1494 						{
1495 							/*
1496 							 * NOTE: token expanded again
1497 							 */
1498 
1499 							s = pp.toknxt;
1500 							while (s > pp.token) ungetchr(*--s);
1501 							*(pp.toknxt = s) = 0;
1502 							break;
1503 						}
1504 						continue;
1505 					}
1506 					break;
1507 				}
1508 				break;
1509 			case T_X_LINE:
1510 				for (;;)
1511 				{
1512 					ADVANCE();
1513 					switch (pplex())
1514 					{
1515 					case 0:
1516 						break;
1517 					case '\n':
1518 						error_info.line++;
1519 						break;
1520 					default:
1521 						continue;
1522 					}
1523 					break;
1524 				}
1525 				break;
1526 			case T_X_STATEMENT:
1527 				for (;;)
1528 				{
1529 					ADVANCE();
1530 					switch (pplex())
1531 					{
1532 					case 0:
1533 						break;
1534 					case ';':
1535 						ungetchr(';');
1536 						*(pp.toknxt = pp.token) = 0;
1537 						break;
1538 					default:
1539 						continue;
1540 					}
1541 					break;
1542 				}
1543 				break;
1544 			}
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;
1552 		}
1553 		if (pp.option & NOISEFILTER)
1554 		{
1555 			BACKOUT();
1556 			goto fsm_top;
1557 		}
1558 	}
1559 
1560 							/*INDENT*/
1561 						}
1562 						else if ((pp.option & NOISE) && c == T_ID && strneq(tp, "__builtin_", 10))
1563 						{
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;
1568 						}
1569 					}
1570 				}
1571 				goto fsm_symbol;
1572 			}
1573 			goto fsm_check;
1574 		}
1575 		if (pp.level == 1)
1576 		{
1577 			st &= ~(NEWLINE|PASSEOF);
1578 			pp.in->flags |= IN_tokens;
1579 		}
1580 		else st &= ~PASSEOF;
1581 		count(candidate);
1582 		SETCHR(0);
1583 		if (sym = ppsymref(pp.symtab, tp))
1584 		{
1585 			SYNCIN();
1586 			c = ppcall(sym, 1);
1587 			CACHEIN();
1588 			if (c >= 0)
1589 			{
1590 				BACKOUT();
1591 				if ((sym->flags & SYM_MULTILINE) && pp.linesync)
1592 				{
1593 					SYNCOUT();
1594 					(*pp.linesync)(error_info.line, error_info.file);
1595 					CACHEOUT();
1596 				}
1597 				goto fsm_top;
1598 			}
1599 		}
1600 		c = T_ID;
1601 		if (pp.level == 1)
1602 		{
1603 			if (st & NOTEXT)
1604 			{
1605 				BACKOUT();
1606 				goto fsm_top;
1607 			}
1608 			if (st & COMPILE)
1609 			{
1610 				if (pp.truncate && (op - tp) > pp.truncate)
1611 				{
1612 					tp[pp.truncate] = 0;
1613 					sym = 0;
1614 				}
1615 				if (!sym)
1616 				{
1617 					if (!(pp.option & NOHASH)) sym = ppsymset(pp.symtab, tp);
1618 					else if (!(sym = ppsymref(pp.symtab, tp))) goto fsm_symbol;
1619 				}
1620 				goto fsm_noise;
1621 			}
1622 			goto fsm_symbol;
1623 		}
1624 		goto fsm_check;
1625 #endif
1626 
1627 	case S_SHARP:
1628 		if (c == '(')
1629 		{
1630 			pp.in->flags |= IN_tokens;
1631 			if ((st & STRICT) && pp.in->type != IN_MACRO && pp.in->type != IN_MULTILINE)
1632 			{
1633 				if (!(pp.mode & HOSTED)) error(1, "non-standard reference to #(...)");
1634 				if (st & STRICT)
1635 				{
1636 					PUTCHR(c);
1637 #if CPP
1638 					st &= ~NEWLINE;
1639 					count(token);
1640 					goto fsm_start;
1641 #else
1642 					break;
1643 #endif
1644 				}
1645 			}
1646 			if (st & (COLLECTING|DEFINITION|DISABLE|SKIPCONTROL))
1647 			{
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
1657 			}
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
1668 		}
1669 		BACKIN();
1670 #if CPP
1671 		if (!(st & NEWLINE) || !(pp.in->type & IN_TOP))
1672 		{
1673  fsm_nondirective:
1674 			st &= ~NEWLINE;
1675 			pp.in->flags |= IN_tokens;
1676 			count(token);
1677 			goto fsm_start;
1678 		}
1679 		if (*(s = tp) != '#')
1680 		{
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;
1686 		}
1687 		BACKOUT();
1688 #else
1689 		if (!(st & NEWLINE) || (st & DEFINITION) || !(pp.in->type & IN_TOP))
1690 		{
1691 			if (c == '#')
1692 			{
1693 				SKIPIN();
1694 				if (!(st & DEFINITION))
1695 					PUTCHR(c);
1696 				c = T_TOKCAT;
1697 			}
1698 			else if (pp.level == 1 && !(st & (JOINING|SPACEOUT)) && !(pp.option & PRESERVE))
1699 			{
1700 				char*		pptoken;
1701 				char*		oop;
1702 				PPCOMMENT	ppcomment;
1703 
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 (;;)
1711 				{
1712 					ADVANCE();
1713 					switch (pplex())
1714 					{
1715 					case 0:
1716 						break;
1717 					case '\n':
1718 						error_info.line++;
1719 						break;
1720 					default:
1721 						continue;
1722 					}
1723 					break;
1724 				}
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))
1732 				{
1733 					*s = 0;
1734 					SYNC();
1735 					(*pp.pragma)(NiL, NiL, NiL, tp, 1);
1736 					CACHE();
1737 				}
1738 				if (!c) BACKIN();
1739 				goto fsm_top;
1740 			}
1741 			else c = '#';
1742 			break;
1743 		}
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)
1748 		{
1749 			/*
1750 			 * pass line to pp.pragma VERBATIM
1751 			 */
1752 
1753 			SKIPIN();
1754 			s = pp.valbuf;
1755 			while ((c = GETCHR()) && c != '\n')
1756 				if ((*s++ = c) == MARK) SKIPIN();
1757 			if (pp.pragma && !(st & NOTEXT))
1758 			{
1759 				*s = 0;
1760 				SYNC();
1761 				(*pp.pragma)(NiL, NiL, NiL, pp.valbuf, 1);
1762 				CACHE();
1763 			}
1764 			if (!c) BACKIN();
1765 #if CPP
1766 			goto fsm_start;
1767 #else
1768 			goto fsm_top;
1769 #endif
1770 		}
1771 		SYNC();
1772 		ppcontrol();
1773 		CACHE();
1774 #if CPP
1775 		if (st & (NOTEXT|SKIPCONTROL))
1776 		{
1777 			if (!sp)
1778 			{
1779 				PPCHECKOUTTP();
1780 				sp = tp;
1781 			}
1782 		}
1783 		else if (sp)
1784 		{
1785 			tp = op = sp;
1786 			sp = 0;
1787 		}
1788 		goto fsm_start;
1789 #else
1790 		goto fsm_top;
1791 #endif
1792 
1793 	case S_NL:
1794 #if CPP
1795 		if (op == tp && !(st & JOINING) && pp.in->type == IN_FILE && !(pp.option & PRESERVE))
1796 		{
1797 			st |= NEWLINE|HIDDEN;
1798 			pp.hidden++;
1799 			error_info.line++;
1800 			goto fsm_start;
1801 		}
1802 #endif
1803  fsm_newline:
1804 #if CPP
1805 		if (sp)
1806 			op = sp;
1807 		else if (!(pp.in->flags & IN_noguard))
1808 		{
1809 			while (tp < op)
1810 				if ((c = *tp++) != ' ' && c != '\t')
1811 				{
1812 					pp.in->flags |= IN_tokens;
1813 					break;
1814 				}
1815 			c = '\n';
1816 		}
1817 		st |= NEWLINE;
1818 		error_info.line++;
1819 		if (*ip == '\n' && *(ip + 1) != '\n' && !pp.macref && !(st & (ADD|HIDDEN)))
1820 		{
1821 			ip++;
1822 			PUTCHR('\n');
1823 			error_info.line++;
1824 		}
1825 		if ((st & NOTEXT) && ((pp.mode & FILEDEPS) || (pp.option & (DEFINITIONS|PREDEFINITIONS))))
1826 			BACKOUT();
1827 		else
1828 		{
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)
1833 			{
1834 				PPCHECKOUT();
1835 				sp = op;
1836 			}
1837 		}
1838 		goto fsm_start;
1839 #else
1840 		st |= NEWLINE;
1841 		if (pp.level == 1)
1842 		{
1843 			error_info.line++;
1844 			if (!(st & (JOINING|SPACEOUT)))
1845 			{
1846 				debug((-5, "token[%d] %03o = %s [line=%d]", pp.level, c, pptokchr(c), error_info.line));
1847 				BACKOUT();
1848 				goto fsm_top;
1849 			}
1850 		}
1851 		BACKOUT();
1852 		if (st & SKIPCONTROL)
1853 		{
1854 			error_info.line++;
1855 			st |= HIDDEN;
1856 			pp.hidden++;
1857 			goto fsm_start;
1858 		}
1859 		PUTCHR(c = '\n');
1860 		goto fsm_return;
1861 #endif
1862 
1863 #if !CPP
1864 	case S_TOK:
1865 		PUTCHR(c);
1866 		c = TYPE(state) | qual;
1867 		break;
1868 
1869 	case S_TOKB:
1870 		BACKIN();
1871 		c = TYPE(state) | qual;
1872 		break;
1873 #endif
1874 
1875 	case S_VS:
1876 		PUTCHR(c);
1877 #if !CPP
1878 		if (st & NOVERTICAL)
1879 		{
1880 			error(1, "%s invalid in directives", pptokchr(c));
1881 			st &= ~NOVERTICAL;
1882 		}
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')
1891 				{
1892 					pp.in->flags |= IN_tokens;
1893 					break;
1894 				}
1895 		goto fsm_start;
1896 #else
1897 		bp = ip;
1898 		rp = fsm[WS1];
1899 		goto fsm_get;
1900 #endif
1901 
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)
1908 		{
1909 			if ((st & (COMPATIBILITY|SPACEOUT)) && !(st & TRANSITION))
1910 			{
1911 				if (st & (COMPILE|NOTEXT))
1912 				{
1913 #if CATSTRINGS
1914 					if ((st & (JOINING|NOTEXT|SPACEOUT)) != SPACEOUT)
1915 #else
1916 					if ((st & (NOTEXT|SPACEOUT)) != SPACEOUT)
1917 #endif
1918 					{
1919 						BACKOUT();
1920 						bp = ip - 1;
1921 						rp = fsm[START];
1922 						if (state = rp[c]) goto fsm_next;
1923 						goto fsm_get;
1924 					}
1925 				}
1926 				else
1927 #if CATSTRINGS
1928 				if (!(st & JOINING))
1929 #endif
1930 				{
1931 					tp = op;
1932 					bp = ip - 1;
1933 					rp = fsm[START];
1934 					if (state = rp[c]) goto fsm_next;
1935 					goto fsm_get;
1936 				}
1937 				BACKIN();
1938 				c = ' ';
1939 				goto fsm_return;
1940 			}
1941 			BACKOUT();
1942 			bp = ip - 1;
1943 			rp = fsm[START];
1944 			if (state = rp[c]) goto fsm_next;
1945 			goto fsm_get;
1946 		}
1947 		if (st & (NOSPACE|SKIPCONTROL))
1948 		{
1949 			BACKOUT();
1950 			bp = ip - 1;
1951 			rp = fsm[START];
1952 			if (state = rp[c]) goto fsm_next;
1953 			goto fsm_get;
1954 		}
1955 		if (c != '\n')
1956 		{
1957 			BACKIN();
1958 			c = ' ';
1959 		}
1960 		if (!(pp.option & PRESERVE))
1961 		{
1962 			BACKOUT();
1963 			PUTCHR(c);
1964 		}
1965 		goto fsm_return;
1966 #endif
1967 
1968 	default:
1969 		if (state & SPLICE)
1970 		{
1971 			switch (c)
1972 			{
1973 			case MARK:
1974 				/*
1975 				 * internal mark
1976 				 */
1977 
1978 				switch (pp.in->type)
1979 				{
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())
1994 					{
1995 					case 'A':
1996 						if (!(st & (DEFINITION|DISABLE)))
1997 						{
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;
2007 						}
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))
2012 						{
2013 							s = ip - 3;
2014 							while (--op > tp && --s > bp && ppisidig(*s));
2015 						}
2016 						else
2017 						{
2018 							SYNCIN();
2019 							PUSH_COPY(s, pp.macp->line);
2020 							CACHEIN();
2021 						}
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)
2056 						{
2057 							bp = ip;
2058 							goto fsm_get;
2059 						}
2060 						if (pp.in->type == IN_EXPAND)
2061 						{
2062 							st &= ~SKIPMACRO;
2063 							PUTCHR(c);
2064 							PUTCHR('X');
2065 						}
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)
2079 						{
2080 							if (!INQUOTE(rp))
2081 								PUTCHR(c);
2082 						}
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;
2095 					}
2096 					break;
2097 				}
2098 				break;
2099 			case '?':
2100 				/*
2101 				 * trigraph
2102 				 */
2103 
2104 				if (pp.in->type == IN_FILE)
2105 				{
2106 					GET(c, n, tp, xp);
2107 					if (n == '?')
2108 					{
2109 						GET(c, n, tp, xp);
2110 						if (c = trigraph[n])
2111 						{
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)
2116 							{
2117 #endif
2118 							*(bp = ip - 1) = c;
2119 							if (state = rp[c]) goto fsm_next;
2120 							goto fsm_get;
2121 #if COMPATIBLE
2122 							}
2123 #endif
2124 						}
2125 						if (n != EOB) BACKIN();
2126 						UNGETCHR(c = '?');
2127 					}
2128 					else if (n != EOB) BACKIN();
2129 				}
2130 				break;
2131 			case '%':
2132 			case '<':
2133 			case ':':
2134 				/*
2135 				 * digraph = --trigraph
2136 				 */
2137 
2138 				if (pp.in->type == IN_FILE && (pp.option & PLUSPLUS))
2139 				{
2140 					m = 0;
2141 					GET(c, n, tp, xp);
2142 					switch (n)
2143 					{
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;
2155 					}
2156 					if (m)
2157 					{
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)
2162 						{
2163 #endif
2164 						*(bp = ip - 1) = c = m;
2165 						if (state = rp[c]) goto fsm_next;
2166 						goto fsm_get;
2167 #if COMPATIBLE
2168 						}
2169 #endif
2170 					}
2171 					if (n != EOB) BACKIN();
2172 				}
2173 				break;
2174 			case '\\':
2175 				/*
2176 				 * line splice
2177 				 */
2178 
2179 				if (pp.in->type == IN_FILE && (!(pp.option & PLUSSPLICE) || !INCOMMENTXX(rp)))
2180 				{
2181 					m = 0;
2182 					GET(c, n, tp, xp);
2183 					if ((pp.option & SPLICESPACE) && !INQUOTE(rp))
2184 						while (n == ' ')
2185 						{
2186 							GET(c, n, tp, xp);
2187 							m = 1;
2188 						}
2189 					if (n == '\r')
2190 					{
2191 						GET(c, n, tp, xp);
2192 						if (n != '\n' && n != EOB)
2193 							BACKIN();
2194 					}
2195 					if (n == '\n')
2196 					{
2197 #if CPP
2198 						if (INQUOTE(rp))
2199 						{
2200 							if ((pp.option & STRINGSPLIT) && quot == '"')
2201 							{
2202 								PUTCHR(quot);
2203 								PUTCHR(n);
2204 								PUTCHR(quot);
2205 							}
2206 							else if (*pp.lineid)
2207 							{
2208 								PUTCHR(c);
2209 								PUTCHR(n);
2210 							}
2211 							else
2212 							{
2213 								st |= HIDDEN;
2214 								pp.hidden++;
2215 							}
2216 						}
2217 						else
2218 #else
2219 #if COMPATIBLE
2220 						if (!INQUOTE(rp) && (st & (COMPATIBILITY|DEFINITION|TRANSITION)) == (COMPATIBILITY|DEFINITION))
2221 						{
2222 							if (op == tp)
2223 							{
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;
2232 							}
2233 							UNGETCHR(n);
2234 							state &= ~SPLICE;
2235 							goto fsm_terminal;
2236 						}
2237 #endif
2238 #endif
2239 						{
2240 							st |= HIDDEN;
2241 							pp.hidden++;
2242 						}
2243 #if CPP
2244 						spliced++;
2245 #else
2246 						error_info.line++;
2247 #endif
2248 						bp = ip;
2249 						goto fsm_get;
2250 					}
2251 					else if ((n == 'u' || n == 'U') && !INQUOTE(rp))
2252 					{
2253 						PUTCHR(c);
2254 						PUTCHR(n);
2255 						bp = ip;
2256 						goto fsm_get;
2257 					}
2258 #if COMPATIBLE
2259 					else if ((st & (COMPATIBILITY|TRANSITION)) == COMPATIBILITY && (n == '"' || n == '\'') && !INQUOTE(rp))
2260 					{
2261 						PUTCHR(c);
2262 						PUTCHR(n);
2263 						bp = ip;
2264 						goto fsm_get;
2265 					}
2266 #endif
2267 					else if (n != EOB)
2268 						BACKIN();
2269 					if (m && INSPACE(rp))
2270 						UNGETCHR(c);
2271 				}
2272 #if COMPATIBLE
2273 				else if ((st & (COMPATIBILITY|TRANSITION)) == COMPATIBILITY && !INQUOTE(rp))
2274 				{
2275 					GET(c, n, tp, xp);
2276 					if (n == '"' || n == '\'')
2277 					{
2278 						PUTCHR(c);
2279 						PUTCHR(n);
2280 						bp = ip;
2281 						goto fsm_get;
2282 					}
2283 					if (n != EOB)
2284 						BACKIN();
2285 				}
2286 #endif
2287 				break;
2288 			case '\r':
2289 				/*
2290 				 * barf
2291 				 */
2292 
2293 				if (pp.in->type == IN_FILE)
2294 				{
2295 					GET(c, n, tp, xp);
2296 					if (n == '\n')
2297 					{
2298 						*(bp = ip - 1) = c = n;
2299 						if (state = rp[c]) goto fsm_next;
2300 						goto fsm_get;
2301 					}
2302 					if (n != EOB) BACKIN();
2303 				}
2304 				break;
2305 			case CC_sub:
2306 				/*
2307 				 * barf & puke
2308 				 */
2309 
2310 				if ((pp.option & ZEOF) && pp.in->type == IN_FILE)
2311 				{
2312 					pp.in->flags |= IN_eof;
2313 					c = 0;
2314 					state = S_EOB;
2315 					goto fsm_terminal;
2316 				}
2317 				break;
2318 			}
2319 			if ((state &= ~SPLICE) >= TERMINAL)
2320 				goto fsm_terminal;
2321 			PUTCHR(c);
2322 			goto fsm_begin;
2323 		}
2324 #if CPP
2325 		if (INOPSPACE(rp))
2326 		{
2327 			BACKIN();
2328 			goto fsm_start;
2329 		}
2330 #endif
2331 		PUTCHR(c);
2332 		bp = ip;
2333 		goto fsm_get;
2334 	}
2335 #if !CPP
2336  fsm_token:
2337 	st &= ~NEWLINE;
2338 	if (pp.level == 1)
2339 	{
2340 		pp.in->flags |= IN_tokens;
2341 		if (st & NOTEXT)
2342 		{
2343 			BACKOUT();
2344 			goto fsm_top;
2345 		}
2346  fsm_symbol:
2347 		count(token);
2348 	}
2349  fsm_check:
2350 	if (st & SKIPCONTROL)
2351 	{
2352 		BACKOUT();
2353 		goto fsm_start;
2354 	}
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
2366 }
2367 
2368 #if CPP && POOL
2369 
2370 #include <ls.h>
2371 #include <wait.h>
2372 
2373 /*
2374  * output pool status on exit
2375  */
2376 
2377 static void
poolstatus(void)2378 poolstatus(void)
2379 {
2380 	error(ERROR_OUTPUT|0, pp.pool.output, "%d", error_info.errors != 0);
2381 }
2382 
2383 /*
2384  * loop on < input output >
2385  */
2386 
2387 static void
pool(void)2388 pool(void)
2389 {
2390 	char*	ifile;
2391 	char*	ofile;
2392 
2393 	ppflushout();
2394 	if (!sfnew(sfstdin, NiL, SF_UNBOUND, pp.pool.input, SF_READ))
2395 		error(ERROR_SYSTEM|3, "cannot dup pool input");
2396 
2397 	/*
2398 	 * kick the -I cache
2399 	 */
2400 
2401 	ppsearch(".", T_STRING, SEARCH_EXISTS);
2402 
2403 	/*
2404 	 * loop on < input output >
2405 	 */
2406 
2407 	pp.pool.input = 0;
2408 	while (ifile = sfgetr(sfstdin, '\n', 1))
2409 	{
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())
2415 		{
2416 		case -1:
2417 			error(ERROR_SYSTEM|3, "cannot fork pool");
2418 			/* FALLTHROUGH */
2419 		case 0:
2420 			atexit(poolstatus);
2421 			error_info.errors = 0;
2422 			error_info.warnings = 0;
2423 			close(0);
2424 			if (open(ifile, O_RDONLY))
2425 				error(ERROR_SYSTEM|3, "%s: cannot read", ifile);
2426 			close(1);
2427 			if (open(ofile, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH) != 1)
2428 				error(ERROR_SYSTEM|3, "%s: cannot create", ofile);
2429 			pp.outfile = ofile;
2430 			pathcanon(ifile, 0, 0);
2431 			ifile = ppsetfile(ifile)->name;
2432 #if CHECKPOINT
2433 			if (pp.mode & DUMP)
2434 			{
2435 				if (!pp.pragma)
2436 					error(3, "#%s must be enabled for checkpoints", dirname(PRAGMA));
2437 				(*pp.pragma)(dirname(PRAGMA), pp.pass, keyname(X_CHECKPOINT), pp.checkpoint, 1);
2438 			}
2439 #endif
2440 			PUSH_FILE(ifile, 0);
2441 			return;
2442 		}
2443 	}
2444 	while (wait(NiL) != -1);
2445 }
2446 
2447 #endif
2448