% This file contains the full parser. It can handle all the sentences in 
% test.txt, test_grad.txt, and interesting.txt.


%
% First, declare the features that we will be using in the parser.
g_features([number,               % singular or plural - used to match number in subject and verb
            person,               % first, second, third: used to mach person in subject and verb
            case,                 % nominative, accusative: used to match form of pronoun & relation to ver
            form,                 % form of verb: infinitive, finite, pastParticiple, presentParticiple
            auxtense,             % form of aux verb: pastParticiple, finite, infinitive, presentParticiple
			finite,               % if the verb is finite (ie not infinitive), this is set to true
            mood,                 % mood of sentence: question, assertion
            whphrase,             % has value 'yes' if an np phrase has a wh-pronoun or wh-determiner
            restriction,          % property that nests other properties: the properties of a subordinate clause
			pprestriction,        % property that nests other properties: the properties of a prepositional phrase
            role,                 % patient, recipient, agent, destination: pragmatic role in sentence of an np
            subjrole,             % pragmatic role of the subject np in a sentence
            npcount,              % count or mass: describes nps, determines the kind of determiners it can take
			nptype,               % fact about noun phrases that semantics uses
			vptype,               % fact about verb phrases that semantics uses
            tense,                % not well implemented now: contains inforamtion about past, present of verb
            verbtype,             % like nptype, contains class or semantic information about the verb
            ppcase,               % the role of the pp when it's a vp complement
            pptypes,              % the types of complements a preposition can take
            modifiesList,         % the types of phrases a pp can modify
            subcat,               % the subcategories of complement that a verb will accept
            gender,               % grammatical gender of a word, person or pronoun
			value,                % numerical value of a quantifier
			adjform,              % if an adjective is regular, superlative or comparative
			destination,          % role for a prep phrase
			source,               % role for a prep phrase
			possessor,            % role for a prep phrase
			recipient,            % role for a prep phrase
			time,                 % role for a prep phrase
			location,             % role for a prep phrase
			agent,                % role for a prep phrase
			vppassive,            % set to 'yes' if the verb phrase uses a passive construction
            toinf_complement,     % property that nests other properties: the properties of a to-infinitive vp complement
            pp_complement,        % property that nests other properties: the properties of a pp vp complement
            dobj_complement,      % property that nests other properties: the properties of a direct object vp complement
            iobj_complement,      % property that nests other properties: the properties of an indirect object vp complement
			modal_complement      % property that nests other properties: the properties of a vp following a modal verb
            ]).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% PARSER
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% General notes: What follows are productions in a DCG format. This means that
% in terms of ordinary Prolog rules, these have two implicit parameters
% representing difference lists. Every now and then, we have occassion to
% use standard Prolog predicates. These are marked by being enclosed in
% curly brackets. Another bit of notation particular to DCG productions is
% [word] to match an exact word. For example, infinitive constructions are
% parsed similar to this: vp (Infinitive) --> [to], infinitive(Infinitive).
% This may be read as: to parse a verb phrase with the parse tree bound to
% the variable Infinitive, first parse the word "to", then use the predicate
% "infinitive" to produce the parse tree for an infinitive construction,
% bound to "Infinitive".
% Functors of the form head(element1, element2, ..., element n) are a way of
% building up data structures.
% Gap handling is somewhat complicated; see the external documentation.
% In general, if a gap is parsed on the right hand side of the production,
% we have a parameter for a gap on the left hand side.
% Some predicates (e.g. "aux" are not defined here, but in the file "lexicon"
% because they are lexical predicates.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% FORMAT: s(S).
%         S - parse tree
%
% The following rule maps the sentence predicate with one parameter (the
% parse tree) to the sentence predicate with three parameters:
%           S - parse tree of the sentence
%           Features of the sentence (in Gulp):
%               sentence:(mood:  question, assertion, command)
%           Gap - nogap, gap(np,NPTree,NPFeatures), gap(pp,PPTree,PPFeatures)
% The one-parm predicate is true of well-formed sentences
% having no gap in them.
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% A nice interface for testing in the prolog environment:
% To parse a sentence s with parse tree S, parse s with parse tree S, of type
%  SentenceType, without a gap.

s( S ) --> s( S,SentenceFeatures, nogap),
           {prettytree(S), nl,
		   g_display(SentenceFeatures), nl}.

% similarly for noun phrases
np( NP) --> np(NP, NPFeatures, nogap),
            {prettytree(NP),nl,
			g_display(NPFeatures), nl}.

% and for prepositional phrases
pp( PP) --> pp( PP, PPFeatures, nogap),
            {prettytree(PP),nl,
			g_display(PPFeatures), nl}.

% and for verb phrases
vp( VP) --> vp( VP, VPFeatures, nogap),
            {prettytree(VP),nl,
			g_display(VPFeatures), nl}.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% FORMAT: s(S,SentenceFeatures,Gap)
%         S - parse tree
%         SentenceFeatures 
%               sentence:(mood:  question, assertion, command)
%         Gap - nogap, gap(np,NPTree,NPFeatures)
%
% The following rules match the sentence to its type:
%         assertion - np followed by vp
%		  - for-to clause followed by vp
%         command - dummy np (you) followed by vp
%         question - sinv
%                  - whnp followed by vp
%                  - whnp followed by sinv having an np gap 
%                    (missing object) or pobj gap (missing
%                     object of a preposition).
%		           - wh_adverb followed by an sinv
%                  - whpp (includes whadverb) followed by sinv having
%                    a pp(Prep) gap
%
% Cases for the np are fixed, and number and person of np and vp
% must agree.
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%
% assertions
%

% e.g. "I saw the man on the hill".
% To parse a sentence s such that 
% 1) its parse tree is an s-assert consisting of a noun phrase and a verb phrase
% 2) it is of type assertion
% 3) it may or may not have a gap,
% parse a noun phrase and a verb phrase.
% The noun phrase should have no gap, and is the subject, hence nominative.
% The verb phrase may have a gap, and should be finite (i.e. conjugated).
% NP and VP must agree in Number and Person.


