class AdLint::Cc1::StatementInterpreter
Public Class Methods
new(owner)
click to toggle source
Calls superclass method
AdLint::Cc1::SubInterpreter::new
# File lib/adlint/cc1/interp.rb, line 971 def initialize(owner) super(owner, Statement) # NOTE: All effective controlling expressions in the executing # iteration-statements. @effective_ctrlexpr_stack = [] end
Public Instance Methods
visit_break_statement(node)
click to toggle source
# File lib/adlint/cc1/interp.rb, line 1238 def visit_break_statement(node) checkpoint(node.location) node.executed = true BreakEvent.of_break.throw end
visit_c99_for_statement(node)
click to toggle source
# File lib/adlint/cc1/interp.rb, line 1197 def visit_c99_for_statement(node) checkpoint(node.location) scoped_eval do interpret(node.declaration) node.executed = true notify_c99_for_stmt_started(node) if ctrlexpr_val = interpret_for_ctrlexpr(node) notify_c99_for_ctrlexpr_evaled(node, ctrlexpr_val) else ctrlexpr_val = scalar_value_of_true end case when ctrlexpr_val.test_must_be_true.true? interpret_for_body_statement(node, true) when ctrlexpr_val.test_may_be_true.true? interpret_for_body_statement(node, false) end end ensure notify_c99_for_stmt_ended(node) end
visit_case_labeled_statement(node)
click to toggle source
# File lib/adlint/cc1/interp.rb, line 989 def visit_case_labeled_statement(node) checkpoint(node.location) node.executed = true ctrlexpr = node.expression ctrlexpr_var = object_to_variable(interpret(ctrlexpr, QUIET), ctrlexpr) notify_case_ctrlexpr_evaled(node, ctrlexpr_var) interpret(node.statement) end
visit_compound_statement(node)
click to toggle source
# File lib/adlint/cc1/interp.rb, line 1007 def visit_compound_statement(node) checkpoint(node.location) node.executed = true scoped_eval do begin notify_block_started(node) node.block_items.each { |item| interpret(item) } ensure notify_block_ended(node) end end end
visit_continue_statement(node)
click to toggle source
# File lib/adlint/cc1/interp.rb, line 1231 def visit_continue_statement(node) checkpoint(node.location) node.executed = true BreakEvent.of_continue.throw end
visit_default_labeled_statement(node)
click to toggle source
# File lib/adlint/cc1/interp.rb, line 1000 def visit_default_labeled_statement(node) checkpoint(node.location) node.executed = true interpret(node.statement) end
visit_do_statement(node)
click to toggle source
# File lib/adlint/cc1/interp.rb, line 1145 def visit_do_statement(node) checkpoint(node.location) node.executed = true notify_do_stmt_started(node) widen_varying_variable_value_domain(node) orig_ctrlexpr, * = node.deduct_controlling_expression begin enter_iteration_statement(orig_ctrlexpr) branch_opts = [ITERATION, NARROWING, FINAL, IMPLICIT_COND, COMPLETE] branched_eval(nil, *branch_opts) { interpret(node.statement) } ensure leave_iteration_statement(orig_ctrlexpr) end ctrlexpr_obj = interpret(node.expression) ctrlexpr_var = object_to_variable(ctrlexpr_obj, node.expression) ctrlexpr_val = value_of(ctrlexpr_var) notify_variable_value_referred(node.expression, ctrlexpr_var) notify_sequence_point_reached(SequencePoint.new(node.expression)) notify_do_ctrlexpr_evaled(node, ctrlexpr_val) ensure notify_do_stmt_ended(node) end
visit_expression_statement(node)
click to toggle source
# File lib/adlint/cc1/interp.rb, line 1021 def visit_expression_statement(node) checkpoint(node.location) node.executed = true notify_expression_stmt_started(node) interpret(node.expression) if node.expression ensure notify_expression_stmt_ended(node) end
visit_for_statement(node)
click to toggle source
# File lib/adlint/cc1/interp.rb, line 1173 def visit_for_statement(node) checkpoint(node.location) node.executed = true notify_for_stmt_started(node) node.initial_statement.accept(self) if ctrlexpr_val = interpret_for_ctrlexpr(node) notify_for_ctrlexpr_evaled(node, ctrlexpr_val) else ctrlexpr_val = scalar_value_of_true end case when ctrlexpr_val.test_must_be_true.true? interpret_for_body_statement(node, true) when ctrlexpr_val.test_may_be_true.true? interpret_for_body_statement(node, false) end ensure notify_for_stmt_ended(node) end
visit_generic_labeled_statement(node)
click to toggle source
# File lib/adlint/cc1/interp.rb, line 979 def visit_generic_labeled_statement(node) checkpoint(node.location) node.executed = true notify_label_defined(node) uninitialize_block_local_variables(node) interpret(node.statement) end
visit_goto_statement(node)
click to toggle source
# File lib/adlint/cc1/interp.rb, line 1223 def visit_goto_statement(node) checkpoint(node.location) # TODO: Must implement goto semantics. node.executed = true notify_goto_stmt_evaled(node, node.identifier.value) end
visit_if_else_statement(node)
click to toggle source
# File lib/adlint/cc1/interp.rb, line 1066 def visit_if_else_statement(node) checkpoint(node.location) node.executed = true orig_ctrlexpr = node.expression if orig_ctrlexpr == effective_ctrlexpr ctrlexpr_val = scalar_value_of_arbitrary ctrlexpr = nil else ctrlexpr_obj = interpret(orig_ctrlexpr) ctrlexpr_var = object_to_variable(ctrlexpr_obj, orig_ctrlexpr) ctrlexpr_val = value_of(ctrlexpr_var) notify_variable_value_referred(orig_ctrlexpr, ctrlexpr_var) notify_sequence_point_reached(SequencePoint.new(orig_ctrlexpr)) ctrlexpr = orig_ctrlexpr.to_normalized_logical end notify_if_else_ctrlexpr_evaled(node, ctrlexpr_val) case when ctrlexpr_val.test_must_be_true.true? branched_eval(ctrlexpr, NARROWING, FINAL, IMPLICIT_COND, COMPLETE) do interpret(node.then_statement) end return when ctrlexpr_val.test_may_be_true.true? branched_eval(ctrlexpr, NARROWING, IMPLICIT_COND) do interpret(node.then_statement) end end case node.else_statement when IfStatement, IfElseStatement interpret(node.else_statement) else branched_eval(nil, NARROWING, COMPLEMENTAL, FINAL, COMPLETE) do interpret(node.else_statement) end end end
visit_if_statement(node)
click to toggle source
# File lib/adlint/cc1/interp.rb, line 1032 def visit_if_statement(node) checkpoint(node.location) node.executed = true orig_ctrlexpr = node.expression if orig_ctrlexpr == effective_ctrlexpr ctrlexpr_val = scalar_value_of_arbitrary ctrlexpr = nil else ctrlexpr_obj = interpret(orig_ctrlexpr) ctrlexpr_var = object_to_variable(ctrlexpr_obj, orig_ctrlexpr) ctrlexpr_val = value_of(ctrlexpr_var) notify_variable_value_referred(orig_ctrlexpr, ctrlexpr_var) notify_sequence_point_reached(SequencePoint.new(orig_ctrlexpr)) ctrlexpr = orig_ctrlexpr.to_normalized_logical end notify_if_ctrlexpr_evaled(node, ctrlexpr_val) case when ctrlexpr_val.test_must_be_true.true? branched_eval(ctrlexpr, NARROWING, FINAL, IMPLICIT_COND, COMPLETE) do interpret(node.statement) end when ctrlexpr_val.test_may_be_true.true? branched_eval(ctrlexpr, NARROWING, FINAL, IMPLICIT_COND) do interpret(node.statement) end else # NOTE: To end the current branch group of else-if sequence. branched_eval(nil, NARROWING, FINAL) {} end end
visit_return_statement(node)
click to toggle source
# File lib/adlint/cc1/interp.rb, line 1245 def visit_return_statement(node) checkpoint(node.location) node.executed = true unless node.expression notify_return_stmt_evaled(node, nil) BreakEvent.of_return.throw end var = object_to_variable(interpret(node.expression), node.expression) notify_variable_value_referred(node.expression, var) if active_fun = interpreter._active_function and ret_type = active_fun.type.return_type if var.type.same_as?(ret_type) conved = var else conved = do_conversion(var, ret_type) || create_tmpvar(ret_type) notify_implicit_conv_performed(node.expression, var, conved) end else conved = var end notify_sequence_point_reached(SequencePoint.new(node)) notify_return_stmt_evaled(node, var) BreakEvent.of_return.throw end
visit_while_statement(node)
click to toggle source
# File lib/adlint/cc1/interp.rb, line 1107 def visit_while_statement(node) checkpoint(node.location) node.executed = true notify_while_stmt_started(node) ctrlexpr_obj = interpret_iteration_ctrlexpr(node, node.expression) ctrlexpr_var = object_to_variable(ctrlexpr_obj, node.expression) ctrlexpr_val = value_of(ctrlexpr_var) notify_variable_value_referred(node.expression, ctrlexpr_var) notify_sequence_point_reached(SequencePoint.new(node.expression)) notify_while_ctrlexpr_evaled(node, ctrlexpr_val) orig_ctrlexpr, ctrlexpr = node.deduct_controlling_expression case when ctrlexpr_val.test_must_be_true.true? begin enter_iteration_statement(orig_ctrlexpr) branch_opts = [ITERATION, NARROWING, FINAL, IMPLICIT_COND, COMPLETE] branched_eval(ctrlexpr, *branch_opts) { interpret(node.statement) } ensure leave_iteration_statement(orig_ctrlexpr) end when ctrlexpr_val.test_may_be_true.true? begin enter_iteration_statement(orig_ctrlexpr) branch_opts = [ITERATION, NARROWING, FINAL, IMPLICIT_COND] branched_eval(ctrlexpr, *branch_opts) { interpret(node.statement) } ensure leave_iteration_statement(orig_ctrlexpr) end end ensure notify_while_stmt_ended(node) end
Private Instance Methods
deduct_ctrl_var_path_by_compound_assignment_expr(var, expr)
click to toggle source
# File lib/adlint/cc1/interp.rb, line 1432 def deduct_ctrl_var_path_by_compound_assignment_expr(var, expr) return nil unless expr.lhs_operand.identifier.value == var.name case expr.operator.type when "+=" :increase when "-=" :decrease else nil end end
deduct_ctrl_var_path_by_simple_assignment_expr(var, expr)
click to toggle source
# File lib/adlint/cc1/interp.rb, line 1401 def deduct_ctrl_var_path_by_simple_assignment_expr(var, expr) return nil unless expr.lhs_operand.identifier.value == var.name additive_exprs = collect_additive_expressions(expr.rhs_operand) histogram = additive_exprs.map { |additive_expr| if additive_expr.lhs_operand.kind_of?(ObjectSpecifier) lhs_name = additive_expr.lhs_operand.identifier.value end if additive_expr.rhs_operand.kind_of?(ObjectSpecifier) rhs_name = additive_expr.rhs_operand.identifier.value end next nil unless lhs_name == var.name || rhs_name == var.name case additive_expr.operator.type when "+" :increase when "-" :decrease else nil end }.compact.each_with_object(Hash.new(0)) { |dir, hash| hash[dir] += 1 } if histogram.empty? nil else histogram[:decrease] <= histogram[:increase] ? :increase : :decrease end end
deduct_variable_varying_path(var, iter_stmt)
click to toggle source
# File lib/adlint/cc1/interp.rb, line 1378 def deduct_variable_varying_path(var, iter_stmt) histogram = iter_stmt.varying_expressions.map { |expr| case expr when SimpleAssignmentExpression deduct_ctrl_var_path_by_simple_assignment_expr(var, expr) when CompoundAssignmentExpression deduct_ctrl_var_path_by_compound_assignment_expr(var, expr) when PrefixIncrementExpression, PostfixIncrementExpression expr.operand.identifier.value == var.name ? :increase : nil when PrefixDecrementExpression, PostfixDecrementExpression expr.operand.identifier.value == var.name ? :decrease : nil else nil end }.compact.each_with_object(Hash.new(0)) { |dir, hash| hash[dir] += 1 } if histogram.empty? nil else histogram[:decrease] <= histogram[:increase] ? :increase : :decrease end end
effective_ctrlexpr()
click to toggle source
# File lib/adlint/cc1/interp.rb, line 1445 def effective_ctrlexpr @effective_ctrlexpr_stack.last end
enter_iteration_statement(effective_ctrlexpr)
click to toggle source
# File lib/adlint/cc1/interp.rb, line 1449 def enter_iteration_statement(effective_ctrlexpr) @effective_ctrlexpr_stack.push(effective_ctrlexpr) end
interpret_for_body_statement(node, complete)
click to toggle source
# File lib/adlint/cc1/interp.rb, line 1295 def interpret_for_body_statement(node, complete) if complete branch_opts = [ITERATION, NARROWING, FINAL, IMPLICIT_COND, COMPLETE] else branch_opts = [ITERATION, NARROWING, FINAL, IMPLICIT_COND] end orig_ctrlexpr, ctrlexpr = node.deduct_controlling_expression enter_iteration_statement(orig_ctrlexpr) branched_eval(ctrlexpr, *branch_opts) do interpret(node.body_statement) interpret(node.expression) if node.expression if explicit_ctrlexpr = node.condition_statement.expression # NOTE: To avoid that value of the controlling variable is marked # as updated at end of the for-statement. Value of the # controlling variable is referred by the controlling # expression at the last iteration. # FIXME: This re-interpretation of the controlling expression may # cause duplicative warning messages. # FIXME: This re-interpretation of the controlling expression always # causes "logical-expression must be false" warnings about a # one-time-for-loop. To avoid this, now, workarounds are in # builtin code checks W0609 and W0610. var = object_to_variable(interpret(explicit_ctrlexpr), explicit_ctrlexpr) notify_variable_value_referred(explicit_ctrlexpr, var) notify_sequence_point_reached(SequencePoint.new(explicit_ctrlexpr)) end end ensure leave_iteration_statement(orig_ctrlexpr) end
interpret_for_ctrlexpr(node)
click to toggle source
# File lib/adlint/cc1/interp.rb, line 1276 def interpret_for_ctrlexpr(node) node.condition_statement.executed = true if ctrlexpr = node.condition_statement.expression ctrlexpr_obj = interpret(ctrlexpr, QUIET) ctrlexpr_var = object_to_variable(ctrlexpr_obj, ctrlexpr) ctrlexpr_val = value_of(ctrlexpr_var) ctrlexpr_obj = interpret_iteration_ctrlexpr(node, ctrlexpr) ctrlexpr_var = object_to_variable(ctrlexpr_obj, ctrlexpr) notify_variable_value_referred(ctrlexpr, ctrlexpr_var) notify_sequence_point_reached(SequencePoint.new(ctrlexpr)) else widen_varying_variable_value_domain(node) end ctrlexpr_val end
interpret_iteration_ctrlexpr(iter_stmt, ctrlexpr)
click to toggle source
# File lib/adlint/cc1/interp.rb, line 1351 def interpret_iteration_ctrlexpr(iter_stmt, ctrlexpr) environment.enter_branch(FINAL).execute(interpreter, nil) do widen_varying_variable_value_domain(iter_stmt) end interpret(ctrlexpr) ensure environment.leave_branch_group environment.leave_branch end
leave_iteration_statement(effective_ctrlexpr)
click to toggle source
# File lib/adlint/cc1/interp.rb, line 1453 def leave_iteration_statement(effective_ctrlexpr) @effective_ctrlexpr_stack.pop end
uninitialize_block_local_variables(generic_labeled_stmt)
click to toggle source
# File lib/adlint/cc1/interp.rb, line 1330 def uninitialize_block_local_variables(generic_labeled_stmt) related_goto_stmts = generic_labeled_stmt.referrers return if related_goto_stmts.empty? local_variables.each do |var| var_def = var.declarations_and_definitions.first anterior_goto_stmts = related_goto_stmts.select { |goto_stmt| goto_stmt.location.line_no < var_def.location.line_no } unless anterior_goto_stmts.empty? var.value.enter_versioning_group var.value.begin_versioning var.uninitialize! var.value.end_versioning var.value.leave_versioning_group(true) end end end
widen_varying_variable_value_domain(iter_stmt)
click to toggle source
# File lib/adlint/cc1/interp.rb, line 1361 def widen_varying_variable_value_domain(iter_stmt) iter_stmt.varying_variable_names.each do |name| if var = variable_named(name) widened_sval = var.type.arbitrary_value case deduct_variable_varying_path(var, iter_stmt) when :increase widened_sval.narrow_domain!(Operator::GE, var.value) when :decrease widened_sval.narrow_domain!(Operator::LE, var.value) end var.widen_value_domain!(Operator::EQ, widened_sval) end end end