Slightly simplify daisy chaining gotos.
[cparser] / parser.c
index 1c332d1..417b1e2 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -100,34 +100,34 @@ typedef struct parse_initializer_env_t {
 typedef entity_t* (*parsed_declaration_func) (entity_t *declaration, bool is_definition);
 
 /** The current token. */
-static token_t             token;
+static token_t              token;
 /** The lookahead ring-buffer. */
-static token_t             lookahead_buffer[MAX_LOOKAHEAD];
+static token_t              lookahead_buffer[MAX_LOOKAHEAD];
 /** Position of the next token in the lookahead buffer. */
-static int                 lookahead_bufpos;
-static stack_entry_t      *environment_stack = NULL;
-static stack_entry_t      *label_stack       = NULL;
-static scope_t            *file_scope        = NULL;
-static scope_t            *current_scope     = NULL;
+static int                  lookahead_bufpos;
+static stack_entry_t       *environment_stack = NULL;
+static stack_entry_t       *label_stack       = NULL;
+static scope_t             *file_scope        = NULL;
+static scope_t             *current_scope     = NULL;
 /** Point to the current function declaration if inside a function. */
-static function_t         *current_function  = NULL;
-static entity_t           *current_init_decl = NULL;
-static switch_statement_t *current_switch    = NULL;
-static statement_t        *current_loop      = NULL;
-static statement_t        *current_parent    = NULL;
-static ms_try_statement_t *current_try       = NULL;
-static symbol_t           *current_linkage   = NULL;
-static goto_statement_t   *goto_first        = NULL;
-static goto_statement_t   *goto_last         = NULL;
-static label_statement_t  *label_first       = NULL;
-static label_statement_t  *label_last        = NULL;
+static function_t          *current_function  = NULL;
+static entity_t            *current_init_decl = NULL;
+static switch_statement_t  *current_switch    = NULL;
+static statement_t         *current_loop      = NULL;
+static statement_t         *current_parent    = NULL;
+static ms_try_statement_t  *current_try       = NULL;
+static linkage_kind_t       current_linkage   = LINKAGE_INVALID;
+static goto_statement_t    *goto_first        = NULL;
+static goto_statement_t   **goto_anchor       = NULL;
+static label_statement_t   *label_first       = NULL;
+static label_statement_t  **label_anchor      = NULL;
 /** current translation unit. */
-static translation_unit_t *unit              = NULL;
+static translation_unit_t  *unit              = NULL;
 /** true if we are in a type property context (evaluation only for type. */
-static bool                in_type_prop      = false;
+static bool                 in_type_prop      = false;
 /** true in we are in a __extension__ context. */
-static bool                in_gcc_extension  = false;
-static struct obstack      temp_obst;
+static bool                 in_gcc_extension  = false;
+static struct obstack       temp_obst;
 
 
 #define PUSH_PARENT(stmt)                          \
@@ -3592,12 +3592,12 @@ static void parse_declaration_specifiers(declaration_specifiers_t *specifiers)
                /* type specifiers */
 #define MATCH_SPECIFIER(token, specifier, name)                         \
                case token:                                                     \
-                       next_token();                                               \
                        if (type_specifiers & specifier) {                           \
                                errorf(HERE, "multiple " name " type specifiers given"); \
                        } else {                                                    \
                                type_specifiers |= specifier;                           \
                        }                                                           \
+                       next_token();                                               \
                        break
 
                MATCH_SPECIFIER(T__Bool,      SPECIFIER_BOOL,      "_Bool");
@@ -3629,7 +3629,6 @@ static void parse_declaration_specifiers(declaration_specifiers_t *specifiers)
                        break;
 
                case T_long:
-                       next_token();
                        if (type_specifiers & SPECIFIER_LONG_LONG) {
                                errorf(HERE, "multiple type specifiers given");
                        } else if (type_specifiers & SPECIFIER_LONG) {
@@ -3637,6 +3636,7 @@ static void parse_declaration_specifiers(declaration_specifiers_t *specifiers)
                        } else {
                                type_specifiers |= SPECIFIER_LONG;
                        }
+                       next_token();
                        break;
 
                case T_struct: {
@@ -5272,8 +5272,8 @@ static void check_labels(void)
                               "label '%Y' used but not defined", label->base.symbol);
                 }
        }
-       goto_first = NULL;
-       goto_last  = NULL;
+       goto_first  = NULL;
+       goto_anchor = &goto_first;
 
        if (warning.unused_label) {
                for (const label_statement_t *label_statement = label_first;
@@ -5288,7 +5288,8 @@ static void check_labels(void)
                        }
                }
        }
-       label_first = label_last = NULL;
+       label_first  = NULL;
+       label_anchor = &label_first;
 }
 
 static void warn_unused_decl(entity_t *entity, entity_t *end,
@@ -7746,6 +7747,48 @@ static bool same_compound_type(const type_t *type1, const type_t *type2)
                type1->compound.compound == type2->compound.compound;
 }
 
