Inform - Support - Source

Back to List

Inventory
Complete

Backward
Forward

Plain
Coloured
Gaudy

This code
in plain text

Browsing parserm.h

Parser__parse (lines 1224-2097)

1224  !   To simplify the picture a little, a rough map of the main routine:
1225  !
1226  !   (A) Get the input, do "oops" and "again"
1227  !   (B) Is it a direction, and so an implicit "go"?  If so go to (K)
1228  !   (C) Is anyone being addressed?
1229  !   (D) Get the verb: try all the syntax lines for that verb
1230  !   (E) Break down a syntax line into analysed tokens
1231  !   (F) Look ahead for advance warning for multiexcept/multiinside
1232  !   (G) Parse each token in turn (calling ParseToken to do most of the work)
1233  !   (H) Cheaply parse otherwise unrecognised conversation and return
1234  !   (I) Print best possible error message
1235  !   (J) Retry the whole lot
1236  !   (K) Last thing: check for "then" and further instructions(s), return.
1237  !
1238  !   The strategic points (A) to (K) are marked in the commentary.
1239  !
1240  !   Note that there are three different places where a return can happen.
1241  ! ----------------------------------------------------------------------------
1242   
1243  [ Parser__parse  results   syntax line num_lines line_address i j k
1244                             token l m;
1245   
1246      !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1247      !
1248      ! A: Get the input, do "oops" and "again"
1249      !
1250      !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1251   
1252      ! Firstly, in "not held" mode, we still have a command left over from last
1253      ! time (eg, the user typed "eat biscuit", which was parsed as "take biscuit"
1254      ! last time, with "eat biscuit" tucked away until now).  So we return that.
1255   
1256      if (notheld_mode == 1) {
1257          for (i=0 : i<8 : i++) results-->i = kept_results-->i;
1258          notheld_mode = 0;
1259          rtrue;
1260      }
1261   
1262      if (held_back_mode == 1) {
1263          held_back_mode = 0;
1264          Tokenise__(buffer, parse);
1265          jump ReParse;
1266      }
1267   
1268    .ReType;
1269   
1270      Keyboard(buffer,parse);
1271   
1272    .ReParse;
1273   
1274      parser_inflection = name;
1275   
1276      ! Initially assume the command is aimed at the player, and the verb
1277      ! is the first word
1278   
1279      #Ifdef TARGET_ZCODE;
1280      num_words = parse->1;
1281      #Ifnot; ! TARGET_GLULX
1282      num_words = parse-->0;
1283      #Endif; ! TARGET_
1284      wn = 1;
1285   
1286      #Ifdef LanguageToInformese;
1287      LanguageToInformese();
1288      #IfV5;
1289      ! Re-tokenise:
1290      Tokenise__(buffer,parse);
1291      #Endif; ! V5
1292      #Endif; ! LanguageToInformese
1293   
1294      BeforeParsing();
1295      #Ifdef TARGET_ZCODE;
1296      num_words = parse->1;
1297      #Ifnot; ! TARGET_GLULX
1298      num_words = parse-->0;
1299      #Endif; ! TARGET_
1300   
1301      k=0;
1302      #Ifdef DEBUG;
1303      if (parser_trace >= 2) {
1304          print "[ ";
1305          for (i=0 : i<num_words : i++) {
1306   
1307              #Ifdef TARGET_ZCODE;
1308              j = parse-->(i*2 + 1);
1309              #Ifnot; ! TARGET_GLULX
1310              j = parse-->(i*3 + 1);
1311              #Endif; ! TARGET_
1312              k = WordAddress(i+1);
1313              l = WordLength(i+1);
1314              print "~"; for (m=0 : m<l : m++) print (char) k->m; print "~ ";
1315   
1316              if (j == 0) print "?";
1317              else {
1318                  #Ifdef TARGET_ZCODE;
1319                  if (UnsignedCompare(j, HDR_DICTIONARY-->0) >= 0 &&
1320                      UnsignedCompare(j, HDR_HIGHMEMORY-->0) < 0)
1321                       print (address) j;
1322                  else print j;
1323                  #Ifnot; ! TARGET_GLULX
1324                  if (j->0 == $60) print (address) j;
1325                  else print j;
1326                  #Endif; ! TARGET_
1327              }
1328              if (i ~= num_words-1) print " / ";
1329          }
1330          print " ]^";
1331      }
1332      #Endif; ! DEBUG
1333      verb_wordnum = 1;
1334      actor = player;
1335      actors_location = ScopeCeiling(player);
1336      usual_grammar_after = 0;
1337   
1338    .AlmostReParse;
1339   
1340      scope_token = 0;
1341      action_to_be = NULL;
1342   
1343      ! Begin from what we currently think is the verb word
1344   
1345    .BeginCommand;
1346   
1347      wn = verb_wordnum;
1348      verb_word = NextWordStopped();
1349   
1350      ! If there's no input here, we must have something like "person,".
1351   
1352      if (verb_word == -1) {
1353          best_etype = STUCK_PE;
1354          jump GiveError;
1355      }
1356   
1357      ! Now try for "again" or "g", which are special cases: don't allow "again" if nothing
1358      ! has previously been typed; simply copy the previous text across
1359   
1360      if (verb_word == AGAIN2__WD or AGAIN3__WD) verb_word = AGAIN1__WD;
1361      if (verb_word == AGAIN1__WD) {
1362          if (actor ~= player) {
1363              L__M(##Miscellany, 20);
1364              jump ReType;
1365          }
1366          #Ifdef TARGET_ZCODE;
1367          if (buffer3->1 == 0) {
1368              L__M(##Miscellany, 21);
1369              jump ReType;
1370          }
1371          #Ifnot; ! TARGET_GLULX
1372          if (buffer3-->0 == 0) {
1373              L__M(##Miscellany, 21);
1374              jump ReType;
1375          }
1376          #Endif; ! TARGET_
1377          for (i=0 : i<INPUT_BUFFER_LEN : i++) buffer->i = buffer3->i;
1378          jump ReParse;
1379      }
1380   
1381      ! Save the present input in case of an "again" next time
1382   
1383      if (verb_word ~= AGAIN1__WD)
1384          for (i=0 : i<INPUT_BUFFER_LEN : i++) buffer3->i = buffer->i;
1385   
1386      if (usual_grammar_after == 0) {
1387          j = verb_wordnum;
1388          i = RunRoutines(actor, grammar); 
1389          #Ifdef DEBUG;
1390          if (parser_trace >= 2 && actor.grammar ~= 0 or NULL)
1391              print " [Grammar property returned ", i, "]^";
1392          #Endif; ! DEBUG
1393   
1394          #Ifdef TARGET_ZCODE;
1395          if ((i ~= 0 or 1) &&
1396              (UnsignedCompare(i, dict_start) < 0 ||
1397               UnsignedCompare(i, dict_end) >= 0 ||
1398               (i - dict_start) % dict_entry_size ~= 0)) {
1399              usual_grammar_after = j;
1400              i=-i;
1401          }
1402   
1403          #Ifnot; ! TARGET_GLULX
1404          if (i < 0) { usual_grammar_after = verb_wordnum; i=-i; }
1405          #Endif;
1406   
1407          if (i == 1) {
1408              results-->0 = action;
1409              results-->1 = noun;
1410              results-->2 = second;
1411              rtrue;
1412          }
1413          if (i ~= 0) { verb_word = i; wn--; verb_wordnum--; }
1414          else { wn = verb_wordnum; verb_word = NextWord(); }
1415      }
1416      else usual_grammar_after = 0;
1417   
1418      !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1419      !
1420      ! B: Is it a direction, and so an implicit "go"?  If so go to (K)
1421      !
1422      !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1423   
1424      #Ifdef LanguageIsVerb;
1425      if (verb_word == 0) {
1426          i = wn; verb_word = LanguageIsVerb(buffer, parse, verb_wordnum);
1427          wn = i;
1428      }
1429      #Endif; ! LanguageIsVerb
1430   
1431      ! If the first word is not listed as a verb, it must be a direction
1432      ! or the name of someone to talk to
1433   
1434      if (verb_word == 0 || ((verb_word->#dict_par1) & 1) == 0) {
1435   
1436          ! So is the first word an object contained in the special object "compass"
1437          ! (i.e., a direction)?  This needs use of NounDomain, a routine which
1438          ! does the object matching, returning the object number, or 0 if none found,
1439          ! or REPARSE_CODE if it has restructured the parse table so the whole parse
1440          ! must be begun again...
1441   
1442          wn = verb_wordnum; indef_mode = false; token_filter = 0;
1443          l = NounDomain(compass, 0, 0);
1444          if (l == REPARSE_CODE) jump ReParse;
1445   
1446          ! If it is a direction, send back the results:
1447          ! action=GoSub, no of arguments=1, argument 1=the direction.
1448   
1449          if (l ~= 0) {
1450              results-->0 = ##Go;
1451              action_to_be = ##Go;
1452              results-->1 = 1;
1453              results-->2 = l;
1454              jump LookForMore;
1455          }
1456   
1457      !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1458      !
1459      ! C: Is anyone being addressed?
1460      !
1461      !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1462   
1463          ! Only check for a comma (a "someone, do something" command) if we are
1464          ! not already in the middle of one.  (This simplification stops us from
1465          ! worrying about "robot, wizard, you are an idiot", telling the robot to
1466          ! tell the wizard that she is an idiot.)
1467   
1468          if (actor == player) {
1469              for (j=2 : j<=num_words : j++) {
1470                  i=NextWord();
1471                  if (i == comma_word) jump Conversation;
1472              }
1473              verb_word = UnknownVerb(verb_word);
1474              if (verb_word ~= 0) jump VerbAccepted;
1475          }
1476          best_etype = VERB_PE;
1477          jump GiveError;
1478   
1479          ! NextWord nudges the word number wn on by one each time, so we've now
1480          ! advanced past a comma.  (A comma is a word all on its own in the table.)
1481   
1482        .Conversation;
1483   
1484          j = wn - 1;
1485          if (j == 1) {
1486              L__M(##Miscellany, 22);
1487              jump ReType;
1488          }
1489   
1490          ! Use NounDomain (in the context of "animate creature") to see if the
1491          ! words make sense as the name of someone held or nearby
1492   
1493          wn = 1; lookahead = HELD_TOKEN;
1494          scope_reason = TALKING_REASON;
1495          l = NounDomain(player,actors_location,6);
1496          scope_reason = PARSING_REASON;
1497          if (l == REPARSE_CODE) jump ReParse;
1498          if (l == 0) {
1499              L__M(##Miscellany, 23);
1500              jump ReType;
1501          }
1502   
1503        .Conversation2;
1504   
1505          ! The object addressed must at least be "talkable" if not actually "animate"
1506          ! (the distinction allows, for instance, a microphone to be spoken to,
1507          ! without the parser thinking that the microphone is human).
1508   
1509          if (l hasnt animate && l hasnt talkable) {
1510              L__M(##Miscellany, 24, l);
1511              jump ReType;
1512          }
1513   
1514          ! Check that there aren't any mystery words between the end of the person's
1515          ! name and the comma (eg, throw out "dwarf sdfgsdgs, go north").
1516   
1517          if (wn ~= j) {
1518              L__M(##Miscellany, 25);
1519              jump ReType;
1520          }
1521   
1522          ! The player has now successfully named someone.  Adjust "him", "her", "it":
1523   
1524          PronounNotice(l);
1525   
1526          ! Set the global variable "actor", adjust the number of the first word,
1527          ! and begin parsing again from there.
1528   
1529          verb_wordnum = j + 1;
1530   
1531          ! Stop things like "me, again":
1532   
1533          if (l == player) {
1534              wn = verb_wordnum;
1535              if (NextWordStopped() == AGAIN1__WD or AGAIN2__WD or AGAIN3__WD) {
1536                  L__M(##Miscellany, 20);
1537                  jump ReType;
1538              }
1539          }
1540   
1541          actor = l;
1542          actors_location = ScopeCeiling(l);
1543          #Ifdef DEBUG;
1544          if (parser_trace >= 1)
1545              print "[Actor is ", (the) actor, " in ", (name) actors_location, "]^";
1546          #Endif; ! DEBUG
1547          jump BeginCommand;
1548   
1549      } ! end of first-word-not-a-verb
1550   
1551      !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1552      !
1553      ! D: Get the verb: try all the syntax lines for that verb
1554      !
1555      !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1556   
1557    .VerbAccepted;
1558   
1559      ! We now definitely have a verb, not a direction, whether we got here by the
1560      ! "take ..." or "person, take ..." method.  Get the meta flag for this verb:
1561   
1562      meta = ((verb_word->#dict_par1) & 2)/2;
1563   
1564      ! You can't order other people to "full score" for you, and so on...
1565   
1566      if (meta == 1 && actor ~= player) {
1567          best_etype = VERB_PE;
1568          meta = 0;
1569          jump GiveError;
1570      }
1571   
1572      ! Now let i be the corresponding verb number, stored in the dictionary entry
1573      ! (in a peculiar 255-n fashion for traditional Infocom reasons)...
1574   
1575      i = $ff-(verb_word->#dict_par2);
1576   
1577      ! ...then look up the i-th entry in the verb table, whose address is at word
1578      ! 7 in the Z-machine (in the header), so as to get the address of the syntax
1579      ! table for the given verb...
1580   
1581      #Ifdef TARGET_ZCODE;
1582      syntax = (HDR_STATICMEMORY-->0)-->i;
1583      #Ifnot; ! TARGET_GLULX
1584      syntax = (#grammar_table)-->(i+1);
1585      #Endif; ! TARGET_
1586   
1587      ! ...and then see how many lines (ie, different patterns corresponding to the
1588      ! same verb) are stored in the parse table...
1589   
1590      num_lines = (syntax->0) - 1;
1591   
1592      ! ...and now go through them all, one by one.
1593      ! To prevent pronoun_word 0 being misunderstood,
1594   
1595      pronoun_word = NULL; pronoun_obj = NULL;
1596   
1597      #Ifdef DEBUG;
1598      if (parser_trace >= 1) print "[Parsing for the verb '", (address) verb_word, "' (", num_lines+1, " lines)]^";
1599      #Endif; ! DEBUG
1600   
1601      best_etype = STUCK_PE; nextbest_etype = STUCK_PE;
1602      multiflag = false;
1603   
1604      ! "best_etype" is the current failure-to-match error - it is by default
1605      ! the least informative one, "don't understand that sentence".
1606      ! "nextbest_etype" remembers the best alternative to having to ask a
1607      ! scope token for an error message (i.e., the best not counting ASKSCOPE_PE).
1608      ! multiflag is used here to prevent inappropriate MULTI_PE errors
1609      ! in addition to its unrelated duties passing information to action routines
1610   
1611      !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1612      !
1613      ! E: Break down a syntax line into analysed tokens
1614      !
1615      !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1616   
1617      line_address = syntax + 1;
1618   
1619      for (line=0 : line<=num_lines : line++) {
1620   
1621          for (i=0 : i<32 : i++) {
1622              line_token-->i = ENDIT_TOKEN;
1623              line_ttype-->i = ELEMENTARY_TT;
1624              line_tdata-->i = ENDIT_TOKEN;
1625          }
1626   
1627          ! Unpack the syntax line from Inform format into three arrays; ensure that
1628          ! the sequence of tokens ends in an ENDIT_TOKEN.
1629   
1630          line_address = UnpackGrammarLine(line_address);
1631   
1632          #Ifdef DEBUG;
1633          if (parser_trace >= 1) {
1634              if (parser_trace >= 2) new_line;
1635              print "[line ", line; DebugGrammarLine();
1636              print "]^";
1637          }
1638          #Endif; ! DEBUG
1639   
1640          ! We aren't in "not holding" or inferring modes, and haven't entered
1641          ! any parameters on the line yet, or any special numbers; the multiple
1642          ! object is still empty.
1643   
1644          not_holding = 0;
1645          inferfrom = 0;
1646          parameters = 0;
1647          nsns = 0; special_word = 0; special_number = 0;
1648          multiple_object-->0 = 0;
1649          multi_context = 0;
1650          etype = STUCK_PE;
1651   
1652          ! Put the word marker back to just after the verb
1653   
1654          wn = verb_wordnum+1;
1655   
1656      !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1657      !
1658      ! F: Look ahead for advance warning for multiexcept/multiinside
1659      !
1660      !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1661   
1662          ! There are two special cases where parsing a token now has to be
1663          ! affected by the result of parsing another token later, and these
1664          ! two cases (multiexcept and multiinside tokens) are helped by a quick
1665          ! look ahead, to work out the future token now.  We can only carry this
1666          ! out in the simple (but by far the most common) case:
1667          !
1668          !     multiexcept  noun
1669          !
1670          ! and similarly for multiinside.
1671   
1672          advance_warning = NULL; indef_mode = false;
1673          for (i=0,m=false,pcount=0 : line_token-->pcount ~= ENDIT_TOKEN : pcount++) {
1674              scope_token = 0;
1675   
1676              if (line_ttype-->pcount ~= PREPOSITION_TT) i++;
1677   
1678              if (line_ttype-->pcount == ELEMENTARY_TT) {
1679                  if (line_tdata-->pcount == MULTI_TOKEN) m = true;
1680                  if (line_tdata-->pcount == MULTIEXCEPT_TOKEN or MULTIINSIDE_TOKEN  && i == 1) {
1681                      ! First non-preposition is "multiexcept" or
1682                      ! "multiinside", so look ahead.
1683   
1684                      #Ifdef DEBUG;
1685                      if (parser_trace >= 2) print " [Trying look-ahead]^";
1686                      #Endif; ! DEBUG
1687   
1688                      ! We need this to be followed by 1 or more prepositions.
1689   
1690                      pcount++;
1691                      if (line_ttype-->pcount == PREPOSITION_TT) {
1692                          while (line_ttype-->pcount == PREPOSITION_TT) pcount++;
1693   
1694                          if ((line_ttype-->pcount == ELEMENTARY_TT) && (line_tdata-->pcount == NOUN_TOKEN)) {
1695   
1696                              ! Advance past the last preposition
1697   
1698                              while (wn < num_words) {
1699                                  l=NextWord();
1700                                  if ( l && (l->#dict_par1) &8 ) {   ! if preposition
1701                                      l = Descriptors();  ! skip past THE etc
1702                                      if (l~=0) etype=l;  ! don't allow multiple objects
1703                                      l = NounDomain(actors_location, actor, NOUN_TOKEN);
1704                                      #Ifdef DEBUG;
1705                                      if (parser_trace >= 2) {
1706                                          print " [Advanced to ~noun~ token: ";
1707                                          if (l == REPARSE_CODE) print "re-parse request]^";
1708                                          if (l == 1) print "but multiple found]^";
1709                                          if (l == 0) print "error ", etype, "]^";
1710                                          if (l >= 2) print (the) l, "]^";
1711                                      }
1712                                      #Endif; ! DEBUG
1713                                      if (l == REPARSE_CODE) jump ReParse;
1714                                      if (l >= 2) advance_warning = l;
1715                                  }
1716                              }
1717                          }
1718                      }
1719                      break;
1720                  }
1721              }
1722          }
1723   
1724          ! Slightly different line-parsing rules will apply to "take multi", to
1725          ! prevent "take all" behaving correctly but misleadingly when there's
1726          ! nothing to take.
1727   
1728          take_all_rule = 0;
1729          if (m && params_wanted == 1 && action_to_be == ##Take)
1730              take_all_rule = 1;
1731   
1732          ! And now start again, properly, forearmed or not as the case may be.
1733          ! As a precaution, we clear all the variables again (they may have been
1734          ! disturbed by the call to NounDomain, which may have called outside
1735          ! code, which may have done anything!).
1736   
1737          not_holding = 0;
1738          inferfrom = 0;
1739          parameters = 0;
1740          nsns = 0; special_word = 0; special_number = 0;
1741          multiple_object-->0 = 0;
1742          etype = STUCK_PE;
1743          wn = verb_wordnum+1;
1744   
1745      !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1746      !
1747      ! G: Parse each token in turn (calling ParseToken to do most of the work)
1748      !
1749      !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1750   
1751          ! "Pattern" gradually accumulates what has been recognised so far,
1752          ! so that it may be reprinted by the parser later on
1753   
1754          for (pcount=1 : : pcount++) {
1755              pattern-->pcount = PATTERN_NULL; scope_token = 0;
1756   
1757              token = line_token-->(pcount-1);
1758              lookahead = line_token-->pcount;
1759   
1760              #Ifdef DEBUG;
1761              if (parser_trace >= 2)
1762                  print " [line ", line, " token ", pcount, " word ", wn, " : ", (DebugToken) token,
1763                    "]^";
1764              #Endif; ! DEBUG
1765   
1766              if (token ~= ENDIT_TOKEN) {
1767                  scope_reason = PARSING_REASON;
1768                  parser_inflection = name;
1769                  AnalyseToken(token);
1770   
1771                  if (action_to_be == ##AskTo && found_ttype == ELEMENTARY_TT &&
1772                      found_tdata == TOPIC_TOKEN)
1773                  {
1774                      l=inputobjs-->2;
1775                      wn--;
1776                      j = wn;
1777                      jump Conversation2;
1778                  }
1779   
1780                  l = ParseToken__(found_ttype, found_tdata, pcount-1, token);
1781                  while (l<-200) l = ParseToken__(ELEMENTARY_TT, l + 256);
1782                  scope_reason = PARSING_REASON;
1783   
1784                  if (l == GPR_PREPOSITION) {
1785                      if (found_ttype~=PREPOSITION_TT && (found_ttype~=ELEMENTARY_TT ||
1786                          found_tdata~=TOPIC_TOKEN)) params_wanted--;
1787                      l = true;
1788                  }
1789                  else
1790                      if (l < 0) l = false;
1791                      else
1792                          if (l ~= GPR_REPARSE) {
1793                              if (l == GPR_NUMBER) {
1794                                  if (nsns == 0) special_number1 = parsed_number;
1795                                  else special_number2 = parsed_number;
1796                                  nsns++; l = 1;
1797                              }
1798                              if (l == GPR_MULTIPLE) l = 0;
1799                              results-->(parameters+2) = l;
1800                              parameters++;
1801                              pattern-->pcount = l;
1802                              l = true;
1803                          }
1804   
1805                  #Ifdef DEBUG;
1806                  if (parser_trace >= 3) {
1807                      print "  [token resulted in ";
1808                      if (l == REPARSE_CODE) print "re-parse request]^";
1809                      if (l == 0) print "failure with error type ", etype, "]^";
1810                      if (l == 1) print "success]^";
1811                  }
1812                  #Endif; ! DEBUG
1813   
1814                  if (l == REPARSE_CODE) jump ReParse;
1815                  if (l == false) break;
1816              }
1817              else {
1818   
1819                  ! If the player has entered enough already but there's still
1820                  ! text to wade through: store the pattern away so as to be able to produce
1821                  ! a decent error message if this turns out to be the best we ever manage,
1822                  ! and in the mean time give up on this line
1823   
1824                  ! However, if the superfluous text begins with a comma or "then" then
1825                  ! take that to be the start of another instruction
1826   
1827                  if (wn <= num_words) {
1828                      l = NextWord();
1829                      if (l == THEN1__WD or THEN2__WD or THEN3__WD or comma_word) {
1830                          held_back_mode = 1; hb_wn = wn-1;
1831                      }
1832                      else {
1833                          for (m=0 : m<32 : m++) pattern2-->m = pattern-->m;
1834                          pcount2 = pcount;
1835                          etype = UPTO_PE;
1836                          break;
1837                      }
1838                  }
1839   
1840                  ! Now, we may need to revise the multiple object because of the single one
1841                  ! we now know (but didn't when the list was drawn up).
1842   
1843                  if (parameters >= 1 && results-->2 == 0) {
1844                      l = ReviseMulti(results-->3);
1845                      if (l ~= 0) { etype = l; results-->0 = action_to_be; break; }
1846                  }
1847                  if (parameters >= 2 && results-->3 == 0) {
1848                      l = ReviseMulti(results-->2);
1849                      if (l ~= 0) { etype = l; break; }
1850                  }
1851   
1852                  ! To trap the case of "take all" inferring only "yourself" when absolutely
1853                  ! nothing else is in the vicinity...
1854   
1855                  if (take_all_rule == 2 && results-->2 == actor) {
1856                      best_etype = NOTHING_PE;
1857                      jump GiveError;
1858                  }
1859   
1860                  #Ifdef DEBUG;
1861                  if (parser_trace >= 1) print "[Line successfully parsed]^";
1862                  #Endif; ! DEBUG
1863   
1864                  ! The line has successfully matched the text.  Declare the input error-free...
1865   
1866                  oops_from = 0;
1867   
1868                  ! ...explain any inferences made (using the pattern)...
1869   
1870                  if (inferfrom ~= 0) {
1871                      print "("; PrintCommand(inferfrom); print ")^";
1872                  }
1873   
1874                  ! ...copy the action number, and the number of parameters...
1875   
1876                  results-->0 = action_to_be;
1877                  results-->1 = parameters;
1878   
1879                  ! ...reverse first and second parameters if need be...
1880   
1881                  if (action_reversed && parameters == 2) {
1882                      i = results-->2; results-->2 = results-->3;
1883                      results-->3 = i;
1884                      if (nsns == 2) {
1885                          i = special_number1; special_number1 = special_number2;
1886                          special_number2 = i;
1887                      }
1888                  }
1889   
1890                  ! ...and to reset "it"-style objects to the first of these parameters, if
1891                  ! there is one (and it really is an object)...
1892   
1893                  if (parameters > 0 && results-->2 >= 2)
1894                      PronounNotice(results-->2);
1895   
1896                  ! ...and worry about the case where an object was allowed as a parameter
1897                  ! even though the player wasn't holding it and should have been: in this
1898                  ! event, keep the results for next time round, go into "not holding" mode,
1899                  ! and for now tell the player what's happening and return a "take" request
1900                  ! instead...
1901   
1902                  if (not_holding ~= 0 && actor == player) {
1903                      action = ##Take;
1904                      i = RunRoutines(not_holding, before_implicit);
1905                      ! i = 0: Take the object, tell the player (default)
1906                      ! i = 1: Take the object, don't tell the player
1907                      ! i = 2: don't Take the object, continue
1908                      ! i = 3: don't Take the object, don't continue
1909                      if (i > 2) { best_etype = NOTHELD_PE; jump GiveError; }
1910                      if (i < 2) {        ! perform the implicit Take
1911                          if (i ~= 1)     ! and tell the player
1912                              L__M(##Miscellany, 26, not_holding);
1913                          notheld_mode = 1;
1914                          for (i=0 : i<8 : i++) kept_results-->i = results-->i;
1915                          results-->0 = ##Take;
1916                          results-->1 = 1;
1917                          results-->2 = not_holding;
1918                      }
1919                  }
1920   
1921                  ! (Notice that implicit takes are only generated for the player, and not
1922                  ! for other actors.  This avoids entirely logical, but misleading, text
1923                  ! being printed.)
1924   
1925                  ! ...and return from the parser altogether, having successfully matched
1926                  ! a line.
1927   
1928                  if (held_back_mode == 1) {
1929                      wn=hb_wn;
1930                      jump LookForMore;
1931                  }
1932                  rtrue;
1933   
1934              } ! end of if(token ~= ENDIT_TOKEN) else
1935          } ! end of for(pcount++)
1936   
1937          ! The line has failed to match.
1938          ! We continue the outer "for" loop, trying the next line in the grammar.
1939   
1940          if (etype > best_etype) best_etype = etype;
1941          if (etype ~= ASKSCOPE_PE && etype > nextbest_etype) nextbest_etype = etype;
1942   
1943          ! ...unless the line was something like "take all" which failed because
1944          ! nothing matched the "all", in which case we stop and give an error now.
1945   
1946          if (take_all_rule == 2 && etype==NOTHING_PE) break;
1947   
1948      } ! end of for(line++)
1949   
1950      ! The grammar is exhausted: every line has failed to match.
1951   
1952      !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1953      !
1954      ! H: Cheaply parse otherwise unrecognised conversation and return
1955      !
1956      !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1957   
1958    .GiveError;
1959   
1960      etype = best_etype;
1961   
1962      ! Errors are handled differently depending on who was talking.
1963      ! If the command was addressed to somebody else (eg, "dwarf, sfgh") then
1964      ! it is taken as conversation which the parser has no business in disallowing.
1965   
1966      if (actor ~= player) {
1967          if (usual_grammar_after ~= 0) {
1968              verb_wordnum = usual_grammar_after;
1969              jump AlmostReParse;
1970          }
1971          wn = verb_wordnum;
1972          special_word = NextWord();
1973          if (special_word == comma_word) {
1974              special_word = NextWord();
1975              verb_wordnum++;
1976          }
1977          special_number = TryNumber(verb_wordnum);
1978          results-->0 = ##NotUnderstood;
1979          results-->1 = 2;
1980          results-->2 = 1; special_number1 = special_word;
1981          results-->3 = actor;
1982          consult_from = verb_wordnum; consult_words = num_words-consult_from+1;
1983          rtrue;
1984      }
1985   
1986      !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1987      !
1988      ! I: Print best possible error message
1989      !
1990      !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1991   
1992      ! If the player was the actor (eg, in "take dfghh") the error must be printed,
1993      ! and fresh input called for.  In three cases the oops word must be jiggled.
1994   
1995      if (ParserError(etype) ~= 0) jump ReType;
1996      pronoun_word = pronoun__word; pronoun_obj = pronoun__obj;
1997   
1998      if (etype == STUCK_PE) {    L__M(##Miscellany, 27); oops_from = 1; }
1999      if (etype == UPTO_PE) {     L__M(##Miscellany, 28);
2000          for (m=0 : m<32 : m++) pattern-->m = pattern2-->m;
2001          pcount = pcount2; PrintCommand(0); L__M(##Miscellany, 56);
2002      }
2003      if (etype == NUMBER_PE)     L__M(##Miscellany, 29);
2004      if (etype == CANTSEE_PE) {  L__M(##Miscellany, 30); oops_from=saved_oops; }
2005      if (etype == TOOLIT_PE)     L__M(##Miscellany, 31);
2006      if (etype == NOTHELD_PE) {  L__M(##Miscellany, 32); oops_from=saved_oops; }
2007      if (etype == MULTI_PE)      L__M(##Miscellany, 33);
2008      if (etype == MMULTI_PE)     L__M(##Miscellany, 34);
2009      if (etype == VAGUE_PE)      L__M(##Miscellany, 35);
2010      if (etype == EXCEPT_PE)     L__M(##Miscellany, 36);
2011      if (etype == ANIMA_PE)      L__M(##Miscellany, 37);
2012      if (etype == VERB_PE)       L__M(##Miscellany, 38);
2013      if (etype == SCENERY_PE)    L__M(##Miscellany, 39);
2014      if (etype == ITGONE_PE) {
2015          if (pronoun_obj == NULL)
2016                                  L__M(##Miscellany, 35);
2017          else                    L__M(##Miscellany, 40);
2018      }
2019      if (etype == JUNKAFTER_PE)  L__M(##Miscellany, 41);
2020      if (etype == TOOFEW_PE)     L__M(##Miscellany, 42, multi_had);
2021      if (etype == NOTHING_PE) {
2022          if (results-->0 == ##Remove && results-->3 ofclass Object) {
2023              noun = results-->3; ! ensure valid for messages
2024              if (noun has animate) L__M(##Take, 6, noun);
2025              else if (noun hasnt container or supporter) L__M(##Insert, 2, noun);
2026              else if (noun has container && noun hasnt open) L__M(##Take, 9, noun);
2027              else if (children(noun)==0