Original Parser

version 1 by Ron Newcomb

  • Home page
  • Beginning
  • Previous
  • Next



  • Section - Parse Token__

    To decide if (token - a grammar token) isn't a first slashed synonym:
    (- (({token}->0) & (+last slashed synonym+)) -).

    To decide what parser result is the actual parsing of (y[given_tdata] - a grammar token) as (x[given_ttype] - a token type) at (this - number) and (token - a grammar token) (this is ParseToken__ Part A):
        now the noun filter is the nothing rule;
        bugfix now the current names list is the name list;
        let the very next be this + 1;
        let the word be an understood word;
        if x is:
            -- '<grammar token>':
                if y is:
                    -- 'understood word': [Either a number or understood word. Usually the latter despite the return value.]
                        now the number understood is the number typed in by the player at the parser's current word position;
                        now the numeric word is the next word;
                        if the number understood is not -1000:
                            if trace 3, say " [bracket]Read special as the number [the number understood][close bracket][line break]";
                        if the number understood is -1000:
                            if trace 3, say " [bracket]Read special word at word number [parser's current word position][line break]";
                            now the understood word understood is the numeric word;
                        decide on the parse succeeds as the-K-understood;
                    -- 'number':
                        now the number understood is the number typed in by the player at the parser's current word position;
                        increment the parser's current word position;
                        if the number understood is -1000:
                            issue "I didn't understand that number." as the didn’t understand that number error;
                            decide on parse fails;
                        if trace 3, say " [bracket]Read number as [the number understood][close bracket][line break]";
                        decide on the parse succeeds as the-K-understood;
                    -- 'text':
                        now the position of the topic understood is the parser's current word position;
                        unless the very next element of the grammar line types is '<understood word>' or the very next element of the grammar line tokens is the end of line token:
                            issue the 13th run-time message "A ’topic’ token can only be followed by a preposition." [...or the end of the line ];
                        while this isn't done:
                            now the word is the next word if any;
                        do that again until the word is no more words left to parse OR the word is one of the slashed synonyms that start at the very next position;
                        decrement the parser's current word position;
                        now the length of the topic understood is the parser's current word position - the position of the topic understood;
                        if the length of the topic understood is 0, decide on parse fails;
                        if the action to be is either the asking it about action or the answering it that action or the telling it about action: [not sure what this is doing. Turns topic understood to a single word? ]
                            let the saved spot be the parser's current word position;
                            now the parser's current word position is the position of the topic understood;
                            now the understood word understood is the next word;
                            now the parser's current word position is the saved spot;
                            decide on the parse succeeds as the-K-understood;
                        if the word is no more words left to parse and the very next element of the grammar line types is '<understood word>':
                            decide on parse fails; [ don't infer if required preposition is absent ]
                        decide on parse succeeds;
                    -- 'someone':
                        if the action to be is either the asking it about action or the answering it that action or the telling it about action or the asking it for action:
                            now the reason for deciding scope is because we're parsing the addressee;
            -- '<understood word>': [PREPOSITION_TT]
                [ Is it an unnecessary alternative preposition, when a previous choice has already been matched? ]
                if the token isn't a first slashed synonym, decide on parse succeeds;
                [ If we've run out of the player's input, but still have parameters to specify, we go into "infer" mode, remembering where we are and the preposition we are inferring... ]
                if the parser's current word position > the number of words in the command:
                    if 0 is where inferring the pattern from and the number of parameters in the command < the number of parameters for this line:
                        now where inferring the pattern from is the understood command's current position;
                        now the inferred preposition is the token as an understood word;
                        change (the understood command's current position) element of the player's understood command to y as an understood word as a pattern union;
                    [ If we are not inferring, then the line is wrong... ]
                    if 0 is where inferring the pattern from, decide on parse fails;
                    [ If not, then the line is right but we mark in the preposition... ]
                    change (understood command's current position) element of the player's understood command to y as an understood word as a pattern union;
                    decide on parse succeeds;
                now the word is the next word;
                change the (understood command's current position) element of the player's understood command to the word as a pattern union;
                [ Whereas, if the player has typed something here, see if it is the required preposition... if it's wrong, the line must be wrong, but if it's right, the token is passed (jump to finish this token). ]
                if the word is y as an understood word, decide on parse succeeds;
                if the word is one of the slashed synonyms that start at this position, decide on parse succeeds;
                decide on parse fails;
            -- '<understand token>': [ A "general parsing routine" which returns something of type "parser result" ]
                let the result be the parser result produced by (y as a filter); [too many parameters?]
                if trace 3, say " [bracket]Outside parsing routine returned [the result][close bracket][line break]";
                decide on the result;
            -- 'any <description of objects>':
                now the scope decider is y as a filter;
                now the scope stage is does this allow multiple objects;
                if trace 3, say " [bracket]Scope routine called at stage 1[close bracket][line break]";
                if the scope decider returns true, now y is 'things';
                otherwise now y is 'something';
                if trace 3, say " [bracket]Scope routine returned multiple-flag of [y][close bracket][line break]";
            -- '<adjective>':
                now the noun filter is y as an adjective filter;
                now y is 'something';
            -- '<description of values>':
                now the noun filter is y as a filter;
                now y is 'something';
        decide on the parsed token as a y.

    To decide what parser result is the parsed token as a (token - a grammar token) (this is ParseToken Parts BCDEF):
        let accept multiple objects be whether or not the token is either 'things' or 'things preferably held' or 'other things' or 'things inside'; [token_allows_multiple]
        let the singular object be an object; [ the eventual return value ]
        we may make inferences; [dont_infer, negated]
        let have many objects in the command be false; [many_flag]
        now the saved number of items wanted is the number of items wanted; [prev_indef_wanted]
        let assume 'AND' means add objects be true; [and_parity]
        let the word be the comma;
        while the word is the comma or the word is 'AND' or the word is 'BUT': [this is .ObjectList ]
            if trace 3, say " [bracket]Object list from word [parser's current word position][close bracket][line break]";
            [ Peek ahead and see if there's a pronoun. ]
            now the word is the next word;
            decrement the parser's current word position;
            now the pronoun used is no more words left to parse;
            now the pronoun reference object is the used-up object;
            now the singular object [presumably an antecedent] is what the word [presumably a pronoun] stands for;
            if the singular object is not nothing:
                now the pronoun used is the word;
                now the pronoun reference object is the singular object;
                if the singular object is the used-up object:
                    now the saved pronoun used is the pronoun used;
                    now the saved pronoun reference object is the pronoun reference object;
                    issue "I'm not sure what that pronoun refers to." as the not sure what it refers to error;
                    if trace 3, say " [bracket]Stop: unset pronoun[close bracket][line break]";
                    decide on parse fails;
            if the word is 'ME':
                now the pronoun used is the word;
                now the pronoun reference object is the player;
            we should allow numeric words as descriptors;
            now where the descriptor starts is the parser's current word position; [desc_wn]
            (At this point we TryAgain);
            now any problems is the result of parsing determiners like ALL\OTHER\FIVE\MY\THESE\HIS\THE\AN\SOME\etc;
            unless any problems is no errors here:
                now the latest parser error is any problems;
                decide on parse succeeds; [do what?? succeeds? ]
            (At this point we TryAgain2 due to an ambiguous descriptor word);
            now where the previous typo's at is the parser's current word position;
            let the former list size be the number of elements in the multiple-object list;
            if trace 3, say " [bracket]Calling NounDomain on location and actor[close bracket][line break]";
            let pu be the noun domain the actor's scopewise location and the person asked under the token;
            if pu is the misunderstood command, decide on reparsing;
            if the token is 'something preferably held':
                if pu is noun domain's no match:
                    if we still assume leading words to be descriptors:
                        reset descriptor words;
                        now the parser's current word position is where the descriptor starts;
                        Go back up to where we TryAgain2 due to an ambiguous descriptor word; [-->]
                    otherwise:
                        now the latest parser error is a more specific error if possible;
                        decide on what the token fails as unless it's reparsing;
                        Go back up to where we TryAgain; [-->]
                if the parent of pu as an object is not the person asked:
                    if trace 3, say " [bracket]Allowing object [the pu as an object] for now[close bracket][line break]"; [implicit take coming up]
                now the singular object is pu as an object;
            otherwise:
                if pu is noun domain's no match and the number of objects in the match list is 0 and the number of items wanted is all items are wanted:
                    now pu is noun domain's bunch of objects; [ ReviseMulti if TAKE ALL FROM empty container]
                if we accept multiple objects and we haven't process the multiple object list:
                    if the best parser error so far is the can't use multiple objects error:
                        now the best parser error so far is the didn't understand error;
                    we should process the multiple object list;
                if pu is noun domain's no match:
                    if we still assume leading words to be descriptors:
                        reset descriptor words;
                        now the parser's current word position is where the descriptor starts;
                        Go back up to where we TryAgain2 due to an ambiguous descriptor word;[-->]
                    otherwise:
                        if we should process the multiple object list and the latest parser error is either the can't use multiple objects error or the not enough of those available error:
                            now the latest parser error is the didn't understand error;
                        now the latest parser error is a more specific error if possible;
                        decide on what the token fails as unless it's reparsing;
                        Go back up to where we TryAgain; [-->]
                if trace 3, say that pu matched with the former list size;
                if pu is noun domain's bunch of objects:
                    if we do not have many objects in the command:
                        we now have many objects in the command;
                    otherwise:
                        if trace 3, say " [bracket]Merging [number of elements in the multiple-object list minus the former list size] new objects to the [number of elements in the multiple-object list] old ones[close bracket][line break]";
                        unless we assume 'AND' means add objects: [ND already added them? ] [ TEST THIS ]
                            repeat through the multiple-object list starting at the former list size + 1:
                                remove the multiple-object list element from the multiple-object list;
                otherwise:
                    if the number of words matched per object is 0 and we still assume leading words to be descriptors:
                        [ So the answer had to be inferred from no textual data, and we know that there was an ambiguity in the descriptor stage (such as a word which could be a pronoun being parsed as an article or possessive). It's worth having another go.]
                        reset descriptor words;
                        now the parser's current word position is where the descriptor starts;
                        Go back up to where we TryAgain2 due to an ambiguous descriptor word;[-->]
                    if the token is 'someone':
                        unless pu as an object is a creature:
                            now the latest parser error is the can only do that to something animate error;
                            decide on what the token fails as unless it's reparsing;
                            Go back up to where we TryAgain; [-->]
                    if we do not have many objects in the command:
                        now the singular object is pu as an object;
                    otherwise:
                        if we assume 'AND' means add objects:
                            add pu as an object to the multiple-object list;
                        otherwise:
                            remove pu as an object from the multiple-object list;
                        if trace 3, say " [bracket]Combining [the pu as an object] with list[close bracket][line break]";
            now the parser's current word position is where the previous typo's at + the number of words matched per object;
            [ PARSE TOKEN LETTER E ]
            [ Getting ready to loop back to "while the word is 'AND' or 'BUT'.... ]
            now the word is the next word;
            if the word is 'AND' or the word is 'BUT' or the word is the comma:
                if trace 3, say " [bracket]Read connective '[the word]'[close bracket][line break]";
                if we do not accept multiple objects:
                    unless we still process the multiple object list:
                        now the latest parser error is the can't use multiple objects error;
                        decide on what the token fails as unless it's reparsing;
                        Go back up to where we TryAgain; [-->]
                    otherwise:
                        increment the parser's current word position;
                        break; [ out of the ObjectList loop ]
                if the word is 'BUT':
                    we will assume 'AND' means add objects if we shouldn't assume 'AND' means add objects;
                if we do not have many objects in the command:
                    change the multiple-object list to have 1 elements;
                    change the 1st element of the multiple-object list to the singular object;
                    we now have many objects in the command;
                    if trace 3, say " [bracket]Making new list from [the singular object][close bracket][line break]";
                we shouldn't make inferences;
                now where inferring the pattern from is 0;
        decrement the parser's current word position;
        [ PARSE TOKEN LETTER F -- PassToken ]
        if we have many objects in the command:
            now the kind of multi is the token;
            decide on the resulting objects;
        if indefinite article mode is false or the type of descriptor word used does not include a plural descriptor:
            decide on the singular object as a parser result;
        if the number of items wanted < 2:
            decide on the singular object as a parser result;
        [ otherwise we have a problem ]
        now the latest parser error is the not enough of those available error;
        now the number of items actually received is 1;
        now the number of items wanted previously wanted is the number of items wanted;
        decide on what the token fails as unless it's reparsing;
        go back up to where we TryAgain.

    To decide on (phrase - a parser result) unless it's (pr - a parser result):
    (- cacheval4 = {phrase};
        if (cacheval4 ~= {pr}) return cacheval4; -).

    Where the descriptor starts is a number that varies.
    The saved number of items wanted is a number that varies.

    To decide what parser result is what the token fails as (this is ParseToken__ FailToken):
        [(At this point we FailToken);] [ If we were only guessing about it being a plural, try again but only allowing singulars (so that words like "six" are not swallowed up as Descriptors) ][-->]
        if we allow numeric words as descriptors and probably plural is true:
            if trace 4, say " [bracket]Retrying singulars after failure [latest parser error][close bracket][line break]";
            now the saved number of items wanted is the number of items wanted;
            we shouldn't allow numeric words as descriptors;
            now the parser's current word position is where the descriptor starts;
            decide on reparsing; [Go back up to where we TryAgain;[-->]]
        if (the number of items wanted is at least 1 or the saved number of items wanted is at least 1) and we haven't process the multiple object list:
            now the latest parser error is the can't use multiple objects error;
        decide on parse fails.


    [for (we allow numeric words as descriptors;
        failtoken not :
        failtoken = retrysingular?)
    ]

    [ ParseToken__ given_ttype given_tdata token_n token
        l o i j k and_parity single_object desc_wn many_flag
        token_allows_multiple prev_indef_wanted;

    token_filter = 0;
    parser_inflection = name;

    switch (given_ttype) {
    ELEMENTARY_TT:
    switch (given_tdata) {
    SPECIAL_TOKEN: ! special number token
    l = TryNumber(wn);
    special_word = NextWord();
    #Ifdef DEBUG;
    if (l ~= -1000)
    if (parser_trace >= 3) print " [Read special as the number ", l, "]^";
    #Endif; ! DEBUG
    if (l == -1000) {
    #Ifdef DEBUG;
    if (parser_trace >= 3) print " [Read special word at word number ", wn, "]^";
    #Endif; ! DEBUG
    l = special_word;
    }
    parsed_number = l;
    return GPR_NUMBER;

    NUMBER_TOKEN:
    l=TryNumber(wn++);
    if (l == -1000) {
    etype = NUMBER_PE;
    return GPR_FAIL;
    }
    #Ifdef DEBUG;
    if (parser_trace>=3) print " [Read number as ", l, "]^";
    #Endif; ! DEBUG
    parsed_number = l;
    return GPR_NUMBER;

    CREATURE_TOKEN:
    if (action_to_be == ##Answer or ##Ask or ##AskFor or ##Tell)
    scope_reason = TALKING_REASON;

    TOPIC_TOKEN:
    consult_from = wn;
    if ((line_ttype-->(token_n+1) ~= PREPOSITION_TT) &&
    (line_token-->(token_n+1) ~= ENDIT_TOKEN))
    RunTimeError(13);
    do o = NextWordStopped();
    until (o == -1 || PrepositionChain(o, token_n+1) ~= false);
    wn--;
    consult_words = wn-consult_from;
    if (consult_words == 0) return GPR_FAIL;
    if (action_to_be == ##Ask or ##Answer or ##Tell) {
    o = wn; wn = consult_from; parsed_number = NextWord();
    wn = o; return 1;
    }
    if (o==-1 && (line_ttype-->(token_n+1) == PREPOSITION_TT))
    return GPR_FAIL; ! don't infer if required preposition is absent
    return GPR_PREPOSITION;
    }

    PREPOSITION_TT:
    ! Is it an unnecessary alternative preposition, when a previous choice
    ! has already been matched?
    if ((token->0) & $10) return GPR_PREPOSITION;

    ! If we've run out of the player's input, but still have parameters to
    ! specify, we go into "infer" mode, remembering where we are and the
    ! preposition we are inferring...

    if (wn > num_words) {
    if (inferfrom==0 && parameters<params_wanted) {
    inferfrom = pcount; inferword = token;
    pattern-->pcount = REPARSE_CODE + VM_DictionaryAddressToNumber(given_tdata);
    }

    ! If we are not inferring, then the line is wrong...

    if (inferfrom == 0) return -1;

    ! If not, then the line is right but we mark in the preposition...

    pattern-->pcount = REPARSE_CODE + VM_DictionaryAddressToNumber(given_tdata);
    return GPR_PREPOSITION;
    }

    o = NextWord();

    pattern-->pcount = REPARSE_CODE + VM_DictionaryAddressToNumber(o);

    ! Whereas, if the player has typed something here, see if it is the
    ! required preposition... if it's wrong, the line must be wrong,
    ! but if it's right, the token is passed (jump to finish this token).

    if (o == given_tdata) return GPR_PREPOSITION;
    if (PrepositionChain(o, token_n) ~= false) return GPR_PREPOSITION;
    return -1;

    GPR_TT:
    l = indirect(given_tdata);
    #Ifdef DEBUG;
    if (parser_trace >= 3) print " [Outside parsing routine returned ", l, "]^";
    #Endif; ! DEBUG
    return l;

    SCOPE_TT:
    scope_token = given_tdata;
    scope_stage = (+ does this allow multiple objects +);
    #Ifdef DEBUG;
    if (parser_trace >= 3) print " [Scope routine called at stage 1]^";
    #Endif; ! DEBUG
    l = scope_token(); ! truth state
    ! if the scope decider returns true,
    if (l == 1) given_tdata = (+ 'things' +); else given_tdata = (+ 'something' +);
    #Ifdef DEBUG;
    if (parser_trace >= 3) print " [Scope routine returned multiple-flag of ", l, "]^"; ! use given_tdata in here
    #Endif; ! DEBUG

    ATTR_FILTER_TT:
    token_filter = 1 + given_tdata;
    given_tdata = NOUN_TOKEN;

    ROUTINE_FILTER_TT:
    token_filter = given_tdata;
    given_tdata = NOUN_TOKEN;

    } ! end of switch(given_ttype)

    token = given_tdata;


    !Chapter - Parse Token Letter B

    ![Begin parsing an object list.]

    !Include (-
    ! There are now three possible ways we can be here:
    ! parsing an elementary token other than "special" or "number";
    ! parsing a scope token;
    ! parsing a noun-filter token (either by routine or attribute).
    !
    ! In each case, token holds the type of elementary parse to
    ! perform in matching one or more objects, and
    ! token_filter is 0 (default), an attribute + 1 for an attribute filter
    ! or a routine address for a routine filter.

    token_allows_multiple = false;
    if (token == MULTI_TOKEN or MULTIHELD_TOKEN or MULTIEXCEPT_TOKEN or MULTIINSIDE_TOKEN)
    token_allows_multiple = true;

    many_flag = false; and_parity = true; dont_infer = true; !false;


    !Chapter - Parse Token Letter C

    ![Parse descriptors (articles, pronouns, etc.) in the list.]

    !Include (-
    ! We expect to find a list of objects next in what the player's typed.

    .ObjectList;

    #Ifdef DEBUG;
    if (parser_trace >= 3) print " [Object list from word ", wn, "]^";
    #Endif; ! DEBUG

    ! Take an advance look at the next word: if it's "it" or "them", and these
    ! are unset, set the appropriate error number and give up on the line
    ! (if not, these are still parsed in the usual way - it is not assumed
    ! that they still refer to something in scope)

    o = NextWord(); wn--;

    pronoun_word = NULL; pronoun_obj = NULL;
    l = PronounValue(o);
    if (l ~= 0) {
    pronoun_word = o; pronoun_obj = l;
    if (l == NULL) {
    ! Don't assume this is a use of an unset pronoun until the
    ! descriptors have been checked, because it might be an
    ! article (or some such) instead

    for (l=1 : l<=LanguageDescriptors-->0 : l=l+4)
    if (o == LanguageDescriptors-->l) jump AssumeDescriptor; ! i'm pretty sure this is unattainable. If the word 'o' was an article or some such, then PronounValue would've returned 0 and we wouldn't be here to begin with.
    pronoun__word = pronoun_word; pronoun__obj = pronoun_obj;
    etype = VAGUE_PE;
    if (parser_trace >= 3) print " [Stop: unset pronoun]^";
    return GPR_FAIL;
    }
    }

    .AssumeDescriptor;

    if (o == ME1__WD or ME2__WD or ME3__WD) { pronoun_word = o; pronoun_obj = player; }

    allow_plurals = true; desc_wn = wn;

    .TryAgain;

    ! First, we parse any descriptive words (like "the", "five" or "every"):
    l = Descriptors(token_allows_multiple); ! this function does not use this value
    if (l ~= 0) { etype = l; return 0; }

    .TryAgain2;


    !Chapter - Parse Token Letter D

    ![Parse an object name.]

    !Include (-
    ! This is an actual specified object, and is therefore where a typing error
    ! is most likely to occur, so we set:

    oops_from = wn;

    ! So, two cases. Case 1: token not equal to "held" (so, no implicit takes)
    ! but we may well be dealing with multiple objects

    ! In either case below we use NounDomain, giving it the token number as
    ! context, and two places to look: among the actor's possessions, and in the
    ! present location. (Note that the order depends on which is likeliest.)

    if (token ~= HELD_TOKEN) {
    i = multiple_object-->0;
    #Ifdef DEBUG;
    if (parser_trace >= 3) print " [Calling NounDomain on location and actor]^";
    #Endif; ! DEBUG
    l = NounDomain(actors_location, actor, token);
    if (l == REPARSE_CODE) return l; ! Reparse after Q&A
    if (indef_wanted == INDEF_ALL_WANTED && l == 0 && number_matched == 0)
    l = 1; ! ReviseMulti if TAKE ALL FROM empty container

    if (token_allows_multiple && ~~multiflag) {
    if (best_etype==MULTI_PE) best_etype=STUCK_PE;
    multiflag = true;
    }
    if (l == 0) {
    if (indef_possambig) {
    ResetDescriptors();
    wn = desc_wn;
    jump TryAgain2;
    }
    if (etype == MULTI_PE or TOOFEW_PE && multiflag) etype = STUCK_PE;
    etype=CantSee();
    jump FailToken;
    } ! Choose best error

    #Ifdef DEBUG;
    if (parser_trace >= 3) {
    if (l > 1) print " [ND returned ", (the) l, "]^";
    else {
    print " [ND appended to the multiple object list:^";
    k = multiple_object-->0;
    for (j=i+1 : j<=k : j++)
    print " Entry ", j, ": ", (The) multiple_object-->j,
    " (", multiple_object-->j, ")^";
    print " List now has size ", k, "]^";
    }
    }
    #Endif; ! DEBUG

    if (l == 1) {
    if (~~many_flag) many_flag = true;
    else { ! Merge with earlier ones
    k = multiple_object-->0; ! (with either parity)
    multiple_object-->0 = i;
    for (j=i+1 : j<=k : j++) {
    if (and_parity) MultiAdd(multiple_object-->j);
    else MultiSub(multiple_object-->j);
    }
    #Ifdef DEBUG;
    if (parser_trace >= 3)
    print " [Merging ", k-i, " new objects to the ", i, " old ones]^";
    #Endif; ! DEBUG
    }
    }
    else {
    ! A single object was indeed found

    if (match_length == 0 && indef_possambig) {
    ! So the answer had to be inferred from no textual data,
    ! and we know that there was an ambiguity in the descriptor
    ! stage (such as a word which could be a pronoun being
    ! parsed as an article or possessive). It's worth having
    ! another go.

    ResetDescriptors();
    wn = desc_wn;
    jump TryAgain2;
    }

    if ((token == CREATURE_TOKEN) && (CreatureTest(l) == 0)) {
    etype = ANIMA_PE;
    jump FailToken;
    } ! Animation is required

    if (~~many_flag) single_object = l;
    else {
    if (and_parity) MultiAdd(l); else MultiSub(l);
    #Ifdef DEBUG;
    if (parser_trace >= 3) print " [Combining ", (the) l, " with list]^";
    #Endif; ! DEBUG
    }
    }
    }

    else {

    ! Case 2: token is "held" (which fortunately can't take multiple objects)
    ! and may generate an implicit take

    l = NounDomain(actor,actors_location,token); ! Same as above...
    if (l == REPARSE_CODE) return l;
    if (l == 0) {
    if (indef_possambig) {
    ResetDescriptors();
    wn = desc_wn;
    jump TryAgain2;
    }
    etype = CantSee(); jump FailToken; ! Choose best error
    }

    ! ...until it produces something not held by the actor. Then an implicit
    ! take must be tried. If this is already happening anyway, things are too
    ! confused and we have to give up (but saving the oops marker so as to get
    ! it on the right word afterwards).
    ! The point of this last rule is that a sequence like
    !
    ! > read newspaper
    ! (taking the newspaper first)
    ! The dwarf unexpectedly prevents you from taking the newspaper!
    !
    ! should not be allowed to go into an infinite repeat - read becomes
    ! take then read, but take has no effect, so read becomes take then read...
    ! Anyway for now all we do is record the number of the object to take.

    o = parent(l);
    if (o ~= actor) {
    #Ifdef DEBUG;
    if (parser_trace >= 3) print " [Allowing object ", (the) l, " for now]^";
    #Endif; ! DEBUG
    }
    single_object = l;
    } ! end of if (token ~= HELD_TOKEN) else

    ! The following moves the word marker to just past the named object...

    wn = oops_from + match_length;


    !Chapter - Parse Token Letter E

    ![Parse connectives (AND, BUT, etc.) and go back to (C).]

    !Include (-
    ! Object(s) specified now: is that the end of the list, or have we reached
    ! "and", "but" and so on? If so, create a multiple-object list if we
    ! haven't already (and are allowed to).

    ! .NextInList;

    o = NextWord();

    if (o == AND1__WD or AND2__WD or AND3__WD or BUT1__WD or BUT2__WD or BUT3__WD or comma_word) {

    #Ifdef DEBUG;
    if (parser_trace >= 3) print " [Read connective '", (address) o, "']^";
    #Endif; ! DEBUG

    if (~~token_allows_multiple) {
    if (multiflag) jump PassToken; ! give UPTO_PE error
    etype=MULTI_PE;
    jump FailToken;
    }

    if (o == BUT1__WD or BUT2__WD or BUT3__WD) and_parity = 1-and_parity;

    if (~~many_flag) {
    multiple_object-->0 = 1;
    multiple_object-->1 = single_object;
    many_flag = true;
    #Ifdef DEBUG;
    if (parser_trace >= 3) print " [Making new list from ", (the) single_object, "]^";
    #Endif; ! DEBUG
    }
    dont_infer = false; !true;
    inferfrom=0; ! Don't print (inferences)
    jump ObjectList; ! And back around
    }

    wn--; ! Word marker back to first not-understood word


    !Chapter - Parse Token Letter F

    ![Return the conclusion of parsing an object list.]

    !Include (-
    ! Happy or unhappy endings:

    .PassToken;

    if (many_flag) {
    single_object = GPR_MULTIPLE;
    multi_context = token;
    }
    else {
    if (indef_mode == 1 && indef_type & PLURAL_BIT ~= 0) {
    if (indef_wanted < INDEF_ALL_WANTED && indef_wanted > 1) {
    multi_had = 1; multi_wanted = indef_wanted;
    etype = TOOFEW_PE;
    jump FailToken;
    }
    }
    }
    return single_object;

    .FailToken;

    ! If we were only guessing about it being a plural, try again but only
    ! allowing singulars (so that words like "six" are not swallowed up as
    ! Descriptors)

    if (allow_plurals && indef_guess_p == 1) {
    #Ifdef DEBUG;
    if (parser_trace >= 4) print " [Retrying singulars after failure ", etype, "]^";
    #Endif;
    prev_indef_wanted = indef_wanted;
    allow_plurals = false;
    wn = desc_wn;
    jump TryAgain;
    }

    if ((indef_wanted > 0 || prev_indef_wanted > 0) && (~~multiflag)) etype = MULTI_PE;

    return GPR_FAIL;

    ]