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 web site has not been fully supported since April 2008. Information may be out of date. This page was originally managed by Graham Nelson (graham@gnelson.demon.co.uk) assisted by C Knight.