/* 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" + }