Please send questions to
st10@humboldt.edu .
* Extended BNF (EBNF)
* reference: MacLennan, p. 153-154
(please use BNF for Homework 1....)
* for convenience, pretty much...
* * - Kleene star
+ - Kleene cross
<unsigned integer> ::= <digit>+
...
<identifier> ::= <letter><alphanumeric>*
* some version of EBNF let you use { } to
indicate a grouping that the * or + applies to;
<identifier> ::= <letter>{<letter>|<digit>|_}*
(you can also stack options within a big
{ } instead of using | for or, also)
* also common: to use [ ] to indicate something
that is optional
<integer> ::= [+ | -]<unsigned integer>
(and you can also stack options inside a big [ ]
too)
* definition: the language generation by a CFG
* assume that =*=> can be used to indicate
a sequence of derivations
* that is, if you had: u => u1 => u2 => v
you could write: u =*=> v
* then, you could say (Sipser, p. 94 and HU, p. 80)
The language of the grammar G, L(G), is:
{w | (w contains characters from its alphabet)
and (S =*=> w) }
* leftmost and rightmost derivations
* for a given derivation tree, there may
be more than one derivation...
(drew derivations + derivation tree for
<expr> + <expr> on the board)
* so -- a string having two different
derivations doesn't tell you much;
BUT -- if a string has two different
derivation TREES -- then its grammar
is said to be AMBIGUOUS
(there's at least one string which
might essentially have two different
meaning/semantics)
* ambiguity isn't ideal for a programming
language -- we need a given statement
to have a consistent meaning/semantics;
(sometimes handled with additional
assumptions...)
* a leftmost derivation:
you ALWAYS substitute for the leftmost non-terminal
in each step;
* a rightmost derivation:
you ALWAYS substitute for the rightmost non-terminal
in each step;
...it turns out that if a grammar has a string
with two different LEFTMOST derivations,
it can be proven to be ambiguous;
...it turns out that if a grammar has a string
with two different RIGHTMOST derivations,
it can be proven to be ambiguous;
...so that's 3 ways to prove a grammar ambiguous
* abstract syntax tree
(Louden, p. 89)
...if you condense this down, sort of replacing
each non-terminal with its terminal leaf,
you get a different tree, an abstract syntax
tree;
(there are only terminals in a abstract
syntax tree)
* it turns out it is reasonable to go from
a statement to an abstract syntax tree
version of that statement;
(as opposed as from a grammar to a derivation
of a statement using that grammar);
...it is not uncommon for a compiler
to turn a statement into abstract
syntax tree form, and then evaluate that;
* it is pretty reasonable to use a parenthesized
notation to represent such abstract syntax
trees...
(for the two trees on the board...)
(+ (* <id> <id>) <id>)
(* <id> (+ <id> <id>))
(yes, this IS Lisp's/Scheme's syntax...!)
and that segues us to Functional Programming/Lisp/Scheme
* now, LISP and Scheme are multi-model -- they
can be used for functional and non-functional
programming;
(they are not "pure" functional languages)
...but they can be used in a quite functional
manner;
* a little LISP history (some of this is in MacLennan,
but I also used Webber, pp. 535-538)