/* 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); } }