DavidKinder / Inform6

The latest version of the Inform 6 compiler, used for generating interactive fiction games.
http://inform-fiction.org/
Other
204 stars 34 forks source link

GRAMMAR_META_FLAG option #283

Closed erkyrath closed 6 months ago

erkyrath commented 6 months ago

As discussed: https://github.com/DavidKinder/Inform6/issues/278 . This is Graham's proposal, not the original idea.

If $GRAMMAR_META_FLAG=1, then actions are ordered (in the game file) with all meta actions before all non-meta actions. The highest meta action number is the new system constant #highest_meta_action_number.

A meta action is declared by writing:

Verb 'score' * -> Score meta;

The old left-hand style is still supported:

Verb meta 'score' * -> Score;

The difference is that with the new right-hand form, a single verb word can invoke both meta and non-meta actions:

Verb 'load'
  * noun -> Push
  * 'game' -> Restore meta;

If $GRAMMAR_META_FLAG is set, we define a GRAMMAR_META_FLAG I6 symbol so that game/library code can #ifdef on it.

If $GRAMMAR_META_FLAG is not set, the right-hand "meta" format and #highest_meta_action_number are rejected.


Implementation details:

This required a lot of code changes, but they're mostly contained under if (GRAMMAR_META_FLAG) checks. If the option is not set, we do almost nothing new.

When $GRAMMAR_META_FLAG is set, action constants (ACTION_MV) must be backpatched. We call the new sort_actions() routine, which creates a sorted_actions array that maps the "internal" action number (declaration order) to the "external" action number (properly sorted in the game file). The backpatching operation then consists of a sorted_actions lookup.

When generating the action table in the game file, we use sorted_actions to write them in the proper (external) order. Same goes for the action-name symbol table.

The grammar_line() routine now takes an allmeta argument, indicating whether a left-hand "meta" keyword was used for this Verb declaration (and thus should be applied to all grammar lines).


Other code cleanup:

The expression ((grammar_version_number==1)?256:4096) was used in a bunch of places to determine the lowest fake action number. (That is, the maximum number of actions supported by the grammar version.) I have moved this to a lowest_fake_action() routine.

We never had an explicit check for exceeding the maximum number of actions. (Doing this led to errors, but they were confusing "fake action, not a real one" errors.) We now have an explicit check and error report.

--trace actions now displays an action table at the end (including meta flags if appropriate!) It used to list actions as they were declared, which was untidily mixed in with other compilation output. The old behavior is now --trace actions=2.

The system constants #highest_action_number, #action_names_array, #lowest_fake_action_number, #highest_fake_action_number, #fake_action_names_array are now supported in Glulx. They have never been important -- they were added to Inform for Infix support, which has never existed for Glulx. But they were convenient for testing this feature. So I threw them in. (I should probably throw in all the other missing system constants, but not this week.)


Testing:

We compile Advent.inf with $GRAMMAR_META_FLAG set but use the old library. The old declaration style still sets the meta flag for verb dict words, so the old library parser still works correctly.

We also compile a short game (https://github.com/erkyrath/Inform6-Testing/blob/meta-flag/src/withdaemon.inf) with a modified library that does not check verb dict words, but rather relies on #highest_meta_action_number. (See https://github.com/erkyrath/Inform6-Testing/blob/meta-flag/i6lib-611meta/parserm.h.) The game has a daemon that ticks on every (non-meta) turn, so it's easy to tell that meta actions are working right.

https://github.com/erkyrath/Inform6-Testing/blob/meta-flag/src/grammar-metaflag-test.inf shows various combinations of the meta flag.