/*
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
.
*/
/*
* Grammar.java
*
* Created on March 2, 2008, 7:17 PM
*
* To change this template, choose Tools | Template Manager
* and open the template in the editor.
*/
package syntacticanalysis;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
/**
*
* @author Brandon
*/
public class Grammar {
// grammar consists of a start symbol
private GrammarToken startSymbol; // list of rules
private ArrayList rules; // terminals
private ArrayList terminals; // nonterminals
private ArrayList nonterminals; // action symbols
private ArrayList actionSymbols;
HashMap> first;
HashMap> follow;
ArrayList> rulesSignature;
HashMap parseTable;
public static Grammar createFromFile() throws IOException {
Grammar g = new Grammar(grammarString);
FirstCalculator.constructFirsts(g);
FollowCalculator.constructFollows(g);
SignatureCalculator.constructSignatures(g);
ParseTableCalculator.constructParseTable(g);
return g;
}
public static Grammar createFromFile(String grammarFilePath) throws IOException {
// open the source file
BufferedReader br = new BufferedReader(new FileReader(grammarFilePath));
// read the grammar file
String grammar = readFile(br);
Grammar g = new Grammar(grammar);
// close the source file
br.close();
FirstCalculator.constructFirsts(g);
FollowCalculator.constructFollows(g);
SignatureCalculator.constructSignatures(g);
ParseTableCalculator.constructParseTable(g);
return g;
}
public static Grammar createFromFile(String grammarFilePath, String parseTablePath) throws IOException {
Grammar g = createFromFile(grammarFilePath);
BufferedReader br = new BufferedReader(new FileReader(parseTablePath));
// read the parseTable file
String parseTable = readFile(br);
br.close();
g.setParseTable(parseTable);
return g;
}
public static String readFile(BufferedReader br) throws IOException {
StringBuilder sb = new StringBuilder();
String line = br.readLine();
while (line != null) {
sb.append(line);
sb.append("\n");
line = br.readLine();
}
return sb.toString();
}
/** Creates a new instance of Grammar */
public Grammar(String grammar) {
setRules(new ArrayList());
setNonterminals(new ArrayList());
setTerminals(new ArrayList());
setActionSymbols(new ArrayList());
// find the start state
StringBuilder g = new StringBuilder();
g.append(grammar);
setStartState(g);
while (g.length() > 0) {
findRule(g);
}
for (GrammarRule rule : rules) {
checkRule(rule);
}
}
private void setStartState(StringBuilder grammar) {
// the first line should be: "StartState: "
int start = grammar.indexOf("<");
int end = grammar.indexOf(">");
String startName = grammar.substring(start + 1, end);
setStartSymbol(new Nonterminal(startName));
// strip off the line
// also grab the new line
grammar.replace(0, end + 2, "");
}
private void findRule(StringBuilder grammar) {
// assume each rule is on a line
int index = grammar.indexOf("\n");
String rule = grammar.substring(0, index);
if (rule.startsWith("<")) {
getRules().add(new GrammarRule(rule));
} else {
boolean br = true;
}
// add one to also remove the new line
grammar.replace(0, index + 1, "");
}
private void checkRule(GrammarRule rule) {
// check the lhs
if (!getNonterminals().contains(rule.getLhs())) {
getNonterminals().add(rule.getLhs());
}
// check the rhs
for (GrammarToken t : rule.getRhs()) {
if (t instanceof Terminal) {
if (!getTerminals().contains(t)) {
getTerminals().add((Terminal) t);
}
}
if (t instanceof Nonterminal) {
if (!getNonterminals().contains(t)) {
getNonterminals().add((Nonterminal) t);
}
}
if (t instanceof ActionSymbol) {
if (!getActionSymbols().contains(t)) {
getActionSymbols().add((ActionSymbol) t);
}
}
}
}
public void setParseTable(String parseTable) {
this.setParseTable(new HashMap());
StringBuilder sb = new StringBuilder();
sb.append(parseTable);
// assume of the form: ~[input]~0
int index = sb.indexOf("\n");
while (index > -1) {
// read the next parse entry
String line = sb.substring(0, index);
ParseEntry parseEntry = new ParseEntry(line);
// find the rule
GrammarRule rule = getRules().get(parseEntry.getRuleIndex());
// add to the parse table
this.getParseTable().put(parseEntry, rule);
// strip off the entry
sb.replace(0, index + 1, "");
index = sb.indexOf("\n");
}
}
public GrammarRule determineRule(Nonterminal sententialFormToken, Terminal sourceToken) {
ParseEntry entry = new ParseEntry(sourceToken, sententialFormToken);
GrammarRule r = getParseTable().get(entry);
// HACK FIX
if (r == null && sourceToken.name.equals("=")) {
// try changing the type to [relationalOperator]
sourceToken.name = "relationalOperator";
entry = new ParseEntry(sourceToken, sententialFormToken);
r = getParseTable().get(entry);
}
return r;
}
public void toFile(String filePath) throws IOException {
PrintWriter pw = new PrintWriter(new BufferedWriter(new FileWriter(filePath)));
pw.print(toString());
pw.close();
}
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("Start State:");
sb.append(getStartSymbol().toString());
sb.append("\n");
for (GrammarRule rule : rules) {
sb.append(rule.toString());
sb.append("\n");
}
return sb.toString();
}
public void parseTableToFile(String filePath) throws IOException {
PrintWriter pw = new PrintWriter(new BufferedWriter(new FileWriter(filePath)));
pw.print(parseTableToString());
pw.close();
}
public String parseTableToString() {
StringBuilder sb = new StringBuilder();
for (ParseEntry entry : getParseTable().keySet()) {
sb.append(entry.toString());
sb.append("\n");
}
return sb.toString();
}
public GrammarToken getStartSymbol() {
return startSymbol;
}
public void setStartSymbol(GrammarToken startSymbol) {
this.startSymbol = startSymbol;
}
public ArrayList getRules() {
return rules;
}
public void setRules(ArrayList rules) {
this.rules = rules;
}
public ArrayList getTerminals() {
return terminals;
}
public void setTerminals(ArrayList terminals) {
this.terminals = terminals;
}
public ArrayList getNonterminals() {
return nonterminals;
}
public void setNonterminals(ArrayList nonterminals) {
this.nonterminals = nonterminals;
}
public ArrayList getActionSymbols() {
return actionSymbols;
}
public void setActionSymbols(ArrayList actionSymbols) {
this.actionSymbols = actionSymbols;
}
public HashMap getParseTable() {
return parseTable;
}
public void setParseTable(HashMap parseTable) {
this.parseTable = parseTable;
}
protected static String grammarString = "Start Symbol:\n" +
"->{24}{26}\n" +
"->[#]\n" +
"->[nl]{1}{27}\n" +
"->[input][=]{2}\n" +
"->[variableName][variableName]{3}\n" +
"->[#]\n" +
"->[,]{1}\n" +
"->\n" +
"->[nl]{1}{24}\n" +
"->[#]\n" +
"->\n" +
"->\n" +
"->\n" +
"->\n" +
"->\n" +
"->\n" +
"->\n" +
"->\n" +
"->\n" +
"->\n" +
"->[initialize]{1}\n" +
"->[variableName][as][variableName]{4}\n" +
"->[,]{1}\n" +
"->[#]\n" +
"->{22}[=]{5}\n" +
"->[if][then][nl]{6}{24}\n" +
"->[else][nl]{7}{24}[endIf]{1}{31}\n" +
"->[endIf]{1}{31}\n" +
"->{39}[while]{40}[nl]{8}{24}[endWhile]{41}{9}\n" +
"->{30}[forEach][variableName][in]{32}[nl]{10}{29}{24}[next]{11}\n" +
"->[call]{22}{28}\n" +
"->[return]{21}\n" +
"->[say][(][)]{25}\n" +
"->[finish]{1}{33}\n" +
"->[ask][:]{38}\n" +
"->\n" +
"->{22}\n" +
"->[#]\n" +
"->[*/]{12}\n" +
"->\n" +
"->[(]{1}[)]{36}\n" +
"->[#]\n" +
"->[+-]{13}\n" +
"->[#]\n" +
"->[or]{34}\n" +
"->[and]{35}\n" +
"->[relationalOperator]{14}\n" +
"->[variableName]{15}\n" +
"->[constant]{23}\n" +
"->[#]{16}\n" +
"->[.]{17}\n" +
"->[(][)]{18}\n" +
"->\n" +
"->[#]\n" +
"->[#]\n" +
"->[,]\n" +
"->[nl]\n" +
"->[#]\n" +
"->\n" +
"->[function][variableName][(]{19}[)][nl]{20}{24}[endFunction]\n" +
"->[variableName][variableName]\n" +
"->[,]\n" +
"->[#]\n" +
"->[#]\n";
//"->[ask][:]{38}{37}\n" +
}