struct pp_definition_t {
symbol_t *symbol;
- source_position_t source_position;
+ position_t pos;
pp_definition_t *parent_expansion;
size_t expand_pos;
whitespace_info_t expand_info;
typedef struct pp_conditional_t pp_conditional_t;
struct pp_conditional_t {
- source_position_t source_position;
+ position_t pos;
bool condition;
bool in_else;
/** conditional in skip mode (then+else gets skipped) */
utf32 buf[1024+MAX_PUTBACK];
const utf32 *bufend;
const utf32 *bufpos;
- source_position_t position;
+ position_t pos;
pp_input_t *parent;
unsigned output_line;
searchpath_entry_t *path;
struct searchpath_entry_t {
const char *path;
searchpath_entry_t *next;
+ bool is_system_path;
};
static pp_input_t input;
static struct obstack pp_obstack;
static struct obstack config_obstack;
static const char *printed_input_name = NULL;
-static source_position_t expansion_pos;
+static position_t expansion_pos;
static pp_definition_t *current_expansion = NULL;
static pp_definition_t *current_call = NULL;
static pp_definition_t *current_argument = NULL;
static strset_t stringset;
static token_kind_t last_token;
-static searchpath_entry_t *searchpath;
+struct searchpath_t {
+ searchpath_entry_t *first;
+ searchpath_entry_t **anchor;
+ bool is_system_path;
+};
+
+searchpath_t bracket_searchpath = { NULL, &bracket_searchpath.first, false };
+searchpath_t quote_searchpath = { NULL, "e_searchpath.first, false };
+searchpath_t system_searchpath = { NULL, &system_searchpath.first, true };
+searchpath_t after_searchpath = { NULL, &after_searchpath.first, true };
static whitespace_info_t next_info; /* valid if had_whitespace is true */
static whitespace_info_t info;
static inline void next_char(void);
static void next_input_token(void);
-static void print_line_directive(const source_position_t *pos, const char *add);
+static void print_line_directive(const position_t *pos, const char *add);
static symbol_t *symbol_colongreater;
static symbol_t *symbol_lesscolon;
static symbol_t *symbol_percentcolonpercentcolon;
static symbol_t *symbol_percentgreater;
+static symbol_t *symbol_L;
+static symbol_t *symbol_U;
+static symbol_t *symbol_u;
+static symbol_t *symbol_u8;
+
static void init_symbols(void)
{
symbol_colongreater = symbol_table_insert(":>");
symbol_percentcolon = symbol_table_insert("%:");
symbol_percentcolonpercentcolon = symbol_table_insert("%:%:");
symbol_percentgreater = symbol_table_insert("%>");
+
+ symbol_L = symbol_table_insert("L");
+ symbol_U = symbol_table_insert("U");
+ symbol_u = symbol_table_insert("u");
+ symbol_u8 = symbol_table_insert("u8");
}
-void switch_pp_input(FILE *const file, char const *const filename, searchpath_entry_t *const path)
+void switch_pp_input(FILE *const file, char const *const filename, searchpath_entry_t *const path, bool const is_system_header)
{
- input.file = file;
- input.input = input_from_stream(file, NULL);
- input.bufend = NULL;
- input.bufpos = NULL;
- input.output_line = 0;
- input.position.input_name = filename;
- input.position.lineno = 1;
- input.path = path;
+ input.file = file;
+ input.input = input_from_stream(file, NULL);
+ input.bufend = NULL;
+ input.bufpos = NULL;
+ input.output_line = 0;
+ input.pos.input_name = filename;
+ input.pos.lineno = 1;
+ input.pos.is_system_header = is_system_header;
+ input.path = path;
/* indicate that we're at a new input */
- print_line_directive(&input.position, input_stack != NULL ? "1" : NULL);
+ print_line_directive(&input.pos, input_stack != NULL ? "1" : NULL);
/* place a virtual '\n' so we realize we're at line begin */
- input.position.lineno = 0;
- input.c = '\n';
+ input.pos.lineno = 0;
+ input.c = '\n';
}
FILE *close_pp_input(void)
*/
static void parse_error(const char *msg)
{
- errorf(&pp_token.base.source_position, "%s", msg);
+ errorf(&pp_token.base.pos, "%s", msg);
}
static inline void next_real_char(void)
input.bufend = input.bufpos + n;
}
input.c = *input.bufpos++;
- ++input.position.colno;
+ ++input.pos.colno;
}
/**
{
assert(input.bufpos > input.buf);
*(--input.bufpos - input.buf + input.buf) = (char) pc;
- --input.position.colno;
+ --input.pos.colno;
}
#define NEWLINE \
case '\n': \
next_char(); \
} \
- ++input.position.lineno; \
- input.position.colno = 1; \
+ ++input.pos.lineno; \
+ input.pos.colno = 1; \
goto newline; \
newline // Let it look like an ordinary case label.
obstack_1grow(&symbol_obstack, input.c);
next_char();
} else {
- errorf(&input.position,
+ errorf(&input.pos,
"short universal character name, expected %u more digits",
k);
break;
}
}
if (!is_universal_char_valid(v)) {
- errorf(&input.position,
+ errorf(&input.pos,
"\\%c%0*X is not a valid universal character name",
n_digits == 4 ? 'u' : 'U', (int)n_digits, v);
}
return v;
}
-static bool is_universal_char_valid_identifier(utf32 const v)
+static bool is_universal_char_valid_identifier_c99(utf32 const v)
+{
+ static const utf32 single_chars[] = {
+ 0x00AA, 0x00BA, 0x0386, 0x038C, 0x03DA, 0x03DC, 0x03DE, 0x03E0,
+ 0x1F59, 0x1F5B, 0x1F5D, 0x05BF, 0x09B2, 0x0A02, 0x0A5E, 0x0A74,
+ 0x0A8D, 0x0AD0, 0x0AE0, 0x0B9C, 0x0CDE, 0x0E84, 0x0E8A, 0x0E8D,
+ 0x0EA5, 0x0EA7, 0x0EC6, 0x0F00, 0x0F35, 0x0F37, 0x0F39, 0x0F97,
+ 0x0FB9, 0x00B5, 0x00B7, 0x02BB, 0x037A, 0x0559, 0x093D, 0x0B3D,
+ 0x1FBE, 0x2102, 0x2107, 0x2115, 0x2124, 0x2126, 0x2128
+ };
+
+ static const utf32 ranges[][2] = {
+ {0x00C0, 0x00D6}, {0x00D8, 0x00F6}, {0x00F8, 0x01F5}, {0x01FA, 0x0217},
+ {0x0250, 0x02A8}, {0x1E00, 0x1E9B}, {0x1EA0, 0x1EF9}, {0x0388, 0x038A},
+ {0x038E, 0x03A1}, {0x03A3, 0x03CE}, {0x03D0, 0x03D6}, {0x03E2, 0x03F3},
+ {0x1F00, 0x1F15}, {0x1F18, 0x1F1D}, {0x1F20, 0x1F45}, {0x1F48, 0x1F4D},
+ {0x1F50, 0x1F57}, {0x1F5F, 0x1F7D}, {0x1F80, 0x1FB4}, {0x1FB6, 0x1FBC},
+ {0x1FC2, 0x1FC4}, {0x1FC6, 0x1FCC}, {0x1FD0, 0x1FD3}, {0x1FD6, 0x1FDB},
+ {0x1FE0, 0x1FEC}, {0x1FF2, 0x1FF4}, {0x1FF6, 0x1FFC}, {0x0401, 0x040C},
+ {0x040E, 0x044F}, {0x0451, 0x045C}, {0x045E, 0x0481}, {0x0490, 0x04C4},
+ {0x04C7, 0x04C8}, {0x04CB, 0x04CC}, {0x04D0, 0x04EB}, {0x04EE, 0x04F5},
+ {0x04F8, 0x04F9}, {0x0531, 0x0556}, {0x0561, 0x0587}, {0x05B0, 0x05B9},
+ {0x05BB, 0x05BD}, {0x05C1, 0x05C2}, {0x05D0, 0x05EA}, {0x05F0, 0x05F2},
+ {0x0621, 0x063A}, {0x0640, 0x0652}, {0x0670, 0x06B7}, {0x06BA, 0x06BE},
+ {0x06C0, 0x06CE}, {0x06D0, 0x06DC}, {0x06E5, 0x06E8}, {0x06EA, 0x06ED},
+ {0x0901, 0x0903}, {0x0905, 0x0939}, {0x093E, 0x094D}, {0x0950, 0x0952},
+ {0x0958, 0x0963}, {0x0981, 0x0983}, {0x0985, 0x098C}, {0x098F, 0x0990},
+ {0x0993, 0x09A8}, {0x09AA, 0x09B0}, {0x09B6, 0x09B9}, {0x09BE, 0x09C4},
+ {0x09C7, 0x09C8}, {0x09CB, 0x09CD}, {0x09DC, 0x09DD}, {0x09DF, 0x09E3},
+ {0x09F0, 0x09F1}, {0x0A05, 0x0A0A}, {0x0A0F, 0x0A10}, {0x0A13, 0x0A28},
+ {0x0A2A, 0x0A30}, {0x0A32, 0x0A33}, {0x0A35, 0x0A36}, {0x0A38, 0x0A39},
+ {0x0A3E, 0x0A42}, {0x0A47, 0x0A48}, {0x0A4B, 0x0A4D}, {0x0A59, 0x0A5C},
+ {0x0A81, 0x0A83}, {0x0A85, 0x0A8B}, {0x0A8F, 0x0A91}, {0x0A93, 0x0AA8},
+ {0x0AAA, 0x0AB0}, {0x0AB2, 0x0AB3}, {0x0AB5, 0x0AB9}, {0x0ABD, 0x0AC5},
+ {0x0AC7, 0x0AC9}, {0x0ACB, 0x0ACD}, {0x0B01, 0x0B03}, {0x0B05, 0x0B0C},
+ {0x0B0F, 0x0B10}, {0x0B13, 0x0B28}, {0x0B2A, 0x0B30}, {0x0B32, 0x0B33},
+ {0x0B36, 0x0B39}, {0x0B3E, 0x0B43}, {0x0B47, 0x0B48}, {0x0B4B, 0x0B4D},
+ {0x0B5C, 0x0B5D}, {0x0B5F, 0x0B61}, {0x0B82, 0x0B83}, {0x0B85, 0x0B8A},
+ {0x0B8E, 0x0B90}, {0x0B92, 0x0B95}, {0x0B99, 0x0B9A}, {0x0B9E, 0x0B9F},
+ {0x0BA3, 0x0BA4}, {0x0BA8, 0x0BAA}, {0x0BAE, 0x0BB5}, {0x0BB7, 0x0BB9},
+ {0x0BBE, 0x0BC2}, {0x0BC6, 0x0BC8}, {0x0BCA, 0x0BCD}, {0x0C01, 0x0C03},
+ {0x0C05, 0x0C0C}, {0x0C0E, 0x0C10}, {0x0C12, 0x0C28}, {0x0C2A, 0x0C33},
+ {0x0C35, 0x0C39}, {0x0C3E, 0x0C44}, {0x0C46, 0x0C48}, {0x0C4A, 0x0C4D},
+ {0x0C60, 0x0C61}, {0x0C82, 0x0C83}, {0x0C85, 0x0C8C}, {0x0C8E, 0x0C90},
+ {0x0C92, 0x0CA8}, {0x0CAA, 0x0CB3}, {0x0CB5, 0x0CB9}, {0x0CBE, 0x0CC4},
+ {0x0CC6, 0x0CC8}, {0x0CCA, 0x0CCD}, {0x0CE0, 0x0CE1}, {0x0D02, 0x0D03},
+ {0x0D05, 0x0D0C}, {0x0D0E, 0x0D10}, {0x0D12, 0x0D28}, {0x0D2A, 0x0D39},
+ {0x0D3E, 0x0D43}, {0x0D46, 0x0D48}, {0x0D4A, 0x0D4D}, {0x0D60, 0x0D61},
+ {0x0E01, 0x0E3A}, {0x0E40, 0x0E5B}, {0x0E81, 0x0E82}, {0x0E87, 0x0E88},
+ {0x0E94, 0x0E97}, {0x0E99, 0x0E9F}, {0x0EA1, 0x0EA3}, {0x0EAA, 0x0EAB},
+ {0x0EAD, 0x0EAE}, {0x0EB0, 0x0EB9}, {0x0EBB, 0x0EBD}, {0x0EC0, 0x0EC4},
+ {0x0EC8, 0x0ECD}, {0x0EDC, 0x0EDD}, {0x0F18, 0x0F19}, {0x0F3E, 0x0F47},
+ {0x0F49, 0x0F69}, {0x0F71, 0x0F84}, {0x0F86, 0x0F8B}, {0x0F90, 0x0F95},
+ {0x0F99, 0x0FAD}, {0x0FB1, 0x0FB7}, {0x10A0, 0x10C5}, {0x10D0, 0x10F6},
+ {0x3041, 0x3093}, {0x309B, 0x309C}, {0x30A1, 0x30F6}, {0x30FB, 0x30FC},
+ {0x3105, 0x312C}, {0x4E00, 0x9FA5}, {0xAC00, 0xD7A3}, {0x0660, 0x0669},
+ {0x06F0, 0x06F9}, {0x0966, 0x096F}, {0x09E6, 0x09EF}, {0x0A66, 0x0A6F},
+ {0x0AE6, 0x0AEF}, {0x0B66, 0x0B6F}, {0x0BE7, 0x0BEF}, {0x0C66, 0x0C6F},
+ {0x0CE6, 0x0CEF}, {0x0D66, 0x0D6F}, {0x0E50, 0x0E59}, {0x0ED0, 0x0ED9},
+ {0x0F20, 0x0F33}, {0x02B0, 0x02B8}, {0x02BD, 0x02C1}, {0x02D0, 0x02D1},
+ {0x02E0, 0x02E4}, {0x203F, 0x2040}, {0x210A, 0x2113}, {0x2118, 0x211D},
+ {0x212A, 0x2131}, {0x2133, 0x2138}, {0x2160, 0x2182}, {0x3005, 0x3007},
+ {0x3021, 0x3029},
+ };
+ for (size_t i = 0; i < sizeof(ranges)/sizeof(ranges[0]); ++i) {
+ if (ranges[i][0] <= v && v <= ranges[i][1])
+ return true;
+ }
+ for (size_t i = 0; i < sizeof(single_chars)/sizeof(single_chars[0]); ++i) {
+ if (v == single_chars[i])
+ return true;
+ }
+ return false;
+}
+
+static bool is_universal_char_valid_identifier_c11(utf32 const v)
{
/* C11 Annex D.1 */
if ( v == 0x000A8) return true;
return false;
}
-static bool is_universal_char_valid_identifier_start(utf32 const v)
+static bool is_universal_char_valid_identifier(utf32 const v)
+{
+ if (c_mode & _C11)
+ return is_universal_char_valid_identifier_c11(v);
+ return is_universal_char_valid_identifier_c99(v);
+}
+
+static bool is_universal_char_invalid_identifier_start(utf32 const v)
{
+ if (! (c_mode & _C11))
+ return false;
+
/* C11 Annex D.2 */
- if (0x0300 <= v && v <= 0x036F) return false;
- if (0x1DC0 <= v && v <= 0x1DFF) return false;
- if (0x20D0 <= v && v <= 0x20FF) return false;
- if (0xFE20 <= v && v <= 0xFE2F) return false;
- return true;
+ if (0x0300 <= v && v <= 0x036F) return true;
+ if (0x1DC0 <= v && v <= 0x1DFF) return true;
+ if (0x20D0 <= v && v <= 0x20FF) return true;
+ if (0xFE20 <= v && v <= 0xFE2F) return true;
+ return false;
}
/**
return sym_make_string(STRING_ENCODING_CHAR);
}
+static utf32 get_string_encoding_limit(string_encoding_t const enc)
+{
+ switch (enc) {
+ case STRING_ENCODING_CHAR: return 0xFF;
+ case STRING_ENCODING_CHAR16: return 0xFFFF;
+ case STRING_ENCODING_CHAR32: return 0xFFFFFFFF;
+ case STRING_ENCODING_UTF8: return 0xFFFFFFFF;
+ case STRING_ENCODING_WIDE: return 0xFFFFFFFF; // FIXME depends on settings
+ }
+ panic("invalid string encoding");
+}
+
static void parse_string(utf32 const delimiter, token_kind_t const kind,
string_encoding_t const enc,
char const *const context)
{
- const unsigned start_linenr = input.position.lineno;
-
eat(delimiter);
+ utf32 const limit = get_string_encoding_limit(enc);
while (true) {
switch (input.c) {
case '\\': {
if (resolve_escape_sequences) {
utf32 const tc = parse_escape_sequence();
+ if (tc > limit) {
+ warningf(WARN_OTHER, &pp_token.base.pos,
+ "escape sequence out of range");
+ }
if (enc == STRING_ENCODING_CHAR) {
- if (tc >= 0x100) {
- warningf(WARN_OTHER, &pp_token.base.source_position, "escape sequence out of range");
- }
obstack_1grow(&symbol_obstack, tc);
} else {
obstack_grow_utf8(&symbol_obstack, tc);
}
case NEWLINE:
- errorf(&pp_token.base.source_position, "newline while parsing %s", context);
+ errorf(&pp_token.base.pos, "newline while parsing %s", context);
break;
- case EOF: {
- source_position_t source_position;
- source_position.input_name = pp_token.base.source_position.input_name;
- source_position.lineno = start_linenr;
- errorf(&source_position, "EOF while parsing %s", context);
+ case EOF:
+ errorf(&pp_token.base.pos, "EOF while parsing %s", context);
goto end_of_string;
- }
default:
if (input.c == delimiter) {
if (current_expansion->expand_pos > 0)
info.had_whitespace = saved->had_whitespace;
current_expansion->expand_pos = pos;
- pp_token.base.source_position = expansion_pos;
+ pp_token.base.pos = expansion_pos;
return true;
}
{
info.had_whitespace = true;
- unsigned start_linenr = input.position.lineno;
+ position_t const start_pos = input.pos;
while (true) {
switch (input.c) {
case '/':
case '*':
next_char();
if (input.c == '/') {
- if (input.position.lineno != input.output_line)
- info.whitespace_at_line_begin = input.position.colno;
+ if (input.pos.lineno != input.output_line)
+ info.whitespace_at_line_begin = input.pos.colno;
next_char();
return;
}
case NEWLINE:
break;
- case EOF: {
- source_position_t source_position;
- source_position.input_name = pp_token.base.source_position.input_name;
- source_position.lineno = start_linenr;
- errorf(&source_position, "at end of file while looking for comment end");
+ case EOF:
+ errorf(&start_pos, "at end of file while looking for comment end");
return;
- }
default:
next_char();
next_input_token();
}
+static string_encoding_t identify_encoding_prefix(symbol_t *const sym)
+{
+ if (sym == symbol_L) return STRING_ENCODING_WIDE;
+ if (c_mode & _C11) {
+ if (sym == symbol_U) return STRING_ENCODING_CHAR32;
+ if (sym == symbol_u) return STRING_ENCODING_CHAR16;
+ if (sym == symbol_u8) return STRING_ENCODING_UTF8;
+ }
+ return STRING_ENCODING_CHAR;
+}
+
static void parse_symbol(void)
{
assert(obstack_object_size(&symbol_obstack) == 0);
utf32 const v = parse_universal_char(n);
if (!is_universal_char_valid_identifier(v)) {
if (is_universal_char_valid(v)) {
- errorf(&input.position,
+ errorf(&input.pos,
"universal character \\%c%0*X is not valid in an identifier",
n == 4 ? 'u' : 'U', (int)n, v);
}
- } else if (obstack_object_size(&symbol_obstack) == 0 && !is_universal_char_valid_identifier_start(v)) {
- errorf(&input.position,
+ } else if (obstack_object_size(&symbol_obstack) == 0 && is_universal_char_invalid_identifier_start(v)) {
+ errorf(&input.pos,
"universal character \\%c%0*X is not valid as start of an identifier",
n == 4 ? 'u' : 'U', (int)n, v);
} else if (resolve_escape_sequences) {
obstack_1grow(&symbol_obstack, '\0');
char *string = obstack_finish(&symbol_obstack);
- /* might be a wide string or character constant ( L"string"/L'c' ) */
- if (input.c == '"' && string[0] == 'L' && string[1] == '\0') {
- obstack_free(&symbol_obstack, string);
- parse_string_literal(STRING_ENCODING_WIDE);
- return;
- } else if (input.c == '\'' && string[0] == 'L' && string[1] == '\0') {
- obstack_free(&symbol_obstack, string);
- parse_character_constant(STRING_ENCODING_WIDE);
- return;
- }
-
symbol_t *symbol = symbol_table_insert(string);
+ /* Might be a prefixed string or character constant: L/U/u/u8"string". */
+ if (input.c == '"') {
+ string_encoding_t const enc = identify_encoding_prefix(symbol);
+ if (enc != STRING_ENCODING_CHAR) {
+ parse_string_literal(enc);
+ return;
+ }
+ } else if (input.c == '\'') {
+ string_encoding_t const enc = identify_encoding_prefix(symbol);
+ if (enc != STRING_ENCODING_CHAR) {
+ if (enc == STRING_ENCODING_UTF8) {
+ errorf(&pp_token.base.pos,
+ "'u8' is not a valid encoding for a chracter constant");
+ }
+ parse_character_constant(enc);
+ return;
+ }
+ }
+
pp_token.kind = symbol->ID;
pp_token.base.symbol = symbol;
info.had_whitespace = false;
}
restart:
- pp_token.base.source_position = input.position;
- pp_token.base.symbol = NULL;
+ pp_token.base.pos = input.pos;
+ pp_token.base.symbol = NULL;
switch (input.c) {
case ' ':
if (input_stack != NULL) {
fclose(close_pp_input());
pop_restore_input();
- fputc('\n', out);
+ if (out)
+ fputc('\n', out);
if (input.c == (utf32)EOF)
- --input.position.lineno;
- print_line_directive(&input.position, "2");
+ --input.pos.lineno;
+ print_line_directive(&input.pos, "2");
goto restart;
} else {
info.at_line_begin = true;
default:
dollar_sign:
if (error_on_unknown_chars) {
- errorf(&pp_token.base.source_position,
- "unknown character '%lc' found\n", input.c);
+ errorf(&pp_token.base.pos, "unknown character '%lc' found", input.c);
next_char();
goto restart;
} else {
fputc('"', out);
}
-static void print_line_directive(const source_position_t *pos, const char *add)
+static void print_line_directive(const position_t *pos, const char *add)
{
if (!out)
return;
static bool emit_newlines(void)
{
- unsigned delta = pp_token.base.source_position.lineno - input.output_line;
+ if (!out)
+ return true;
+
+ unsigned delta = pp_token.base.pos.lineno - input.output_line;
if (delta == 0)
return false;
if (delta >= 9) {
fputc('\n', out);
- print_line_directive(&pp_token.base.source_position, NULL);
+ print_line_directive(&pp_token.base.pos, NULL);
fputc('\n', out);
} else {
for (unsigned i = 0; i < delta; ++i) {
fputc('\n', out);
}
}
- input.output_line = pp_token.base.source_position.lineno;
+ input.output_line = pp_token.base.pos.lineno;
unsigned whitespace = info.whitespace_at_line_begin;
/* make sure there is at least 1 whitespace before a (macro-expanded)
for (size_t i = 0; i < len; ++i, ++t1, ++t2) {
if (!pp_tokens_equal(&t1->token, &t2->token))
return false;
+ if (t1->had_whitespace != t2->had_whitespace)
+ return false;
}
return true;
}
static void missing_macro_param_error(void)
{
- errorf(&pp_token.base.source_position,
- "'#' is not followed by a macro parameter");
+ errorf(&pp_token.base.pos, "'#' is not followed by a macro parameter");
}
static bool is_defineable_token(char const *const context)
{
if (info.at_line_begin) {
- errorf(&pp_token.base.source_position, "unexpected end of line after %s", context);
+ errorf(&pp_token.base.pos, "unexpected end of line after %s", context);
}
symbol_t *const symbol = pp_token.base.symbol;
default:
no_ident:
- errorf(&pp_token.base.source_position, "expected identifier after %s, got %K", context, &pp_token);
+ errorf(&pp_token.base.pos, "expected identifier after %s, got %K",
+ context, &pp_token);
return false;
}
}
switch (symbol->pp_ID) {
/* §6.10.8:4 */
case TP_defined:
- errorf(&pp_token.base.source_position, "%K cannot be used as macro name in %s", &pp_token, context);
+ errorf(&pp_token.base.pos, "%K cannot be used as macro name in %s",
+ &pp_token, context);
return false;
default:
pp_definition_t *new_definition
= obstack_alloc(&pp_obstack, sizeof(new_definition[0]));
memset(new_definition, 0, sizeof(new_definition[0]));
- new_definition->symbol = symbol;
- new_definition->source_position = input.position;
+ new_definition->symbol = symbol;
+ new_definition->pos = input.pos;
/* this is probably the only place where spaces are significant in the
* lexer (except for the fact that they separate tokens). #define b(x)
new_definition->is_variadic = true;
eat_token(T_DOTDOTDOT);
if (pp_token.kind != ')') {
- errorf(&input.position,
+ errorf(&input.pos,
"'...' not at end of macro argument list");
goto error_out;
}
case T_IDENTIFIER: {
pp_definition_t parameter;
memset(¶meter, 0, sizeof(parameter));
- parameter.source_position = pp_token.base.source_position;
- parameter.symbol = pp_token.base.symbol;
- parameter.is_parameter = true;
+ parameter.pos = pp_token.base.pos;
+ parameter.symbol = pp_token.base.symbol;
+ parameter.is_parameter = true;
obstack_grow(&pp_obstack, ¶meter, sizeof(parameter));
eat_token(T_IDENTIFIER);
}
if (pp_token.kind != ')') {
- errorf(&pp_token.base.source_position,
+ errorf(&pp_token.base.pos,
"expected ',' or ')' after identifier, got %K",
&pp_token);
goto error_out;
goto finish_argument_list;
default:
- errorf(&pp_token.base.source_position,
+ errorf(&pp_token.base.pos,
"expected identifier, '...' or ')' in #define argument list, got %K",
&pp_token);
goto error_out;
pp_definition_t *previous = symbol->pp_definition;
if (previous != NULL
&& previous->function_definition == new_definition) {
- errorf(¶m->source_position,
- "duplicate macro parameter '%Y'", symbol);
+ errorf(¶m->pos, "duplicate macro parameter '%Y'", symbol);
param->symbol = sym_anonymous;
continue;
}
pp_definition_t *old_definition = symbol->pp_definition;
if (old_definition != NULL) {
if (!pp_definitions_equal(old_definition, new_definition)) {
- warningf(WARN_OTHER, &input.position, "multiple definition of macro '%Y' (first defined %P)", symbol, &old_definition->source_position);
+ warningf(WARN_OTHER, &input.pos,
+ "multiple definition of macro '%Y' (first defined %P)",
+ symbol, &old_definition->pos);
} else {
/* reuse the old definition */
obstack_free(&pp_obstack, new_definition);
next_input_token();
if (!info.at_line_begin) {
- warningf(WARN_OTHER, &input.position, "extra tokens at end of #undef directive");
+ warningf(WARN_OTHER, &input.pos, "extra tokens at end of #undef directive");
}
eat_pp_directive();
}
return NULL;
}
- /* check wether we have a "... or <... headername */
- source_position_t position = input.position;
+ /* check whether we have a "... or <... headername */
+ position_t pos = input.pos;
switch (input.c) {
{
utf32 delimiter;
char *dummy = obstack_finish(&symbol_obstack);
obstack_free(&symbol_obstack, dummy);
}
- errorf(&pp_token.base.source_position,
+ errorf(&pp_token.base.pos,
"header name without closing '%c'", (char)delimiter);
return NULL;
obstack_free(&symbol_obstack, dummy);
}
- errorf(&pp_token.base.source_position,
+ errorf(&pp_token.base.pos,
"expected \"FILENAME\" or <FILENAME> after #include");
return NULL;
}
obstack_1grow(&symbol_obstack, '\0');
char *const headername = obstack_finish(&symbol_obstack);
const char *identified = identify_string(headername);
- pp_token.base.source_position = position;
+ pp_token.base.pos = pos;
return identified;
}
-static bool do_include(bool const system_include, bool const include_next, char const *const headername)
+static bool do_include(bool const bracket_include, bool const include_next, char const *const headername)
{
size_t const headername_len = strlen(headername);
searchpath_entry_t *entry;
if (include_next) {
- entry = input.path ? input.path->next : searchpath;
+ entry = input.path ? input.path->next
+ : bracket_include ? bracket_searchpath.first
+ : quote_searchpath.first;
} else {
- if (!system_include) {
+ if (!bracket_include) {
/* put dirname of current input on obstack */
- const char *filename = input.position.input_name;
+ const char *filename = input.pos.input_name;
const char *last_slash = strrchr(filename, '/');
const char *full_name;
if (last_slash != NULL) {
FILE *file = fopen(full_name, "r");
if (file != NULL) {
- switch_pp_input(file, full_name, NULL);
+ switch_pp_input(file, full_name, NULL, false);
return true;
}
+ entry = quote_searchpath.first;
+ } else {
+ entry = bracket_searchpath.first;
}
-
- entry = searchpath;
}
assert(obstack_object_size(&symbol_obstack) == 0);
FILE *file = fopen(complete_path, "r");
if (file != NULL) {
const char *filename = identify_string(complete_path);
- switch_pp_input(file, filename, entry);
+ switch_pp_input(file, filename, entry, entry->is_system_path);
return true;
} else {
obstack_free(&symbol_obstack, complete_path);
bool had_nonwhitespace = skip_till_newline(false);
if (had_nonwhitespace) {
- warningf(WARN_OTHER, &input.position,
+ warningf(WARN_OTHER, &input.pos,
"extra tokens at end of #include directive");
}
if (n_inputs > INCLUDE_LIMIT) {
- errorf(&pp_token.base.source_position, "#include nested too deeply");
+ errorf(&pp_token.base.pos, "#include nested too deeply");
/* eat \n or EOF */
next_input_token();
return;
if (res) {
next_input_token();
} else {
- errorf(&pp_token.base.source_position, "failed including '%s': %s", headername, strerror(errno));
+ errorf(&pp_token.base.pos, "failed including '%s': %s", headername, strerror(errno));
pop_restore_input();
}
}
pp_conditional_t *conditional = conditional_stack;
if (conditional->in_else) {
- errorf(&conditional->source_position, "unterminated #else");
+ errorf(&conditional->pos, "unterminated #else");
} else {
- errorf(&conditional->source_position, "unterminated condition");
+ errorf(&conditional->pos, "unterminated condition");
}
pop_conditional();
}
if (skip_mode) {
eat_pp_directive();
pp_conditional_t *conditional = push_conditional();
- conditional->source_position = pp_token.base.source_position;
- conditional->skip = true;
+ conditional->pos = pp_token.base.pos;
+ conditional->skip = true;
return;
}
if (pp_token.kind != T_IDENTIFIER || info.at_line_begin) {
- errorf(&pp_token.base.source_position,
- "expected identifier after #%s, got %K",
+ errorf(&pp_token.base.pos, "expected identifier after #%s, got %K",
is_ifdef ? "ifdef" : "ifndef", &pp_token);
eat_pp_directive();
/* just take the true case in the hope to avoid further errors */
condition = true;
} else {
- /* evaluate wether we are in true or false case */
+ /* evaluate whether we are in true or false case */
condition = (bool)pp_token.base.symbol->pp_definition == is_ifdef;
eat_token(T_IDENTIFIER);
if (!info.at_line_begin) {
- errorf(&pp_token.base.source_position,
- "extra tokens at end of #%s",
+ errorf(&pp_token.base.pos, "extra tokens at end of #%s",
is_ifdef ? "ifdef" : "ifndef");
eat_pp_directive();
}
}
pp_conditional_t *conditional = push_conditional();
- conditional->source_position = pp_token.base.source_position;
- conditional->condition = condition;
+ conditional->pos = pp_token.base.pos;
+ conditional->condition = condition;
if (!condition) {
skip_mode = true;
if (!info.at_line_begin) {
if (!skip_mode) {
- warningf(WARN_OTHER, &pp_token.base.source_position, "extra tokens at end of #else");
+ warningf(WARN_OTHER, &pp_token.base.pos, "extra tokens at end of #else");
}
eat_pp_directive();
}
pp_conditional_t *conditional = conditional_stack;
if (conditional == NULL) {
- errorf(&pp_token.base.source_position, "#else without prior #if");
+ errorf(&pp_token.base.pos, "#else without prior #if");
return;
}
if (conditional->in_else) {
- errorf(&pp_token.base.source_position,
+ errorf(&pp_token.base.pos,
"#else after #else (condition started %P)",
- &conditional->source_position);
+ &conditional->pos);
skip_mode = true;
return;
}
if (!conditional->skip) {
skip_mode = conditional->condition;
}
- conditional->source_position = pp_token.base.source_position;
+ conditional->pos = pp_token.base.pos;
}
static void parse_endif_directive(void)
if (!info.at_line_begin) {
if (!skip_mode) {
- warningf(WARN_OTHER, &pp_token.base.source_position, "extra tokens at end of #endif");
+ warningf(WARN_OTHER, &pp_token.base.pos, "extra tokens at end of #endif");
}
eat_pp_directive();
}
pp_conditional_t *conditional = conditional_stack;
if (conditional == NULL) {
- errorf(&pp_token.base.source_position, "#endif without prior #if");
+ errorf(&pp_token.base.pos, "#endif without prior #if");
return;
}
}
if (pp_token.kind != T_IDENTIFIER) {
- warningf(WARN_UNKNOWN_PRAGMAS, &pp_token.base.source_position,
+ warningf(WARN_UNKNOWN_PRAGMAS, &pp_token.base.pos,
"expected identifier after #pragma");
eat_pp_directive();
return;
}
if (value == STDC_VALUE_UNKNOWN) {
kind = STDC_UNKNOWN;
- errorf(&pp_token.base.source_position, "bad STDC pragma argument");
+ errorf(&pp_token.base.pos, "bad STDC pragma argument");
}
}
}
eat_pp_directive();
if (kind == STDC_UNKNOWN) {
- warningf(WARN_UNKNOWN_PRAGMAS, &pp_token.base.source_position,
+ warningf(WARN_UNKNOWN_PRAGMAS, &pp_token.base.pos,
"encountered unknown #pragma");
}
}
long const line = strtol(pp_token.literal.string.begin, &end, 0);
if (*end == '\0') {
/* use offset -1 as this is about the next line */
- input.position.lineno = line - 1;
+ input.pos.lineno = line - 1;
/* force output of line */
- input.output_line = input.position.lineno - 20;
+ input.output_line = input.pos.lineno - 20;
} else {
if (!skip_mode) {
- errorf(&input.position, "'%S' is not a valid line number",
+ errorf(&input.pos, "'%S' is not a valid line number",
&pp_token.literal.string);
}
}
}
if (pp_token.kind == T_STRING_LITERAL
&& pp_token.literal.string.encoding == STRING_ENCODING_CHAR) {
- input.position.input_name = pp_token.literal.string.begin;
- input.position.is_system_header = false;
+ input.pos.input_name = pp_token.literal.string.begin;
+ input.pos.is_system_header = false;
next_input_token();
/* attempt to parse numeric flags as outputted by gcc preprocessor */
* currently we're only interested in "3"
*/
if (streq(pp_token.literal.string.begin, "3")) {
- input.position.is_system_header = true;
+ input.pos.is_system_header = true;
}
next_input_token();
}
bool const old_resolve_escape_sequences = resolve_escape_sequences;
resolve_escape_sequences = false;
- source_position_t const pos = pp_token.base.source_position;
+ position_t const pos = pp_token.base.pos;
do {
if (info.had_whitespace && obstack_object_size(&pp_obstack) != 0)
obstack_1grow(&pp_obstack, ' ');
} else {
skip:
if (!skip_mode) {
- errorf(&pp_token.base.source_position, "invalid preprocessing directive #%K", &pp_token);
+ errorf(&pp_token.base.pos, "invalid preprocessing directive #%K", &pp_token);
}
eat_pp_directive();
}
if (next_token == '(') {
if (current_expansion == NULL)
- expansion_pos = pp_token.base.source_position;
+ expansion_pos = pp_token.base.pos;
next_preprocessing_token();
assert(pp_token.kind == '(');
}
} else {
if (current_expansion == NULL)
- expansion_pos = pp_token.base.source_position;
+ expansion_pos = pp_token.base.pos;
start_expanding(pp_definition);
goto restart;
}
finish_current_argument();
current_call->expand_pos++;
if (current_call->expand_pos >= current_call->n_parameters) {
- errorf(&pp_token.base.source_position,
+ errorf(&pp_token.base.pos,
"too many arguments passed for macro '%Y'",
current_call->symbol);
current_argument = NULL;
}
}
-
-static void prepend_include_path(const char *path)
+void append_include_path(searchpath_t *paths, const char *path)
{
searchpath_entry_t *entry = OALLOCZ(&config_obstack, searchpath_entry_t);
- entry->path = path;
- entry->next = searchpath;
- searchpath = entry;
+ entry->path = path;
+ entry->is_system_path = paths->is_system_path;
+
+ *paths->anchor = entry;
+ paths->anchor = &entry->next;
}
-static void setup_include_path(void)
+static void append_env_paths(searchpath_t *paths, const char *envvar)
{
- /* built-in paths */
- prepend_include_path("/usr/include");
-
- /* parse environment variable */
- const char *cpath = getenv("CPATH");
- if (cpath != NULL && *cpath != '\0') {
- const char *begin = cpath;
+ const char *val = getenv(envvar);
+ if (val != NULL && *val != '\0') {
+ const char *begin = val;
const char *c;
do {
c = begin;
size_t len = c-begin;
if (len == 0) {
- /* for gcc compatibility (Matze: I would expect that
+ /* use "." for gcc compatibility (Matze: I would expect that
* nothing happens for an empty entry...) */
- prepend_include_path(".");
+ append_include_path(paths, ".");
} else {
char *const string = obstack_copy0(&config_obstack, begin, len);
- prepend_include_path(string);
+ append_include_path(paths, string);
}
begin = c+1;
/* skip : */
if (*begin == ':')
++begin;
- } while(*c != '\0');
+ } while (*c != '\0');
}
}
+static void append_searchpath(searchpath_t *path, const searchpath_t *append)
+{
+ *path->anchor = append->first;
+}
+
+static void setup_include_path(void)
+{
+ /* built-in paths */
+ append_include_path(&system_searchpath, "/usr/include");
+
+ /* parse environment variable */
+ append_env_paths(&bracket_searchpath, "CPATH");
+ append_env_paths(&system_searchpath,
+ c_mode & _CXX ? "CPLUS_INCLUDE_PATH" : "C_INCLUDE_PATH");
+
+ /* append system search path to bracket searchpath */
+ append_searchpath(&system_searchpath, &after_searchpath);
+ append_searchpath(&bracket_searchpath, &system_searchpath);
+ append_searchpath("e_searchpath, &bracket_searchpath);
+}
+
static void input_error(unsigned const delta_lines, unsigned const delta_cols, char const *const message)
{
- source_position_t pos = pp_token.base.source_position;
+ position_t pos = pp_token.base.pos;
pos.lineno += delta_lines;
pos.colno += delta_cols;
errorf(&pos, "%s", message);
}
+void init_include_paths(void)
+{
+ obstack_init(&config_obstack);
+}
+
void init_preprocessor(void)
{
init_symbols();
- obstack_init(&config_obstack);
obstack_init(&pp_obstack);
obstack_init(&input_obstack);
strset_init(&stringset);
int pptest_main(int argc, char **argv)
{
init_symbol_table();
+ init_include_paths();
init_preprocessor();
init_tokens();
for (int i = 1; i < argc; ++i) {
const char *opt = argv[i];
if (streq(opt, "-I")) {
- prepend_include_path(argv[++i]);
+ append_include_path(&bracket_searchpath, argv[++i]);
continue;
} else if (streq(opt, "-E")) {
/* ignore */
fprintf(stderr, "Couldn't open input '%s'\n", filename);
return 1;
}
- switch_pp_input(file, filename, NULL);
+ switch_pp_input(file, filename, NULL, false);
for (;;) {
next_preprocessing_token();