Starting Disaster Compiler

I came to the realization a couple weekends ago that I needed to write a compiler.  I was hoping to avoid it by simply reducing the type of commands that the pinball machine could run, but I keep coming back to the issue that I want this to be a generic pinball driving machine.  That being said, the pinball rule set must be able to handle all sorts of different instructions.  Some of the instructions will be high-bred instructions to make writing pinball rules easier for users, but many will simply be math like instructions.  I’ve spent a good deal of time trying to come up with a good number of these high-bred instructions, and a good amount of time on the architecture of the rules file.  I will eventually write a document on writing a pinball rules file, but doing a first cut for my simple pinball machine has really helped to make the ideas concrete.

Here is a link to the current rules file  (I’ll point this out so that people can find it more easily and not need to download the whole code base):

The first section of the file is simply stating what hardware needs to exist for the pinball machine and names each of the solenoids, inputs, and LEDs.  This is so each used hardware pin can be identified by name.  Next section is variables and indexed variables.  This is going to be implemented as a simple array of integers with the dictionary (keyed off the name) handing back the offset into the array.  Next sections are sound and video clips.  These will be pre-allocated so they can quickly be switched between or even play multiple sounds at once.

The next section contains the processing chains.  This is the section that requires a compiler.  The input pins named in the above sections can be used to alter the operation of the machine.

A simple example would be kicking the ball into the shooter lane.  While it would be easiest to kick the solenoid, and just hope that the ball got onto the playfield, it might not necessarily happen.  The solenoid might not be working properly.  One way to deal with this is to kick the solenoid and check the switch if a ball shows up in the shooter lane (one of the input switches).  At the same time, if the ball doesn’t show up, you want to try to kick the ball another few times just in case the issue fixes itself.   (Maybe two of the balls were interfering with each other, or maybe the solenoid was a little sticky, and a second kick would work.)  If the maximum number of retries is exceeded, the pinball machine should display an error and not allow anybody else to put more money in the machine.  This simple action of the pinball shows that it needs to support timers, math functions (incrementing the retry count), comparisons, and reading switch inputs during the loop.  The process chains that implement this are Proc_Start_Ball_Init and Proc_Start_Ball_Start.  The init function is run once when a mode is entered, while the start routine is run after each tick.  At the end of this chain, the pinball machine will move to the Mode_Ball_In_Play or Mode_Error.

I originally thought that I could implement this with a simplified amount of functions, but during writing the rules file, I found it was much easier to assume that I had that ability to use anything that is available to me in any normal language.  That means that it is time to write a simple compiler.  (Luckily it is only the top end of the compiler to convert command lines into pseudo-code.  I don’t need to write the bottom end of the compiler.  Of course, if I would write the bottom half of the compiler, it would be much faster, but then I would need the parser to create code and then compile the generated code.  I currently believe it will be fast enough without doing this last step, but it is arguable that it would be a cleaner design using self generated code.)

This has taught me not to laugh at my friends when they were taking compiler theory in college, while I was taking fields and waves.  Maybe I should have taken it as an elective.  Somebody on the web wrote a article about how a pinball machine is the ultimate renaissance man machine.  It requires electrical engineering, mechanical engineering, graphics design, animation, and computer science disciplines.  I have certainly enjoyed the strange paths that it has taken me and allowed me to probe some new areas that I was not expecting.

Anyhow, there are also high-bred commands.  An example would be the LED_ROT_RIGHT/LED_ROT_LEFT commands.  These commands are very useful for implementing the “change lane” function.  In most modern pinball machines, when you hit the right flipper, the inlanes, or outlanes lights rotate to the right so that it makes it easier to complete all of the lights.  The left flipper sometimes does the same thing to the left.  (It actually freaks me out when playing early 70s machines where you actually have to shoot accurately instead of just rotating the lights to complete a set of lights.)  In the pinball machine, hitting the right flipper simple rotates the subset of lights.  The high-bred command rotates the group by using the LED_ROT_xxxx command, then providing the mask of bits to rotate, and the variable containing the currently lit bits.  The Proc_Flipper chain does this processing.  It is a high-bred command because it does a lot processing beneath the command, but the user just has to write a simple upper layer command to get it to happen.

If anybody has any comments on what they would need in a rules file, I would be glad to hear them.  Once the framework is finished, it will be simple to add more commands, but suggestions would be appreciated to make sure that I don’t miss major functionality that is required.  It is always best to plan for major features at the start to make sure that the architecture supports them.

5 responses to “Starting Disaster Compiler

  1. interesting. I essentially came up with something similar for my machine, I did my compiler in ruby to output c for pic32 (still working on it), but it basically defines solenoids, switches, leds etc then a rules sets.

    I often group things so, switches might be
    pop_rollver ##top level

    then I can reference them individually or as a group on_switches(pop_rollover)

    • Interesting idea about the grouping. I can definitely see how that would make things easier. It allows you to more easily address different groupings. You could even do something similar in a pre-processor step so when you refer to the group, it actually boils it down to the individual bits, but the compiler deals with that instead of forcing the user to deal with it.

      Writing the compiler has taken a much larger amount of time than I was expecting. I’m almost done with the top of the compiler so that it compiles it into java and fills out the data structures, but I still have to write the lower level functions to take those data structures and act on them. I was making really good progress for a while, but now it is a lot of slogging. I think that I should have spent more time researching yacc or other tools that are meant to generate native code. It might have taken a little less time but would end up generating less optimal code.

      I’m hoping the compiler is done in the next month, and I can start running simulations of the pinball machine. I’ve got a good idea for a visual tester of the code (just a really simple toolkit which you can choose each of the switch inputs and they are labeled and you can either press them momentarily, press and hold, or release the button. That should give most of the states so you can end up walking through your rule set.

      Best of luck!

    • See the comment I just made to Vectortrex. I believe both of you were a little further along in your idea/designs, and I believe the new approach will be significantly better. I also like that it will be much, much faster.

  2. Maybe I’m just not in the right frame of mind, but why go with a custom compiled solution and not just use C? I can see your process system having trouble with multiple machine states (for instance, triggering multiball conditions while in a higher level event? Or a simple example in your file there, inserting a coin while one is already in? You could copy/paste the insert coin routine but that behavior isn’t going to scale well). While the rule sheet is a bit simpler to code, I’m not convinced you’re really saving yourself any time against a C/C++ solution, while losing a lot of flexibility in the process.

    • So I originally decided to do everything in Java. Truth be told, I don’t really like Java as a language, but I was able to very quickly stream video to the screen and do other things like throw scores on the screen, and display the current mode. That all worked out really well, but I’m not really happy with how the compiler is coming around. It is now basically munging the compile ruleset, but it isn’t the most efficient code because it doesn’t do any optimizations. Writing a compiler and boiling it down to a data structure was a good exercise, but now I’m at a point that I should start writing an optimizer.

      Your suggestion of switching to C is looking much better. I’m not at the point of abandoning the rules.txt file yet because I think it will make programming the machine much simpler.

      Here is my current idea, and what I’m going to start running with. The rules are still written in the pseudocode. Instead of munging it directly into a data structure, it gets converted into actual C code. This happens in the same way that the C preprocessor gets makes the code more readable for the compiler. (Gets rid of comments, expands macros, etc.) The pinball pre-processor ends up converting the rules into C and most of the pre-defined routines are converted into function calls. Those C files are then compiled using a standard compiler. I can then get to these functions using JNI or maybe find a better way to stream video that doesn’t involve Java. That should be a much cleaner solution, and it should run significantly faster.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s