tags:

views:

79

answers:

3

I have built a parser using a FSM/Pushdown Automaton approach like here (and it works, well!): http://stackoverflow.com/questions/3176110/c-fsm-design-and-ownership It allows me to exit gracefully and output a helpful error message to the user when something goes wrong at the parser stage.

I have been wondering about a good way to get that done in the rest of my program, and naturally, the parser approach popped in my mind...

I would make every object a state, which has a single event() function that has a switch statement calling object specific functions depending on the stage of execution I am. I can keep track of that with object-specific enum's, and keep the code more readable (case parser is more readable than case 5). This will allow me to close off the pushdown tree of states I have created (using the m_parent* approach in my other question).

Is this good design (forcing everything in a FSM-mode)? Is there a better way, and how much more complicated will it be (I find the FSM pretty easy to implement and test)?

Thanks for the suggestions!

PS: I know boost has about everything one may ever need, but I want to limit external dependencies, especially on boost. c++0x is ok though (but not really relevant here I think)

A: 

Most people would use inheritance instead of switch/case/default. However, the idea of forcing everything to be one way is inherently wrong. You should always approach each required functionality on it's own merits.

DeadMG
Well, as Pontus said, logging and error reporting is pretty great to have for free, so I'm wondering if there are any more downsides than the slightly forced event() function that is called over and over.
rubenvb
A: 

You can always take a look at boost.

Dervin Thunk
Or the new Meta-State Machine library from Boost 1.44http://www.boost.org/doc/libs/1_44_0/libs/msm/doc/HTML/index.html
Klaim
+1  A: 

What you are doing is a bit like building a (simple) virtual machine in your programme. An FSM tends to be a good fit for some restricted problems such as lexing and parsing, and as you've probably noted, you can get quite a bit of logging and error management 'for free'.

However, if you try to apply the FSM pattern to everything (which is going to be tough for e.g. GUI programmes which contain quite a lot of state you normally wouldn't want to make into explicit states), you're going to realize that you also need facilities to debug your FSM (since the C++ debugger won't understand your states and events) and facilities to link and reuse states (since the states won't be OO level constructs). If you ever want to hand over your code to someone else, he or she is going to need additional training to use your FSM successfully. Are you going to want to keep one FSM engine for multiple applications? If so, how are you going to deal with versioning and upgrades?

Use the right tool for the right job. Every approach has its strengths and weaknesses. Your solution adds another layer of complexity: you can deal with logging and error handling in more C++-ish ways. If you're not happy with writing C++ code, you might consider other existing languages, rather than building an FSM language only you understand.

Pontus Gagge
Well, the background in this is the following: I am creating a build system that 1. reads a project file, 2. creates targets, 3. cross-checks files in project with source files in filesystem, 4. generates compiler commands, 5. executes them, 6. perhaps test the result, 7. perhaps create installer/archives. The only way I see of "gracefully exiting" + helpful error message through these different things is a general EndState + cleanup throughout the whole hierarchy of pushed down states (see parser question). It's a personal project, and I am trying to do everything The Right Way (R).
rubenvb
The right way to terminate and clean up in (modern) C++ is to use RAII and exceptions. Using anything else is possible, but the burden of proof is on the proponent of other techniques.
Pontus Gagge
Sounds like re-inventing the wheel here. Look at make, scons, waf, ant, eclipse, visual studio, rake, bjam or any other number of build environments. Is there a reason to create your own build system? Not that it is bad as an academic exercise. I've often thought about it myself over bouts of frustration with SCons
bradgonesurfing
@Pontus: That's what I do now, but throwing an exception causes a dialog to pop up (Windows) and a (very) cryptic OS-dependent error message to appear. Is there a way to get just a normal error message, no dialog?@bradgonesurfing: I'm using it as an academic exercise, and I feel there are tons of problems with current build systems, as probably does anyone :)
rubenvb
You also need to **catch** exceptions, preferably at the top level of your program. Have separate catch clauses for each interesting exception classes (you should add your own application-specific exception classes to describe specific problems with e.g. parsing, compiler errors or testing). In each catch clause, use information you've passed into the exception to construct a user-friendly error message (design your exception classes to facilitate this). This assumes a non-GUI application where you have control over the flow of control, which seems reasonable based on your other information.
Pontus Gagge