#include "type_hash.h"
#include "ast_t.h"
#include "lang_features.h"
+#include "walk_statements.h"
#include "warning.h"
#include "adt/bitfiddle.h"
#include "adt/error.h"
static statement_t *parse_compound_statement(bool inside_expression_statement);
static statement_t *parse_statement(void);
-static expression_t *parse_sub_expression(unsigned precedence);
+typedef enum precedence_t {
+ PREC_EXPRESSION,
+ PREC_ASSIGNMENT,
+ PREC_CONDITIONAL,
+ PREC_LOGICAL_OR,
+ PREC_LOGICAL_AND,
+ PREC_OR,
+ PREC_XOR,
+ PREC_AND,
+ PREC_EQUALITY,
+ PREC_RELATIONAL,
+ PREC_SHIFT,
+ PREC_ADDITIVE,
+ PREC_MULTIPLICATIVE,
+ PREC_CAST,
+ PREC_UNARY,
+ PREC_POSTFIX,
+ PREC_PRIMARY
+} precedence_t;
+
+static expression_t *parse_sub_expression(precedence_t);
static expression_t *parse_expression(void);
static type_t *parse_typename(void);
static expression_t *parse_constant_expression(void)
{
- /* start parsing at precedence 7 (conditional expression) */
- expression_t *result = parse_sub_expression(7);
+ expression_t *result = parse_sub_expression(PREC_CONDITIONAL);
if (!is_constant_expression(result)) {
errorf(&result->base.source_position,
static expression_t *parse_assignment_expression(void)
{
- /* start parsing at precedence 2 (assignment expression) */
- return parse_sub_expression(2);
+ return parse_sub_expression(PREC_ASSIGNMENT);
}
static type_t *make_global_typedef(const char *name, type_t *type)
}
}
+static void mark_decls_read(expression_t *expr, declaration_t *lhs_decl);
+
+static declaration_t *determine_lhs_decl(expression_t *const expr, declaration_t *lhs_decl)
+{
+ switch (expr->kind) {
+ case EXPR_REFERENCE: {
+ declaration_t *const decl = expr->reference.declaration;
+ return decl;
+ }
+
+ case EXPR_ARRAY_ACCESS: {
+ expression_t *const ref = expr->array_access.array_ref;
+ declaration_t * decl = NULL;
+ if (is_type_array(skip_typeref(revert_automatic_type_conversion(ref)))) {
+ decl = determine_lhs_decl(ref, lhs_decl);
+ lhs_decl = decl;
+ } else {
+ mark_decls_read(expr->select.compound, lhs_decl);
+ }
+ mark_decls_read(expr->array_access.index, lhs_decl);
+ return decl;
+ }
+
+ case EXPR_SELECT: {
+ if (is_type_compound(skip_typeref(expr->base.type))) {
+ return determine_lhs_decl(expr->select.compound, lhs_decl);
+ } else {
+ mark_decls_read(expr->select.compound, lhs_decl);
+ return NULL;
+ }
+ }
+
+ case EXPR_UNARY_DEREFERENCE: {
+ expression_t *const val = expr->unary.value;
+ if (val->kind == EXPR_UNARY_TAKE_ADDRESS) {
+ /* *&x is a NOP */
+ return determine_lhs_decl(val->unary.value, lhs_decl);
+ } else {
+ mark_decls_read(val, NULL);
+ return NULL;
+ }
+ }
+
+ default:
+ mark_decls_read(expr, NULL);
+ return NULL;
+ }
+}
+
+#define DECL_ANY ((declaration_t*)-1)
+
+/**
+ * Mark declarations, which are read. This is used to deted variables, which
+ * are never read.
+ * Example:
+ * x = x + 1;
+ * x is not marked as "read", because it is only read to calculate its own new
+ * value.
+ *
+ * x += y; y += x;
+ * x and y are not detected as "not read", because multiple variables are
+ * involved.
+ */
+static void mark_decls_read(expression_t *const expr, declaration_t *lhs_decl)
+{
+ switch (expr->kind) {
+ case EXPR_REFERENCE: {
+ declaration_t *const decl = expr->reference.declaration;
+ if (lhs_decl != decl && lhs_decl != DECL_ANY)
+ decl->read = true;
+ return;
+ }
+
+ case EXPR_CALL:
+ // TODO respect pure/const
+ mark_decls_read(expr->call.function, NULL);
+ for (call_argument_t *arg = expr->call.arguments; arg != NULL; arg = arg->next) {
+ mark_decls_read(arg->expression, NULL);
+ }
+ return;
+
+ case EXPR_CONDITIONAL:
+ // TODO lhs_decl should depend on whether true/false have an effect
+ mark_decls_read(expr->conditional.condition, NULL);
+ if (expr->conditional.true_expression != NULL)
+ mark_decls_read(expr->conditional.true_expression, lhs_decl);
+ mark_decls_read(expr->conditional.false_expression, lhs_decl);
+ return;
+
+ case EXPR_SELECT:
+ if (lhs_decl == DECL_ANY && !is_type_compound(skip_typeref(expr->base.type)))
+ lhs_decl = NULL;
+ mark_decls_read(expr->select.compound, lhs_decl);
+ return;
+
+ case EXPR_ARRAY_ACCESS: {
+ expression_t *const ref = expr->array_access.array_ref;
+ mark_decls_read(ref, lhs_decl);
+ lhs_decl = determine_lhs_decl(ref, lhs_decl);
+ mark_decls_read(expr->array_access.index, lhs_decl);
+ return;
+ }
+
+ case EXPR_VA_ARG:
+ mark_decls_read(expr->va_arge.ap, lhs_decl);
+ return;
+
+ case EXPR_UNARY_CAST:
+ /* Special case: Use void cast to mark a variable as "read" */
+ if (is_type_atomic(skip_typeref(expr->base.type), ATOMIC_TYPE_VOID))
+ lhs_decl = NULL;
+ goto unary;
+
+ case EXPR_UNARY_DEREFERENCE:
+ if (lhs_decl == DECL_ANY)
+ lhs_decl = NULL;
+ goto unary;
+
+ case EXPR_UNARY_NEGATE:
+ case EXPR_UNARY_PLUS:
+ case EXPR_UNARY_BITWISE_NEGATE:
+ case EXPR_UNARY_NOT:
+ case EXPR_UNARY_TAKE_ADDRESS:
+ case EXPR_UNARY_POSTFIX_INCREMENT:
+ case EXPR_UNARY_POSTFIX_DECREMENT:
+ case EXPR_UNARY_PREFIX_INCREMENT:
+ case EXPR_UNARY_PREFIX_DECREMENT:
+ case EXPR_UNARY_CAST_IMPLICIT:
+ case EXPR_UNARY_ASSUME:
+unary:
+ mark_decls_read(expr->unary.value, lhs_decl);
+ return;
+
+ case EXPR_BINARY_ADD:
+ case EXPR_BINARY_SUB:
+ case EXPR_BINARY_MUL:
+ case EXPR_BINARY_DIV:
+ case EXPR_BINARY_MOD:
+ case EXPR_BINARY_EQUAL:
+ case EXPR_BINARY_NOTEQUAL:
+ case EXPR_BINARY_LESS:
+ case EXPR_BINARY_LESSEQUAL:
+ case EXPR_BINARY_GREATER:
+ case EXPR_BINARY_GREATEREQUAL:
+ case EXPR_BINARY_BITWISE_AND:
+ case EXPR_BINARY_BITWISE_OR:
+ case EXPR_BINARY_BITWISE_XOR:
+ case EXPR_BINARY_LOGICAL_AND:
+ case EXPR_BINARY_LOGICAL_OR:
+ case EXPR_BINARY_SHIFTLEFT:
+ case EXPR_BINARY_SHIFTRIGHT:
+ case EXPR_BINARY_COMMA:
+ case EXPR_BINARY_ISGREATER:
+ case EXPR_BINARY_ISGREATEREQUAL:
+ case EXPR_BINARY_ISLESS:
+ case EXPR_BINARY_ISLESSEQUAL:
+ case EXPR_BINARY_ISLESSGREATER:
+ case EXPR_BINARY_ISUNORDERED:
+ mark_decls_read(expr->binary.left, lhs_decl);
+ mark_decls_read(expr->binary.right, lhs_decl);
+ return;
+
+ case EXPR_BINARY_ASSIGN:
+ case EXPR_BINARY_MUL_ASSIGN:
+ case EXPR_BINARY_DIV_ASSIGN:
+ case EXPR_BINARY_MOD_ASSIGN:
+ case EXPR_BINARY_ADD_ASSIGN:
+ case EXPR_BINARY_SUB_ASSIGN:
+ case EXPR_BINARY_SHIFTLEFT_ASSIGN:
+ case EXPR_BINARY_SHIFTRIGHT_ASSIGN:
+ case EXPR_BINARY_BITWISE_AND_ASSIGN:
+ case EXPR_BINARY_BITWISE_XOR_ASSIGN:
+ case EXPR_BINARY_BITWISE_OR_ASSIGN: {
+ if (lhs_decl == DECL_ANY)
+ lhs_decl = NULL;
+ lhs_decl = determine_lhs_decl(expr->binary.left, lhs_decl);
+ mark_decls_read(expr->binary.right, lhs_decl);
+ return;
+ }
+
+ case EXPR_VA_START:
+ determine_lhs_decl(expr->va_starte.ap, lhs_decl);
+ return;
+
+ case EXPR_UNKNOWN:
+ case EXPR_INVALID:
+ case EXPR_CONST:
+ case EXPR_CHARACTER_CONSTANT:
+ case EXPR_WIDE_CHARACTER_CONSTANT:
+ case EXPR_STRING_LITERAL:
+ case EXPR_WIDE_STRING_LITERAL:
+ case EXPR_COMPOUND_LITERAL: // TODO init?
+ case EXPR_SIZEOF:
+ case EXPR_CLASSIFY_TYPE:
+ case EXPR_ALIGNOF:
+ case EXPR_FUNCNAME:
+ case EXPR_BUILTIN_SYMBOL:
+ case EXPR_BUILTIN_CONSTANT_P:
+ case EXPR_BUILTIN_PREFETCH:
+ case EXPR_OFFSETOF:
+ case EXPR_STATEMENT: // TODO
+ case EXPR_LABEL_ADDRESS:
+ case EXPR_BINARY_BUILTIN_EXPECT:
+ return;
+ }
+
+ panic("unhandled expression");
+}
+
static designator_t *parse_designation(void)
{
designator_t *result = NULL;
}
expression_t *expression = parse_assignment_expression();
+ mark_decls_read(expression, NULL);
if (must_be_constant && !is_initializer_constant(expression)) {
errorf(&expression->base.source_position,
"Initialisation expression '%E' is not constant\n",
if (declaration != NULL) {
declaration->scope.declarations = parameters;
declaration->scope.last_declaration = last;
- declaration->scope.is_parameter = true;
}
construct_function_type_t *construct_function_type =
case CONSTRUCT_POINTER: {
parsed_pointer_t *parsed_pointer = (parsed_pointer_t*) iter;
- type_t *pointer_type = allocate_type_zero(TYPE_POINTER, &null_position);
- pointer_type->pointer.points_to = type;
- pointer_type->base.qualifiers = parsed_pointer->type_qualifiers;
-
- type = pointer_type;
- break;
+ type = make_pointer_type(type, parsed_pointer->type_qualifiers);
+ continue;
}
case CONSTRUCT_ARRAY: {
assert(declaration != previous_declaration);
if (previous_declaration != NULL &&
- previous_declaration->parent_scope->is_parameter &&
+ previous_declaration->parent_scope == ¤t_function->scope &&
scope->depth == previous_declaration->parent_scope->depth + 1) {
errorf(&declaration->source_position,
"declaration '%#T' redeclares the parameter '%#T' (declared %P)",
label_first = label_last = NULL;
}
+static void warn_unused_decl(declaration_t *decl, declaration_t *end, char const *const what)
+{
+ for (; decl != NULL; decl = decl->next) {
+ if (decl->implicit)
+ continue;
+
+ if (!decl->used) {
+ print_in_function();
+ warningf(&decl->source_position, "%s '%Y' is unused", what, decl->symbol);
+ } else if (!decl->read) {
+ print_in_function();
+ warningf(&decl->source_position, "%s '%Y' is never read", what, decl->symbol);
+ }
+
+ if (decl == end)
+ break;
+ }
+}
+
+static void check_unused_variables(statement_t *const stmt, void *const env)
+{
+ (void)env;
+
+ switch (stmt->kind) {
+ case STATEMENT_DECLARATION: {
+ declaration_statement_t const *const decls = &stmt->declaration;
+ warn_unused_decl(decls->declarations_begin, decls->declarations_end, "variable");
+ return;
+ }
+
+ case STATEMENT_FOR:
+ warn_unused_decl(stmt->fors.scope.declarations, NULL, "variable");
+ return;
+
+ default:
+ return;
+ }
+}
+
/**
* Check declarations of current_function for unused entities.
*/
if (warning.unused_parameter) {
const scope_t *scope = ¤t_function->scope;
- if (is_sym_main(current_function->symbol)) {
- /* do not issue unused warnings for main */
- return;
- }
- const declaration_t *parameter = scope->declarations;
- for (; parameter != NULL; parameter = parameter->next) {
- if (! parameter->used) {
- print_in_function();
- warningf(¶meter->source_position,
- "unused parameter '%Y'", parameter->symbol);
- }
+ /* do not issue unused warnings for main */
+ if (!is_sym_main(current_function->symbol)) {
+ warn_unused_decl(scope->declarations, NULL, "parameter");
}
}
if (warning.unused_variable) {
+ walk_statements(current_function->init.statement, check_unused_variables, NULL);
}
}
check_reachable(next);
}
-static void check_unreachable(statement_t const* const stmt)
+static void check_unreachable(statement_t* const stmt, void *const env)
{
- if (!stmt->base.reachable &&
- stmt->kind != STATEMENT_DO_WHILE &&
- stmt->kind != STATEMENT_FOR &&
- (stmt->kind != STATEMENT_COMPOUND || stmt->compound.statements == NULL)) {
- warningf(&stmt->base.source_position, "statement is unreachable");
- }
+ (void)env;
switch (stmt->kind) {
- case STATEMENT_INVALID:
- case STATEMENT_EMPTY:
- case STATEMENT_RETURN:
- case STATEMENT_DECLARATION:
- case STATEMENT_EXPRESSION:
- case STATEMENT_CONTINUE:
- case STATEMENT_BREAK:
- case STATEMENT_GOTO:
- case STATEMENT_ASM:
- case STATEMENT_LEAVE:
- break;
-
- case STATEMENT_COMPOUND:
- if (stmt->compound.statements)
- check_unreachable(stmt->compound.statements);
- break;
-
- case STATEMENT_IF:
- check_unreachable(stmt->ifs.true_statement);
- if (stmt->ifs.false_statement != NULL)
- check_unreachable(stmt->ifs.false_statement);
- break;
-
- case STATEMENT_SWITCH:
- check_unreachable(stmt->switchs.body);
- break;
-
- case STATEMENT_LABEL:
- check_unreachable(stmt->label.statement);
- break;
-
- case STATEMENT_CASE_LABEL:
- check_unreachable(stmt->case_label.statement);
- break;
-
- case STATEMENT_WHILE:
- check_unreachable(stmt->whiles.body);
- break;
-
case STATEMENT_DO_WHILE:
- check_unreachable(stmt->do_while.body);
if (!stmt->base.reachable) {
expression_t const *const cond = stmt->do_while.condition;
if (determine_truth(cond) >= 0) {
"condition of do-while-loop is unreachable");
}
}
- break;
+ return;
case STATEMENT_FOR: {
for_statement_t const* const fors = &stmt->fors;
"step of for-statement is unreachable");
}
}
-
- check_unreachable(fors->body);
- break;
+ return;
}
- case STATEMENT_MS_TRY: {
- ms_try_statement_t const *const ms_try = &stmt->ms_try;
- check_unreachable(ms_try->try_statement);
- check_unreachable(ms_try->final_statement);
- }
- }
+ case STATEMENT_COMPOUND:
+ if (stmt->compound.statements != NULL)
+ return;
+ /* FALLTHROUGH*/
- if (stmt->base.next)
- check_unreachable(stmt->base.next);
+ default:
+ if (!stmt->base.reachable)
+ warningf(&stmt->base.source_position, "statement is unreachable");
+ return;
+ }
}
static void parse_external_declaration(void)
noreturn_candidate = true;
check_reachable(body);
if (warning.unreachable_code)
- check_unreachable(body);
+ walk_statements(body, check_unreachable, NULL);
if (warning.missing_noreturn &&
noreturn_candidate &&
!(declaration->modifiers & DM_NORETURN)) {
-typedef expression_t* (*parse_expression_function) (unsigned precedence);
-typedef expression_t* (*parse_expression_infix_function) (unsigned precedence,
- expression_t *left);
+typedef expression_t* (*parse_expression_function)(void);
+typedef expression_t* (*parse_expression_infix_function)(expression_t *left);
typedef struct expression_parser_function_t expression_parser_function_t;
struct expression_parser_function_t {
is_type_valid(orig_type) && !is_type_function(orig_type)) {
/* access of a variable from an outer function */
declaration->address_taken = true;
- ref->is_outer_ref = true;
current_function->need_closure = true;
}
expression_t *cast = allocate_expression_zero(EXPR_UNARY_CAST);
cast->base.source_position = source_position;
- expression_t *value = parse_sub_expression(20);
+ expression_t *value = parse_sub_expression(PREC_CAST);
cast->base.type = type;
cast->unary.value = value;
}
}
-static expression_t *parse_array_expression(unsigned precedence,
- expression_t *left)
+static expression_t *parse_array_expression(expression_t *left)
{
- (void) precedence;
-
eat('[');
add_anchor_token(']');
}
static expression_t *parse_typeprop(expression_kind_t const kind,
- source_position_t const pos,
- unsigned const precedence)
+ source_position_t const pos)
{
expression_t *tp_expression = allocate_expression_zero(kind);
tp_expression->base.type = type_size_t;
rem_anchor_token(')');
expect(')');
} else {
- expression_t *expression = parse_sub_expression(precedence);
+ expression_t *expression = parse_sub_expression(PREC_UNARY);
type_t* const orig_type = revert_automatic_type_conversion(expression);
expression->base.type = orig_type;
return tp_expression;
}
-static expression_t *parse_sizeof(unsigned precedence)
+static expression_t *parse_sizeof(void)
{
source_position_t pos = *HERE;
eat(T_sizeof);
- return parse_typeprop(EXPR_SIZEOF, pos, precedence);
+ return parse_typeprop(EXPR_SIZEOF, pos);
}
-static expression_t *parse_alignof(unsigned precedence)
+static expression_t *parse_alignof(void)
{
source_position_t pos = *HERE;
eat(T___alignof__);
- return parse_typeprop(EXPR_ALIGNOF, pos, precedence);
+ return parse_typeprop(EXPR_ALIGNOF, pos);
}
-static expression_t *parse_select_expression(unsigned precedence,
- expression_t *compound)
+static expression_t *parse_select_expression(expression_t *compound)
{
- (void) precedence;
assert(token.type == '.' || token.type == T_MINUSGREATER);
bool is_pointer = (token.type == T_MINUSGREATER);
*
* @param expression the function address
*/
-static expression_t *parse_call_expression(unsigned precedence,
- expression_t *expression)
+static expression_t *parse_call_expression(expression_t *expression)
{
- (void) precedence;
expression_t *result = allocate_expression_zero(EXPR_CALL);
result->base.source_position = expression->base.source_position;
*
* @param expression the conditional expression
*/
-static expression_t *parse_conditional_expression(unsigned precedence,
- expression_t *expression)
+static expression_t *parse_conditional_expression(expression_t *expression)
{
expression_t *result = allocate_expression_zero(EXPR_CONDITIONAL);
true_expression = parse_expression();
rem_anchor_token(':');
expect(':');
- expression_t *false_expression = parse_sub_expression(precedence);
+ expression_t *false_expression = parse_sub_expression(PREC_CONDITIONAL);
type_t *const orig_true_type = true_expression->base.type;
type_t *const orig_false_type = false_expression->base.type;
result_type = type_error_type;
}
} else {
- /* TODO: one pointer to void*, other some pointer */
-
if (is_type_valid(true_type) && is_type_valid(false_type)) {
type_error_incompatible("while parsing conditional",
&conditional->base.source_position, true_type,
/**
* Parse an extension expression.
*/
-static expression_t *parse_extension(unsigned precedence)
+static expression_t *parse_extension(void)
{
eat(T___extension__);
bool old_gcc_extension = in_gcc_extension;
in_gcc_extension = true;
- expression_t *expression = parse_sub_expression(precedence);
+ expression_t *expression = parse_sub_expression(PREC_UNARY);
in_gcc_extension = old_gcc_extension;
return expression;
}
/**
* Parse a __builtin_classify_type() expression.
*/
-static expression_t *parse_builtin_classify_type(const unsigned precedence)
+static expression_t *parse_builtin_classify_type(void)
{
eat(T___builtin_classify_type);
expect('(');
add_anchor_token(')');
- expression_t *expression = parse_sub_expression(precedence);
+ expression_t *expression = parse_expression();
rem_anchor_token(')');
expect(')');
result->classify_type.type_expression = expression;
expression->base.type = make_pointer_type(orig_type, TYPE_QUALIFIER_NONE);
}
-#define CREATE_UNARY_EXPRESSION_PARSER(token_type, unexpression_type, sfunc) \
-static expression_t *parse_##unexpression_type(unsigned precedence) \
-{ \
- expression_t *unary_expression \
- = allocate_expression_zero(unexpression_type); \
- unary_expression->base.source_position = *HERE; \
- eat(token_type); \
- unary_expression->unary.value = parse_sub_expression(precedence); \
- \
- sfunc(&unary_expression->unary); \
- \
- return unary_expression; \
+#define CREATE_UNARY_EXPRESSION_PARSER(token_type, unexpression_type, sfunc) \
+static expression_t *parse_##unexpression_type(void) \
+{ \
+ expression_t *unary_expression \
+ = allocate_expression_zero(unexpression_type); \
+ unary_expression->base.source_position = *HERE; \
+ eat(token_type); \
+ unary_expression->unary.value = parse_sub_expression(PREC_UNARY); \
+ \
+ sfunc(&unary_expression->unary); \
+ \
+ return unary_expression; \
}
CREATE_UNARY_EXPRESSION_PARSER('-', EXPR_UNARY_NEGATE,
#define CREATE_UNARY_POSTFIX_EXPRESSION_PARSER(token_type, unexpression_type, \
sfunc) \
-static expression_t *parse_##unexpression_type(unsigned precedence, \
- expression_t *left) \
+static expression_t *parse_##unexpression_type(expression_t *left) \
{ \
- (void) precedence; \
- \
expression_t *unary_expression \
= allocate_expression_zero(unexpression_type); \
unary_expression->base.source_position = *HERE; \
expression->base.type = expression->right->base.type;
}
-#define CREATE_BINEXPR_PARSER(token_type, binexpression_type, sfunc, lr) \
-static expression_t *parse_##binexpression_type(unsigned precedence, \
- expression_t *left) \
-{ \
- expression_t *binexpr = allocate_expression_zero(binexpression_type); \
- binexpr->base.source_position = *HERE; \
- binexpr->binary.left = left; \
- eat(token_type); \
- \
- expression_t *right = parse_sub_expression(precedence + lr); \
- \
- binexpr->binary.right = right; \
- sfunc(&binexpr->binary); \
- \
- return binexpr; \
-}
-
-CREATE_BINEXPR_PARSER(',', EXPR_BINARY_COMMA, semantic_comma, 1)
-CREATE_BINEXPR_PARSER('*', EXPR_BINARY_MUL, semantic_binexpr_arithmetic, 1)
-CREATE_BINEXPR_PARSER('/', EXPR_BINARY_DIV, semantic_divmod_arithmetic, 1)
-CREATE_BINEXPR_PARSER('%', EXPR_BINARY_MOD, semantic_divmod_arithmetic, 1)
-CREATE_BINEXPR_PARSER('+', EXPR_BINARY_ADD, semantic_add, 1)
-CREATE_BINEXPR_PARSER('-', EXPR_BINARY_SUB, semantic_sub, 1)
-CREATE_BINEXPR_PARSER('<', EXPR_BINARY_LESS, semantic_comparison, 1)
-CREATE_BINEXPR_PARSER('>', EXPR_BINARY_GREATER, semantic_comparison, 1)
-CREATE_BINEXPR_PARSER('=', EXPR_BINARY_ASSIGN, semantic_binexpr_assign, 0)
-
-CREATE_BINEXPR_PARSER(T_EQUALEQUAL, EXPR_BINARY_EQUAL,
- semantic_comparison, 1)
-CREATE_BINEXPR_PARSER(T_EXCLAMATIONMARKEQUAL, EXPR_BINARY_NOTEQUAL,
- semantic_comparison, 1)
-CREATE_BINEXPR_PARSER(T_LESSEQUAL, EXPR_BINARY_LESSEQUAL,
- semantic_comparison, 1)
-CREATE_BINEXPR_PARSER(T_GREATEREQUAL, EXPR_BINARY_GREATEREQUAL,
- semantic_comparison, 1)
-
-CREATE_BINEXPR_PARSER('&', EXPR_BINARY_BITWISE_AND,
- semantic_binexpr_arithmetic, 1)
-CREATE_BINEXPR_PARSER('|', EXPR_BINARY_BITWISE_OR,
- semantic_binexpr_arithmetic, 1)
-CREATE_BINEXPR_PARSER('^', EXPR_BINARY_BITWISE_XOR,
- semantic_binexpr_arithmetic, 1)
-CREATE_BINEXPR_PARSER(T_ANDAND, EXPR_BINARY_LOGICAL_AND,
- semantic_logical_op, 1)
-CREATE_BINEXPR_PARSER(T_PIPEPIPE, EXPR_BINARY_LOGICAL_OR,
- semantic_logical_op, 1)
-CREATE_BINEXPR_PARSER(T_LESSLESS, EXPR_BINARY_SHIFTLEFT,
- semantic_shift_op, 1)
-CREATE_BINEXPR_PARSER(T_GREATERGREATER, EXPR_BINARY_SHIFTRIGHT,
- semantic_shift_op, 1)
-CREATE_BINEXPR_PARSER(T_PLUSEQUAL, EXPR_BINARY_ADD_ASSIGN,
- semantic_arithmetic_addsubb_assign, 0)
-CREATE_BINEXPR_PARSER(T_MINUSEQUAL, EXPR_BINARY_SUB_ASSIGN,
- semantic_arithmetic_addsubb_assign, 0)
-CREATE_BINEXPR_PARSER(T_ASTERISKEQUAL, EXPR_BINARY_MUL_ASSIGN,
- semantic_arithmetic_assign, 0)
-CREATE_BINEXPR_PARSER(T_SLASHEQUAL, EXPR_BINARY_DIV_ASSIGN,
- semantic_divmod_assign, 0)
-CREATE_BINEXPR_PARSER(T_PERCENTEQUAL, EXPR_BINARY_MOD_ASSIGN,
- semantic_divmod_assign, 0)
-CREATE_BINEXPR_PARSER(T_LESSLESSEQUAL, EXPR_BINARY_SHIFTLEFT_ASSIGN,
- semantic_arithmetic_assign, 0)
-CREATE_BINEXPR_PARSER(T_GREATERGREATEREQUAL, EXPR_BINARY_SHIFTRIGHT_ASSIGN,
- semantic_arithmetic_assign, 0)
-CREATE_BINEXPR_PARSER(T_ANDEQUAL, EXPR_BINARY_BITWISE_AND_ASSIGN,
- semantic_arithmetic_assign, 0)
-CREATE_BINEXPR_PARSER(T_PIPEEQUAL, EXPR_BINARY_BITWISE_OR_ASSIGN,
- semantic_arithmetic_assign, 0)
-CREATE_BINEXPR_PARSER(T_CARETEQUAL, EXPR_BINARY_BITWISE_XOR_ASSIGN,
- semantic_arithmetic_assign, 0)
-
-static expression_t *parse_sub_expression(unsigned precedence)
+/**
+ * @param prec_r precedence of the right operand
+ */
+#define CREATE_BINEXPR_PARSER(token_type, binexpression_type, prec_r, sfunc) \
+static expression_t *parse_##binexpression_type(expression_t *left) \
+{ \
+ expression_t *binexpr = allocate_expression_zero(binexpression_type); \
+ binexpr->base.source_position = *HERE; \
+ binexpr->binary.left = left; \
+ eat(token_type); \
+ \
+ expression_t *right = parse_sub_expression(prec_r); \
+ \
+ binexpr->binary.right = right; \
+ sfunc(&binexpr->binary); \
+ \
+ return binexpr; \
+}
+
+CREATE_BINEXPR_PARSER('*', EXPR_BINARY_MUL, PREC_CAST, semantic_binexpr_arithmetic)
+CREATE_BINEXPR_PARSER('/', EXPR_BINARY_DIV, PREC_CAST, semantic_divmod_arithmetic)
+CREATE_BINEXPR_PARSER('%', EXPR_BINARY_MOD, PREC_CAST, semantic_divmod_arithmetic)
+CREATE_BINEXPR_PARSER('+', EXPR_BINARY_ADD, PREC_MULTIPLICATIVE, semantic_add)
+CREATE_BINEXPR_PARSER('-', EXPR_BINARY_SUB, PREC_MULTIPLICATIVE, semantic_sub)
+CREATE_BINEXPR_PARSER(T_LESSLESS, EXPR_BINARY_SHIFTLEFT, PREC_ADDITIVE, semantic_shift_op)
+CREATE_BINEXPR_PARSER(T_GREATERGREATER, EXPR_BINARY_SHIFTRIGHT, PREC_ADDITIVE, semantic_shift_op)
+CREATE_BINEXPR_PARSER('<', EXPR_BINARY_LESS, PREC_SHIFT, semantic_comparison)
+CREATE_BINEXPR_PARSER('>', EXPR_BINARY_GREATER, PREC_SHIFT, semantic_comparison)
+CREATE_BINEXPR_PARSER(T_LESSEQUAL, EXPR_BINARY_LESSEQUAL, PREC_SHIFT, semantic_comparison)
+CREATE_BINEXPR_PARSER(T_GREATEREQUAL, EXPR_BINARY_GREATEREQUAL, PREC_SHIFT, semantic_comparison)
+CREATE_BINEXPR_PARSER(T_EXCLAMATIONMARKEQUAL, EXPR_BINARY_NOTEQUAL, PREC_RELATIONAL, semantic_comparison)
+CREATE_BINEXPR_PARSER(T_EQUALEQUAL, EXPR_BINARY_EQUAL, PREC_RELATIONAL, semantic_comparison)
+CREATE_BINEXPR_PARSER('&', EXPR_BINARY_BITWISE_AND, PREC_EQUALITY, semantic_binexpr_arithmetic)
+CREATE_BINEXPR_PARSER('^', EXPR_BINARY_BITWISE_XOR, PREC_AND, semantic_binexpr_arithmetic)
+CREATE_BINEXPR_PARSER('|', EXPR_BINARY_BITWISE_OR, PREC_XOR, semantic_binexpr_arithmetic)
+CREATE_BINEXPR_PARSER(T_ANDAND, EXPR_BINARY_LOGICAL_AND, PREC_OR, semantic_logical_op)
+CREATE_BINEXPR_PARSER(T_PIPEPIPE, EXPR_BINARY_LOGICAL_OR, PREC_LOGICAL_AND, semantic_logical_op)
+CREATE_BINEXPR_PARSER('=', EXPR_BINARY_ASSIGN, PREC_ASSIGNMENT, semantic_binexpr_assign)
+CREATE_BINEXPR_PARSER(T_PLUSEQUAL, EXPR_BINARY_ADD_ASSIGN, PREC_ASSIGNMENT, semantic_arithmetic_addsubb_assign)
+CREATE_BINEXPR_PARSER(T_MINUSEQUAL, EXPR_BINARY_SUB_ASSIGN, PREC_ASSIGNMENT, semantic_arithmetic_addsubb_assign)
+CREATE_BINEXPR_PARSER(T_ASTERISKEQUAL, EXPR_BINARY_MUL_ASSIGN, PREC_ASSIGNMENT, semantic_arithmetic_assign)
+CREATE_BINEXPR_PARSER(T_SLASHEQUAL, EXPR_BINARY_DIV_ASSIGN, PREC_ASSIGNMENT, semantic_divmod_assign)
+CREATE_BINEXPR_PARSER(T_PERCENTEQUAL, EXPR_BINARY_MOD_ASSIGN, PREC_ASSIGNMENT, semantic_divmod_assign)
+CREATE_BINEXPR_PARSER(T_LESSLESSEQUAL, EXPR_BINARY_SHIFTLEFT_ASSIGN, PREC_ASSIGNMENT, semantic_arithmetic_assign)
+CREATE_BINEXPR_PARSER(T_GREATERGREATEREQUAL, EXPR_BINARY_SHIFTRIGHT_ASSIGN, PREC_ASSIGNMENT, semantic_arithmetic_assign)
+CREATE_BINEXPR_PARSER(T_ANDEQUAL, EXPR_BINARY_BITWISE_AND_ASSIGN, PREC_ASSIGNMENT, semantic_arithmetic_assign)
+CREATE_BINEXPR_PARSER(T_PIPEEQUAL, EXPR_BINARY_BITWISE_OR_ASSIGN, PREC_ASSIGNMENT, semantic_arithmetic_assign)
+CREATE_BINEXPR_PARSER(T_CARETEQUAL, EXPR_BINARY_BITWISE_XOR_ASSIGN, PREC_ASSIGNMENT, semantic_arithmetic_assign)
+CREATE_BINEXPR_PARSER(',', EXPR_BINARY_COMMA, PREC_ASSIGNMENT, semantic_comma)
+
+
+static expression_t *parse_sub_expression(precedence_t precedence)
{
if (token.type < 0) {
return expected_expression_error();
expression_t *left;
if (parser->parser != NULL) {
- left = parser->parser(parser->precedence);
+ left = parser->parser();
} else {
left = parse_primary_expression();
}
if (parser->infix_precedence < precedence)
break;
- left = parser->infix_parser(parser->infix_precedence, left);
+ left = parser->infix_parser(left);
assert(left != NULL);
assert(left->kind != EXPR_UNKNOWN);
*/
static expression_t *parse_expression(void)
{
- return parse_sub_expression(1);
+ return parse_sub_expression(PREC_EXPRESSION);
}
/**
{
memset(&expression_parsers, 0, sizeof(expression_parsers));
- register_infix_parser(parse_array_expression, '[', 30);
- register_infix_parser(parse_call_expression, '(', 30);
- register_infix_parser(parse_select_expression, '.', 30);
- register_infix_parser(parse_select_expression, T_MINUSGREATER, 30);
- register_infix_parser(parse_EXPR_UNARY_POSTFIX_INCREMENT,
- T_PLUSPLUS, 30);
- register_infix_parser(parse_EXPR_UNARY_POSTFIX_DECREMENT,
- T_MINUSMINUS, 30);
-
- register_infix_parser(parse_EXPR_BINARY_MUL, '*', 17);
- register_infix_parser(parse_EXPR_BINARY_DIV, '/', 17);
- register_infix_parser(parse_EXPR_BINARY_MOD, '%', 17);
- register_infix_parser(parse_EXPR_BINARY_ADD, '+', 16);
- register_infix_parser(parse_EXPR_BINARY_SUB, '-', 16);
- register_infix_parser(parse_EXPR_BINARY_SHIFTLEFT, T_LESSLESS, 15);
- register_infix_parser(parse_EXPR_BINARY_SHIFTRIGHT, T_GREATERGREATER, 15);
- register_infix_parser(parse_EXPR_BINARY_LESS, '<', 14);
- register_infix_parser(parse_EXPR_BINARY_GREATER, '>', 14);
- register_infix_parser(parse_EXPR_BINARY_LESSEQUAL, T_LESSEQUAL, 14);
- register_infix_parser(parse_EXPR_BINARY_GREATEREQUAL, T_GREATEREQUAL, 14);
- register_infix_parser(parse_EXPR_BINARY_EQUAL, T_EQUALEQUAL, 13);
- register_infix_parser(parse_EXPR_BINARY_NOTEQUAL,
- T_EXCLAMATIONMARKEQUAL, 13);
- register_infix_parser(parse_EXPR_BINARY_BITWISE_AND, '&', 12);
- register_infix_parser(parse_EXPR_BINARY_BITWISE_XOR, '^', 11);
- register_infix_parser(parse_EXPR_BINARY_BITWISE_OR, '|', 10);
- register_infix_parser(parse_EXPR_BINARY_LOGICAL_AND, T_ANDAND, 9);
- register_infix_parser(parse_EXPR_BINARY_LOGICAL_OR, T_PIPEPIPE, 8);
- register_infix_parser(parse_conditional_expression, '?', 7);
- register_infix_parser(parse_EXPR_BINARY_ASSIGN, '=', 2);
- register_infix_parser(parse_EXPR_BINARY_ADD_ASSIGN, T_PLUSEQUAL, 2);
- register_infix_parser(parse_EXPR_BINARY_SUB_ASSIGN, T_MINUSEQUAL, 2);
- register_infix_parser(parse_EXPR_BINARY_MUL_ASSIGN, T_ASTERISKEQUAL, 2);
- register_infix_parser(parse_EXPR_BINARY_DIV_ASSIGN, T_SLASHEQUAL, 2);
- register_infix_parser(parse_EXPR_BINARY_MOD_ASSIGN, T_PERCENTEQUAL, 2);
- register_infix_parser(parse_EXPR_BINARY_SHIFTLEFT_ASSIGN,
- T_LESSLESSEQUAL, 2);
- register_infix_parser(parse_EXPR_BINARY_SHIFTRIGHT_ASSIGN,
- T_GREATERGREATEREQUAL, 2);
- register_infix_parser(parse_EXPR_BINARY_BITWISE_AND_ASSIGN,
- T_ANDEQUAL, 2);
- register_infix_parser(parse_EXPR_BINARY_BITWISE_OR_ASSIGN,
- T_PIPEEQUAL, 2);
- register_infix_parser(parse_EXPR_BINARY_BITWISE_XOR_ASSIGN,
- T_CARETEQUAL, 2);
-
- register_infix_parser(parse_EXPR_BINARY_COMMA, ',', 1);
-
- register_expression_parser(parse_EXPR_UNARY_NEGATE, '-', 25);
- register_expression_parser(parse_EXPR_UNARY_PLUS, '+', 25);
- register_expression_parser(parse_EXPR_UNARY_NOT, '!', 25);
- register_expression_parser(parse_EXPR_UNARY_BITWISE_NEGATE, '~', 25);
- register_expression_parser(parse_EXPR_UNARY_DEREFERENCE, '*', 25);
- register_expression_parser(parse_EXPR_UNARY_TAKE_ADDRESS, '&', 25);
- register_expression_parser(parse_EXPR_UNARY_PREFIX_INCREMENT,
- T_PLUSPLUS, 25);
- register_expression_parser(parse_EXPR_UNARY_PREFIX_DECREMENT,
- T_MINUSMINUS, 25);
- register_expression_parser(parse_sizeof, T_sizeof, 25);
- register_expression_parser(parse_alignof, T___alignof__, 25);
- register_expression_parser(parse_extension, T___extension__, 25);
- register_expression_parser(parse_builtin_classify_type,
- T___builtin_classify_type, 25);
+ register_infix_parser(parse_array_expression, '[', PREC_POSTFIX);
+ register_infix_parser(parse_call_expression, '(', PREC_POSTFIX);
+ register_infix_parser(parse_select_expression, '.', PREC_POSTFIX);
+ register_infix_parser(parse_select_expression, T_MINUSGREATER, PREC_POSTFIX);
+ register_infix_parser(parse_EXPR_UNARY_POSTFIX_INCREMENT, T_PLUSPLUS, PREC_POSTFIX);
+ register_infix_parser(parse_EXPR_UNARY_POSTFIX_DECREMENT, T_MINUSMINUS, PREC_POSTFIX);
+ register_infix_parser(parse_EXPR_BINARY_MUL, '*', PREC_MULTIPLICATIVE);
+ register_infix_parser(parse_EXPR_BINARY_DIV, '/', PREC_MULTIPLICATIVE);
+ register_infix_parser(parse_EXPR_BINARY_MOD, '%', PREC_MULTIPLICATIVE);
+ register_infix_parser(parse_EXPR_BINARY_ADD, '+', PREC_ADDITIVE);
+ register_infix_parser(parse_EXPR_BINARY_SUB, '-', PREC_ADDITIVE);
+ register_infix_parser(parse_EXPR_BINARY_SHIFTLEFT, T_LESSLESS, PREC_SHIFT);
+ register_infix_parser(parse_EXPR_BINARY_SHIFTRIGHT, T_GREATERGREATER, PREC_SHIFT);
+ register_infix_parser(parse_EXPR_BINARY_LESS, '<', PREC_RELATIONAL);
+ register_infix_parser(parse_EXPR_BINARY_GREATER, '>', PREC_RELATIONAL);
+ register_infix_parser(parse_EXPR_BINARY_LESSEQUAL, T_LESSEQUAL, PREC_RELATIONAL);
+ register_infix_parser(parse_EXPR_BINARY_GREATEREQUAL, T_GREATEREQUAL, PREC_RELATIONAL);
+ register_infix_parser(parse_EXPR_BINARY_EQUAL, T_EQUALEQUAL, PREC_EQUALITY);
+ register_infix_parser(parse_EXPR_BINARY_NOTEQUAL, T_EXCLAMATIONMARKEQUAL, PREC_EQUALITY);
+ register_infix_parser(parse_EXPR_BINARY_BITWISE_AND, '&', PREC_AND);
+ register_infix_parser(parse_EXPR_BINARY_BITWISE_XOR, '^', PREC_XOR);
+ register_infix_parser(parse_EXPR_BINARY_BITWISE_OR, '|', PREC_OR);
+ register_infix_parser(parse_EXPR_BINARY_LOGICAL_AND, T_ANDAND, PREC_LOGICAL_AND);
+ register_infix_parser(parse_EXPR_BINARY_LOGICAL_OR, T_PIPEPIPE, PREC_LOGICAL_OR);
+ register_infix_parser(parse_conditional_expression, '?', PREC_CONDITIONAL);
+ register_infix_parser(parse_EXPR_BINARY_ASSIGN, '=', PREC_ASSIGNMENT);
+ register_infix_parser(parse_EXPR_BINARY_ADD_ASSIGN, T_PLUSEQUAL, PREC_ASSIGNMENT);
+ register_infix_parser(parse_EXPR_BINARY_SUB_ASSIGN, T_MINUSEQUAL, PREC_ASSIGNMENT);
+ register_infix_parser(parse_EXPR_BINARY_MUL_ASSIGN, T_ASTERISKEQUAL, PREC_ASSIGNMENT);
+ register_infix_parser(parse_EXPR_BINARY_DIV_ASSIGN, T_SLASHEQUAL, PREC_ASSIGNMENT);
+ register_infix_parser(parse_EXPR_BINARY_MOD_ASSIGN, T_PERCENTEQUAL, PREC_ASSIGNMENT);
+ register_infix_parser(parse_EXPR_BINARY_SHIFTLEFT_ASSIGN, T_LESSLESSEQUAL, PREC_ASSIGNMENT);
+ register_infix_parser(parse_EXPR_BINARY_SHIFTRIGHT_ASSIGN, T_GREATERGREATEREQUAL, PREC_ASSIGNMENT);
+ register_infix_parser(parse_EXPR_BINARY_BITWISE_AND_ASSIGN, T_ANDEQUAL, PREC_ASSIGNMENT);
+ register_infix_parser(parse_EXPR_BINARY_BITWISE_OR_ASSIGN, T_PIPEEQUAL, PREC_ASSIGNMENT);
+ register_infix_parser(parse_EXPR_BINARY_BITWISE_XOR_ASSIGN, T_CARETEQUAL, PREC_ASSIGNMENT);
+ register_infix_parser(parse_EXPR_BINARY_COMMA, ',', PREC_EXPRESSION);
+
+ register_expression_parser(parse_EXPR_UNARY_NEGATE, '-', PREC_UNARY);
+ register_expression_parser(parse_EXPR_UNARY_PLUS, '+', PREC_UNARY);
+ register_expression_parser(parse_EXPR_UNARY_NOT, '!', PREC_UNARY);
+ register_expression_parser(parse_EXPR_UNARY_BITWISE_NEGATE, '~', PREC_UNARY);
+ register_expression_parser(parse_EXPR_UNARY_DEREFERENCE, '*', PREC_UNARY);
+ register_expression_parser(parse_EXPR_UNARY_TAKE_ADDRESS, '&', PREC_UNARY);
+ register_expression_parser(parse_EXPR_UNARY_PREFIX_INCREMENT, T_PLUSPLUS, PREC_UNARY);
+ register_expression_parser(parse_EXPR_UNARY_PREFIX_DECREMENT, T_MINUSMINUS, PREC_UNARY);
+ register_expression_parser(parse_sizeof, T_sizeof, PREC_UNARY);
+ register_expression_parser(parse_alignof, T___alignof__, PREC_UNARY);
+ register_expression_parser(parse_extension, T___extension__, PREC_UNARY);
+ register_expression_parser(parse_builtin_classify_type, T___builtin_classify_type, PREC_UNARY);
}
/**
errorf(&expression->base.source_position,
"asm output argument is not an lvalue");
}
+
+ if (argument->constraints.begin[0] == '+')
+ mark_decls_read(expression, NULL);
+ } else {
+ mark_decls_read(expression, NULL);
}
argument->expression = expression;
expect(')');
expect('(');
add_anchor_token(')');
- statement->ifs.condition = parse_expression();
+ expression_t *const expr = parse_expression();
+ statement->ifs.condition = expr;
+ mark_decls_read(expr, NULL);
rem_anchor_token(')');
expect(')');
expect('(');
add_anchor_token(')');
expression_t *const expr = parse_expression();
+ mark_decls_read(expr, NULL);
type_t * type = skip_typeref(expr->base.type);
if (is_type_integer(type)) {
type = promote_integer(type);
expect('(');
add_anchor_token(')');
- statement->whiles.condition = parse_expression();
+ expression_t *const cond = parse_expression();
+ statement->whiles.condition = cond;
+ mark_decls_read(cond, NULL);
rem_anchor_token(')');
expect(')');
expect(T_while);
expect('(');
add_anchor_token(')');
- statement->do_while.condition = parse_expression();
+ expression_t *const cond = parse_expression();
+ statement->do_while.condition = cond;
+ mark_decls_read(cond, NULL);
rem_anchor_token(')');
expect(')');
expect(';');
add_anchor_token(';');
expression_t *const init = parse_expression();
statement->fors.initialisation = init;
+ mark_decls_read(init, DECL_ANY);
if (warning.unused_value && !expression_has_effect(init)) {
warningf(&init->base.source_position,
"initialisation of 'for'-statement has no effect");
if (token.type != ';') {
add_anchor_token(';');
- statement->fors.condition = parse_expression();
+ expression_t *const cond = parse_expression();
+ statement->fors.condition = cond;
+ mark_decls_read(cond, NULL);
rem_anchor_token(';');
}
expect(';');
if (token.type != ')') {
expression_t *const step = parse_expression();
statement->fors.step = step;
+ mark_decls_read(step, DECL_ANY);
if (warning.unused_value && !expression_has_effect(step)) {
warningf(&step->base.source_position,
"step of 'for'-statement has no effect");
if (GNU_MODE && token.type == '*') {
next_token();
expression_t *expression = parse_expression();
+ mark_decls_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 */
next_token();
statement->gotos.label = get_label(symbol);
-
- if (statement->gotos.label->parent_scope->depth < current_function->scope.depth) {
- statement->gotos.outer_fkt_jmp = true;
- }
}
/* remember the goto's in a list for later checking */
expression_t *return_value = NULL;
if (token.type != ';') {
return_value = parse_expression();
+ mark_decls_read(return_value, NULL);
}
const type_t *const func_type = current_function->type;
expression_t *const expr = parse_expression();
statement->expression.expression = expr;
+ mark_decls_read(expr, DECL_ANY);
expect(';');
expect('(');
add_anchor_token(')');
expression_t *const expr = parse_expression();
+ mark_decls_read(expr, NULL);
type_t * type = skip_typeref(expr->base.type);
if (is_type_integer(type)) {
type = promote_integer(type);
case T_do: statement = parse_do(); break;
case T_for: statement = parse_for(); break;
case T_goto: statement = parse_goto(); break;
- case T_if: statement = parse_if (); break;
+ case T_if: statement = parse_if(); break;
case T_return: statement = parse_return(); break;
case T_switch: statement = parse_switch(); break;
case T_while: statement = parse_while(); break;