/*
* @(#)$Id: Rules.java 1087 2001-08-18 01:37:50Z Bear $
*
* Copyright 2001 Sun Microsystems, Inc. All Rights Reserved.
*
* This software is the proprietary information of Sun Microsystems, Inc.
* Use is subject to license terms.
*
*/
package com.sun.tahiti.compiler.ll;
import com.sun.msv.grammar.Expression;
import com.sun.msv.grammar.NameClassAndExpression;
import com.sun.tahiti.compiler.XMLWriter;
import com.sun.tahiti.compiler.Symbolizer;
import java.util.Iterator;
import java.util.Set;
import java.util.Map;
/**
* a set of rules.
*
* @author
* <a href="mailto:kohsuke.kawaguchi@sun.com">Kohsuke KAWAGUCHI</a>
*/
public final class Rules {
/**
* set of all distinctive rules.
* This map can possibly contain unreachable object.
*/
private final Map distinctiveRules = new java.util.HashMap();
/**
* a map from left side symbol (Object) to the set of Rules.
*/
private final Map rules = new java.util.HashMap();
/** gets a Set that stores the values associated with the specified key. */
public Set get( Expression symbol ) {
Set s = (Set)rules.get(symbol);
if(s==null)
rules.put(symbol,s=new java.util.HashSet());
return s;
}
/** gets all values associated with the specified symbol. */
public Rule[] getAll( Expression symbol ) {
return (Rule[])get(symbol).toArray(new Rule[0]);
}
/** returns true if this container has a rule that expands the specified symbol
*/
public boolean contains( Expression symbol ) {
Set s = (Set)rules.get(symbol);
if(s==null) return false;
return s.size()!=0;
}
/** iterates non-terminal symbols in this rules. */
public Iterator iterateKeys() {
return rules.keySet().iterator();
}
Rule unifyRule( Rule r ) {
Rule unified = (Rule)distinctiveRules.get(r);
if(unified==null)
distinctiveRules.put( unified=r, r );
return unified;
}
/** adds a new rule. */
public void add( Expression left, Rule right ) {
get(left).add(unifyRule(right));
}
/** adds a new rule. */
public void add( Expression left, Expression[] right, boolean isInterleave ) {
add(left, new Rule(right,isInterleave));
}
/** adds a new rule. */
public void add( Expression left, Expression right ) {
add(left, new Expression[]{right}, false );
}
/** adds all rules. */
public void addAll( Expression left, Rule[] rules ) {
for( int i=0; i<rules.length; i++ )
add( left, rules[i] );
}
/** merges redundant rules and makes the rule set smaller. */
public void intern() {
final Map distinctRules = new java.util.HashMap();
final Set temp = new java.util.HashSet();
Iterator itr = iterateKeys();
while( itr.hasNext() ) {
Set s = get( (Expression)itr.next() );
temp.clear();
Iterator jtr = s.iterator();
while( jtr.hasNext() ) {
// unify 'r'
Rule r = (Rule)jtr.next();
Rule unified = (Rule)distinctiveRules.get(r);
if(unified==null) {
distinctiveRules.put(r,r);
unified = r;
}
temp.add(unified);
}
// replace the contents of 's' by the unified rules.
s.clear();
s.addAll(temp);
}
}
/**
* computes a new rule set by removing unreachable rules from the rule set.
*
* <p>
* A rule which is unreachable from the specified <code>rootSymbol</code>
* will be removed.
*
* @param recurseElement
* <p>
* if true, this method recursively visits element and attribute and
* discover all reachable rules. This is useful for global optimization.
*
* <p>
* if set to false, this method treats element and attribute as terminal
* symbols. This is useful to extract per-element/per-attribute rules.
*/
public Rules removeUnreachableRules( Expression rootSymbol, boolean recurseElement ) {
Rules result = new Rules();
Set workQueue = new java.util.HashSet();
workQueue.add(rootSymbol);
while(!workQueue.isEmpty()) {
// get the first one in the queue.
Expression symbol = (Expression)workQueue.iterator().next();
workQueue.remove(symbol);
Rule[] rs = this.getAll(symbol);
assert(rs!=null && rs.length!=0);
result.addAll(symbol,rs);
for( int i=0; i<rs.length; i++ ) {
for( int j=0; j<rs[i].right.length; j++ ) {
Expression e = rs[i].right[j];
if(!Util.isTerminalSymbol(e) && !result.contains(e)) {
if(!recurseElement && (e instanceof NameClassAndExpression) )
// if this is ElementExp or AttributeExp and
// we don't want to recursively visit them.
continue;
// recursively add rules reachable from this rule
workQueue.add(e);
assert( e!=null );
}
}
}
}
return result;
}
private static void assert( boolean b ) {
if(!b) throw new Error();
}
}