Chapter 10 - University of Wisconsin
Download
Report
Transcript Chapter 10 - University of Wisconsin
Chapter 10:
Structured Analysis
Omar Meqdadi
SE 3860 Lecture 10
Department of Computer Science and Software Engineering
University of Wisconsin-Platteville
Topic Covered
Why Structured Analysis?
Data Dictionary
Structured Diagrams
Static Program Slicing
2
Reverse Engineering
Recall:
Forward
Engineering is the traditional process of moving
from high-level abstractions and logical, implementationindependent designs to the physical implementation of a
system.
Reverse Engineering is the process of analyzing a subject
system to
Identify the system's components and their interrelationships
and
Create representations of the system in another form or a
higher level of abstraction.
3
Structured Analysis
Structured analysis : static representations of the code
Part of the impact analysis of required change
Why
Help
maintainer gain initial understanding of a software
system
Determine which functions call which other functions and
what data are passed.
Keep track of data identifiers and how and where they are
used
4
Data Dictionary
Data dictionary is a repository of information about the
data in a system.
It is usually alphabetical
Easily
lookup information about the usage of the constants,
variables and structures.
Items may have a secondary key
Help
us look up an identifier in other ways other than name
Secondary key Example: function name, logical
relationships
Data Dictionary
A Data Diction may contains:
A
description of the data
A formal definition of the data, which may include:
Data type (and size for strings, arrays, structures, etc.)
Initial and/or default value
Range of values (valid values)
Logical relationships with other fields
Cross references to other functions, which use this data
Data Dictionary
Example:
Data id Description
Type
Initial
value
Range
Logical
Function
Cross Reference
relation-ships
score
A test score
float
N/a
(0,100)
N/a
processOneSection
Max( num1)
sum
Sum of scores
Float
0.0
GE 0.0
The more scores
and higher the
scores the larger
sum will be
main
processOneSection
processClassTotals
A data dictionary can be the start of a database schema.
7
Data Dictionary Generation
Automated tools that helps generating the data dictionary
from the source code
Static program
Slicing
Generate dictionary for every variable of the existing system
Many
CASE workbenches support data dictionaries.
Structure Diagrams
Graphical representation of existing system
Traceability Graph
Flow
Chart (Graph)
Show all branches
Show all execution paths
Linear code sequences
Structure Call
Graph
Program Dependency Graph
Traceability Graph (TG)
TG is a graphical representation of existing system
TG shows the relationships among work products (
requirements, design, code, and test cases)
TG is used to find the impact of a given maintenance
change
TG contains two edge types:
Horizontal: relationships between
different work products
Vertical: relationships between entities within the same
kind of work
TG Example:
Analysis of TG Example 1:
Impact Analysis : from slide 11 , if some changes are
made to the requirement object R4, the results of the
horizontal traceability and vertical traceability are
Analysis of TG
Changes in one part of the software system may have
direct impacts or indirect impacts on other parts.
Direct
impact: A direct impact relation exists between two
entities if they are connected by an edge in the TG
Indirect impact: If an entity A directly impacts another
entity B and B directly impacts a third entity C, then we
can say that A indirectly impacts C.
Analysis of TG
For a node A in a TG:
in-degree of
A (in(A)) : the number of edges for which A is
the destination node
Represents the number of nodes having a direct impact on A
Low in-degrees of nodes are an indication of a good design
out-degree of
A (out(A)): the number of edges for which A
is the source
Represents the number of nodes which are likely to be
modified because of A
To minimize the impact of a change, out-degrees of nodes
need to be made small
Analysis of TG Example2:
Consider the following figure
Each
SLO represents a
software artifact connected to
other artifacts.
Dependencies among SLOs
are represented by arrows.
The out-degree of SLO1 is 3
The in-degree of SLO1 is 4
SLO1 has an indirect impact
from SLO8 and a direct
impact from SLO9.
Flow Graph Example- Binary Search
int search ( int key, int [] elemArray)
{
int bottom = 0;
int top = elemArray.length - 1;
int mid;
int result = -1;
while ( bottom <= top )
{
mid = (top + bottom) / 2;
if (elemArray [mid] == key)
{
result = mid;
return result;
} // if part
else
{
if (elemArray [mid] < key)
bottom = mid + 1;
else
top = mid - 1;
}
} //while loop
return result;
} // search
1
bottom > top
Binary Search Flow Graph
while bottom < = top
2
3
if (elemArray [mid] == key
4
8
5
(if (elemArray [mid]< key
6
9
7
Flow Graph Terminologies
Dominators:
Given
a Flow Graph with nodes D and N:
D dominates N if every path from the initial node to N goes
through D
Properties of dominance:
Every node dominates itself
Initial node dominates all others
Flow Graph Terminologies
Dominators- Example:
Flow Graph Terminologies
Dominator Tree:
In
a dominator tree of a flow graph
The initial node N is the root of the Flow Graph
The parent of a node X is its immediate dominator (i.e., the
last dominator of X on any path)
The parent (immediate dominator) for X is unique
Flow Graph Terminologies
Dominator Tree - Example:
Flow Graph Application: Loops
Algorithm for finding loops from the Flow Graph:
Given
a Flow Graph:
Find back edges in the graph
Given a back edge N D , loop corresponding to this edge is:
{D} + {N} + { all nodes that can reach the N without going
f
through D }
Flow Graph Application: Loops
Example 1:
Flow Graph Application: Loops
Example 2: Finding Nested Loops
L2 B, S2
L1 A,S1,B,S2
L2 nested in L1
While A do
S1
While B do
S2
Endwhile
Endwhile
Flow Graph Terminologies
Post-Dominators :
Given
a Flow Graph with nodes PD and N:
PD post dominates N if every path from N to the final nodes
goes through PD
Flow Graph Terminologies
Post-Dominator - Example:
Flow Graph Terminologies
Post-Dominator Tree:
In
a post-dominator tree of a flow graph
The initial node N is the exit node of the Flow Graph
The parent of a node X is its immediate post dominator (i.e.,
the first post dominator of X on any path)
The parent (immediate post dominator) for X is unique
Flow Graph Terminologies
Post-Dominator Tree - Example:
Structure Call Graph
A call graph is a directed graph in which a node
represents a function, a component, or a method.
An edge between two nodes A and B means that A
invokes B
Each
edge is annotated with all parameters that are
exchanged between the calling and called function.
Use the parameter id of the called function
Structure Call Graph
Each edge has arrow indicating its parameter’s usage
(IN, OUT , INOUT).
An
edge with an arrow pointing into the called function
would be an IN parameter.
An edge with an arrow pointing into the calling function
would be an OUT parameter.
INOUT parameters would have arrows point into both the
calling and called functions.
Example:
Example: Structure Call Graph
//------- main () -----------------------------------------------int main()
{
float sum, sumAll = 0.0;
int sections = 1; // section number being processed
int count, countAll = 0; // count of students
//------------------------------------// PRIMING READ FOR eof LOOP
cin >> count; // how many scores in a section
while ( ! cin.eof() ) // loop till eof
{
//---------------------------------// PROCESS ONE SECTION OF GRADES
processOneSection( sum, sections, count );
//---------------------------------// ACCUMULATE CLASS SUM AND COUNT
processClassTotals( sumAll, countAll, sum, count );
cin >> count;
sections++;
} //------ END WHILE
displayClassResults( sections, countAll, sumAll );
cout << endl << "That's all the sections!! Normal Termination.";
return 0;
}
Example: Structure Call Graph
//-----------------------------------------------------------------// Function to process a section's worth of data
// PARAMS (
OUT, IN,
IN )
void processOneSection( float & sum, int sections, int count )
{
int a_count, b_count, c_count, d_count, f_count, loopEnd;
float score, hi_score, lo_score;
cout << "Scores for section " << sections << endl;
//--------------------------------------------// INTIALIZE SECTION ACCUMULATORS AND COUNTERS
initSection( a_count, b_count, c_count, d_count, f_count,
loopEnd, sum, hi_score, lo_score );
while ( loopEnd < count ) // loop to read section scores
{
cin >> score;
//-------------------------------// COUNT A's, B's, etc.
determineGrade( score, a_count, b_count, c_count, d_count, f_count );
//--------------------------------// FIND HIGHEST AND LOWEST SCORES
hi_score = max ( score, hi_score );
min ( lo_score, score );
//----------------------------------// SECTION SUM OF SCORES FOR AVERAGE
// to compute the average
sum += score;
loopEnd++; // COUNT CONTROL LOOP UPDATE
}//------ END WHILE -- SECTION END -------//--------------------------------// DISPLAY THIS SECTION'S RESULTS
displaySectionResults( a_count, b_count, c_count, d_count, f_count,
count, sum, hi_score, lo_score );
Example: Structure Call Graph
// function to return the larger of two numbers
// PARAMS (
IN,
IN )
float max( float num1, float num2 )
{
float max;
if ( num1 < num2 )
max = num2;
else
max = num1;
return max;
} //--------------END OF max( )--------------------------------------
Example: Structure Call Graph
main( )
sum
sections,
count
processOneSection( )
//reads and processed one
sections worth of grades.
max
num1 , num2
max()
How do changes propagate?
Assume the following change:
char G (void) {
int x;
char y;
….
if (x == 0)
y = true;
else
y = false;
return y;
}
35
char G (void) {
int x;
char y;
….
if (x != 0)
y = true;
else
y = false;
return y;
}
How do changes propagate?
Assume the following main:
void main (void) {
….
if ( G() == true)
}
36
Do1;
else
Do2;
….
Q: Do we modify
the main because of
the change in G?
Call Graph : Impact of Change
Programmers use call graphs to understand the
potential impacts that a software change may have.
Change impact assumption:
Some
change in method p has the potential to impact
changes in all nodes reachable from p in the call graph.
Change propagates between methods through
Parameters(call by reference )
Return values
Global variables
Call Graph Example
Impact of G:
Main,A,B,H
int G (void)
Impact of C:
E,F,D
G
v
main
r
int H (int x)
v
H
void C (void)
B
r
r
C
A
r: ref. edge
v: val. edge
(none):
call edge
38
v, r
void A (struct_type &x)
r
F
E
D
Program Dependency Graph(PDG)
In the PDG of a program:
(i) each simple statement is represented by a node, also called
a vertex;
(ii) each predicate expression is represented by a node.
Types of edges in a PDG:
Data
dependency (solid edge): from node A to node B
indicates that computations performed at node A are
directly dependent upon the results of computations
performed at node B .
Control dependency (dashed edge) : from node A to node B
indicates that node A may execute based on the result of
evaluation of a condition at B .
PDG Example
Program Slicing
Program Slice : a subset of a program that contains the
relevant code to the computation of interest
The
parts of a program which have a direct or indirect
effect on the computation of interest
Program slicing provides a useful way of filtering out
irrelevant code.
A slice S(V, N) produces the portions of the program that
contribute to the value of the variable V at statement N
(V,N
) is called a slicing criterion
Application:
Debugging
Testing
Program Slicing
Program Slicing types:
Static: does
not make assumptions regarding the input
Dynamic: assumes fixed input for a program (next chapter)
Backward: S(V,N): all statements and predicates in the
program that may affect the value of variable V at
statement N
Forward: S(V,N): all statements and predicates in the
program that may be affected by the value of variable V at
statement N
Static Backward Slicing
void main ( ) {
1. int I=0;
2. int sum=0;
3. while (I<N) {
4. sum=add(sum,I);
5. I=add(I,1);
6. }
7. cout << sum << endl;
8. cout << I << endl;
}
S(V,N) : Slice of
variable V at
statement ( node ) N
is the set of
statements involved
in computing V’s
value at N.
Example: S < I , 8 >
Static Backward Slicing Example:
int main() {
1. int max, min, avg;
2. int val, sum, num;
3.
4. cin >> val ;
5. max = val;
6. min = val;
7. sum = val;
8. num = 1;
9.
10. while(val >= 0)
11. {
12. if (max < val)
13.
max = val;
14. if (min > val)
15.
min = val;
16. sum += val;
17. Add (num);
18. cin >> val;
19. }
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
avg = sum / num;
cout << max << endl;
cout << min << endl;
cout << avg <<endl;
cout << sum << endl;
cout << num << endl;
return 0;
}
void Add (int & x){
++x;
}
Example : Slice S(avg, 24)
int main() {
1. int avg;
2. int val, sum, num;
4. cin >> val;
7. sum = val;
8. num = 1;
10. while(val >= 0)
11. {
16. sum += val;
17. Add (num);
18. cin >> val;
19. }
21. avg = sum / num;
24. cout << avg << endl;
28. }
29. void Add (int & x){
30. ++x;
31. }
Static Backward Slicing
Using PDG
A static program slice is identified from a PDG as follows:
for a variable V at node N, identify all reaching
definitions of V.
find all nodes in the PDG which are reachable from
those nodes.
The visited nodes in the traversal process constitute the
desired slice.
Consider the program in the slide 40 and variable Y at S10.
First, find all the reaching definitions of Y at node S10 – and the
answer is the set of nodes {S3, S6 and S8}.
Next, find the set of all nodes which are reachable from {S3, S6
and S8} – and the answer is the set {S1, S2, S3, S5, S6, S8}.
Static Forward Slicing
Example1: Find Static Forward Slicing: S ( sum , 3 )
1. cin >> n ;
2. i = 1;
3. sum = 0;
4. product = 1;
5. while (i <= n){
6. sum = sum + i;
7. product = product * i ;
8. i = i + 1;}
9. cout << sum ;
10. cout << product ;
Static Forward Slicing
Example1: S ( sum , 3 )
1. cin >> n ;
2. i = 1;
3. sum = 0;
4. product = 1;
5. while (i <= n){
6. sum = sum + i;
7. product = product * i ;
8. i = i + 1;}
9. cout << sum ;
10. cout << product ;
Static Forward Slicing
Example2: Static Forward Slicing: S ( n , 1 )
1. cin >> n ;
2. i = 1;
3. sum = 0;
4. product = 1;
5. while (i <= n){
6. sum = sum + i;
7. product = product * i ;
8. i = i + 1;}
9. cout << sum ;
10. cout << product ;
Static Slicing : Problem
Problems:
Static analysis
is very imprecise
Inefficient in identifying the errors and bugs.
Solution:
Dynamic
Slicing