[comp.object] Interpreters and OOD issues - A follow up

charlie@genrad.com (Charlie D. Havener) (10/13/89)

This is a follow up to my request for info on OOD applied
to AST (Abstract Syntax Tree) interpreters of a language
like Pascal for example. 

Ron Casselman mailed an interesting reply to me and with his
permission I am posting it, ( See below ).

A review of the "Programming in C++" text by Dewhurst and Stark
indicated there was a good example of an OOD for an abstract syntax
tree expression interpreter. After reading it, it sounded a lot
like Ron's approach. I typed it in using a
little expression grammar in YACC and it works fine as far as it
goes which is just integers. 

Now I am interested in how to handle mixed data types and how to
handle storage assignment of local stack variables for recursive
function calls. 

There seems to be at least two ways to deal with the types. In one,
the data object itself knows how to add ( for example ) an object
of another type to itself. Ron said this is how he did it and it is
how Smalltalk does it. It seems to me that the binop node for Plus
is a more logical place to handle addition of different types. It could
test the type of the object or node returned from applying eval() to the
left child and likewise the right child and apply a conversion if needed.
Both of these schemes seem to require building a case statement into 
the objects to handle the different possible types. A new type put into
the system then requires repairing all the case statements in all the Binops
which seems to be a red flag warning that the design is not Object oriented.
    ---  Any thoughts on this --- ????

As far as storage of local stack variables, Ron said he used a stack of
'object identifiers' so his references could just be an offset into the
stack. Thus a double indirection is needed to access a variable. I guess the
storage allocation mechanism is outside the realm of OOD. 


------------------------------------------------------------
From mit-eddie!sce!cassel@wonko Wed Oct  4 17:44:21 1989
>Newsgroups: comp.object
>Organization: Systems Eng., Carleton Univ., Ottawa, Canada

I am currently developing an interpreter for a simple language as part
of a CASE tool effort. I am using lex and yacc to develop the front-end of
the interpreter. The yacc rules are written in Objective C an object-oriented
extension to C. I found the marriage between yacc an Objective C to 
be excellent. As my grammar rules reduce I create "Objects" that
represent the non-terminals and terminals of the language. 
Examples of these "Objects"
include: IfThenElse, CaseStatement, AssignementStatement objects.
I build the parse tree in the classic bottom-up style as the grammar
rules reduce. The result is a normal looking parse tree but the nodes
of the tree are now "Objects". 

The interpreter becomes very simple. Each node in the tree is responsible
for knowing how to "evaluate". In the particulars of my case this
means that each node (read "Object") must respond to the message eval.
Intrepretation amounts to sending the eval message to the root of the
parse tree. The "eval" message is propogated through the tree
(like a tree walk) to achieve execution.

The advantages as I see them are:
	1. Intrepretation becomes very simple because each node
	   in the tree is responsible for knowing how to evaluate.
	2. Extending the interpreter becomes very easy.
	3. The yacc rules are somewhat simplier because they always
	   return "Objects".

 
Disclaimer: I am not a compiler writer nor an expert in OOP, but for what
	it is worth I found the development of this code to be 
	intuitive.

						Ron Casselman
						Dept. Of Systems Engineering
						Carleton U.
						Ottawa, Canada
						(613) 788-5726


----------------------------------------------------------------------

Charlie Havener - GenRad Inc. 300 Baker Ave., MS 1A, Concord Mass. 508-369-4400 X3302

davidc@vlsisj.VLSI.COM (David Chapman) (10/14/89)

In article <27307@genrad.UUCP> charlie@genrad.com (Charlie D. Havener) writes:
>how Smalltalk does it. It seems to me that the binop node for Plus
>is a more logical place to handle addition of different types. It could
>...
>Both of these schemes seem to require building a case statement into 
>the objects to handle the different possible types. A new type put into
>the system then requires repairing all the case statements in all the Binops
>which seems to be a red flag warning that the design is not Object oriented.

Not all operators need to work for all data types.  I defined a small language
for data base queries that had a bunch of special types such as dates and
times.  You don't want to multiply two dates together!  This would help you
limit the damage.

Recompiling the operators that need to operate on a new data type does not
seem to be much of a burden to me.  At least you don't have to recompile the
entire system.

The alternative is likely to be a set of meta-operators that can perform the 
specified operations on _anything_.  That's a much harder problem.
-- 
		David Chapman

{known world}!decwrl!vlsisj!fndry!davidc
vlsisj!fndry!davidc@decwrl.dec.com