s( s_assert(NP,VP), Features, Gap) -->
     {Features = mood:assertion..whphrase:no..finite:yes},
     np( NP, Features, nogap),		
     vp( VP, Features, Gap),
     {Features = case:nominative}.


% 
%
% questions
%

% A question which is a regular assert sentence in terms of syntax, but there's
% a wh-word in the subject noun phrase, making the whole thing a question.

s( s_question(NP, VP), Features, nogap) -->
    {Features = mood:question..whphrase:yes..finite:yes},
    np(NP, Features, nogap),
    vp(VP, Features, nogap),
    {Features = case:nominative}.
	


% A simple inverted question, e.g. "Did you see the man on the hill?"
% Such a question has the parse tree of an inverted sentence, is of type
% question, may contain a gap, and is parsed as an inverted sentence.

s( s_question(SInv), Features, Gap) -->
    {Features = mood:question..case:nominative},
     sinv( SInv, Features, Gap).

% Next, straightforward wh-noun phrase, verb phrase questions, e.g
% "Who saw the man on the hill?" The wh-noun phrase is in the nominative 
% case.
% We know a np is a wh-np, because it sets the feature 'whphrase:yes'.
% To make sure this happens, add the feature 'whphrase:yes' to your lexical
% entries for wh-determiners (like which and what) and wh-pronouns (like
% what and who).
% By now, this rule should be easy to read.

s( s_question(WhNP,VP), Features, nogap) -->
    {Features = mood:question..whphrase:yes..case:nominative..finite:yes},
     np( WhNP, Features, nogap), 
     vp( VP, Features, nogap).


% Now, sentences where there is a np that has been wh-fronted
% out from either a pp or the complement of a vp, as in:
% 'Which man did you give to'  (for pp)  or
% 'Which stamp did you give'   (for vp)
s( s_question(WhNP,VP), Features, nogap) -->
     {Features = mood:question},
     {NPFeatures = whphrase:yes..case:accusative},
     np( WhNP, NPFeatures, nogap),
     sinv( VP, Features, gap(np, WhNP, NPFeatures)),
	 {Features = case:nominative}.


% Sentence with a wh-fronted prepositional phrase.
% We parse off the whole prep phrase, then pass it in as a gap.
% Example: 'in what office did the man give'
s( s_question(PP, VP), Features, nogap) -->
     {Features = mood:question},
     {PPFeatures = whphrase:yes},
     pp(PP, PPFeatures, nogap),
     {copy_term(PPFeatures, GapFeatures)},
     sinv(VP, Features, gap(pp, PP, GapFeatures)).

% Imperative sentence
% Example 'list all movies'
s( s_imperative(np(dummy_you), VP), Features, nogap) -->
     {Features = mood:imperative..person:second..form:infinitive..finite:no},
	 vp(VP, Features, nogap).  

% Sentence with a wh-adverb at the front
% eg. 'when will i go there'
% or 'how do i buy it'
s( s_question(modifier(WhAdv), SInverted), Features, nogap) -->
     whadverb(WhAdv, Features),
	 sinv(SInverted, Features, nogap).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% FORMAT sinv(SINV,Features, Gap)
%        SINV - parse subtree
%        Gap - nogap, gap(np,NPTree,NPFeatures), gap(pp,PPTree,PPFeatures)
%
% The following rule deals with subject/aux inverted sentences.  Conceptually
% it rearranges the sentence so that the auxiliary comes after the initial
% np and then parses it just like a non-inverted sentence.
% 
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% For inverted sentences. First we parse the auxiliary
% Next we parse a noun phrase and store it in NP.
% We then re-insert the auxiliary back into the input stream of words
% to be parsed, and parse the verb phrase.
% We use Diff1 and Diff2 instead of DCG format (which keeps these two parameters
% implicit) because we need to look ahead at what words come in the sentence.


