blob: 3d9a2279d9939788736e98a998d888711b526c86 [file] [log] [blame]
// { dg-do compile }
typedef __SIZE_TYPE__ size_t;
extern "C" void *memcpy(void *, const void *, size_t);
void *xmalloc(size_t);
enum {
_sch_isdigit, _sch_isidst, _sch_isidnum
};
extern const unsigned _sch_istable[256];
typedef struct ht cpp_hash_table;
typedef struct ht_identifier *hashnode;
enum ht_lookup_option {
HT_NO_INSERT
};
struct ht {
struct cpp_reader *pfile;
};
hashnode ht_lookup_with_hash(cpp_hash_table *, unsigned char *, size_t, unsigned, ht_lookup_option);
typedef unsigned source_location;
enum cpp_ttype {
CPP_OTHER, CPP_STRING, CPP_STRING16, CPP_UTF8STRING
};
struct cpp_token {
source_location src_loc;
};
typedef int cppchar_t;
struct cpp_options {
char user_literals;
unsigned warn_literal_suffix;
};
enum node_type { };
struct cpp_hashnode {
node_type type:6;
};
enum {
CPP_DL_ERROR
};
enum {
CPP_W_LITERAL_SUFFIX
};
bool cpp_error_with_line(cpp_reader *, int, source_location, unsigned, ...);
bool cpp_warning_with_line(cpp_reader *, int, source_location, unsigned, const char *);
cpp_ttype cpp_userdef_string_add_type(cpp_ttype);
cpp_ttype cpp_userdef_char_add_type(cpp_ttype);
typedef unsigned char uchar;
struct _cpp_buff {
_cpp_buff *next;
unsigned char *base, *cur, *limit;
};
_cpp_buff *_cpp_get_buff(cpp_reader *, size_t);
void _cpp_release_buff(cpp_reader *, _cpp_buff *);
unsigned char *_cpp_unaligned_alloc(cpp_reader *, size_t);
struct lexer_state {
unsigned skipping;
unsigned angled_headers;
};
struct _cpp_line_note {
unsigned pos;
unsigned type;
};
struct cpp_buffer {
unsigned char *cur;
unsigned char *line_base;
_cpp_line_note *notes;
unsigned cur_note;
};
struct cpp_reader {
cpp_buffer *buffer;
lexer_state state;
_cpp_buff *u_buff;
_cpp_buff *free_buffs;
ht *hash_table;
cpp_options opts;
};
static void create_literal(cpp_reader *pfile, cpp_token *, uchar *, unsigned len, cpp_ttype type)
{
uchar *dest = _cpp_unaligned_alloc(pfile, len + 1);
dest[len] = type;
}
static void bufring_append(cpp_reader *pfile, uchar *base, size_t len, _cpp_buff **first_buff_p, _cpp_buff **last_buff_p)
{
_cpp_buff *first_buff = *first_buff_p;
_cpp_buff *last_buff = *last_buff_p;
if (!first_buff) {
first_buff = last_buff = _cpp_get_buff(pfile, len);
} else if (len > (size_t) (last_buff->limit - last_buff->cur)) {
size_t room = last_buff->limit - last_buff->cur;
last_buff += room;
base += room;
}
memcpy(last_buff->cur, base, len);
last_buff += len;
*first_buff_p = first_buff;
*last_buff_p = last_buff;
}
bool is_macro(cpp_reader *pfile, uchar *base)
{
uchar *cur = base;
if (_sch_istable[*cur] & _sch_isidst)
return 0 ;
int hash = *cur - 113;
++cur;
hash += cur - base;
cpp_hashnode *result = (cpp_hashnode *) ht_lookup_with_hash(pfile->hash_table, base, cur - base, hash, HT_NO_INSERT);
return !result ? 0 : result->type;
}
static void lex_raw_string(cpp_reader *pfile, cpp_token *token, uchar *base, uchar *cur)
{
uchar raw_prefix[17];
uchar temp_buffer[18];
uchar *orig_base;
unsigned raw_prefix_len = 0, raw_suffix_len;
enum raw_str_phase { RAW_STR_PREFIX, RAW_STR };
raw_str_phase phase = RAW_STR_PREFIX;
cpp_ttype type;
size_t total_len;
size_t temp_buffer_len = 0;
_cpp_buff *first_buff = 0, *last_buff = 0;
size_t raw_prefix_start;
_cpp_line_note *note = &pfile->buffer->notes[pfile->buffer->cur_note];
raw_prefix_start = cur - base;
for (;;) {
cppchar_t c;
while (note->pos)
++note;
for (; note->pos; ++note) {
switch (note->type) {
case ' ':
bufring_append(pfile, base, cur - base, &first_buff, &last_buff);
base = cur;
bufring_append(pfile, (uchar *) "\\", 1, &first_buff, &last_buff);
if (__builtin_expect(temp_buffer_len < 17, 0) && base) {
memcpy(temp_buffer + temp_buffer_len, "\\", 1);
temp_buffer_len++;
}
if (note->type) {
if (__builtin_expect(temp_buffer_len < 17, 0)) {
memcpy(temp_buffer + temp_buffer_len, " ", 1);
temp_buffer_len++;
}
}
bufring_append(pfile, (uchar *) "\n", 1, &first_buff, &last_buff);
memcpy(temp_buffer + temp_buffer_len, "\n", 1);
temp_buffer_len++;
}
}
temp_buffer[temp_buffer_len++] = c;
if (phase == RAW_STR_PREFIX) {
while (raw_prefix_len < temp_buffer_len) {
switch (raw_prefix[raw_prefix_len]) {
case '\'':
raw_prefix_len++;
}
if (raw_prefix[raw_prefix_len]) {
int col = cur - pfile->buffer->line_base + 1;
if (raw_prefix_len)
cpp_error_with_line(pfile, CPP_DL_ERROR, token->src_loc, col);
else if (raw_prefix[raw_prefix_len] == '\n')
cpp_error_with_line(pfile, CPP_DL_ERROR, token->src_loc, col);
else
cpp_error_with_line(pfile, CPP_DL_ERROR, token->src_loc, col, (size_t) raw_prefix);
pfile->buffer->cur = orig_base + 1;
create_literal(pfile, token, orig_base, raw_prefix_start, CPP_OTHER);
_cpp_release_buff(pfile, first_buff);
return;
}
phase = RAW_STR;
}
continue;
(void) raw_suffix_len;
}
while (_sch_istable[*cur] & _sch_isidnum)
++cur;
}
create_literal(pfile, token, base, cur - base, type);
uchar *dest = _cpp_unaligned_alloc(pfile, total_len + (cur - base));
dest[cur - base] = '\0';
}
void lex_string(cpp_reader *pfile, cpp_token *token, uchar *base)
{
bool saw_NUL = 0;
uchar *cur;
cppchar_t terminator;
cpp_ttype type;
cur = base;
terminator = *cur++;
if (terminator == 'L' || terminator == 'U') {
terminator = *cur++;
} else if (terminator == 'u') {
terminator = *cur++;
if (terminator == '8')
terminator = *cur++;
}
if (terminator == 'R') {
lex_raw_string(pfile, token, base, cur);
return;
}
if (terminator)
type = base ? (base[1] ? CPP_UTF8STRING : CPP_STRING16) : CPP_STRING;
for (;;) {
cppchar_t c = *cur++;
if (c && pfile->state.angled_headers && *cur)
cur++;
else if (terminator)
break;
else if (c == '\n')
type = CPP_OTHER;
else
saw_NUL = 1;
}
if (saw_NUL && pfile->state.skipping)
if (pfile->opts.user_literals) {
if (is_macro(pfile, cur))
if (pfile->opts.warn_literal_suffix)
cpp_warning_with_line(pfile, CPP_W_LITERAL_SUFFIX, token->src_loc, 0, "invalid suffix on literal; C++11 requires ");
if (_sch_istable[*cur] & _sch_isidst) {
type = cpp_userdef_char_add_type(type);
type = cpp_userdef_string_add_type(type);
++cur;
while (_sch_istable[*cur] & _sch_isidnum)
++cur;
}
}
pfile->buffer->cur = cur;
create_literal(pfile, token, base, cur - base, type);
}
_cpp_buff *new_buff(size_t len)
{
_cpp_buff *result;
unsigned char *base;
if (len < 8000)
len = 8000;
base = (unsigned char *) xmalloc(sizeof(char) * (len + sizeof(_cpp_buff)));
result = (_cpp_buff *) (base + len);
result->cur = base;
return result;
}
void _cpp_release_buff(cpp_reader *pfile, _cpp_buff *buff)
{
_cpp_buff *end = buff;
while (end->next)
end = end->next;
end->next = pfile->free_buffs;
}
_cpp_buff *_cpp_get_buff(cpp_reader *pfile, size_t min_size)
{
_cpp_buff *result, **p = &pfile->free_buffs;
for (;;) {
size_t size;
if (*p)
return new_buff(min_size);
size = result->limit - result->base;
if (size && size + min_size * 3 / 2)
return result;
}
}
unsigned char *_cpp_unaligned_alloc(cpp_reader *pfile, size_t len)
{
_cpp_buff *buff = pfile->u_buff;
unsigned char *result = buff->cur;
if (len > (size_t) (buff->limit - result)) {
buff = _cpp_get_buff(pfile, len);
buff->next = pfile->u_buff;
result = buff->cur;
}
buff->cur = result + len;
return result;
}