Concrete and abstract syntax
2.6 Concrete and abstract syntax
The goal of this section is to introduce abstract syntax, and to show how to obtain an abstract syntax from a concrete syntax.
Recall the grammar SequenceOfS for producing sequences of s’s:
Beside : S → SS Single : S → s
As explained in Section 2.4.1, the following datatype can be used to represent parse trees of sentences of the language of S .
data S = Beside S S
| Single Char
For example, the sequence sss may be represented by the parse tree
Beside (Beside (Single ’s’) (Single ’s’)) (Single ’s’) The function s2string constructs the sentence that corresponds to a value of the
datatype S:
s2string
:: S -> String
s2string x = case x of
Beside l r -> s2string l ++ s2string r Single x
-> "s"
Since in each parse tree for a sentence of the language of S Single will always be fol- lowed by the character ’s’, we do not have to include the type Char in the datatype definition S. We refine the datatype for representing parse trees of SequenceOfS as follows:
2.6 Concrete and abstract syntax
data SA = BesideA SA SA
| SingleA Note that the type Char, representing the terminal symbol, has disappeared now.
The sequence sss is represented by the parse tree
BesideA (BesideA SingleA SingleA) SingleA
A concrete syntax of a language describes the appearance of the sentences of a
concrete
language. So the concrete syntax of the language of S is given by the grammar
syntax
SequenceOfS . An abstract syntax of a language describes the parse trees of a lan-
abstract
guage. Parse trees are therefore sometimes also called abstract syntax trees. The
syntax
datatype SA is an example of an abstract syntax for the language of SequenceOfS . The adjective abstract says that values of the abstract syntax do not need to have all information about particular sentences, as long as the information is recover- able. For example, function sa2string takes a value of the abstract syntax for SequenceOfS , and returns the sentence represented by the abstract syntax tree.
sa2string
:: SA -> String
sa2string x = case x of
BesideA l r -> sa2string l ++ sa2string r SingleA
-> "s"
Such a function is often called a semantic function. A semantic function is a func-
semantic
tion that is defined on an abstract syntax of a language. Semantic functions are
func-
used to give semantics (meaning) to values. Here, the meaning of a more abstract
tion
representation is expressed in terms of a concrete representation. Using the removing left recursion grammar transformation, the grammar SequenceOfS
can be transformed into the grammar with the following productions:
S → sZ | s Z → SZ | S
An abstract syntax of this grammar may be given by
data SA2 = ConsS Z | SingleS data Z
= ConsSA2 SA2 Z | SingleSA2 SA2
In fact, the only important information about sequences of s’s is how many occur- rences of s there are. So the ultimate abstract syntax for SequenceOfS is
data SA3 = Size Int The sequence sss is represented by the parse tree Size 3.
The SequenceOfS example shows that one may choose between many different ab- stract syntaxes for a given grammar. The application determines which abstract syntax is most convenient.
Exercise 2.20 . A datatype in Haskell describes an inductively defined set. The following
datatype represents a limited form of arithmetic expressions
data Expr = Add Expr Expr | Mul Expr Expr | Con Int Give a grammar that corresponds to this datatype.
Context-Free Grammars
Exercise 2.21 . Consider your answer to exercise 2.7, which describes the concrete syntax for
palindromes over {a, b}.
1 Define a datatype Pal that describes the abstract syntax corresponding to your
grammar. Give the two abstract palindromes aPal1 and aPal2 that corre- spond to the concrete palindromes cPal1 = "abaaba" and cPal2 = "baaab"
2 Write a (semantic) function that transforms an abstract representation of a
palindrome into a concrete one. Test your function with the abstract palin- dromes aPal1 and aPal2.
3 Write a function that counts the number of a’s occurring in a palindrome. Test
your function with the abstract palindromes aPal1 and aPal2.
Exercise 2.22 . Consider your answer to exercise 2.8, which describes the concrete syntax for
mirror-palindromes.
1 Define a datatype Mir that describes the abstract syntax corresponding to
your grammar. Give the two abstract mirror-palindromes aMir1 and aMir2 that correspond to the concrete mirror-palindromes cMir1 = "abaaba" and cMir2 = "abbbba"
2 Write a (semantic) function that transforms an abstract representation of a
mirror-palindrome into a concrete one. Test your function with the abstract mirror-palindromes aMir1 and aMir2.
3 Write a function that transforms an abstract representation of a mirror-palin-
drome into the corresponding abstract representation of a palindrome. Test your function with the abstract mirror-palindromes aMir1 and aMir2.
Exercise 2.23 . Consider your anwer to exercise 2.9, which describes the concrete syntax for
parity-sequences.
1 Describe the abstract syntax corresponding to your grammar. Give the two
abstract parity-sequences aEven1 and aEven2 that correspond to the concrete parity-sequences cEven1 = "00101" and cEven2 = "01010"
2 Write a (semantic) function that transforms an abstract representation of a
parity-sequence into a concrete one. Test your function with the abstract parity-sequences aEven1 and aEven2.
Exercise 2.24 . Consider your answer to exercise 2.18, which describes the concrete syntax for
bit-lists by means of a grammar that is not left recursive.
1 Define a datatype BitList that describes the abstract syntax corresponding to
your grammar. Give the two abstract bit-lists aBitList1 and aBitList2 that correspond to the concrete bit-lists cBitList1 = "0,1,0" and cBitList2 = "0,0,1".
2 Write a function that transforms an abstract representation of a bit-list into
a concrete one. Test your function with the abstract bit-lists aBitList1 and aBitList2.
3 Write a function that concatenates two abstract representations of a bit-lists
into a bit-list. Test your function with the abstract bit-lists aBitList1 and aBitList2.
2.7 Constructions on grammars