How does input parsing in the Å-machine work?

In the Å-machine specification for get-input:

		The string of characters typed by the player is converted into
		lowercase, and split into substrings as follows:

			* Every stop character (as declared in the LANG chunk)
			becomes a single substring.

			* Remaining characters are separated by whitespace.

		Thus, the string "drop    ball.north" is split into the
		substrings "drop", "ball", ".", and "north".

The pseudo-code for the instruction results in DEST being a list of all the substrings after each one is parsed (into either a number, character, dictionary word or extdict reference).

If all the words the player typed are in the DICT chunk, then the list should be a list of dictionary words (unless there’s something I’m missing). However, the game code I’m using to check the action and topic in the list doesn’t work in the reference interpreter since they end up being of type extdict:

    ;; Our actions
    (perform ; (perform [$Action $Noun])
     (assign ,arg1 ,lst)(jmpl-simple (jump car-cdr))
     (assign ,head ,acc)(assign ,tail ,lst)(jmpl-simple (jump car-cdr))
     (assign ,head ,topic)(assign ,acc ,head)
     ;; The parsing code below is considered invalid by the reference interpreter.
     ;; I'm not sure why the IDX isn't considered a dictionary word,
     ;; since the input given was already processed by `get-input`.
     (idx-set ,head)
     (check-eq? "wait" (jump wait))
     (empty? ,lst (jump unrecognised))
     (check-eq? "go" (jump go))
     (check-eq? "search" (jump search))
     (idx-set ,topic)(jmpl-simple (jump get-loc))
     (idx-set ,head)
     (check-eq? "question" (jump question))
     (check-eq? "accuse" (jump accuse)))
    ,(leaf 'unrecognised "Without a place in mind, you continue pondering.")

The bytecode emitted by the Dialog compiler seems to use a different mechanism entirely, where the AUX stack and R13 work in parallel to build up the parse manually. Maybe it would be easier if I understood why extended dictionary words work the way they do, so I could fix my port of Mini-Cluedo.

1 Like

Hmm. It seems like it should return a list of dictionary words. The builtin (get input $) gets compiled into a I_GET_INPUT instruction in compile.c:

	case BI_GETINPUT:
		// this cannot be inlined because the debugger may want to inject queries
		ci = add_instr(I_GET_INPUT);
		end_routine(0xffff, &pred->arena);
		break;

And that gets compiled into a AA_GET_INPUT instruction in backend_aa.c:

			case I_GET_INPUT:
				ai = add_instr(AA_GET_INPUT);
				ai->oper[0] = (aaoper_t) {AAO_REG, REG_A + 0};
				ai = add_instr(AA_PROCEED);
				break;

Which means (get input $) should get converted into a straightforward AA_GET_INPUT instruction. I don’t see where the AUX stack would come into it.

Is the behavior consistent between the JavaScript and 6502 reference interpreters?

Which means (get input $) should get converted into a straightforward AA_GET_INPUT instruction. I don’t see where the AUX stack would come into it.

Sorry, the get-input instruction is there, so the problem should be elsewhere. The reason why I mentioned it was because the input worked as expected when I stubbed it with the equivalent AUX stack setup and a AUX_POP_LIST instruction.

Is the behavior consistent between the JavaScript and 6502 reference interpreters?

Yes, I’ve tested with both interpreters, though I’m not sure why just using get-input acts differently from what the spec implies. For example, when I type “wait” into the game, the value is correct when I check with a print-val, but the check-eq? instruction doesn’t detect it as equal to its dictionary word.

Hmm. My first thought is that something’s going wrong with your DICT chunk, since that’s what determines if a word is stored as a dict or an extdict. Do any problems come up when you pass it through aamshow?

This is the DICT chunk of the story file (from aamshow):

=== DICT ======================================================================
2000: @hedgemaze
2001: @fountain
2002: @rosegarden
2003: @peach
2004: @brown
2005: @grey
2006: @wait
2007: @go
2008: @search
2009: @question
200a: @accuse
200b: @spell of ancient powder
200c: @poisoned croquembouche
200d: @waffle iron

I don’t think the problem is with the last 3 dictionary words having a space in them, since the bug still persists when they’re removed. I could make a small reproducer story file if it helps with debugging…

That would definitely help! I’m not seeing anything obviously wrong so far…

input-test.zip (1.7 KB)

It seems like the bug was in the game logic all along :sweat_smile: It’s up to me to fix it, though I’ll have to figure out why it’s subtly wrong.