The notes are rather sparse and only include definitions and the like (and maybe some worked, tedious exercises). They are a good summary for later reference but are by no means a substitute for the actual lectures and/or textbook.
Regular languages (handout and overhead presentation), or regular expressions and state transition diagrams put together, plus generat properties of regular languages. The relevant textbook material is you guessed it, Chapter 9.
As an example of using regular languages in practice the file scanner.l describes a complete lexical
analyzer (or scanner) for a Java-like programming language. This is the input of Flex which generates C
code that implements one big finite automaton (which in turn implements the actual lexical analysis).
You will notice that the regular expressions that define the lexical structure of a programming language
are not overly complicated, but on the other hand there are lots of them; the resulting finite automaton
(that is used for the actual lexical analysis) is therefore quite large (several tens of states).
Parsing (handout and overhead presentation). This section covers Chapter 11 from the textbook plus bottom-up parsing (the latter presented in too simplified a manner to be worth a reference). Here is a realistic sample grammar together with its transformation into a grammar suitable for recursive descent parsing (handout and overhead presentation).
As an example of practical application of context-free languages, the file parser.y describes a complete
parser for a Java-like language. This is the input of Yacc or its successor Bison which generate C/C++
code that implements the actual parsing.
Algorithm verification (handout and overhead presentation). This section covers Chapters 2 and 4 of the textbook.
Here are the proofs done in class.
Lecture 17 (11 March):
ASSERT(x==x0 && y==y0)
ASSERT(y==y0 && x==x0) // 5 - math
ASSERT(y==y0 && x-y+y==x0) // 4 - assign
x = x - y;
ASSERT(y==y0 && x+y==x0) // 3 - math
ASSERT(x+y-x==y0 && x+y==x0) // 2 - assign
y = x + y;
ASSERT(y-x==y0 && y==x0) // 1 - assign
x = y - x;
ASSERT(x==y0 && y==x0)
ASSERT(i >= 0 && y == power(x,i)) // 5 strengthen
ASSERT(i+1 >= 0 && y == power(x,i)) // 4 - math
FACT(power(x,i+1) == x * power(x,i))
ASSERT(i+1 >= 0 && y*x == x*power(x,i)) // 3 - math
ASSERT(i+1 >= 0 && y*x == power(x,i+1)) // 2 - assign
y = y * x;
ASSERT(i+1 >= 0 && y == power(x,i+1)) // 1 - assign
i++; // i = i+1;
ASSERT(i >= 0 && y == power(x,i))
ASSERT(true) // 13 - if, qed
if (x>y)
ASSERT(true && x > y) // 9 - strengthen
ASSERT(true && x >= y) // 8 - strengthen
ASSERT(x >= y) // 6 - math
ASSERT(x >= x && x >= y && (x == x || x == y)) // 5 - assign
m = x;
ASSERT(m >= x && m >= y && (m == x || m == y)) // 1 - if
else
ASSERT(true && ! x>y ) // 12 - math
ASSERT(true && ! y<x ) // 11 - math
ASSERT(true && ! !(y >= x)) // 10 - math
ASSERT(true && y >= x) // 7 - strengthen
ASSERT(y >= x) // 4 - math
ASSERT(y >= x && true && (y == x || true)) // 3 - math
ASSERT(y >= x && y >= y && (y == x || y == y)) // 2 - assign
m = y;
ASSERT(m >= x && m >= y && (m == x || m == y)) // 1 - if
ASSERT(m >= x && m >= y && (m == x || m == y))
ASSERT(true) // 14
ASSERT(x == x) // 13
m = x;
ASSERT(m == x) // 12
if (y > x)
ASSERT(m == x && y > x) // 11
ASSERT(y > x) // 5
ASSERT(y >= x && y > x) // 4
ASSERT(y >= x) // 3
ASSERT(y >= x && y >= y && (y == x || y == y)) // 2
m = y;
ASSERT(m >= x && m >= y && (m == x || m == y)) // 1
else // added to comply with the tableau for conditionals
ASSERT(m == x && ! (y > x)) // 10
ASSERT(m == x && x >= y && ! (y > x)) // 9
ASSERT(m == x && x >= x && x >= y && (x == x || x == y) && ! (y > x)) // 8
ASSERT(m == x && m >= x && m >= y && (m == x || m == y) && ! (y > x)) // 7
ASSERT(m >= x && m >= y && (m == x || m == y) && ! (y > x)) // 6
ASSERT(m >= x && m >= y && (m == x || m == y)) // 1
ASSERT(m >= x && m >= y && (m == x || m == y))
Lecture 18 (13 March):
ASSERT(n >= 0)
ASSERT(0 <= n)
ASSERT(1 == 1 && 0 <= n)
ASSERT(1 == 1 && 0 <= 0 <= n)
ASSERT(1 == power(x,0) && 0 <= 0 <= n)
i = 0;
ASSERT(1 == power(x,i) && 0 <= i <= n)
y = 1;
ASSERT(y == power(x,i) && 0 <= i <= n)
while (i != n) {
ASSERT(y == power(x,i) && 0 <= i <= n && i != n)
FACT(0 <= i+1 <= n && i != n <=> 0 <= i <= n && i != n)
ASSERT(y == power(x,i) && 0 <= i+1 <= n && i != n)
ASSERT(y == power(x,i) && 0 <= i+1 <= n)
ASSERT(y * x == power(x,i) * x && 0 <= i+1 <= n)
FACT(power(x,i+1) == power(x,i) * x)
ASSERT(y * x == power(x,i+1) && 0 <= i+1 <= n)
y = y * x;
ASSERT(y == power(x,i+1) && 0 <= i+1 <= n)
i++; // i = i + 1;
ASSERT(y == power(x,i) && 0 <= i <= n)
}
ASSERT(y == power(x,i) && i == n && 0 <= i <= n)
ASSERT(y == power(x,n) && i == n && 0 <= i <= n)
ASSERT(y == power(x,n))
Helpful for determining the variant: i==n <=> n-i == 0, which suggests the variant n-i. Also
recall that we started without the range for i, which was introduced in a second phase to support the
variant.
ASSERT(true)
ASSERT(1 == 1)
ASSERT(1 == power(x,0))
i = 0;
ASSERT(1 == power(x,i))
y = 1;
ASSERT(y == power(x,i))
while (i < n) {
ASSERT(y == power(x,i) && i < n)
FACT(i+1 <= n <=> i < n)
ASSERT(y == power(x,i) && i+1 <= n && i < n)
ASSERT(y == power(x,i) && i+1 <= n)
ASSERT(y*x == power(x,i) * x && i+1 <= n)
y = y * x;
ASSERT(y == power(x,i) * x && i+1 <= n)
ASSERT(y == power(x,i+1) && i+1 <= n)
i++; // i = i + 1;
ASSERT(y == power(x,i) && i <= n)
}
ASSERT(y == power(x,i) && i >= n && i <= n)
ASSERT(y == power(x,n) && i >= n && i <= n)
ASSERT(y == power(x,n) && i >= n)
ASSERT(y == power(x,n))
ASSERT(n >= 0 && n % 2 == 0)
i = 0;
y = 1;
while (i != n) {
y = y * x * x;
i = i + 2;
}
ASSERT(y == power(x,n))
To determine variant: i==n <=> n-i == 0
Variant: (n-i)/2
The complete proof was left as an exercise, but the key takeaway is that pre-condition has to be
strengthened to ensure total correctness. The property i==n <=> n-i == 0 is still useful for the
establishment of a variant; this time the variant is (n-i)/2.
Lectures are recorded as follows:
Note: Lecture 14 was the mid-term examination.