+static expression_t const *get_reference_address(expression_t const *expr)
+{
+       bool regular_take_address = true;
+       for (;;) {
+               if (expr->kind == EXPR_UNARY_TAKE_ADDRESS) {
+                       expr = expr->unary.value;
+               } else {
+                       regular_take_address = false;
+               }
+
+               if (expr->kind != EXPR_UNARY_DEREFERENCE)
+                       break;
+
+               expr = expr->unary.value;
+       }
+
+       if (expr->kind != EXPR_REFERENCE)
+               return NULL;
+
+       /* special case for functions which are automatically converted to a
+        * pointer to function without an extra TAKE_ADDRESS operation */
+       if (!regular_take_address &&
+                       expr->reference.entity->kind != ENTITY_FUNCTION) {
+               return NULL;
+       }
+
+       return expr;
+}
+
+static void warn_reference_address_as_bool(expression_t const* expr)
+{
+       if (!warning.address)
+               return;
+
+       expr = get_reference_address(expr);
+       if (expr != NULL) {
+               warningf(&expr->base.source_position,
+                        "the address of '%Y' will always evaluate as 'true'",
+                        expr->reference.entity->base.symbol);
+       }
+}
+
 /**
  * Parse a conditional expression, ie. 'expression ? ... : ...'.
  *
@@ -7758,6 +7801,8 @@ static expression_t *parse_conditional_expression(expression_t *expression)
        conditional_expression_t *conditional = &result->conditional;
        conditional->condition                = expression;
 
+       warn_reference_address_as_bool(expression);
+
        eat('?');
        add_anchor_token(':');
 
@@ -8096,45 +8141,6 @@ static void semantic_unexpr_plus(unary_expression_t *expression)
                        "traditional C rejects the unary plus operator");
 }
 
-static expression_t const *get_reference_address(expression_t const *expr)
-{
-       bool regular_take_address = true;
-       for (;;) {
-               if (expr->kind == EXPR_UNARY_TAKE_ADDRESS) {
-                       expr = expr->unary.value;
-               } else {
-                       regular_take_address = false;
-               }
-
-               if (expr->kind != EXPR_UNARY_DEREFERENCE)
-                       break;
-
-               expr = expr->unary.value;
-       }
-
-       /* special case for functions which are automatically converted to a
-        * pointer to function without an extra TAKE_ADDRESS operation */
-       if (!regular_take_address && expr->kind == EXPR_REFERENCE
-                       && expr->reference.entity->kind == ENTITY_FUNCTION) {
-               return expr;
-       }
-
-       return NULL;
-}
-
-static void warn_function_address_as_bool(expression_t const* expr)
-{
-       if (!warning.address)
-               return;
-
-       expr = get_reference_address(expr);
-       if (expr != NULL) {
-               warningf(&expr->base.source_position,
-                        "the address of '%Y' will always evaluate as 'true'",
-                        expr->reference.entity->base.symbol);
-       }
-}
-
 static void semantic_not(unary_expression_t *expression)
 {
        type_t *const orig_type = expression->value->base.type;
@@ -8144,7 +8150,7 @@ static void semantic_not(unary_expression_t *expression)
                       "operand of ! must be of scalar type");
        }
 
-       warn_function_address_as_bool(expression->value);
+       warn_reference_address_as_bool(expression->value);
 
        expression->base.type = c_mode & _CXX ? type_bool : type_int;
 }
@@ -8221,11 +8227,8 @@ static void semantic_take_addr(unary_expression_t *expression)
                return;
 
        /* ยง6.5.3.2 */
