+++ /dev/null
-
-package java_cup;
-
-import java.util.Hashtable;
-import java.util.Enumeration;
-
-/** This class represents a production in the grammar. It contains
- * a LHS non terminal, and an array of RHS symbols. As various
- * transformations are done on the RHS of the production, it may shrink.
- * As a result a separate length is always maintained to indicate how much
- * of the RHS array is still valid.<p>
- *
- * I addition to construction and manipulation operations, productions provide
- * methods for factoring out actions (see remove_embedded_actions()), for
- * computing the nullability of the production (i.e., can it derive the empty
- * string, see check_nullable()), and operations for computing its first
- * set (i.e., the set of terminals that could appear at the beginning of some
- * string derived from the production, see check_first_set()).
- *
- * @see java_cup.production_part
- * @see java_cup.symbol_part
- * @see java_cup.action_part
- * @version last updated: 7/3/96
- * @author Frank Flannery
- */
-
-public class production {
-
- /*-----------------------------------------------------------*/
- /*--- Constructor(s) ----------------------------------------*/
- /*-----------------------------------------------------------*/
-
- /** Full constructor. This constructor accepts a LHS non terminal,
- * an array of RHS parts (including terminals, non terminals, and
- * actions), and a string for a final reduce action. It does several
- * manipulations in the process of creating a production object.
- * After some validity checking it translates labels that appear in
- * actions into code for accessing objects on the runtime parse stack.
- * It them merges adjacent actions if they appear and moves any trailing
- * action into the final reduce actions string. Next it removes any
- * embedded actions by factoring them out with new action productions.
- * Finally it assigns a unique index to the production.<p>
- *
- * Factoring out of actions is accomplished by creating new "hidden"
- * non terminals. For example if the production was originally: <pre>
- * A ::= B {action} C D
- * </pre>
- * then it is factored into two productions:<pre>
- * A ::= B X C D
- * X ::= {action}
- * </pre>
- * (where X is a unique new non terminal). This has the effect of placing
- * all actions at the end where they can be handled as part of a reduce by
- * the parser.
- */
- public production(
- non_terminal lhs_sym,
- production_part rhs_parts[],
- int rhs_l,
- String action_str)
- throws internal_error
- {
- int i;
- action_part tail_action;
- String declare_str;
- int rightlen = rhs_l;
-
- /* remember the length */
- if (rhs_l >= 0)
- _rhs_length = rhs_l;
- else if (rhs_parts != null)
- _rhs_length = rhs_parts.length;
- else
- _rhs_length = 0;
-
- /* make sure we have a valid left-hand-side */
- if (lhs_sym == null)
- throw new internal_error(
- "Attempt to construct a production with a null LHS");
-
- /* I'm not translating labels anymore, I'm adding code to declare
- labels as valid variables. This way, the users code string is
- untouched
- 6/96 frankf */
-
- /* check if the last part of the right hand side is an action. If
- it is, it won't be on the stack, so we don't want to count it
- in the rightlen. Then when we search down the stack for a
- Symbol, we don't try to search past action */
-
- if (rhs_l > 0) {
- if (rhs_parts[rhs_l - 1].is_action()) {
- rightlen = rhs_l - 1;
- } else {
- rightlen = rhs_l;
- }
- }
-
- /* get the generated declaration code for the necessary labels. */
- declare_str = declare_labels(
- rhs_parts, rightlen, action_str);
-
- if (action_str == null)
- action_str = declare_str;
- else
- action_str = declare_str + action_str;
-
- /* count use of lhs */
- lhs_sym.note_use();
-
- /* create the part for left-hand-side */
- _lhs = new symbol_part(lhs_sym);
-
- /* merge adjacent actions (if any) */
- _rhs_length = merge_adjacent_actions(rhs_parts, _rhs_length);
-
- /* strip off any trailing action */
- tail_action = strip_trailing_action(rhs_parts, _rhs_length);
- if (tail_action != null) _rhs_length--;
-
- /* Why does this run through the right hand side happen
- over and over? here a quick combination of two
- prior runs plus one I wanted of my own
- frankf 6/25/96 */
- /* allocate and copy over the right-hand-side */
- /* count use of each rhs symbol */
- _rhs = new production_part[_rhs_length];
- for (i=0; i<_rhs_length; i++) {
- _rhs[i] = rhs_parts[i];
- if (!_rhs[i].is_action()) {
- ((symbol_part)_rhs[i]).the_symbol().note_use();
- if (((symbol_part)_rhs[i]).the_symbol() instanceof terminal) {
- _rhs_prec =
- ((terminal)((symbol_part)_rhs[i]).the_symbol()).precedence_num();
- _rhs_assoc =
- ((terminal)((symbol_part)_rhs[i]).the_symbol()).precedence_side();
- }
- }
- }
-
- /*now action string is really declaration string, so put it in front!
- 6/14/96 frankf */
- if (action_str == null) action_str = "";
- if (tail_action != null && tail_action.code_string() != null)
- action_str = action_str + "\t\t" + tail_action.code_string();
-
- /* stash the action */
- _action = new action_part(action_str);
-
- /* rewrite production to remove any embedded actions */
- remove_embedded_actions();
-
- /* assign an index */
- _index = next_index++;
-
- /* put us in the global collection of productions */
- _all.put(new Integer(_index),this);
-
- /* put us in the production list of the lhs non terminal */
- lhs_sym.add_production(this);
- }
-
- /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
-
- /** Constructor with no action string. */
- public production(
- non_terminal lhs_sym,
- production_part rhs_parts[],
- int rhs_l)
- throws internal_error
- {
- this(lhs_sym,rhs_parts,rhs_l,null);
- }
-
- /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
-
- /* Constructor with precedence and associativity of production
- contextually define */
- public production(
- non_terminal lhs_sym,
- production_part rhs_parts[],
- int rhs_l,
- String action_str,
- int prec_num,
- int prec_side)
- throws internal_error
- {
- this(lhs_sym,rhs_parts,rhs_l,action_str);
-
- /* set the precedence */
- set_precedence_num(prec_num);
- set_precedence_side(prec_side);
- }
-
- /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
-
- /* Constructor w/ no action string and contextual precedence
- defined */
- public production(
- non_terminal lhs_sym,
- production_part rhs_parts[],
- int rhs_l,
- int prec_num,
- int prec_side)
- throws internal_error
- {
- this(lhs_sym,rhs_parts,rhs_l,null);
- /* set the precedence */
- set_precedence_num(prec_num);
- set_precedence_side(prec_side);
- }
-
- /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
-
- /*-----------------------------------------------------------*/
- /*--- (Access to) Static (Class) Variables ------------------*/
- /*-----------------------------------------------------------*/
-
-
- /** Table of all productions. Elements are stored using their index as
- * the key.
- */
- protected static Hashtable _all = new Hashtable();
-
- /** Access to all productions. */
- public static Enumeration all() {return _all.elements();}
-
- /** Lookup a production by index. */
- public static production find(int indx) {
- return (production) _all.get(new Integer(indx));
- }
-
- /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
-
- /** Total number of productions. */
- public static int number() {return _all.size();}
-
- /** Static counter for assigning unique index numbers. */
- protected static int next_index;
-
- /*-----------------------------------------------------------*/
- /*--- (Access to) Instance Variables ------------------------*/
- /*-----------------------------------------------------------*/
-
- /** The left hand side non-terminal. */
- protected symbol_part _lhs;
-
- /** The left hand side non-terminal. */
- public symbol_part lhs() {return _lhs;}
-
-
- /** The precedence of the rule */
- protected int _rhs_prec = -1;
- protected int _rhs_assoc = -1;
-
- /** Access to the precedence of the rule */
- public int precedence_num() { return _rhs_prec; }
- public int precedence_side() { return _rhs_assoc; }
-
- /** Setting the precedence of a rule */
- public void set_precedence_num(int prec_num) {
- _rhs_prec = prec_num;
- }
- public void set_precedence_side(int prec_side) {
- _rhs_assoc = prec_side;
- }
-
- /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
-
- /** A collection of parts for the right hand side. */
- protected production_part _rhs[];
-
- /** Access to the collection of parts for the right hand side. */
- public production_part rhs(int indx) throws internal_error
- {
- if (indx >= 0 && indx < _rhs_length)
- return _rhs[indx];
- else
- throw new internal_error(
- "Index out of range for right hand side of production");
- }
-
- /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
-
- /** How much of the right hand side array we are presently using. */
- protected int _rhs_length;
-
- /** How much of the right hand side array we are presently using. */
- public int rhs_length() {return _rhs_length;}
-
- /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
-
- /** An action_part containing code for the action to be performed when we
- * reduce with this production.
- */
- protected action_part _action;
-
- /** An action_part containing code for the action to be performed when we
- * reduce with this production.
- */
- public action_part action() {return _action;}
-
- /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
-
- /** Index number of the production. */
- protected int _index;
-
- /** Index number of the production. */
- public int index() {return _index;}
-
- /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
-
- /** Count of number of reductions using this production. */
- protected int _num_reductions = 0;
-
- /** Count of number of reductions using this production. */
- public int num_reductions() {return _num_reductions;}
-
- /** Increment the count of reductions with this non-terminal */
- public void note_reduction_use() {_num_reductions++;}
-
- /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
-
- /** Is the nullability of the production known or unknown? */
- protected boolean _nullable_known = false;
-
- /** Is the nullability of the production known or unknown? */
- public boolean nullable_known() {return _nullable_known;}
-
- /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
-
- /** Nullability of the production (can it derive the empty string). */
- protected boolean _nullable = false;
-
- /** Nullability of the production (can it derive the empty string). */
- public boolean nullable() {return _nullable;}
-
- /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
-
- /** First set of the production. This is the set of terminals that
- * could appear at the front of some string derived from this production.
- */
- protected terminal_set _first_set = new terminal_set();
-
- /** First set of the production. This is the set of terminals that
- * could appear at the front of some string derived from this production.
- */
- public terminal_set first_set() {return _first_set;}
-
- /*-----------------------------------------------------------*/
- /*--- Static Methods ----------------------------------------*/
- /*-----------------------------------------------------------*/
-
- /** Determine if a given character can be a label id starter.
- * @param c the character in question.
- */
- protected static boolean is_id_start(char c)
- {
- return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c == '_');
-
- //later need to handle non-8-bit chars here
- }
-
- /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
-
- /** Determine if a character can be in a label id.
- * @param c the character in question.
- */
- protected static boolean is_id_char(char c)
- {
- return is_id_start(c) || (c >= '0' && c <= '9');
- }
-
- /*-----------------------------------------------------------*/
- /*--- General Methods ---------------------------------------*/
- /*-----------------------------------------------------------*/
-
-
- /** Return label declaration code
- * @param labelname the label name
- * @param stack_type the stack type of label?
- * @author frankf
- */
- protected String make_declaration(
- String labelname,
- String stack_type,
- int offset)
- {
- String ret;
-
- /* Put in the left/right value labels */
- if (emit.lr_values())
- ret = "\t\tint " + labelname + "left = ((java_cup.runtime.Symbol)" +
- emit.pre("stack") + ".elementAt(" + emit.pre("top") +
- "-" + offset + ")).left;\n" +
- "\t\tint " + labelname + "right = ((java_cup.runtime.Symbol)" +
- emit.pre("stack") + ".elementAt(" + emit.pre("top") +
- "-" + offset + ")).right;\n";
- else ret = "";
-
- /* otherwise, just declare label. */
- return ret + "\t\t" + stack_type + " " + labelname + " = (" + stack_type +
- ")((" + "java_cup.runtime.Symbol) " + emit.pre("stack") + ".elementAt(" + emit.pre("top")
- + "-" + offset + ")).value;\n";
-
- }
- /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
-
- /** Declare label names as valid variables within the action string
- * @param rhs array of RHS parts.
- * @param rhs_len how much of rhs to consider valid.
- * @param final_action the final action string of the production.
- * @param lhs_type the object type associated with the LHS symbol.
- */
- protected String declare_labels(
- production_part rhs[],
- int rhs_len,
- String final_action)
- {
- String declaration = "";
-
- symbol_part part;
- action_part act_part;
- int pos;
-
- /* walk down the parts and extract the labels */
- for (pos = 0; pos < rhs_len; pos++)
- {
- if (!rhs[pos].is_action())
- {
- part = (symbol_part)rhs[pos];
-
- /* if it has a label, make declaration! */
- if (part.label() != null)
- {
- declaration = declaration +
- make_declaration(part.label(), part.the_symbol().stack_type(),
- rhs_len-pos-1);
- }
- }
- }
- return declaration;
- }
-
-
-
- /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
-
- /** Helper routine to merge adjacent actions in a set of RHS parts
- * @param rhs_parts array of RHS parts.
- * @param len amount of that array that is valid.
- * @return remaining valid length.
- */
- protected int merge_adjacent_actions(production_part rhs_parts[], int len)
- {
- int from_loc, to_loc, merge_cnt;
-
- /* bail out early if we have no work to do */
- if (rhs_parts == null || len == 0) return 0;
-
- merge_cnt = 0;
- to_loc = -1;
- for (from_loc=0; from_loc<len; from_loc++)
- {
- /* do we go in the current position or one further */
- if (to_loc < 0 || !rhs_parts[to_loc].is_action()
- || !rhs_parts[from_loc].is_action())
- {
- /* next one */
- to_loc++;
-
- /* clear the way for it */
- if (to_loc != from_loc) rhs_parts[to_loc] = null;
- }
-
- /* if this is not trivial? */
- if (to_loc != from_loc)
- {
- /* do we merge or copy? */
- if (rhs_parts[to_loc] != null && rhs_parts[to_loc].is_action() &&
- rhs_parts[from_loc].is_action())
- {
- /* merge */
- rhs_parts[to_loc] = new action_part(
- ((action_part)rhs_parts[to_loc]).code_string() +
- ((action_part)rhs_parts[from_loc]).code_string());
- merge_cnt++;
- }
- else
- {
- /* copy */
- rhs_parts[to_loc] = rhs_parts[from_loc];
- }
- }
- }
-
- /* return the used length */
- return len - merge_cnt;
- }
-
- /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
-
- /** Helper routine to strip a trailing action off rhs and return it
- * @param rhs_parts array of RHS parts.
- * @param len how many of those are valid.
- * @return the removed action part.
- */
- protected action_part strip_trailing_action(
- production_part rhs_parts[],
- int len)
- {
- action_part result;
-
- /* bail out early if we have nothing to do */
- if (rhs_parts == null || len == 0) return null;
-
- /* see if we have a trailing action */
- if (rhs_parts[len-1].is_action())
- {
- /* snip it out and return it */
- result = (action_part)rhs_parts[len-1];
- rhs_parts[len-1] = null;
- return result;
- }
- else
- return null;
- }
-
- /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
-
- /** Remove all embedded actions from a production by factoring them
- * out into individual action production using new non terminals.
- * if the original production was: <pre>
- * A ::= B {action1} C {action2} D
- * </pre>
- * then it will be factored into: <pre>
- * A ::= B NT$1 C NT$2 D
- * NT$1 ::= {action1}
- * NT$2 ::= {action2}
- * </pre>
- * where NT$1 and NT$2 are new system created non terminals.
- */
-
- /* the declarations added to the parent production are also passed along,
- as they should be perfectly valid in this code string, since it
- was originally a code string in the parent, not on its own.
- frank 6/20/96 */
- protected void remove_embedded_actions(
-
- ) throws internal_error
- {
- non_terminal new_nt;
- production new_prod;
- String declare_str;
-
- /* walk over the production and process each action */
- for (int act_loc = 0; act_loc < rhs_length(); act_loc++)
- if (rhs(act_loc).is_action())
- {
-
-
- declare_str = declare_labels(
- _rhs, act_loc, "");
- /* create a new non terminal for the action production */
- new_nt = non_terminal.create_new();
- new_nt.is_embedded_action = true; /* 24-Mar-1998, CSA */
-
- /* create a new production with just the action */
- new_prod = new action_production(this, new_nt, null, 0,
- declare_str + ((action_part)rhs(act_loc)).code_string());
-
- /* replace the action with the generated non terminal */
- _rhs[act_loc] = new symbol_part(new_nt);
- }
- }
-
- /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
-
- /** Check to see if the production (now) appears to be nullable.
- * A production is nullable if its RHS could derive the empty string.
- * This results when the RHS is empty or contains only non terminals
- * which themselves are nullable.
- */
- public boolean check_nullable() throws internal_error
- {
- production_part part;
- symbol sym;
- int pos;
-
- /* if we already know bail out early */
- if (nullable_known()) return nullable();
-
- /* if we have a zero size RHS we are directly nullable */
- if (rhs_length() == 0)
- {
- /* stash and return the result */
- return set_nullable(true);
- }
-
- /* otherwise we need to test all of our parts */
- for (pos=0; pos<rhs_length(); pos++)
- {
- part = rhs(pos);
-
- /* only look at non-actions */
- if (!part.is_action())
- {
- sym = ((symbol_part)part).the_symbol();
-
- /* if its a terminal we are definitely not nullable */
- if (!sym.is_non_term())
- return set_nullable(false);
- /* its a non-term, is it marked nullable */
- else if (!((non_terminal)sym).nullable())
- /* this one not (yet) nullable, so we aren't */
- return false;
- }
- }
-
- /* if we make it here all parts are nullable */
- return set_nullable(true);
- }
-
- /** set (and return) nullability */
- boolean set_nullable(boolean v)
- {
- _nullable_known = true;
- _nullable = v;
- return v;
- }
-
- /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
-
- /** Update (and return) the first set based on current NT firsts.
- * This assumes that nullability has already been computed for all non
- * terminals and productions.
- */
- public terminal_set check_first_set() throws internal_error
- {
- int part;
- symbol sym;
-
- /* walk down the right hand side till we get past all nullables */
- for (part=0; part<rhs_length(); part++)
- {
- /* only look at non-actions */
- if (!rhs(part).is_action())
- {
- sym = ((symbol_part)rhs(part)).the_symbol();
-
- /* is it a non-terminal?*/
- if (sym.is_non_term())
- {
- /* add in current firsts from that NT */
- _first_set.add(((non_terminal)sym).first_set());
-
- /* if its not nullable, we are done */
- if (!((non_terminal)sym).nullable())
- break;
- }
- else
- {
- /* its a terminal -- add that to the set */
- _first_set.add((terminal)sym);
-
- /* we are done */
- break;
- }
- }
- }
-
- /* return our updated first set */
- return first_set();
- }
-
- /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
-
- /** Equality comparison. */
- public boolean equals(production other)
- {
- if (other == null) return false;
- return other._index == _index;
- }
-
- /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
-
- /** Generic equality comparison. */
- public boolean equals(Object other)
- {
- if (!(other instanceof production))
- return false;
- else
- return equals((production)other);
- }
-
- /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
-
- /** Produce a hash code. */
- public int hashCode()
- {
- /* just use a simple function of the index */
- return _index*13;
- }
-
- /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
-
- /** Convert to a string. */
- public String toString()
- {
- String result;
-
- /* catch any internal errors */
- try {
- result = "production [" + index() + "]: ";
- result += ((lhs() != null) ? lhs().toString() : "$$NULL-LHS$$");
- result += " :: = ";
- for (int i = 0; i<rhs_length(); i++)
- result += rhs(i) + " ";
- result += ";";
- if (action() != null && action().code_string() != null)
- result += " {" + action().code_string() + "}";
-
- if (nullable_known())
- if (nullable())
- result += "[NULLABLE]";
- else
- result += "[NOT NULLABLE]";
- } catch (internal_error e) {
- /* crash on internal error since we can't throw it from here (because
- superclass does not throw anything. */
- e.crash();
- result = null;
- }
-
- return result;
- }
-
- /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
-
- /** Convert to a simpler string. */
- public String to_simple_string() throws internal_error
- {
- String result;
-
- result = ((lhs() != null) ? lhs().the_symbol().name() : "NULL_LHS");
- result += " ::= ";
- for (int i = 0; i < rhs_length(); i++)
- if (!rhs(i).is_action())
- result += ((symbol_part)rhs(i)).the_symbol().name() + " ";
-
- return result;
- }
-
- /*-----------------------------------------------------------*/
-
-}