Professional Documents
Culture Documents
Supporting The Attribute Grammar Programming Paradigm in A Lazy Functional Programming Language
Supporting The Attribute Grammar Programming Paradigm in A Lazy Functional Programming Language
Introduction
Over the last several years researchers at the University of Windsor have been involved in various projects involving the investigation of new theories and techniques
in the areas of database management, VLSI design and natural language processing.
These investigations have all required the construction of special purpose language
processers. The design and construction of these processors required a good deal of
effort. It became evident that substantial resources were being used for this purpose
and that this was having a deleterious effect on our research. We decided, therefore,
to construct a programming environment that would enable researchers to produce
language processors with minimum effort. The environment that we have built is
called the Windsor Attribute Grammar Programming Environment W / A G E . This
environment allows language processors to be constructed as executable specifications of the syntax and semantics of the languages required.
W / A G E was initially used in the construction of natural language interpreters,
database front-ends, and specification transformers. Subsequently, it was recognised
that other types of program could be profitably constructed as language processors
and W / A G E has since been used to build theorem provers, tree procesors and even
file processors.
The purpose of this paper is twofold: firstly to introduce readers to W / A G E
and secondly to illustrate the wide applicability of the technique of constructing
programs as executable attribute grammars.
2
Attribute
Grammars
279
3.1
Notation
[char]
[char]
[char]
[char]
I REIL_TEIL~
[char]
I SPECIAL_SYMBOL_TEI~I [char]
I UNCATEGORISED_TERM [char]
In addition to defining the type terminal this introduces seven new identifiers:
INT_TERM, REAL_TERM, etc. as constructors for terminals. Note that each of these
T h e T y p e o f t h e L e x i c a l S c a n n i n g F u n c t i o n tokenise
t o k e n i s e :: s t r i n g _ t o _ b e _ p r o c e s s e d -> [ t e r m i n a l ]
where
string_to_be_processed == [char]
3.4
The t y p e a t t r i b u t e
example:
attribute
: := LITERAL_VALt e r m i n a l
I VAL n t m
[ OP n u l l - > n u , . - > num [ P A I R num [char]
Note t h a t constructors can have any number of fields. For example, the constructor
PAIR has two fields. A field m a y be any M i r a n d a t y p e as defined in 3.1. To analyse
an a t t r i b u t e , we use M i r a n d a p a t t e r n matching as illustrated later.
280
With a little change in perspective, many other types of program can be constructed as executable attribute grammars. We refer to such programs as passages.
This style of programming was first suggested by Knuth in 1971112], and subsequently developed by Katayama[9], ttehner and Silverberg[7], Simon[16], Johnsson[8], Panayiotopoulos, Papakonstantinou, and Stamatopoulos[14], Forbig and Lammel[3], Frost[4][5] and others. Several environments have been built to support the attribute grammar programming paradigm, eg. PLASTIC [16], SAGE[15], AGILP[14],
FLR[3], and W / A G E .
W / A G E consists of a several functions that extend the standard environment
of the pure lazy programming language Miranda[17]. The resulting combination of
programming paradigms facilitates software development in several ways:
1. Programs are completely declarative, extremely modular, and are largely variable free. This simplifies reasoning about them for the purpose of verification,
complexity analysis, transformation, etc.
2. The inductive program structure that results from the combined paradigm lends
itself well to the technique of deriving 'programs from proofs'.
3. The structure of a program that is built in this way is closely related to the
structure of the data that it is to process. This results in code that is easier to
maintain and easier to modify.
This paper will introduce readers to the attribute grammar programming paradigm, show how this paradigm can be readily supported in a pure functional programming language, and briefly discuss some of the advantages that derive from this
approach.
An Overview of W / A G E
tokenize
{apply..recogniser,
tmint erpreted}
{$orelse, $excl_orelse~
structure}
meaning-of
281
3.5
== [ ( [ a t t r i b u t e ] ,
[terminal])]
->
[([attribute],
[terminal])]
3.6
T h e T y p e o f F u n c t i o n s for Top-level A p p l i c a t i o n o f I n t e r p r e t e r s
apply_interpreter
: : i n t e r p r e t e r -> s t r i n g _ t o _ b e _ i n t e r p r e t e d
-> [ a t t r i b u t e ]
where s t r i n g _ t o _ b e _ i n t e r p r e t e d
=ffi [ c h a r ]
Throughout the paper, we use the notation x => y to indicate that output y is
returned by the Miranda interpreter when x is evaluated. For example:
apply_interpreter number "12"
3.7
T h e T y p e o f F u n c t i o n s for B u i l d i n g Basic I n t e r p r e t e r s
There are three functions in W / A G E that may be used to build interpreters for
single terminals:
literal
uninterpreted
interpreted
:: terminal_constructor
-> interpreter
:: terminal
-> interpreter
:: (terminal, [attribute]) -> interpreter
282
3.8
There are three functions in W / A G E that may be used to define new interpreters
in terms of other interpreters:
$orelse
:: interpreter -> interpreter -> interpreter
Sexcl_orelse :: interpreter -> interpreter -> interpreter
structure
:: list.of_tagged_interpreters -> list_of_attribute_rules
-> interpreter
where
list_of_tagged_interpreters == [(tag, interpreter)]
list_of_attribute_rules
ffi [(rule_hum, att_id, art_function, [att_id])]
where
att_id -= ((tag, art_direction), att_type)
art_function == [attribute] -> attribute
art_type
ffi [char]
att_direction : : = U P ] DOWN
3.9
[attribute]
In the next few sections, we give examples of various passages that have been built
using W / A G E . All of the passages are complete and can be executed as Miranda
programs just as they appear provided that the W / A G E script is available in the
Miranda 'local' directory.
Lexical
Analysis
attribute
: : type
I. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
reserved_words
,)J, , - , ,
~/,, ,+,, , - , ]
.......................................................................
I EXAMPLE APPLICATION
tokenise "123 begin sas ddd a234 b3.2 3.4 (ff~"
=>
283
Constructing
Basic
Recognisers
and
Interpreters
Passage #2 illustrateshow the W / A G E functions literal, interpreted, and uninterpreted can be used to build basic recognisers and interpreters, ie. recognisers
and interpreters for single terminals.
l[ Passage #2:
Zinsert <Iocal/header_for_WAGE_VERSION_I_RELEASE_0.m>
I I......................................................................
attribute
I VAL
num
[ GENDER char
I I......................................................................
reserved_words
= ["begin", "one"]
special_symbols = [3
I I......................................................................
int
anything
key
begin
one
salaire
=
=
=
=
=
literal
literal
uninterpreted
uninterpreted
interpreted
= interpreted
INT_TERM
ANY_TERM
(IDENTIFIER_TERMany)
(RESERVED_WORD_TERM"begin")
(RESERVED_WORD_TERM"one", [VAL 11)
(IDENTIFIER_TERM"salaire",[ENGLISH "wage",
GENDER 'm'])
EXAMPLE APPLICATIONS
apply_recognizer
apply_interpreter
apply_interpreter
apply_interpreter
apply_interpreter
apply_interpreter
apply_interpreter
~[ apply_interpreter
int
"64"
int
"106"
anything
"3.21"
key
"sas"
begin
"begin"
begin
"sas"
one
"one"
salaire "salaire"
=>
=>
=>
=>
=>
=>
=>
=>
284
Constructing
Non-Basic
Recognizers
Passage # 3 illustrates how non-basic recognizers can be built by 'gluing' other recognisers together using the combinators $ o r e a s e and $ u t r u c t u r e .
attribute
::= LITERAL_VALterminal
[ .......................................................................
reserved_words = []
special_symbols = [~(', ~)~, '*', '/', '+', '-']
J] . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
op
negate
opbr
clbr
uninterpreted_number
= uninterpreted
$orelse
uninterpreted
$orelse
uninterpreted
(SPECIAL_SYMBOL_TERM "+")
=uninterpreted
= uninterpreted
= uninterpreted
= uninterpreted
$orelse
(SPECIAL_SYMBOL_TERM"-")
(SPECIAL_SYMBOL_TERM"(")
(SPECIAL_SYMBOL_TERM")")
(INT_TERM any)
uninterpreted
(SPECIAL_SYMBOL_TERM "*")
(SPECIAL_SYMBOL_TERM "1" )
(REAL_TERM any)
J .......................................................................
Notice that the lists of attribute rules in the definition of rec_expr are empty.
This is because rec_expr is a recognizer and not an interpreter, therefore no attributes are to be computed.
285
] .......................................................................
reserved_.ords = []
special_symbols = ['(', ')', '*', '/', '+', '-']
[ .......................................................................
op
= interpreted
$orelse
interpreted
$orelse
interpreted
negop = u n i n t e r p r e t e d
opbr = u n i n t e r p r e t e d
clbr = uninterpreted
(SPECIAL_SYMBOL_TERM"+",[OP (+)])
(SPECIAL_SYMBOL_TERM"*", [OP ( * ) ] )
(SPECIAL_SYMBOL_TERM"/", [0P ( / ) ] )
(SPECIAL_SYMBOL_TERM"-")
(SPECIAL_SYMBOL_TERM"(")
(SPECIAL_SYMBOL_TERM")")
I I. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
expr = s t r u c t u r e
[c_rule 1
$orelse
structure
[a_rule 2
$orelse
structure
[a_rule 3
apply_op
negate
( s l number)
(VAL $u l h s ) EQ
(VAL $u s l ) ]
= VAL (y x z)
= VAL (-x)
{{ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
II EXAMPLEAPPLICATIONS
II
11 a p p l y _ i n t e r p r e t e r expr "(12 + 4 . 5 ) "
[[ a p p l y _ i n t e r p r e t e r expr " ( ( 4 + (4 * 3 ) ) / - 2 ) "
286
v $u s
v Sd e
c_rule
a.xule
i_rule
Examples of Passages
8.1
A Simple
Data
Processing
Example
P a s s a g e # 5 c a l c u l a t e s t h e a v e r a g e n u m b e r o f e n t r i e s p e r r e c o r d in a file i n w h i c h
e a c h r e c o r d c o n s i s t s o f a n i n t e g e r key followed b y o n e o r m o r e a l p h a n u m e r i c s t r i n g
e n t r i e s . R e c o r d s are s e p a r a t e d b y s e m i c o l o n s , fields b y c o m m a s , a n d end-of-file is
signified b y a p e r i o d .
reserved_words ffi []
special_symbols = ['.', *;', ',']
J j .......................................................................
key
entry
period
semicolon
comma
=
=
=
=
=
uninterpreted
uninterpreted
uninterpreted
uninterpreted
uninterpreted
(INT_TERH any)
(IDENTIFIER_TERM any)
(SPECIAL_SYMBOL_TERM ".")
(SPECIAL_SYMBDL_TERM ";")
(SPECIAL_SYMBOL_TERM ",")
j.......................................................................
file
= structure
[c_rule 1
c_rule 2
a_rule 3
(sl records ++ s2
(NUH_ENTS $u lhs)
(NUH_EECS $u lhs)
(AV_ENTS Su lhs)
period)
EQ (NUH_ENTS $u sl),
EQ (~GH_RECS Su sl),
EQ
calc_average[NUM_ENTS $u lhs,
NUH_RECS $u lhs]]
r e c o r d s ffi s t r u c t u r e ( s l r e c o r d ++ s2 s e m i c o l o n ++ s3 r e c o r d s )
[ a _ r u l e .4 (NUM_RECS Su l h s ) EQ add_one_to_num_recs[~FOM_RECS $u s 3 ] ,
a _ r u l e 5 (NUM_ENTS $u l h s ) EQ
add_num_ents [ ~ _ E N T S $u s l ,
~t~_ENTS $u s 3 ] ]
$excl_orelse
s t r u c t u r e ( s l record)
[i_rule 6 (NUM_RECS Su lhs) EQ (NUM_RECS I),
c_rule 7 ( ~ _ E N T S $u lhs) EQ (NUM_ENTS $u sl)]
287
record
[~_ENTS
[NUM_RECS
[NUM_ENTS
[NUM_ENTS
x, ~ _ R E C S
y] =
x]
=
x, NUH_ENTS y] x]
-
AV_ENTS (x/y)
NUM_RECS (I + x)
NUM_ENTS (x + y)
NUN_ENTS (1 + x)
~I . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
]l EXAMPLE APPLICATION
]l apply_interpreter file "1234,hesselink,hensenjones;2345,
I~
bauer,partsch,sharir,morgan;5678,heath,lin."
I]
=> [NUM_ENTS 9,NUH_EECS 3,AV_ENTS 3.0]
8.2
attribute
tl . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
reserved_words = []
special_symbols = []
II .......................................................................
elem
= literal ANY_TERM
]] EXAMPLE APPLICATION
]] apply_interpreter list "5 six 7 8"
=> IRES lINT_TERM "8",INT_TERM"7",IDENTIFIER_TERM,.six.,
l]
II
INT_TERM "5"]]
288
8.3
Passage ~ 7 recognizes numbers and returns their Fibonacci values. It would appear
that the attribute grammar paradigm is not appropriate for this problem. However, an alternative passage for calculating fibonacci numbers in linear time can be
obtained by transforming this passage as discussed in Frost[5].
[1 Passage #7: Calculating Fibonacci numbers
~insert <local/header_for_WAGE_VERSION_l_KELEASE_O.m>
~insert <iocal/number_interpreter_for_WAGE_VERSION_l_RELEASE_O.m>
11 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
attribute
~ ......................................................................
reserved_words = []
special_symbols ffi []
II . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
x] = FIB (fib x)
where
fib n ffi i
, n <ffi 2
fib n = fib (n - I) + fib (n - 2), otherwise
~ ......................................................................
I[ EXAMPLE APPLICATION
[[
apply_interpreter fibnumb "5" => [FIB 5]
meaning_of
The function m e a n i n g _ o f
allows lists of attributes to be defined in terms of the
application of an interpreter to an expression. The following passage illustrates such
use.
Notice that in this passage, the proper noun "john" does not denote an entity.
Rather, it denotes a function defined in terms of the entity denoted by the number
1. This idea is loosely based on a notion from Richard Montague's approach to the
interpretation of natural language.
][ Passage #8:
~insert
<Iocal/header_for_WAGE_VERSION_I_RELEASE_O.m>
II . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
attribute
entity == num
~ ........................................................................
reserved_words
special_symbols
II . . . . . . . . . .
cnoun
= []
= []
- .............................................................
ffi interpreted
(IDENTIFIER_TERM"person",[CNDUNVAL
[I..I0]])
$orelse interpreted (IDENTIFIER_TERM"woman",
[CNOUNVAL [6..10]])
intrvb = interpreted
(IDENTIFIER_TERM"runs",
[INTRVBVAL [2..7]])
289
det
ffi interpreted
$orelse interpreted
= interpreted
$orelse interpreted
pnoun
(IDENTIFIER_TERM"every", [DETVAL
f_every])
(IDENTIFIER_TERM"a",
[DETVAL
f_a])
(IDENTIFIER_TERM "john", [T_PHRASEVAL f_john])
(IDENTIFIER_TERM"someone",
meaning_of detphrase "a person")
[[ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
-- . . . . . . . . . . . . . . .
sent
EQ
apply2[
$u sl,
$u s2]]
Su sl)]
$u 81)]
DETVAL $u sl,
CNOUNVAL Su s2]]
applyl
apply2
f_every x
f_a
x
f_john
y
y
ffi (x --- y) = []
= (intersect x y) -= []
where intersect x y = (x --- (x --- y))
ffi member x
[ ........................................................................
11 EXAMPLE APPLICATIONS
II
I I apply_interpreter sent "every woman runs" => [ANS False]
I I apply_interpreter sent "someone runs"
=> [ANS True]
10
Left Recursion
Interpreting
Ambiguous
Input
290
Each of these four results is related to a parse of the input as a list. The first result
corresponds to a parse of the whole of the input as a list. The last result corresponds
to a parse of the input as a singleton list followed by three uninterpreted terminals.
The ability to handle ambiguous input is useful in many applications including natural language processing. However, it is also a fundamental property of the
W / A G E system. All interpreters are implemented as top down, fully backtracking,
syntax directed, lazy evaluators. There is one major advantage of this: passages
are modular. A different, but somewhat related, approach to lazy recursive descent
parsing for modular language implementation is described in Koskimies[13]. Many
of the arguments given there apply to the parsing strategy that we have adopted in
W/AGE.
12
An Example
of a Complex
Passage
Passage # 9 converts expressions of propositional logic to clausal form. If the expression is valid, the interpreter wff returns the empty clause set, and may therefore be
regarded as a decision procedure for propositional logic.
I ~ Passage #9:
~insert <local/header_f or_WAGE_VERSION_I_RW-~ASE_O 9m>
11 .......................................................................
attribute ::= LITERAL_VAL terminal J CCFSET [disjclause]
disjclause ::= DISJCL [[char]]
J CONTEXT [char]
jj .......................................................................
[ I opbr,
orr
aand
implies
var
J j. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
wff
-- structure
(sl expr
++
[c_rule I (CCFSET $u lhs)
i_rule 2 (CONTEXT $ d sl)
--. . . . . . . .
s2 period)
EQ
(CCFSET $u sl),
EQ
(CONTEXT "pos") ]
291
expr
EQ
make_ccfset
[LITERAL_VAL $u sl,
CONTEXT Sd lhs]]
$orelse
structure (sl opbr ++ s2 (conjunction $orelse disjunction
$orelse implication) ++ s3 clbr)
[c_rule 4
(CCFSET Su lhs) EO
(CCFSET Su s2),
c_rule 5
(CONTEXT Sd s2) EQ
(CONTEXT Sd lhs)]
$orelse structure
(sl negate
++
s2 expr)
[c_rule 6
(CCFSET Su lhs) EQ
(CCFSET Su s2),
a_rule ?
(CONTEXT $d s2) EQ opposite [CONTEXT $d lhs]]
conjunction =
++
s3 conjunction)
structure (sl expr
++
s2 aand
[a_rule 8 (CCFSET $u lhs) EQ context_and
[CONTEXT Sd lhs,
CCFSET $u sl,
CCFSET $u s3],
c_rule 9 (CONTEXT Sd sl) EQ
(CONTEXT Sd lhs),
c_rule I0 (CONTEXT Sd s3) EQ
(CONTEXT Sd lhs)]
$orelse structure
(sl expr)
[c_rule ii (CCFSET $u lhs) EQ
(CCFSET Su sl),
c_rule 12 (CONTEXT Sd sl) EQ
(CONTEXT Sd lhs)]
disjunction =
++
s2 orr
++
s3 disjunction)
$u lhs) EQ context_or
[CONTEXT $d lhs,
CCFSET Su sl,
CCFSET Su s3],
c_rule 14 (CONTEXT $d sl) EO
(CONTEXT Sd lhs),
c_rule 15 (CONTEXT $d s3) EQ
(CONTEXT Sd l h s ) ]
$orelse structure
(sl expr)
[c_rule 16 (CCFSET Su lhs) EQ
(CCFSET $u sl),
c_rule 17 (CONTEXT Sd sl) EQ
(CONTEXT Sd lhs)]
The function sort is required in the definition of unite_clauses in order that mkset
performs ~ required.
implication =
++
s2 implies
++
s3
Su lhs) EQ
context_or
[CONTEXT
CCFSET
CCFSET
a_rule 19 (CONTEXT $d sl) EQ
opposite
[CONTEXT
c_rule 20 (CONTEXT Sd s3) EQ
(CONTEXT Sd
I j .......................................................................
expr)
$d lhs,
Su sl,
$u s3],
Sd lhs],
lhs)]
292
=
=
ccf_and
ccf_or
x
x
y
y
context_or
context_or
[CONTEXT "pos", x, y]
[CONTEXT "neg", x, y]
=
=
ccf_or
ccf_and
x
x
y
y
opposite
opposite
[CONTEXT "pos"]
[CONTEXT "neg"]
=
=
CONTEXT "neg"
CONTEXT "pos"
[[ The function ccf_or forms the clausal disjunction of two clause sets
][ tautologous clauses are removed when produced, mkset makes a set
][ from a list
negate_lit (~-~ : x) = x
negate_lit
y
= (~-~ : y)
unite_clauses cl c2 = (sort . mkset) (cl ++ c2)
~ .......................................................................
[[ EXAMPLE APPLICATIONS
II
293
13
13.1
Concluding
Comments
Experimentation with W / A G E
During the last twelve months, W / A G E has been used extensively in a number of application areas. In particular, it has been used in the construction of a sophisticated
experimental natural language interface to a database, in the transformation component of a VLSI designer's assistant, and as a teaching aid in a third year 'Grammars
and Translators' course. The natural language interface that was constructed using
W / A G E can handle both syntactic and semantic ambiguity and provides 'dialogue'
answers to user's questions. The interpreter was built as part of an investigation into
the feasibility of extending Montague's compositional semantics to accommodate
semantic ambiguity. The VLSI project involved the construction of (i) programs to
translate mathematical specifications of finite impulse response filters to executable
specifications of systolic circuits based on a standard VLSI cell, and (ii) programs
to translate the executable specifications to EDIF netlist representations suitable
for input to a VLSI layout package. The viability of the approach was confirmed
by testing the translators on a real FIR filter design comprising 3 moduli and 64
coefficients. A detailed description of this work is given in Master's theses available
from the University of Windsor. W / A G E has also been used in the construction of
various other programs in a separate study into the use of the attribute grammar
paradigm in constructive (transformational) programming/4/.
13.2
Findings
We have found that the integration of the lazy functional programming and attribute
grammar paradigms is straightforward. Construction of a programming environment
to support this combined paradigm was helped significantly by the declarative nature
of the host language Miranda. Some of the more difficult aspects of the W / A G E
were constructed using the method of 'programs from proofs' in which induction
is used 'in reverse' to design a complex recursive function definition. We chose to
implement the syntax analyzers as top-down fully backtracking parsers. It has been
argued elsewhere/13/ that such parsers are more modular than those built using
other strategies. The lazy evaluation order allows attribute evaluation to be closely
related to syntax analysis carried out by top-down fully backtracking parsers without
incurring the redundant computation that would occur if a strict evaluation order
were used.
Our experimentation with W / A G E has convinced us that application of the new
combined programming paradigm results in extremely clear and modular executable
specifications of language interpreters. However, the actual construction of the interpreters was hindered by the poor debugging facilities of both W / A G E and Miranda.
In particular, the absence of trace facilities in W / A G E was a very noticeable shortcoming. Adding a trace facility to W / A G E is not a simple task. The fact that pure
functional programming languages do not allow any kind of side effects requires one
to adopt a completely different approach to the provision of de-bugging facilities.
We hope to overcome this problem in the next few months.
294
ca.
References
1. B. Edupuganty and B. R. Bryant, Two-level grammar as a functional programming
language. The Computer Journal, 32 (1), 36 - 44 (1989).
2. M. S. Feather, A survey and Classification of some program transformation approaches
and techniques. In L. G. L. T. Meertens (Editor) Program Specification and Transformation. IFIP 1987. Elsevier Science Publishers B. V. North-Holland.
3. P. Forbig, and U. Lammel, Knowledge based program generation using attribute grammars, in: Grabowski, J (ed), Proc. of the Berliner Informatik Tage bit '89. Akademie d.
Wissenschaften der DDR, fir-Report, 114-123, (1989).
4. R. A. Frost, Constructing Programs in a Calculus of Interpreters, Proceedings of the 1990
ACM International Workshop on Formal Methods in Software Development, (1990).
5. R. A. Frost, Constructing programs as executable attribute grammars, The Computer
Journal (to appear in the August 1992 issue).
6. R. A Frost, Guarded Attribute Grammars: Top Down Parsing and Left Recursive Productions, ACM SIGPLAN 27(6), 72-76, (1992).
7. E. C. R. Hehner and B. A. Silverberg, Programming with grammars: an exercise in
methodology-directed language design. The Computer Journal 26 (3), 227 - 281 (1983).
8. T. Johnsson, Attribute grammars as a functional programming paradigm. Springer Lecture Notes 274, 155 - 173 (1987).
9. T. Katayama, HFP : A hierarchical and functional programming based on attribute
grammars, Proceedings of 5th International Conf. on Software Engineering, 343-353,
(1981).
10. D. E. Knuth, Semantics of context-free languages. Math. Syst. Theory. 2(2), 127-145,
(1968).
11. D. E. Knuth, Semantics of context-free languages: correction. Math. Syst. Theory. 5,
95-96, (1971).
12. D. E. Knuth, Examples of Formal Semantics. Springer Lecture Notes in Computer
Science Vol 188, 212-235 (1971).
13. K. Koskimies, Lazy recursive descent parsing for modular language implementation.
Software Practice and Experience, 20 (8), 749-772 (1990).
14. T. Panayiotopoulos, G. Papakonstantinou, and G. Stamatopoulos, Attribute grammars
and logic programming, Agnew. Inf. No 5 (1988) 227.
15. Y. Shinoda and T. Katayama, Attribute grammar based programming a~d its environment, Proceedings of 21st Hawaii International Conference on System Sciences,
Kailu-Kona, Hawaii, 612-620, (1988).
295
16. E. Simon, A new programming methodology using attribute grammars, Acta Cybernetica, 7 (4), 425-436 (1986).
17. D. Turner, A non-strict functional language with polymorphic types. Proc. IFIP
Int. Conf. on Functional Programming Languages and Computer Architecture, Nancy,
France. Springer Lecture Notes in Computer Science 201. (1985).