Improve error recovery in parse_local_label_declaration().
[cparser] / lexer.c
diff --git a/lexer.c b/lexer.c
index ad249c3..d9bd2c4 100644 (file)
--- a/lexer.c
+++ b/lexer.c
@@ -276,8 +276,8 @@ end_symbol:
        char     *string = obstack_finish(&symbol_obstack);
        symbol_t *symbol = symbol_table_insert(string);
 
-       lexer_token.kind              = symbol->ID;
-       lexer_token.identifier.symbol = symbol;
+       lexer_token.kind        = symbol->ID;
+       lexer_token.base.symbol = symbol;
 
        if (symbol->string != string) {
                obstack_free(&symbol_obstack, string);
@@ -398,6 +398,31 @@ static void parse_number_hex(void)
        parse_number_suffix();
 }
 
+static void parse_number_bin(void)
+{
+       bool has_digits = false;
+
+       while (c == '0' || c == '1') {
+               has_digits = true;
+               obstack_1grow(&symbol_obstack, (char)c);
+               next_char();
+       }
+       obstack_1grow(&symbol_obstack, '\0');
+
+       size_t  const size   = obstack_object_size(&symbol_obstack) - 1;
+       char   *const string = obstack_finish(&symbol_obstack);
+       lexer_token.number.number = identify_string(string, size);
+       lexer_token.kind          = T_INTEGER;
+
+       if (!has_digits) {
+               errorf(&lexer_token.base.source_position, "invalid number literal '%S'", &lexer_token.number.number);
+               lexer_token.number.number.begin = "0";
+               lexer_token.number.number.size  = 1;
+       }
+
+       parse_number_suffix();
+}
+
 /**
  * Returns true if the given char is a octal digit.
  *
@@ -425,9 +450,14 @@ static void parse_number(void)
                        next_char();
                        parse_number_hex();
                        return;
-               } else {
-                       has_digits = true;
+               } else if (c == 'b' || c == 'B') {
+                       /* GCC extension: binary constant 0x[bB][01]+.  */
+                       obstack_1grow(&symbol_obstack, (char)c);
+                       next_char();
+                       parse_number_bin();
+                       return;
                }
+               has_digits = true;
        }
 
        while (isdigit(c)) {
@@ -932,8 +962,6 @@ typedef enum stdc_pragma_value_kind_t {
  */
 static void parse_pragma(void)
 {
-       bool unknown_pragma = true;
-
        next_pp_token();
        if (pp_token.kind != T_IDENTIFIER) {
                warningf(WARN_UNKNOWN_PRAGMAS, &pp_token.base.source_position,
@@ -942,55 +970,34 @@ static void parse_pragma(void)
                return;
        }
 
-       symbol_t *symbol = pp_token.identifier.symbol;
-       if (symbol->pp_ID == TP_STDC) {
-               stdc_pragma_kind_t kind = STDC_UNKNOWN;
+       stdc_pragma_kind_t kind = STDC_UNKNOWN;
+       if (pp_token.base.symbol->pp_ID == TP_STDC && c_mode & _C99) {
                /* a STDC pragma */
-               if (c_mode & _C99) {
-                       next_pp_token();
+               next_pp_token();
 
-                       switch (pp_token.identifier.symbol->pp_ID) {
-                       case TP_FP_CONTRACT:
-                               kind = STDC_FP_CONTRACT;
-                               break;
-                       case TP_FENV_ACCESS:
-                               kind = STDC_FENV_ACCESS;
-                               break;
-                       case TP_CX_LIMITED_RANGE:
-                               kind = STDC_CX_LIMITED_RANGE;
-                               break;
-                       default:
-                               break;
+               switch (pp_token.base.symbol->pp_ID) {
+               case TP_FP_CONTRACT:      kind = STDC_FP_CONTRACT;      break;
+               case TP_FENV_ACCESS:      kind = STDC_FENV_ACCESS;      break;
+               case TP_CX_LIMITED_RANGE: kind = STDC_CX_LIMITED_RANGE; break;
+               default:                  break;
+               }
+               if (kind != STDC_UNKNOWN) {
+                       next_pp_token();
+                       stdc_pragma_value_kind_t value;
+                       switch (pp_token.base.symbol->pp_ID) {
+                       case TP_ON:      value = STDC_VALUE_ON;      break;
+                       case TP_OFF:     value = STDC_VALUE_OFF;     break;
+                       case TP_DEFAULT: value = STDC_VALUE_DEFAULT; break;
+                       default:         value = STDC_VALUE_UNKNOWN; break;
                        }
-                       if (kind != STDC_UNKNOWN) {
-                               stdc_pragma_value_kind_t value = STDC_VALUE_UNKNOWN;
-                               next_pp_token();
-                               switch (pp_token.identifier.symbol->pp_ID) {
-                               case TP_ON:
-                                       value = STDC_VALUE_ON;
-                                       break;
-                               case TP_OFF:
-                                       value = STDC_VALUE_OFF;
-                                       break;
-                               case TP_DEFAULT:
-                                       value = STDC_VALUE_DEFAULT;
-                                       break;
-                               default:
-                                       break;
-                               }
-                               if (value != STDC_VALUE_UNKNOWN) {
-                                       unknown_pragma = false;
-                               } else {
-                                       errorf(&pp_token.base.source_position,
-                                              "bad STDC pragma argument");
-                               }
+                       if (value == STDC_VALUE_UNKNOWN) {
+                               kind = STDC_UNKNOWN;
+                               errorf(&pp_token.base.source_position, "bad STDC pragma argument");
                        }
                }
-       } else {
-               unknown_pragma = true;
        }
        eat_until_newline();
-       if (unknown_pragma) {
+       if (kind == STDC_UNKNOWN) {
                warningf(WARN_UNKNOWN_PRAGMAS, &pp_token.base.source_position,
                         "encountered unknown #pragma");
        }
@@ -1002,9 +1009,7 @@ static void parse_pragma(void)
 static void parse_preprocessor_identifier(void)
 {
        assert(pp_token.kind == T_IDENTIFIER);
-       symbol_t *symbol = pp_token.identifier.symbol;
-
-       switch (symbol->pp_ID) {
+       switch (pp_token.base.symbol->pp_ID) {
        case TP_line:
                next_pp_token();
                parse_line_directive();
@@ -1080,6 +1085,7 @@ void lexer_next_preprocessing_token(void)
 {
        while (true) {
                lexer_token.base.source_position = lexer_pos;
+               lexer_token.base.symbol          = NULL;
 
                switch (c) {
                case ' ':
@@ -1095,7 +1101,7 @@ void lexer_next_preprocessing_token(void)
                SYMBOL_CHARS
                        parse_symbol();
                        /* might be a wide string ( L"string" ) */
-                       if (lexer_token.identifier.symbol == symbol_L) {
+                       if (lexer_token.base.symbol == symbol_L) {
                                switch (c) {
                                        case '"':  parse_wide_string_literal();     break;
                                        case '\'': parse_wide_character_constant(); break;