1 /***********************************************************************
3 * This software is part of the ast package *
4 * Copyright (c) 1986-2009 AT&T Intellectual Property *
5 * and is licensed under the *
6 * Common Public License, Version 1.0 *
7 * by AT&T Intellectual Property *
9 * A copy of the License is available at *
10 * http://www.opensource.org/licenses/cpl1.0.txt *
11 * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
13 * Information and Software Systems Research *
17 * Glenn Fowler <gsf@research.att.com> *
19 ***********************************************************************/
25 * preprocessor lexical analyzer
26 * standalone and tokenizing lexer combined in one source
27 * define CPP=1 for standalone
36 * standalone entry point
42 #define INMACRO(x) INQMACRO(x)
43 #define DOSTRIP() (st&STRIP)
45 #if DEBUG & TRACE_debug
46 static int hit
[LAST
-TERMINAL
+2];
49 #define BACKIN() (ip--)
50 #define BACKOUT() (op=tp)
51 #define CACHE() do{CACHEINX();CACHEOUTX();st=pp.state;if(!pp.hidden)spliced=0;}while(0)
52 #define CACHEIN() do{CACHEINX();st=pp.state;if(!pp.hidden)spliced=0;}while(0)
53 #define CACHEINX() do{ip=pp.in->nextchr;}while(0)
54 #define CACHEOUT() do{CACHEOUTX();st=pp.state;if(!pp.hidden)spliced=0;}while(0)
55 #define CACHEOUTX() do{tp=op=pp.outp;xp=pp.oute;if(sp)sp=op;}while(0)
56 #define GETCHR() (*(unsigned char*)ip++)
57 #define LASTCHR() (*(ip-1))
58 #define LASTOUT() ((op>pp.outbuf)?*(op-1):pp.lastout)
59 #define SKIPIN() (ip++)
60 #define PUTCHR(c) (*op++=(c))
61 #define SETCHR(c) (*op=(c))
62 #define SYNC() do{SYNCINX();SYNCOUTX();pp.state=st;}while(0)
63 #define SYNCIN() do{SYNCINX();pp.state=st;}while(0)
64 #define SYNCINX() do{pp.in->nextchr=ip;}while(0)
65 #define SYNCOUT() do{SYNCOUTX();pp.state=st;}while(0)
66 #define SYNCOUTX() do{if(sp)op=tp=sp;pp.outp=op;}while(0)
67 #define UNGETCHR(c) (*--ip=(c))
69 #define PPCHECKOUT() do{if(op>xp){{PPWRITE(PPBUFSIZ);if(pp.outbuf==pp.outb){pp.outbuf+=PPBUFSIZ;xp=pp.oute+=PPBUFSIZ;}else{pp.outbuf-=PPBUFSIZ;memcpy(pp.outbuf,xp,op-xp);xp=pp.oute-=PPBUFSIZ;op-=2*PPBUFSIZ;}}}}while(0)
70 #define PPCHECKOUTSP() do{if(op>xp){if(sp)op=sp;else{PPWRITE(PPBUFSIZ);if(pp.outbuf==pp.outb){pp.outbuf+=PPBUFSIZ;xp=pp.oute+=PPBUFSIZ;}else{pp.outbuf-=PPBUFSIZ;memcpy(pp.outbuf,xp,op-xp);xp=pp.oute-=PPBUFSIZ;op-=2*PPBUFSIZ;}}}}while(0)
71 #define PPCHECKOUTTP() do{if(op>xp){{PPWRITE(PPBUFSIZ);if(pp.outbuf==pp.outb){pp.outbuf+=PPBUFSIZ;xp=pp.oute+=PPBUFSIZ;}else{pp.outbuf-=PPBUFSIZ;memcpy(pp.outbuf,xp,op-xp);xp=pp.oute-=PPBUFSIZ;op-=2*PPBUFSIZ;}}tp=op;}}while(0)
73 #define PPSYNCLINE() do { \
74 if ((st & (ADD|HIDDEN)) && !(*pp.control & SKIP)) \
78 error_info.line += spliced; \
86 m = pp.addp - pp.addbuf; \
87 pp.addp = pp.addbuf; \
88 memcpy(op, pp.addbuf, m); \
94 if ((st & SYNCLINE) || pp.hidden >= MAXHIDDEN) \
97 st &= ~(HIDDEN|SYNCLINE); \
98 if (error_info.line) \
100 if (LASTOUT() != '\n') \
103 (*pp.linesync)(error_info.line, error_info.file); \
129 * <wait.h> is poison here so pool moved to the end
132 static void poolstatus(void);
133 static void pool(void);
140 * return next pp token
142 * NOTE: pp.token points to at least MAXTOKEN*2 chars and is
143 * truncated back to MAXTOKEN on EOB
150 #define INMACRO(x) INTMACRO(x)
151 #define DOSTRIP() ((st&STRIP)||pp.level==1&&(st&(COMPILE|JOINING))==COMPILE&&!(pp.option&PRESERVE))
155 #define xp &pp.token[MAXTOKEN]
157 #define BACKIN() (ip--)
158 #define BACKOUT() (op=pp.token)
159 #define CACHE() do{CACHEIN();CACHEOUT();}while(0)
160 #define CACHEIN() (ip=pp.in->nextchr)
161 #define CACHEOUT() (op=pp.token)
162 #define GETCHR() (*(unsigned char*)ip++)
163 #define LASTCHR() (*(ip-1))
164 #define PUTCHR(c) (*op++=(c))
165 #define SETCHR(c) (*op=(c))
166 #define SKIPIN() (ip++)
167 #define SYNC() do{SYNCIN();SYNCOUT();}while(0)
168 #define SYNCIN() (pp.in->nextchr=ip)
169 #define SYNCOUT() (pp.toknxt=op)
170 #define UNGETCHR(c) (*--ip=(c))
191 struct ppsymbol
* sym
;
229 while (!(state
= rp
[c
= GETCHR()]));
233 if (((state
= ~state
) != S_COMMENT
|| pp
.comment
|| c
== '/' && !INCOMMENT(rp
)) && (n
= ip
- bp
- 1) > 0)
237 if (op
== tp
&& (st
& (ADD
|HIDDEN
)) && !(st
& PASSTHROUGH
) && !(pp
.option
& PRESERVE
))
248 if ((pp
.option
& PRESERVE
) && !(st
& NEWLINE
) && c
!= '\n')
259 #if CPP && (DEBUG & TRACE_debug)
260 hit
[(state
& SPLICE
) ? (elementsof(hit
) - 1) : (TERM(state
) - 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
)));
277 pp
.in
->flags
|= IN_tokens
;
289 if (!INCOMMENTXX(rp
))
292 if (!comstart
) comstart
= comdelim
= error_info
.line
;
294 if (pp
.comment
) PUTCHR(c
);
305 else if (comwarn
< 0 && !(pp
.mode
& HOSTED
))
306 error(1, "/* appears in // comment");
309 if (!comwarn
&& !(pp
.mode
& HOSTED
))
311 if (INCOMMENTXX(rp
)) comwarn
= -1;
312 else if (comstart
&& comstart
!= error_info
.line
)
314 if (qual
|| comdelim
< error_info
.line
- 1)
316 error(1, "/* appears in /* ... */ comment starting at line %d", comstart
);
319 else comdelim
= error_info
.line
;
325 rp
= fsm
[INCOMMENTXX(rp
) ? COM5
: COM3
];
329 state
= INCOMMENTXX(rp
) ? COM5
: COM3
;
335 if (!(pp
.mode
& HOSTED
))
336 error(1, "*/ appears outside of comment");
340 pp
.in
->flags
|= IN_tokens
;
345 if (!pp
.comment
) PUTCHR(c
);
349 else if (INCOMMENTXX(rp
))
351 if (!(pp
.mode
& HOSTED
))
353 if (comwarn
< 0) comwarn
= 0;
357 error(1, "*/ appears in // comment");
365 if (!(pp
.mode
& HOSTED
))
367 if (comstart
) error(2, "unterminated /* ... */ comment starting at line %d", comstart
);
368 else if (INCOMMENTXX(rp
)) error(2, "unterminated // ... comment");
369 else error(2, "unterminated /* ... */ comment");
374 if (!pp
.comment
|| sp
)
377 if (!(pp
.state
& COMPATIBILITY
) || *bp
== ' ' || *bp
== '\t')
385 else if (pp
.in
->type
& IN_TOP
)
387 if (pp
.comment
&& !(st
& (COLLECTING
|DIRECTIVE
|JOINING
)) && !(*pp
.control
& SKIP
) && (pp
.in
->type
& IN_TOP
))
392 *(op
- (c
!= '\n')) = 0;
393 m
= (op
- (c
!= '\n') - tp
> MAXTOKEN
- 6) ? (error_info
.line
- MAXHIDDEN
) : 0;
396 while (*tp
!= '/') tp
++;
397 (*pp
.comment
)(c
== '\n' ? "//" : "/*", tp
+ 2, c
== '\n' ? "" : (st
& HEADER
) ? "*/\n" : "*/", comstart
? comstart
: error_info
.line
);
404 pp
.hidden
+= error_info
.line
- comstart
;
407 qual
= comwarn
= comdelim
= 0;
409 if (c
== '\n') goto fsm_newline
;
410 if ((st
& PASSTHROUGH
) && ((st
& (HIDDEN
|NEWLINE
)) || *ip
== '\n'))
417 if ((st
& (COMPATIBILITY
|TRANSITION
)) == COMPATIBILITY
) st
&= ~NEWLINE
;
420 if (pp
.level
> 1 && !(st
& (NOSPACE
|SKIPCONTROL
)))
423 c
= ((st
& (COMPATIBILITY
|DEFINITION
)) == ((COMPATIBILITY
|DEFINITION
))) ? '\t' : ' ';
435 if (state
= fsm
[TERMINAL
][INDEX(rp
)+1])
457 register struct ppinstk
* cur
= pp
.in
;
458 register struct ppinstk
* prv
= pp
.in
->prev
;
471 if (!(st
& PASSEOF
) && prv
)
474 if (cur
->type
== IN_RESCAN
|| cur
->type
== IN_BUFFER
)
478 if (cur
->flags
& IN_prototype
)
479 pppclose(cur
->buffer
+ PPBAKSIZ
);
482 if (!(cur
->flags
& IN_static
))
485 while (pp
.control
-- != cur
->control
)
486 error(2, "#%s on line %d has no #%s", dirname(IF
), GETIFLINE(pp
.control
+1), dirname(ENDIF
));
488 error_info
.file
= cur
->file
;
489 error_info
.line
= cur
->line
;
494 if (cur
->flags
& IN_hosted
)
497 pp
.flags
|= PP_hosted
;
502 pp
.flags
&= ~PP_hosted
;
504 #if !CPP && CATSTRINGS
505 if (st
& JOINING
) st
|= HIDDEN
|SYNCLINE
;
509 st
&= ~(HIDDEN
|SYNCLINE
);
514 if (!prv
->prev
) break;
518 if (prv
->type
== IN_FILE
|| cur
->type
== IN_FILE
&& (prv
->type
== IN_RESCAN
|| prv
->type
== IN_MULTILINE
))
520 if (pp
.linesync
&& (cur
->type
!= IN_RESCAN
|| (cur
->flags
& IN_sync
)))
524 (*pp
.linesync
)(error_info
.line
, error_info
.file
);
534 #if DEBUG & TRACE_count
535 if (pp
.test
& TEST_count
)
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
);
548 #if CPP && (DEBUG & TRACE_debug)
549 if (pp
.test
& TEST_hit
)
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
++)
557 sfprintf(sfstderr
, "%7d: %s\n", hit
[n
], pplexstr(TERMINAL
+ n
));
560 if (pp
.test
& (TEST_hashcount
|TEST_hashdump
))
563 sfprintf(sfstderr
, "\n");
564 hashdump(NiL
, (pp
.test
& TEST_hashdump
) ? HASH_BUCKET
: 0);
566 if (c
) sfprintf(sfstderr
, "\n");
577 cur
->index
->end
= ppoffset();
592 error_info
.line
= cur
->line
;
593 if (!(prv
->symbol
->flags
& SYM_MULTILINE
))
594 prv
->symbol
->flags
|= SYM_DISABLED
;
604 error_info
.line
= cur
->line
;
617 if ((st
& (NOTEXT
|HIDDEN
)) == HIDDEN
&& LASTOUT() != '\n')
624 *(ip
- 1) = c
= '\n';
626 else if (!(st
& (FILEPOP
|PASSEOF
)) && prv
)
629 if (!(cur
->flags
& IN_newline
))
631 cur
->flags
|= IN_newline
;
632 if ((pp
.mode
& (HOSTED
|PEDANTIC
)) == PEDANTIC
&& LASTCHR() != '\f' && LASTCHR() != CC_sub
)
633 error(1, "file does not end with %s", pptokchr('\n'));
634 *(ip
- 1) = c
= '\n';
638 if (!(cur
->flags
& (IN_noguard
|IN_tokens
)) && cur
->symbol
)
639 ppmultiple(ppsetfile(error_info
.file
), cur
->symbol
);
642 if (pp
.incref
&& !(pp
.mode
& INIT
))
645 (*pp
.incref
)(error_info
.file
, cur
->file
, error_info
.line
- 1, PP_SYNC_POP
);
661 if (prv
&& (!INMACRO(rp
) || (st
& (COMPATIBILITY
|TRANSITION
)) == COMPATIBILITY
&& ppismac(*prv
->nextchr
)))
663 if (prv
&& !INMACRO(rp
))
666 if (cur
->type
== IN_MULTILINE
)
668 while (pp
.control
-- != cur
->control
)
669 error(2, "#%s on line %d has no #%s", dirname(IF
), GETIFLINE(pp
.control
+1), dirname(ENDIF
));
671 error_info
.file
= cur
->file
;
672 error_info
.line
= cur
->line
;
676 (*pp
.linesync
)(error_info
.line
, error_info
.file
);
680 cur
->symbol
->flags
&= ~SYM_DISABLED
;
681 if (cur
->symbol
->flags
& SYM_FUNCTION
)
685 if (!(st
& COMPATIBILITY
) && ppisidig(*(op
- 1)) && ppisidig(*ip
)) UNGETCHR(' ');
695 error_info
.line
= cur
->line
;
696 st
&= ~(ESCAPE
|QUOTE
);
705 error_info
.line
= cur
->line
;
706 st
&= ~(ESCAPE
|SQUOTE
);
716 if (!(st
& PASSEOF
) && !(cur
->flags
& IN_expand
) && prv
)
719 if (cur
->flags
& IN_disable
) st
|= DISABLE
;
733 if (state
= rp
[c
]) goto fsm_next
;
743 if (pp
.in
->flags
& IN_prototype
) PUTCHR(c
);
747 while (*(op
- 1) == ' ' || *(op
- 1) == '\t') op
--;
749 if (st
& (STRICT
|WARN
)) error(1, "%-*.*s: space ignored in operator", op
- tp
, op
- tp
, tp
);
801 else if (pp
.level
> 1 || (pp
.option
& PRESERVE
)) PUTCHR(c
);
804 if (pp
.in
->type
!= IN_BUFFER
)
806 if (!(pp
.option
& ALLPOSSIBLE
))
807 error(1, "%s: invalid character ignored", pptokchr(c
));
815 if (c
== '=') error(2, "real programmers use =");
827 if ((state
= NEXT(state
)) != LIT1
)
834 if (!(st
& COMPATIBILITY
) || c
!= 'u' && c
!= 'U')
844 if (!(st
& COMPATIBILITY
))
857 if (!(st
& COMPATIBILITY
))
870 if (DOSTRIP()) BACKOUT();
884 if ((quot
= c
) == '<')
886 if (!(st
& HEADER
) || (pp
.option
& (HEADEREXPAND
|HEADEREXPANDALL
)) && pp
.in
->type
!= IN_FILE
&& pp
.in
->type
!= IN_BUFFER
&& pp
.in
->type
!= IN_INIT
&& pp
.in
->type
!= IN_RESCAN
)
907 if (c
!= '\n' && c
!= EOF
)
909 if (st
& (QUOTE
|SQUOTE
))
916 else if (c
== quotquot
) st
&= ~ESCAPE
;
923 if ((st
& PASSTHROUGH
) || (pp
.option
& PRESERVE
))
925 if (c
== '\n') goto fsm_newline
;
930 m
= (st
& SKIPCONTROL
) && (pp
.mode
& HOSTED
) ? -1 : 1;
931 if (c
== '\n' && quot
== '\'' && (pp
.option
& STRINGSPAN
)) n
= 0;
933 #if COMPATIBLE && !CPP
934 if ((st
& (COMPATIBILITY
|DEFINITION
)) != (COMPATIBILITY
|DEFINITION
))
942 if (!(pp
.option
& STRINGSPAN
) || (st
& (COMPATIBILITY
|STRICT
)) == STRICT
)
943 error(m
, "%s in string", pptokchr(c
));
945 if (!(pp
.option
& STRINGSPAN
))
950 else if (pp
.option
& STRINGSPLIT
)
962 error(m
, "%s in string", pptokchr(c
));
966 if (!(st
& DIRECTIVE
) || !(pp
.mode
& (HOSTED
|RELAX
)))
967 error(m
, "%s in character constant", pptokchr(c
));
970 error(m
, "%s in header constant", pptokchr(c
));
973 error(m
, "%s in %c quote", pptokchr(c
), quot
);
987 else if (st
& (SQUOTE
|QUOTE
))
994 else if (c
== quotquot
) st
&= ~ESCAPE
;
1003 else if (!DOSTRIP()) PUTCHR(c
);
1007 if (c
== '"' && !(st
& (COLLECTING
|NOTEXT
|PASSTHROUGH
|SKIPCONTROL
)) && (pp
.mode
& CATLITERAL
))
1009 if (c
== '"' && pp
.level
== 1 && !(st
& (COLLECTING
|JOINING
|NOTEXT
|SKIPCONTROL
)) && (pp
.mode
& CATLITERAL
))
1016 pp
.token
= pp
.catbuf
;
1018 ppstate
= (st
& STRIP
);
1020 ppstate
|= ADD
|QUOTE
;
1022 st
&= ~(NEWLINE
|STRIP
);
1025 * revert to the top level since string
1026 * concatenation crosses file boundaries
1027 * (allowing intervening directives)
1035 switch (c
= pplex())
1049 else if (m
== n
|| !(st
& SPACEOUT
))
1057 STRCOPY(op
, pp
.token
+ 2 + (*pp
.token
== ' '), s
);
1062 else if (m
== n
|| !(st
& SPACEOUT
))
1070 STRCOPY(op
, pp
.token
+ 1 + (*pp
.token
== ' '), s
);
1073 m
= error_info
.line
? (error_info
.line
- 1) : 0;
1081 pp
.state
|= HIDDEN
|SYNCLINE
;
1085 if ((st
& COMPATIBILITY
) && c
== '#' && *(pp
.token
- 1))
1087 *(pp
.token
+ 3) = *(pp
.token
+ 2);
1088 *(pp
.token
+ 2) = *(pp
.token
+ 1);
1089 *(pp
.token
+ 1) = *pp
.token
;
1090 *pp
.token
= *(pp
.token
- 1);
1096 else if (*(pp
.token
- 1))
1098 if (ppisidig(*pp
.token
))
1100 if (pp
.in
->type
== IN_MACRO
&& (s
= strchr(pp
.token
, MARK
)) && !*(s
+ 1))
1105 PUSH_STRING(pp
.token
);
1106 pp
.state
&= ~(JOINING
|NEWLINE
);
1107 pp
.state
|= ppstate
& ~(ADD
|QUOTE
);
1108 if ((ppstate
& (ADD
|QUOTE
)) == QUOTE
)
1118 c
= T_STRING
| qual
;
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
)
1129 st
&= ~(ESCAPE
|NEWLINE
);
1130 pp
.in
->flags
|= IN_tokens
;
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
;
1147 c
= T_STRING
| qual
;
1154 if (st
& (COLLECTING
|DIRECTIVE
|QUOTE
|SQUOTE
))
1159 if (c
== quot
) PUTCHR('\\');
1164 else if (st
& PASSTHROUGH
) PUTCHR(c
);
1166 else if (pp
.option
& PRESERVE
) PUTCHR(c
);
1183 if (!(st
& COMPATIBILITY
)) goto unknown
;
1184 if (st
& STRICT
) error(1, "%c: invalid character in octal character escape", c
);
1196 for (m
= 0; m
< 2; m
++)
1204 if (!(st
& COMPATIBILITY
))
1209 if (st
& STRICT
) error(1, "%c: invalid character in octal character escape", c
);
1220 n
= (n
<< 3) + c
- '0';
1228 if (n
& ~0777) error(1, "octal character constant too large");
1231 if (pp
.option
& MODERN
)
1237 if (st
& COMPATIBILITY
) goto unknown
;
1242 if (pp
.option
& MODERN
)
1250 if (st
& (COMPATIBILITY
|STRICT
)) goto unknown
;
1255 if (st
& COMPATIBILITY
) goto unknown
;
1258 for (m
= 0; m
< 3; m
++)
1273 n
= (n
<< 4) + c
- '0';
1281 n
= (n
<< 4) + c
- 'a' + 10;
1289 n
= (n
<< 4) + c
- 'A' + 10;
1292 if (!m
) error(1, "\\x%c: invalid character in hexadecimal character constant", c
);
1298 if (n
& ~0777) error(1, "hexadecimal character constant too large");
1300 PUTCHR(((n
>> 6) & 07) + '0');
1301 PUTCHR(((n
>> 3) & 07) + '0');
1302 PUTCHR((n
& 07) + '0');
1306 if (st
& (STRICT
|WARN
)) error(1, "\\%c: non-standard character constant", c
);
1316 if (st
& (DISABLE
|SKIPCONTROL
|SKIPMACRO
))
1319 pp
.mode
|= MARKMACRO
;
1320 st
&= ~(NEWLINE
|SKIPMACRO
);
1321 pp
.in
->flags
|= IN_tokens
;
1327 switch (state
= INDEX(rp
))
1334 tp
= op
- ((pp
.truncate
&& pp
.truncate
< (HITN
- HIT0
)) ? (pp
.truncate
- 1) : (HITN
- HIT0
));
1335 while (tp
> bp
&& ppisidig(*(tp
- 1))) tp
--;
1339 if ((tp
= op
- (state
- HIT0
)) > bp
&& *(tp
- 1) == 'L') tp
--;
1342 if (sym
= ppsymref(pp
.symtab
, tp
))
1356 ip
= sym
->macro
->value
;
1357 c
= sym
->macro
->size
;
1360 if (op
+ c
< xp
+ PPBUFSIZ
) n
= c
;
1361 else n
= xp
+ PPBUFSIZ
- op
;
1369 else if ((sym
->flags
& SYM_MULTILINE
) && pp
.linesync
)
1372 if (!(state
& NEWLINE
))
1374 (*pp
.linesync
)(error_info
.line
, error_info
.file
);
1379 pp
.in
->flags
|= IN_tokens
;
1382 if (st
& (COLLECTING
|DEFINITION
|DISABLE
|SKIPCONTROL
|SKIPMACRO
))
1385 pp
.mode
|= MARKMACRO
;
1386 st
&= ~(NEWLINE
|NOEXPAND
|SKIPMACRO
);
1390 pp
.in
->flags
|= IN_tokens
;
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
);
1402 if (pp
.symbol
= sym
)
1404 if ((sym
->flags
& SYM_KEYWORD
) && (!pp
.truncate
|| (op
- tp
) <= pp
.truncate
|| (tp
[pp
.truncate
] = '_', tp
[pp
.truncate
+ 1] = 0, pp
.symbol
= sym
= (pp
.option
& NOHASH
) ? ppsymref(pp
.symtab
, tp
) : ppsymset(pp
.symtab
, tp
), 0)))
1406 c
= ((struct ppsymkey
*)sym
)->lex
;
1409 #define ADVANCE() do{if(pp.toknxt<op)pp.token=pp.toknxt;}while(0)
1411 #define NOISE_BRACE 01
1412 #define NOISE_NOSPACEOUT 02
1413 #define NOISE_PAREN 04
1415 if ((pp
.option
& NOISE
) && ppisnoise(c
))
1422 PPCOMMENT ppcomment
;
1427 if (!(pp
.state
& SPACEOUT
))
1429 pp
.state
|= SPACEOUT
;
1430 f
|= NOISE_NOSPACEOUT
;
1432 ppcomment
= pp
.comment
;
1434 op
= (pptoken
= tp
) + MAXTOKEN
;
1443 switch (c
= pplex())
1451 if (f
& NOISE_PAREN
)
1462 f
|= NOISE_BRACE
|NOISE_PAREN
;
1468 else if (c
== m
) n
++;
1473 if (c
== p
&& --n
<= 0)
1475 if (c
== '}') break;
1496 * NOTE: token expanded again
1500 while (s
> pp
.token
) ungetchr(*--s
);
1501 *(pp
.toknxt
= s
) = 0;
1536 *(pp
.toknxt
= pp
.token
) = 0;
1545 pp
.comment
= ppcomment
;
1546 if (f
& NOISE_NOSPACEOUT
)
1547 pp
.state
&= ~SPACEOUT
;
1553 if (pp
.option
& NOISEFILTER
)
1562 else if ((pp
.option
& NOISE
) && c
== T_ID
&& strneq(tp
, "__builtin_", 10))
1564 hashlook(pp
.symtab
, tp
, HASH_DELETE
, NiL
);
1565 pp
.symbol
= sym
= (struct ppsymbol
*)ppkeyset(pp
.symtab
, tp
);
1566 sym
->flags
|= SYM_KEYWORD
;
1567 c
= ((struct ppsymkey
*)sym
)->lex
= T_BUILTIN
;
1577 st
&= ~(NEWLINE
|PASSEOF
);
1578 pp
.in
->flags
|= IN_tokens
;
1580 else st
&= ~PASSEOF
;
1583 if (sym
= ppsymref(pp
.symtab
, tp
))
1591 if ((sym
->flags
& SYM_MULTILINE
) && pp
.linesync
)
1594 (*pp
.linesync
)(error_info
.line
, error_info
.file
);
1610 if (pp
.truncate
&& (op
- tp
) > pp
.truncate
)
1612 tp
[pp
.truncate
] = 0;
1617 if (!(pp
.option
& NOHASH
)) sym
= ppsymset(pp
.symtab
, tp
);
1618 else if (!(sym
= ppsymref(pp
.symtab
, tp
))) goto fsm_symbol
;
1630 pp
.in
->flags
|= IN_tokens
;
1631 if ((st
& STRICT
) && pp
.in
->type
!= IN_MACRO
&& pp
.in
->type
!= IN_MULTILINE
)
1633 if (!(pp
.mode
& HOSTED
)) error(1, "non-standard reference to #(...)");
1646 if (st
& (COLLECTING
|DEFINITION
|DISABLE
|SKIPCONTROL
))
1671 if (!(st
& NEWLINE
) || !(pp
.in
->type
& IN_TOP
))
1675 pp
.in
->flags
|= IN_tokens
;
1679 if (*(s
= tp
) != '#')
1682 if ((st
& (COMPATIBILITY
|TRANSITION
)) == COMPATIBILITY
) goto fsm_nondirective
;
1684 while (*s
== ' ' || *s
== '\t') s
++;
1685 if (*s
!= '#') goto fsm_nondirective
;
1689 if (!(st
& NEWLINE
) || (st
& DEFINITION
) || !(pp
.in
->type
& IN_TOP
))
1694 if (!(st
& DEFINITION
))
1698 else if (pp
.level
== 1 && !(st
& (JOINING
|SPACEOUT
)) && !(pp
.option
& PRESERVE
))
1702 PPCOMMENT ppcomment
;
1705 pp
.toknxt
= oop
= op
;
1706 pp
.state
|= SPACEOUT
;
1707 ppcomment
= pp
.comment
;
1709 op
= (pptoken
= tp
) + MAXTOKEN
;
1725 pp
.comment
= ppcomment
;
1726 pp
.state
&= ~SPACEOUT
;
1731 if (pp
.pragma
&& !(st
& NOTEXT
))
1735 (*pp
.pragma
)(NiL
, NiL
, NiL
, tp
, 1);
1744 if ((st
& (COLLECTING
|STRICT
)) == (COLLECTING
|STRICT
))
1745 error(1, "directives in macro call arguments are not portable");
1747 if (c
== '#' && pp
.in
->type
== IN_RESCAN
)
1750 * pass line to pp.pragma VERBATIM
1755 while ((c
= GETCHR()) && c
!= '\n')
1756 if ((*s
++ = c
) == MARK
) SKIPIN();
1757 if (pp
.pragma
&& !(st
& NOTEXT
))
1761 (*pp
.pragma
)(NiL
, NiL
, NiL
, pp
.valbuf
, 1);
1775 if (st
& (NOTEXT
|SKIPCONTROL
))
1795 if (op
== tp
&& !(st
& JOINING
) && pp
.in
->type
== IN_FILE
&& !(pp
.option
& PRESERVE
))
1797 st
|= NEWLINE
|HIDDEN
;
1807 else if (!(pp
.in
->flags
& IN_noguard
))
1810 if ((c
= *tp
++) != ' ' && c
!= '\t')
1812 pp
.in
->flags
|= IN_tokens
;
1819 if (*ip
== '\n' && *(ip
+ 1) != '\n' && !pp
.macref
&& !(st
& (ADD
|HIDDEN
)))
1825 if ((st
& NOTEXT
) && ((pp
.mode
& FILEDEPS
) || (pp
.option
& (DEFINITIONS
|PREDEFINITIONS
))))
1829 debug((-5, "token[%d] %03o = %s [line=%d]", pp
.level
, c
, pptokchr(c
), error_info
.line
));
1844 if (!(st
& (JOINING
|SPACEOUT
)))
1846 debug((-5, "token[%d] %03o = %s [line=%d]", pp
.level
, c
, pptokchr(c
), error_info
.line
));
1852 if (st
& SKIPCONTROL
)
1866 c
= TYPE(state
) | qual
;
1871 c
= TYPE(state
) | qual
;
1878 if (st
& NOVERTICAL
)
1880 error(1, "%s invalid in directives", pptokchr(c
));
1885 if (st
& COMPATIBILITY
) st
|= NEWLINE
;
1888 if (!(pp
.in
->flags
& IN_noguard
))
1890 if ((c
= *tp
++) != ' ' && c
!= '\t')
1892 pp
.in
->flags
|= IN_tokens
;
1905 if ((st
& (COMPATIBILITY
|TRANSITION
)) == COMPATIBILITY
) st
&= ~NEWLINE
;
1909 if ((st
& (COMPATIBILITY
|SPACEOUT
)) && !(st
& TRANSITION
))
1911 if (st
& (COMPILE
|NOTEXT
))
1914 if ((st
& (JOINING
|NOTEXT
|SPACEOUT
)) != SPACEOUT
)
1916 if ((st
& (NOTEXT
|SPACEOUT
)) != SPACEOUT
)
1922 if (state
= rp
[c
]) goto fsm_next
;
1928 if (!(st
& JOINING
))
1934 if (state
= rp
[c
]) goto fsm_next
;
1944 if (state
= rp
[c
]) goto fsm_next
;
1947 if (st
& (NOSPACE
|SKIPCONTROL
))
1952 if (state
= rp
[c
]) goto fsm_next
;
1960 if (!(pp
.option
& PRESERVE
))
1978 switch (pp
.in
->type
)
1985 if ((st
& JOINING
) && (!INQUOTE(rp
) || quot
!= '"') || pp
.level
> 1 && (rp
== fsm
[START
] || INQUOTE(rp
)))
1987 if (pp
.level
> 1 && (rp
== fsm
[START
] || INQUOTE(rp
)))
1996 if (!(st
& (DEFINITION
|DISABLE
)))
2000 if (pp
.macp
->arg
[c
- ARGOFFSET
][-1])
2001 PUSH_EXPAND(pp
.macp
->arg
[c
- ARGOFFSET
], pp
.macp
->line
);
2003 PUSH_COPY(pp
.macp
->arg
[c
- ARGOFFSET
], pp
.macp
->line
);
2010 c
= GETCHR() - ARGOFFSET
;
2011 if (!*(s
= pp
.macp
->arg
[c
]) && (pp
.in
->symbol
->flags
& SYM_VARIADIC
) && pp
.in
->symbol
->macro
->arity
== (c
+ 1))
2014 while (--op
> tp
&& --s
> bp
&& ppisidig(*s
));
2019 PUSH_COPY(s
, pp
.macp
->line
);
2025 error_info
.file
= (char*)strtoul(ip
, &s
, 16);
2026 debug((-6, "actual sync: file = \"%s\"", error_info
.file
));
2030 error_info
.line
= strtoul(ip
, &s
, 16);
2031 debug((-6, "actual sync: line = %d", error_info
.line
));
2037 PUSH_QUOTE(pp
.macp
->arg
[c
- ARGOFFSET
], pp
.macp
->line
);
2039 *(bp
= ip
- 1) = '"';
2040 if (st
& (COLLECTING
|EOF2NL
|JOINING
)) rp
= fsm
[START
];
2041 if (state
= rp
[c
= '"']) goto fsm_next
;
2046 PUSH_SQUOTE(pp
.macp
->arg
[c
- ARGOFFSET
], pp
.macp
->line
);
2049 if (st
& COLLECTING
) rp
= fsm
[START
];
2050 if (state
= rp
[c
= '\'']) goto fsm_next
;
2053 if (pp
.in
->type
!= IN_COPY
)
2060 if (pp
.in
->type
== IN_EXPAND
)
2069 if ((state
&= ~SPLICE
) >= TERMINAL
) goto fsm_terminal
;
2073 error(PANIC
, "invalid mark op `%c'", LASTCHR());
2078 if ((st
& (JOINING
|QUOTE
)) == JOINING
)
2086 if (rp
!= fsm
[START
] && !INQUOTE(rp
))
2089 if (rp
!= fsm
[START
] && !INQUOTE(rp
))
2091 else if (pp
.level
> 1)
2104 if (pp
.in
->type
== IN_FILE
)
2110 if (c
= trigraph
[n
])
2112 if ((st
& WARN
) && (st
& (COMPATIBILITY
|TRANSITION
)) && !(pp
.mode
& HOSTED
) && !INCOMMENT(rp
))
2113 error(1, "trigraph conversion %c%c%c -> %c%s", '?', '?', n
, c
, (st
& TRANSITION
) ? "" : " inhibited");
2115 if ((st
& (COMPATIBILITY
|TRANSITION
)) != COMPATIBILITY
)
2119 if (state
= rp
[c
]) goto fsm_next
;
2125 if (n
!= EOB
) BACKIN();
2128 else if (n
!= EOB
) BACKIN();
2135 * digraph = --trigraph
2138 if (pp
.in
->type
== IN_FILE
&& (pp
.option
& PLUSPLUS
))
2145 if (c
== '<') m
= '{';
2148 if (c
== '%') m
= '}';
2149 else if (c
== ':') m
= ']';
2152 if (c
== '%') m
= '#';
2153 else if (c
== '<') m
= '[';
2158 if ((st
& WARN
) && (st
& (COMPATIBILITY
|TRANSITION
)) && !(pp
.mode
& HOSTED
) && !INCOMMENT(rp
))
2159 error(1, "digraph conversion %c%c -> %c%s", c
, n
, m
, (st
& TRANSITION
) ? "" : " inhibited");
2161 if ((st
& (COMPATIBILITY
|TRANSITION
)) != COMPATIBILITY
)
2164 *(bp
= ip
- 1) = c
= m
;
2165 if (state
= rp
[c
]) goto fsm_next
;
2171 if (n
!= EOB
) BACKIN();
2179 if (pp
.in
->type
== IN_FILE
&& (!(pp
.option
& PLUSSPLICE
) || !INCOMMENTXX(rp
)))
2183 if ((pp
.option
& SPLICESPACE
) && !INQUOTE(rp
))
2192 if (n
!= '\n' && n
!= EOB
)
2200 if ((pp
.option
& STRINGSPLIT
) && quot
== '"')
2206 else if (*pp
.lineid
)
2220 if (!INQUOTE(rp
) && (st
& (COMPATIBILITY
|DEFINITION
|TRANSITION
)) == (COMPATIBILITY
|DEFINITION
))
2229 c
= (pp
.option
& SPLICECAT
) ? '\t' : ' ';
2251 else if ((n
== 'u' || n
== 'U') && !INQUOTE(rp
))
2259 else if ((st
& (COMPATIBILITY
|TRANSITION
)) == COMPATIBILITY
&& (n
== '"' || n
== '\'') && !INQUOTE(rp
))
2269 if (m
&& INSPACE(rp
))
2273 else if ((st
& (COMPATIBILITY
|TRANSITION
)) == COMPATIBILITY
&& !INQUOTE(rp
))
2276 if (n
== '"' || n
== '\'')
2293 if (pp
.in
->type
== IN_FILE
)
2298 *(bp
= ip
- 1) = c
= n
;
2299 if (state
= rp
[c
]) goto fsm_next
;
2302 if (n
!= EOB
) BACKIN();
2310 if ((pp
.option
& ZEOF
) && pp
.in
->type
== IN_FILE
)
2312 pp
.in
->flags
|= IN_eof
;
2319 if ((state
&= ~SPLICE
) >= TERMINAL
)
2340 pp
.in
->flags
|= IN_tokens
;
2350 if (st
& SKIPCONTROL
)
2357 error_info
.line
+= spliced
;
2360 debug((-5, "token[%d] %03o = %s", pp
.level
, c
, pptokstr(tp
, 0)));
2363 error_info
.indent
--;
2374 * output pool status on exit
2380 error(ERROR_OUTPUT
|0, pp
.pool
.output
, "%d", error_info
.errors
!= 0);
2384 * loop on < input output >
2394 if (!sfnew(sfstdin
, NiL
, SF_UNBOUND
, pp
.pool
.input
, SF_READ
))
2395 error(ERROR_SYSTEM
|3, "cannot dup pool input");
2401 ppsearch(".", T_STRING
, SEARCH_EXISTS
);
2404 * loop on < input output >
2408 while (ifile
= sfgetr(sfstdin
, '\n', 1))
2410 if (!(ofile
= strchr(ifile
, ' ')))
2411 error(3, "%s: pool output file expected", ifile
);
2413 waitpid(0, NiL
, WNOHANG
);
2417 error(ERROR_SYSTEM
|3, "cannot fork pool");
2420 error_info
.errors
= 0;
2421 error_info
.warnings
= 0;
2423 if (open(ifile
, O_RDONLY
))
2424 error(ERROR_SYSTEM
|3, "%s: cannot read", ifile
);
2426 if (open(ofile
, O_WRONLY
|O_CREAT
|O_TRUNC
, S_IRUSR
|S_IWUSR
|S_IRGRP
|S_IWGRP
|S_IROTH
|S_IWOTH
) != 1)
2427 error(ERROR_SYSTEM
|3, "%s: cannot create", ofile
);
2429 pathcanon(ifile
, 0);
2430 ifile
= ppsetfile(ifile
)->name
;
2435 error(3, "#%s must be enabled for checkpoints", dirname(PRAGMA
));
2436 (*pp
.pragma
)(dirname(PRAGMA
), pp
.pass
, keyname(X_CHECKPOINT
), pp
.checkpoint
, 1);
2439 PUSH_FILE(ifile
, 0);
2443 while (wait(NiL
) != -1);