def make_pred(tbentry, stemtag, glosstag, predchoice, lextype): ''' Construct pred value from toolbox entry according to the predchoice specified. ''' # Figure out if we're doing a noun or a verb lex_cat = lextype.rstrip('0123456789') # FIXME: What should I actually be doing with these errors? if lex_cat == 'verb': rel = '_v_rel' elif lex_cat == 'noun': rel = '_n_rel' else: print("Error: lex cat isn't verb or noun.") # Construct stem if predchoice == 'stem': pred = TDLencode('_' + tbentry[stemtag] + rel) elif predchoice == 'gloss': if tbentry[glosstag]: pred = TDLencode('_' + tbentry[glosstag] + rel) else: pred = TDLencode('_' + tbentry[stemtag] + rel) elif predchoice == 'glossfw': if tbentry[glosstag]: pred = TDLencode('_' + tbentry[glosstag].split()[0] + rel) else: pred = TDLencode('_' + tbentry[stemtag] + rel) else: print("Error: bad predchoice.") return pred
def add_auxiliaries_to_lexicon(userstypename, sem, aux, lexicon, trigger): for stem in aux.get('stem', []): orth = orth_encode(stem.get('orth')) id = stem.get('name') typedef = TDLencode(id) + ' := ' + userstypename + ' & \ [ STEM < "' + orth + '" > ].' lexicon.add(typedef) evid_present = False evid_value = None for feat in aux.get('feat', []): if feat.get('name') == 'evidential': evid_present = True evid_value = feat.get('value') if sem == 'add-pred' or evid_present: pred = 'ev_' + str(evid_value) + '_rel' if not evid_present: pred = stem.get('pred') typedef = TDLencode(id) + \ ' := [ SYNSEM.LKEYS.KEYREL.PRED "' + pred + '" ].' lexicon.add(typedef, merge=True) else: tense = aspect = mood = evidential = '' for feat in aux.get('feat', []): if feat.get('name') == 'tense': tense = feat.get('value') if feat.get('name') == 'aspect': aspect = feat.get('value') if feat.get('name') == 'mood': mood = feat.get('value') if feat.get('name') == 'evidential': evidential = feat.get('value') grdef = TDLencode(id) + '_gr := arg0e_gtr & \ [ CONTEXT [ RELS.LIST < [ ' if tense == '' and aspect == '' and mood == '': grdef += 'PRED "non_existing_rel" ] > ],' else: grdef += 'ARG0.E [ ' if tense != '': grdef += 'TENSE ' + tense + ',' if aspect != '': grdef += 'ASPECT ' + aspect + ',' if mood != '': grdef += 'MOOD ' + mood + ',' grdef = grdef[:len(grdef) - 1] + ' ] ] > ], ' grdef += 'FLAGS.TRIGGER "' + TDLencode(id) + '" ].' trigger.add(grdef)
def customize_misc_lex(ch, lexicon, trigger): # Question particle if ch.get('q-part'): orth = ch.get('q-part-orth') orthstr = orth_encode(orth) typedef = \ TDLencode(orth) + ' := qpart-lex-item & \ [ STEM < "' + orthstr + '" > ].' lexicon.add(typedef) grdef = TDLencode(orth) +'_gr := generator_rule & \ [ CONTEXT [ RELS <! [ ARG0.SF ques ] !> ], \ FLAGS.TRIGGER "' + TDLencode(orth) + '" ].' trigger.add(grdef)
def customize_head_comp_neg(mylang,ch,lexicon, hierarchies): # bipartite neg with negauxiliary which has a 'dummy' negcomp # add type for neg-adv # this analysis requires the neg-head-feature, if it's not on # simulate it here if(ch.get('neg-head-feature')!='on'): mylang.add('head :+ [ NEGATED luk ].', section='addenda') # negauxes with modified comps lists are # generated by auxiliaries.py #TODO deal with v head # need to add type and instance for semantically empty neg-comp mylang.set_section('otherlex') mylang.add('''neg-comp-lex := norm-zero-arg & [ SYNSEM.LOCAL [ CAT [ HEAD adv & [ NEGATED + ], VAL [ SUBJ < >, COMPS < > ] ], CONT [ RELS <! !>, HCONS <! !> ]]].''', '''Type for negative selected comps. This type uses the MOD list to get scopal semantics. Constrain head-modifier rules to be [NEGATED -] if you don't want this type to act as a modifer.''') # add lexical instance if(ch.get('comp-neg-orth')): orth = ch.get('comp-neg-orth') orthstr = orth_encode(orth) lexicon.add(TDLencode(orth) + ' := neg-comp-lex &\ [ STEM < \"'+ orthstr +'\" > ].')
def customize_comp_neg(mylang, ch, lexicon, rules, lrules): # the neg-comp analyses require the neg-head-feature choice # simulate it here if it's not on if(ch.get('neg-head-feature')!='on'): mylang.add('head :+ [ NEGATED luk ].', section='addenda') # first add lexical type mylang.set_section('otherlex') mylang.add('''neg-adv-lex := basic-scopal-adverb-lex & [ SYNSEM.LOCAL.CAT [ VAL [ SPR < >, COMPS < >, SUBJ < > ], HEAD [ NEGATED +, MOD < [ LOCAL.CAT.HEAD verb ] > ] ] ].''', '''Type for negative selected comps. This type uses the MOD list to get scopal semantics. Constrain head-modifier rules to be [NEGATED -] if you don't want this type to act as a modifer.''') # okay, now add the spelling and lexical instance if(ch.get('comp-neg-orth')): orth = ch.get('comp-neg-orth') orthstr = orth_encode(orth) lexicon.add(TDLencode(orth) + ' := neg-adv-lex &\ [ STEM < \"'+ orthstr +'\" >,\ SYNSEM.LKEYS.KEYREL.PRED \"neg_rel\" ].') # we need the lexical rule that adds these types to the comps lists # of the verbs that selecte them if ch.get('comp-neg-order') == 'before': mylang.add('''neg-comp-add-lex-rule := const-val-change-only-lex-rule & [ SYNSEM.LOCAL [ CAT.VAL [ SUBJ #subj, COMPS < canonical-synsem & [ LOCAL.CAT.HEAD [ NEGATED +, MOD < [ LOCAL.CONT.HOOK #hook ] > ] ] . #comps > ] ], DTR.SYNSEM.LOCAL [ CAT.VAL [ SUBJ #subj, COMPS #comps ], CONT.HOOK #hook ] ]. ''') elif ch.get('comp-neg-order') == 'after': mylang.add('''neg-comp-add-lex-rule := const-val-change-only-lex-rule & [ SYNSEM.LOCAL.CAT.VAL [ SUBJ #subj, COMPS < #comps , canonical-synsem & [ LOCAL.CAT.HEAD [ NEGATED +, MOD < [ LOCAL.CONT.HOOK #hook ] > ] ] > ], DTR.SYNSEM.LOCAL [ CAT.VAL [ SUBJ #subj, COMPS.FIRST #comps ], CONT.HOOK #hook ] ]. ''') lrules.add('neg-lex-rule := neg-comp-add-lex-rule.') # deal with type of selecting verb: auxiliary verb or any finite verb if(ch.get('comp-neg-head')=='aux'): mylang.add('neg-comp-add-lex-rule := [ DTR aux-lex ].') elif(ch.get('comp-neg-head')=='v'): mylang.add('''neg-comp-add-lex-rule := [ DTR verb-lex & [ SYNSEM.LOCAL.CAT.HEAD.FORM finite ] ].''')
def customize_adv_neg(mylang, ch, lexicon, rules): # first add lexical type for negative adverb mylang.set_section('otherlex') mylang.add('''neg-adv-lex := basic-scopal-adverb-lex & [ SYNSEM.LOCAL.CAT [ VAL [ SPR < >, COMPS < >, SUBJ < > ], HEAD.MOD < [ LOCAL.CAT.HEAD verb ] > ]].''', 'Type for negative adverbs.') mylang.add_comment('neg-adv-lex', '''This adverb should go through a specialized phrase structure rule included with this grammar.''') # now parameterize as pre/posthead, no value here means both orders # should work if ch.get('neg-order') == 'before': mylang.add('neg-adv-lex := [ SYNSEM.LOCAL.CAT.POSTHEAD - ].') elif ch.get('neg-order') == 'after': mylang.add('neg-adv-lex := [ SYNSEM.LOCAL.CAT.POSTHEAD + ].') # constrain type of constituent modified by neg-adv if ch.get('neg-mod') == 's': mylang.add('''neg-adv-lex := [ SYNSEM.LOCAL.CAT.HEAD.MOD.FIRST.LOCAL.CAT.VAL [ SUBJ null, COMPS null ]].''') elif ch.get('neg-mod') == 'vp': mylang.add('''neg-adv-lex := [ SYNSEM.LOCAL.CAT.HEAD.MOD.FIRST.LOCAL.CAT.VAL [ SUBJ cons, COMPS null ]].''') elif ch.get('neg-mod') == 'v': mylang.add('''neg-adv-lex := [ SYNSEM.LOCAL.CAT.HEAD.MOD.FIRST.LIGHT + ].''') mylang.add('verb-lex := [ SYNSEM.LOCAL.CAT.HC-LIGHT - ].','''verb-lex is HC-LIGHT - to allow us to pick out\n lexical Vs for V-level attachment of negative adverbs.''') # add spelling for neg-adverb if(ch.get('neg-adv-orth')): orth = ch.get('neg-adv-orth') orthstr = orth_encode(orth) lexicon.add(TDLencode(orth) + ' := neg-adv-lex &\ [ STEM < \"'+ orthstr +'\" >,\ SYNSEM.LKEYS.KEYREL.PRED \"neg_rel\" ].') rules.add('adj-head-scop := adj-head-scop-phrase.') rules.add('head-adj-scop := head-adj-scop-phrase.', 'Rule instances for head-modifier structures. Corresponding types\n' + 'are defined in matrix.tdl. The matrix customization script did\n' + 'not need to add any further constraints, so no corresponding types\n' + 'appear in ' + ch.get('language').lower() + '.tdl') mylang.add('+nvcdmo :+ [ MOD < > ].', 'This grammar includes head-modifier rules. To keep\n' + 'out extraneous parses, constrain the value of MOD on\n' + 'various subtypes of head. This may need to be loosened later.\n' + 'This constraint says that only adverbs, adjectives,\n' + 'and adpositions can be modifiers.', section='addenda')
def add_to_lexicon(morphtype, typename, type, lexicon): """ add the subordinator or adverb to lexicon """ orth = morphtype.get(type + 'orth') orthstr = orth_encode(orth) pred = morphtype.get(type + 'pred') name = TDLencode(morphtype.get(type + 'name')) lexicon.add(name + ' := ' + typename + ' &\ [ STEM < "' + orthstr + '" >,\ SYNSEM.LKEYS.KEYREL.PRED "' + pred + '"].')
def customize_cops(mylang, ch, lexicon, hierarchies, trigger): if ch.get('cop',False): # Add PRD mylang.add('head :+ [ PRD bool ].', section='addenda') # Add copulas lexicon.add_literal(';;; Copulas') # Core definition mylang.add('''%s := basic-verb-lex-super & trans-first-arg-raising-lex-item-2 & [ SYNSEM.LOCAL [ CAT.VAL [ SUBJ < [ LOCAL [ CONT.HOOK.INDEX #xarg, CAT [ VAL [ SPR < >, COMPS < > ], HEAD noun ] ] ] >, COMPS < [ LOCAL.CAT [ HEAD.PRD +, VAL [ SUBJ < >, COMPS < > ] ] ] >, SPR < >, SPEC < > ], CONT.HOOK.XARG #xarg ] ].''' % LEXICAL_SUPERTYPES['cop']) # only works for adj right now, change in future comment = '''Copula type taking adjectival complements.\nNeed to define more for additional complement types.''' mylang.add('''adj-comp-copula-verb-lex := %s & [ SYNSEM.LOCAL.CAT.VAL.COMPS.FIRST.LOCAL.CAT.HEAD adj ].''' % LEXICAL_SUPERTYPES['cop'], comment=comment) for cop in ch.get('cop', []): ctype = cop_id(cop) ## Calculate supertypes stypes = cop.get('supertypes').split(', ') stype_def = '' if '' in stypes: # Found root stype_def = 'adj-comp-copula-verb-lex & ' # Change for new complement types else: stype_names = [cop_id(ch[st]) for st in filter(None,stypes)] stype_def = " & ".join(stype_names) or "" if stype_def: stype_def += " & " features.customize_feature_values(mylang, ch, hierarchies, cop, ctype, 'cop') # Add the lexical types mylang.add(ctype + ' := ' + stype_def + '.') for stem in cop.get('stem'): orthstr = orth_encode(stem.get('orth')) name = stem.get('name') typedef = TDLencode(name) + ' := ' + ctype + ' & \ [ STEM < "' + orthstr + '" > ].' lexicon.add(typedef)
def customize_determiners(mylang, ch, lexicon, hierarchies): # Lexical type for determiners, if the language has any: if ch.get('has-dets') == 'yes': comment = \ ';;; Determiners\n' + \ ';;; SPEC is non-empty, and already specified by basic-determiner-lex.' mylang.add_literal(comment) # LLD 2016-04-04 changed basic-zero-arg to norm-zero-arg typedef = \ 'determiner-lex := basic-determiner-lex & norm-zero-arg & \ [ SYNSEM.LOCAL.CAT.VAL [ SPR < >, \ COMPS < >, \ SUBJ < > ]].' mylang.add(typedef) mylang.add('determiner-lex := non-mod-lex-item.') # Determiners if 'det' in ch: lexicon.add_literal(';;; Determiners') for det in ch.get('det',[]): stype = 'determiner-lex' dtype = det_id(det) mylang.add(dtype + ' := ' + stype + '.') has_inforstr_feat = False for feat in det.get('feat', []): if feat['name'] == "information-structure meaning": has_inforstr_feat = True mylang.add(dtype + ' := infostr-marking-determiner-lex.') break if not has_inforstr_feat: mylang.add(dtype + ' := no-icons-lex-item.') features.customize_feature_values(mylang, ch, hierarchies, det, dtype, 'det') for stem in det.get('stem',[]): orthstr = orth_encode(stem.get('orth')) pred = stem.get('pred') name = stem.get('name') typedef = \ TDLencode(name) + ' := ' + dtype + ' & \ [ STEM < "' + orthstr + '" >, \ SYNSEM.LKEYS.KEYREL.PRED "' + pred + '" ].' lexicon.add(typedef)
def add_complementizers_to_lexicon(lexicon, ch): lexicon.add_literal(';;; Complementizers') have_comp = False for comp_strategy in ch[COMPS]: id = comp_strategy.full_key stype = id + '-' + COMP_LEX_ITEM # TODO: Perhaps turn complementizers into full-blown # lexical items and then can call insert_ids() from lexical_items.py instead # This would need to be done via redesigning the questionnaire a little. for complementizer in comp_strategy[COMPLEMENTIZER]: orth = orth_encode(complementizer.get('orth')) name = TDLencode(complementizer.get('name')) typedef = name + ' := ' + stype + ' & \ [ STEM < "' + orth + '" > ].' lexicon.add(typedef) have_comp = True return have_comp
def customize_infl_comp_neg(mylang,ch,lexicon): # neg affix on verb requires neg-adv with neg semantics # neg-adv is a selected complement # this analysis requires the neg-head-feature, if it's not on # simulate it here if(ch.get('neg-head-feature')!='on'): mylang.add('head :+ [ NEGATED luk ].', section='addenda') # add type for neg-adv mylang.set_section('otherlex') mylang.add('''neg-comp-lex := basic-scopal-adverb-lex & [ SYNSEM.LOCAL.CAT [ VAL [ SPR < >, SPEC < >, COMPS < >, SUBJ < > ], HEAD [ NEGATED +, MOD < [ LOCAL.CAT.HEAD verb ] > ] ] ].''', '''Type for negative selected comps. This type uses the MOD list to get scopal semantics. Constrain head-modifier rules to be [NEGATED -] if you don't want this type to act as a modifer.''') # add lexical instance if(ch.get('comp-neg-orth')): orth = ch.get('comp-neg-orth') orthstr = orth_encode(orth) lexicon.add(TDLencode(orth) + ' := neg-comp-lex &\ [ STEM < \"'+ orthstr +'\" >,\ SYNSEM.LKEYS.KEYREL.PRED \"neg_rel\" ].') # inflecting lexical rule must add neg-adv to comps list, for vpc in ch['verb-pc']: for lrt in vpc['lrt']: for f in lrt['feat']: if 'negation' in f['name'] and f['value']=='plus': lrt['supertypes'] = ', '.join(lrt['supertypes'].split(', ') +\ ['val-change-only-lex-rule']) f['value']='d'
def customize_coordination(mylang, ch, lexicon, rules, irules): """ The main coordination customization routine """ mylang.set_section('coord') for cs in ch.get('cs'): csnum = str(cs.iter_num()) mark = cs.get('mark') pat = cs.get('pat') orth = cs.get('orth') orthstr = orth_encode(orth) order = cs.get('order') pre = '' suf = '' tn = TDLencode(orth) if (len(ch.get('cs')) > 1): tn += csnum if mark == 'word': lexicon.add(tn + ' := conj-lex &\ [ STEM < "' + orthstr + '" >,\ SYNSEM.LKEYS.KEYREL.PRED "_and_coord_rel",\ CFORM "' + csnum + '" ].') if pat == 'omni': lexicon.add(tn + '_nosem := nosem-conj-lex &\ [ STEM < "' + orthstr + '" >,\ CFORM "' + csnum + '" ].') if pat == 'a': top = 'apoly-' mid = '' bot = 'unary-' left = '' else: if pat == 'mono': top = 'monopoly-' mid = 'monopoly-' bot = '' left = '' elif pat == 'omni': top = 'omni-' mid = 'omni-' bot = 'omni-' left = 'omni-' elif pat == 'poly': top = 'apoly-' mid = '' bot = '' left = '' if mark == 'affix': bot = 'infl-' if order == 'before': pre = orth else: suf = orth else: if order == 'before': bot += 'conj-first-' if left: left += 'conj-first-' else: bot += 'conj-last-' if left: left += 'conj-last-' # EKN 02-13-2018 Add identification of possessive feats across # conjuncts poss = True if (ch.get('poss-strat') or ch.get('poss-pron'))\ else False if poss: if top: customize_poss_feats(mylang, 'top') if mid: customize_poss_feats(mylang, 'mid') if bot: customize_poss_feats(mylang, 'bottom') # If this CS uses feature resolution, we will set up closest conjunct as a mixed strategy # (with additional rules and specifications). mixed_strategy = True if any([csap.get('pat').startswith('fr') for csap in cs.get('csap')]) \ and any([csap.get('pat').startswith('dconj') for csap in cs.get('csap')]) \ else False # make a list of the agreement rules for this coord strat if cs.get('csap'): agrrules = [] for csap in cs.get( 'csap'): # iterate through the agreement patterns used agrrules += customize_agreement_pattern(mylang, ch, csap, cs) # use an empty list if no agreement pattern is defined else: agrrules = [('', '')] # olzama 2020-04-28 Add adverb coordination if adverbs are present. # For now, I just hard coded Strategy 1 because I don't really know # how this library works. Adverbs are unlikely to require agreement though? if len(ch.get('adv')) > 0: mylang.add( 'adv1-top-coord-rule := basic-adv-top-coord-rule & monopoly-top-coord-rule & \ [ SYNSEM.LOCAL.COORD-STRAT "1" ].') mylang.add( '''adv1-mid-coord-rule := basic-adv-mid-coord-rule & monopoly-mid-coord-rule & [ SYNSEM.LOCAL.COORD-STRAT "1" ].''') mylang.add( '''adv1-bottom-coord-rule := conj-first-bottom-coord-rule & adv-bottom-coord-phrase & [ SYNSEM.LOCAL.COORD-STRAT "1" ].''') rules.add('adv1-bottom-coord := adv1-bottom-coord-rule.') rules.add('adv1-mid-coord := adv1-mid-coord-rule.') rules.add('adv1-top-coord := adv1-top-coord-rule.') for pos in ('n', 'np', 'vp', 's'): # don't use noun-y agreement rules with VP or S agrrules = [('', '')] if pos in ('vp', 's') else agrrules # now write the rules if cs.get(pos): define_coord_strat(csnum, pos, top, mid, bot, left, pre, suf, mylang, rules, irules, agrrules, mixed_strategy)
def customize_mod_mod_neg(mylang,ch,lexicon,rules): # need to create two modifiers, one sets neg-sat to minus, the other to # back to plus. # add neg-sat and decorate psrs # this analysis uses the neg-head-feature if(ch.get('neg-head-feature')!='on'): mylang.add('head :+ [ NEGATED luk ].', section='addenda') # add neg-sat to SYNSEM mylang.set_section('addenda') mylang.add('''synsem :+ [ NEG-SAT luk ].''') # verbs must start out NEG-SAT na-or-+ mylang.add('''basic-verb-lex :+ [ SYNSEM.NEG-SAT na-or-+ ].''') # decorate psrs to pass up NEG-SAT value mylang.add('''basic-head-comp-phrase :+ [ SYNSEM.NEG-SAT #ns, HEAD-DTR.SYNSEM.NEG-SAT #ns ].''') mylang.add('''basic-head-subj-phrase :+ [ SYNSEM.NEG-SAT #ns, HEAD-DTR.SYNSEM.NEG-SAT #ns ].''') # ammend root condition mylang.add('''clause :+ [ SYNSEM.NEG-SAT na-or-+ ].''') # add neg1 mod (sets neg-sat to -, via its psr) mylang.set_section('otherlex') mylang.add('''neg1-adv-lex := basic-scopal-adverb-lex & [ SYNSEM.LOCAL.CAT [ VAL [ SPR < >, SPEC < >, COMPS < >, SUBJ < > ], HEAD [ NEGATED +, MOD < [ LOCAL.CAT.HEAD verb ] > ] ] ].''', '''This type uses the MOD list to get scopal semantics. Constrain head-modifier rules to be [NEGATED -] if you don't want this type to act as a modifer.''') # add neg2 mod (sets neg-sat back to +, via its psr) mylang.add('''neg2-adv-lex := norm-zero-arg & [ SYNSEM.LOCAL [ CAT [ VAL [ SPR < >, SPEC < >, COMPS < >, SUBJ < > ], HEAD adv & [ NEGATED +, MOD < [ LOCAL.CAT.HEAD verb ] > ] ], CONT [ RELS <! !>, HCONS <! !> ] ] ].''') # create lexical instance for neg1 if(ch.get('neg1-mod-orth')): orth = ch.get('neg1-mod-orth') orthstr = orth_encode(orth) lexicon.add(TDLencode(orth) + ' := neg1-adv-lex &\ [ STEM < \"'+ orthstr +'\" >,\ SYNSEM.LKEYS.KEYREL.PRED \"neg_rel\" ].') # create lexical instance for neg2 if(ch.get('neg2-mod-orth')): orth = ch.get('neg2-mod-orth') orthstr = orth_encode(orth) lexicon.add(TDLencode(orth) + ' := neg2-adv-lex &\ [ STEM < \"'+ orthstr +'\" > ].') # now parameterize as pre/posthead, no value here means both orders # should work, also add specialized modifier rules if ch.get('neg1-mod-order') == 'before': mylang.add('neg1-adv-lex := [ SYNSEM.LOCAL.CAT.POSTHEAD - ].') mylang.add('''neg1-adj-head-scop-phrase := adj-head-scop-phrase & [ SYNSEM.NEG-SAT -, HEAD-DTR.SYNSEM.NEG-SAT na-or-+, NON-HEAD-DTR neg1-adv-lex ].''') rules.add('neg1-adj-head-scop := neg1-adj-head-scop-phrase.') elif ch.get('neg1-mod-order') == 'after': mylang.add('neg1-adv-lex := [ SYNSEM.LOCAL.CAT.POSTHEAD + ].') mylang.add('''neg1-head-adj-scop-phrase := head-adj-scop-phrase & [ SYNSEM.NEG-SAT -, HEAD-DTR.SYNSEM.NEG-SAT na-or-+, NON-HEAD-DTR neg1-adv-lex ].''') rules.add('neg1-head-adj-scop := neg1-head-adj-scop-phrase.') else: mylang.add('''neg1-adj-head-scop-phrase := adj-head-scop-phrase & [ SYNSEM.NEG-SAT -, HEAD-DTR.SYNSEM.NEG-SAT na-or-+, NON-HEAD-DTR neg1-adv-lex ].''') rules.add('neg1-adj-head-scop := neg1-adj-head-scop-phrase.') mylang.add('''neg1-head-adj-scop-phrase := head-adj-scop-phrase & [ SYNSEM.NEG-SAT -, HEAD-DTR.SYNSEM.NEG-SAT na-or-+, NON-HEAD-DTR neg1-adv-lex ].''') rules.add('neg1-head-adj-scop := neg1-head-adj-scop-phrase.') # constrain type of constituent modified by neg-adv if ch.get('neg1-mod') == 's': mylang.add('''neg1-adv-lex := [ SYNSEM.LOCAL.CAT.HEAD.MOD.FIRST.LOCAL.CAT.VAL [ SUBJ null, COMPS null ]].''') elif ch.get('neg-mod1') == 'vp': mylang.add('''neg1-adv-lex := [ SYNSEM.LOCAL.CAT.HEAD.MOD.FIRST.LOCAL.CAT.VAL [ SUBJ cons, COMPS null ]].''') elif ch.get('neg1-mod') == 'v': mylang.add('''neg1-adv-lex := [ SYNSEM.LOCAL.CAT.HEAD.MOD.FIRST.LIGHT + ].''') mylang.add('verb-lex := [ SYNSEM.LOCAL.CAT.HC-LIGHT - ].','''verb-lex is HC-LIGHT - to allow us to pick out\n lexical Vs for V-level attachment of negative adverbs.''') # now parameterize as pre/posthead, no value here means both orders # should work, also add specialized modifier rules if ch.get('neg2-mod-order') == 'before': mylang.add('neg2-adv-lex := [ SYNSEM.LOCAL.CAT.POSTHEAD - ].') mylang.add('''neg2-adj-head-scop-phrase := adj-head-scop-phrase & [ SYNSEM.NEG-SAT +, HEAD-DTR.SYNSEM.NEG-SAT -, NON-HEAD-DTR neg2-adv-lex ].''') rules.add('neg2-adj-head-scop := neg2-adj-head-scop-phrase.') elif ch.get('neg2-mod-order') == 'after': mylang.add('neg2-adv-lex := [ SYNSEM.LOCAL.CAT.POSTHEAD + ].') mylang.add('''neg2-head-adj-scop-phrase := head-adj-scop-phrase & [ SYNSEM.NEG-SAT +, HEAD-DTR.SYNSEM.NEG-SAT -, NON-HEAD-DTR neg2-adv-lex ].''') rules.add('neg2-head-adj-scop := neg2-head-adj-scop-phrase.') else: mylang.add('''neg2-adj-head-scop-phrase := adj-head-scop-phrase & [ SYNSEM.NEG-SAT +, HEAD-DTR.SYNSEM.NEG-SAT -, NON-HEAD-DTR neg2-adv-lex ].''') rules.add('neg2-adj-head-scop := neg2-adj-head-scop-phrase.') mylang.add('''neg2-head-adj-scop-phrase := head-adj-scop-phrase & [ SYNSEM.NEG-SAT +, HEAD-DTR.SYNSEM.NEG-SAT -, NON-HEAD-DTR neg2-adv-lex ].''') rules.add('neg2-head-adj-scop := neg2-head-adj-scop-phrase.') # constrain type of constituent modified by neg-adv if ch.get('neg2-mod') == 's': mylang.add('''neg2-adv-lex := [ SYNSEM.LOCAL.CAT.HEAD.MOD.FIRST.LOCAL.CAT.VAL [ SUBJ null, COMPS null ]].''') elif ch.get('neg-mod2') == 'vp': mylang.add('''neg2-adv-lex := [ SYNSEM.LOCAL.CAT.HEAD.MOD.FIRST.LOCAL.CAT.VAL [ SUBJ cons, COMPS null ]].''') elif ch.get('neg2-mod') == 'v': mylang.add('''neg2-adv-lex := [ SYNSEM.LOCAL.CAT.HEAD.MOD.FIRST.LIGHT + ].''') mylang.add('verb-lex := [ SYNSEM.LOCAL.CAT.HC-LIGHT - ].','''verb-lex is HC-LIGHT - to allow us to pick out\n lexical Vs for V-level attachment of negative adverbs.''')
def customize_comp_mod_neg(mylang,ch,lexicon,rules): # here we create a negation strategy with one selected complement, # which presumably carries the negative force # this analysis uses the neg-head-feature if(ch.get('neg-head-feature')!='on'): mylang.add('head :+ [ NEGATED luk ].', section='addenda') # add neg-sat to SYNSEM mylang.set_section('addenda') mylang.add('''synsem :+ [ NEG-SAT luk ].''') # verbs must start out NEG-SAT na-or-+ mylang.add('''basic-verb-lex :+ [ SYNSEM.NEG-SAT na-or-+ ].''') # decorate psrs to pass up NEG-SAT value mylang.add('''basic-head-comp-phrase :+ [ SYNSEM.NEG-SAT #ns, HEAD-DTR.SYNSEM.NEG-SAT #ns ].''') mylang.add('''basic-head-subj-phrase :+ [ SYNSEM.NEG-SAT #ns, HEAD-DTR.SYNSEM.NEG-SAT #ns ].''') # ammend root condition mylang.add('''clause :+ [ SYNSEM.NEG-SAT na-or-+ ].''') # first introduce the lexical rule that introduces the negative complement # also needs to set NEG-SAT - on its target #TODO: parameterize this rule according to neg-comp before/after # current system only supports before and ignores the choice! attach='' if ch.get('comp-neg-head-comp-mod') == 'v': attach='verb' else: attach='aux' next_n = ch['verb-pc'].next_iter_num() if 'verb-pc' in ch else 1 ch['verb-pc%d_name' % next_n] = 'neg1' nvpc = ch['verb-pc'].get_last() nvpc['order'] = 'suffix' nvpc['inputs'] = attach nvpc['lrt1_feat1_name'] = 'negation' nvpc['lrt1_feat1_value'] = 'h' nvpc['lrt1_lri1_inflecting'] = 'no' nvpc['lrt1_supertypes'] = 'val-change-only-lex-rule' # create lexical type for neg-comp mylang.set_section('otherlex') mylang.add('''neg1-comp-lex := basic-scopal-adverb-lex & [ SYNSEM.LOCAL.CAT [ VAL [ SPR < >, SPEC < >, COMPS < >, SUBJ < > ], HEAD [ NEGATED +, MOD < [ LOCAL.CAT.HEAD verb ] > ] ] ].''', '''Type for negative selected comps. This type uses the MOD list to get scopal semantics. Constrain head-modifier rules to be [NEGATED -] if you don't want this type to act as a modifer.''') # create lexical instance for neg1 if(ch.get('comp-neg-orth')): orth = ch.get('comp-neg-orth') orthstr = orth_encode(orth) lexicon.add(TDLencode(orth) + ' := neg1-comp-lex &\ [ STEM < \"'+ orthstr +'\" >,\ SYNSEM.LKEYS.KEYREL.PRED \"neg_rel\" ].') # add lexical type for negadv "neg2" mylang.set_section('otherlex') mylang.add('''neg-adv-lex := norm-zero-arg & [ SYNSEM.LOCAL [ CAT [ VAL [ SPR < >, COMPS < >, SUBJ < > ], HEAD adv & [ MOD < [ LOCAL.CAT.HEAD verb ] >, NEGATED + ] ], CONT [ RELS <! !>, HCONS <! !> ] ] ].''', 'Type for negative adverbs.') mylang.add_comment('neg-adv-lex', '''This adverb should go through a specialized phrase structure rule included with this grammar.''') # now parameterize as pre/posthead, no value here means both orders # should work, also add specialized modifier rules if ch.get('neg-mod-order-comp-mod-neg') == 'before': mylang.add('neg-adv-lex := [ SYNSEM.LOCAL.CAT.POSTHEAD - ].') mylang.add('''neg-adj-head-scop-phrase := adj-head-scop-phrase & [ SYNSEM.NEG-SAT +, HEAD-DTR.SYNSEM.NEG-SAT -, NON-HEAD-DTR neg-adv-lex ].''') rules.add('neg-adj-head-scop := neg-adj-head-scop-phrase.') elif ch.get('neg-mod-order-comp-mod-neg') == 'after': mylang.add('neg-adv-lex := [ SYNSEM.LOCAL.CAT.POSTHEAD + ].') mylang.add('''neg-head-adj-scop-phrase := head-adj-scop-phrase & [ SYNSEM.NEG-SAT +, HEAD-DTR.SYNSEM.NEG-SAT -, NON-HEAD-DTR neg-adv-lex ].''') rules.add('neg-head-adj-scop := neg-head-adj-scop-phrase.') else: mylang.add('''neg-adj-head-scop-phrase := adj-head-scop-phrase & [ SYNSEM.NEG-SAT +, HEAD-DTR.SYNSEM.NEG-SAT -, NON-HEAD-DTR neg-adv-lex ].''') rules.add('neg-adj-head-scop := neg-adj-head-scop-phrase.') mylang.add('''neg-head-adj-scop-phrase := head-adj-scop-phrase & [ SYNSEM.NEG-SAT +, HEAD-DTR.SYNSEM.NEG-SAT -, NON-HEAD-DTR neg-adv-lex ].''') rules.add('neg-head-adj-scop := neg-head-adj-scop-phrase.') # constrain type of constituent modified by neg-adv if ch.get('neg-mod-comp-mod-neg') == 's': mylang.add('''neg-adv-lex := [ SYNSEM.LOCAL.CAT.HEAD.MOD.FIRST.LOCAL.CAT.VAL [ SUBJ null, COMPS null ]].''') elif ch.get('neg-mod-comp-mod-neg') == 'vp': mylang.add('''neg-adv-lex := [ SYNSEM.LOCAL.CAT.HEAD.MOD.FIRST.LOCAL.CAT.VAL [ SUBJ cons, COMPS null ]].''') elif ch.get('neg-mod-comp-mod-neg') == 'v': mylang.add('''neg-adv-lex := [ SYNSEM.LOCAL.CAT.HEAD.MOD.FIRST.LIGHT + ].''') mylang.add('verb-lex := [ SYNSEM.LOCAL.CAT.HC-LIGHT - ].','''verb-lex is HC-LIGHT - to allow us to pick out\n lexical Vs for V-level attachment of negative adverbs.''') # add spelling for neg-adverb if(ch.get('neg-mod-orth')): orth = ch.get('neg-mod-orth') orthstr = orth_encode(orth) lexicon.add(TDLencode(orth) + ' := neg-adv-lex &\ [ STEM < \"'+ orthstr +'\" > ].') mylang.add('+nvcdmo :+ [ MOD < > ].', 'This grammar includes head-modifier rules. To keep\n' + 'out extraneous parses, constrain the value of MOD on\n' + 'various subtypes of head. This may need to be loosened later.\n' + 'This constraint says that only adverbs, adjectives,\n' + 'and adpositions can be modifiers.', section='addenda')
def customize_comp_comp_neg(mylang,ch,lexicon): # bipartite negation type with two negative complements, # presumably one is selected by an aux, the other by a v # # this analysis uses the neg-head-feature if(ch.get('neg-head-feature')!='on'): mylang.add('head :+ [ NEGATED luk ].', section='addenda') # verbs need to be NEGATED - 'underlyingly' mylang.add('verb-lex := [ SYNSEM.LOCAL.CAT.HEAD.NEGATED na-or-- ].') # add neg1 complement mylang.set_section('otherlex') mylang.add('''neg1-comp-lex := basic-scopal-adverb-lex & [ SYNSEM.LOCAL.CAT [ VAL [ SPR < >, SPEC < >, COMPS < >, SUBJ < > ], HEAD [ NEGATED +, MOD < [ LOCAL.CAT.HEAD verb ] > ] ] ].''', '''Type for negative selected comps. This type uses the MOD list to get scopal semantics. Constrain head-modifier rules to be [NEGATED -] if you don't want this type to act as a modifer.''') # add neg2 complement mylang.add('''neg2-comp-lex := norm-zero-arg & [ SYNSEM.LOCAL [ CAT [ VAL [ SPR < >, SPEC < >, COMPS < >, SUBJ < > ], HEAD [ NEGATED +, MOD < [ LOCAL.CAT.HEAD verb ] > ] ], CONT [ HCONS <! !>, RELS <! !> ] ] ].''', '''Type for negative selected comps. This type uses the MOD list to get scopal semantics. Constrain head-modifier rules to be [NEGATED -] if you don't want this type to act as a modifer.''') # add lexical instances if(ch.get('comp-neg1-orth')): orth = ch.get('comp-neg1-orth') orthstr = orth_encode(orth) lexicon.add(TDLencode(orth) + ' := neg1-comp-lex &\ [ STEM < \"'+ orthstr +'\" >,\ SYNSEM.LKEYS.KEYREL.PRED \"neg_rel\" ].') if(ch.get('comp-neg2-orth')): orth = ch.get('comp-neg2-orth') orthstr = orth_encode(orth) lexicon.add(TDLencode(orth) + ' := neg2-comp-lex &\ [ STEM < \"'+ orthstr +'\" > ].') # non-inflecting lexical rule must add neg-adv to comps list, next_n = ch['verb-pc'].next_iter_num() if 'verb-pc' in ch else 1 ch['verb-pc%d_name' % next_n] = 'neg1' nvpc = ch['verb-pc'].get_last() nvpc['order'] = 'suffix' nvpc['inputs'] = 'aux' nvpc['lrt1_feat1_name'] = 'negation' nvpc['lrt1_feat1_value'] = 'f' nvpc['lrt1_lri1_inflecting'] = 'no' nvpc['lrt1_supertypes'] = 'val-change-only-lex-rule' # other non-inflecting lex rule adds other neg comp to other verbs # can go in same pc as above (the two rules should be exclusive) ch['verb-pc%d_name' % (next_n + 1)] = 'neg2' nvpc = ch['verb-pc'].get_last() nvpc['order'] = 'suffix' nvpc['inputs'] = 'verb' nvpc['lrt1_feat1_name'] = 'negation' nvpc['lrt1_feat1_value'] = 'g' nvpc['lrt1_lri1_inflecting'] = 'no' nvpc['lrt1_supertypes'] = 'cat-change-only-lex-rule, same-hc-light-lex-rule, same-posthead-lex-rule, same-mc-lex-rule' # also need auxes to underlyingly select for [ NEGATED - ] types mylang.add('''aux-lex := [ SYNSEM.LOCAL.CAT.VAL.COMPS.FIRST.LOCAL.CAT.HEAD.NEGATED na-or-- ].''')
def customize_head_mod_neg(mylang, ch, lexicon,rules): # basically just need to add NEG-SAT feature dependencies # this analysis uses the neg-head-feature if(ch.get('neg-head-feature')!='on'): mylang.add('head :+ [ NEGATED luk ].', section='addenda') # add neg-sat to SYNSEM mylang.set_section('addenda') mylang.add('''synsem :+ [ NEG-SAT luk ].''') # verbs must start out NEG-SAT na-or-+ mylang.add('''basic-verb-lex :+ [ SYNSEM.NEG-SAT na-or-+ ].''') # decorate psrs to pass up NEG-SAT value mylang.add('''basic-head-comp-phrase :+ [ SYNSEM.NEG-SAT #ns, HEAD-DTR.SYNSEM.NEG-SAT #ns ].''') mylang.add('''basic-head-subj-phrase :+ [ SYNSEM.NEG-SAT #ns, HEAD-DTR.SYNSEM.NEG-SAT #ns ].''') # ammend root condition mylang.add('''clause :+ [ SYNSEM.NEG-SAT na-or-+ ].''') # neg-aux lexically introduces SYNSEM.NEG-SAT - # # add type for neg-adv mylang.set_section('otherlex') mylang.add('''neg-adv-lex := norm-zero-arg & [ SYNSEM.LOCAL [ CAT [ VAL [ SPR < >, COMPS < >, SUBJ < > ], HEAD adv & [ MOD < [ LOCAL.CAT.HEAD verb ] >, NEGATED + ] ], CONT [ RELS <! !>, HCONS <! !> ] ] ].''', 'Type for negative adverbs.') mylang.add_comment('neg-adv-lex', '''This adverb should go through a specialized phrase structure rule included with this grammar.''') # now parameterize as pre/posthead, no value here means both orders # should work, also add specialized modifier rules if ch.get('neg-mod-order-head-mod-neg') == 'before': mylang.add('neg-adv-lex := [ SYNSEM.LOCAL.CAT.POSTHEAD - ].') mylang.add('''neg-adj-head-scop-phrase := adj-head-scop-phrase & [ SYNSEM.NEG-SAT +, HEAD-DTR.SYNSEM.NEG-SAT -, NON-HEAD-DTR neg-adv-lex ].''') rules.add('neg-adj-head-scop := neg-adj-head-scop-phrase.') elif ch.get('neg-mod-order-head-mod-neg') == 'after': mylang.add('neg-adv-lex := [ SYNSEM.LOCAL.CAT.POSTHEAD + ].') mylang.add('''neg-head-adj-scop-phrase := head-adj-scop-phrase & [ SYNSEM.NEG-SAT +, HEAD-DTR.SYNSEM.NEG-SAT -, NON-HEAD-DTR neg-adv-lex ].''') rules.add('neg-head-adj-scop := neg-head-adj-scop-phrase.') else: mylang.add('''neg-adj-head-scop-phrase := adj-head-scop-phrase & [ SYNSEM.NEG-SAT +, HEAD-DTR.SYNSEM.NEG-SAT -, NON-HEAD-DTR neg-adv-lex ].''') rules.add('neg-adj-head-scop := neg-adj-head-scop-phrase.') mylang.add('''neg-head-adj-scop-phrase := head-adj-scop-phrase & [ SYNSEM.NEG-SAT +, HEAD-DTR.SYNSEM.NEG-SAT -, NON-HEAD-DTR neg-adv-lex ].''') rules.add('neg-head-adj-scop := neg-head-adj-scop-phrase.') # constrain type of constituent modified by neg-adv if ch.get('neg-mod-head-mod-neg') == 's': mylang.add('''neg-adv-lex := [ SYNSEM.LOCAL.CAT.HEAD.MOD.FIRST.LOCAL.CAT.VAL [ SUBJ null, COMPS null ]].''') elif ch.get('neg-mod-head-mod-neg') == 'vp': mylang.add('''neg-adv-lex := [ SYNSEM.LOCAL.CAT.HEAD.MOD.FIRST.LOCAL.CAT.VAL [ SUBJ cons, COMPS null ]].''') elif ch.get('neg-mod-head-mod-neg') == 'v': mylang.add('''neg-adv-lex := [ SYNSEM.LOCAL.CAT.HEAD.MOD.FIRST.LIGHT + ].''') mylang.add('verb-lex := [ SYNSEM.LOCAL.CAT.HC-LIGHT - ].','''verb-lex is HC-LIGHT - to allow us to pick out\n lexical Vs for V-level attachment of negative adverbs.''') # add spelling for neg-adverb if(ch.get('neg-mod-orth')): orth = ch.get('neg-mod-orth') orthstr = orth_encode(orth) lexicon.add(TDLencode(orth) + ' := neg-adv-lex &\ [ STEM < \"'+ orthstr +'\" > ].') mylang.add('+nvcdmo :+ [ MOD < > ].', 'This grammar includes head-modifier rules. To keep\n' + 'out extraneous parses, constrain the value of MOD on\n' + 'various subtypes of head. This may need to be loosened later.\n' + 'This constraint says that only adverbs, adjectives,\n' + 'and adpositions can be modifiers.', section='addenda')
def create_adverb_subordinator_lexical_subtypes(mylang, lexicon, trigger, cms): """ Create the lexical subtype for the adverb subordinator with constraints for subordinator's position (before/after a vp/s), morphological constraints, and the SUBORDINATED feature. Then add each to lexicon. """ lextype = [] constraints = [] pos = cms.get('position') subpos = cms.get('subposition') # add constraints for subordinator position if subpos == 'before': lextype.append('clause-init') constraints.append('SYNSEM.LOCAL.CAT.POSTHEAD -') elif subpos == 'after': lextype.append('clause-final') constraints.append('SYNSEM.LOCAL.CAT.POSTHEAD +') if pos == 'before': lextype.append('prehead') elif pos == 'after': lextype.append('posthead') # add morphological constraints lextype, constraints = add_morphological_constraints( lextype, constraints, cms, 'adverb') saved_constraints = constraints saved_lextype = lextype # each free adverb subordinator gets it's own lexical type with a special SUBORDINATED value so that the non-branching # rule can select it if cms.get('subordinator') == 'free': for adverb in cms.get('freemorph'): constraints = saved_constraints lextype = saved_lextype pred = adverb.get('pred') value = shortform_pred(pred) lextype = [value] + lextype constraints.append('SYNSEM.SUBORDINATED ' + value) # add constriants for the adverb's attaching to vp or s if cms.get('adverb-attach') == 's': if cms.get('shared-subj') == 'on': constraints.append('SYNSEM.LOCAL [ CONT.HOOK.XARG #xarg,\ CAT.HEAD.MOD < [ LOCAL [ CONT.HOOK.XARG #xarg,\ CAT.VAL [ SUBJ < unexpressed >,\ COMPS < > ]]] > ]' ) else: constraints.append( 'SYNSEM.LOCAL.CAT.HEAD.MOD < [ LOCAL.CAT.VAL [ SUBJ < >, COMPS < > ]] >' ) elif cms.get('adverb-attach') == 'vp': constraints.append( 'SYNSEM.LOCAL.CAT.HEAD.MOD < [ LOCAL.CAT.VAL [ SUBJ < [ ] >, COMPS < > ]] >' ) if cms.get('adverb-attach') == 'both': constraints.append( 'SYNSEM.LOCAL.CAT.HEAD.MOD < [ LOCAL.CAT.VAL [ COMPS < > ]] >' ) type = build_type_name(lextype) type += '-adv-subord-lex-item' mylang.add(type + ' := adverb-subord-lex-item & [ ' + constraints.pop() + ' ].') while constraints != []: mylang.add(type + ' := [ ' + constraints.pop() + ' ].') orth = adverb.get('orth') orthstr = orth_encode(orth) name = TDLencode(adverb.get('name')) lexicon.add(name + ' := ' + type + ' & [ STEM < "' + orthstr + '" > ].') trigger_rule = TDLencode(orth) + '_gr := arg0e_gtr & \ [ CONTEXT [ RELS.LIST < [ PRED "' + TDLencode( pred) + '" ] > ], \ FLAGS.TRIGGER "' + TDLencode(orth) + '" ].' trigger.add(trigger_rule) # each adverb gets it's own lexical type with a special SUBORDINATED value so that the non-branching # rule can select it and so that the SUBPAIR feature can be added elif cms.get('subordinator') == 'pair': for adverb in cms.get('morphpair'): constraints = saved_constraints lextype = saved_lextype pred = adverb.get('subordpred') value = shortform_pred(pred) lextype = [value] + lextype constraints.append('SYNSEM.SUBORDINATED ' + value) constraints.append('SYNSEM.LOCAL.CAT.SUBPAIR ' + value) # add constriants for the adverb's attaching to vp or s if cms.get('adverb-attach') == 's': if cms.get('shared-subj') == 'on': constraints.append('SYNSEM.LOCAL [ CONT.HOOK.XARG #xarg,\ CAT.HEAD.MOD < [ LOCAL [ CONT.HOOK.XARG #xarg,\ CAT.VAL [ SUBJ < unexpressed >,\ COMPS < > ]]] > ]' ) else: constraints.append( 'SYNSEM.LOCAL.CAT.HEAD.MOD < [ LOCAL.CAT.VAL [ SUBJ < >, COMPS < > ]] >' ) elif cms.get('adverb-attach') == 'vp': constraints.append( 'SYNSEM.LOCAL.CAT.HEAD.MOD < [ LOCAL.CAT.VAL [ SUBJ < [ ] >, COMPS < > ]] >' ) if cms.get('adverb-attach') == 'both': constraints.append( 'SYNSEM.LOCAL.CAT.HEAD.MOD < [ LOCAL.CAT.VAL [ COMPS < > ]] >' ) type = build_type_name(lextype) type += '-adv-subord-lex-item' mylang.add(type + ' := adverb-subord-lex-item & [ ' + constraints.pop() + ' ].') while constraints != []: mylang.add(type + ' := [ ' + constraints.pop() + ' ].') orth = adverb.get('subordorth') orthstr = orth_encode(orth) name = TDLencode(adverb.get('subordname')) lexicon.add(name + ' := ' + type + ' & [ STEM < "' + orthstr + '" > ].')
def customize_infl_mod_neg(mylang,ch,lexicon,rules): # neg affix on verb requires neg-adv with neg semantics # neg-adv is a modifier # this analysis requires the neg-head-feature, if it's not on # simulate it here if(ch.get('neg-head-feature')!='on'): mylang.add('head :+ [ NEGATED luk ].', section='addenda') # add neg-sat to SYNSEM mylang.set_section('addenda') mylang.add('''synsem :+ [ NEG-SAT luk ].''') # verbs must start out NEG-SAT na-or-+ mylang.add('''basic-verb-lex :+ [ SYNSEM.NEG-SAT na-or-+ ].''') # decorate psrs to pass up NEG-SAT value mylang.add('''basic-head-comp-phrase :+ [ SYNSEM.NEG-SAT #ns, HEAD-DTR.SYNSEM.NEG-SAT #ns ].''') mylang.add('''basic-head-subj-phrase :+ [ SYNSEM.NEG-SAT #ns, HEAD-DTR.SYNSEM.NEG-SAT #ns ].''') # ammend root condition mylang.add('''clause :+ [ SYNSEM.NEG-SAT na-or-+ ].''') # inflecting lexical rule must add NEG-SAT - to verb, for vpc in ch['verb-pc']: for lrt in vpc['lrt']: for f in lrt['feat']: if 'negation' in f['name'] and f['value']=='plus': f['value']='e' # add type for neg-adv mylang.set_section('otherlex') mylang.add('''neg-adv-lex := basic-scopal-adverb-lex & [ SYNSEM.LOCAL.CAT [ VAL [ SPR < >, COMPS < >, SUBJ < > ], HEAD [ MOD < [ LOCAL.CAT.HEAD verb ] >, NEGATED + ]]].''', 'Type for negative adverbs.') mylang.add_comment('neg-adv-lex', '''This adverb should go through a specialized phrase structure rule included with this grammar.''') # now parameterize as pre/posthead, no value here means both orders # should work, also add specialized modifier rules if ch.get('neg-mod-order-infl-mod-neg') == 'before': mylang.add('neg-adv-lex := [ SYNSEM.LOCAL.CAT.POSTHEAD - ].') mylang.add('''neg-adj-head-scop-phrase := adj-head-scop-phrase & [ SYNSEM.NEG-SAT +, HEAD-DTR.SYNSEM.NEG-SAT -, NON-HEAD-DTR neg-adv-lex ].''') rules.add('neg-adj-head-scop := neg-adj-head-scop-phrase.') elif ch.get('neg-mod-order-infl-mod-neg') == 'after': mylang.add('neg-adv-lex := [ SYNSEM.LOCAL.CAT.POSTHEAD + ].') mylang.add('''neg-head-adj-scop-phrase := head-adj-scop-phrase & [ SYNSEM.NEG-SAT +, HEAD-DTR.SYNSEM.NEG-SAT -, NON-HEAD-DTR neg-adv-lex ].''') rules.add('neg-head-adj-scop := neg-head-adj-scop-phrase.') else: mylang.add('''neg-adj-head-scop-phrase := adj-head-scop-phrase & [ SYNSEM.NEG-SAT +, HEAD-DTR.SYNSEM.NEG-SAT -, NON-HEAD-DTR neg-adv-lex ].''') rules.add('neg-adj-head-scop := neg-adj-head-scop-phrase.') mylang.add('''neg-head-adj-scop-phrase := head-adj-scop-phrase & [ SYNSEM.NEG-SAT +, HEAD-DTR.SYNSEM.NEG-SAT -, NON-HEAD-DTR neg-adv-lex ].''') rules.add('neg-head-adj-scop := neg-head-adj-scop-phrase.') # constrain type of constituent modified by neg-adv if ch.get('neg-mod-infl-mod-neg') == 's': mylang.add('''neg-adv-lex := [ SYNSEM.LOCAL.CAT.HEAD.MOD.FIRST.LOCAL.CAT.VAL [ SUBJ null, COMPS null ]].''') elif ch.get('neg-mod-infl-mod-neg') == 'vp': mylang.add('''neg-adv-lex := [ SYNSEM.LOCAL.CAT.HEAD.MOD.FIRST.LOCAL.CAT.VAL [ SUBJ cons, COMPS null ]].''') elif ch.get('neg-mod-infl-mod-neg') == 'v': mylang.add('''neg-adv-lex := [ SYNSEM.LOCAL.CAT.HEAD.MOD.FIRST.LIGHT + ].''') mylang.add('verb-lex := [ SYNSEM.LOCAL.CAT.HC-LIGHT - ].','''verb-lex is HC-LIGHT - to allow us to pick out\n lexical Vs for V-level attachment of negative adverbs.''') # add spelling for neg-adverb if(ch.get('neg-mod-orth')): orth = ch.get('neg-mod-orth') orthstr = orth_encode(orth) lexicon.add(TDLencode(orth) + ' := neg-adv-lex &\ [ STEM < \"'+ orthstr +'\" >,\ SYNSEM.LKEYS.KEYREL.PRED \"neg_rel\" ].') mylang.add('+nvcdmo :+ [ MOD < > ].', 'This grammar includes head-modifier rules. To keep\n' + 'out extraneous parses, constrain the value of MOD on\n' + 'various subtypes of head. This may need to be loosened later.\n' + 'This constraint says that only adverbs, adjectives,\n' + 'and adpositions can be modifiers.', section='addenda')
def customize_case_adpositions(mylang, lexicon, trigger, ch): cases = case_names(ch) #features = ch.features() to_cfv = [] if ch.has_adp_case(): comment = \ ';;; Case-marking adpositions\n' + \ ';;; Case marking adpositions are constrained not to\n' + \ ';;; be modifiers.' mylang.add_literal(comment) mylang.add('+np :+ [ CASE case ].', section='addenda') typedef = \ 'case-marking-adp-lex := basic-one-arg & raise-sem-lex-item & \ [ SYNSEM.LOCAL.CAT [ HEAD adp & [ CASE #case, MOD < > ], \ VAL [ SPR < >, \ SUBJ < >, \ COMPS < #comps >, \ SPEC < > ]], \ ARG-ST < #comps & [ LOCAL.CAT [ HEAD noun & [ CASE #case ], \ VAL.SPR < > ]] > ].' mylang.add(typedef) if ch.has_mixed_case(): mylang.add('+np :+ [ CASE-MARKED bool ].', section='addenda') mylang.add('case-marking-adp-lex := \ [ ARG-ST < [ LOCAL.CAT.HEAD.CASE-MARKED - ] > ].') # checking whether language has both prepositions and postpositions bidirectional = False adporders = [] for adp in ch.get('adp', []): adp_order = adp.get('order') if not adp_order in adporders: adporders.append(adp_order) if len(adporders) == 2: bidirectional = True mylang.add('case-marking-prep-lex := case-marking-adp-lex & \ [ SYNSEM.LOCAL.CAT.HEADFINAL - ].') mylang.add('case-marking-postp-lex := case-marking-adp-lex & \ [ SYNSEM.LOCAL.CAT.HEADFINAL + ].') # Lexical entries lexicon.add_literal(';;; Case-marking adpositions') for adp in ch.get('adp', []): orth = orth_encode(adp.get('orth')) infix_tname = 'ad' if bidirectional: if adp.get('order') == 'before': infix_tname = 'pre' elif adp.get('order') == 'after': infix_tname = 'post' super_type = 'case-marking-' + infix_tname + 'p-lex' # figure out the abbreviation for the case this adp marks cn = '' abbr = '' for feat in adp.get('feat', []): if feat['name'] == 'case': cn = feat['value'] break abbr = name_to_abbr(cn, cases) adp_type = TDLencode(abbr + '-marker') typedef = \ adp_type + ' := ' + super_type + ' & \ [ STEM < "' + orth + '" > ].' lexicon.add(typedef) has_inforstr_feat = False for feat in adp.get('feat', []): if feat['name'] == "information-structure meaning": has_inforstr_feat = True typedef = \ adp_type + ' := [ SYNSEM.LOCAL [ CAT.VAL.COMPS < [ LOCAL.CONT.HOOK.INDEX #target ] >, \ CONT [ HOOK.ICONS-KEY #icons, \ ICONS <! info-str & #icons & [ IARG2 #target ] !> ] ] ] ].' lexicon.add(typedef) break if not has_inforstr_feat: typedef = \ adp_type + ' := [ SYNSEM.LOCAL.CONT [ HOOK [ ICONS-KEY.IARG1 #clause, CLAUSE-KEY #clause ], ICONS <! !> ] ].' lexicon.add(typedef) if cn.strip() != '': customize_trigger_rules(adp_type, trigger) to_cfv += [(adp.full_key, adp_type, 'adp')] return to_cfv
def customize_verbs(mylang, ch, lexicon, hierarchies): negmod = ch.get('neg-mod') negadv = ch.get('neg-adv') wo = ch.get('word-order') auxcomp = ch.get('aux-comp') auxorder = ch.get('aux-comp-order') # Do we need to constrain HC-LIGHT on verbs, to distinguish V from VP? hclight = (negadv == 'ind-adv' and negmod == 'v') hclightallverbs = False if ch.get('has-aux') == 'yes': vc = determine_vcluster(auxcomp, auxorder, wo, ch) if wo == 'vso' or wo == 'osv': wo = 'req-hcl-vp' if auxcomp == 'v' and hclight != True: hclight = True if wo != 'free' or vc == True: hclightallverbs = True if auxcomp == 'vp' and wo == 'req-hcl-vp': hclightallverbs = True else: vc = False if wo == 'req-hcl-vp': wo = ch.get('word-order') # Lexical types for verbs # I'm adding the constraint to associate XARG with the # first ARG-ST element here (so raising auxiliaries work), # but perhaps this belongs in matrix.tdl? Or maybe this # is another module/parameter (like, the external argument # might not be the first one? mainorverbtype = main_or_verb(ch) # The variable mainorverbtype is a type name for lexical/main (non-aux) verbs. # Note that the use of 'main' instead of 'lexical' is strictly for # coding clarity # If there are auxiliaries, non-aux verbs are 'main-verb-lex', and 'verb-lex' # includes both aux and lexical/main verbs. # If there are no auxiliaries then 'verb-lex' covers all verbs # Neither mainverbs or auxs should start out as modifiers (for now) # Assigning constraint to verb-lex if ch.get('has-aux') == 'yes': mylang.add('head :+ [ AUX bool ].', section='addenda') #mainorverbtype = 'main-verb-lex' # we need to know whether the auxiliaries form a vcluster auxcomp = ch.get('aux-comp') wo = ch.get('word-order') auxorder = ch.get('aux-comp-order') vcluster = determine_vcluster(auxcomp, auxorder, wo, ch) typedef = \ 'verb-lex := non-mod-lex-item & \ [ SYNSEM.LOCAL.CAT.HEAD verb ].' mylang.add(typedef) typedef = \ 'main-verb-lex := verb-lex & basic-verb-lex & \ [ SYNSEM.LOCAL.CAT.HEAD.AUX - ].' mylang.add(typedef) typedef = \ 'aux-lex := verb-lex & \ [ SYNSEM.LOCAL.CAT.HEAD.AUX + ].' mylang.add(typedef) if vcluster: mylang.add('main-verb-lex := [ SYNSEM.LOCAL.CAT.VC + ].') mylang.add('aux-lex := [ SYNSEM.LOCAL.CAT.VC - ].') else: #mainorverbtype = 'verb-lex' vcluster = False mylang.add('verb-lex := basic-verb-lex & non-mod-lex-item.') typedef = mainorverbtype + ' := \ [ SYNSEM.LOCAL [ CAT.VAL [ SPR < >, \ SPEC < >, \ SUBJ < #subj > ], \ CONT.HOOK.XARG #xarg ], \ ARG-ST < #subj & \ [ LOCAL [ CAT.VAL [ SPR < >, \ COMPS < > ], \ CONT.HOOK.INDEX #xarg ] ], ... > ].' mylang.add(typedef) if hclightallverbs: mylang.add('verb-lex := [ SYNSEM.LOCAL.CAT.HC-LIGHT - ].') elif hclight: comment = \ ';;; If there are aspects of the syntax which pick out\n' + \ ';;; lexical Vs (transitive or intransitive) such as V-attachment\n' + \ ';;; of adverbs or argument composition auxiliaries which take V\n' + \ ';;; complements, we need to distinguish (intranstive) V and VP.\n' + \ ';;; To do so, we make use of a feature LIGHT. Phrases are\n' + \ ';;; generally [LIGHT -] with the exception of head-complement\n' + \ ';;; phrases, which take their value for LIGHT from the head\'s\n' + \ ';;; HC-LIGHT feature. To make this work for us here, constraint\n' + \ ';;; HC-LIGHT on verbs to be -.' # mylang.add_literal(comment) mylang.add(mainorverbtype + ' := [ SYNSEM.LOCAL.CAT.HC-LIGHT - ].') # intransitive verb lexical type typedef = \ 'intransitive-verb-lex := ' + mainorverbtype + ' & intransitive-lex-item & \ [ SYNSEM.LOCAL.CAT.VAL.COMPS < > ].' mylang.add(typedef) # transitive verb lexical type typedef = \ 'transitive-verb-lex := ' + mainorverbtype + ' & transitive-lex-item & \ [ SYNSEM.LOCAL.CAT.VAL.COMPS < #comps >, \ ARG-ST < [ ], \ #comps & \ [ LOCAL.CAT [ VAL [ SPR < >, \ COMPS < > ] ] ] > ].' mylang.add(typedef) case.customize_verb_case(mylang, ch) # Add constraints to choices to create lex rules for bipartite stems customize_bipartite_stems(ch) # Lexical entries lexicon.add_literal(';;; Verbs') # Now create the lexical entries for all the defined verb types cases = case.case_names(ch) for verb in ch.get('verb',[]): stypes = verb.get('supertypes').split(', ') stype_names = [verb_id(ch[st]) for st in stypes if st != ''] vtype = verb_id(verb) val = verb.get('valence') if not val == '': i = val.find(',') dir_inv = '' tivity = '' if i != -1: val = val[:i] dir_inv = 'dir-inv-' if val == 'trans': tivity = 'trans' elif val == 'intrans': tivity = 'intrans' elif val.find('-') != -1: c = val.split('-') a_case = case.canon_to_abbr(c[0], cases) o_case = case.canon_to_abbr(c[1], cases) tivity = a_case + '-' + o_case + '-trans' else: s_case = case.canon_to_abbr(val, cases) tivity = s_case + '-intrans' if not dir_inv == '' or not tivity == '': stype_names.append(dir_inv + tivity + 'itive-verb-lex') if len(stype_names) == 0: mylang.add(vtype + ' := verb-lex .') else: mylang.add(vtype + ' := ' + ' & '.join(stype_names) + '.') features.customize_feature_values(mylang, ch, hierarchies, verb, vtype, 'verb', None, cases) stems = verb.get('stem', []) stems.extend(verb.get('bistem', [])) for stem in stems: orthstr = orth_encode(stem.get('orth')) pred = stem.get('pred') name = stem.get('name') typedef = \ TDLencode(name) + ' := ' + vtype + ' & \ [ STEM < "' + orthstr + '" >, \ SYNSEM.LKEYS.KEYREL.PRED "' + pred + '" ].' lexicon.add(typedef)
def customize_adjs(mylang, ch, lexicon, hierarchies, rules): # Add basic adjective definition if ch.get('adj',[]): mylang.add("adj-lex := basic-intersective-adjective-lex.") # Check which rules need to be added to rules.tdl adj_rules = {'adj_head': False, 'head_adj': False} # Check which types need to be added to mylanguage.tdl adj_type_base = ('pred_word', 'pred_lex', 'pred_only', 'attr_word', 'attr_lex', 'attr_only', 'stative_word', 'stative_lex', 'any_adj') # Convert into dictionary with False default values #adj_types = {item: False for item in adj_types} adj_types = dict() for item in adj_type_base: adj_types[item] = False # Lexical super types of different adjective types lst_map = {"both": "attr-adj-lex", "attr": "attr-only-adj-lex", "pred": "pred-only-adj-lex", "none": "adj-lex" } # Go through adjective position classes... for adj_pc in ch.get('adj-pc',[]): # check if any have "any adj" as input if not adj_types['any_adj'] and 'adj' in adj_pc.get('inputs',[]).split(', '): adj_types['any_adj'] = True # Additional checks for switching adjectives switching = adj_pc.get('switching',False) if switching: # For each switching adjective... for lrt in adj_pc.get('lrt',[]): # Check its mode to get lexical types to add if not (adj_types['pred_lex'] and adj_types['attr_lex']): adj_pc_mod = lrt.get('mod','') if adj_pc_mod: # TJT 12-05-14: "both" lexical rule types are predicative, too! if adj_pc_mod in ('pred','both'): adj_types['pred_lex'] = True # TJT 11-06-14: "both" lexical rule types are attributive elif adj_pc_mod in ('attr','both'): adj_types['attr_lex'] = True # Check modification direction to get rules to add if not (adj_rules['head_adj'] and adj_rules['adj_head']): lrt_modpos = lrt.get('modpos',False) if lrt_modpos: if lrt_modpos == 'before': adj_rules['head_adj'] = True elif lrt_modpos == 'after': adj_rules['adj_head'] = True elif lrt_modpos == 'either': adj_rules['head_adj'] = True adj_rules['adj_head'] = True # Check predicative behavoir to get rules to add if not adj_types['stative_lex']: # If not a copula complement if not lrt.get('predcop',False): adj_types['stative_lex'] = True # Add the lextypes to mylanguage.tdl for adj in ch.get('adj',[]): # Reset values lst, posthead, subj, pred, adj_constraints, modunique = '', '', '', '', '', '' root = False # Get all supertypes to check for redundant specifications all_supertypes, pathToRoot = get_all_supertypes(adj, ch) if not pathToRoot: raise ValueError("No path to the root was found for type %s." % adj.get('name','') +\ "Please try validating your choices and compiling again.") # Keep track of redundancies supertype_redundancies = defaultdict(lambda: False) ## Check pivots # Pivot on type of adjective mode = adj.get('mod',False) # TJT 2014-09-04: Commenting this out because one should be able # to define subtypes for purely morphological use #if not mode: continue # Pivot on modification direction modpos = adj.get('modpos',False) # Pivot on copula complementation predcop = adj.get('predcop',False) # Pivot on unique modification modunique = adj.get('modunique',False) # Optionally copula complement and adjectives that only agree # in only position must be unspecified at the lexical level if predcop == "opt": mode = "none" # Check for redundancies and collisions def_error = " ".join('''Collision found in supertype at %s! Validate your choices file and try again. Supertype: %s; Supertype Choice: %s Type: %s; Type choice: %s'''.split()).strip() for supertype in all_supertypes: supertype_choice = ch.get(supertype,False) if supertype_choice: # Check mode if mode: supertype_mode = supertype_choice.get('mode',False) if supertype_mode: if supertype_mode == "both" and mode in ('attr', 'pred'): pass # attr and pred unify with both elif mode != supertype_mode: raise ValueError(def_error % (supertype, supertype_mode, adj.get('name',''), mode)) # Check modpos if modpos: supertype_modpos = supertype_choice.get('modpos',False) if supertype_modpos: if modpos == supertype_modpos: supertype_redundancies['modpos'] = True elif supertype_modpos == 'either' and modpos in ('before', 'after'): pass # before and after unify with either else: raise ValueError(def_error % (supertype, supertype_modpos, adj.get('name',''), modpos)) # Check modunique if modunique and supertype_choice.get('modunique',False): supertype_redundancies['modunique'] = True # Check predcop if predcop: supertype_predcop = supertype_choice.get('predcop',False) if supertype_predcop: if predcop == supertype_predcop: supertype_redundancies['predcop'] = True elif supertype_predcop == 'opt' and predcop in ('opt', 'obl'): pass else: raise ValueError(def_error % (supertype, supertype_predcop, adj.get('name',''), predcop)) ## Calculate supertypes stypes = adj.get('supertypes').split(', ') stype_names = [] if '' in stypes: # Found root root = True # Set up root supertypes if root: stype_names = [lst_map[mode]] # Set up defined supertypes else: stype_names = [adj_id(ch[st]) for st in stypes if st] # Add pred-only or attr-only types if mode == 'pred' and predcop != 'opt': stype_names.append("pred-only-adj-lex") elif mode == 'attr': stype_names.append("attr-only-adj-lex") # Format supertypes stype_def = " & ".join(stype_names) or "" if stype_def: stype_def += " & " # Add pred-only and attr-only types if applicable if mode in ('attr','pred'): adj_types["%s_only" % mode] = True # Add proper type to mylanguage.tdl # For attributive adjectives... if mode in ("both", "attr"): # Set up proper rule for mylanguage.tdl adj_types['attr_word'] = True # Pivot on direction of modification if not supertype_redundancies['modpos']: if modpos == 'after': posthead = 'POSTHEAD - ' adj_rules['adj_head'] = True elif modpos == 'before': posthead = 'POSTHEAD + ' adj_rules['head_adj'] = True elif modpos == "either": adj_rules['head_adj'] = True adj_rules['adj_head'] = True # Set up unique modification if necessary if modunique: if not supertype_redundancies['modunique']: modunique = 'MOD < [ MODIFIED notmod ] >' else: modunique = '' if not supertype_redundancies['predcop']: # For predicative adjectives... if mode in ('both', 'pred'): # Set up proper rule for mylanguage.tdl # Pivot on copula complement if predcop == 'obl': # Adjective only appears as copula complement pred = '+' subj = 'VAL.SUBJ < >' if mode == 'pred': adj_types['pred_word'] = True elif predcop == 'opt': # Switching between copula complement and inflection # See deffile.py for zero affixes added here adj_types['stative_lex'] = True adj_types['pred_lex'] = True elif predcop == 'imp': # Adjective only appears as stative predicate pred = '-' adj_types['stative_word'] = True adj_types['pred_word'] = True # Add additional supertype if root: stype_def += 'stative-pred-adj-lex & ' # Calculate HEAD value head = '' if pred and modunique: head = "HEAD [ PRD %s, %s ]" % (pred, modunique) elif pred: head = "HEAD.PRD %s" % pred elif modunique: head = "HEAD." + modunique # Only output constraints if defined if posthead or pred or subj or modunique: adj_constraints = "\n [ SYNSEM.LOCAL.CAT [" + "\n".join([posthead, subj, head]).strip(",\n") + '] ]' # Add lexical types to mylanguage.tdl atype = adj_id(adj) mylang.add(atype + ' := ' + lst + stype_def + adj_constraints + '.') ### Add the proper lexical types to mylanguage.tdl ## Add attributive adjective types if adj_types['attr_word']: mylang.add('''attr-adj-lex := adj-lex & intersective-mod-lex & [ SYNSEM.LOCAL.CAT.HEAD.MOD < [ LOCAL.CAT [ HEAD noun, VAL.SPR cons ] ] > ].''', comment='Basic attributive adjective definition') if adj_types['attr_lex']: mylang.add('''attr-adj-lex-rule := add-only-no-ccont-rule & [ SYNSEM [ LOCAL [ CAT.HEAD.MOD < [ LOCAL intersective-mod & [ CONT.HOOK.INDEX #xarg, CAT [ HEAD noun, VAL.SPR cons ] ] ] >, CONT.HOOK.XARG #xarg ] ] ].''', comment='Basic attributive adjective lexical rule definition', section='lexrules') ## Add attributive-only adjective types if adj_types['attr_only']: attr_only_map = {'attr_word': {'type_name':'attr-only-adj-lex := attr-adj-lex & ', 'section':''}, 'attr_lex': {'type_name':'attr-only-adj-lex-rule := attr-adj-lex-rule & ', 'section':'lexrules'} } for sort in ('attr_word', 'attr_lex'): if adj_types[sort]: mylang.add('''%s [ SYNSEM.LOCAL.CAT [ HEAD.PRD -, VAL.SUBJ < > ] ].''' % \ attr_only_map[sort]['type_name'], section=attr_only_map[sort]['section']) ## Add predicative-only adjective types if adj_types['pred_only']: if adj_types['pred_word']: mylang.add('''pred-only-adj-lex := adj-lex & no-mod-lex.''') if adj_types['pred_lex']: mylang.add('''pred-only-adj-lex-rule := add-only-no-ccont-rule & no-mod-lex.''') ## Add additional types # If there are stative predicates, add the proper rule and supertype pred_adj_map = {'stative_word': {'supertype':'stative-pred-adj-lex := adj-lex &', 'comment':'Stative predicate adjective definition', 'section':''}, 'stative_lex': {'supertype':'stative-pred-lex-rule := add-only-no-ccont-rule & ', 'comment':'Stative predicate adjective lexical rule definition', 'section':'lexrules'}} pred_adj_definition = '''%s [ SYNSEM.LOCAL [ CAT.VAL.SUBJ < [ LOCAL [ CONT.HOOK.INDEX #xarg, CAT [ VAL [ SPR < >, COMPS < > ], HEAD noun ] ] ] >, CONT.HOOK.XARG #xarg ] ].''' for form in ("stative_word", "stative_lex"): if adj_types[form]: mylang.add(pred_adj_definition % pred_adj_map[form]['supertype'], comment=pred_adj_map[form]['comment'], section=pred_adj_map[form]['section']) # If adjective incorporation, add to mylanguage.tdl if ch.get("adj_incorp",False): mylang.add('''adj_incorporation-lex-rule := add-only-rule & [ C-CONT [ RELS <! arg1-ev-relation & [ LBL #ltop, ARG1 #index ] !>, HOOK #hook ], DTR.SYNSEM.LOCAL [ CAT.HEAD noun, CONT.HOOK #hook & [ LTOP #ltop, INDEX #index ] ] ].''', comment='Adjective Incorporation', section='lexrules') # Add the proper syntactic rules to rules.tdl if adj_rules['head_adj']: rules.add("head-adj-int := head-adj-int-phrase.") if adj_rules['adj_head']: rules.add("adj-head-int := adj-head-int-phrase.") # Add the lexical entries to lexicon.tdl lexicon.add_literal(';;; Adjectives') for adj in ch.get('adj',[]): atype = adj_id(adj) # Automatically generate feature values based on choices features.customize_feature_values(mylang, ch, hierarchies, adj, atype, 'adj') for stem in adj.get('stem', []): typedef = TDLencode(stem.get('name')) + ' := ' + atype + ' & \n \ [ STEM < "' + orth_encode(stem.get('orth')) + '" >, \ SYNSEM.LKEYS.KEYREL.PRED "' + stem.get('pred') + '" ].' lexicon.add(typedef)
def customize_nouns(mylang, ch, lexicon, hierarchies): # Figure out which kinds of determiner-marking are in the language seen = {'obl':False, 'opt':False, 'imp':False} seenCount = 0 for noun in ch.get('noun',[]): det = noun.get('det') if not det == '' and not seen[det]: seen[det] = True seenCount += 1 singlentype = (seenCount == 1) # Playing fast and loose with the meaning of OPT on SPR. Using # OPT - to mean obligatory (as usual), OPT + to mean impossible (that's # weird), and leaving OPT unspecified for truly optional. Hoping # this will work at least for LSA111 lab. # ERB 2006-11-28 Update: To make that weird use of OPT work, the # head-spec rule has to require [OPT -] on its non-head daughter. # Adding that just in case we add the no-spr-noun-lex type. typedef = \ 'noun-lex := basic-noun-lex & basic-one-arg & no-hcons-lex-item & \ [ SYNSEM.LOCAL [ CAT.VAL [ SPR < #spr & [ LOCAL.CAT.HEAD det ] >, \ COMPS < >, \ SUBJ < >, \ SPEC < > ] ], \ ARG-ST < #spr > ].' mylang.add(typedef) # Adding empty MOD on general definitiion for noun-lex mylang.add('noun-lex := non-mod-lex-item.') # singlentype means there's only one type of n in the hierarchy. if singlentype: if seen['obl']: typedef = 'noun-lex := [ SYNSEM.LOCAL.CAT.VAL.SPR < [ OPT - ] > ].' mylang.add(typedef) elif seen['imp']: typedef = 'noun-lex := [ SYNSEM.LOCAL.CAT.VAL.SPR < [ OPT + ] > ].' mylang.add(typedef) else: if seen['obl']: typedef = \ 'obl-spr-noun-lex := noun-lex & \ [ SYNSEM.LOCAL.CAT.VAL.SPR < [ OPT - ] > ].' mylang.add(typedef) if seen['imp']: typedef = \ 'no-spr-noun-lex := noun-lex & \ [ SYNSEM.LOCAL.CAT.VAL.SPR < [ OPT + ] > ].' mylang.add(typedef) if seen['imp'] and ch.get('has-dets') == 'yes': mylang.add( 'head-spec-phrase := [ NON-HEAD-DTR.SYNSEM.OPT - ].', 'Nouns which cannot take specifiers mark their SPR requirement\n' + 'as OPT +. Making the non-head daughter OPT - in this rule\n' + 'keeps such nouns out.') if ch.get('case-marking') != 'none': if not ch.has_adp_case(): mylang.add('noun :+ [ CASE case ].', section='addenda') # Add the lexical entries lexicon.add_literal(';;; Nouns') # make a hash of nountypes --> lists of children so that we # can stopdet on children children = defaultdict(dict) for noun in ch.get('noun',[]): for p in noun.get('supertypes').split(', '): children[p][noun.full_key] = 1 # make and populate a dictionary of stopdets, to avoid vacuous det supertypes # have to follow inheritance paths downwards from any nonempty det values stopdets={} for noun in ch.get('noun',[]): # if det is nonempty, child nouns shouldn't inherit det det = noun.get('det') if det != '': if noun.full_key in children: # there are children to stopdet on # recursively look for children parents = [ noun.full_key ] while (True): next_parents = [] for p in parents: if p in children: for c in children[p].keys(): stopdets[c]=True if not c in next_parents: next_parents.append(c) if len(next_parents) == 0: break else: parents = next_parents for noun in ch.get('noun',[]): ntype = noun_id(noun) det = noun.get('det') if noun.full_key in stopdets: det = '' stypes = noun.get('supertypes').split(', ') stype_names = [noun_id(ch[st]) for st in stypes if st != ''] #if singlentype or det == 'opt': # stype = 'noun-lex' if not singlentype: if det == 'obl': stype_names.append('obl-spr-noun-lex') elif det == 'imp': stype_names.append('no-spr-noun-lex') if len(stype_names) == 0: mylang.add(ntype + ' := noun-lex .') else: mylang.add(ntype + ' := ' + ' & '.join(stype_names) + '.') features.customize_feature_values(mylang, ch, hierarchies, noun, ntype, 'noun') for stem in noun.get('stem', []): orthstr = orth_encode(stem.get('orth')) pred = stem.get('pred') name = stem.get('name') typedef = TDLencode(name) + ' := ' + ntype + ' & \ [ STEM < "' + orthstr + '" >, \ SYNSEM.LKEYS.KEYREL.PRED "' + pred + '" ].' lexicon.add(typedef)
def customize_case_adpositions(mylang, lexicon, trigger, ch, case_pos): cases = case_names(ch) # features = ch.features() to_cfv = [] if ch.has_adp_case(): comment = \ ';;; Case-marking adpositions\n' + \ ';;; Case marking adpositions are constrained not to\n' + \ ';;; be modifiers.' mylang.add_literal(comment) case_pos.add('adp') #mylang.add('+np :+ [ CASE case ].', section='addenda') # EKN 2018-04-14 Case marking adps need to be marked as nonpossessive poss = True if ch.get('poss-strat') or ch.get('poss-pron') else False typedef = \ 'case-marking-adp-lex := non-local-none-lex-item & raise-sem-lex-item & \ [ SYNSEM.LOCAL.CAT [ HEAD adp & [ CASE #case, MOD < > ], \ VAL [ SPR < >, \ SUBJ < >, \ COMPS < #comps >, \ SPEC < > ]], \ ARG-ST < #comps & [ LOCAL.CAT [ HEAD noun & [ CASE #case ], \ VAL.SPR < > ]] > ].' mylang.add(typedef) # EKN 03-02-2018 Add CASE real-case to comp of adp if possessives # implemented: if poss: mylang.add('case-marking-adp-lex := [ SYNSEM.LOCAL.CAT \ [ HEAD.POSSESSOR nonpossessive, \ POSSESSUM nonpossessive ], \ ARG-ST < [ LOCAL.CAT.HEAD.CASE real-case ] > ].') if ch.has_mixed_case(): mylang.add('+np :+ [ CASE-MARKED bool ].', section='addenda') mylang.add('case-marking-adp-lex := \ [ ARG-ST < [ LOCAL.CAT.HEAD.CASE-MARKED - ] > ].') # checking whether language has both prepositions and postpositions bidirectional = False adporders = [] for adp in ch.get('adp', []): adp_order = adp.get('order') if adp_order not in adporders: adporders.append(adp_order) if len(adporders) == 2: bidirectional = True mylang.add('case-marking-prep-lex := case-marking-adp-lex & \ [ SYNSEM.LOCAL.CAT.HEADFINAL - ].') mylang.add('case-marking-postp-lex := case-marking-adp-lex & \ [ SYNSEM.LOCAL.CAT.HEADFINAL + ].') # Lexical entries lexicon.add_literal(';;; Case-marking adpositions') adp_type_names = [] for adp in ch.get('adp', []): orth = orth_encode(adp.get('orth')) infix_tname = 'ad' if bidirectional: if adp.get('order') == 'before': infix_tname = 'pre' elif adp.get('order') == 'after': infix_tname = 'post' super_type = 'case-marking-' + infix_tname + 'p-lex' # figure out the abbreviation for the case this adp marks cn = '' abbr = '' for feat in adp.get('feat', []): if feat['name'] == 'case': cn = feat['value'] break abbr = name_to_abbr(cn, cases) # the type name for the adp marker includes the orthography of the marker at the end # this serves to ensure each marker has its own lexical entry # and prevents them from being "merged" due to having identical names adp_type = TDLencode(abbr + '-marker_' + orth) adp_type_names.append(adp_type) typedef = \ adp_type + ' := ' + super_type + ' & \ [ STEM < "' + orth + '" > ].' lexicon.add(typedef) has_inforstr_feat = False for feat in adp.get('feat', []): if feat['name'] == "information-structure meaning": has_inforstr_feat = True typedef = adp_type + \ ' := [ SYNSEM.LOCAL \ [ CAT.VAL.COMPS < \ [ LOCAL.CONT.HOOK.INDEX #target ] >, \ CONT [ HOOK.ICONS-KEY #icons, \ ICONS.LIST < info-str & \ #icons & [ \ IARG2 #target ] > ] ] ] ].' lexicon.add(typedef) break if not has_inforstr_feat: typedef = \ adp_type + ' := [ SYNSEM.LOCAL.CONT [ \ HOOK [ ICONS-KEY.IARG1 #clause, \ CLAUSE-KEY #clause ], \ ICONS.LIST < > ] ].' lexicon.add(typedef) if cn.strip() != '': customize_trigger_rules(adp_type, trigger) to_cfv += [(adp.full_key, adp_type, 'adp')] return to_cfv
def customize_coordination(mylang, ch, lexicon, rules, irules): """ The main coordination customization routine """ mylang.set_section('coord') for cs in ch.get('cs'): csnum = str(cs.iter_num()) mark = cs.get('mark') pat = cs.get('pat') orth = cs.get('orth') orthstr = orth_encode(orth) order = cs.get('order') pre = '' suf = '' tn = TDLencode(orth) if (len(ch.get('cs')) > 1): tn += csnum if mark == 'word': lexicon.add(tn + ' := conj-lex &\ [ STEM < "' + orthstr + '" >,\ SYNSEM.LKEYS.KEYREL.PRED "_and_coord_rel",\ CFORM "' + csnum + '" ].') if pat == 'omni': lexicon.add(tn + '_nosem := nosem-conj-lex &\ [ STEM < "' + orthstr + '" >,\ CFORM "' + csnum + '" ].') if pat == 'a': top = 'apoly-' mid = '' bot = 'unary-' left = '' else: if pat == 'mono': top = 'monopoly-' mid = 'monopoly-' bot = '' left = '' elif pat == 'omni': top = 'omni-' mid = 'omni-' bot = 'omni-' left = 'omni-' elif pat == 'poly': top = 'apoly-' mid = '' bot = '' left = '' if mark == 'affix': bot = 'infl-' if order == 'before': pre = orth else: suf = orth else: if order == 'before': bot += 'conj-first-' if left: left += 'conj-first-' else: bot += 'conj-last-' if left: left += 'conj-last-' # hook this coord strat up to some agreement patterns, or not, if we have no info. if cs.get('csap'): agrrules = [] for csap in cs.get('csap'): # get the agreement patterns used agrrules += customize_agreement_pattern( mylang, ch, csap) # fetch the agreement rules else: agrrules = [('', '')] for pos in ('n', 'np', 'vp', 's'): agrrules = [('', '')] if pos in ('vp', 's') else agrrules if cs.get(pos): define_coord_strat(csnum, pos, top, mid, bot, left, pre, suf, mylang, rules, irules, agrrules)