1

I have built a parser using a FSM/Pushdown Automaton approach like here (and it works, well!): 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)

Community
  • 1
  • 1
rubenvb
  • 74,642
  • 33
  • 187
  • 332
  • "I find the FSM pretty easy to implement and test" - unless number of states times number of events goes into thousands. Finding every possible valid path through the transition table is a full-time job of its own. FSMs are great for many things and scale well - sadly human brains do not scale as well. Thus it is advised to have many smaller FSMs which are easy to understand - instead of trying to cram it all into one huge instance. – Dummy00001 Sep 13 '10 at 13:31
  • @Dummy: I find it allows for a great segmentation of the program flow, which a main object might make "unintuitive". What I did now is have categories of states with a specific sub-baseclass with common class members. This essentially functions as "several smaller FSMs", but there's still only one event loop. – rubenvb Nov 21 '10 at 13:49

3 Answers3

1

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
  • 17,166
  • 1
  • 38
  • 51
  • 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 Sep 13 '10 at 11:42
  • 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 Sep 13 '10 at 12:41
  • 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 Sep 13 '10 at 12:59
  • 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 Sep 13 '10 at 13:14
  • 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 Sep 13 '10 at 13:19
0

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.

Puppy
  • 144,682
  • 38
  • 256
  • 465
  • 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 Sep 13 '10 at 11:57
0

You can always take a look at boost.

Dervin Thunk
  • 19,515
  • 28
  • 127
  • 217
  • Or the new Meta-State Machine library from Boost 1.44 http://www.boost.org/doc/libs/1_44_0/libs/msm/doc/HTML/index.html – Klaim Sep 13 '10 at 11:02