package net.sf.jlinkgrammar; /** * TODO add javadoc * The E_list an Exp structures defined below comprise the expression * trees that are stored in the dictionary. The expression has a type * (AND, OR or TERMINAL). If it is not a terminal it has a list * (an EList) of children. * */ public class Exp { /* one of three types, see below */ int type; /* The cost of using this expression. Only used for non-terminals */ int cost; /* '-' means to the left, '+' means to right (for connector) */ char dir; /* true if a multi-connector (for connector) */ boolean multi; /* only needed for non-terminals */ ExpList l; /* only needed if it's a connector */ String string; Exp next; Exp(Exp e) { type = e.type; cost = e.cost; dir = e.dir; multi = e.multi; l = e.l; string = e.string; next = e.next; } Exp() { } Clause build_Clause(int cost_cutoff) { /* Build the Clause for the expression e. Does not change e */ Clause c = null, c1, c2, c3, c4, c_head; ExpList e_list; if (type == GlobalBean.AND_type) { c1 = new Clause(); c1.c = null; c1.next = null; c1.cost = 0; c1.maxcost = 0; for (e_list = l; e_list != null; e_list = e_list.next) { c2 = e_list.e.build_Clause(cost_cutoff); c_head = null; for (c3 = c1; c3 != null; c3 = c3.next) { for (c4 = c2; c4 != null; c4 = c4.next) { c = new Clause(); c.cost = c3.cost + c4.cost; c.maxcost = Math.max(c3.maxcost, c4.maxcost); c.c = TConnector.catenate(c3.c, c4.c); c.next = c_head; c_head = c; } } c1 = c_head; } c = c1; } else if (type == GlobalBean.OR_type) { /* we'll catenate the lists of clauses */ c = null; for (e_list = l; e_list != null; e_list = e_list.next) { c1 = e_list.e.build_Clause(cost_cutoff); while (c1 != null) { c3 = c1.next; c1.next = c; c = c1; c1 = c3; } } } else if (type == GlobalBean.CONNECTOR_type) { c = new Clause(); c.c = build_terminal(); c.cost = 0; c.maxcost = 0; c.next = null; } else { throw new RuntimeException("an expression node with no type"); } /* c now points to the list of clauses */ for (c1 = c; c1 != null; c1 = c1.next) { c1.cost += cost; /* This is how Dennis had it. I prefer the line below */ /* c1.maxcost = MAX(c1.maxcost,cost); */ c1.maxcost += cost; } return c; } TConnector build_terminal() { /* build the connector for the terminal node n */ TConnector c; c = new TConnector(this); return c; } int size_of_expression() { /* Returns the number of connectors in the expression e */ int size; ExpList el; if (type == GlobalBean.CONNECTOR_type) return 1; size = 0; for (el = l; el != null; el = el.next) { size += el.e.size_of_expression(); } return size; } void insert_connectors(int dir) { /* Put into the set S all of the dir-pointing connectors still in e. */ Connector dummy = new Connector(); ExpList el; dummy.init_connector(); dummy.label = GlobalBean.NORMAL_LABEL; dummy.priority = GlobalBean.THIN_priority; /* dummy.my_word = NO_WORD; */ /* turn off the length part of the matching */ if (type == GlobalBean.CONNECTOR_type) { if (dir == this.dir) { dummy.string = string; Sentence.insert_S(dummy); } } else { for (el = l; el != null; el = el.next) { el.e.insert_connectors(dir); } } } int mark_dead_connectors(Sentence sent,char d) { /* Mark as dead all of the dir-pointing connectors in e that are not matched by anything in the current set. Returns the number of connectors so marked. */ Connector dummy = new Connector(); int count; ExpList el; dummy.init_connector(); dummy.label = GlobalBean.NORMAL_LABEL; dummy.priority = GlobalBean.THIN_priority; /* dummy.my_word = NO_WORD; */ /* turn off the length part of the matching */ count = 0; if (type == GlobalBean.CONNECTOR_type) { if (dir == d) { dummy.string = string; if (!sent.matches_S(dummy, d)) { string = null; count++; } } } else { for (el = l; el != null; el = el.next) { count += el.e.mark_dead_connectors(sent,d); } } return count; } /* The purge operations remove all irrelevant stuff from the expression, */ /* and free the purged stuff. A connector is deemed irrelevant if its */ /* string pointer has been set to null. The passes through the sentence */ /* have the job of doing this. */ /* If an OR or AND type expression node has one child, we can replace it by */ /* its child. This, of course, is not really necessary */ Exp purge_Exp() { /* Must be called with a non-null expression */ /* Return null iff the expression has no disjuncts. */ /* Exp * ne; */ if (type == GlobalBean.CONNECTOR_type) { if (string == null) { return null; } else { return this; } } if (type == GlobalBean.AND_type) { if (!and_purge_ExpList(l)) { return null; } } else { l = or_purge_ExpList(l); if (l == null) { return null; } } return this; } static boolean and_purge_ExpList(ExpList l) { /* Returns 0 iff the length of the disjunct list is 0. */ /* If this is the case, it frees the structure rooted at l. */ if (l == null) return true; if ((l.e = l.e.purge_Exp()) == null) { return false; } if (!and_purge_ExpList(l.next)) { return false; } return true; } ExpList or_purge_ExpList(ExpList l) { /* get rid of the elements with null expressions */ ExpList el; if (l == null) return null; if ((l.e = l.e.purge_Exp()) == null) { el = or_purge_ExpList(l.next); return el; } l.next = or_purge_ExpList(l.next); return l; } static Exp copy_Exp(Exp e) { Exp n; if (e == null) return null; n = new Exp(e); if (e.type != GlobalBean.CONNECTOR_type) { n.l = ExpList.copy_ExpList(e.l); } return n; } ConnectorSet connector_set_create() { int i; ConnectorSet conset; conset = new ConnectorSet(); conset.table_size = MyRandom.next_power_of_two_up(size_of_expression()); conset.hash_table = new Connector[conset.table_size]; for (i = 0; i < conset.table_size; i++) conset.hash_table[i] = null; build_connector_set_from_expression(conset); return conset; } void build_connector_set_from_expression(ConnectorSet conset) { ExpList el; Connector c; int h; if (type == GlobalBean.CONNECTOR_type) { c = new Connector(); c.init_connector(); c.string = string; c.label = GlobalBean.NORMAL_LABEL; /* so we can use match() */ c.priority = GlobalBean.THIN_priority; c.word = dir; /* just use the word field to give the dir */ h = conset.connector_set_hash(c.string, c.word); c.next = conset.hash_table[h]; conset.hash_table[h] = c; } else { for (el = l; el != null; el = el.next) { el.e.build_connector_set_from_expression(conset); } } } }