sinv( sinv(NP,VP), Features, Gap, InputWords, OutputWords) :-     
  
  % parse the auxiliary verb off the head of InputWords, and put the list
  % of what's left into AuxTail.
	aux( aux(Aux), Features, InputWords, AuxTail ),
  
  % now parse the np off of AuxTail, and return whatever's left after 
  % parsing an NP in NPTail.
	np( NP, Features, nogap, AuxTail, NPTail ),
  
  % Now stick the Auxiliary we already parsed off back into the list
  % of words to parse.
	append( [Aux], NPTail, VPHead ),
  
  % Now the verb phrase will be parsed from VPHead to OutputWords.
	vp( VP, Features, Gap, VPHead, OutputWords ).


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% FORMAT np(NP,Features, Gap)
%        NP - parse subtree
%        Features
%          number..person..case..type
%        Gap - nogap, gap(np,NPTree,NPFeatures)

%
% The following rules deal with noun phrases.  A noun phrase is:
%          1) gap(np,NPTree,NPFeatures)
%          2) a pronoun
%          3) a proper noun, or a compound (multi-word) proper noun
%          4) an optional determiner followed by adjectives, a noun and an
%            optional relative clause or a prepositional phrase
%          
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%   Case 1   an np may be filled by a gap. 
%
%      NP
%      | 
%    [Gap]    e.g. The man who runs ... Gap holds "The man".
%                  After 'who', we need a noun phrase for the sentence 'x runs'.
%                  The Gap is subbed in for the np, and we get 'The man runs'
% 
np( np(gap(NP)), GapFeaturesCopy, gap(np,NP, GapFeatures)) --> 
     [],
	 {copy_term(GapFeatures, GapFeaturesCopy)}.


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%   Case 2  - a pronoun
%
%      NP
%      | 
%    Pron
  
np(np(Pronoun), NPFeatures, nogap) -->
    pronoun(Pronoun, NPFeatures).



%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%    Case 3 - a proper noun
%
%      NP
%      | 
%    Propernoun  
%
np(np(ProperNoun), NPFeatures, nogap) -->
    pnoun(ProperNoun, NPFeatures).


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%   Case 4 - noun phrase with optional determiners
%   and adjectives.
%
%                 NP
% +---------+-----|-----+
% |         |     |     |
% (det)  *(adjs)  N   (clause)
%

% We handle the optional clause by first parsing a noun
% phrase, and then using that freshly-made noun phrase
% as a gap to see if we can create a clause.
% E.g. in "The man who [gap:the man] likes candy", 
% we finish parsing "The man" as an np, and 
% we need to pass  this np along so the clause 
% "x likes candy" can have a gap to use for x.
% Gap is also used for nps like "the stamp that I 
% can buy [gap:the stamp]" or 
% "whom did I buy the stamp for [gap:whom]?"

% Start parsing a noun phrase by calling np_Determiner, to look
% for a determiner; this rule will then call the next element down
% the line, until we're done.

np(NPTree, NPFeatures, nogap) -->
  {NPFeatures = person:third},	  % because you can't have a non-pronoun noun phrase that's not 3rd person
  np_Determiner(NPTree, NPFeatures).

% After the np has been parsed (which we start doing by calling
% np_Determiner), we call np_Clause to look for a relative clause.
np(np(NPTree, ClauseTree), NPFeatures, nogap) --> 
  {NPFeatures = person:third},
  np_Determiner(NPTree, NPFeatures),
  np_Clause(ClauseTree, ClauseFeatures, gap(np, NPTree, NPFeatures)),
  {NPFeatures=restriction:(ClauseFeatures)}.



%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%   Case 5 - noun phrase with a prep phrase
%   attached 'the man with a dog' or 'the house of that man'
%
%                 NP
% +---------+-----|-----+
% |         |     |     |
% (det)  *(adjs)  N    pp


% After the np has been parsed (which we start doing by calling
% np_Determiner), we call pp to look for a prepositional phrase
np(np(NPTree, PPTree), NPFeatures, nogap) --> 
  np_Determiner(NPTree, NPFeatures),
  pp(PPTree, PPFeatures, nogap),
  {PPFeatures = ppcase:PPRole},
  {restrictrole(PPRole, RestrictFeatures, PPFeatures)},
  {NPFeatures = restriction:(RestrictFeatures)}.


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%   Case 6 - noun phrase of the form
%   'for np to vp'
%   as in 'for her to argue'
%
%      NP
% +----+-----+-----+
% |    |     |     |
% for  NP    to    vp


np(np(for, NP, VP), Features, nogap) --> 
  [for],
  {SFeatures = case:accusative},
  np(NP, SFeatures, nogap),
  [to],
  {SFeatures = form:infinitive..finite:no},
  vp(VP, SFeatures, nogap),
  {Features = restriction:(SFeatures)..person:third..number:singular..whphrase:no}. 
  

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%   Case 7 - noun phrase using a verb gerund:
%   'buying a house is nice' or 'eating at a restaurant with her gives pleasure'

%      NP
%      |
%   vp(ing)  

