/projects/sablecc-3.2/src/org/sablecc/sablecc/Grammar.java
Java | 687 lines | 512 code | 119 blank | 56 comment | 68 complexity | e5cd317fafdc5f9c6ae2f571b77065bf MD5 | raw file
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * This file is part of SableCC. *
- * See the file "LICENSE" for copyright information and the *
- * terms and conditions for copying, distribution and *
- * modification of SableCC. *
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
- package org.sablecc.sablecc;
- import java.util.Vector;
- import java.util.*;
- public final class Grammar
- {
- private static TreeMap fastLr0Closure = new TreeMap();
- private static TreeMap fastLr1Closure = new TreeMap();
- static int startSymbol;
- static int startProduction;
- static int eof ;
- static int dummy ;
- static int[][][] action_;
- static int[][] goto_;
- static
- {
- reinit();
- }
- private Grammar()
- {}
- public static int addTerminal(String name, String errorName)
- {
- return new Symbol(name, errorName, true).index;
- }
- public static int addNonterminal(String name)
- {
- return new Symbol(name, null, false).index;
- }
- public static int addProduction(String nonterminal, String name)
- {
- Symbol symbol = Symbol.symbol(nonterminal);
- if(symbol.terminal)
- {
- throw new IllegalArgumentException("The symbol " + nonterminal +
- " is a terminal.");
- }
- return new Production(symbol.index, name).index;
- }
- public static void addSymbolToProduction(String symbol, int production)
- {
- Production.production(production).addSymbol(Symbol.symbol(symbol));
- }
- public static void reinit()
- {
- fastLr0Closure = new TreeMap();
- fastLr1Closure = new TreeMap();
- startSymbol = 0;
- startProduction = -1;
- eof = -1;
- dummy = -1;
- action_ = null;
- goto_ = null;
- }
- public static void computeLALR() throws ConflictException
- {
- // Add EOF to terminals
- eof = addTerminal("EOF", "EOF");
- // Add dummy to terminals
- dummy = addTerminal("#", null);
- // Add the production S'->S
- startSymbol = addNonterminal("Start");
- Production start = new Production(startSymbol, "Start");
- start.addSymbol(Symbol.symbol(0, false));
- startProduction = start.index;
- computeFirst();
- LR0ItemSet set
- = new LR0ItemSet();
- set.set(new LR0Item(startProduction, 0));
- LR1Collection collection = new LR1Collection(set
- );
- LR0ItemSet[] sets = collection.collection.sets();
- Symbol[] terminals = Symbol.terminals();
- Symbol[] nonterminals = Symbol.nonterminals();
- action_ = new int[sets.length][terminals.length - 1][];
- goto_ = new int[sets.length][nonterminals.length - 1];
- Set listOfConflictualProds = new HashSet();
- StringBuffer conflictMessage = new StringBuffer();
- for(int i = 0; i < sets.length; i++)
- {
- System.out.print(".");
- LR1ItemSet state = new LR1ItemSet();
- {
- LR0Item[] items = sets[i].items();
- for(int j = 0; j < items.length; j++)
- {
- Symbol[] lookaheads = ((SymbolSet) collection.lookaheads[i].
- get
- (items[j])).getSymbols();
- for(int k = 0; k < lookaheads.length; k++)
- {
- state.set(new LR1Item(items[j], lookaheads[k].index));
- }
- }
- }
- state = CLOSURE(state);
- LR1Item[] items = state.items();
- for(int j = 0; j < terminals.length; j++)
- {
- Integer destination = collection.collection.GOTO(i, terminals[j]);
- if(destination != null)
- {
- //Shift action is taken
- action_[i][j] = new int[] {0, destination.intValue()};
- }
- for(int k = 0; k < items.length; k++)
- {
- Production production = Production.
- production(items[k].lr0Item.production);
- //A conflict occurs only if one is on the end of an alternative
- try
- {
- production.rightside(items[k].lr0Item.position);
- }
- catch(Exception e)
- {
- if(production.leftside != startSymbol)
- {
- if(items[k].terminal == terminals[j].index)
- {
- int[] action = action_[i][j];
- if(action != null)
- {
- /* The current alternative is conflictual (reduce in a XXX/reduce conflict) */
- listOfConflictualProds.add(Symbol.symbol(production.leftside, false).toString());
- /* */
- switch(action[0])
- {
- case 0:
- conflictMessage.append(
- "\n\nshift/reduce conflict in state [stack:" +
- collection.collection.names.elementAt(i) + "*] on " +
- terminals[j] + " in " + state.toString(terminals[j]));
- /* nothing else to do */
- break;
- case 1:
- conflictMessage.append(
- "\n\nreduce/reduce conflict in state [stack:" +
- collection.collection.names.elementAt(i) + "*] on " +
- terminals[j] + " in " + state.toString(terminals[j]));
- listOfConflictualProds.add(Symbol.symbol(Production.production(action[1]).leftside, false).toString());
- break;
- case 2:
- conflictMessage.append(
- "\n\nreduce/accept conflict in state [stack:" +
- collection.collection.names.elementAt(i) + "*] on " +
- terminals[j] + " in " + state.toString(terminals[j]));
- listOfConflictualProds.add(Symbol.symbol(Production.production(action[1]).leftside, false).toString());
- break;
- }
- }
- else
- {
- //it's a reduction action
- action_[i][j] = new int[] {1,
- items[k].lr0Item.production};
- }
- }
- }
- else
- {
- if(terminals[j].index == eof)
- {
- int[] action = action_[i][j];
- if(action != null)
- {
- /* The current alternative is conflictual (accept in a XXX/accept conflict) */
- listOfConflictualProds.add(Symbol.symbol(production.leftside, false).toString());
- /* */
- switch(action[0])
- {
- case 0:
- conflictMessage.append(
- "shift/accept conflict in state [stack:" +
- collection.collection.names.elementAt(i) + "*] on " +
- terminals[j] + " in " + state);
- /* nothing else to do */
- break;
- case 1:
- conflictMessage.append(
- "reduce/accept conflict in state [stack:" +
- collection.collection.names.elementAt(i) + "*] on " +
- terminals[j] + " in " + state);
- listOfConflictualProds.add(Symbol.symbol(Production.production(action[1]).leftside, false).toString());
- break;
- }
- }
- else
- {
- //accept action is taken
- action_[i][j] = new int[] {2};
- }
- }
- }
- }//End of catch
- }
- }
- if (listOfConflictualProds.size() > 0)
- {
- throw new ConflictException(listOfConflictualProds, conflictMessage.toString());
- }
- for(int j = 0; j < nonterminals.length - 1; j++)
- {
- Integer destination = collection.collection.GOTO(i, nonterminals[j]);
- if(destination != null)
- {
- goto_[i][j] = destination.intValue();
- }
- else
- {
- goto_[i][j] = -1;
- }
- }
- }
- System.out.println();
- }
- static SymbolSet[] FIRST_Terminal;
- static SymbolSet[] FIRST_Nonterminal;
- static void computeFirst()
- {
- // Get terminals, nonterminals and productions
- Symbol[] terminals = Symbol.terminals();
- Symbol[] nonterminals = Symbol.nonterminals();
- Production[] productions = Production.productions();
- // Initialize FIRST(X) to {}
- FIRST_Terminal = new SymbolSet[terminals.length];
- for(int i = 0; i < terminals.length; i++)
- {
- FIRST_Terminal[i] = new SymbolSet();
- }
- FIRST_Nonterminal = new SymbolSet[nonterminals.length];
- for(int i = 0; i < nonterminals.length; i++)
- {
- FIRST_Nonterminal[i] = new SymbolSet();
- }
- // if X is terminal, then FIRST(X) is {X}
- for(int i = 0; i < terminals.length; i++)
- {
- FIRST_Terminal[i].setTerminal(terminals[i].index);
- }
- // if X -> empty is a production, then add empty to FIRST(X)
- for(int i = 0; i < productions.length; i++)
- {
- if(productions[i].rightside().length == 0)
- {
- FIRST_Nonterminal[productions[i].leftside].
- setEmpty();
- }
- }
- // if X is nonterminal and X -> Y(1) Y(2) ... Y(k) is a production,
- // then place t in FIRST(X) if for some i, t is in FIRST(Y(i)), and
- // empty is in all of FIRST(Y(1)), ... , FIRST(Y(i-1)).
- boolean changed;
- do
- {
- changed = false;
- for(int i = 0; i < productions.length; i++)
- {
- SymbolSet before =
- (SymbolSet) FIRST_Nonterminal[productions[i].leftside].clone();
- FIRST_Nonterminal[productions[i].leftside].
- or(FIRST(productions[i].rightside()));
- if(!before.equals(FIRST_Nonterminal[productions[i].leftside]))
- {
- changed = true;
- }
- }
- }
- while(changed);
- }
- static SymbolSet FIRST(Symbol[] symbols)
- {
- return FIRST(symbols, 0, symbols.length);
- }
- static SymbolSet FIRST(Symbol[] symbols, int begin)
- {
- return FIRST(symbols, begin, symbols.length);
- }
- static SymbolSet FIRST(Symbol[] symbols, int begin, int end)
- {
- SymbolSet result = new SymbolSet();
- boolean previousContainsEmpty = true;
- for(int i = begin; i < end; i++)
- {
- if(!previousContainsEmpty)
- {
- break;
- }
- if(symbols[i].terminal)
- {
- result.or(FIRST_Terminal[symbols[i].index]);
- previousContainsEmpty = FIRST_Terminal[symbols[i].index].getEmpty();
- }
- else
- {
- result.or(FIRST_Nonterminal[symbols[i].index]);
- previousContainsEmpty = FIRST_Nonterminal[symbols[i].index].getEmpty();
- }
- }
- if(previousContainsEmpty)
- {
- result.setEmpty();
- }
- else
- {
- result.clearEmpty();
- }
- return result;
- }
- static SymbolSet[] FOLLOW;
- static void computeFollow()
- {
- // Get terminals, nonterminals and productions
- Symbol[] terminals = Symbol.terminals();
- Symbol[] nonterminals = Symbol.nonterminals();
- Production[] productions = Production.productions();
- // Initialize FOLLOW(A) to {}
- FOLLOW = new SymbolSet[nonterminals.length];
- for(int i = 0; i < nonterminals.length; i++)
- {
- FOLLOW[i] = new SymbolSet();
- }
- // Place eof in FOLLOW(S) where S is the start symbol.
- FOLLOW[startSymbol].setTerminal(eof);
- // If there is a production A->xBy, then everything in FIRST(y) except
- // for empty is placed in FOLLOW(B).
- for(int i = 0; i < productions.length; i++)
- {
- Symbol[] rightside = productions[i].rightside();
- for(int j = 0; j < rightside.length; j++)
- {
- if(!rightside[j].terminal)
- {
- SymbolSet set
- = FIRST(rightside, j + 1);
- set.clearEmpty();
- FOLLOW[rightside[j].index].or(set
- );
- }
- }
- }
- // If there is a production A->xB, or a production A->xBy where FIRST(y)
- // contains empty, then everything in FOLLOW(A) is in FOLLOW(B).
- boolean changed;
- do
- {
- changed = false;
- for(int i = 0; i < productions.length; i++)
- {
- Symbol[] rightside = productions[i].rightside();
- for(int j = 0; j < rightside.length; j++)
- {
- if(!rightside[j].terminal)
- {
- SymbolSet before =
- (SymbolSet) FOLLOW[rightside[j].index].clone();
- if(FIRST(rightside, j + 1).getEmpty())
- {
- FOLLOW[rightside[j].index].
- or(FOLLOW[productions[i].leftside]);
- }
- if(!before.equals(FOLLOW[rightside[j].index]))
- {
- changed = true;
- }
- }
- }
- }
- }
- while(changed);
- }
- static SymbolSet FOLLOW(int nonterminal)
- {
- return FOLLOW[nonterminal];
- }
- static LR0ItemSet CLOSURE(LR0Item item)
- {
- LR0ItemSet result = (LR0ItemSet) fastLr0Closure.get(item);
- if(result != null)
- {
- return result;
- }
- result = new LR0ItemSet();
- result.set(item);
- LR0ItemSet newItems = result;
- boolean modified;
- do
- {
- modified = false;
- LR0Item[] items = newItems.items();
- newItems = new LR0ItemSet();
- for(int i = 0; i < items.length; i++)
- {
- Production production = Production.production(items[i].production);
- Symbol[] rightside = production.rightside();
- if(items[i].position < rightside.length)
- {
- Symbol symbol = rightside[items[i].position];
- if(!symbol.terminal)
- {
- Production[] alternatives =
- Production.alternatives(symbol.index);
- for(int j = 0; j < alternatives.length; j++)
- {
- LR0Item newItem = new LR0Item(alternatives[j].index, 0);
- if(!result.get(newItem))
- {
- result.set(newItem);
- newItems.set(newItem);
- modified = true;
- }
- }
- }
- }
- }
- }
- while(modified);
- fastLr0Closure.put(item, result);
- return result;
- }
- // private static final SplayTreeMap fastLr0SetClosure = new SplayTreeMap();
- static LR0ItemSet CLOSURE(LR0ItemSet set
- )
- {
- LR0ItemSet result =
- /*
- (LR0ItemSet) fastLr0SetClosure.get(set);
- if(result != null)
- {
- return result;
- }
- result =*/
- new LR0ItemSet();
- LR0Item[] setItems = set.items();
- for(int i = 0; i < setItems.length; i++)
- {
- LR0Item[] items = CLOSURE(setItems[i]).items();
- for(int j = 0; j < items.length; j++)
- {
- result.set(items[j]);
- }
- }
- // fastLr0SetClosure.put(set, result);
- return result;
- }
- static LR1ItemSet CLOSURE(LR1Item item)
- {
- LR1ItemSet result = (LR1ItemSet) fastLr1Closure.get(item);
- if(result != null)
- {
- return result;
- }
- result = new LR1ItemSet();
- result.set(item);
- LR1ItemSet newItems = result;
- boolean modified;
- do
- {
- modified = false;
- LR1Item[] items = newItems.items();
- newItems = new LR1ItemSet();
- for(int i = 0; i < items.length; i++)
- {
- Production production = Production.production(items[i].lr0Item.production);
- Symbol[] rightside = production.rightside();
- if(items[i].lr0Item.position < rightside.length)
- {
- Symbol symbol = rightside[items[i].lr0Item.position];
- if(!symbol.terminal)
- {
- Vector tailVector = new Vector(0);
- for(int k = items[i].lr0Item.position + 1; k < rightside.length; k++)
- {
- tailVector.addElement(rightside[k]);
- }
- tailVector.addElement(Symbol.symbol(items[i].terminal, true));
- Symbol[] tail = new Symbol[tailVector.size()];
- tailVector.copyInto(tail);
- Symbol[] symbols = FIRST(tail).getSymbols();
- Production[] alternatives =
- Production.alternatives(symbol.index);
- for(int k = 0; k < symbols.length; k++)
- {
- if(symbols[k].terminal)
- {
- for(int j = 0; j < alternatives.length; j++)
- {
- LR1Item newItem = new LR1Item(
- new LR0Item(alternatives[j].index, 0),
- symbols[k].index);
- if(!result.get(newItem))
- {
- result.set(newItem);
- newItems.set(newItem);
- modified = true;
- }
- }
- }
- }
- }
- }
- }
- }
- while(modified);
- fastLr1Closure.put(item, result);
- return result;
- }
- // private static final SplayTreeMap fastLr1SetClosure = new SplayTreeMap();
- static LR1ItemSet CLOSURE(LR1ItemSet set
- )
- {
- LR1ItemSet result =
- /*
- (LR1ItemSet) fastLr1SetClosure.get(set);
- if(result != null)
- {
- return result;
- }
- result =*/
- new LR1ItemSet();
- LR1Item[] setItems = set.items();
- for(int i = 0; i < setItems.length; i++)
- {
- LR1Item[] items = CLOSURE(new LR1Item(setItems[i].lr0Item, dummy)).items();
- for(int j = 0; j < items.length; j++)
- {
- result.set(new LR1Item(items[j].lr0Item,
- items[j].terminal == dummy ? setItems[i].terminal : items[j].terminal));
- }
- }
- // fastLr1SetClosure.put(set, result);
- return result;
- }
- static LR0ItemSet GOTO(LR0ItemSet set
- , Symbol symbol)
- {
- LR0ItemSet initialset = set
- ;
- set
- = CLOSURE(set
- );
- LR0ItemSet result = new LR0ItemSet();
- // return all items A->xS.y such that A->x.Sy is in set. (S=symbol)
- LR0Item[] items = set.items();
- for(int i = 0; i < items.length; i++)
- {
- Production production = Production.production(items[i].production);
- Symbol[] rightside = production.rightside();
- if(items[i].position < rightside.length)
- {
- if(symbol.equals(rightside[items[i].position]))
- {
- result.set(new LR0Item(items[i].production,
- items[i].position + 1));
- }
- }
- }
- return result;
- }
- }