diff options
Diffstat (limited to 'pre-process.c')
| -rw-r--r-- | pre-process.c | 255 |
1 files changed, 194 insertions, 61 deletions
diff --git a/pre-process.c b/pre-process.c index 7d335ab0..da4b7acd 100644 --- a/pre-process.c +++ b/pre-process.c @@ -47,6 +47,7 @@ static struct ident_list *macros; // only needed for -dD static int false_nesting = 0; static int counter_macro = 0; // __COUNTER__ expansion +static int include_level = 0; #define INCLUDEPATHS 300 const char *includepath[INCLUDEPATHS+1] = { @@ -145,48 +146,89 @@ static int token_defined(struct token *token) return 0; } -static void replace_with_defined(struct token *token) +static void replace_with_bool(struct token *token, bool val) { static const char *string[] = { "0", "1" }; - int defined = token_defined(token); token_type(token) = TOKEN_NUMBER; - token->number = string[defined]; + token->number = string[val]; +} + +static void replace_with_defined(struct token *token) +{ + replace_with_bool(token, token_defined(token)); +} + +static void replace_with_has_builtin(struct token *token) +{ + struct symbol *sym = lookup_symbol(token->ident, NS_SYMBOL); + replace_with_bool(token, sym && sym->builtin); +} + +static void expand_line(struct token *token) +{ + replace_with_integer(token, token->pos.line); +} + +static void expand_file(struct token *token) +{ + replace_with_string(token, stream_name(token->pos.stream)); +} + +static void expand_basefile(struct token *token) +{ + replace_with_string(token, base_filename); +} + +static time_t t = 0; +static void expand_date(struct token *token) +{ + static char buffer[12]; /* __DATE__: 3 + ' ' + 2 + ' ' + 4 + '\0' */ + + if (!t) + time(&t); + strftime(buffer, 12, "%b %e %Y", localtime(&t)); + replace_with_string(token, buffer); +} + +static void expand_time(struct token *token) +{ + static char buffer[9]; /* __TIME__: 2 + ':' + 2 + ':' + 2 + '\0' */ + + if (!t) + time(&t); + strftime(buffer, 9, "%T", localtime(&t)); + replace_with_string(token, buffer); +} + +static void expand_counter(struct token *token) +{ + replace_with_integer(token, counter_macro++); +} + +static void expand_include_level(struct token *token) +{ + replace_with_integer(token, include_level - 1); } static int expand_one_symbol(struct token **list) { struct token *token = *list; struct symbol *sym; - static char buffer[12]; /* __DATE__: 3 + ' ' + 2 + ' ' + 4 + '\0' */ - static time_t t = 0; if (token->pos.noexpand) return 1; sym = lookup_macro(token->ident); - if (sym) { + if (!sym) + return 1; + if (sym->expander) { + sym->expander(token); + return 1; + } else { sym->used_in = file_scope; return expand(list, sym); } - if (token->ident == &__LINE___ident) { - replace_with_integer(token, token->pos.line); - } else if (token->ident == &__FILE___ident) { - replace_with_string(token, stream_name(token->pos.stream)); - } else if (token->ident == &__DATE___ident) { - if (!t) - time(&t); - strftime(buffer, 12, "%b %e %Y", localtime(&t)); - replace_with_string(token, buffer); - } else if (token->ident == &__TIME___ident) { - if (!t) - time(&t); - strftime(buffer, 9, "%T", localtime(&t)); - replace_with_string(token, buffer); - } else if (token->ident == &__COUNTER___ident) { - replace_with_integer(token, counter_macro++); - } - return 1; } static inline struct token *scan_next(struct token **where) @@ -511,13 +553,10 @@ static int merge(struct token *left, struct token *right) left->pos.noexpand = 0; return 1; - case TOKEN_NUMBER: { - char *number = __alloc_bytes(strlen(buffer) + 1); - memcpy(number, buffer, strlen(buffer) + 1); + case TOKEN_NUMBER: token_type(left) = TOKEN_NUMBER; /* could be . + num */ - left->number = number; + left->number = xstrdup(buffer); return 1; - } case TOKEN_SPECIAL: if (buffer[2] && buffer[3]) @@ -868,8 +907,7 @@ static int try_include(const char *path, const char *filename, int flen, struct return 1; fd = open(fullname, O_RDONLY); if (fd >= 0) { - char * streamname = __alloc_bytes(plen + flen); - memcpy(streamname, fullname, plen + flen); + char *streamname = xmemdup(fullname, plen + flen); *where = tokenize(streamname, fd, *where, next_path); close(fd); return 1; @@ -1299,40 +1337,16 @@ Earg: return NULL; } -static int do_handle_define(struct stream *stream, struct token **line, struct token *token, int attr) +static int do_define(struct position pos, struct token *token, struct ident *name, + struct token *arglist, struct token *expansion, int attr) { - struct token *arglist, *expansion; - struct token *left = token->next; struct symbol *sym; - struct ident *name; - int ret; - - if (token_type(left) != TOKEN_IDENT) { - sparse_error(token->pos, "expected identifier to 'define'"); - return 1; - } - - name = left->ident; - - arglist = NULL; - expansion = left->next; - if (!expansion->pos.whitespace) { - if (match_op(expansion, '(')) { - arglist = expansion; - expansion = parse_arguments(expansion); - if (!expansion) - return 1; - } else if (!eof_token(expansion)) { - warning(expansion->pos, - "no whitespace before object-like macro body"); - } - } + int ret = 1; expansion = parse_expansion(expansion, arglist, name); if (!expansion) return 1; - ret = 1; sym = lookup_symbol(name, NS_MACRO | NS_UNDEF); if (sym) { int clean; @@ -1347,7 +1361,7 @@ static int do_handle_define(struct stream *stream, struct token **line, struct t ret = 0; if ((clean && attr == SYM_ATTR_NORMAL) || sym->used_in == file_scope) { - warning(left->pos, "preprocessor token %.*s redefined", + warning(pos, "preprocessor token %.*s redefined", name->len, name->name); info(sym->pos, "this was the original definition"); } @@ -1356,7 +1370,7 @@ static int do_handle_define(struct stream *stream, struct token **line, struct t } if (!sym || sym->scope != file_scope) { - sym = alloc_symbol(left->pos, SYM_NODE); + sym = alloc_symbol(pos, SYM_NODE); bind_symbol(sym, name, NS_MACRO); add_ident(¯os, name); ret = 0; @@ -1365,7 +1379,8 @@ static int do_handle_define(struct stream *stream, struct token **line, struct t if (!ret) { sym->expansion = expansion; sym->arglist = arglist; - __free_token(token); /* Free the "define" token, but not the rest of the line */ + if (token) /* Free the "define" token, but not the rest of the line */ + __free_token(token); } sym->namespace = NS_MACRO; @@ -1375,6 +1390,74 @@ out: return ret; } +/// +// predefine a macro with a printf-formatted value +// @name: the name of the macro +// @weak: 0/1 for a normal or a weak define +// @fmt: the printf format followed by it's arguments. +// +// The type of the value is automatically infered: +// TOKEN_NUMBER if it starts by a digit, TOKEN_IDENT otherwise. +// If @fmt is null or empty, the macro is defined with an empty definition. +void predefine(const char *name, int weak, const char *fmt, ...) +{ + struct ident *ident = built_in_ident(name); + struct token *value = &eof_token_entry; + int attr = weak ? SYM_ATTR_WEAK : SYM_ATTR_NORMAL; + + if (fmt && fmt[0]) { + static char buf[256]; + va_list ap; + + va_start(ap, fmt); + vsnprintf(buf, sizeof(buf), fmt, ap); + va_end(ap); + + value = __alloc_token(0); + if (isdigit(buf[0])) { + token_type(value) = TOKEN_NUMBER; + value->number = xstrdup(buf); + } else { + token_type(value) = TOKEN_IDENT; + value->ident = built_in_ident(buf); + } + value->pos.whitespace = 1; + value->next = &eof_token_entry; + } + + do_define(value->pos, NULL, ident, NULL, value, attr); +} + +static int do_handle_define(struct stream *stream, struct token **line, struct token *token, int attr) +{ + struct token *arglist, *expansion; + struct token *left = token->next; + struct ident *name; + + if (token_type(left) != TOKEN_IDENT) { + sparse_error(token->pos, "expected identifier to 'define'"); + return 1; + } + + name = left->ident; + + arglist = NULL; + expansion = left->next; + if (!expansion->pos.whitespace) { + if (match_op(expansion, '(')) { + arglist = expansion; + expansion = parse_arguments(expansion); + if (!expansion) + return 1; + } else if (!eof_token(expansion)) { + warning(expansion->pos, + "no whitespace before object-like macro body"); + } + } + + return do_define(left->pos, token, name, arglist, expansion, attr); +} + static int handle_define(struct stream *stream, struct token **line, struct token *token) { return do_handle_define(stream, line, token, SYM_ATTR_NORMAL); @@ -1505,6 +1588,10 @@ static int expression_value(struct token **where) state = 1; beginning = list; break; + } else if (p->ident == &__has_builtin_ident) { + state = 4; + beginning = list; + break; } if (!expand_one_symbol(list)) continue; @@ -1535,6 +1622,33 @@ static int expression_value(struct token **where) sparse_error(p->pos, "missing ')' after \"defined\""); *list = p->next; continue; + + // __has_builtin(xyz) + case 4: + if (match_op(p, '(')) { + state = 5; + } else { + sparse_error(p->pos, "missing '(' after \"__has_builtin\""); + state = 0; + } + *beginning = p; + break; + case 5: + if (token_type(p) != TOKEN_IDENT) { + sparse_error(p->pos, "identifier expected"); + state = 0; + break; + } + if (!match_op(p->next, ')')) + sparse_error(p->pos, "missing ')' after \"__has_builtin\""); + state = 6; + replace_with_has_builtin(p); + *beginning = p; + break; + case 6: + state = 0; + *list = p->next; + continue; } list = &p->next; } @@ -1891,6 +2005,18 @@ static void init_preprocessor(void) { "if", handle_if }, { "elif", handle_elif }, }; + static struct { + const char *name; + void (*expander)(struct token *); + } dynamic[] = { + { "__LINE__", expand_line }, + { "__FILE__", expand_file }, + { "__BASE_FILE__", expand_basefile }, + { "__DATE__", expand_date }, + { "__TIME__", expand_time }, + { "__COUNTER__", expand_counter }, + { "__INCLUDE_LEVEL__", expand_include_level }, + }; for (i = 0; i < ARRAY_SIZE(normal); i++) { struct symbol *sym; @@ -1904,6 +2030,11 @@ static void init_preprocessor(void) sym->handler = special[i].handler; sym->normal = 0; } + for (i = 0; i < ARRAY_SIZE(dynamic); i++) { + struct symbol *sym; + sym = create_symbol(stream, dynamic[i].name, SYM_NODE, NS_MACRO); + sym->expander = dynamic[i].expander; + } counter_macro = 0; } @@ -1985,9 +2116,11 @@ static void do_preprocess(struct token **list) if (!stream->dirty) stream->constant = CONSTANT_FILE_YES; *list = next->next; + include_level--; continue; case TOKEN_STREAMBEGIN: *list = next->next; + include_level++; continue; default: |