np(np_gerund(Verb,Comps,Mods), Features, nogap) -->
    {VPFeatures = form:presentParticiple..vppassive:no..finite:no},
	    % now find a verb that conforms to the specified
		% person, number and verbform.
	verb(Verb, VPFeatures),
	{VPFeatures = subcat:Slots},
	complementlist( Comps, Slots, VPFeatures, nogap),
	modifiers( Mods, VPFeatures, nogap),
   {Features = restriction:(VPFeatures)..person:third..number:singular..whphrase:no..case:nominative}.




%%%%%%%%%%%%%%%%
% To parse a np, make a rule that handles the determiners.
% Find a determiner, then do the rest of the noun phrase, by
% looking for the list of adjectives next.
% If there's no determiner, ok, just do the rest of the np.
np_Determiner(np(Det, AdjList, Noun), NPFeatures) -->
   det(Det, NPFeatures),
   np_Adjectives(AdjList, Noun, NPFeatures).

np_Determiner(np(Quantifier, AdjList, Noun), NPFeatures) -->
   quantifier(Quantifier, NPFeatures),
   np_Adjectives(AdjList, Noun, NPFeatures).

np_Determiner(np(AdjList, Noun), NPFeatures) -->
   np_Adjectives(AdjList, Noun, NPFeatures).
   

%%%%%%%%%%%%%%%%
% Make a rule that handles the adjective list.
% Keep going, finding adjectives as long as possible.  When you can't find
% any more adjectives, move on to look for the Noun itself.

% The adjective list consists of:
% {possessive pronoun} {quantifier} {Adjectives *}

% possessive pronouns (like 'my' and 'her') are adjectives too
np_Adjectives([PossesiveAdj | MoreAdjectives], Noun, NPFeatures) -->
  pronoun(PossesiveAdj, case:possessive),
  np_AdjectivesAfterPossPron(MoreAdjectives, Noun, NPFeatures).
np_Adjectives(MoreAdjectives, Noun, NPFeatures) -->
  np_AdjectivesAfterPossPron(MoreAdjectives, Noun, NPFeatures).

np_AdjectivesAfterPossPron([NumQuantifier | MoreAdjectives], Noun, NPFeatures) -->
  number(NumQuantifier, NPFeatures),
  np_AdjectivesAfterNumber(MoreAdjectives, Noun, NPFeatures).
np_AdjectivesAfterPossPron(MoreAdjectives, Noun, NPFeatures) -->
  np_AdjectivesAfterNumber(MoreAdjectives, Noun, NPFeatures).

np_AdjectivesAfterNumber([NewAdjective | MoreAdjectives], Noun, NPFeatures) -->
   adj(NewAdjective, _AdjectiveFeatures),
   np_AdjectivesAfterNumber(MoreAdjectives, Noun, NPFeatures).

np_AdjectivesAfterNumber([], Noun, NPFeatures) -->
   np_Noun(Noun, NPFeatures).


%%%%%%%%%%%%%%%%
% Now a rule that handles the noun itself.
% The noun, of course, is not an optional part of an np.
% At this point, we have an entire noun phrase.
np_Noun(Noun, NPFeatures) -->
   noun(Noun, NPFeatures).


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% FORMAT np_Clause(ClauseTree,ClauseFeatures,Gap)
%        ClauseTree- parse subtree
%        Features include
%           Number - plural, singular
%           Person - first, second, third
%	   Gap    - gap(np,NP,NPFeatures), gap(pp,PP,PPFeatures)
%         
%
% The following rules deal with optional relative clauses, which consist
% of:
%      - a relative pronoun followed by a sentence
%          with its subject missing (i.e. a verb phrase)
%          e.g. The man who [gap: the man] eats salad.
%
%	   - an active present participle verb phrase
%          e.g  The man [gap:the man] eating salad is here
%
%	   - a passive past participle verb phrase
%          e.g. The salad eaten by the man [=the man eats [gap: the salad]] is good
%     
%      - an optional relative pronoun followed by a sentence
%          with a gap in the (object) noun phrase or prepositional
%          object
%          e.g. This is the man whom I gave the book to [gap: the man]
%          e.g. This is the book that I gave him [gap: the book]
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% Optimize: don't try to find a clause if there's only an empty
% list left to parse.
np_Clause(_Tree, _Features, _Gap, [], _Rest) :- !, fail.


% Parse a relative clause, with a relative pronoun and a verb phrase.
% Example: "(The man) who saw us yesterday".
% The pronoun is required to fill the grammatical slot of the subject of the
% relative clause.
% The relative clause takes a gap as input, which can be used to fill in the subject

np_Clause(relative_clause(NPTree, Pronoun, VPTree), ClauseFeatures, gap(np, NPTree, NPFeatures)) -->
      {copy_term(NPFeatures, ClauseFeatures)},	 
         % Since we use the NPTree in the gap as the subject, we use NPFeatures to start ClauseFeatures.
         % We need to make a copy of NPFeatures before we try to unify the set of features in the gap
         % with the verb phrase, because this verb phrase's features need not unify with the features
         % of the larger sentence of which this clause is a part!
	  relpron(Pronoun, ClauseFeatures),
      vp(VPTree, ClauseFeatures, nogap).


