While working on a code golf challenge in
dc today, my mind turned to if and how I could solve the same challenge with the current instruction set of
wo. We left off in the middle of
wo5, with six slots to go and the promise of division. Internally, I was filling a couple of slots with additional stack manipulation instructions, with three slots still open. The goal isn’t necessarily to be able to do everything (or, perhaps, much of anything) efficiently at this point, but to leave that bit-shaving option on the table, letting the programmer do the most with the least. Since there’s no fractional input, division was a no-brainer: now you can enter fractions, you can waste a little time making a reciprocal for multiplication, and you can (of course) divide.
While working on a code golf challenge in
wo have slowed down slightly, largely because I think I’ve gotten a lot of easy answers out of the way. I haven’t yet addressed – no. 4,
REGISTER. Delegating as much responsibility to internal registers as possible, and allowing a
wo programmer to modify these registers is paramount to opening up the extent of what can be done inside of a limited instruction set. As few system registers as possible will be reset at every turn – this is likely necessary for something like ‘stack depth,’ as it is a valuable value for a user to be able to fetch, but for a user to change it would be both unpredictable and of limited value.
At some point the question of stacks in
wo needs to come up. How many, how do they work, how do we manipulate them. As mentioned in the first post in the matter, I’ve been operating under the premise of a stack that does not shrink (unless cleared). It takes the theoretically-infinite stack of RPL, and combines it with the repeating bottom of RPN. Thus (pseudocode, obvs):
> 1 2 PRINT_STACK 1 2 > 3 PRINT_STACK 1 2 3 > DROP PRINT_STACK 1 1 2
I’ve been thinking a lot about instructions for
wo, how to eke the most out of low-byte-count programs. And, while I haven’t touched on it here yet (soon!), I’ve been thinking a lot about what system registers could prove useful as well. But a big part of me wonders how I’ll implement the thing, if I ever do. That so many esoteric/golfing languages are just layers on top of another scripting language makes me a bit grumpy, and that isn’t a path I’d like to take with
wo. My plan would be to write the reference interpreter in go, but I wouldn’t discount ANSI C either. That decision is trivial, though.
wo3, we get two extra instructions for a total of four. OISCs can be Turing complete, so four instructions should be enough to give us some brunt. At this point, some amount of math is probably a good idea. Instruction three, then, is
ADD, which does what you think it does. Since we’re capable of entering negatives, we can pretty much get to any number we want at this point, albeit terribly inefficiently.
Branching would be very convenient at this point as well, so a simple
SKIPZERO instruction gets the no. 4 position; it pops a value from the stack and if that value is zero, it skips until past the next instruction. All odd (input) words are skipped until an even (instruction) word is encountered, at which point that is skipped and the next word is interpreted.
Skip if zero is a standard simple conditional branch, but I’ll likely change this to
skip if (skip register), so a user can theoretically set the branch condition via a register (with a command certain to be available in
A draft of this post began:
A few thoughts on numbers in
wo. Numbered input is pushed to the stack via
LSB==0signifies an instruction, so in either case, effective word size is 1 bit less than total word size. The stack itself won’t care what sort of numbers it’s holding, input is the tricky part.
wo3would allow you to enter the integers 0-3, or −2-1 depending on unsigned vs. signed input.
wo40-7 or −4-3. These aren’t big numbers to work with, so getting instructions in early to allow for more complicated input would be welcome. The easiest solution here is simply getting the
WORDSIZEinstruction out of the way as early as possible, ideally in two bits. With signed input, this would only get a user up to a 4-bit word size with 6 bits of input. Unsigned, a user could get up to 6-bit word size in the same 6-bit input, which raises the question of whether allowing a single word input of −1 is more important than more immediate access to slightly higher integers. Signed input would reduce the need for a sign-changing instruction at the low end of the set, and there are little hacks that could be put in place – for example, if 1s’ complement was used instead of 2s’, −0 could act as a stand-in for the next highest byte size or the like. Thus 6 bits of input could immediately kick word size up to a full byte.
As outlined in this post killing off
WORDSIZE, I have changed my thoughts on that matter. I do think input will (by default) be 1s’ complement, with −0 receiving special treatment, what I am internally referring to as the Magic Number or MNum. MNum would allow some instructions to serve multiple purposes, which could theoretically put us on the path to larger integers at lower word sizes. Additionally, MNum can act as a stand-in for a predetermined value for other instructions, again opening up some integer growth options.
A few things have occurred to me regarding the
WORDSIZE instruction in
wo. Namely, that changing word size in the middle of a program could be entirely unpredictable – my first thought would be to break every word out into an array before interpreting (aside from the
WORDSIZE instruction itself), but that would be impossible – the stack would necessarily have to be computed before
WORDSIZE could execute. Even before this, I was wondering if I should really prioritize it so low in the instruction set, or if it just turns into an abuse of a reduced instruction set claim.
I’ve been thinking a lot about languages designed for code golf and programming puzzles/challenges. They run no risk of extinction — seems a new utterly inexplicable dialect is always freshly hatching. And here I am, about to fan these flames with my own bonkers idea. I call it
wo1. Here’s the thing – there will be several posts in this series, as I figure out how I would ideally like this thing to work. There will be a lot of theoretical code. But it is very possible that I will never actually bother writing a reference implementation for it. I’d like to think that I will, but I’m really not a great programmer and the fun for me is largely in the thought experiment, the puzzle.
There are a few key points that I think will make this language unique. First and foremost, it’s based on binary instructions with variable word sizes. The interpreter should set the initial word size based on invocation:
wo4 would start with 4 bit words,
wo7 with 7 bit words, etc. Smaller word sizes mean more instructions per byte, but fewer instructions are available (and smaller numbers can be pushed to the stack). It is postfix, stack-based, influenced by RPN, RPL, Forth, and dc. The main stack is initialized at zero, and can never be empty. I am very seriously considering a stack that grows but does not shrink (aside from clears) – drop operations would duplicate the bottom of the stack like RPN. Word size would be resettable via a relatively low (preferably 3-bit) instruction. A separate stack would handle certain scratch activities like string manipulation. Least Significant Bit (LSB) would determine stack input vs. instruction execution. Nearly every instruction would be rewritable (don’t need GOTO? plop something else in there before dropping your word size and taking care of business). That pretty much sums up the core philosophy/principals, the big remaining question is implementation — primarily, instruction set.