Inform - Support - Source

Back to List

Inventory
Complete

Backward
Forward

Plain
Coloured
Gaudy

This code
in plain text

Browsing parserm.h

NounDomain (lines 2690-3029)

2690  !  NounDomain does the most substantial part of parsing an object name.
2691  !
2692  !  It is given two "domains" - usually a location and then the actor who is
2693  !  looking - and a context (i.e. token type), and returns:
2694  !
2695  !   0    if no match at all could be made,
2696  !   1    if a multiple object was made,
2697  !   k    if object k was the one decided upon,
2698  !   REPARSE_CODE if it asked a question of the player and consequently rewrote
2699  !        the player's input, so that the whole parser should start again
2700  !        on the rewritten input.
2701  !
2702  !   In the case when it returns 1
2703  !   length_of_noun to the number of words in the input text matched to the
2704  !   noun.
2705  !   In the case k=1, the multiple objects are added to multiple_object by
2706  !   hand (not by MultiAdd, because we want to allow duplicates).
2707  ! ----------------------------------------------------------------------------
2708   
2709  [ NounDomain domain1 domain2 context    first_word i j k l
2710                                          answer_words marker;
2711      #Ifdef DEBUG;
2712      if (parser_trace >= 4) {
2713          print "   [NounDomain called at word ", wn, "^";
2714          print "   ";
2715          if (indef_mode) {
2716              print "seeking indefinite object: ";
2717              if (indef_type & OTHER_BIT)  print "other ";
2718              if (indef_type & MY_BIT)     print "my ";
2719              if (indef_type & THAT_BIT)   print "that ";
2720              if (indef_type & PLURAL_BIT) print "plural ";
2721              if (indef_type & LIT_BIT)    print "lit ";
2722              if (indef_type & UNLIT_BIT)  print "unlit ";
2723              if (indef_owner ~= 0) print "owner:", (name) indef_owner;
2724              new_line;
2725              print "   number wanted: ";
2726              if (indef_wanted == 100) print "all"; else print indef_wanted;
2727              new_line;
2728              print "   most likely GNAs of names: ", indef_cases, "^";
2729          }
2730          else print "seeking definite object^";
2731      }
2732      #Endif; ! DEBUG
2733   
2734      match_length = 0; number_matched = 0; match_from = wn; placed_in_flag = 0;
2735   
2736      SearchScope(domain1, domain2, context);
2737   
2738      #Ifdef DEBUG;
2739      if (parser_trace >= 4) print "   [ND made ", number_matched, " matches]^";
2740      #Endif; ! DEBUG
2741   
2742      wn = match_from+match_length;
2743   
2744      ! If nothing worked at all, leave with the word marker skipped past the
2745      ! first unmatched word...
2746   
2747      if (number_matched == 0) { wn++; rfalse; }
2748   
2749      ! Suppose that there really were some words being parsed (i.e., we did
2750      ! not just infer).  If so, and if there was only one match, it must be
2751      ! right and we return it...
2752   
2753      if (match_from <= num_words) {
2754          if (number_matched == 1) {
2755              i=match_list-->0;
2756              return i;
2757          }
2758   
2759          ! ...now suppose that there was more typing to come, i.e. suppose that
2760          ! the user entered something beyond this noun.  If nothing ought to follow,
2761          ! then there must be a mistake, (unless what does follow is just a full
2762          ! stop, and or comma)
2763   
2764          if (wn <= num_words) {
2765              i = NextWord(); wn--;
2766              if (i ~=  AND1__WD or AND2__WD or AND3__WD or comma_word
2767                     or THEN1__WD or THEN2__WD or THEN3__WD
2768                     or BUT1__WD or BUT2__WD or BUT3__WD) {
2769                  if (lookahead == ENDIT_TOKEN) rfalse;
2770              }
2771          }
2772      }
2773   
2774      ! Now look for a good choice, if there's more than one choice...
2775   
2776      number_of_classes = 0;
2777   
2778      if (number_matched == 1) i = match_list-->0;
2779      if (number_matched > 1) {
2780          i = Adjudicate(context);
2781          if (i == -1) rfalse;
2782          if (i == 1) rtrue;       !  Adjudicate has made a multiple
2783                               !  object, and we pass it on
2784      }
2785   
2786      ! If i is non-zero here, one of two things is happening: either
2787      ! (a) an inference has been successfully made that object i is
2788      !     the intended one from the user's specification, or
2789      ! (b) the user finished typing some time ago, but we've decided
2790      !     on i because it's the only possible choice.
2791      ! In either case we have to keep the pattern up to date,
2792      ! note that an inference has been made and return.
2793      ! (Except, we don't note which of a pile of identical objects.)
2794   
2795      if (i ~= 0) {
2796          if (dont_infer) return i;
2797          if (inferfrom == 0) inferfrom=pcount;
2798          pattern-->pcount = i;
2799          return i;
2800      }
2801   
2802      ! If we get here, there was no obvious choice of object to make.  If in
2803      ! fact we've already gone past the end of the player's typing (which
2804      ! means the match list must contain every object in scope, regardless
2805      ! of its name), then it's foolish to give an enormous list to choose
2806      ! from - instead we go and ask a more suitable question...
2807   
2808      if (match_from > num_words) jump Incomplete;
2809   
2810      ! Now we print up the question, using the equivalence classes as worked
2811      ! out by Adjudicate() so as not to repeat ourselves on plural objects...
2812   
2813      if (context==CREATURE_TOKEN) L__M(##Miscellany, 45);
2814      else                         L__M(##Miscellany, 46);
2815   
2816      j = number_of_classes; marker = 0;
2817      for (i=1 : i<=number_of_classes : i++) {
2818          while (((match_classes-->marker) ~= i) && ((match_classes-->marker) ~= -i)) marker++;
2819          k = match_list-->marker;
2820   
2821          if (match_classes-->marker > 0) print (the) k; else print (a) k;
2822   
2823          if (i < j-1)  print (string) COMMA__TX;
2824          if (i == j-1) print (string) OR__TX;
2825      }
2826      L__M(##Miscellany, 57);
2827   
2828      ! ...and get an answer:
2829   
2830    .WhichOne;
2831      #Ifdef TARGET_ZCODE;
2832      for (i=2 : i<INPUT_BUFFER_LEN : i++) buffer2->i = ' ';
2833      #Endif; ! TARGET_ZCODE
2834      answer_words=Keyboard(buffer2, parse2);
2835   
2836      ! Conveniently, parse2-->1 is the first word in both ZCODE and GLULX.
2837      first_word = (parse2-->1);
2838   
2839      ! Take care of "all", because that does something too clever here to do
2840      ! later on:
2841   
2842      if (first_word == ALL1__WD or ALL2__WD or ALL3__WD or ALL4__WD or ALL5__WD) {
2843          if (context == MULTI_TOKEN or MULTIHELD_TOKEN or MULTIEXCEPT_TOKEN or MULTIINSIDE_TOKEN) {
2844              l = multiple_object-->0;
2845              for (i=0 : i<number_matched && l+i<63 : i++) {
2846                  k = match_list-->i;
2847                  multiple_object-->(i+1+l) = k;
2848              }
2849              multiple_object-->0 = i+l;
2850              rtrue;
2851          }
2852          L__M(##Miscellany, 47);
2853          jump WhichOne;
2854      }
2855   
2856      ! If the first word of the reply can be interpreted as a verb, then
2857      ! assume that the player has ignored the question and given a new
2858      ! command altogether.
2859      ! (This is one time when it's convenient that the directions are
2860      ! not themselves verbs - thus, "north" as a reply to "Which, the north
2861      ! or south door" is not treated as a fresh command but as an answer.)
2862   
2863      #Ifdef LanguageIsVerb;
2864      if (first_word == 0) {
2865          j = wn; first_word = LanguageIsVerb(buffer2, parse2, 1); wn = j;
2866      }
2867      #Endif; ! LanguageIsVerb
2868      if (first_word ~= 0) {
2869          j = first_word->#dict_par1;
2870          if ((0 ~= j&1) && ~~LanguageVerbMayBeName(first_word)) {
2871              CopyBuffer(buffer, buffer2);
2872              return REPARSE_CODE;
2873          }
2874      }
2875   
2876      ! Now we insert the answer into the original typed command, as
2877      ! words additionally describing the same object
2878      ! (eg, > take red button
2879      !      Which one, ...
2880      !      > music
2881      ! becomes "take music red button".  The parser will thus have three
2882      ! words to work from next time, not two.)
2883   
2884      #Ifdef TARGET_ZCODE;
2885      k = WordAddress(match_from) - buffer; l=buffer2->1+1;
2886      for (j=buffer + buffer->0 - 1 : j>=buffer+k+l : j--) j->0 = 0->(j-l);
2887      for (i=0 : i<l : i++) buffer->(k+i) = buffer2->(2+i);
2888      buffer->(k+l-1) = ' ';
2889      buffer->1 = buffer->1 + l;
2890      if (buffer->1 >= (buffer->0 - 1)) buffer->1 = buffer->0;
2891      #Ifnot; ! TARGET_GLULX
2892      k = WordAddress(match_from) - buffer;
2893      l = (buffer2-->0) + 1;
2894      for (j=buffer+INPUT_BUFFER_LEN-1 : j>=buffer+k+l : j--) j->0 = j->(-l);
2895      for (i=0 : i<l : i++) buffer->(k+i) = buffer2->(WORDSIZE+i);
2896      buffer->(k+l-1) = ' ';
2897      buffer-->0 = buffer-->0 + l;
2898      if (buffer-->0 > (INPUT_BUFFER_LEN-WORDSIZE)) buffer-->0 = (INPUT_BUFFER_LEN-WORDSIZE);
2899      #Endif; ! TARGET_
2900   
2901      ! Having reconstructed the input, we warn the parser accordingly
2902      ! and get out.
2903   
2904      return REPARSE_CODE;
2905   
2906      ! Now we come to the question asked when the input has run out
2907      ! and can't easily be guessed (eg, the player typed "take" and there
2908      ! were plenty of things which might have been meant).
2909   
2910    .Incomplete;
2911   
2912      if (context == CREATURE_TOKEN) L__M(##Miscellany, 48);
2913      else                           L__M(##Miscellany, 49);
2914   
2915      #Ifdef TARGET_ZCODE;
2916      for (i=2 : i<INPUT_BUFFER_LEN : i++) buffer2->i=' ';
2917      #Endif; ! TARGET_ZCODE
2918      answer_words = Keyboard(buffer2, parse2);
2919   
2920      first_word=(parse2-->1);
2921      #Ifdef LanguageIsVerb;
2922      if (first_word==0) {
2923          j = wn; first_word=LanguageIsVerb(buffer2, parse2, 1); wn = j;
2924      }
2925      #Endif; ! LanguageIsVerb
2926   
2927      ! Once again, if the reply looks like a command, give it to the
2928      ! parser to get on with and forget about the question...
2929   
2930      if (first_word ~= 0) {
2931          j = first_word->#dict_par1;
2932          if (0 ~= j&1) {
2933              CopyBuffer(buffer, buffer2);
2934              return REPARSE_CODE;
2935          }
2936      }
2937   
2938      ! ...but if we have a genuine answer, then:
2939      !
2940      ! (1) we must glue in text suitable for anything that's been inferred.
2941   
2942      if (inferfrom ~= 0) {
2943          for (j=inferfrom : j<pcount : j++) {
2944              if (pattern-->j == PATTERN_NULL) continue;
2945              #Ifdef TARGET_ZCODE;
2946              i = 2+buffer->1; (buffer->1)++; buffer->(i++) = ' ';
2947              #Ifnot; ! TARGET_GLULX
2948              i = WORDSIZE + buffer-->0;
2949              (buffer-->0)++; buffer->(i++) = ' ';
2950              #Endif; ! TARGET_
2951   
2952              #Ifdef DEBUG;
2953              if (parser_trace >= 5) print "[Gluing in inference with pattern code ", pattern-->j, "]^";
2954              #Endif; ! DEBUG
2955   
2956              ! Conveniently, parse2-->1 is the first word in both ZCODE and GLULX.
2957   
2958              parse2-->1 = 0;
2959   
2960              ! An inferred object.  Best we can do is glue in a pronoun.
2961              ! (This is imperfect, but it's very seldom needed anyway.)
2962   
2963              if (pattern-->j >= 2 && pattern-->j < REPARSE_CODE) {
2964                  PronounNotice(pattern-->j);
2965                  for (k=1 : k<=LanguagePronouns-->0 : k=k+3)
2966                      if (pattern-->j == LanguagePronouns-->(k+2)) {
2967                          parse2-->1 = LanguagePronouns-->k;
2968                          #Ifdef DEBUG;
2969                          if (parser_trace >= 5) print "[Using pronoun '", (address) parse2-->1, "']^";
2970                          #Endif; ! DEBUG
2971                          break;
2972                      }
2973              }
2974              else {
2975                  ! An inferred preposition.
2976                  parse2-->1 = No__Dword(pattern-->j - REPARSE_CODE);
2977                  #Ifdef DEBUG;
2978                  if (parser_trace >= 5) print "[Using preposition '", (address) parse2-->1, "']^";
2979                  #Endif; ! DEBUG
2980              }
2981   
2982              ! parse2-->1 now holds the dictionary address of the word to glue in.
2983   
2984              if (parse2-->1 ~= 0) {
2985                  k = buffer + i;
2986                  #Ifdef TARGET_ZCODE;
2987                  @output_stream 3 k;
2988                   print (address) parse2-->1;
2989                  @output_stream -3;
2990                  k = k-->0;
2991                  for (l=i : l<i+k : l++) buffer->l = buffer->(l+2);
2992                  i = i + k; buffer->1 = i-2;
2993                  #Ifnot; ! TARGET_GLULX
2994                  k = PrintAnyToArray(buffer+i, INPUT_BUFFER_LEN-i, parse2-->1);
2995                  i = i + k; buffer-->0 = i - WORDSIZE;
2996                  #Endif; ! TARGET_
2997              }
2998          }
2999      }
3000   
3001      ! (2) we must glue the newly-typed text onto the end.
3002   
3003      #Ifdef TARGET_ZCODE;
3004      i = 2+buffer->1; (buffer->1)++; buffer->(i++) = ' ';
3005      for (j=0 : j<buffer2->1 : i++,j++) {
3006          buffer->i = buffer2->(j+2);
3007          (buffer->1)++;
3008          if (buffer->1 == INPUT_BUFFER_LEN) break;
3009      }
3010      #Ifnot; ! TARGET_GLULX
3011      i = WORDSIZE + buffer-->0;
3012      (buffer-->0)++; buffer->(i++) = ' ';
3013      for (j=0 : j<buffer2-->0 : i++,j++) {
3014          buffer->i = buffer2->(j+WORDSIZE);
3015          (buffer-->0)++;
3016          if (buffer-->0 == INPUT_BUFFER_LEN) break;
3017      }
3018      #Endif; ! TARGET_
3019   
3020      ! (3) we fill up the buffer with spaces, which is unnecessary, but may
3021      !     help incorrectly-written interpreters to cope.
3022   
3023      #Ifdef TARGET_ZCODE;
3024      for (: i<INPUT_BUFFER_LEN : i++) buffer->i = ' ';
3025      #Endif; ! TARGET_ZCODE
3026   
3027      return REPARSE_CODE;
3028   
3029  ]; ! end of NounDomain


Last updated 27 February 2004. The librarian in charge of this page is Graham Nelson (graham@gnelson.demon.co.uk) assisted by C Knight. Please email any comments, suggestions or corrections to cedenqs@inform-fiction.org.