preprocessor: scanning for :: token was missing
[cparser] / parser.c
index fc156f4..b33c140 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -20,6 +20,7 @@
 #include <config.h>
 
 #include <assert.h>
+#include <ctype.h>
 #include <stdarg.h>
 #include <stdbool.h>
 
@@ -247,16 +248,12 @@ static void semantic_comparison(binary_expression_t *expression);
        case '~':                         \
        case T_ANDAND:                    \
        case T_CHARACTER_CONSTANT:        \
-       case T_FLOATINGPOINT:             \
-       case T_INTEGER:                   \
+       case T_NUMBER:                    \
        case T_MINUSMINUS:                \
        case T_PLUSPLUS:                  \
        case T_STRING_LITERAL:            \
-       case T_WIDE_CHARACTER_CONSTANT:   \
-       case T_WIDE_STRING_LITERAL:       \
        case T___FUNCDNAME__:             \
        case T___FUNCSIG__:               \
-       case T___FUNCTION__:              \
        case T___PRETTY_FUNCTION__:       \
        case T___alignof__:               \
        case T___builtin_classify_type:   \
@@ -328,10 +325,8 @@ static size_t get_expression_struct_size(expression_kind_t kind)
                [EXPR_LITERAL_BOOLEAN]            = sizeof(literal_expression_t),
                [EXPR_LITERAL_INTEGER]            = sizeof(literal_expression_t),
                [EXPR_LITERAL_FLOATINGPOINT]      = sizeof(literal_expression_t),
-               [EXPR_LITERAL_CHARACTER]          = sizeof(literal_expression_t),
-               [EXPR_LITERAL_WIDE_CHARACTER]     = sizeof(literal_expression_t),
+               [EXPR_LITERAL_CHARACTER]          = sizeof(string_literal_expression_t),
                [EXPR_STRING_LITERAL]             = sizeof(string_literal_expression_t),
-               [EXPR_WIDE_STRING_LITERAL]        = sizeof(string_literal_expression_t),
                [EXPR_COMPOUND_LITERAL]           = sizeof(compound_literal_expression_t),
                [EXPR_CALL]                       = sizeof(call_expression_t),
                [EXPR_UNARY_FIRST]                = sizeof(unary_expression_t),
@@ -432,8 +427,7 @@ static size_t get_initializer_size(initializer_kind_t kind)
 {
        static const size_t sizes[] = {
                [INITIALIZER_VALUE]       = sizeof(initializer_value_t),
-               [INITIALIZER_STRING]      = sizeof(initializer_string_t),
-               [INITIALIZER_WIDE_STRING] = sizeof(initializer_wide_string_t),
+               [INITIALIZER_STRING]      = sizeof(initializer_value_t),
                [INITIALIZER_LIST]        = sizeof(initializer_list_t),
                [INITIALIZER_DESIGNATOR]  = sizeof(initializer_designator_t)
        };
@@ -487,12 +481,17 @@ static inline void next_token(void)
 #endif
 }
 
-#define eat(token_kind) (assert(token.kind == (token_kind)), next_token())
+static inline void eat(token_kind_t const kind)
+{
+       assert(token.kind == kind);
+       (void)kind;
+       next_token();
+}
 