% Parse a relative clause, with the form of the verb as present participle.
% Example: "(The man) buying a car".
% The pronoun is required to fill the grammatical slot of the subject of the
% relative clause.
% The relative clause takes a gap as input, which can be used to fill in the subject
np_Clause(relative_clause(NPTree, VPTree), ClauseFeatures, gap(np, NPTree, nptype:NPType..person:P..number:N..whphrase:WH)) -->
      {ClauseFeatures = nptype:NPType..person:P..number:N..whphrase:WH..form:presentParticiple..finite:no},	       
      vp(VPTree, ClauseFeatures, nogap).


% Things like 'the stamp given to the office'.
% This is really like 'the stamp _that was_ given to the office.
% Use the rule that passives use after they've gotten rid of the 'was' verb.
np_Clause(relative_clause(NPTree, vp_passive(Verb, Comps, Mods)), ClauseFeatures, gap(np, NPTree, NPFeat)) -->
    {copy_term(NPFeat, ClauseFeatures)},
	passive_verb(Verb, ClauseFeatures, Comps, Mods, nogap).

% The following rule parses object-relative clauses, e.g. "(The man) we saw
% on the hill" or "(The man) whom we saw on the hill".
% To parse this, parse an optional pronoun followed by a sentence. The
% sentence will contain a noun phrase gap, as in the example given, and is 
% analyzed as an assertion.

np_Clause(relative_clause(Pronoun, SentenceTree), ClauseFeatures, gap(np, NPTree, NPFeatures)) -->
      opt_rel_pronoun(Pronoun, _Feat),
      {ClauseFeatures = mood:assertion},
	  s(SentenceTree, ClauseFeatures, gap(np, NPTree, NPFeatures)).
    

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% FORMAT opt_rel_pronoun( RelPronoun )
%	RelPronoun - parse subtree
% 
% The following rules deal with relative pronouns that need not appear.
% e.g.  I like the stamp that you bought
%   or  I like the stamp you bought
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

opt_rel_pronoun( RelPronoun, Features) --> relpron( RelPronoun,Features).
opt_rel_pronoun( rel_pronoun(none), _Features ) --> [].


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%  Prepositional phrases
%
% FORMAT pp(PP,Features, Gap)
%        PP - parse subtree
%        Gap - nogap, gap(np,NPTree, NPFeatures), gap(pp,PPTree,PPFeatures)
%        Features - properties of the prep phrase such as:
%         - prepType - the preposition the phrase is introduced by e.g. 'to', 'with'
%
% The following rules deal with prepositional phrases, which consist of:
%	    - a gap(pp(pp,PrepTree,PPFeatures)))
%       - a preposition followed by a noun phrase
%       - a preposition followed by two conjoined noun phrases
%       - a preposition followed by a gap(np,NPTree,NPFeatures)
%       - an adverb "phrase" (it has the same grammatical role)
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% If the prepositional phrase is filled in by a gap, just retrieve and
% return the information from the lexicon. 

pp(PP, PPFeatures, gap(pp, PP, GapPPFeatures)) -->
       [],
	   {copy_term(GapPPFeatures, PPFeatures)}.


% Next, the straighforward case: parse a prepositon and a noun phrase.
% Also ensure that the noun phrase is in the accusative case

pp( pp(Prep, NPTree), PPFeatures, Gap) -->
      prep(Prep, PPFeatures),
      {PPFeatures = case:accusative},
      np(NPTree, PPFeatures, Gap).


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% FORMAT auxList(AuxList, TenseForVerb, VPFeatures)
%        AuxList - list of the baseforms of all the auxiliary verbs
%        TenseForVerb - the form that the verb is expected to take, given
%           the preceeding auxiliaries.
%        VPFeatures will include:
%        -  AuxForm - present, past, presParticiple, pastParticiple
%        -  Number - plural, singular
%        -  Person - first, second, third

%  In the simple parser, it just processes the string of auxiliaries to
%  make sure it's grammatically legal.  You can add a rule that will figure
%  out the tense, based on what auxiliaries are used, eg:
%  present (eats), past (has eaten), past perfect (had eaten),
%  present progressive (is eating), etc.
%  
%
% The following rules deal with sequences of auxiliaries, which
% consist of:
%        - zero or more auxiliaries
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% The structure of the auxes predicate: 
% Param1: a list that gets built up of all the auxiliaries, in their base forms
% Param2: the form that the verb will have to be: this only gets filled in
%         when we reach the end of the list of auxiliaries, and we find out what
%         form of verb is expected next.
% Param3: the Gulp feature list for these words: tense holds the form that the
%         auxiliary word is expected to be; it's unified to auxForm.
%         Depending what word it was, we determine the form of the aux or verb
%         we expect next.

