| // { 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; |
| } |