1 /* neatcc preprocessor */
10 #include <sys/types.h>
19 char name
[NAMELEN
]; /* macro name */
20 char def
[MDEFLEN
]; /* macro definition */
21 char args
[NARGS
][NAMELEN
];
22 int nargs
; /* number of arguments */
23 int isfunc
; /* macro is a function */
24 int undef
; /* macro is removed */
26 static int mcount
= 1; /* number of macros */
27 static int mhead
[256]; /* macro hash table heads */
28 static int mnext
[NDEFS
]; /* macro hash table next entries */
36 /* preprocessing input buffers for files, macros and macro arguments */
46 char args
[NARGS
][MARGLEN
]; /* arguments passed to a macro */
48 int arg_buf
; /* the bufs index of the owning macro */
51 static int bufs_limit
= 0; /* cpp_read() limit; useful in cpp_eval() */
53 void die(char *fmt
, ...)
58 vsprintf(msg
, fmt
, ap
);
60 write(2, msg
, strlen(msg
));
64 static void buf_new(int type
, char *dat
, long dlen
)
67 bufs
[bufs_n
- 1].buf
= buf
;
68 bufs
[bufs_n
- 1].cur
= cur
;
69 bufs
[bufs_n
- 1].len
= len
;
72 die("nomem: NBUFS reached!\n");
77 bufs
[bufs_n
- 1].type
= type
;
80 static void buf_file(char *path
, char *dat
, int dlen
)
82 buf_new(BUF_FILE
, dat
, dlen
);
83 strcpy(bufs
[bufs_n
- 1].path
, path
? path
: "");
86 static int macro_arg(struct macro
*m
, char *arg
);
88 static void buf_macro(struct macro
*m
)
98 if (quote
&& s
[0] == quote
)
100 else if (!quote
&& s
[0] == '"')
102 else if (!quote
&& s
[0] == '\'')
104 if (!quote
&& s
[0] == '#')
105 numsign
= s
[1] == '#' ? 2 : 1;
106 if (numsign
&& s
[numsign
]) {
107 struct buf
*mbuf
= &bufs
[bufs_n
];
108 char *r
= s
+ numsign
;
110 while (*r
&& d
- arg
< sizeof(arg
) - 1 &&
111 (isalnum((unsigned char) *r
) || *r
== '_'))
114 if (macro_arg(m
, arg
) >= 0) {
115 char *def
= mbuf
->args
[macro_arg(m
, arg
)];
116 if (def
&& numsign
== 1) {
117 mem_putc(&mem
, '\"');
120 mem_putc(&mem
, '\\');
121 mem_putc(&mem
, (unsigned char) *def
++);
123 mem_putc(&mem
, '\"');
127 if (def
&& numsign
== 2) {
129 mem_putc(&mem
, (unsigned char) *def
++);
135 if (quote
&& s
[0] == '\\')
136 mem_putc(&mem
, (unsigned char) *s
++);
138 mem_putc(&mem
, (unsigned char) *s
++);
141 buf_new(BUF_MACRO
, mem_get(&mem
), len
);
143 bufs
[bufs_n
- 1].macro
= m
;
146 static void buf_arg(char *arg
, int mbuf
)
148 buf_new(BUF_ARG
, arg
, strlen(arg
));
149 bufs
[bufs_n
- 1].arg_buf
= mbuf
;
152 static void buf_pop(void)
155 if (bufs
[bufs_n
].type
== BUF_FILE
|| bufs
[bufs_n
].type
== BUF_MACRO
)
158 cur
= bufs
[bufs_n
- 1].cur
;
159 len
= bufs
[bufs_n
- 1].len
;
160 buf
= bufs
[bufs_n
- 1].buf
;
164 static int buf_iseval(void)
167 for (i
= bufs_n
- 1; i
>= 0; i
--)
168 if (bufs
[i
].type
== BUF_EVAL
)
173 static size_t file_size(int fd
)
181 static int include_file(char *path
)
183 int fd
= open(path
, O_RDONLY
);
189 size
= file_size(fd
) + 1;
191 while ((n
= read(fd
, dat
+ nr
, size
- nr
)) > 0)
195 buf_file(path
, dat
, nr
);
199 int cpp_init(char *path
)
201 return include_file(path
);
204 static int jumpws(void)
207 while (cur
< len
&& isspace(buf
[cur
]))
212 static void read_word(char *dst
)
215 while (cur
< len
&& (isalnum(buf
[cur
]) || buf
[cur
] == '_'))
220 static int jumpcomment(void)
222 if (buf
[cur
] == '/' && buf
[cur
+ 1] == '*') {
223 while (++cur
< len
) {
224 if (buf
[cur
] == '*' && buf
[cur
+ 1] == '/') {
230 if (buf
[cur
] == '/' && buf
[cur
+ 1] == '/') {
231 while (++cur
< len
&& buf
[cur
] != '\n')
232 if (buf
[cur
] == '\\')
239 static int jumpstr(void)
241 if (buf
[cur
] == '\'') {
242 while (++cur
< len
&& buf
[cur
] != '\'')
243 if (buf
[cur
] == '\\')
248 if (buf
[cur
] == '"') {
249 while (++cur
< len
&& buf
[cur
] != '"')
250 if (buf
[cur
] == '\\')
258 static void read_tilleol(char *dst
)
260 while (cur
< len
&& isspace(buf
[cur
]) && buf
[cur
] != '\n')
262 while (cur
< len
&& buf
[cur
] != '\n') {
264 if (buf
[cur
] == '\\' && buf
[cur
+ 1] == '\n') {
269 memcpy(dst
, buf
+ last
, cur
- last
);
280 static char *locs
[NLOCS
] = {};
281 static int nlocs
= 0;
283 /* header directory */
284 void cpp_path(char *s
)
289 static int include_find(char *name
, int std
)
292 for (i
= std
? nlocs
- 1 : nlocs
; i
>= 0; i
--) {
295 sprintf(path
, "%s/%s", locs
[i
], name
);
298 if (!include_file(path
))
304 static void readarg(char *s
)
308 while (cur
< len
&& (depth
|| (buf
[cur
] != ',' && buf
[cur
] != ')'))) {
309 if (!jumpstr() || !jumpcomment())
311 switch (buf
[cur
++]) {
325 memcpy(s
, buf
+ beg
, cur
- beg
);
330 /* find a macro; if undef is nonzero, search #undef-ed macros too */
331 static int macro_find(char *name
, int undef
)
333 int i
= mhead
[(unsigned char) name
[0]];
335 if (!strcmp(name
, macros
[i
].name
))
336 if (!macros
[i
].undef
|| undef
)
343 static void macro_undef(char *name
)
345 int i
= macro_find(name
, 0);
350 static int macro_new(char *name
)
352 int i
= macro_find(name
, 1);
356 die("nomem: NDEFS reached!\n");
358 strcpy(macros
[i
].name
, name
);
359 mnext
[i
] = mhead
[(unsigned char) name
[0]];
360 mhead
[(unsigned char) name
[0]] = i
;
364 static void macro_define(void)
369 d
= ¯os
[macro_new(name
)];
373 if (buf
[cur
] == '(') {
376 while (cur
< len
&& buf
[cur
] != ')') {
377 readarg(d
->args
[d
->nargs
++]);
387 read_tilleol(d
->def
);
390 static char ebuf
[MARGLEN
];
394 static long evalexpr(void);
396 static long cpp_eval(void)
398 char evalbuf
[MARGLEN
];
402 read_tilleol(evalbuf
);
403 buf_new(BUF_EVAL
, evalbuf
, strlen(evalbuf
));
406 old_limit
= bufs_limit
;
408 while (!cpp_read(&cbuf
, &clen
)) {
409 memcpy(ebuf
+ elen
, cbuf
, clen
);
412 bufs_limit
= old_limit
;
418 static void jumpifs(int jumpelse
)
422 if (buf
[cur
] == '#') {
426 if (!strcmp("else", cmd
))
427 if (!depth
&& !jumpelse
)
429 if (!strcmp("elif", cmd
))
430 if (!depth
&& !jumpelse
&& cpp_eval())
432 if (!strcmp("endif", cmd
)) {
438 if (!strcmp("ifdef", cmd
) || !strcmp("ifndef", cmd
) ||
451 static int cpp_cmd(void)
456 if (!strcmp("define", cmd
)) {
460 if (!strcmp("undef", cmd
)) {
466 if (!strcmp("ifdef", cmd
) || !strcmp("ifndef", cmd
) ||
467 !strcmp("if", cmd
)) {
471 int not = cmd
[2] == 'n';
473 matched
= not ? macro_find(name
, 0) < 0 :
474 macro_find(name
, 0) >= 0;
476 matched
= cpp_eval();
482 if (!strcmp("else", cmd
) || !strcmp("elif", cmd
)) {
486 if (!strcmp("endif", cmd
))
488 if (!strcmp("include", cmd
)) {
493 e
= strchr(buf
+ cur
+ 1, buf
[cur
] == '"' ? '"' : '>');
494 memcpy(file
, s
, e
- s
);
497 if (include_find(file
, *e
== '>') == -1)
498 err("cannot include <%s>\n", file
);
501 err("unknown directive <%s>\n", cmd
);
505 static int macro_arg(struct macro
*m
, char *arg
)
508 for (i
= 0; i
< m
->nargs
; i
++)
509 if (!strcmp(arg
, m
->args
[i
]))
514 static int buf_arg_find(char *name
)
517 for (i
= bufs_n
- 1; i
>= 0; i
--) {
518 struct buf
*mbuf
= &bufs
[i
];
519 struct macro
*m
= mbuf
->macro
;
520 if (mbuf
->type
== BUF_MACRO
&& macro_arg(m
, name
) >= 0)
522 if (mbuf
->type
== BUF_ARG
)
528 static void macro_expand(char *name
)
532 if ((mbuf
= buf_arg_find(name
)) >= 0) {
533 int arg
= macro_arg(bufs
[mbuf
].macro
, name
);
534 char *dat
= bufs
[mbuf
].args
[arg
];
538 m
= ¯os
[macro_find(name
, 0)];
544 if (buf
[cur
] == '(') {
546 struct buf
*mbuf
= &bufs
[bufs_n
];
549 while (cur
< len
&& buf
[cur
] != ')') {
550 readarg(mbuf
->args
[i
++]);
558 mbuf
->args
[i
++][0] = '\0';
564 static int buf_expanding(char *macro
)
567 for (i
= bufs_n
- 1; i
>= 0; i
--) {
568 if (bufs
[i
].type
== BUF_ARG
)
570 if (bufs
[i
].type
== BUF_MACRO
&&
571 !strcmp(macro
, bufs
[i
].macro
->name
))
577 /* return 1 for plain macros and arguments and 2 for function macros */
578 static int expandable(char *word
)
581 if (buf_arg_find(word
) >= 0)
583 if (buf_expanding(word
))
585 i
= macro_find(word
, 0);
586 return i
>= 0 ? macros
[i
].isfunc
+ 1 : 0;
589 void cpp_define(char *name
, char *def
)
591 char tmp_buf
[MDEFLEN
];
592 sprintf(tmp_buf
, "%s\t%s", name
, def
);
593 buf_new(BUF_TEMP
, tmp_buf
, strlen(tmp_buf
));
598 static int seen_macro
; /* seen a macro; 2 if a function macro */
599 static char seen_name
[NAMELEN
]; /* the name of the last macro */
604 int cpp_read(char **obuf
, long *olen
)
610 if (seen_macro
== 1) {
611 macro_expand(seen_name
);
615 if (bufs_n
< bufs_limit
+ 1)
620 if (cur
< len
&& buf
[cur
] == '#')
630 if (seen_macro
== 2) {
632 macro_expand(seen_name
);
639 if (isalnum(buf
[cur
]) || buf
[cur
] == '_') {
642 seen_macro
= expandable(word
);
644 strcpy(seen_name
, word
);
648 if (buf_iseval() && !strcmp("defined", word
)) {
651 if (buf
[cur
] == '(') {
665 /* macros are expanded later; ignoring their names */
666 end
= jump_name
? cur
- strlen(seen_name
) : cur
;
668 hunk_off
+= hunk_len
;
669 hunk_len
= end
- old
;
676 /* preprocessor constant expression evaluation */
678 #define TOK2(a) ((a)[0] << 16 | (a)[1] << 8)
683 static char etok
[NAMELEN
];
686 static char *tok2
[] = {
687 "<<", ">>", "&&", "||", "==", "!=", "<=", ">="
690 static int eval_tok(void)
694 while (ecur
< elen
) {
695 while (ecur
< elen
&& isspace(ebuf
[ecur
]))
697 if (ebuf
[ecur
] == '/' && ebuf
[ecur
+ 1] == '*') {
698 while (ecur
< elen
&& (ebuf
[ecur
- 2] != '*' ||
699 ebuf
[ecur
- 1] != '/'))
707 if (isalpha(ebuf
[ecur
]) || ebuf
[ecur
] == '_') {
708 while (isalnum(ebuf
[ecur
]) || ebuf
[ecur
] == '_')
713 if (isdigit(ebuf
[ecur
])) {
714 while (isdigit(ebuf
[ecur
]))
716 while (tolower(ebuf
[ecur
]) == 'u' || tolower(ebuf
[ecur
]) == 'l')
721 for (i
= 0; i
< LEN(tok2
); i
++)
722 if (TOK2(tok2
[i
]) == TOK2(ebuf
+ ecur
)) {
723 int ret
= TOK2(tok2
[i
]);
730 static int eval_see(void)
737 static int eval_get(void)
747 static long eval_num(void)
752 static int eval_jmp(int tok
)
754 if (eval_see() == tok
) {
761 static void eval_expect(int tok
)
766 static char *eval_id(void)
771 static long evalcexpr(void);
773 static long evalatom(void)
775 if (!eval_jmp(TOK_NUM
))
777 if (!eval_jmp(TOK_NAME
)) {
778 int parens
= !eval_jmp('(');
780 eval_expect(TOK_NAME
);
781 ret
= macro_find(eval_id(), 0) >= 0;
786 if (!eval_jmp('(')) {
787 long ret
= evalcexpr();
794 static long evalpre(void)
805 static long evalmul(void)
807 long ret
= evalpre();
809 if (!eval_jmp('*')) {
813 if (!eval_jmp('/')) {
817 if (!eval_jmp('%')) {
826 static long evaladd(void)
828 long ret
= evalmul();
830 if (!eval_jmp('+')) {
834 if (!eval_jmp('-')) {
843 static long evalshift(void)
845 long ret
= evaladd();
847 if (!eval_jmp(TOK2("<<"))) {
851 if (!eval_jmp(TOK2(">>"))) {
860 static long evalcmp(void)
862 long ret
= evalshift();
864 if (!eval_jmp('<')) {
865 ret
= ret
< evalshift();
868 if (!eval_jmp('>')) {
869 ret
= ret
> evalshift();
872 if (!eval_jmp(TOK2("<="))) {
873 ret
= ret
<= evalshift();
876 if (!eval_jmp(TOK2(">="))) {
877 ret
= ret
>= evalshift();
885 static long evaleq(void)
887 long ret
= evalcmp();
889 if (!eval_jmp(TOK2("=="))) {
890 ret
= ret
== evalcmp();
893 if (!eval_jmp(TOK2("!="))) {
894 ret
= ret
!= evalcmp();
902 static long evalbitand(void)
905 while (!eval_jmp('&'))
910 static long evalxor(void)
912 long ret
= evalbitand();
913 while (!eval_jmp('^'))
918 static long evalbitor(void)
920 long ret
= evalxor();
921 while (!eval_jmp('|'))
926 static long evaland(void)
928 long ret
= evalbitor();
929 while (!eval_jmp(TOK2("&&")))
930 ret
= ret
&& evalbitor();
934 static long evalor(void)
936 long ret
= evaland();
937 while (!eval_jmp(TOK2("||")))
938 ret
= ret
|| evaland();
942 static long evalcexpr(void)
949 while (eval_get() != ':')
954 static long evalexpr(void)
960 static int buf_loc(char *s
, int off
)
964 while ((s
= strchr(s
, '\n')) && s
< e
) {
971 char *cpp_loc(long addr
)
973 static char loc
[256];
976 for (i
= bufs_n
- 1; i
> 0; i
--)
977 if (bufs
[i
].type
== BUF_FILE
)
979 if (addr
>= hunk_off
&& i
== bufs_n
- 1)
980 line
= buf_loc(buf
, (cur
- hunk_len
) + (addr
- hunk_off
));
982 line
= buf_loc(bufs
[i
].buf
, bufs
[i
].cur
);
983 sprintf(loc
, "%s:%d", bufs
[i
].path
, line
);