Skip to main content
GameDev.net gamedev.net
🔒 Locked 🎮 Unity

adding a new type in a class hierarchy without recoding the whole program

Started by r Feb 21, 2005 at 12:59 AM 0 replies 900+ views
Original Post
r
r
hi, several weeks ago i wrote a simple assembler in c++. last night i was going over the source and i realized that i've done some very bad design decisions, here it is: the assembler contains a lexical analyzer and a syntax analyzer, as anybody knows about lexical analyzers its job is to transform a stream of characters into a stream of tokens, and the job of the syntax analyzer is to transform the stream of tokens from the lexical analyzer into a stream of instructions.(actually a parse tree but that's an assembler not a compiler) here is my set of classes: class Token { public: virtual bool IsMnemonic() = 0; virtual bool IsRegister() = 0; virtual bool IsIdentifier() = 0; virtual bool IsInteger() = 0; virtual const char* GetString() = 0; virtual int GetInteger() = 0; }; class Mnemonic : public Token { public: bool IsMnemonic() { return true; } bool IsRegister() { return false; } bool IsIdentifier() { return false; } bool IsInteger() { return false; } const char* GetString() { return _mnemonic; } int GetInteger() { return 0; } private: char* _mnemonic; }; class Integer : public Token { // the same as mnemonic except that GetString returns 0 while // GetInteger returns the _integer member }; class Identifier : public Token { // u get the idea }; class Register : public Token { // bla bla }; // then here is my lexical analyzer interface (not abstract i mean operations) class LexicalAnalyzer { public: void Analyze(const char* assemblyListing, SymbolTable* symbolTable, std::list* tokenList); // rest of the class }; now i want to add another kind of Token like Real so i'll have to add an IsReal() and GetReal() in the Token interface then inherit a Real class from the Token interface and when i begin to use it i must change the LexicalAnalyzer::Analyze() and also the SyntaxAnalyzer::Analyze() so my problem is (1)i need another way so that i could just inherit a new class from the Token interface without changing it and also without changing the LexicalAnalyzer and the SyntaxAnalyzer. (2)is there any possible way that i wouldn't need the Is*() operations which is one way of removing the dependency of the SyntaxAnalyzer::Analyze() method on the different kinds of tokens. someone i know suggested the visitor pattern but i couldn't figure out how to use it in this situation. thanx in advance
rad
Clash
Clash
The visitor pattern is one that you use on a "very stable" class hierarchy, not one that needs to be open to change. By using a visitor you require VisitXXXX functions for each type to be in the base visitor and all visitor types. So if you need to add a new class to the hierarchy, every visitor has to be updated.

What I *think* you want is just a good application of some Polymorphic functions. For instance, if you have a function which checks the type of the token (by using the IsXXXX functions) and then performs logic based on each type, you could instead give that logic a name, like "CountTokenByType." Put that function in the base Token class, make it virtual and just call the function on each token. If you need to populate data somewhere external to the Tokens themselves, you could pass that data into the function and the token can operate on it. This way, adding a new token requires you to simply add a new class to the token hierarcy, implement the various bits of functionality in terms of that token, and you're done!

Using this design, the actual logic for the various operations will be moved into the Token hierarchy. The LexicalAnalyzer will more or less be the "logic invoker," because it will determine when and which objects have their operations invoked. In addition, the analyzer will probably be the place where the results of the operations go -- so all the operations will need to operate on the analyzer's data. Depending upon the operations, you may have to expose more data than you would have the other way (breaking encapsulation a bit). The tradeoff is up to you.

Also, this obviously will not help to avoid new "GetAsXXXX" functions, because those are explicitly requesting type information.

I hope this helped! If you are still unclear, please elaborate on your specific problem and we'll be glad to help!
Jason Citron- Programmer, Stormfront Studios- www.stormfront.com

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.