| 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
|