A program slice consists of the parts of a program that affect the values computed at some designated program point referred to as a slicing criterion[23]. Static slicing isolates parts of a program that potentially affect the values computed at slicing criterion over all possible inputs. Program slicing can be used for debugging, program optimization such as dead code elimination and parallelization of sequential programs.
We define a static slice using the denotational collecting semantics of our language.
Our semantics returns not only the resulting value of the expression but also a
collection which stores all the evaluated values for each subexpression during the
program execution. The semantics shown in Figure 2
is composed of the semantic functions
for expressions,
for function definitions and the pattern matching rules.
The subscription
is a set of labels, which represents the set of
subexpressions whose values are masked.
By replacing values evaluated from masked subexpressions with
,
we can isolate subexpressions which use values of masked subexpressions or variable patterns.
Sets and domains used in the semantics are shown in Figure 3.
means a flat cpo with
the least element
.
is a function domain which maps a label
to a set of values evaluated from the subexpression designated with the label.
is a domain for semantic values of functions. A function value maps a value to a
tuple of an output value and a collection.
Auxiliary functions used in the semantics are shown in Figure 4.
The
function returns
, if the input value has
as its part. This function is used in the
semantic rules for primitive operations and pattern matching of variable patterns.
In primitive operations, if any operand value has
as its part, the result becomes
. In pattern matching, if a value matched to a variable pattern has
as its part,
the variable is mapped to
in the resulting environment.
The
operator is used to sum collections. Resulting collection from the
operator returns the sum of the results of summed collections for a given label.
So, in the semantic rules the resulting collection maps a label to a set of
all the values which have been computed from the designated expression.
The
operator is used to sum environments. It overwrites the return values of the left environment
with the return values of the right environment.
The semantic functions shown in Figure 2 have following types :
Each rule of
is composed of two alternatives for each case.
With the second alternatives only, the semantic rules are the same as a usual denotational
semantics. Each rule evaluates the value of an expression under a given environment
and returns an evaluated value and a collection. The first alternatives are added to
express the effect of values from subexpressions whose labels are in
.
When the label of an evaluated expression is in
,
the resulting value is not used as an output value and
is returned instead.
So, expressions which use the value of masked expressions use
for their evaluation.
Because any evaluation which uses the value
always results in a value having
as its part, we can identify the effect of the masked
expressions on any expression.
Now we can formally define a static slice as follows.
Given some dynamic input value which does not have
as its part,
if some value evaluated from an expression
has
as its part,
it means that expression
uses some value evaluated from the masked
expression
. So
is included in the static slice for
.
Static slices are defined based on the behaviors of a program over all possible inputs. We can analyze static slice using abstract interpretation[4,15]. The method for static slicing is not presented in this paper.
Now we can formally define the usage relation using static slicing.
For two labels
and
,
uses
if and only if
.