rubenvb
rubenvb

Reputation: 76519

Extensible parser design

I have a class Target with a "fileType" enum which holds all kinds of files my parser needs to know about (currently SOURCE, HEADER, RESOURCE). I'd like my Parsing function to be able to do something generic like:

if( token == some_known_fileType )
    put_nextToken_in_the_list_for_that_fileType();
else
    return an_error();

But there's a catch: I'd like to be able to simply extend the known fileTypes with subclasses of Target, that extend the enum in a correct way, see Base enum class inheritance for how I did this. I don't want to modify the above code, but only generically extend the Target half. C++0X may be required and is very welcome.

Thanks!

UPDATE: Upon trying to explain it here and posting some reduced class declarations, I realised my design is broken, and I tried to push the specialization of fileType too deep in my class structure. I wanted only one place to store a full list of all known types, but in trying to do so, I accidentally forced the design to have access to that list in two places at a time. I now realise that the list of all fileTypes should be where the keywords SOURCE, HEADER, etc. are read, and be handled *generically from thereon. I will store a full list in one place, and access that list through a "huge" enum later on. A std::map<fileType, std::set<std::string> > pops into my head as a logical choice here, instead of seperately named set for each specific fileType. Thanks for the braincandy in your responses though! Any thoughts are still welcome.

Upvotes: 0

Views: 716

Answers (3)

Rajivji
Rajivji

Reputation: 315

I believe this is not usually the right approach, but that's my belief. I would do this in a different way. Take a step back and what are we trying to achieve, we want to control the behavior based on an incoming (input parameter) value. Lets say we have classes: FileA FileB ... the file_type holds the type of file. Use a factory to control the available list of files (which can change based on the registration of different files).

class FileA {
    void register_type();  // register itself to the factory.
};

class FileB..
//main code
class FileFactoryDelegator {
    ...
    delegateControl (FileType file_type) {
        //validate file_type.
        file_types[file_type]->performFileOperation (..);
    }
};

Instead of if-else loop.

file_factory.delegateControl (token);

Upvotes: 2

DennyRolling
DennyRolling

Reputation: 486

don't write your parser. use boost::spirit

Upvotes: -1

Lars
Lars

Reputation: 1387

This is hard to answer as a lot depends on what exactly your are doing with the tokens, file type values, and Target instances. However, I think the underlying theme here is that you need to replace if() statements with virtual method calls. For example, your code fragment could end up being

if (tokenLists.supportsFileType(token))
    tokenLists.getListForType(token).put_nextToken_into_this_list();
else
    return an_error();

The above tokenLists example could be generalized into a registry of TargetSpecificLogic instances, which combine all kinds of filetype specific methods.

You Target class could implement a virtual method retrieveAllKnownFileTypes(), which the subclasses would extend, and which the rest of your code could evaluate.

You Target class could implement a virtual method bool isFileTypeKnown(filetype), returning true or false.

...and so on.

Upvotes: 0

Related Questions