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