/* * Copyright (C) 2008 Universidade Federal de Campina Grande * * This file is part of OurGrid. * * OurGrid is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) * any later version. * * This program 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 Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * */ package org.ourgrid.common.specification.grammar.io; import java.io.BufferedReader; import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.Iterator; import java.util.StringTokenizer; import java.util.Vector; import org.ourgrid.common.specification.grammar.Grammar; import org.ourgrid.common.specification.grammar.Rule; import org.ourgrid.common.specification.grammar.Symbol; import org.ourgrid.common.specification.grammar.exception.InvalidRuleException; /** * This is a GrammarReader entity that knows how to read a file generated by the * Gals software (version 2003.10.03) * * @see Gals - http://sourceforge.net/projects/gals/ */ public class GalsGrammarReader implements GrammarReader { /** * This symbol is the one that is recognized as the empty rule at the * grammar description language. In this case is the GALS grammar * description language. */ private final String NULL_SYMBOL = "" + '@'; // OBS.: This symbols was modified because we have got problems using the // original '?' symbol. // Theses problems are related with the codifications at the remote machines // that do not support // this symbol... then, to use our grammars into GALS, change this symbol. private BufferedReader reader; private Grammar grammar; private int ruleCounter; private int symbolCounter; /** * @see org.ourgrid.common.specification.grammar.io.GrammarReader#read(java.io.File, * org.ourgrid.common.specification.grammar.Grammar) */ public Grammar read( File grammarFile, Grammar toFillGrammar ) throws MalformedGrammarException, FileNotFoundException, IOException { this.reader = new BufferedReader( new FileReader( grammarFile ) ); buildGrammar( toFillGrammar ); return this.grammar; } /** * @see org.ourgrid.common.specification.grammar.io.GrammarReader#read(java.io.InputStream, * org.ourgrid.common.specification.grammar.Grammar) */ public Grammar read( InputStream stream, Grammar toFillGrammar ) throws MalformedGrammarException, FileNotFoundException, IOException { this.reader = new BufferedReader( new InputStreamReader( stream ) ); buildGrammar( toFillGrammar ); return this.grammar; } /** * @param toFillGrammar The grammar object to be filled with the read * informations * @throws IOException * @throws MalformedGrammarException */ private void buildGrammar( Grammar toFillGrammar ) throws IOException, MalformedGrammarException { this.grammar = toFillGrammar; this.ruleCounter = 0; this.symbolCounter = 0; this.getGrammar(); } /** * Changes the grammar passed as paramether for the read() method. It will * fill up the grammar with the information read from the file. * * @throws MalformedGrammarException */ private void getGrammar() throws IOException, MalformedGrammarException { String actualLine = null; StringBuffer buffer = null; actualLine = this.readNonBlankLine(); if ( actualLine != null ) { buffer = new StringBuffer( actualLine ); String blockName = (buffer.substring( 1 )).trim(); // First Block of needed informatin from the Gals grammar // description file. while ( !blockName.equals( "Tokens" ) && !blockName.equals( "" ) ) { blockName = this.getNextBlockName(); } blockName = this.getTerminalInformations(); // Second Block of needed informatin from the Gals grammar // description file. blockName = this.getNonTerminalInformations(); // Third Block of needed informatin from the Gals grammar // description file. this.getRulesInformations(); } else { throw new MalformedGrammarException( "The grammar file is empty." ); } } /** * Will read the informations from the grammar block and insert the * necessary ones at the grammar. * * @throws MalformedGrammarException */ private void getRulesInformations() throws IOException, MalformedGrammarException { String line = this.readNonBlankLine(); while ( line != null ) { StringTokenizer headAndBodies = new StringTokenizer( line, " " ); String headStr = headAndBodies.nextToken().trim(); Symbol head = this.createSymbol( ++this.symbolCounter, headStr, Symbol.NON_TERMINAL ); if ( headAndBodies.nextToken().equals( "::=" ) ) { Vector<Symbol> bodyVector = new Vector<Symbol>(); String symbolStr = ""; while ( head != null ) { if ( headAndBodies.hasMoreTokens() ) { symbolStr = headAndBodies.nextToken().trim(); } else { // the line ended and was not found a ";" // symbol. It is necessary to get next line headAndBodies = this.getNextNonEmptyTokenizer(); symbolStr = headAndBodies.nextToken().trim(); } if ( symbolStr.equals( "|" ) ) { // Time to close a rule // with the actual head // and bodyVector createAndDeployRule( ++ruleCounter, head, bodyVector ); bodyVector = new Vector<Symbol>(); } else { if ( symbolStr.equals( ";" ) ) { // Time to eliminate // the actual head createAndDeployRule( ++ruleCounter, head, bodyVector ); bodyVector = new Vector<Symbol>(); head = null; } else { // Read another symbol from token and add it // at bodyVector Symbol symbol; if ( symbolStr.charAt( 0 ) == '<' ) { symbol = this.createSymbol( ++this.symbolCounter, symbolStr, Symbol.NON_TERMINAL ); } else if ( symbolStr.charAt( 0 ) == '#' ) { String action = symbolStr.trim(); symbol = new Symbol( Integer.MAX_VALUE, action, Symbol.SEMANTIC_ACTION ); } else { symbol = this.createSymbol( ++this.symbolCounter, symbolStr, Symbol.TERMINAL ); } bodyVector.add( symbol ); } } } } else { // Error situation throw new MalformedGrammarException( "There is a rule without a head or the symbol \"::=\" was forgot." ); } line = this.readNonBlankLine(); } } private String readNonBlankLine() throws IOException { String line = ""; do { line = reader.readLine(); if ( line == null ) break; } while ( line.equals( "" ) ); return line; } /* * Search for the next line non empty and returns a StringTokenizer of this * line. */ private StringTokenizer getNextNonEmptyTokenizer() throws IOException { String line = this.readNonBlankLine(); return new StringTokenizer( line, " " ); } private Symbol createSymbol( int code, String value, int type ) { // If the value is in format "xxx" will eliminate the " symbols int last = value.length() - 1; if ( value.charAt( 0 ) == '\"' && value.charAt( last ) == '\"' ) { StringBuffer buffer = new StringBuffer( value ); value = buffer.substring( 1, last ); } Symbol toTest = grammar.getSymbol( value ); if ( toTest == null ) { if ( value.equals( this.NULL_SYMBOL ) ) { toTest = Symbol.EMPTY; } else { toTest = new Symbol( code, value, type ); } } else { --symbolCounter; } return toTest; } /* * Creates a rule and add it at the grammar. */ private void createAndDeployRule( int codeCounter, Symbol head, Vector<Symbol> bodyVector ) throws MalformedGrammarException { try { Rule rule = new Rule( codeCounter, head, getArrayOfSymbols( bodyVector ) ); this.grammar.addRule( rule ); } catch ( InvalidRuleException irex ) { Iterator<Symbol> it = bodyVector.iterator(); String rule = head.getValue() + " ::= "; while ( it.hasNext() ) rule = rule + (it.next()).getValue(); throw new MalformedGrammarException( "Found a MalFormed rule : " + rule, irex ); } } /* * Transform a vector os Symbol objects in a array cointaining them. */ private Symbol[ ] getArrayOfSymbols( Vector<Symbol> vec ) { Symbol[ ] toReturn = new Symbol[ vec.size() ]; Iterator<Symbol> it = vec.iterator(); int counter = 0; while ( it.hasNext() ) { toReturn[counter++] = it.next(); } return toReturn; } /** * Will read the informations from the non terminals block and insert the * necessaries ones at the grammar. * * @return The last line read from the file. The empty string if occurres * any problem. */ private String getNonTerminalInformations() throws IOException { String newSymbol = this.readNonBlankLine(); while ( newSymbol.charAt( 0 ) != '#' ) { Symbol symbol = this.createSymbol( ++this.symbolCounter, newSymbol.trim(), Symbol.NON_TERMINAL ); this.grammar.addSymbol( symbol ); newSymbol = this.readNonBlankLine(); } StringBuffer buffer = new StringBuffer( newSymbol ); return buffer.substring( 1 ); } /** * Will read the informations from the tokens block and insert the * necessaries ones at the grammar. * * @return The last line read from the file. The empty string if occurres * any problem. */ private String getTerminalInformations() throws IOException { String newSymbol = this.readNonBlankLine(); while ( newSymbol.charAt( 0 ) != '#' ) { Symbol symbol = this.createSymbol( ++this.symbolCounter, newSymbol.trim(), Symbol.TERMINAL ); this.grammar.addSymbol( symbol ); newSymbol = this.readNonBlankLine(); } StringBuffer buffer = new StringBuffer( newSymbol ); return buffer.substring( 1 ); } /** * Will try to find another line that begins with the '#' symbol. * * @return The name of the next block if it was found, and the empty string * if not. * @throws MalformedGrammarException if the EOF was found */ private String getNextBlockName() throws IOException, MalformedGrammarException { String line = ""; do { line = reader.readLine(); if ( line != null ) { // Test if this line is empty because of the index above. if ( !line.equals( "" ) ) { if ( line.charAt( 0 ) == '#' ) { StringBuffer buffer = new StringBuffer( line ); return buffer.substring( 1 ).trim(); } } } } while ( line != null ); throw new MalformedGrammarException( "The grammar have not all the informations block necessaries." ); } }