% handle 'be' followed by presentParticiple
auxList( [be | MoreAuxes], VerbForm, person:P..number:Num..form:FormExpected) -->
   aux( aux(be), person:P..number:Num..auxtense:FormExpected),
   auxList(MoreAuxes, VerbForm, person:P..number:Num..form:presentParticiple).

% handle 'have' followed by pastParticiple
auxList( [have | MoreAuxes], VerbForm, person:P..number:Num..form:FormExpected) -->
   aux( aux(have), person:P..number:Num..auxtense:FormExpected),
   auxList(MoreAuxes, VerbForm, person:P..number:Num..form:pastParticiple).

% handle 'will' followed by infinitive
auxList( [will | MoreAuxes], VerbForm, person:P..number:Num..form:present) -->
   aux( aux(will), person:P..number:Num),
   auxList(MoreAuxes, VerbForm, person:P..number:Num..form:future).

% handle 'do' followed by an infinitive verb: you can't have more auxiliaries
% after a 'do'.
auxList( [do], infinitive, person:P..number:Num) -->
   aux( aux(do), person:P..number:Num).

% No auxiliaries is a valid possibility - there could be no auxiliaries,
% or this can be the last auxiliary in a list.
auxList( [], FormExpected, form:FormExpected) --> [].



%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% FORMAT vp(VP,Features, Gap)
%        VP - parse subtree
%        Features include:
%           Form - finite, nonfinite, presentParticiple, pastParticiple, infinitive
%           Number - plural, singular
%           Person - first, second, third
%           SubjType - The type of the syntactic subject of the sentence
%        Gap - nogap, gap(pobj,POBJ), gap(np,NP)
%                  
% 
% Note: the vp_passive predicate is used whenever the verb is known to
%	be passive, but for some reason is not preceded by a `to be' verb
%	(i.e. in inverted sentences or rel clauses without a rel pronoun)
%
% The following rules deal with verb phrases, which consist of:
%        - optional auxiliaries,
%          followed by a verb in the appropriate form, followed by
%          allowable complements, followed by modifiers.
%        - as above, but in passive form, which changes the
%          allowable complements and the subject type.
%
% The term "complements" covers various constructions. The most important
% ones are objects, i.e. direct objects and indirect objects, and "to"
% constructions, as in "(I want) to read this program". See Comps below.
% Modifiers are general constructions that can modify just about any verb,
% for example adverbs and prepositional phrases.
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

vp(_VP, _Feat, _Gap, [], []) :- !, fail.
	% optimize if the list is empty.

% Active voice verbs. To parse these, parse auxiliaries, then
% the main verb. Depending on the verb, there may be different kinds 
% of complements.
% The verb phrase may contain one gap, either in the complements or in the
% modifiers. This means that both the "complementlist" and the "modifiers" predicate
% require a gap variable. To ensure that only one gap is used, these gap
% variables are made synonomous by the "one-gap" predicate.


%          VP
%   +-------+--------+-----------------+
%   |       |        |                 |
% (auxes)   V    *(complements)  *(modifiers)
%
vp( vp(aux(AuxList),Verb,Comps,Mods), VPFeatures, Gap) -->
    {copy_term(VPFeatures, AgentFeatures)},
	{VPFeatures = agent:AgentFeatures},
	{VPFeatures = finite:MustBeFinite},
	{helper_finite(MustBeFinite, FiniteForm)},
	auxList( AuxList, VerbForm, person:P..number:N..form:FiniteForm),
        % The auxiliares are followed by a verb.  
        % The VerbForm parameter in that's passed to auxList
		% is the form the verb should be in.
    {VPFeatures = person:P..number:N..form:VerbForm..vppassive:no},
	    % now find a verb that conforms to the specified
		% person, number and verbform.
	verb(Verb, VPFeatures),
	{one_gap( Gap, Gap1, Gap2 )},
	{VPFeatures = subcat:Slots},
	complementlist( Comps, Slots, VPFeatures, Gap1),
	modifiers( Mods, VPFeatures, Gap2).


% Passive voice.  Example: "(He) was seen."
% The auxiliary has to be followed by a derivative of "be". 
% "FormAux" holds the form of the auxiliary (not that of the main 
% verb as above because we know the main verb to be a derivative of 
% "be"). Aside from a "to be" verb, there must be a past
% participle. The possible complements depend on the passive cases that
% the verb allows. Example: "It was given to the Prime Minister".


vp( vp_passive(aux(AuxList),to_be_verb(be,VerbForm), Verb ,Comps,Mods), VPFeatures, Gap) -->
	
	{gapSubjectIntoObject(VPFeatures)},	

	auxList( AuxList, VerbForm, number:N..person:P),
        % the auxiliaries determine the form of 'to be', e.g. "will be
        % read", or "will have been read".       
	{VPFeatures = number:N..person:P},	
	    % make sure the 'be' verb matches the subject in num and person
	verb( verb(be), number:N..person:P..form:VerbForm..vptype:VPType),
        % 'to be' verb with no complement cases 
	{VPFeatures = form:VerbForm..number:N..person:P..vptype:VPType},
	passive_verb(Verb, VPFeatures, Comps, Mods, Gap).

passive_verb(Verb, VPFeatures, Comps, Mods, Gap) -->
    {MainVerbFeatures = form:pastParticiple},
	verb( Verb, MainVerbFeatures),
    {MainVerbFeatures = subcat:Slots},  % extract the complement slots.
    {VPFeatures = subcat:Slots..vppassive:yes},
	{one_gap( Gap, Gap1, Gap2 )},
	complementlist( Comps, Slots, VPFeatures, Gap1),
	modifiers( Mods, VPFeatures, Gap2).



helper_finite(MustBeFinite, present) :- atom(MustBeFinite), MustBeFinite = yes.
helper_finite(MustBeFinite, past) :- atom(MustBeFinite), MustBeFinite = yes.
helper_finite(no, _).


% Tried to gap the subject of the sentence into the direct object role.
% If this fails further down the line (ie the verb already has a 
% complement that will act as dobj, as in 'will the man be given a chance'
% we can try to use the subject as indirect object.
gapSubjectIntoObject( VPFeatures) :-
    copy_term(VPFeatures, ObjectFeatures),
	VPFeatures = dobj_complement:(ObjectFeatures).
gapSubjectIntoObject( VPFeatures) :-
    copy_term(VPFeatures, ObjectFeatures),
	VPFeatures = iobj_complement:(ObjectFeatures).


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% FORMAT complementlist(CompTree, Slots, VPFeatures, Gap)
%        CompTree - parse subtree
%        Slots - A list of functors that determine what complements the verb can take.
%              This list is a guide to complement types to look for
%        VPFeatures - the features of the verb phrase of which these complements
%             are a part.  The complements can add their features into this struct.
%        Gap - nogap, gap(pobj,POBJ), gap(np,NP)
%
% The following rule parses the complements of a verb, according
% to complement type:
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% To parse a complement, go through a list of possible complements (slots)
% (for the verb under consideration), and use the "comp" production to see
% if the string to be parsed matches the first. The elements in the
% list are of the form (subject class, complement). See the external
% documentation.
%

% Optimize complement seeking if there are no more words and no gap
complementlist( complement([]), _Slots, _Features, nogap, [], []) :- !.

complementlist( CompTree, [ComplementRule | _RestOfSlots], VPFeatures, Gap) -->
      vpcomplement(CompTree, ComplementRule, ComplementFeatures, Gap),
      {VPFeatures = ComplementFeatures}.

% If the first slot doesn't match, try (by "cdr recursion") the next
% element in the list of possible cases of the verb

complementlist( CompTree, [_FirstRule|RestOfRules], VPFeatures, Gap) -->
	complementlist( CompTree, RestOfRules, VPFeatures, Gap).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% FORMAT vpcomplement( ParseTree, ComplementType, ComplementRole, ComplementFeatures, Gap)
%	ParseTree - the parse subtree
%     ComplementType - the type of complement, dobj, iobj, pp, etc.
%     ComplementRole - the role of the complement - patient, agent, etc.
%     ComplementFeatures - holds features of the np or vp or whatever the complement is
%	Gap - nogap, gap(pobj,POBJ), gap(np,NP)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% a verb may require no complement
vpcomplement( complement([]), none, _CompFeatures, nogap) --> [].

% A verb may require a noun phrase as a complement
% A single noun phrase will act as a direct object.
% The case must be accusative
vpcomplement( complement(NP), np, CompFeatures, Gap) -->
      {NPFeatures = case:accusative},
      np( NP, NPFeatures, Gap),
      {CompFeatures = dobj_complement:(NPFeatures)}.


	  
% A verb may require two noun phrases as complements.
% The first will be an indirect object, the second a direct object
% as in 'give the man a book'fs
vpcomplement( complement(NP1, NP2), np_np, CompFeatures, Gap) -->
      {NPFeatures1 =case:accusative},
      np( NP1, NPFeatures1, nogap),
      {CompFeatures = iobj_complement:(NPFeatures1)},
	  {NPFeatures2 = case:accusative},
	  np( NP2, NPFeatures2, Gap),
	  {CompFeatures = dobj_complement:(NPFeatures2)}.


% The complement vpbase, as in 'must go' - the thing following
% the verb is another verb phrase, in infinitive form
vpcomplement( complement(VP), vpbase, CompFeatures, Gap) -->
      {VPFeatures = form:infinitive},
	  vp( VP, VPFeatures, Gap),
	  {CompFeatures = modal_complement:(VPFeatures)}.


% The complement vpinf, as in 'want to go' - the thing following
% the verb is another verb phrase, in infinitive form, marked
% with a 'to'.
vpcomplement( complement(VP), vpinf, CompFeatures, Gap) -->
      [to],
      {VPFeatures = form:infinitive},
	  vp( VP, VPFeatures, Gap),
	  {CompFeatures = modal_complement:(VPFeatures)}.
	  
vpcomplement( complement(VP), vping, CompFeatures, Gap) -->
      {VPFeatures = form:presentParticiple},
	  vp( VP, VPFeatures, Gap),
	  {CompFeatures = modal_complement:(VPFeatures)}.


vpcomplement( complement(NP, VP), np_vpinf, CompFeatures, Gap) -->
      {SentenceFeatures = case:accusative},
	  np(NP, SentenceFeatures, nogap),
      {SentenceFeatures = form:infinitive},
	  [to],
	  vp( VP, SentenceFeatures, Gap),
	  {CompFeatures = modal_complement:(SentenceFeatures)}.

vpcomplement( complement(Adv, Adj), adj, CompFeatures, nogap) -->
      opt_adv(Adv, CompFeatures),
	  adj(Adj, CompFeatures).

opt_adv(Adv, AdvFeatures) -->
      adverb( Adv, AdvFeatures).
opt_adv([], _Features) --> [].



%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% FORMAT modifiers(ModTree, ModFeatures, Gap)
%        Modifiers - parse subtree
%        ModFeatures - Features of any modifiers that get added here
%	   Gap - nogap, gap(pp,PP), gap(np,NP)
%
% The following rule parses the modifiers of a verb, which can be:
%        - a prepositional phrase
%        - empty
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% no modifiers is a valid modifier
modifiers( modifier([]), _Feature, nogap) --> [].

% Optimize - no modifiers if there are no more words to read.
modifiers( [], _Feature, nogap, [], []) :- !.

% Parse possibly several modifiers. 
modifiers([modifier(PP) | MoreModifiers], ModFeatures, Gap) --> 
	{one_gap( Gap, Gap1, Gap2 ) },
	pp( PP, PPFeatures, Gap1),
	{PPFeatures = ppcase:PPRole},
    {restrictrole(PPRole, ModFeatures, PPFeatures)},
	modifiersList( MoreModifiers, ModFeatures, Gap2).

modifiers([modifier(Adv) | MoreModifiers], ModFeatures, Gap) --> 
	adverb( Adv, AdvFeatures),
	{ModFeatures = AdvFeatures},
	modifiersList( MoreModifiers, ModFeatures, Gap).


modifiersList([modifier(PP) | MoreModifiers], ModFeatures, Gap) --> 
	{one_gap( Gap, Gap1, Gap2 ) },
	pp( PP, PPFeatures, Gap1),
	{PPFeatures = ppcase:PPRole},
    {restrictrole(PPRole, ModFeatures, PPFeatures)},
	modifiersList( MoreModifiers, ModFeatures, Gap2).

modifiersList([modifier(Adv) | MoreModifiers], ModFeatures, Gap) --> 
	adverb( Adv, AdvFeatures),
      {ModFeatures = AdvFeatures},
	modifiers( MoreModifiers, ModFeatures, Gap).

modifiersList([], _Features, _Gap) --> [].


restrictrole(destination, FeaturesOut, FeaturesIn) :- FeaturesOut = destination:(FeaturesIn).
restrictrole(time, FeaturesOut, FeaturesIn) :- FeaturesOut = time:(FeaturesIn).
restrictrole(location, FeaturesOut, FeaturesIn) :- FeaturesOut = location:(FeaturesIn).
restrictrole(agent, FeaturesOut, FeaturesIn) :- FeaturesOut = agent:(FeaturesIn).
restrictrole(possessor, FeaturesOut, FeaturesIn) :- FeaturesOut = possessor:(FeaturesIn).
restrictrole(recipient, FeaturesOut, FeaturesIn) :- FeaturesOut = recipient:(FeaturesIn).
restrictrole(source, FeaturesOut, FeaturesIn) :- FeaturesOut = source:(FeaturesIn).



%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% FORMAT advP(ADVP)
%        ADVP - parse subtree
%
% The following rules deal with optional adverb "phrases", which 
% consist of:
%        - an optional intensifier followed by an adverb
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% adverb phrase without an intensifier

advP( advP(Adverb), Features) --> adverb( Adverb, Features).


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% one_gap( Gap, Gap1, Gap2 )
%	Gap -  The type of gap required (i.e. nogap, gap(np), gap(pobj)).
%	Gap1 - The first possible gap.
%	Gap2 - The second possible gap.
% 
% The one_gap predicate is used to make sure that a gap is used only once
% "Gap" is bound to the gap used.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

one_gap( nogap, nogap, nogap ).
% if you have used no gaps, then you haven't used two gaps.

one_gap( gap(Type,Tree,Features), gap(Type,Tree,Features), nogap ) :-
	gap(Type).
% if you used Gap1, bind it to "Gap".

one_gap( gap(Type,Tree,Features), nogap, gap(Type,Tree,Features) ) :-
	gap(Type).
% if you used Gap2, bind that to "Gap".
% Otherwise, you used two gaps, and "one_gap" fails.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% gap( GapType ).
%	GapType - A permissible gap - i.e. np, pp
%
% This predicate is used to identify permissible gap types.
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

gap(np).  % A noun phrase may fill a gap.
gap(pp).  % A prep phrase may fill a gap

