/*
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
.
*/
/*
* FollowCalculator.java
*
* Created on March 3, 2008, 1:06 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 FollowCalculator {
/** Creates a new instance of FollowCalculator */
public FollowCalculator() {
}
/**
* attempt to add a given string to the follow of a specified nonteminal
*/
private static boolean addToFollow(GrammarToken X, ArrayList toAdd, HashMap> follow) {
if (toAdd == null) {
return false;
}
if (X instanceof ActionSymbol) {
return false;
}
// first, go ahead and retrieve Follow(X)
ArrayList followX = follow.get(X);
// note if any additions are made to Follow(X)
boolean added = false;
for(GrammarToken curr : toAdd) {
if(curr instanceof ActionSymbol) {
continue;
}
// is it already in Follow(X)
if (!followX.contains(curr)) {
// add it if it isn't
followX.add(curr);
added = true;
}
}
// let the caller know if anything was added
return added;
}
/**
* construct the follow tables for the language.
**/
public static void constructFollows(Grammar grammar) {
ArrayList rules = grammar.getRules();
ArrayList terminals = grammar.getTerminals();
ArrayList nonterminals = grammar.getNonterminals();
grammar.follow = new HashMap> ();
boolean keepGoing = true;
for(Nonterminal nonterminal : nonterminals) {
ArrayList followSet = new ArrayList();
grammar.follow.put(nonterminal, followSet);
}
/* make sure to add $ to follow(s) */
ArrayList endOfSourceFollowSet = new ArrayList();
endOfSourceFollowSet.add(new Terminal("$"));
addToFollow(grammar.getStartSymbol(), endOfSourceFollowSet, grammar.follow);
/* loop through the rules until no new additions occur over an entire pass */
do {
keepGoing = false;
for(int i=0; i rhs = rule.getRhs();
for(int j=0; j= rhs.size()) {
needToCheck = false;
break;
}
nextChar = rhs.get(j + counter);
}
}
if (needToCheck) {
/* then this was not the last symbol in this rule */
ArrayList toAdd = grammar.first.get(nextChar);
/* make sure we actually added something */
if (addToFollow(curr, toAdd, grammar.follow) ) {
keepGoing = true;
}
} else {
/* so it must be the last symbol in the rule, so add follow(lhs) to follow(rhs) */
GrammarToken lhs = rule.getLhs();
ArrayList toAdd = grammar.follow.get(lhs);
if (addToFollow(curr, toAdd, grammar.follow) ) {
keepGoing = true;
}
}
}
/* so it must be the last symbol in the rule, so add follow(lhs) to follow(rhs) */
else {
GrammarToken lhs = rule.getLhs();
ArrayList toAdd = grammar.follow.get(lhs);
if (addToFollow(curr, toAdd, grammar.follow) ) {
keepGoing = true;
}
}
/* can everything after this go to # */
boolean add = true;
boolean notLast=false;
for(int k=j+1;k nextFirst = grammar.first.get(nextChar);
if (!nextFirst.contains(new Terminal("#"))) {
add = false;
break;
}
}
/* add follow(lhs) to follow(rhs) */
if (add && notLast) {
/* find follow(lhs) */
ArrayList followLhs = grammar.follow.get(rule.getLhs());
/* add it to follow(rhs) */
if (addToFollow(curr, followLhs, grammar.follow)) {
keepGoing=true;
}
}
} // end if (nonterminal)
} // end for each character in the rhs
} // end for each rule
} while (keepGoing);
}
}