/* 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 . */ /* * Analyzer.java * * Created on February 25, 2008, 11:05 PM * * To change this template, choose Tools | Template Manager * and open the template in the editor. */ package lex; 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 Analyzer { public enum State { Start, StringConstant, IntegerConstant, RealConstant, VariableName } public State currentState; // maps from keyword in source to lexicalValue public HashMap keywords; // maps from operator in source to lexicalValue public HashMap operators; // maps from constant in source to sourceValue; the lexicalValue is "constant" public HashMap constants; // contains all white space characters public ArrayList whiteSpace; // the processed part of the source private ArrayList sourceTokens; // the source code private String source; // current position in the source private int currentIndex; // built-up string private StringBuilder buffer; /** Creates a new instance of Analyzer */ public Analyzer() { currentState = State.Start; this.initializeKeywords(); this.initializeOperators(); this.initializeConstants(); this.initializeWhiteSpace(); } private void initializeKeywords() { keywords = new HashMap(); keywords.put("=", "="); keywords.put(",", ","); keywords.put("input", "input"); keywords.put("initialize", "initialize"); keywords.put("as", "as"); keywords.put("if", "if"); keywords.put("then", "then"); keywords.put("else", "else"); keywords.put("endIf", "endIf"); keywords.put("while", "while"); keywords.put("endWhile", "endWhile"); keywords.put("forEach", "forEach"); keywords.put("in", "in"); keywords.put("next", "next"); keywords.put("return", "return"); keywords.put("function","function"); keywords.put("endFunction","endFunction"); keywords.put("call", "call"); keywords.put("say", "say"); keywords.put("true", "constant"); keywords.put("false", "constant"); keywords.put("finish", "finish"); keywords.put("and", "and"); keywords.put("or", "or"); keywords.put("ask", "ask"); keywords.put("*","*/"); keywords.put("/","*/"); keywords.put("%", "*/"); keywords.put("+","+-"); keywords.put("-","+-"); keywords.put("(","("); keywords.put(")",")"); keywords.put("!=", "relationalOperator"); keywords.put("==", "relationalOperator"); keywords.put(">","relationalOperator"); keywords.put("gt","relationalOperator"); keywords.put("gte","relationalOperator"); keywords.put("<","relationalOperator"); keywords.put("lt","relationalOperator"); keywords.put("lte","relationalOperator"); keywords.put(".","."); keywords.put(":", ":"); // newLine is most like an operator keywords.put("\n", "newLine"); } private void initializeOperators() { operators = new HashMap(); operators.put("*","*/"); operators.put("/","*/"); operators.put("%", "*/"); operators.put("+","+-"); operators.put("-","+-"); operators.put("(","("); operators.put(")",")"); operators.put("!=", "relationalOperator"); operators.put("==", "relationalOperator"); operators.put(">","relationalOperator"); operators.put("gt","relationalOperator"); operators.put("gte","relationalOperator"); operators.put("<","relationalOperator"); operators.put("lt","relationalOperator"); operators.put("lte","relationalOperator"); operators.put(".","."); operators.put(":", ":"); operators.put("call", "call"); // newLine is most like an operator operators.put("\n", "newLine"); operators.put("=", "="); operators.put(",", ","); operators.put("input", "input"); operators.put("initialize", "initialize"); operators.put("as", "as"); operators.put("if", "if"); operators.put("then", "then"); operators.put("else", "else"); operators.put("endIf", "endIf"); operators.put("while", "while"); operators.put("endWhile", "endWhile"); operators.put("forEach", "forEach"); operators.put("in", "in"); operators.put("next", "next"); operators.put("return", "return"); operators.put("function","function"); operators.put("endFunction","endFunction"); operators.put("say", "say"); operators.put("true", "constant"); operators.put("false", "constant"); operators.put("finish", "finish"); operators.put("or", "or"); operators.put("and", "and"); operators.put("ask", "ask"); } private void initializeConstants() { constants = new HashMap(); constants.put("PI", "3.1415"); constants.put("EXP", "2.71828"); } private void initializeWhiteSpace() { whiteSpace = new ArrayList(); whiteSpace.add(" "); whiteSpace.add("\t"); } public ArrayList analyzeSourceFile(String sourceFilePath) throws IOException { // open the source file BufferedReader br= new BufferedReader(new FileReader(sourceFilePath)); // read the source String source = readSourceFile(br); // close the source file br.close(); // analyze the source text ArrayList tokens = analyze(source); return tokens; } public ArrayList analyze(String sourceFilePath, String tokenFilePath) throws IOException { // open the source file BufferedReader br= new BufferedReader(new FileReader(sourceFilePath)); // read the source String source = readSourceFile(br); // close the source file br.close(); // analyze the source text ArrayList tokens = analyze(source); // open token file PrintWriter pw = new PrintWriter(new BufferedWriter(new FileWriter(tokenFilePath))); // write to the token file writeTokenFile(pw, tokens); // close the token file pw.close(); return tokens; } private String readSourceFile(BufferedReader br) throws IOException { StringBuilder str = new StringBuilder(); String line = br.readLine(); while(line != null) { if (line.length() > 0) { str.append(line); str.append("\n"); } line = br.readLine(); } str.append("\n"); return str.toString(); } private void writeTokenFile(PrintWriter pw, ArrayList tokens) throws IOException { // write each of the tokens to the file for(SourceToken token : tokens) { pw.println(token.toString()); } } public ArrayList analyze(String source) { // analyze the provided source this.source = source; // start at the beginning of the source this.currentIndex = 0; // reset the state this.currentState = State.Start; // clear memory buffer this.buffer = new StringBuilder(); // reset the source tokens sourceTokens = new ArrayList(); // and analyze while (this.currentIndex < source.length()) { analyze(); } // once finished analyzing, return the source tokens return sourceTokens; } private void analyze() { // find the current character String currentChar = String.valueOf(source.charAt(currentIndex)); // based on the current state, determine what to do switch(this.currentState) { case Start: start(currentChar); break; case StringConstant: stringConstant(currentChar); break; case IntegerConstant: integerConstant(currentChar); break; case RealConstant: realConstant(currentChar); break; case VariableName: variableName(currentChar); break; } } private void start(String c) { // if this is a control character, generate a source token if (operators.containsKey(c)) { generateSourceToken(operators.get(c), c); currentIndex++; } // if this is white space, then just skip this character else if (whiteSpace.contains(c)) { currentIndex++; } // if this is a double quote, then begin a string constant else if (c.equals("\"")) { // begin a string constant this.currentState = State.StringConstant; // advance to the next character currentIndex++; } // if this is a number, then begin a numeric constant else if (Character.isDigit(c.charAt(0))) { // add this to the buffer buffer.append(c); // begin an integer constant this.currentState = State.IntegerConstant; // advance to the next character currentIndex++; } // if this is a character, then begin a "variable" name // "variable" - else { // if (Character.isLetter(c.charAt(0))) { // add this to the buffer buffer.append(c); // begin a variableName constant this.currentState = State.VariableName; // advance to the next character currentIndex++; } /* // otherwise, just ignore this character else { // advance to the next character currentIndex++; } **/ } public void stringConstant(String c) { // end of the string constant? if (c.equals("\"")) { // create a source token for this string generateSourceToken("constant", this.buffer.toString()); // move to the next character currentIndex++; } // otherwise, add this character to the current string else { // append to the buffer this.buffer.append(c); // move to the next character currentIndex++; } } public void integerConstant(String c) { // is this a digit? if (Character.isDigit(c.charAt(0))) { // append to the buffer this.buffer.append(c); // move to the next character currentIndex++; } // is it a decimal? else if (c.equals(".")) { // append to the buffer this.buffer.append(c); // move to the Real Number state, since this has a decimal this.currentState = State.RealConstant; // move to the next character currentIndex++; } // otherwise, create a source token for the number in the buffer else { generateSourceToken("constant", this.buffer.toString()); // no need to advance; this could be a '*','+', etc. // the state is also set correctly } } public void realConstant(String c) { // is this a digit? if (Character.isDigit(c.charAt(0))) { // append to the buffer this.buffer.append(c); // move to the next character currentIndex++; } // otherwise, create a source token for the number in the buffer else { generateSourceToken("constant", this.buffer.toString()); // no need to advance; this could be a '*','+', etc. // the state is also set correctly } } public void variableName(String c) { // is this a character? if (Character.isLetter(c.charAt(0))) { // append to the buffer this.buffer.append(c); // move to the next character currentIndex++; } // is this a digit? else if (Character.isDigit(c.charAt(0))) { // append to the buffer this.buffer.append(c); // move to the next character currentIndex++; } // otherwise, create a source token else { String word = this.buffer.toString(); // special case - '!=' if (word.equals("!") && c.equals("=")) { generateSourceToken("relationalOperator", "!="); // also need to advance currentIndex++; } else if (keywords.containsKey(word)) { // check to see if this is a keyword generateSourceToken(keywords.get(word), word); } else { generateSourceToken("variableName", word); } // no need to advance // the state is also set correctly } } /*Start, StringConstant, IntegerConstant, RealConstant, Word;*/ private void generateSourceToken(String lexicalValue, String sourceValue) { // make sure not to actually set the source value to a new line // because it inserts newlines into the file if (sourceValue.equals("\n")) { lexicalValue = "nl"; sourceValue = SourceToken.NewLine; } SourceToken t = new SourceToken(lexicalValue, sourceValue); sourceTokens.add(t); // also, clear the buffer this.buffer = new StringBuilder(); // move to the start state this.currentState = State.Start; // stay at the same index, so don't advance the counter // no need to do anything else } }