/*
PseudoCode Interpreted Language (PCIL): Part of the algoviz@vt collection of algorithm visualizations.
Copyright (C) 2008 Brandon Malone, Frank Hadlock
This file is part of the PseudoCode Interpreted Language.
PseudoCode Interpreted Language is free software: you can redistribute
it and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of the License,
or (at your option) any later version.
PseudoCode Interpreted Language is distributed in the hope that it will
be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
Public License for more details.
You should have received a copy of the GNU General Public License along with
PseudoCode Interpreted Language. If not, see
.
*/
/*
* FirstCalculator.java
*
* Created on March 3, 2008, 12:33 AM
*
* To change this template, choose Tools | Template Manager
* and open the template in the editor.
*/
package syntacticanalysis;
import java.util.ArrayList;
import java.util.HashMap;
/**
*
* @author Brandon
*/
public class FirstCalculator {
/** Creates a new instance of FirstCalculator */
public FirstCalculator() {
}
/**
* attempt to add a given string to the first of a specified nonteminal
*/
private static boolean addToFirst(GrammarToken X, ArrayList toAdd, HashMap> first) {
if (toAdd == null) {
return false;
}
if (X instanceof ActionSymbol) {
return false;
}
// first, go ahead and retrieve First(X)
ArrayList firstX = first.get(X);
// note if any additions are made to First(X)
boolean added = false;
for (GrammarToken curr : toAdd) {
/* ignore action symbols */
if(curr instanceof ActionSymbol) {
continue;
}
// is it already in First(X)
if (!firstX.contains(curr)) {
firstX.add(curr);
added = true;
}
}
// let the caller know if anything was added
return added;
}
/**
* follow the algorithms to construct the first table for the
* grammar that was read in.
**/
public static void constructFirsts(Grammar grammar) {
ArrayList rules = grammar.getRules();
ArrayList terminals = grammar.getTerminals();
ArrayList nonterminals = grammar.getNonterminals();
grammar.first = new HashMap> ();
boolean keepGoing = true;
for(Terminal terminal : terminals) {
ArrayList firstSet = new ArrayList();
firstSet.add(terminal);
grammar.first.put(terminal, firstSet);
}
for(Nonterminal nonterminal : nonterminals) {
ArrayList firstSet = new ArrayList();
grammar.first.put(nonterminal, firstSet);
}
// loop through the rules until no additions occur over an entire pass
do {
keepGoing = false;
for (int i=0; i X1Xn = rule.getRhs();
/**
* now, beginning with X1, add First(Xi) to First(X)
* until First(Xi) does not contain the empty string.
*/
boolean canBeLambda = true;
for(int j=0; j firstXi = grammar.first.get(Xi);
if (Xi instanceof ActionSymbol) {
// just assume action symbols can go to empty string
firstXi = new ArrayList();
firstXi.add(new Terminal("#"));
}
//System.out.println(firstXi);
// add it to First(X)
if (addToFirst(X, firstXi, grammar.first)) {
keepGoing = true;
}
// can Xi be lambda
if (firstXi.contains(new Terminal("#"))) {
canBeLambda = true;
// at the end of the rule?
if (j == X1Xn.size()-1){
ArrayList lambdaFirstSet = new ArrayList();
lambdaFirstSet.add(new Terminal("#"));
addToFirst(X, lambdaFirstSet, grammar.first);
}
}
}
}
} while (keepGoing);
}
}