-       if (value->kind != EXPR_ARRAY_ACCESS
-                       && value->kind != EXPR_UNARY_DEREFERENCE
-                       && !is_lvalue(value)) {
-               errorf(&expression->base.source_position,
-                      "'&' requires an lvalue");
+       if (!is_lvalue(value)) {
+               errorf(&expression->base.source_position, "'&' requires an lvalue");
        }
        if (type->kind == TYPE_BITFIELD) {
                errorf(&expression->base.source_position,
@@ -8744,8 +8747,8 @@ static void semantic_logical_op(binary_expression_t *expression)
        type_t       *const type_left       = skip_typeref(orig_type_left);
        type_t       *const type_right      = skip_typeref(orig_type_right);
 
-       warn_function_address_as_bool(left);
-       warn_function_address_as_bool(right);
+       warn_reference_address_as_bool(left);
+       warn_reference_address_as_bool(right);
 
        if (!is_type_scalar(type_left) || !is_type_scalar(type_right)) {
                /* TODO: improve error message */
@@ -9129,8 +9132,8 @@ static void init_expression_parsers(void)
  */
 static asm_argument_t *parse_asm_arguments(bool is_out)
 {
-       asm_argument_t *result = NULL;
-       asm_argument_t *last   = NULL;
+       asm_argument_t  *result = NULL;
+       asm_argument_t **anchor = &result;
 
        while (token.type == T_STRING_LITERAL || token.type == '[') {
                asm_argument_t *argument = allocate_ast_zero(sizeof(argument[0]));
@@ -9213,12 +9216,8 @@ static asm_argument_t *parse_asm_arguments(bool is_out)
 
                set_address_taken(expression, true);
 
-               if (last != NULL) {
-                       last->next = argument;
-               } else {
-                       result = argument;
-               }
-               last = argument;
+               *anchor = argument;
+               anchor  = &argument->next;
 
                if (token.type != ',')
                        break;
@@ -9510,12 +9509,8 @@ static statement_t *parse_label_statement(void)
        }
 
        /* remember the labels in a list for later checking */
-       if (label_last == NULL) {
-               label_first = &statement->label;
-       } else {
-               label_last->next = &statement->label;
-       }
-       label_last = &statement->label;
+       *label_anchor = &statement->label;
+       label_anchor  = &statement->label.next;
 
        POP_PARENT;
        return statement;
@@ -9538,6 +9533,7 @@ static statement_t *parse_if(void)
        add_anchor_token(')');
        expression_t *const expr = parse_expression();
        statement->ifs.condition = expr;
+       warn_reference_address_as_bool(expr);
        mark_vars_read(expr, NULL);
        rem_anchor_token(')');
        expect(')');
@@ -9678,6 +9674,7 @@ static statement_t *parse_while(void)
        add_anchor_token(')');
        expression_t *const cond = parse_expression();
        statement->whiles.condition = cond;
+       warn_reference_address_as_bool(cond);
        mark_vars_read(cond, NULL);
        rem_anchor_token(')');
        expect(')');
@@ -9711,6 +9708,7 @@ static statement_t *parse_do(void)
        add_anchor_token(')');
        expression_t *const cond = parse_expression();
        statement->do_while.condition = cond;
+       warn_reference_address_as_bool(cond);
        mark_vars_read(cond, NULL);
        rem_anchor_token(')');
        expect(')');
@@ -9763,6 +9761,7 @@ static statement_t *parse_for(void)
                add_anchor_token(';');
                expression_t *const cond = parse_expression();
                statement->fors.condition = cond;
+               warn_reference_address_as_bool(cond);
                mark_vars_read(cond, NULL);
                rem_anchor_token(';');
        }
@@ -9810,8 +9809,8 @@ static statement_t *parse_goto(void)
                expression_t *expression = parse_expression();
                mark_vars_read(expression, NULL);
 
-               /* Argh: although documentation say the expression must be of type void *,
-                * gcc excepts anything that can be casted into void * without error */
+               /* Argh: although documentation says the expression must be of type void*,
+                * gcc accepts anything that can be casted into void* without error */
                type_t *type = expression->base.type;
 
                if (type != type_error_type) {
@@ -9842,12 +9841,8 @@ static statement_t *parse_goto(void)
        }
 
        /* remember the goto's in a list for later checking */
-       if (goto_last == NULL) {
-               goto_first = &statement->gotos;
-       } else {
-               goto_last->next = &statement->gotos;
-       }
-       goto_last = &statement->gotos;
+       *goto_anchor = &statement->gotos;
+       goto_anchor  = &statement->gotos.next;
 
        expect(';');
 
@@ -10469,13 +10464,19 @@ static void parse_linkage_specification(void)
        eat(T_extern);
        assert(token.type == T_STRING_LITERAL);
 
-       string_t  linkage = parse_string_literals();
-       /* convert to symbol for easier handling... */
-       symbol_t *symbol = symbol_table_insert(linkage.begin);
-
+       const char *linkage = parse_string_literals().begin;
 
-       symbol_t *old_linkage = current_linkage;
-       current_linkage       = symbol;
+       linkage_kind_t old_linkage = current_linkage;
+       linkage_kind_t new_linkage;
+       if (strcmp(linkage, "C") == 0) {
+               new_linkage = LINKAGE_C;
+       } else if (strcmp(linkage, "C++") == 0) {
+               new_linkage = LINKAGE_CXX;
+       } else {
+               errorf(HERE, "linkage string \"%s\" not recognized", linkage);
+               new_linkage = LINKAGE_INVALID;
+       }
+       current_linkage = new_linkage;
 
        if (token.type == '{') {
                next_token();
@@ -10486,7 +10487,7 @@ static void parse_linkage_specification(void)
        }
 
 end_error:
-       assert(current_linkage == symbol);
+       assert(current_linkage == new_linkage);
        current_linkage = old_linkage;
 }
 
@@ -10641,6 +10642,7 @@ void parse(void)
        for (int i = 0; i < MAX_LOOKAHEAD + 2; ++i) {
                next_token();
        }
+       current_linkage = c_mode & _CXX ? LINKAGE_CXX : LINKAGE_C;
        parse_translation_unit();
 }