#!/usr/bin/env python # # For this to work, you need to have the main directory that contains # parser/ and semantics/ in your PYTHONPATH. # import decompile from nltk.tree import Tree from parser.feature import * from parser import parser trace = 2 TITLE = "6.863 Semantic Framework" VERSION = "1.1" DATE = "April 14, 2004" class SemanticRuleSet(object): def __init__(self): self._dict = {} self._grammar = [] self.learned = SemanticDatabase() def addMatch(self, production, func): if isinstance(production, str): production = parseRule(production) self._dict[production] = func def add(self, production, func): if isinstance(production, str): production = parseRule(production) self.addMatch(production, func) self._grammar.append(production) def get(self, production): if isinstance(production, str): production = parseRule(production) return self._dict.get(production) def addLexicon(self, preterminal, terminals): if isinstance(preterminal, str): preterminal = Category.parse(preterminal) for terminal in terminals: prod = CFGProduction(preterminal, terminal) self._grammar.append(prod) def items(self): return self._dict.items() def grammar(self): return parser.EarleyCFG(C("Start"), self._grammar) class SemanticDatabase(object): def __init__(self): self._facts = [] def add(self, fact): self._facts.insert(0, fact) def match(self, fact): for fact2 in self._facts: if fact2.match(fact) is not None: return fact2 return None def matchVar(self, fact): for fact2 in self._facts: vars = fact2.match(fact) if vars is not None: return vars return None def nodevalue(node): if not isinstance(node, Tree): return node else: return node.node() def process_tree(node, semantic_dict): if not isinstance(node, Tree): return node root = nodevalue(node) children = [nodevalue(x) for x in node.children()] children_str = " ".join([repr(x) for x in children]) if children_str == '-': children = [] edge_str = "%s -> %s" % (root, children_str) loc_str = " ".join([str(x) for x in node.leaves()]) for (edge, expr) in semantic_dict.items(): if expr is None: continue # Find the first entry in the semantic table for this edge lhsvars = root.match(edge.lhs()) if lhsvars is not None: rhsvars = matchall(children, edge.rhs()) vars = merge(lhsvars, rhsvars) if vars is not None: if trace > 1: print ">> Evaluating: %s" % edge_str print " Text: %s" % loc_str print " Expression: %s" % decompile.lambdastr(expr) print if children == []: args = [] else: args = [process_tree(subtree, semantic_dict) for subtree in node.children()] try: result = apply(expr, args, vars) except TypeError: print "Could not apply %s to %s" % (decompile.lambdastr(expr), args) raise if trace: print "<< Evaluated: %s" % edge_str print " Text: %s" % loc_str print " Value: %s" % (decompile.lambdastr(result)) print return result raise ValueError, "Could not find a semantic entry for %s -> %s" %\ (root, children_str) def matchall(tok1, tok2): if len(tok1) != len(tok2): return None vars = {} for (t1, t2) in zip(tok1, tok2): if type(t1) == str: if type(t2) == str and t1.upper() != t2.upper(): return None else: vars = merge(vars, t1.match(t2)) if vars is None: return None return vars def demo_sentence(sentence): import lab_rules parseit = parser.ParserInterface(lab_rules.sem.grammar(), trace=trace) tree = parseit.getOneParse(sentence) if tree is None: print "The sentence did not parse." else: tree = tree.type() print tree print process_tree(tree, lab_rules.sem) def demo(): import sys, lab_rules while True: sys.stdout.write("> ") sentence = sys.stdin.readline() if not sentence: break else: parseit = parser.ParserInterface(lab_rules.sem.grammar(), trace=trace) tree = parseit.getOneParse(sentence) if tree is None: print "I don't understand." else: tree = tree.type() print process_tree(tree, lab_rules.sem) def main(): global trace import sys, os, shutil from optparse import OptionParser, OptionGroup usage = """%%prog [options] [rule_file] %(TITLE)s version %(VERSION)s (%(DATE)s) by Rob Speer Distributed under the GPL. See LICENSE.TXT for information.""" % globals() homedir = os.path.expanduser('~') newdir = os.sep.join([homedir, ".6863semantics"]) if not os.path.isdir(newdir): sys.stderr.write(\ """The semantics engine now writes its working file to a directory under your home directory, ~/.6863semantics, instead of to /tmp. That directory will be created now. """) os.mkdir(newdir) tmpdir = newdir sys.path.insert(0, tmpdir) curfile = os.sep.join([tmpdir, "current_rules.py"]) opts = OptionParser(usage=usage) opts.add_option("-b", "--batch", metavar="FILE", dest="batchfile", default=None, help="Batch test: interpret all the lines in a file") opts.add_option("-v", "--verbose", action="store_true", dest="verbose", help="output lots of lambda applications [default]") opts.add_option("-q", "--quiet", action="store_true", dest="quiet", help="output only the responses [default in batch mode]") (options, args) = opts.parse_args() trace = 2 batch = False if options.batchfile is not None: trace = 0 batch = True if options.verbose: trace = 2 if options.quiet: trace = 0 if not len(args): opts.print_help() sys.exit(0) infile = args[0] if not os.access(infile, os.R_OK): sys.stderr.write("Error: Could not open %s.\n" % infile) sys.exit(0) try: shutil.copy(infile, curfile) except: sys.stderr.write("Error: Could not write to temp directory (%s).\n" % tmpdir) sys.exit(0) if trace: print "Loading semantics..." import current_rules print print "Hello, Doctor!" instream = None if batch: try: instream = open(options.batchfile) except: sys.stderr.write("Error: Could not open batch file: %s\n" % options.batchfile) sys.exit(0) else: instream = sys.stdin while True: sys.stdout.write("> ") sentence = instream.readline() if (not sentence) or (len(sentence) <= 1): break else: parseit = parser.ParserInterface(current_rules.sem.grammar(), trace=trace) tree = parseit.getOneParse(sentence) if tree is None: print "I don't understand." else: tree = tree.type() print process_tree(tree, current_rules.sem) if __name__ == '__main__': main()