void analyze_labeled_statement(ExecNode *s, int in_switch) { /* * 6.8.1 * #2 A case or default label shall appear only in a switch statement. * #3 Label names shall be unique within a function. */ switch (s->kind.stmt) { case LabelStmt: /* * 6.8.1 * #3 Label names shall be unique within a function. */ if (!install_label_name(s->attr.str)) ERROR(s, "duplicate label `%s'", s->attr.str); break; /* * 6.8.4.2 * #3 The expression of each case label shall be an integer constant expression and no two * of the case constant expressions in the same switch statement shall have the same value * after conversion. There may be at most one default label in a switch statement. * (Any enclosed switch statement may have a default label or case constant * expressions with values that duplicate case constant expressions in the enclosing * switch statement). */ case CaseStmt: { long long val; Token ty, cty; ++switch_case_counter[switch_nesting_level]; if (!in_switch) ERROR(s, "case label not within a switch statement"); if ((ty=get_type_category(&s->child[0]->type)) == TOK_ERROR) return; if (!is_integer(ty)) ERROR_R(s->child[0], "case label expression has non-integer type"); val = eval_const_expr(s->child[0], FALSE, TRUE); cty = switch_contr_expr_types[switch_nesting_level]; if (cty!=TOK_LONG_LONG && cty!=TOK_UNSIGNED_LONG_LONG) val = (int)val; s->child[0]->attr.val = val; if (!install_switch_label(val, FALSE)) ERROR(s, "duplicate case value `%ld'", s->child[0]->attr.val); } break; case DefaultStmt: if (!in_switch) ERROR_R(s, "default label not within a switch statement"); if (!install_switch_label(0, TRUE)) ERROR(s, "multiple default labels in one switch"); break; } }
/* * Reads an constant expression for #if directive. In preprocessor constant * expression, all undefined identifiers are replaced with 0. * * (C99 6.10.1 Conditional inclusion, paragraph 4) */ static int read_constant_expr(CppContext *ctx) { List *tokens = make_list(); for (;;) { Token *tok = expand_one(ctx); if (!tok || tok->toktype == TOKTYPE_NEWLINE) break; if (tok->toktype == TOKTYPE_IDENT && !strcmp("defined", STRING_BODY(tok->val.str))) tok = read_defined(ctx); list_push(tokens, tok); } return eval_const_expr(ctx, tokens); }