[dir] Zum Verzeichnisinhalt     [exercise] Zur Musterlösung     [download] (SHIFT + Linke Maustaste)
@=~
~p maximum_input_line_length = infinity

~A~<Loop Enumeration~>

The program analyzer shall derive information about for loops
in the program: The loops are counted from left to right
throughout the program. For each loop its number, its nesting
depth, and its line number is to be printed.

For example the following program 
~O~<loops.in~>~{~-
{
  int i, k, j, s;
  s = 0;
  for (i=1; i<10; i=i+1)
    for (j=i; j<10; j=j+1)
      s = s + j;
  for (k=0; k<5; k=k+2)
    s = s - k;
  print (s);
}
~}

shall produce output like

~O~<loops.out~>~{~-
for loop number 1 in line 4 has depth 1
for loop number 2 in line 5 has depth 2
for loop number 3 in line 7 has depth 1
~}

The following questions may help to focus your attention on the
significant aspects of this problem:

What is the computational pattern for left-to-right enumeration?
In which context and with which value do you start the enumeration?

What is the computational pattern for nesting depth?
How is the recursive nesting being founded?

~B~<Solution~>

A chain is used to propagate the loop numbers left-to-right
through the program. The chain is started in the root context
with the number of the first loop. Each for loop increments
the incoming chain value and passes it down (~{HEAD~}).

~$~<Loop enumeration~>~{
CHAIN LoopNo: int;

SYMBOL Prog COMPUTE
  CHAINSTART HEAD.LoopNo = 1;
END;

SYMBOL ForStmt COMPUTE
  HEAD.LoopNo = ADD (THIS.LoopNo, 1);
END;
~}

We use an ~{INCLUDING~} construct to access the nesting
depth of the next outer loop. The recursion is founded at
the root symbol.

~$~<Loop nesting depth~>~{
ATTR LoopDepth: int;

SYMBOL Prog COMPUTE
  SYNT.LoopDepth = 0;
END;

SYMBOL ForStmt COMPUTE
  SYNT.LoopDepth =
    ADD (1, INCLUDING (ForStmt.LoopDepth, Prog.LoopDepth));
END;
~}

In the ~{ForStmt~} context the incoming chain value
and the ~{LoopDepth~} attribute is printed:

~$~<Loop information~>~{
SYMBOL ForStmt COMPUTE
  printf ("for loop number %d in line %d has depth %d\n",
          THIS.LoopNo, LINE, THIS.LoopDepth);
END;
~}

~B~<Further Questions~>

Reconsider your solution when you have learned about
SYMBOL computations. Which of the computations can be
turned into SYMBOL computations? Explain why.

~B~<Output files~>

~O~<loops.lido~>~{
~<Loop enumeration~>
~<Loop nesting depth~>
~<Loop information~>
~}