Professional Documents
Culture Documents
Reengineering Software
R.G. Dromey
Low-level
re-engineering
at the code level,
-- loops,
-- branches,
-----------
sequences.
QUESTION
Why re-engineer
software
while ((Op= getopt(arge, argv, Vop)) != ERROR) {
if ((char) Op == Opq) {
QFlag = TRUE;
if (LFlag) {
Error = TRUE;
break; }
if (SFlag) {
Error = TRUE;
break; }
}
else { if ((char) Op == Opl) {
LFlag = TRUE;
if (QFlag) {
Error = TRUE;
break; }
LevelStr = optarg;
}
else {if ((char) Op == Ops) {
SFlag = TRUE;
Subsystem = optarg;
if (QFlag) {
Error = TRUE;
break; }
}
else { Error = TRUE;
break; }
}
}
}
Justification for Re-engineering
• Branched structures either in loops or elsewhere
are a major cause of quality defects in software.
Problems with branched structures include:
– some branches are unreachable
– logic in branched structures may be incorrect
– branched structures in loops can cause termination
problems
– complex branched structures are hard to understand
and modify
Branch Statement Rules
Absorption Into Branch Structure
Promotes statement into branch.
Before
x:=E; if C →S1 [] ¬C → S2 fi
After Transformation
Before
x:=a+b; if x < N → S1 [] x ≥ N → S2 fi
After Transformation
Before
write(E); if C → S1 [] ¬C → S2 fi
After Transformation
if C → write(E); S1 [] ¬C → write(E); S2 fi
Before
if C → S1 [] ¬C → S2 fi; S
After Transformation
if C → S1; S [] ¬C → S2; S fi
The use of multiple exits and flags exacerbates the
difficulties of dealing with loops.
Such features significantly detract from the
structural integrity, simplicity, reliability and the
ultimate quality of programs.
Equivalence Transformations
It is possible to make a number of transformations
on loops that allow us to remove unnecessary
structure involving multiple exits while preserving
correctness with respect to the original program.
Before
do G → if Ce → Se [] C¬e → S¬e fi od
After Transformation
while ((Op= getopt(arge, argv, Vop)) !=
ERROR) {
if ((char) Op == Opq) {
if (LFlag) {
QFlag = TRUE; Error = TRUE;
break; }
if (SFlag) {
QFlag = TRUE; Error = TRUE;
break; }
}
Need to Account for Negated Case
Original
while((Op= getopt(arge, argv, Vop)) != ERROR) {
if ((char) Op == Opq) {
if (LFlag) {
QFlag = TRUE; Error = TRUE;
break; }
if (SFlag) {
QFlag = TRUE; Error = TRUE;
break; }
}
We need to properly account for the case where both
guards are false.
Assignment Absorption Into Branch
After
while ((Op= getopt(arge, argv, Vop)) != ERROR) {
if ((char) Op == Opq) {
if (LFlag) {
QFlag = TRUE; Error = TRUE;
break; }
if (SFlag) {
QFlag = TRUE; Error = TRUE;
break; }
if (¬LFlag ∧ ¬SFlag){
QFlag = TRUE;}
}
Get Resolved Guards For Branches
Get Resolved Guards For Branches
One Iteration Next Iteration (if loop guard holds)
Branch Successor Graph
B4 B6
B2 B3
B7
B1 B8
B5 Exiting nodes (leaf
nodes)
Nonexiting nodes
Reachability = 13
64
Ideally branchsuccessorgraphs should be strongly connected
i.e. each branch connected to every other branch
Loop Normalization
In graph theoretic terms loop rationalization involves removing
all the leaf nodes from the branchsuccessor graph.
B3
B4(Exit) B6 B3
(Exit)
B2
(Exit) Loop B7
Rationalization
B7 B8
B1
(Exit) B5 (Exit) B5
Re-engineered Loop Structure