Inform - Support - Source

Back to List

Inventory
Complete

Plain
Coloured
Gaudy

Browsing parserm.h

This is the complete source code of the example game parserm.inf.

0001  ! ==============================================================================
0002  !   PARSERM:  Core of parser.
0003  !
0004  !   Supplied for use with Inform 6 -- Release 6/11 -- Serial number 040227
0005  !
0006  !   Copyright Graham Nelson 1993-2004 but freely usable (see manuals)
0007  !
0008  !   This file is automatically Included in your game file by "Parser".
0009  ! ------------------------------------------------------------------------------
0010  !   Inclusion of "linklpa" (which defines properties and attributes)
0011  !   Global variables, constants and arrays
0012  !       1: outside of the parser
0013  !       2: used within the parser
0014  !   Inclusion of natural language definition file
0015  !       (which creates a compass and direction-objects)
0016  !   Darkness and player objects
0017  !   Definition of grammar token numbering system used by Inform
0018  !
0019  !   The InformParser object
0020  !       keyboard reading
0021  !       level 0: outer shell, conversation, errors
0022  !             1: grammar lines
0023  !             2: tokens
0024  !             3: object lists
0025  !             4: scope and ambiguity resolving
0026  !             5: object comparisons
0027  !             6: word comparisons
0028  !             7: reading words and moving tables about
0029  !       pronoun management
0030  !
0031  !   The InformLibrary object
0032  !       main game loop
0033  !       action processing
0034  !       end of turn sequence
0035  !       scope looping, before/after sequence, sending messages out
0036  !       timers, daemons, time of day, score notification
0037  !       light and darkness
0038  !       changing player personality
0039  !       tracing code (only present if DEBUG is set)
0040  !
0041  !   Status line printing, menu display
0042  !   Printing object names with articles
0043  !   Miscellaneous utility routines
0044  !   Game banner, "version" verb, run-time errors
0045  ! ==============================================================================
0046   
0047  System_file;
0048   
0049  #Ifdef MODULE_MODE;
0050  Constant DEBUG;
0051  Constant Grammar__Version 2;
0052  Include "linklpa";
0053  #Endif; ! MODULE_MODE
0054   
0055  ! ------------------------------------------------------------------------------
0056  !   Global variables and their associated Constant and Array declarations
0057  ! ------------------------------------------------------------------------------
0058   
0059  Global location = InformLibrary;    ! Must be first global defined
0060  Global sline1;                      ! Must be second
0061  Global sline2;                      ! Must be third
0062                                      ! (for status line display)
0063  ! ------------------------------------------------------------------------------
0064  !   Z-Machine and interpreter issues
0065  ! ------------------------------------------------------------------------------
0066   
0067  #Ifdef TARGET_ZCODE;
0068  Global top_object;                  ! Largest valid number of any tree object
0069  ! ### these globals are not meaningful... well, maybe standard_interpreter,
0070  ! but I'll decide that later (AP).
0071  Constant INDIV_PROP_START 64;       ! Equivalent of a Glulx constant
0072   
0073  #Endif; ! TARGET_ZCODE
0074   
0075  Global standard_interpreter;        ! The version number of the Z-Machine Standard which the
0076                                      ! interpreter claims to support, in form (upper byte).(lower)
0077   
0078  Global undo_flag;                   ! Can the interpreter provide "undo"?
0079  Global just_undone;                 ! Can't have two successive UNDOs
0080   
0081  Global transcript_mode;             ! true when game scripting is on
0082   
0083  #Ifdef TARGET_ZCODE;
0084  Global xcommsdir;                   ! true if command recording is on
0085  #Endif; ! TARGET_ZCODE
0086   
0087  #Ifdef TARGET_GLULX;
0088  Constant GG_MAINWIN_ROCK     201;
0089  Constant GG_STATUSWIN_ROCK   202;
0090  Constant GG_QUOTEWIN_ROCK    203;
0091  Constant GG_SAVESTR_ROCK     301;
0092  Constant GG_SCRIPTSTR_ROCK   302;
0093  Constant GG_COMMANDWSTR_ROCK 303;
0094  Constant GG_COMMANDRSTR_ROCK 304;
0095  Constant GG_SCRIPTFREF_ROCK  401;
0096  Array gg_event --> 4;
0097  #Ifdef VN_1630;
0098  Array gg_arguments buffer 28;
0099  #Ifnot;
0100  Array gg_arguments --> 8;
0101  #Endif; ! VN_
0102  Global gg_mainwin = 0;
0103  Global gg_statuswin = 0;
0104  Global gg_quotewin = 0;
0105  Global gg_scriptfref = 0;
0106  Global gg_scriptstr = 0;
0107  Global gg_savestr = 0;
0108  Global gg_commandstr = 0;
0109  Global gg_command_reading = 0;      ! true if gg_commandstr is being replayed
0110  #Endif; ! TARGET_GLULX
0111   
0112  Global gg_statuswin_cursize = 0;
0113  Global gg_statuswin_size = 1;
0114   
0115  ! ------------------------------------------------------------------------------
0116  !   Time and score
0117  !   (for linkage reasons, the task_* arrays are created not here but in verblib.h)
0118  ! ------------------------------------------------------------------------------
0119   
0120  #Ifndef sys_statusline_flag;
0121  Global sys_statusline_flag = 0;     ! non-zero if status line displays time
0122  #Endif;
0123  #Ifndef START_MOVE;
0124  Constant START_MOVE 0;              ! Traditionally 0 for Infocom, 1 for Inform
0125  #Endif;
0126  Global turns = START_MOVE;          ! Number of turns of play so far
0127  Global the_time = NULL;             ! Current time (in minutes since midnight)
0128  Global time_rate = 1;               ! How often time is updated
0129  Global time_step;                   ! By how much
0130   
0131  #Ifndef MAX_TIMERS;
0132  Constant MAX_TIMERS  32;            ! Max number timers/daemons active at once
0133  #Endif; ! MAX_TIMERS
0134  Array  the_timers  --> MAX_TIMERS;
0135  Global active_timers;               ! Number of timers/daemons actives
0136   
0137  Global score;                       ! The current score
0138  Global last_score;                  ! Score last turn (for testing for changes)
0139  Global notify_mode = true;          ! Score notification
0140  Global places_score;                ! Contribution to score made by visiting
0141  Global things_score;                ! Contribution made by acquisition
0142   
0143  ! ------------------------------------------------------------------------------
0144  !   The player
0145  ! ------------------------------------------------------------------------------
0146   
0147  Global player;                      ! Which object the human is playing through
0148  Global deadflag;                    ! Normally 0, or false; 1 for dead; 2 for victorious, and
0149                                      ! higher numbers represent exotic forms of death
0150   
0151  ! ------------------------------------------------------------------------------
0152  !   Light and room descriptions
0153  ! ------------------------------------------------------------------------------
0154   
0155  Global lightflag = true;            ! Is there currently light to see by?
0156  Global real_location;               ! When in darkness, location = thedark
0157                                      ! and this holds the real location
0158  Global visibility_ceiling;          ! Highest object in tree visible from the player's point of view
0159                                      ! (usually the room, sometimes darkness, sometimes a closed
0160                                      ! non-transparent container).
0161   
0162  Global lookmode = 1;                ! 1=standard, 2=verbose, 3=brief room descs
0163  Global print_player_flag;           ! If set, print something like "(as Fred)" in room descriptions,
0164                                      ! to reveal whom the human is playing through
0165  Global lastdesc;                    ! Value of location at time of most recent room description
0166                                      ! printed out
0167   
0168  ! ------------------------------------------------------------------------------
0169  !   List writing  (style bits are defined as Constants in "verblibm.h")
0170  ! ------------------------------------------------------------------------------
0171   
0172  Global c_style;                     ! Current list-writer style
0173  Global lt_value;                    ! Common value of list_together
0174  Global listing_together;            ! Object number of one member of a group being listed together
0175  Global listing_size;                ! Size of such a group
0176  Global wlf_indent;                  ! Current level of indentation printed by WriteListFrom()
0177   
0178  Global inventory_stage = 1;         ! 1 or 2 according to the context in which "invent" routines
0179                                      ! of objects are called
0180  Global inventory_style;             ! List-writer style currently used while printing inventories
0181  ! ------------------------------------------------------------------------------
0182  !   Menus and printing
0183  ! ------------------------------------------------------------------------------
0184   
0185  Global pretty_flag = true;          ! Use character graphics, or plain text?
0186  Global menu_nesting;                ! Level of nesting (0 = root menu)
0187  Global menu_item;                   ! These are used in communicating
0188  Global item_width = 8;              ! with the menu-creating routines
0189  Global item_name = "---";
0190   
0191  Global lm_n;                        ! Parameters used by LibraryMessages
0192  Global lm_o;                        ! mechanism
0193   
0194  #Ifdef DEBUG;
0195  Global debug_flag;                  ! Bitmap of flags for tracing actions,
0196                                      ! calls to object routines, etc.
0197  Global x_scope_count;               ! Used in printing a list of everything
0198  #Endif; ! DEBUG                     ! in scope
0199   
0200  ! five for colour control
0201  ! see http://www.inform-fiction.org/patches/L61007.html
0202  Global clr_fg = 1;                  ! foreground colour
0203  Global clr_bg = 1;                  ! background colour
0204  Global clr_fgstatus = 1;            ! foreground colour of statusline
0205  Global clr_bgstatus = 1;            ! background colour of statusline
0206  Global clr_on;                      ! has colour been enabled by the player?
0207  Global statuswin_current;           ! if writing to top window
0208   
0209  Constant CLR_DEFAULT 1;
0210  Constant CLR_BLACK   2;
0211  Constant CLR_RED     3;
0212  Constant CLR_GREEN   4;
0213  Constant CLR_YELLOW  5;
0214  Constant CLR_BLUE    6;
0215  Constant CLR_MAGENTA 7;
0216  Constant CLR_CYAN    8;
0217  Constant CLR_WHITE   9;
0218  Constant CLR_PURPLE  7;
0219  Constant CLR_AZURE   8;
0220   
0221  Constant WIN_ALL     0;
0222  Constant WIN_STATUS  1;
0223  Constant WIN_MAIN    2;
0224   
0225  ! ------------------------------------------------------------------------------
0226  !   Action processing
0227  ! ------------------------------------------------------------------------------
0228   
0229  Global action;                      ! Action currently being asked to perform
0230  Global inp1;                        ! 0 (nothing), 1 (number) or first noun
0231  Global inp2;                        ! 0 (nothing), 1 (number) or second noun
0232  Global noun;                        ! First noun or numerical value
0233  Global second;                      ! Second noun or numerical value
0234   
0235  Global keep_silent;                 ! If true, attempt to perform the action silently (e.g. for
0236                                      ! implicit takes, implicit opening of unlocked doors)
0237   
0238  Global reason_code;                 ! Reason for calling a "life" rule
0239                                      ! (an action or fake such as ##Kiss)
0240   
0241  Global receive_action;              ! Either ##PutOn or ##Insert, whichever is action being tried
0242                                      ! when an object's "before" rule is checking "Receive"
0243   
0244  ! ==============================================================================
0245  !   Parser variables: first, for communication to the parser
0246  ! ------------------------------------------------------------------------------
0247   
0248  Global parser_trace = 0;            ! Set this to 1 to make the parser trace tokens and lines
0249  Global parser_action;               ! For the use of the parser when calling
0250  Global parser_one;                  ! user-supplied routines
0251  Global parser_two;                  !
0252  Array  inputobjs       --> 16;      ! For parser to write its results in
0253  Global parser_inflection;           ! A property (usually "name") to find object names in
0254   
0255  ! ------------------------------------------------------------------------------
0256  !   Parser output
0257  ! ------------------------------------------------------------------------------
0258   
0259  Global actor;                       ! Person asked to do something
0260  Global actors_location;             ! Like location, but for the actor
0261  Global meta;                        ! Verb is a meta-command (such as "save")
0262   
0263  Array  multiple_object --> 64;      ! List of multiple parameters
0264  Global multiflag;                   ! Multiple-object flag passed to actions
0265                                      ! Also used to prevent misleading MULTI_PE
0266  Global toomany_flag;                ! Flag for "multiple match too large"
0267                                      ! (e.g. if "take all" took over 100 things)
0268   
0269  Global special_word;                ! Dictionary address for "special" token
0270  Global special_number;              ! Number typed for "special" token
0271  Global parsed_number;               ! For user-supplied parsing routines
0272  Global consult_from;                ! Word that a "consult" topic starts on
0273  Global consult_words;               ! ...and number of words in topic
0274   
0275  ! ------------------------------------------------------------------------------
0276  !   Implicit taking
0277  ! ------------------------------------------------------------------------------
0278   
0279  Global notheld_mode;                ! To do with implicit taking
0280  Global onotheld_mode;               !     "old copy of notheld_mode", ditto
0281  Global not_holding;                 ! Object to be automatically taken as an
0282                                      ! implicit command
0283  Array  kept_results --> 16;         ! Delayed command (while the take happens)
0284   
0285  ! ------------------------------------------------------------------------------
0286  !   Error numbers when parsing a grammar line
0287  ! ------------------------------------------------------------------------------
0288   
0289  Global etype;                       ! Error number on current line
0290  Global best_etype;                  ! Preferred error number so far
0291  Global nextbest_etype;              ! Preferred one, if ASKSCOPE_PE disallowed
0292   
0293  Constant STUCK_PE     = 1;
0294  Constant UPTO_PE      = 2;
0295  Constant NUMBER_PE    = 3;
0296  Constant CANTSEE_PE   = 4;
0297  Constant TOOLIT_PE    = 5;
0298  Constant NOTHELD_PE   = 6;
0299  Constant MULTI_PE     = 7;
0300  Constant MMULTI_PE    = 8;
0301  Constant VAGUE_PE     = 9;
0302  Constant EXCEPT_PE    = 10;
0303  Constant ANIMA_PE     = 11;
0304  Constant VERB_PE      = 12;
0305  Constant SCENERY_PE   = 13;
0306  Constant ITGONE_PE    = 14;
0307  Constant JUNKAFTER_PE = 15;
0308  Constant TOOFEW_PE    = 16;
0309  Constant NOTHING_PE   = 17;
0310  Constant ASKSCOPE_PE  = 18;
0311   
0312  ! ------------------------------------------------------------------------------
0313  !   Pattern-matching against a single grammar line
0314  ! ------------------------------------------------------------------------------
0315   
0316  Array pattern --> 32;               ! For the current pattern match
0317  Global pcount;                      ! and a marker within it
0318  Array pattern2 --> 32;              ! And another, which stores the best match
0319  Global pcount2;                     ! so far
0320  Constant PATTERN_NULL = $ffff;      ! Entry for a token producing no text
0321   
0322  Array  line_ttype-->32;             ! For storing an analysed grammar line
0323  Array  line_tdata-->32;
0324  Array  line_token-->32;
0325   
0326  Global parameters;                  ! Parameters (objects) entered so far
0327  Global nsns;                        ! Number of special_numbers entered so far
0328  Global special_number1;             ! First number, if one was typed
0329  Global special_number2;             ! Second number, if two were typed
0330   
0331  ! ------------------------------------------------------------------------------
0332  !   Inferences and looking ahead
0333  ! ------------------------------------------------------------------------------
0334   
0335  Global params_wanted;               ! Number of parameters needed (which may change in parsing)
0336   
0337  Global inferfrom;                   ! The point from which the rest of the command must be inferred
0338  Global inferword;                   ! And the preposition inferred
0339  Global dont_infer;                  ! Another dull flag
0340   
0341  Global action_to_be;                ! (If the current line were accepted.)
0342  Global action_reversed;             ! (Parameters would be reversed in order.)
0343  Global advance_warning;             ! What a later-named thing will be
0344   
0345  ! ------------------------------------------------------------------------------
0346  !   At the level of individual tokens now
0347  ! ------------------------------------------------------------------------------
0348   
0349  Global found_ttype;                 ! Used to break up tokens into type
0350  Global found_tdata;                 ! and data (by AnalyseToken)
0351  Global token_filter;                ! For noun filtering by user routines
0352   
0353  Global length_of_noun;              ! Set by NounDomain to no of words in noun
0354   
0355  #Ifdef TARGET_ZCODE;
0356  Constant REPARSE_CODE = 10000;      ! Signals "reparse the text" as a reply from NounDomain
0357  #Ifnot; ! TARGET_GLULX
0358  Constant REPARSE_CODE = $40000000;  ! The parser rather gunkily adds addresses to REPARSE_CODE for
0359                                      ! some purposes. And expects the result to be greater than
0360                                      ! REPARSE_CODE (signed comparison). So Glulx Inform is limited
0361                                      ! to a single gigabyte of storage, for the moment.
0362  #Endif; ! TARGET_
0363   
0364  Global lookahead;                   ! The token after the one now being matched
0365   
0366  Global multi_mode;                  ! Multiple mode
0367  Global multi_wanted;                ! Number of things needed in multitude
0368  Global multi_had;                   ! Number of things actually found
0369  Global multi_context;               ! What token the multi-obj was accepted for
0370   
0371  Global indef_mode;                  ! "Indefinite" mode - ie, "take a brick"
0372                                      ! is in this mode
0373  Global indef_type;                  ! Bit-map holding types of specification
0374  Global indef_wanted;                ! Number of items wanted (100 for all)
0375  Global indef_guess_p;               ! Plural-guessing flag
0376  Global indef_owner;                 ! Object which must hold these items
0377  Global indef_cases;                 ! Possible gender and numbers of them
0378  Global indef_possambig;             ! Has a possibly dangerous assumption
0379                                      ! been made about meaning of a descriptor?
0380  Global indef_nspec_at;              ! Word at which a number like "two" was parsed
0381                                      ! (for backtracking)
0382  Global allow_plurals;               ! Whether plurals presently allowed or not
0383   
0384  Global take_all_rule;               ! Slightly different rules apply to "take all" than other uses
0385                                      ! of multiple objects, to make adjudication produce more
0386                                      ! pragmatically useful results
0387                                      ! (Not a flag: possible values 0, 1, 2)
0388   
0389  Global dict_flags_of_noun;          ! Of the noun currently being parsed
0390                                      ! (a bitmap in #dict_par1 format)
0391  Global pronoun_word;                ! Records which pronoun ("it", "them", ...) caused an error
0392  Global pronoun_obj;                 ! And what obj it was thought to refer to
0393  Global pronoun__word;               ! Saved value
0394  Global pronoun__obj;                ! Saved value
0395   
0396  ! ------------------------------------------------------------------------------
0397  !   Searching through scope and parsing "scope=Routine" grammar tokens
0398  ! ------------------------------------------------------------------------------
0399   
0400  Constant PARSING_REASON       = 0;  ! Possible reasons for searching scope
0401  Constant TALKING_REASON       = 1;
0402  Constant EACH_TURN_REASON     = 2;
0403  Constant REACT_BEFORE_REASON  = 3;
0404  Constant REACT_AFTER_REASON   = 4;
0405  Constant LOOPOVERSCOPE_REASON = 5;
0406  Constant TESTSCOPE_REASON     = 6;
0407   
0408  Global scope_reason = PARSING_REASON; ! Current reason for searching scope
0409   
0410  Global scope_token;                 ! For "scope=Routine" grammar tokens
0411  Global scope_error;
0412  Global scope_stage;                 ! 1, 2 then 3
0413   
0414  Global ats_flag = 0;                ! For AddToScope routines
0415  Global ats_hls;                     !
0416   
0417  Global placed_in_flag;              ! To do with PlaceInScope
0418   
0419  ! ------------------------------------------------------------------------------
0420  !   The match list of candidate objects for a given token
0421  ! ------------------------------------------------------------------------------
0422   
0423  Constant MATCH_LIST_SIZE = 128;
0424  Array  match_list    --> 64;        ! An array of matched objects so far
0425  Array  match_classes --> 64;        ! An array of equivalence classes for them
0426  Array  match_scores --> 64;         ! An array of match scores for them
0427  Global number_matched;              ! How many items in it?  (0 means none)
0428  Global number_of_classes;           ! How many equivalence classes?
0429  Global match_length;                ! How many words long are these matches?
0430  Global match_from;                  ! At what word of the input do they begin?
0431  Global bestguess_score;             ! What did the best-guess object score?
0432   
0433  ! ------------------------------------------------------------------------------
0434  !   Low level textual manipulation
0435  ! ------------------------------------------------------------------------------
0436   
0437  #Ifdef TARGET_ZCODE;
0438   
0439  Constant INPUT_BUFFER_LEN = 120;    ! Length of buffer array (although we leave an extra byte
0440                                      ! to allow for interpreter bugs)
0441   
0442  Array  buffer    -> 123;            ! Buffer for parsing main line of input
0443  #Ifdef VN_1630;
0444  Array  parse     buffer 63;         ! Parse table mirroring it
0445  Array  parse2    buffer 63;         !
0446  #Ifnot;
0447  Array  parse     -> 65;             ! Parse table mirroring it
0448  Array  parse2    -> 65;             !
0449  #Endif; ! VN_
0450  Array  buffer2   -> 123;            ! Buffers for supplementary questions
0451  Array  buffer3   -> 123;            ! Buffer retaining input for "again"
0452   
0453  #Ifnot; ! TARGET_GLULX
0454   
0455  Constant INPUT_BUFFER_LEN = 260;    ! No extra byte necessary
0456  Constant MAX_BUFFER_WORDS = 20;
0457  Constant PARSE_BUFFER_LEN = 244;    ! 4 + MAX_BUFFER_WORDS*4;
0458   
0459  #Ifdef VN_1630;
0460  Array  buffer    buffer INPUT_BUFFER_LEN;
0461  Array  buffer2   buffer INPUT_BUFFER_LEN;
0462  Array  buffer3   buffer INPUT_BUFFER_LEN;
0463  #Ifnot;
0464  Array  buffer    -> INPUT_BUFFER_LEN;
0465  Array  buffer2   -> INPUT_BUFFER_LEN;
0466  Array  buffer3   -> INPUT_BUFFER_LEN;
0467  #Endif;
0468  Array  parse     --> PARSE_BUFFER_LEN/WORDSIZE;
0469  Array  parse2    --> PARSE_BUFFER_LEN/WORDSIZE;
0470   
0471  #Endif; ! TARGET_
0472   
0473  Constant comma_word = 'comma,';     ! An "untypeable word" used to substitute
0474                                      ! for commas in parse buffers
0475   
0476  Global wn;                          ! Word number within "parse" (from 1)
0477  Global num_words;                   ! Number of words typed
0478  Global verb_word;                   ! Verb word (eg, take in "take all" or
0479                                      ! "dwarf, take all") - address in dict
0480  Global verb_wordnum;                ! its number in typing order (eg, 1 or 3)
0481  Global usual_grammar_after;         ! Point from which usual grammar is parsed (it may vary from the
0482                                      ! above if user's routines match multi-word verbs)
0483   
0484  Global oops_from;                   ! The "first mistake" word number
0485  Global saved_oops;                  ! Used in working this out
0486  Array  oops_workspace -> 64;        ! Used temporarily by "oops" routine
0487   
0488  Global held_back_mode;              ! Flag: is there some input from last time
0489  Global hb_wn;                       ! left over?  (And a save value for wn.)
0490                                      ! (Used for full stops and "then".)
0491   
0492  ! ----------------------------------------------------------------------------
0493   
0494  Array PowersOfTwo_TB                ! Used in converting case numbers to case bitmaps
0495    --> $$100000000000
0496        $$010000000000
0497        $$001000000000
0498        $$000100000000
0499        $$000010000000
0500        $$000001000000
0501        $$000000100000
0502        $$000000010000
0503        $$000000001000
0504        $$000000000100
0505        $$000000000010
0506        $$000000000001;
0507   
0508  ! ============================================================================
0509  !  Constants, and one variable, needed for the language definition file
0510  ! ----------------------------------------------------------------------------
0511   
0512  Constant POSSESS_PK  = $100;
0513  Constant DEFART_PK   = $101;
0514  Constant INDEFART_PK = $102;
0515  Global short_name_case;
0516   
0517  Global dict_start;
0518  Global dict_entry_size;
0519  Global dict_end;
0520   
0521  ! ----------------------------------------------------------------------------
0522   
0523  Include "language__";               ! The natural language definition, whose filename is taken from
0524                                      ! the ICL language_name variable
0525   
0526  ! ----------------------------------------------------------------------------
0527   
0528  #Ifndef LanguageCases;
0529  Constant LanguageCases = 1;
0530  #Endif; ! LanguageCases
0531   
0532  ! ------------------------------------------------------------------------------
0533  !   Pronouns support for the cruder (library 6/2 and earlier) version:
0534  !   only needed in English
0535  ! ------------------------------------------------------------------------------
0536   
0537  #Ifdef EnglishNaturalLanguage;
0538  Global itobj = NULL;                ! The object which is currently "it"
0539  Global himobj = NULL;               ! The object which is currently "him"
0540  Global herobj = NULL;               ! The object which is currently "her"
0541   
0542  Global old_itobj = NULL;            ! The object which is currently "it"
0543  Global old_himobj = NULL;           ! The object which is currently "him"
0544  Global old_herobj = NULL;           ! The object which is currently "her"
0545  #Endif; ! EnglishNaturalLanguage
0546   
0547  ! ============================================================================
0548  ! "Darkness" is not really a place: but it has to be an object so that the
0549  !  location-name on the status line can be "Darkness".
0550  ! ----------------------------------------------------------------------------
0551   
0552  Object  thedark "(darkness object)"
0553    with  initial 0,
0554          short_name DARKNESS__TX,
0555          description [;  return L__M(##Miscellany, 17); ];
0556   
0557  Object  selfobj "(self object)"
0558    with  short_name  [;  return L__M(##Miscellany, 18); ],
0559          description [;  return L__M(##Miscellany, 19); ],
0560          before NULL,
0561          after NULL,
0562          life NULL,
0563          each_turn NULL,
0564          time_out NULL,
0565          describe NULL,
0566          add_to_scope 0,
0567          capacity 100,
0568          parse_name 0,
0569          orders 0,
0570          number 0,
0571          before_implicit NULL,
0572    has   concealed animate proper transparent;
0573   
0574  ! ============================================================================
0575  !  The definition of the token-numbering system used by Inform.
0576  ! ----------------------------------------------------------------------------
0577   
0578  Constant ILLEGAL_TT         = 0;    ! Types of grammar token: illegal
0579  Constant ELEMENTARY_TT      = 1;    !     (one of those below)
0580  Constant PREPOSITION_TT     = 2;    !     e.g. 'into'
0581  Constant ROUTINE_FILTER_TT  = 3;    !     e.g. noun=CagedCreature
0582  Constant ATTR_FILTER_TT     = 4;    !     e.g. edible
0583  Constant SCOPE_TT           = 5;    !     e.g. scope=Spells
0584  Constant GPR_TT             = 6;    !     a general parsing routine
0585   
0586  Constant NOUN_TOKEN         = 0;    ! The elementary grammar tokens, and
0587  Constant HELD_TOKEN         = 1;    ! the numbers compiled by Inform to
0588  Constant MULTI_TOKEN        = 2;    ! encode them
0589  Constant MULTIHELD_TOKEN    = 3;
0590  Constant MULTIEXCEPT_TOKEN  = 4;
0591  Constant MULTIINSIDE_TOKEN  = 5;
0592  Constant CREATURE_TOKEN     = 6;
0593  Constant SPECIAL_TOKEN      = 7;
0594  Constant NUMBER_TOKEN       = 8;
0595  Constant TOPIC_TOKEN        = 9;
0596   
0597   
0598  Constant GPR_FAIL           = -1;   ! Return values from General Parsing
0599  Constant GPR_PREPOSITION    = 0;    ! Routines
0600  Constant GPR_NUMBER         = 1;
0601  Constant GPR_MULTIPLE       = 2;
0602  Constant GPR_REPARSE        = REPARSE_CODE;
0603  Constant GPR_NOUN           = $ff00;
0604  Constant GPR_HELD           = $ff01;
0605  Constant GPR_MULTI          = $ff02;
0606  Constant GPR_MULTIHELD      = $ff03;
0607  Constant GPR_MULTIEXCEPT    = $ff04;
0608  Constant GPR_MULTIINSIDE    = $ff05;
0609  Constant GPR_CREATURE       = $ff06;
0610   
0611  Constant ENDIT_TOKEN        = 15;   ! Value used to mean "end of grammar line"
0612   
0613  #Iftrue (Grammar__Version == 1);
0614   
0615  [ AnalyseToken token m;
0616      found_tdata = token;
0617      if (token < 0)   { found_ttype = ILLEGAL_TT; return; }
0618      if (token <= 8)  { found_ttype = ELEMENTARY_TT; return; }
0619      if (token < 15)  { found_ttype = ILLEGAL_TT; return; }
0620      if (token == 15) { found_ttype = ELEMENTARY_TT; return; }
0621      if (token < 48)  { found_ttype = ROUTINE_FILTER_TT;
0622                         found_tdata = token - 16;
0623                         return;
0624      }
0625      if (token < 80)  { found_ttype = GPR_TT;
0626                         found_tdata = #preactions_table-->(token-48);
0627                         return;
0628      }
0629      if (token < 128) { found_ttype = SCOPE_TT;
0630                         found_tdata = #preactions_table-->(token-80);
0631                         return;
0632      }
0633      if (token < 180) { found_ttype = ATTR_FILTER_TT;
0634                         found_tdata = token - 128;
0635                         return;
0636      }
0637   
0638      found_ttype = PREPOSITION_TT;
0639      m = #adjectives_table;
0640      for (::) {
0641          if (token == m-->1) { found_tdata = m-->0; return; }
0642          m = m+4;
0643      }
0644      m = #adjectives_table; RunTimeError(1);
0645      found_tdata = m;
0646  ];
0647   
0648  [ UnpackGrammarLine line_address i m;
0649      for (i=0 : i<32 : i++) {
0650          line_token-->i = ENDIT_TOKEN;
0651          line_ttype-->i = ELEMENTARY_TT;
0652          line_tdata-->i = ENDIT_TOKEN;
0653      }
0654      for (i=0 : i<=5 : i++) {
0655          line_token-->i = line_address->(i+1);
0656          AnalyseToken(line_token-->i);
0657          if ((found_ttype == ELEMENTARY_TT) && (found_tdata == NOUN_TOKEN)
0658             && (m == line_address->0)) {
0659              line_token-->i = ENDIT_TOKEN;
0660              break;
0661          }
0662          line_ttype-->i = found_ttype;
0663          line_tdata-->i = found_tdata;
0664          if (found_ttype ~= PREPOSITION_TT) m++;
0665      }
0666      action_to_be = line_address->7;
0667      action_reversed = false;
0668      params_wanted = line_address->0;
0669      return line_address + 8;
0670  ];
0671   
0672  #Ifnot; ! Grammar__Version == 2
0673   
0674  [ AnalyseToken token;
0675      if (token == ENDIT_TOKEN) {
0676          found_ttype = ELEMENTARY_TT;
0677          found_tdata = ENDIT_TOKEN;
0678          return;
0679      }
0680      found_ttype = (token->0) & $$1111;
0681      found_tdata = (token+1)-->0;
0682  ];
0683   
0684  #Ifdef TARGET_ZCODE;
0685   
0686  [ UnpackGrammarLine line_address i;
0687      for (i=0 : i<32 : i++) {
0688          line_token-->i = ENDIT_TOKEN;
0689          line_ttype-->i = ELEMENTARY_TT;
0690          line_tdata-->i = ENDIT_TOKEN;
0691      }
0692      action_to_be = 256*(line_address->0) + line_address->1;
0693      action_reversed = ((action_to_be & $400) ~= 0);
0694      action_to_be = action_to_be & $3ff;
0695      line_address--;
0696      params_wanted = 0;
0697      for (i=0 : : i++) {
0698          line_address = line_address + 3;
0699          if (line_address->0 == ENDIT_TOKEN) break;
0700          line_token-->i = line_address;
0701          AnalyseToken(line_address);
0702          if (found_ttype ~= PREPOSITION_TT) params_wanted++;
0703          line_ttype-->i = found_ttype;
0704          line_tdata-->i = found_tdata;
0705      }
0706      return line_address + 1;
0707  ];
0708   
0709  #Ifnot; ! TARGET_GLULX
0710   
0711  [ UnpackGrammarLine line_address i;
0712      for (i=0 : i<32 : i++) {
0713          line_token-->i = ENDIT_TOKEN;
0714          line_ttype-->i = ELEMENTARY_TT;
0715          line_tdata-->i = ENDIT_TOKEN;
0716      }
0717      @aloads line_address 0 action_to_be;
0718      action_reversed = (((line_address->2) & 1) ~= 0);
0719      line_address = line_address - 2;
0720      params_wanted = 0;
0721      for (i=0 : : i++) {
0722          line_address = line_address + 5;
0723          if (line_address->0 == ENDIT_TOKEN) break;
0724          line_token-->i = line_address;
0725          AnalyseToken(line_address);
0726          if (found_ttype ~= PREPOSITION_TT) params_wanted++;
0727          line_ttype-->i = found_ttype;
0728          line_tdata-->i = found_tdata;
0729      }
0730      return line_address + 1;
0731  ];
0732   
0733  #Endif; ! TARGET_
0734  #Endif; ! Grammar__Version
0735   
0736  ! To protect against a bug in early versions of the "Zip" interpreter:
0737  ! Of course, in Glulx, this routine actually performs work.
0738   
0739  #Ifdef TARGET_ZCODE;
0740   
0741  [ Tokenise__ b p; b->(2 + b->1) = 0; @tokenise b p; ];
0742   
0743  #Ifnot; ! TARGET_GLULX
0744   
0745  Array gg_tokenbuf -> DICT_WORD_SIZE;
0746   
0747  [ GGWordCompare str1 str2 ix jx;
0748      for (ix=0 : ix<DICT_WORD_SIZE : ix++) {
0749          jx = (str1->ix) - (str2->ix);
0750          if (jx ~= 0) return jx;
0751      }
0752      return 0;
0753  ];
0754   
0755  [ Tokenise__ buf tab
0756      cx numwords len bx ix wx wpos wlen val res dictlen entrylen;
0757      len = buf-->0;
0758      buf = buf+WORDSIZE;
0759   
0760      ! First, split the buffer up into words. We use the standard Infocom
0761      ! list of word separators (comma, period, double-quote).
0762   
0763      cx = 0;
0764      numwords = 0;
0765      while (cx < len) {
0766          while (cx < len && buf->cx == ' ') cx++;
0767          if (cx >= len) break;
0768          bx = cx;
0769          if (buf->cx == '.' or ',' or '"') cx++;
0770          else {
0771              while (cx < len && buf->cx ~= ' ' or '.' or ',' or '"') cx++;
0772          }
0773          tab-->(numwords*3+2) = (cx-bx);
0774          tab-->(numwords*3+3) = WORDSIZE+bx;
0775          numwords++;
0776          if (numwords >= MAX_BUFFER_WORDS) break;
0777      }
0778      tab-->0 = numwords;
0779   
0780      ! Now we look each word up in the dictionary.
0781   
0782      dictlen = #dictionary_table-->0;
0783      entrylen = DICT_WORD_SIZE + 7;
0784   
0785      for (wx=0 : wx<numwords : wx++) {
0786          wlen = tab-->(wx*3+2);
0787          wpos = tab-->(wx*3+3);
0788   
0789          ! Copy the word into the gg_tokenbuf array, clipping to DICT_WORD_SIZE
0790          ! characters and lower case.
0791          if (wlen > DICT_WORD_SIZE) wlen = DICT_WORD_SIZE;
0792          cx = wpos - WORDSIZE;
0793          for (ix=0 : ix<wlen : ix++) gg_tokenbuf->ix = glk($00A0, buf->(cx+ix));
0794          for (: ix<DICT_WORD_SIZE : ix++) gg_tokenbuf->ix = 0;
0795   
0796          val = #dictionary_table + WORDSIZE;
0797          @binarysearch gg_tokenbuf DICT_WORD_SIZE val entrylen dictlen 1 1 res;
0798          tab-->(wx*3+1) = res;
0799      }
0800  ];
0801   
0802  #Endif; ! TARGET_
0803   
0804  ! ============================================================================
0805  !   The InformParser object abstracts the front end of the parser.
0806  !
0807  !   InformParser.parse_input(results)
0808  !   returns only when a sensible request has been made, and puts into the
0809  !   "results" buffer:
0810  !
0811  !   --> 0 = The action number
0812  !   --> 1 = Number of parameters
0813  !   --> 2, 3, ... = The parameters (object numbers), but
0814  !                   0 means "put the multiple object list here"
0815  !                   1 means "put one of the special numbers here"
0816  !
0817  ! ----------------------------------------------------------------------------
0818   
0819  Object  InformParser "(Inform Parser)"
0820    with  parse_input [ results; Parser__parse(results); ],
0821    has   proper;
0822   
0823  ! ----------------------------------------------------------------------------
0824  !   The Keyboard routine actually receives the player's words,
0825  !   putting the words in "a_buffer" and their dictionary addresses in
0826  !   "a_table".  It is assumed that the table is the same one on each
0827  !   (standard) call.
0828  !
0829  !   It can also be used by miscellaneous routines in the game to ask
0830  !   yes-no questions and the like, without invoking the rest of the parser.
0831  !
0832  !   Return the number of words typed
0833  ! ----------------------------------------------------------------------------
0834   
0835  #Ifdef TARGET_ZCODE;
0836   
0837  [ KeyboardPrimitive  a_buffer a_table;
0838      read a_buffer a_table;
0839   
0840      #Iftrue (#version_number == 6);
0841      @output_stream -1;
0842      @loadb a_buffer 1 -> sp;
0843      @add a_buffer 2 -> sp;
0844      @print_table sp sp;
0845      new_line;
0846      @output_stream 1;
0847      #Endif;
0848  ];
0849   
0850  [ KeyCharPrimitive win  key;
0851      if (win) @set_window win;
0852      @read_char 1 -> key;
0853      return key;
0854  ];
0855   
0856  [ KeyTimerInterrupt;
0857      rtrue;
0858  ];
0859   
0860  [ KeyDelay tenths  key;
0861      @read_char 1 tenths KeyTimerInterrupt -> key;
0862      return key;
0863  ];
0864   
0865  #Ifnot; ! TARGET_GLULX
0866   
0867  [ KeyCharPrimitive win nostat done res ix jx ch;
0868      jx = ch; ! squash compiler warnings
0869      if (win == 0) win = gg_mainwin;
0870      if (gg_commandstr ~= 0 && gg_command_reading ~= false) {
0871          ! get_line_stream
0872          done = glk($0091, gg_commandstr, gg_arguments, 31);
0873          if (done == 0) {
0874              glk($0044, gg_commandstr, 0); ! stream_close
0875              gg_commandstr = 0;
0876              gg_command_reading = false;
0877              ! fall through to normal user input.
0878          }
0879          else {
0880              ! Trim the trailing newline
0881              if (gg_arguments->(done-1) == 10) done = done-1;
0882              res = gg_arguments->0;
0883              if (res == '\') {
0884                  res = 0