Inform - Support - Source

Back to List

Inventory
Complete

Backward
Forward

Plain
Coloured
Gaudy

This code
in plain text

Browsing parserm.h

Parser__parse (lines 732-1451)

0732  !  To simplify the picture a little, a rough map of the main routine:
0733  !
0734  !  (A)    Get the input, do "oops" and "again"
0735  !  (B)    Is it a direction, and so an implicit "go"?  If so go to (K)
0736  !  (C)    Is anyone being addressed?
0737  !  (D)    Get the verb: try all the syntax lines for that verb
0738  !  (E)    Break down a syntax line into analysed tokens
0739  !  (F)    Look ahead for advance warning for multiexcept/multiinside
0740  !  (G)    Parse each token in turn (calling ParseToken to do most of the work)
0741  !  (H)    Cheaply parse otherwise unrecognised conversation and return
0742  !  (I)    Print best possible error message
0743  !  (J)    Retry the whole lot
0744  !  (K)    Last thing: check for "then" and further instructions(s), return.
0745  !
0746  !  The strategic points (A) to (K) are marked in the commentary.
0747  !
0748  !  Note that there are three different places where a return can happen.
0749  ! ----------------------------------------------------------------------------
0750   
0751  [ Parser__parse  results   syntax line num_lines line_address i j k
0752                             token l m;
0753   
0754  !  **** (A) ****
0755   
0756  !  Firstly, in "not held" mode, we still have a command left over from last
0757  !  time (eg, the user typed "eat biscuit", which was parsed as "take biscuit"
0758  !  last time, with "eat biscuit" tucked away until now).  So we return that.
0759   
0760      if (notheld_mode==1)
0761      {   for (i=0:i<8:i++) results-->i=kept_results-->i;
0762          notheld_mode=0; rtrue;
0763      }
0764   
0765      if (held_back_mode==1)
0766      {   held_back_mode=0;
0767          Tokenise__(buffer,parse);
0768          jump ReParse;
0769      }
0770   
0771    .ReType;
0772   
0773      Keyboard(buffer,parse);
0774   
0775    .ReParse;
0776   
0777      parser_inflection = name;
0778   
0779  !  Initially assume the command is aimed at the player, and the verb
0780  !  is the first word
0781   
0782      num_words=parse->1;
0783      wn=1;
0784  #ifdef LanguageToInformese;
0785      LanguageToInformese();
0786  #ifv5;
0787  !   Re-tokenise:
0788      Tokenise__(buffer,parse);
0789  #endif;
0790  #endif;
0791   
0792      BeforeParsing();
0793      num_words=parse->1;
0794   
0795      k=0;
0796  #ifdef DEBUG;
0797      if (parser_trace>=2)
0798      {   print "[ ";
0799          for (i=0:i<num_words:i++)
0800          {   j=parse-->(i*2 + 1);
0801              k=WordAddress(i+1);
0802              l=WordLength(i+1);
0803              print "~"; for (m=0:m<l:m++) print (char) k->m; print "~ ";
0804   
0805              if (j == 0) print "?";
0806              else
0807              {   if (UnsignedCompare(j, 0-->4)>=0
0808                      && UnsignedCompare(j, 0-->2)<0) print (address) j;
0809                  else print j;
0810              }
0811              if (i ~= num_words-1) print " / ";
0812          }
0813          print " ]^";
0814      }
0815  #endif;
0816      verb_wordnum=1;
0817      actor=player;
0818      actors_location = ScopeCeiling(player);
0819      usual_grammar_after = 0;
0820   
0821    .AlmostReParse;
0822   
0823      scope_token = 0;
0824      action_to_be = NULL;
0825   
0826  !  Begin from what we currently think is the verb word
0827   
0828    .BeginCommand;
0829      wn=verb_wordnum;
0830      verb_word = NextWordStopped();
0831   
0832  !  If there's no input here, we must have something like
0833  !  "person,".
0834   
0835      if (verb_word==-1)
0836      {   best_etype = STUCK_PE; jump GiveError; }
0837   
0838  !  Now try for "again" or "g", which are special cases:
0839  !  don't allow "again" if nothing has previously been typed;
0840  !  simply copy the previous text across
0841   
0842      if (verb_word==AGAIN2__WD or AGAIN3__WD) verb_word=AGAIN1__WD;
0843      if (verb_word==AGAIN1__WD)
0844      {   if (actor~=player)
0845          {   L__M(##Miscellany,20); jump ReType; }
0846          if (buffer3->1==0)
0847          {   L__M(##Miscellany,21); jump ReType; }
0848          for (i=0:i<120:i++) buffer->i=buffer3->i;
0849          jump ReParse;
0850      }
0851   
0852  !  Save the present input in case of an "again" next time
0853   
0854      if (verb_word~=AGAIN1__WD)
0855          for (i=0:i<120:i++) buffer3->i=buffer->i;
0856   
0857      if (usual_grammar_after==0)
0858      {   i = RunRoutines(actor, grammar);
0859          #ifdef DEBUG;
0860          if (parser_trace>=2 && actor.grammar~=0 or NULL)
0861              print " [Grammar property returned ", i, "]^";
0862          #endif;
0863          if (i<0) { usual_grammar_after = verb_wordnum; i=-i; }
0864          if (i==1)
0865          {   results-->0 = action;
0866              results-->1 = noun;
0867              results-->2 = second;
0868              rtrue;
0869          }
0870          if (i~=0) { verb_word = i; wn--; verb_wordnum--; }
0871          else
0872          {   wn = verb_wordnum; verb_word=NextWord();
0873          }
0874      }
0875      else usual_grammar_after=0;
0876   
0877  !  **** (B) ****
0878   
0879      #ifdef LanguageIsVerb;
0880      if (verb_word==0)
0881      {   i = wn; verb_word=LanguageIsVerb(buffer, parse, verb_wordnum);
0882          wn = i;
0883      }
0884      #endif;
0885   
0886  !  If the first word is not listed as a verb, it must be a direction
0887  !  or the name of someone to talk to
0888   
0889      if (verb_word==0 || ((verb_word->#dict_par1) & 1) == 0)
0890      {   
0891   
0892  !  So is the first word an object contained in the special object "compass"
0893  !  (i.e., a direction)?  This needs use of NounDomain, a routine which
0894  !  does the object matching, returning the object number, or 0 if none found,
0895  !  or REPARSE_CODE if it has restructured the parse table so the whole parse
0896  !  must be begun again...
0897   
0898          wn=verb_wordnum; indef_mode = false; token_filter = 0;
0899          l=NounDomain(compass,0,0); if (l==REPARSE_CODE) jump ReParse;
0900   
0901  !  If it is a direction, send back the results:
0902  !  action=GoSub, no of arguments=1, argument 1=the direction.
0903   
0904          if (l~=0)
0905          {   results-->0 = ##Go;
0906              action_to_be = ##Go;
0907              results-->1 = 1;
0908              results-->2 = l;
0909              jump LookForMore;
0910          }
0911   
0912  !  **** (C) ****
0913   
0914  !  Only check for a comma (a "someone, do something" command) if we are
0915  !  not already in the middle of one.  (This simplification stops us from
0916  !  worrying about "robot, wizard, you are an idiot", telling the robot to
0917  !  tell the wizard that she is an idiot.)
0918   
0919          if (actor==player)
0920          {   for (j=2:j<=num_words:j++)
0921              {   i=NextWord(); if (i==comma_word) jump Conversation;
0922              }
0923   
0924              verb_word=UnknownVerb(verb_word);
0925              if (verb_word~=0) jump VerbAccepted;
0926          }
0927   
0928          best_etype=VERB_PE; jump GiveError;
0929   
0930  !  NextWord nudges the word number wn on by one each time, so we've now
0931  !  advanced past a comma.  (A comma is a word all on its own in the table.)
0932   
0933        .Conversation;
0934          j=wn-1;
0935          if (j==1) { L__M(##Miscellany,22); jump ReType; }
0936   
0937  !  Use NounDomain (in the context of "animate creature") to see if the
0938  !  words make sense as the name of someone held or nearby
0939   
0940          wn=1; lookahead=HELD_TOKEN;
0941          scope_reason = TALKING_REASON;
0942          l=NounDomain(player,actors_location,6);
0943          scope_reason = PARSING_REASON;
0944          if (l==REPARSE_CODE) jump ReParse;
0945   
0946          if (l==0) { L__M(##Miscellany,23); jump ReType; }
0947   
0948  !  The object addressed must at least be "talkable" if not actually "animate"
0949  !  (the distinction allows, for instance, a microphone to be spoken to,
0950  !  without the parser thinking that the microphone is human).
0951   
0952          if (l hasnt animate && l hasnt talkable)
0953          {   L__M(##Miscellany, 24, l); jump ReType; }
0954   
0955  !  Check that there aren't any mystery words between the end of the person's
0956  !  name and the comma (eg, throw out "dwarf sdfgsdgs, go north").
0957   
0958          if (wn~=j)
0959          {   L__M(##Miscellany, 25); jump ReType; }
0960   
0961  !  The player has now successfully named someone.  Adjust "him", "her", "it":
0962   
0963          PronounNotice(l);
0964   
0965  !  Set the global variable "actor", adjust the number of the first word,
0966  !  and begin parsing again from there.
0967   
0968          verb_wordnum=j+1;
0969   
0970  !  Stop things like "me, again":
0971   
0972          if (l == player)
0973          {   wn = verb_wordnum;
0974              if (NextWordStopped() == AGAIN1__WD or AGAIN2__WD or AGAIN3__WD)
0975              {   L__M(##Miscellany,20); jump ReType;
0976              }
0977          }
0978   
0979          actor=l;
0980          actors_location=ScopeCeiling(l);
0981          #ifdef DEBUG;
0982          if (parser_trace>=1)
0983              print "[Actor is ", (the) actor, " in ",
0984                  (name) actors_location, "]^";
0985          #endif;
0986          jump BeginCommand;
0987      }
0988   
0989  !  **** (D) ****
0990   
0991     .VerbAccepted;
0992   
0993  !  We now definitely have a verb, not a direction, whether we got here by the
0994  !  "take ..." or "person, take ..." method.  Get the meta flag for this verb:
0995   
0996      meta=((verb_word->#dict_par1) & 2)/2;
0997   
0998  !  You can't order other people to "full score" for you, and so on...
0999   
1000      if (meta==1 && actor~=player)
1001      {   best_etype=VERB_PE; meta=0; jump GiveError; }
1002   
1003  !  Now let i be the corresponding verb number, stored in the dictionary entry
1004  !  (in a peculiar 255-n fashion for traditional Infocom reasons)...
1005   
1006      i=$ff-(verb_word->#dict_par2);
1007   
1008  !  ...then look up the i-th entry in the verb table, whose address is at word
1009  !  7 in the Z-machine (in the header), so as to get the address of the syntax
1010  !  table for the given verb...
1011   
1012      syntax=(0-->7)-->i;
1013   
1014  !  ...and then see how many lines (ie, different patterns corresponding to the
1015  !  same verb) are stored in the parse table...
1016   
1017      num_lines=(syntax->0)-1;
1018   
1019  !  ...and now go through them all, one by one.
1020  !  To prevent pronoun_word 0 being misunderstood,
1021   
1022     pronoun_word=NULL; pronoun_obj=NULL;
1023   
1024     #ifdef DEBUG;
1025     if (parser_trace>=1)
1026     {    print "[Parsing for the verb '", (address) verb_word,
1027                "' (", num_lines+1, " lines)]^";
1028     }
1029     #endif;
1030   
1031     best_etype=STUCK_PE; nextbest_etype=STUCK_PE;
1032   
1033  !  "best_etype" is the current failure-to-match error - it is by default
1034  !  the least informative one, "don't understand that sentence".
1035  !  "nextbest_etype" remembers the best alternative to having to ask a
1036  !  scope token for an error message (i.e., the best not counting ASKSCOPE_PE).
1037   
1038   
1039  !  **** (E) ****
1040   
1041      line_address = syntax + 1;
1042   
1043      for (line=0:line<=num_lines:line++)
1044      {   
1045          for (i = 0 : i < 32 : i++)
1046          {   line_token-->i = ENDIT_TOKEN;
1047              line_ttype-->i = ELEMENTARY_TT;
1048              line_tdata-->i = ENDIT_TOKEN;
1049          }
1050   
1051  !  Unpack the syntax line from Inform format into three arrays; ensure that
1052  !  the sequence of tokens ends in an ENDIT_TOKEN.
1053   
1054          line_address = UnpackGrammarLine(line_address);
1055              
1056          #ifdef DEBUG;
1057          if (parser_trace >= 1)
1058          {   if (parser_trace >= 2) new_line;
1059              print "[line ", line; DebugGrammarLine();
1060              print "]^";
1061          }
1062          #endif;
1063   
1064  !  We aren't in "not holding" or inferring modes, and haven't entered
1065  !  any parameters on the line yet, or any special numbers; the multiple
1066  !  object is still empty.
1067   
1068          not_holding=0;
1069          inferfrom=0;
1070          parameters=0;
1071          nsns=0; special_word=0; special_number=0;
1072          multiple_object-->0 = 0;
1073          multi_context = 0;
1074          etype=STUCK_PE;
1075   
1076  !  Put the word marker back to just after the verb
1077   
1078          wn=verb_wordnum+1;
1079   
1080  !  **** (F) ****
1081  !  There are two special cases where parsing a token now has to be
1082  !  affected by the result of parsing another token later, and these
1083  !  two cases (multiexcept and multiinside tokens) are helped by a quick
1084  !  look ahead, to work out the future token now.  We can only carry this
1085  !  out in the simple (but by far the most common) case:
1086  !
1087  !      multiexcept  noun
1088  !
1089  !  and similarly for multiinside.
1090   
1091          advance_warning = NULL; indef_mode = false;
1092          for (i=0,m=false,pcount=0:line_token-->pcount ~= ENDIT_TOKEN:pcount++)
1093          {   scope_token = 0;
1094   
1095              if (line_ttype-->pcount ~= PREPOSITION_TT) i++;
1096   
1097              if (line_ttype-->pcount == ELEMENTARY_TT)
1098              {   if (line_tdata-->pcount == MULTI_TOKEN) m=true;
1099                  if (line_tdata-->pcount
1100                      == MULTIEXCEPT_TOKEN or MULTIINSIDE_TOKEN  && i==1)
1101                  {   !   First non-preposition is "multiexcept" or
1102                      !   "multiinside", so look ahead.
1103   
1104                      #ifdef DEBUG;
1105                      if (parser_trace>=2) print " [Trying look-ahead]^";
1106                      #endif;
1107   
1108                      !   We need this to be followed by 1 or more prepositions.
1109   
1110                      pcount++;
1111                      if (line_ttype-->pcount == PREPOSITION_TT)
1112                      {   while (line_ttype-->pcount == PREPOSITION_TT)
1113                              pcount++;
1114   
1115                          if ((line_ttype-->pcount == ELEMENTARY_TT)
1116                              && (line_tdata-->pcount == NOUN_TOKEN))
1117                          {
1118                              !  Advance past the last preposition
1119   
1120                              while (wn <= num_words)
1121                              {   if (NextWord() == line_tdata-->(pcount-1))
1122                                  {   l = NounDomain(actors_location, actor,
1123                                              NOUN_TOKEN);
1124                                      #ifdef DEBUG;
1125                                      if (parser_trace>=2)
1126                                      {   print " [Advanced to ~noun~ token: ";
1127                                          if (l==REPARSE_CODE)
1128                                              print "re-parse request]^";
1129                                          if (l==1) print "but multiple found]^";
1130                                          if (l==0) print "error ", etype, "]^";
1131                                          if (l>=2) print (the) l, "]^";
1132                                      }
1133                                      #endif;
1134                                      if (l==REPARSE_CODE) jump ReParse;
1135                                      if (l>=2) advance_warning = l;
1136                                  }
1137                              }
1138                          }
1139                      }
1140                      break;
1141                  }
1142              }
1143          }
1144   
1145  !  Slightly different line-parsing rules will apply to "take multi", to
1146  !  prevent "take all" behaving correctly but misleadingly when there's
1147  !  nothing to take.
1148   
1149          take_all_rule = 0;
1150          if (m && params_wanted==1 && action_to_be==##Take)
1151              take_all_rule = 1;
1152   
1153  !  And now start again, properly, forearmed or not as the case may be.
1154  !  As a precaution, we clear all the variables again (they may have been
1155  !  disturbed by the call to NounDomain, which may have called outside
1156  !  code, which may have done anything!).
1157   
1158          not_holding=0;
1159          inferfrom=0;
1160          parameters=0;
1161          nsns=0; special_word=0; special_number=0;
1162          multiple_object-->0 = 0;
1163          etype=STUCK_PE;
1164          wn=verb_wordnum+1;
1165   
1166  !  **** (G) ****
1167  !  "Pattern" gradually accumulates what has been recognised so far,
1168  !  so that it may be reprinted by the parser later on
1169   
1170          for (pcount=1::pcount++)
1171          {   pattern-->pcount = PATTERN_NULL; scope_token=0;
1172   
1173              token = line_token-->(pcount-1);
1174              lookahead = line_token-->pcount;
1175   
1176              #ifdef DEBUG;
1177              if (parser_trace >= 2)
1178                 print " [line ", line, " token ", pcount, " word ", wn, " : ",
1179                       (DebugToken) token, "]^";
1180              #endif;
1181   
1182              if (token ~= ENDIT_TOKEN)
1183              {   scope_reason = PARSING_REASON;
1184                  parser_inflection = name;
1185                  AnalyseToken(token);
1186                  l = ParseToken__(found_ttype, found_tdata, pcount-1, token);
1187                  while (l<-200) l = ParseToken__(ELEMENTARY_TT, l + 256);
1188                  scope_reason = PARSING_REASON;
1189   
1190                  if (l==GPR_PREPOSITION)
1191                  {   if (found_ttype~=PREPOSITION_TT
1192                          && (found_ttype~=ELEMENTARY_TT
1193                              || found_tdata~=TOPIC_TOKEN)) params_wanted--;
1194                      l = true;
1195                  }
1196                  else
1197                  if (l<0) l = false;
1198                  else
1199                  if (l~=GPR_REPARSE)
1200                  {   if (l==GPR_NUMBER)
1201                      {   if (nsns==0) special_number1=parsed_number;
1202                          else special_number2=parsed_number;
1203                          nsns++; l = 1;
1204                      }
1205                      if (l==GPR_MULTIPLE) l = 0;
1206                      results-->(parameters+2) = l;
1207                      parameters++;
1208                      pattern-->pcount = l;
1209                      l = true;
1210                  }
1211   
1212                  #ifdef DEBUG;
1213                  if (parser_trace >= 3)
1214                  {   print "  [token resulted in ";
1215                      if (l==REPARSE_CODE) print "re-parse request]^";
1216                      if (l==0) print "failure with error type ", etype, "]^";
1217                      if (l==1) print "success]^";
1218                  }
1219                  #endif;
1220   
1221                  if (l==REPARSE_CODE) jump ReParse;
1222                  if (l==false) break;
1223              }
1224              else
1225              {
1226   
1227  !  If the player has entered enough already but there's still
1228  !  text to wade through: store the pattern away so as to be able to produce
1229  !  a decent error message if this turns out to be the best we ever manage,
1230  !  and in the mean time give up on this line
1231   
1232  !  However, if the superfluous text begins with a comma or "then" then
1233  !  take that to be the start of another instruction
1234   
1235                  if (wn <= num_words)
1236                  {   l=NextWord();
1237                      if (l==THEN1__WD or THEN2__WD or THEN3__WD or comma_word)
1238                      {   held_back_mode=1; hb_wn=wn-1; }
1239                      else
1240                      {   for (m=0:m<32:m++) pattern2-->m=pattern-->m;
1241                          pcount2=pcount;
1242                          etype=UPTO_PE; break;
1243                      }
1244                  }
1245   
1246  !  Now, we may need to revise the multiple object because of the single one
1247  !  we now know (but didn't when the list was drawn up).
1248   
1249                  if (parameters>=1 && results-->2 == 0)
1250                  {   l=ReviseMulti(results-->3);
1251                      if (l~=0) { etype=l; break; }
1252                  }
1253                  if (parameters>=2 && results-->3 == 0)
1254                  {   l=ReviseMulti(results-->2);
1255                      if (l~=0) { etype=l; break; }
1256                  }
1257   
1258  !  To trap the case of "take all" inferring only "yourself" when absolutely
1259  !  nothing else is in the vicinity...
1260   
1261                  if (take_all_rule==2 && results-->2 == actor)
1262                  {   best_etype = NOTHING_PE; jump GiveError;
1263                  }
1264   
1265                  #ifdef DEBUG;
1266                  if (parser_trace>=1)
1267                      print "[Line successfully parsed]^";
1268                  #endif;
1269   
1270  !  The line has successfully matched the text.  Declare the input error-free...
1271   
1272                  oops_from = 0;
1273   
1274  !  ...explain any inferences made (using the pattern)...
1275   
1276                  if (inferfrom~=0)
1277                  {   print "("; PrintCommand(inferfrom); print ")^";
1278                  }
1279   
1280  !  ...copy the action number, and the number of parameters...
1281   
1282                  results-->0 = action_to_be;
1283                  results-->1 = parameters;
1284   
1285  !  ...reverse first and second parameters if need be...
1286   
1287                  if (action_reversed && parameters==2)
1288                  {   i = results-->2; results-->2 = results-->3;
1289                      results-->3 = i;
1290                      if (nsns == 2)
1291                      {   i = special_number1; special_number1=special_number2;
1292                          special_number2=i;
1293                      }
1294                  }
1295   
1296  !  ...and to reset "it"-style objects to the first of these parameters, if
1297  !  there is one (and it really is an object)...
1298   
1299                  if (parameters > 0 && results-->2 >= 2)
1300                      PronounNotice(results-->2);
1301   
1302  !  ...and worry about the case where an object was allowed as a parameter
1303  !  even though the player wasn't holding it and should have been: in this
1304  !  event, keep the results for next time round, go into "not holding" mode,
1305  !  and for now tell the player what's happening and return a "take" request
1306  !  instead...
1307   
1308                  if (not_holding~=0 && actor==player)
1309                  {   notheld_mode=1;
1310                      for (i=0:i<8:i++) kept_results-->i = results-->i;
1311                      results-->0 = ##Take;
1312                      results-->1 = 1;
1313                      results-->2 = not_holding;
1314                      L__M(##Miscellany, 26, not_holding);
1315                  }
1316   
1317  !  (Notice that implicit takes are only generated for the player, and not
1318  !  for other actors.  This avoids entirely logical, but misleading, text
1319  !  being printed.)
1320   
1321  !  ...and return from the parser altogether, having successfully matched
1322  !  a line.
1323   
1324                  if (held_back_mode==1) { wn=hb_wn; jump LookForMore; }
1325                  rtrue;
1326              }
1327          }
1328   
1329  !  The line has failed to match.
1330  !  We continue the outer "for" loop, trying the next line in the grammar.
1331   
1332          if (etype>best_etype) best_etype=etype;
1333          if (etype~=ASKSCOPE_PE && etype>nextbest_etype) nextbest_etype=etype;
1334   
1335  !  ...unless the line was something like "take all" which failed because
1336  !  nothing matched the "all", in which case we stop and give an error now.
1337   
1338          if (take_all_rule == 2 && etype==NOTHING_PE) break;
1339     }
1340   
1341  !  The grammar is exhausted: every line has failed to match.
1342   
1343  !  **** (H) ****
1344   
1345    .GiveError;
1346          etype=best_etype;
1347   
1348  !  Errors are handled differently depending on who was talking.
1349   
1350  !  If the command was addressed to somebody else (eg, "dwarf, sfgh") then
1351  !  it is taken as conversation which the parser has no business in disallowing.
1352   
1353      if (actor~=player)
1354      {   if (usual_grammar_after>0)
1355          {   verb_wordnum = usual_grammar_after;
1356              jump AlmostReParse;
1357          }
1358          wn=verb_wordnum;
1359          special_word=NextWord();
1360          if (special_word==comma_word)
1361          {   special_word=NextWord();
1362              verb_wordnum++;
1363          }
1364          special_number=TryNumber(verb_wordnum);
1365          results-->0=##NotUnderstood;
1366          results-->1=2;
1367          results-->2=1; special_number1=special_word;
1368          results-->3=actor;
1369          consult_from = verb_wordnum; consult_words = num_words-consult_from+1;
1370          rtrue;
1371      }
1372   
1373  !  **** (I) ****
1374   
1375  !  If the player was the actor (eg, in "take dfghh") the error must be printed,
1376  !  and fresh input called for.  In three cases the oops word must be jiggled.
1377   
1378      if (ParserError(etype)~=0) jump ReType;
1379      pronoun_word = pronoun__word; pronoun_obj = pronoun__obj;
1380   
1381      if (etype==STUCK_PE)   { L__M(##Miscellany, 27); oops_from=1; }
1382      if (etype==UPTO_PE)    { L__M(##Miscellany, 28);
1383                               for (m=0:m<32:m++) pattern-->m = pattern2-->m;
1384                               pcount=pcount2; PrintCommand(0); print ".^";
1385                             }
1386      if (etype==NUMBER_PE)  L__M(##Miscellany, 29);
1387      if (etype==CANTSEE_PE) { L__M(##Miscellany, 30); oops_from=saved_oops; }
1388      if (etype==TOOLIT_PE)  L__M(##Miscellany, 31);
1389      if (etype==NOTHELD_PE) { L__M(##Miscellany, 32); oops_from=saved_oops; }
1390      if (etype==MULTI_PE)   L__M(##Miscellany, 33);
1391      if (etype==MMULTI_PE)  L__M(##Miscellany, 34);
1392      if (etype==VAGUE_PE)   L__M(##Miscellany, 35);
1393      if (etype==EXCEPT_PE)  L__M(##Miscellany, 36);
1394      if (etype==ANIMA_PE)   L__M(##Miscellany, 37);
1395      if (etype==VERB_PE)    L__M(##Miscellany, 38);
1396      if (etype==SCENERY_PE) L__M(##Miscellany, 39);
1397      if (etype==ITGONE_PE)
1398      {   if (pronoun_obj == NULL) L__M(##Miscellany, 35);
1399                              else L__M(##Miscellany, 40);
1400      }
1401      if (etype==JUNKAFTER_PE) L__M(##Miscellany, 41);
1402      if (etype==TOOFEW_PE)  L__M(##Miscellany, 42, multi_had);
1403      if (etype==NOTHING_PE) { if (multi_wanted==100) L__M(##Miscellany, 43);
1404                               else L__M(##Miscellany, 44);  }
1405   
1406      if (etype==ASKSCOPE_PE)
1407      {   scope_stage=3;
1408          if (indirect(scope_error)==-1)
1409          {   best_etype=nextbest_etype; jump GiveError;  }
1410      }
1411   
1412  !  **** (J) ****
1413   
1414  !  And go (almost) right back to square one...
1415   
1416      jump ReType;
1417   
1418  !  ...being careful not to go all the way back, to avoid infinite repetition
1419  !  of a deferred command causing an error.
1420   
1421   
1422  !  **** (K) ****
1423   
1424  !  At this point, the return value is all prepared, and we are only looking
1425  !  to see if there is a "then" followed by subsequent instruction(s).
1426      
1427     .LookForMore;
1428   
1429     if (wn>num_words) rtrue;
1430   
1431     i=NextWord();
1432     if (i==THEN1__WD or THEN2__WD or THEN3__WD or comma_word)
1433     {   if (wn>num_words)
1434         {   held_back_mode = false; return; }
1435         i = WordAddress(verb_wordnum);
1436         j = WordAddress(wn);
1437         for (:i<j:i++) i->0 = ' ';
1438         i = NextWord();
1439         if (i==AGAIN1__WD or AGAIN2__WD or AGAIN3__WD)
1440         {   !   Delete the words "then again" from the again buffer,
1441             !   in which we have just realised that it must occur:
1442             !   prevents an infinite loop on "i. again"
1443   
1444             i = WordAddress(wn-2)-buffer;
1445             if (wn > num_words) j = 119; else j = WordAddress(wn)-buffer;
1446             for (:i<j:i++) buffer3->i = ' ';
1447         }
1448         Tokenise__(buffer,parse); held_back_mode = true; return;
1449     }
1450     best_etype=UPTO_PE; jump GiveError;
1451  ];


Last updated 27 February 2004. This site is no longer supported; information may be out of date.
Maintained as a historical archive by the Interactive Fiction Technology Foundation. Copyright 1993-2018 IFTF, CC-BY-SA unless otherwise noted.
This page was originally managed by Graham Nelson (graham@gnelson.demon.co.uk) assisted by C Knight.