Interpreting if/else logic with a simple flat list of booleans
While working on a hyperlink text game editor/player called Hiss the last couple days, I "discovered" a way to store and play if/else logic without a traditional tree structure (such as an AST (wikipedia.org)).
Like all good things, it became glaringly "obvious" in hindsight, but I’d never personally seen it before.
The Challenge: Represent nested if/else logic of any depth with just a flat list.
My interpreter’s instructions look something like this (pseudocode):
[ { if foo == bar } { say "Foo is bar!" } { else } { say "Foo is NOT bar!" } { end if } ]
(Note that it’s just a flat list of instructions, not a tree. Also note that it’s not a series of compiled VM opcodes. Just if/else "instructions" with no other semantic information.)
The Solution: Just a flat list of boolean values and four simple rules are all you need to "play" such a script.
I call the list of boolean values the logic stack.
-
if
pushes true or false on the logic stack -
else
inverts the last item on the stack -
endif
pops the last item on the stack -
If all values on the logic stack are true, then you’re in a 'true' branch of the logic, otherwise you’re not.
Check out these pseudocode examples. I am NOT indenting the nested statements to make it clear that these are all independent instructions. And yes, it does make it harder to read the examples.
This one has a false statement in the middle that gets inverted with an else:
instruction logic stack ================================================= if <true> true if <false> true, false else true, true endif true endif (empty also means "true")
This longer one starts off with a false statement. Note how there are true statements inside, but since the logic stack contains a false, none of the trues matter. We are in a true branch only when all of the values are true.
instruction logic stack ================================================= if <false> false if <true> false, true if <true> false, true, true else false, true, false endif false, true endif false else true if true true, true else true, false endif true endif (empty also means "true")
Why?!
The full explanation is in the Hiss dev log (also linked above), but, in short:
-
Because I can and it’s a personal project so nobody can stop me HA HA HA!
-
The intention is to make a scripting language that has no errors.
With just one more rule and some guard statements (shown in action in the example below), you can make a scripting language in which it’s legal to put these statements in any order and my script player will not crash or produce any errors.
It may not do what you want (it can’t read your mind), but it will not complain.
This is perfectly valid HissScript (not pseudocode, though the exact syntax may have changed by the time you read this):
endif Hello! No error here (endif doesn't explode on an empty list). endif else This will never show up (else adds 'false' to an empty list). endif Hello! This will show up (the 'false' is popped by endif).
I want beginners of any kind (including children) to be able to write text-based, hyperlinked, choose-your-own adventure games with a minimum of frustration without resorting to a purely graphical interface.
(It’s also worth noting that Hiss shows the output of your script as you type and anything that isn’t recognized as a Hiss command appears on the screen as text.)
Conclusion
Again, it’s "obvious" in retrospect that a logic stack of booleans can
represent your current position in a tree of if/else logic. Also obvious that
all entries in the stack must be true
for the current position to be in a
"true" branch of the logic…
But it was fun to "discover" such a simple and obvious thing after a couple failed attempts with more complicated logic. :-)