Hotfix for PunyInform parser.h for SpringThing entry ; any advice?

A player kindly sent me a bug report of an error when they try:

WAIT FOR 1

(this isn’t the right syntax; you can WAIT 1 or WAIT FOR 1 MINUTE/HOUR/etc — I’m using Puny’s waittime extension)

I made a small version of the code that shows the error:

!%++puny

Constant INITIAL_LOCATION_VALUE = TheRoom;

Include "globals.h";
Include "puny.h";

[ Initialise; ];

Object TheRoom "The Room" with description "The room";

[ WaitLongSub; ];
Verb 'foo' * 'for' number 'minutes' -> WaitLong;

When you try to FOO FOR 1, it produces the error I think you wanted to say "foo for [** Programming error: Class (object number 1) has no property short_name to read **] Class minutes". Please try again.

I could fix this by adding another grammar line that matches “foo for {number}”; that wouldn’t be unreasonable — but I have a bunch of grammar that rely on numbers, and I worry that these might exhibit similar kinds of parser bugs when players are close-but-not-correct with verb-with-number-noun syntax.

I tracked this down to _PrintPatternSyntax and can see that while it special-cases several token types/data, it doesn’t for numbers, and so it tries to treat it like an object.

I’ve modified the code so that it works (see big obvious spacing showing the two lines I added):

[ _PrintPatternSyntax p_pattern p_noun _num_preps _token _type _data _i _count _token_value;
	! write what pattern we expected, something like:
	! "I think you wanted to say "put all in something". Please try again."
	PrintMsg(MSG_PARSER_BAD_PATTERN_PREFIX);
	print (verbname) verb_word;
	_count = (p_pattern->0) / 8;
	for(_i = 1: _i <= _count: _i++) {
!	for(_token = p_pattern + 3: _token->0 ~= TT_END: _token = _token + 3) {
		_token = p_pattern + _i + _i;
		_token_value = _token -> 0;
		_type = _token_value & $0f;
		_data = _token -> 1;
		! check if this is a new list of prepositions
		if(_token_value == TOKEN_FIRST_PREP or TOKEN_SINGLE_PREP) _num_preps = 0;
		if(_type == TT_PREPOSITION) {
			! only write the first item in a list of alternative prepositions
			if(_num_preps == 0) print " ", (address) #adjectives_table-->_data;
			++_num_preps;
		} else {
			print " ";
			if(p_noun == 0) {
				if(_type == TT_ROUTINE_FILTER && #preactions_table-->_data == ADirection) {
					print (string) SOMEDIRECTION_STR;
				} else if(second == 0) {
!					if(_type == TT_OBJECT && _token->2 == CREATURE_OBJECT) {
					if(_type == TT_OBJECT && _data == CREATURE_OBJECT) {
						print (string) SOMEONE_STR;
					} else {
						print (string) SOMETHING_STR;
					}
				} else print (name) second;
			} else {


        ! only part that Joel changed is that I added this:

        if(_type == TT_OBJECT && _data == NUMBER_OBJECT) {
          print noun;



        } else if(noun ~= 0 && metaclass(noun) ~= ROUTINE) {
					p_noun = 0; ! avoid repeat (we don't need p_noun anymore)
					if(parser_all_found) print "all"; else print (name) noun;
!				} else if(_type == TT_OBJECT && _token->2 == CREATURE_OBJECT) {
				} else if(_type == TT_OBJECT && _data == CREATURE_OBJECT) {
					print (string) SOMEONE_STR;
				} else {
					print (string) SOMETHING_STR;
				}
			}
		}
	}
	PrintMsg(MSG_PARSER_BAD_PATTERN_SUFFIX);
];

that works, and it feels like a low-risk change mid-SpringThing. If anyone more familiar with parsing can see anything risky about this, or has other advice on a better way to solve this, it’d be much welcomed.

2 Likes

@fredrik : I submitted a PR for this, but I can’t figure out what I’m doing wrong with your test system, since it won’t create the .scr file for my test (and therefore the test fails). Hopefully, this will at least make it easier for you all to have a test in the end, if you accept this.

Derp: figured out why the test didn’t create .scr, but can’t figure out why the output is off-by-one-line. I hope the test helps, at least.