-static inline bool next_if(token_kind_t const type)
+static inline bool next_if(token_kind_t const kind)
 {
-       if (token.kind == type) {
-               eat(type);
+       if (token.kind == kind) {
+               eat(kind);
                return true;
        } else {
                return false;
@@ -631,33 +630,33 @@ static void type_error_incompatible(const char *msg,
               msg, type1, type2);
 }
 
-/**
- * Expect the current token is the expected token.
- * If not, generate an error and skip until the next anchor.
- */
-static void expect(token_kind_t const expected)
+static bool skip_till(token_kind_t const expected, char const *const context)
 {
        if (UNLIKELY(token.kind != expected)) {
-               parse_error_expected(NULL, expected, NULL);
+               parse_error_expected(context, expected, NULL);
                add_anchor_token(expected);
                eat_until_anchor();
                rem_anchor_token(expected);
                if (token.kind != expected)
-                       return;
+                       return false;
        }
-       eat(expected);
+       return true;
+}
+
+/**
+ * Expect the current token is the expected token.
+ * If not, generate an error and skip until the next anchor.
+ */
+static void expect(token_kind_t const expected)
+{
+       if (skip_till(expected, NULL))
+               eat(expected);
 }
 
 static symbol_t *expect_identifier(char const *const context, source_position_t *const pos)
 {
-       if (token.kind != T_IDENTIFIER) {
-               parse_error_expected(context, T_IDENTIFIER, NULL);
-               add_anchor_token(T_IDENTIFIER);
-               eat_until_anchor();
-               rem_anchor_token(T_IDENTIFIER);
-               if (token.kind != T_IDENTIFIER)
-                       return NULL;
-       }
+       if (!skip_till(T_IDENTIFIER, context))
+               return NULL;
        symbol_t *const sym = token.base.symbol;
        if (pos)
                *pos = *HERE;
@@ -1037,27 +1036,62 @@ static expression_t *parse_assignment_expression(void)
        return parse_subexpression(PREC_ASSIGNMENT);
 }
 
-static void warn_string_concat(const source_position_t *pos)
+static void append_string(string_t const *const s)
 {
-       warningf(WARN_TRADITIONAL, pos, "traditional C rejects string constant concatenation");
+       /* FIXME Using the ast_obstack is a hack.  Using the symbol_obstack is not
+        * possible, because other tokens are grown there alongside. */
+       obstack_grow(&ast_obstack, s->begin, s->size);
 }
 
-static string_t parse_string_literals(void)
+static string_t finish_string(string_encoding_t const enc)
 {
-       assert(token.kind == T_STRING_LITERAL);
-       string_t result = token.string.string;
+       obstack_1grow(&ast_obstack, '\0');
+       size_t      const size   = obstack_object_size(&ast_obstack) - 1;
+       char const *const string = obstack_finish(&ast_obstack);
+       return (string_t){ string, size, enc };
+}
 
-       eat(T_STRING_LITERAL);
+static string_t concat_string_literals(void)
+{
+       assert(token.kind == T_STRING_LITERAL);
 
-       while (token.kind == T_STRING_LITERAL) {
-               warn_string_concat(HERE);
-               result = concat_strings(&result, &token.string.string);
+       string_t result;
+       if (look_ahead(1)->kind == T_STRING_LITERAL) {
+               append_string(&token.literal.string);
+               eat(T_STRING_LITERAL);
+               warningf(WARN_TRADITIONAL, HERE, "traditional C rejects string constant concatenation");
+               string_encoding_t enc = token.literal.string.encoding;
+               do {
+                       if (token.literal.string.encoding != STRING_ENCODING_CHAR) {
+                               enc = token.literal.string.encoding;
+                       }
+                       append_string(&token.literal.string);
+                       eat(T_STRING_LITERAL);
+               } while (token.kind == T_STRING_LITERAL);
+               result = finish_string(enc);
+       } else {
+               result = token.literal.string;
                eat(T_STRING_LITERAL);
        }
 
        return result;
 }
 
+static string_t parse_string_literals(char const *const context)
+{
+       if (!skip_till(T_STRING_LITERAL, context))
+               return (string_t){ "", 0, STRING_ENCODING_CHAR };
+
+       source_position_t const pos = *HERE;
+       string_t          const res = concat_string_literals();
+
+       if (res.encoding != STRING_ENCODING_CHAR) {
+               errorf(&pos, "expected plain string literal, got wide string literal");
+       }
+
+       return res;
+}
+
 static attribute_t *allocate_attribute_zero(attribute_kind_t kind)
 {
        attribute_t *attribute = allocate_ast_zero(sizeof(*attribute));
@@ -1456,9 +1490,9 @@ unary:
                        return;
 
                case EXPR_LITERAL_CASES:
+               case EXPR_LITERAL_CHARACTER:
                case EXPR_ERROR:
                case EXPR_STRING_LITERAL:
-               case EXPR_WIDE_STRING_LITERAL:
                case EXPR_COMPOUND_LITERAL: // TODO init?
                case EXPR_SIZEOF:
                case EXPR_CLASSIFY_TYPE:
@@ -1512,31 +1546,6 @@ static designator_t *parse_designation(void)
        }
 }
 
-static initializer_t *initializer_from_string(array_type_t *const type,
-                                              const string_t *const string)
-{
-       /* TODO: check len vs. size of array type */
-       (void) type;
-
-       initializer_t *initializer = allocate_initializer_zero(INITIALIZER_STRING);
-       initializer->string.string = *string;
-
-       return initializer;
-}
-
-static initializer_t *initializer_from_wide_string(array_type_t *const type,
-                                                   const string_t *const string)
-{
-       /* TODO: check len vs. size of array type */
-       (void) type;
-
-       initializer_t *const initializer =
-               allocate_initializer_zero(INITIALIZER_WIDE_STRING);
-       initializer->wide_string.string = *string;
-
-       return initializer;
-}
-
 /**
  * Build an initializer from a given expression.
  */
@@ -1545,39 +1554,32 @@ static initializer_t *initializer_from_expression(type_t *orig_type,
 {
        /* TODO check that expression is a constant expression */
 
-       /* §6.7.8.14/15 char array may be initialized by string literals */
-       type_t *type           = skip_typeref(orig_type);
-       type_t *expr_type_orig = expression->base.type;
-       type_t *expr_type      = skip_typeref(expr_type_orig);
+       type_t *const type = skip_typeref(orig_type);
 
-       if (is_type_array(type) && expr_type->kind == TYPE_POINTER) {
+       /* §6.7.8.14/15 char array may be initialized by string literals */
+       if (expression->kind == EXPR_STRING_LITERAL && is_type_array(type)) {
                array_type_t *const array_type   = &type->array;
                type_t       *const element_type = skip_typeref(array_type->element_type);
-
-               if (element_type->kind == TYPE_ATOMIC) {
-                       atomic_type_kind_t akind = element_type->atomic.akind;
-                       switch (expression->kind) {
-                       case EXPR_STRING_LITERAL:
-                               if (akind == ATOMIC_TYPE_CHAR
-                                               || akind == ATOMIC_TYPE_SCHAR
-                                               || akind == ATOMIC_TYPE_UCHAR) {
-                                       return initializer_from_string(array_type,
-                                                       &expression->string_literal.value);
-                               }
-                               break;
-
-                       case EXPR_WIDE_STRING_LITERAL: {
-                               type_t *bare_wchar_type = skip_typeref(type_wchar_t);
-                               if (get_unqualified_type(element_type) == bare_wchar_type) {
-                                       return initializer_from_wide_string(array_type,
-                                                       &expression->string_literal.value);
-                               }
-                               break;
+               switch (expression->string_literal.value.encoding) {
+               case STRING_ENCODING_CHAR: {
+                       if (is_type_atomic(element_type, ATOMIC_TYPE_CHAR)  ||
+                           is_type_atomic(element_type, ATOMIC_TYPE_SCHAR) ||
+                           is_type_atomic(element_type, ATOMIC_TYPE_UCHAR)) {
+                               goto make_string_init;
                        }
+                       break;
+               }
 
-                       default:
-                               break;
+               case STRING_ENCODING_WIDE: {
+                       type_t *bare_wchar_type = skip_typeref(type_wchar_t);
+                       if (get_unqualified_type(element_type) == bare_wchar_type) {
+make_string_init:;
+                               initializer_t *const init = allocate_initializer_zero(INITIALIZER_STRING);
+                               init->value.value = expression;
+                               return init;
                        }
+                       break;
+               }
                }
        }
 
@@ -2057,9 +2059,7 @@ finish_designator:
                        }
 
                        /* handle { "string" } special case */
-                       if ((expression->kind == EXPR_STRING_LITERAL
-                                       || expression->kind == EXPR_WIDE_STRING_LITERAL)
-                                       && outer_type != NULL) {
+                       if (expression->kind == EXPR_STRING_LITERAL && outer_type != NULL) {
                                sub = initializer_from_expression(outer_type, expression);
                                if (sub != NULL) {
                                        next_if(',');
@@ -2208,13 +2208,10 @@ static initializer_t *parse_initializer(parse_initializer_env_t *env)
                        size = max_index + 1;
                        break;
 
-               case INITIALIZER_STRING:
-                       size = result->string.string.size;
-                       break;
-
-               case INITIALIZER_WIDE_STRING:
-                       size = result->wide_string.string.size;
+               case INITIALIZER_STRING: {
+                       size = get_string_len(&get_init_string(result)->value) + 1;
                        break;
+               }
 
                case INITIALIZER_DESIGNATOR:
                case INITIALIZER_VALUE:
@@ -2468,6 +2465,7 @@ static type_t *parse_typeof(void)
 }
 
 typedef enum specifiers_t {
+       SPECIFIER_NONE      = 0,
        SPECIFIER_SIGNED    = 1 << 0,
        SPECIFIER_UNSIGNED  = 1 << 1,
        SPECIFIER_LONG      = 1 << 2,
@@ -3006,7 +3004,8 @@ warn_about_long_long:
                        } else {
                                errorf(pos, "multiple datatypes in declaration");
                        }
-                       goto end_error;
+                       specifiers->type = type_error_type;
+                       return;
                }
                }
 
@@ -3035,10 +3034,6 @@ warn_about_long_long:
        if (specifiers->attributes != NULL)
                type = handle_type_attributes(specifiers->attributes, type);
        specifiers->type = type;
-       return;
-
-end_error:
-       specifiers->type = type_error_type;
 }
 
 static type_qualifiers_t parse_type_qualifiers(void)
@@ -4622,8 +4617,8 @@ static bool expression_returns(expression_t const *const expr)
                case EXPR_REFERENCE:
                case EXPR_ENUM_CONSTANT:
                case EXPR_LITERAL_CASES:
+               case EXPR_LITERAL_CHARACTER:
                case EXPR_STRING_LITERAL:
-               case EXPR_WIDE_STRING_LITERAL:
                case EXPR_COMPOUND_LITERAL: // TODO descend into initialisers
                case EXPR_LABEL_ADDRESS:
                case EXPR_CLASSIFY_TYPE:
@@ -4708,7 +4703,6 @@ static bool initializer_returns(initializer_t const *const init)
                }
 
                case INITIALIZER_STRING:
-               case INITIALIZER_WIDE_STRING:
                case INITIALIZER_DESIGNATOR: // designators have no payload
                        return true;
        }
@@ -5473,8 +5467,7 @@ static expression_t *find_create_select(const source_position_t *pos,
                symbol_t *iter_symbol = iter->base.symbol;
                if (iter_symbol == NULL) {
                        type_t *type = iter->declaration.type;
-                       if (type->kind != TYPE_COMPOUND_STRUCT
-                                       && type->kind != TYPE_COMPOUND_UNION)
+                       if (!is_type_compound(type))
                                continue;
 
                        compound_t *sub_compound = type->compound.compound;
@@ -5681,14 +5674,14 @@ struct expression_parser_function_t {
 
 static expression_parser_function_t expression_parsers[T_LAST_TOKEN];
 
-static type_t *get_string_type(void)
-{
-       return is_warn_on(WARN_WRITE_STRINGS) ? type_const_char_ptr : type_char_ptr;
-}
-
-static type_t *get_wide_string_type(void)
+static type_t *get_string_type(string_encoding_t const enc)
 {
-       return is_warn_on(WARN_WRITE_STRINGS) ? type_const_wchar_t_ptr : type_wchar_t_ptr;
+       bool const warn = is_warn_on(WARN_WRITE_STRINGS);
+       switch (enc) {
+       case STRING_ENCODING_CHAR: return warn ? type_const_char_ptr    : type_char_ptr;
+       case STRING_ENCODING_WIDE: return warn ? type_const_wchar_t_ptr : type_wchar_t_ptr;
+       }
+       panic("invalid string encoding");
 }
 
 /**
@@ -5696,31 +5689,10 @@ static type_t *get_wide_string_type(void)
  */
 static expression_t *parse_string_literal(void)
 {
-       source_position_t begin   = *HERE;
-       string_t          res     = token.string.string;
-       bool              is_wide = (token.kind == T_WIDE_STRING_LITERAL);
-
-       next_token();
-       while (token.kind == T_STRING_LITERAL
-                       || token.kind == T_WIDE_STRING_LITERAL) {
-               warn_string_concat(HERE);
-               res = concat_strings(&res, &token.string.string);
-               next_token();
-               is_wide |= token.kind == T_WIDE_STRING_LITERAL;
-       }
-
-       expression_t *literal;
-       if (is_wide) {
-               literal = allocate_expression_zero(EXPR_WIDE_STRING_LITERAL);
-               literal->base.type = get_wide_string_type();
-       } else {
-               literal = allocate_expression_zero(EXPR_STRING_LITERAL);
-               literal->base.type = get_string_type();
-       }
-       literal->base.source_position = begin;
-       literal->literal.value        = res;
-
-       return literal;
+       expression_t *const expr = allocate_expression_zero(EXPR_STRING_LITERAL);
+       expr->string_literal.value = concat_string_literals();
+       expr->base.type            = get_string_type(expr->string_literal.value.encoding);
+       return expr;
 }
 
 /**
@@ -5737,110 +5709,204 @@ static expression_t *parse_boolean_literal(bool value)
        return literal;
 }
 
-static void warn_traditional_suffix(void)
+static void warn_traditional_suffix(char const *const suffix)
 {
-       warningf(WARN_TRADITIONAL, HERE, "traditional C rejects the '%S' suffix",
-                &token.number.suffix);
+       warningf(WARN_TRADITIONAL, HERE, "traditional C rejects the '%s' suffix", suffix);
 }
 
-static void check_integer_suffix(void)
+static void check_integer_suffix(expression_t *const expr, char const *const suffix)
 {
-       const string_t *suffix = &token.number.suffix;
-       if (suffix->size == 0)
-               return;
-
-       bool not_traditional = false;
-       const char *c = suffix->begin;
-       if (*c == 'l' || *c == 'L') {
-               ++c;
-               if (*c == *(c-1)) {
-                       not_traditional = true;
-                       ++c;
-                       if (*c == 'u' || *c == 'U') {
+       unsigned     spec = SPECIFIER_NONE;
+       char const  *c    = suffix;
+       for (;;) {
+               specifiers_t add;
+               if (*c == 'L' || *c == 'l') {
+                       add = SPECIFIER_LONG;
+                       if (*c == c[1]) {
+                               add |= SPECIFIER_LONG_LONG;
                                ++c;
                        }
-               } else if (*c == 'u' || *c == 'U') {
-                       not_traditional = true;
-                       ++c;
+               } else if (*c == 'U' || *c == 'u') {
+                       add = SPECIFIER_UNSIGNED;
+               } else {
+                       break;
                }
-       } else if (*c == 'u' || *c == 'U') {
-               not_traditional = true;
                ++c;
-               if (*c == 'l' || *c == 'L') {
-                       ++c;
-                       if (*c == *(c-1)) {
-                               ++c;
-                       }
-               }
-       }
-       if (*c != '\0') {
-               errorf(HERE, "invalid suffix '%S' on integer constant", suffix);
-       } else if (not_traditional) {
-               warn_traditional_suffix();
+               if (spec & add)
+                       goto error;
+               spec |= add;
+       }
+
+       if (*c == '\0') {
+               type_t *type;
+               switch (spec) {
+               case SPECIFIER_NONE:                                            type = type_int;                break;
+               case                      SPECIFIER_LONG:                       type = type_long;               break;
+               case                      SPECIFIER_LONG | SPECIFIER_LONG_LONG: type = type_long_long;          break;
+               case SPECIFIER_UNSIGNED:                                        type = type_unsigned_int;       break;
+               case SPECIFIER_UNSIGNED | SPECIFIER_LONG:                       type = type_unsigned_long;      break;
+               case SPECIFIER_UNSIGNED | SPECIFIER_LONG | SPECIFIER_LONG_LONG: type = type_unsigned_long_long; break;
+               default: panic("inconsistent suffix");
+               }
+               if (spec != SPECIFIER_NONE && spec != SPECIFIER_LONG) {
+                       warn_traditional_suffix(suffix);
+               }
+               expr->base.type = type;
+               /* Integer type depends on the size of the number and the size
+                * representable by the types. The backend/codegeneration has to
+                * determine that. */
+               determine_literal_type(&expr->literal);
+       } else {
+error:
+               errorf(HERE, "invalid suffix '%s' on integer constant", suffix);
        }
 }
 
-static type_t *check_floatingpoint_suffix(void)
+static void check_floatingpoint_suffix(expression_t *const expr, char const *const suffix)
 {
-       const string_t *suffix = &token.number.suffix;
-       type_t         *type   = type_double;
-       if (suffix->size == 0)
-               return type;
-
-       bool not_traditional = false;
-       const char *c = suffix->begin;
-       if (*c == 'f' || *c == 'F') {
-               ++c;
-               type = type_float;
-       } else if (*c == 'l' || *c == 'L') {
-               ++c;
-               type = type_long_double;
-       }
-       if (*c != '\0') {
-               errorf(HERE, "invalid suffix '%S' on floatingpoint constant", suffix);
-       } else if (not_traditional) {
-               warn_traditional_suffix();
+       type_t     *type;
+       char const *c    = suffix;
+       switch (*c) {
+       case 'F':
+       case 'f': type = type_float;       ++c; break;
+       case 'L':
+       case 'l': type = type_long_double; ++c; break;
+       default:  type = type_double;           break;
        }
 
-       return type;
+       if (*c == '\0') {
+               expr->base.type = type;
+               if (suffix[0] != '\0') {
+                       warn_traditional_suffix(suffix);
+               }
+       } else {
+               errorf(HERE, "invalid suffix '%s' on floatingpoint constant", suffix);
+       }
 }
 
-/**
- * Parse an integer constant.
- */
 static expression_t *parse_number_literal(void)
 {
-       expression_kind_t  kind;
-       type_t            *type;
+       string_t const *const str      = &token.literal.string;
+       char     const *      i        = str->begin;
+       unsigned              digits   = 0;
+       bool                  is_float = false;
 
-       switch (token.kind) {
-       case T_INTEGER:
-               kind = EXPR_LITERAL_INTEGER;
-               check_integer_suffix();
-               type = type_int;
+       /* Parse base prefix. */
+       unsigned base;
+       if (*i == '0') {
+               switch (*++i) {
+               case 'B': case 'b': base =  2; ++i;               break;
+               case 'X': case 'x': base = 16; ++i;               break;
+               default:            base =  8; digits |= 1U << 0; break;
+               }
+       } else {
+               base = 10;
+       }
+
+       /* Parse mantissa. */
+       for (;; ++i) {
+               unsigned digit;
+               switch (*i) {
+               case '.':
+                       if (is_float) {
+                               errorf(HERE, "multiple decimal points in %K", &token);
+                               i = 0;
+                               goto done;
+                       }
+                       is_float = true;
+                       if (base == 8)
+                               base = 10;
+                       continue;
+
+               case '0':           digit =  0; break;
+               case '1':           digit =  1; break;
+               case '2':           digit =  2; break;
+               case '3':           digit =  3; break;
+               case '4':           digit =  4; break;
+               case '5':           digit =  5; break;
+               case '6':           digit =  6; break;
+               case '7':           digit =  7; break;
+               case '8':           digit =  8; break;
+               case '9':           digit =  9; break;
+               case 'A': case 'a': digit = 10; break;
+               case 'B': case 'b': digit = 11; break;
+               case 'C': case 'c': digit = 12; break;
+               case 'D': case 'd': digit = 13; break;
+               case 'E': case 'e': digit = 14; break;
+               case 'F': case 'f': digit = 15; break;
+
+               default: goto done_mantissa;
+               }
+
+               if (digit >= 10 && base != 16)
+                       goto done_mantissa;
+
+               digits |= 1U << digit;
+       }
+done_mantissa:
+
+       /* Parse exponent. */
+       switch (base) {
+       case 2:
+               if (is_float)
+                       errorf(HERE, "binary floating %K not allowed", &token);
                break;
 
-       case T_FLOATINGPOINT:
-               kind = EXPR_LITERAL_FLOATINGPOINT;
-               type = check_floatingpoint_suffix();
+       case  8:
+       case 10:
+               if (*i == 'E' || *i == 'e') {
+                       base = 10;
+                       goto parse_exponent;
+               }
+               break;
+
+       case 16:
+               if (*i == 'P' || *i == 'p') {
+parse_exponent:
+                       ++i;
+                       is_float = true;
+
+                       if (*i == '-' || *i == '+')
+                               ++i;
+
+                       if (isdigit(*i)) {
+                               do {
+                                       ++i;
+                               } while (isdigit(*i));
+                       } else {
+                               errorf(HERE, "exponent of %K has no digits", &token);
+                       }
+               } else if (is_float) {
+                       errorf(HERE, "hexadecimal floating %K requires an exponent", &token);
+                       i = 0;
+               }
                break;
 
        default:
-               panic("unexpected token type in parse_number_literal");
+               panic("invalid base");
        }
 
-       expression_t *literal = allocate_expression_zero(kind);
-       literal->base.type      = type;
-       literal->literal.value  = token.number.number;
-       literal->literal.suffix = token.number.suffix;
-       next_token();
+done:;
+       expression_t *const expr = allocate_expression_zero(is_float ? EXPR_LITERAL_FLOATINGPOINT : EXPR_LITERAL_INTEGER);
+       expr->literal.value = *str;
 
-       /* integer type depends on the size of the number and the size
-        * representable by the types. The backend/codegeneration has to determine
-        * that
-        */
-       determine_literal_type(&literal->literal);
-       return literal;
+       if (i) {
+               if (digits == 0) {
+                       errorf(HERE, "%K has no digits", &token);
+               } else if (digits & ~((1U << base) - 1)) {
+                       errorf(HERE, "invalid digit in %K", &token);
+               } else {
+                       expr->literal.suffix = i;
+                       if (is_float) {
+                               check_floatingpoint_suffix(expr, i);
+                       } else {
+                               check_integer_suffix(expr, i);
+                       }
+               }
+       }
+
+       eat(T_NUMBER);
+       return expr;
 }
 
 /**
@@ -5848,42 +5914,35 @@ static expression_t *parse_number_literal(void)
  */
 static expression_t *parse_character_constant(void)
 {
-       expression_t *literal = allocate_expression_zero(EXPR_LITERAL_CHARACTER);
-       literal->base.type     = c_mode & _CXX ? type_char : type_int;
-       literal->literal.value = token.string.string;
+       expression_t *const literal = allocate_expression_zero(EXPR_LITERAL_CHARACTER);
+       literal->string_literal.value = token.literal.string;
 
-       size_t len = literal->literal.value.size;
-       if (len > 1) {
-               if (!GNU_MODE && !(c_mode & _C99)) {
-                       errorf(HERE, "more than 1 character in character constant");
-               } else {
-                       literal->base.type = type_int;
+       size_t const size = get_string_len(&token.literal.string);
+       switch (token.literal.string.encoding) {
+       case STRING_ENCODING_CHAR:
+               literal->base.type = c_mode & _CXX ? type_char : type_int;
+               if (size > 1) {
+                       if (!GNU_MODE && !(c_mode & _C99)) {
+                               errorf(HERE, "more than 1 character in character constant");
+                       } else {
+                               literal->base.type = type_int;
+                               warningf(WARN_MULTICHAR, HERE, "multi-character character constant");
+                       }
+               }
+               break;
+
+       case STRING_ENCODING_WIDE:
+               literal->base.type = type_int;
+               if (size > 1) {
                        warningf(WARN_MULTICHAR, HERE, "multi-character character constant");
                }
+               break;
        }
 
        eat(T_CHARACTER_CONSTANT);
        return literal;
 }
 
-/**
- * Parse a wide character constant.
- */
-static expression_t *parse_wide_character_constant(void)
-{
-       expression_t *literal = allocate_expression_zero(EXPR_LITERAL_WIDE_CHARACTER);
-       literal->base.type     = type_int;
-       literal->literal.value = token.string.string;
-
-       size_t len = wstrlen(&literal->literal.value);
-       if (len > 1) {
-               warningf(WARN_MULTICHAR, HERE, "multi-character character constant");
-       }
-
-       eat(T_WIDE_CHARACTER_CONSTANT);
-       return literal;
-}
-
 static entity_t *create_implicit_function(symbol_t *symbol, source_position_t const *const pos)
 {
        type_t *ntype                          = allocate_type_zero(TYPE_FUNCTION);
@@ -5969,13 +6028,9 @@ type_t *revert_automatic_type_conversion(const expression_t *expression)
        }
 
        case EXPR_STRING_LITERAL: {
-               size_t size = expression->string_literal.value.size;
-               return make_array_type(type_char, size, TYPE_QUALIFIER_NONE);
-       }
-
-       case EXPR_WIDE_STRING_LITERAL: {
-               size_t size = wstrlen(&expression->string_literal.value);
-               return make_array_type(type_wchar_t, size, TYPE_QUALIFIER_NONE);
+               size_t  const size = get_string_len(&expression->string_literal.value) + 1;
+               type_t *const elem = get_unqualified_type(expression->base.type->pointer.points_to);
+               return make_array_type(elem, size, TYPE_QUALIFIER_NONE);
        }
 
        case EXPR_COMPOUND_LITERAL:
@@ -6667,13 +6722,9 @@ static expression_t *parse_primary_expression(void)
        switch (token.kind) {
        case T_false:                        return parse_boolean_literal(false);
        case T_true:                         return parse_boolean_literal(true);
-       case T_INTEGER:
-       case T_FLOATINGPOINT:                return parse_number_literal();
+       case T_NUMBER:                       return parse_number_literal();
        case T_CHARACTER_CONSTANT:           return parse_character_constant();
-       case T_WIDE_CHARACTER_CONSTANT:      return parse_wide_character_constant();
-       case T_STRING_LITERAL:
-       case T_WIDE_STRING_LITERAL:          return parse_string_literal();
-       case T___FUNCTION__:
+       case T_STRING_LITERAL:               return parse_string_literal();
        case T___func__:                     return parse_function_keyword(FUNCNAME_FUNCTION);
        case T___PRETTY_FUNCTION__:          return parse_function_keyword(FUNCNAME_PRETTY_FUNCTION);
        case T___FUNCSIG__:                  return parse_function_keyword(FUNCNAME_FUNCSIG);
@@ -6894,9 +6945,7 @@ static expression_t *parse_select_expression(expression_t *addr)
                type_left = type;
        }
 
-       if (type_left->kind != TYPE_COMPOUND_STRUCT &&
-           type_left->kind != TYPE_COMPOUND_UNION) {
-
+       if (!is_type_compound(type_left)) {
                if (is_type_valid(type_left) && !saw_error) {
                        errorf(&pos,
                               "request for member '%Y' in something not a struct or union, but '%T'",
@@ -7970,8 +8019,7 @@ static void warn_string_literal_address(expression_t const* expr)
                expr = expr->unary.value;
        }
 
-       if (expr->kind == EXPR_STRING_LITERAL
-                       || expr->kind == EXPR_WIDE_STRING_LITERAL) {
+       if (expr->kind == EXPR_STRING_LITERAL) {
                source_position_t const *const pos = &expr->base.source_position;
                warningf(WARN_ADDRESS, pos, "comparison with string literal results in unspecified behaviour");
        }
@@ -8309,11 +8357,9 @@ static bool expression_has_effect(const expression_t *const expr)
                case EXPR_LITERAL_MS_NOOP:            return true;
                case EXPR_LITERAL_BOOLEAN:
                case EXPR_LITERAL_CHARACTER:
-               case EXPR_LITERAL_WIDE_CHARACTER:
                case EXPR_LITERAL_INTEGER:
                case EXPR_LITERAL_FLOATINGPOINT:
                case EXPR_STRING_LITERAL:             return false;
-               case EXPR_WIDE_STRING_LITERAL:        return false;
 
                case EXPR_CALL: {
                        const call_expression_t *const call = &expr->call;
@@ -8531,10 +8577,7 @@ static void register_expression_parser(parse_expression_function parser,
 {
        expression_parser_function_t *entry = &expression_parsers[token_kind];
 
-       if (entry->parser != NULL) {
-               diagnosticf("for token '%k'\n", (token_kind_t)token_kind);
-               panic("trying to register multiple expression parsers for a token");
-       }
+       assert(!entry->parser);
        entry->parser = parser;
 }
 
@@ -8550,11 +8593,7 @@ static void register_infix_parser(parse_expression_infix_function parser,
 {
        expression_parser_function_t *entry = &expression_parsers[token_kind];
 
-       if (entry->infix_parser != NULL) {
-               diagnosticf("for token '%k'\n", (token_kind_t)token_kind);
-               panic("trying to register multiple infix expression parsers for a "
-                     "token");
-       }
+       assert(!entry->infix_parser);
        entry->infix_parser     = parser;
        entry->infix_precedence = precedence;
 }
@@ -8640,7 +8679,7 @@ static asm_argument_t *parse_asm_arguments(bool is_out)
                                return NULL;
                }
 
-               argument->constraints = parse_string_literals();
+               argument->constraints = parse_string_literals("asm argument");
                add_anchor_token(')');
                expect('(');
                expression_t *expression = parse_expression();
@@ -8727,7 +8766,7 @@ static asm_clobber_t *parse_asm_clobbers(void)
 
        while (token.kind == T_STRING_LITERAL) {
                asm_clobber_t *clobber = allocate_ast_zero(sizeof(clobber[0]));
-               clobber->clobber       = parse_string_literals();
+               clobber->clobber       = parse_string_literals(NULL);
 
                *anchor = clobber;
                anchor  = &clobber->next;
@@ -8748,40 +8787,27 @@ static statement_t *parse_asm_statement(void)
        asm_statement_t *asm_statement = &statement->asms;
 
        eat(T_asm);
+       add_anchor_token(')');
+       add_anchor_token(':');
+       add_anchor_token(T_STRING_LITERAL);
 
        if (next_if(T_volatile))
                asm_statement->is_volatile = true;
 
        expect('(');
-       add_anchor_token(')');
-       if (token.kind != T_STRING_LITERAL) {
-               parse_error_expected("after asm(", T_STRING_LITERAL, NULL);
-               goto end_of_asm;
-       }
-       asm_statement->asm_text = parse_string_literals();
+       rem_anchor_token(T_STRING_LITERAL);
+       asm_statement->asm_text = parse_string_literals("asm statement");
 
-       add_anchor_token(':');
-       if (!next_if(':')) {
-               rem_anchor_token(':');
-               goto end_of_asm;
-       }
+       if (next_if(':'))
+               asm_statement->outputs = parse_asm_arguments(true);
 
-       asm_statement->outputs = parse_asm_arguments(true);
-       if (!next_if(':')) {
-               rem_anchor_token(':');
-               goto end_of_asm;
-       }
+       if (next_if(':'))
+               asm_statement->inputs = parse_asm_arguments(false);
 
-       asm_statement->inputs = parse_asm_arguments(false);
-       if (!next_if(':')) {
-               rem_anchor_token(':');
-               goto end_of_asm;
-       }
        rem_anchor_token(':');
+       if (next_if(':'))
+               asm_statement->clobbers = parse_asm_clobbers();
 
-       asm_statement->clobbers = parse_asm_clobbers();
-
-end_of_asm:
        rem_anchor_token(')');
        expect(')');
        expect(';');
@@ -9428,22 +9454,6 @@ static bool expression_is_local_variable(const expression_t *expression)
        return is_local_variable(entity);
 }
 
-/**
- * Check if a given expression represents a local variable and
- * return its declaration then, else return NULL.
- */
-entity_t *expression_is_variable(const expression_t *expression)
-{
-       if (expression->base.kind != EXPR_REFERENCE) {
-               return NULL;
-       }
-       entity_t *entity = expression->reference.entity;
-       if (entity->kind != ENTITY_VARIABLE)
-               return NULL;
-
-       return entity;
-}
-
 static void err_or_warn(source_position_t const *const pos, char const *const msg)
 {
        if (c_mode & _CXX || strict_mode) {
@@ -9804,18 +9814,14 @@ static statement_t *parse_compound_statement(bool inside_expression_statement)
        add_anchor_token('~');
        add_anchor_token(T_CHARACTER_CONSTANT);
        add_anchor_token(T_COLONCOLON);
-       add_anchor_token(T_FLOATINGPOINT);
        add_anchor_token(T_IDENTIFIER);
-       add_anchor_token(T_INTEGER);
        add_anchor_token(T_MINUSMINUS);
+       add_anchor_token(T_NUMBER);
        add_anchor_token(T_PLUSPLUS);
        add_anchor_token(T_STRING_LITERAL);
-       add_anchor_token(T_WIDE_CHARACTER_CONSTANT);
-       add_anchor_token(T_WIDE_STRING_LITERAL);
        add_anchor_token(T__Bool);
        add_anchor_token(T__Complex);
        add_anchor_token(T__Imaginary);
-       add_anchor_token(T___FUNCTION__);
        add_anchor_token(T___PRETTY_FUNCTION__);
        add_anchor_token(T___alignof__);
        add_anchor_token(T___attribute__);
@@ -9983,18 +9989,14 @@ static statement_t *parse_compound_statement(bool inside_expression_statement)
        rem_anchor_token(T___attribute__);
        rem_anchor_token(T___alignof__);
        rem_anchor_token(T___PRETTY_FUNCTION__);
-       rem_anchor_token(T___FUNCTION__);
        rem_anchor_token(T__Imaginary);
        rem_anchor_token(T__Complex);
        rem_anchor_token(T__Bool);
-       rem_anchor_token(T_WIDE_STRING_LITERAL);
-       rem_anchor_token(T_WIDE_CHARACTER_CONSTANT);
        rem_anchor_token(T_STRING_LITERAL);
        rem_anchor_token(T_PLUSPLUS);
+       rem_anchor_token(T_NUMBER);
        rem_anchor_token(T_MINUSMINUS);
-       rem_anchor_token(T_INTEGER);
        rem_anchor_token(T_IDENTIFIER);
-       rem_anchor_token(T_FLOATINGPOINT);
        rem_anchor_token(T_COLONCOLON);
        rem_anchor_token(T_CHARACTER_CONSTANT);
        rem_anchor_token('~');
@@ -10062,7 +10064,7 @@ static void parse_global_asm(void)
        expect('(');
 
        rem_anchor_token(T_STRING_LITERAL);
-       statement->asms.asm_text = parse_string_literals();
+       statement->asms.asm_text = parse_string_literals("global asm");
        statement->base.next     = unit->global_asm;
        unit->global_asm         = statement;
 
@@ -10077,7 +10079,7 @@ static void parse_linkage_specification(void)
        eat(T_extern);
 
        source_position_t const pos     = *HERE;
-       char const       *const linkage = parse_string_literals().begin;
+       char const       *const linkage = parse_string_literals(NULL).begin;
 
        linkage_kind_t old_linkage = current_linkage;
        linkage_kind_t new_linkage;
@@ -10215,7 +10217,6 @@ void start_parsing(void)
 {
        environment_stack = NEW_ARR_F(stack_entry_t, 0);
        label_stack       = NEW_ARR_F(stack_entry_t, 0);
-       diagnostic_count  = 0;
        error_count       = 0;
        warning_count     = 0;