/* * 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.lexical; import java.io.IOException; import org.ourgrid.common.specification.CodesTable; import org.ourgrid.common.specification.CompilerMessages; import org.ourgrid.common.specification.SpecialCharException; import org.ourgrid.common.specification.TokenDelimiter; import org.ourgrid.common.specification.io.CharReader; import org.ourgrid.common.specification.token.Operator; import org.ourgrid.common.specification.token.Parenthetic; import org.ourgrid.common.specification.token.Pointing; import org.ourgrid.common.specification.token.StringToken; import org.ourgrid.common.specification.token.Token; /** * This is a Common Lexical Analyzer. It means that it implements the * LexicalAnalyzer interface in a simple way. */ public class CommonLexicalAnalyzer implements LexicalAnalyzer { /** * Logger to store log messages */ private static transient final org.apache.log4j.Logger LOG = org.apache.log4j.Logger .getLogger( CommonLexicalAnalyzer.class ); private CharReader charReader; private boolean findEOF = false; private String readingSource; /** * The CommonLexicalAnalyzer constructor. * * @param sourceFile - is the String that defines where is the file with the * source to be analyzed. */ public CommonLexicalAnalyzer( String sourceFile ) throws LexicalException { this.readingSource = sourceFile; try { charReader = new CharReader( sourceFile ); } catch ( IOException ioex ) { LOG.error( "Unable to read " + sourceFile + ". Cause: " + ioex.getMessage() ); throw new LexicalException( CompilerMessages.LEXICAL_READING_SOURCE_PROBLEM( sourceFile, ioex.getMessage() ), ioex ); } } /** * @see org.ourgrid.common.specification.lexical.LexicalAnalyzer#getToken() */ public Token getToken() throws LexicalException { Token token = new Token(); try { if ( findEOF ) { token = null; } else { char nextNonBlankChar = charReader.readNonBlankChar(); while ( isComment( nextNonBlankChar ) ) { charReader.readLine(); nextNonBlankChar = charReader.readNonBlankChar(); } if ( nextNonBlankChar == CharReader.EOF_CHAR ) { findEOF = true; token = new Token( "\\n", 0, charReader.getActualLine() ); } else if ( nextNonBlankChar == '\n' ) { token = new Token( "\\n", 0, charReader.getActualLine() ); } else { /* * There is no way to previous know the difference between a * pure string and a special word. Thats why we here try to * read a string and the string will check if it is or not a * special type as: operator or a terminal symbol! More then * this, here, to read a StringToken, we check if the next * char is a letter, or if the character is not on the * CodesTable, because if it is then it have to be treated * by the other object types. */ if ( Character.isLetterOrDigit( nextNonBlankChar ) || CodesTable.getInstance().getCode( "" + nextNonBlankChar ) == 0 ) { Operator operator = new Operator(); if ( operator.readOperator( nextNonBlankChar, charReader ) != null ) { token = operator; } else { nextNonBlankChar = charReader.readNonBlankChar(); StringToken string = new StringToken(); token = string.readStringToken( "" + nextNonBlankChar, charReader ); } } else { Pointing pointing = new Pointing(); if ( pointing.readPointing( nextNonBlankChar, charReader ) != null ) { token = pointing; } else { Parenthetic parenthetic = new Parenthetic(); if ( parenthetic.readParantizer( nextNonBlankChar, charReader ) != null ) { token = parenthetic; } else { Operator operator = new Operator(); if ( operator.readOperator( nextNonBlankChar, charReader ) != null ) { token = operator; } else { throw new LexicalException( CompilerMessages.LEXICAL_FATAL_TOKEN_NOT_RECOGNIZED ); } } } } } } return token; } catch ( IOException ioex ) { throw new LexicalException( CompilerMessages.LEXICAL_READING_SOURCE_PROBLEM( this.readingSource, ioex .getMessage() ), ioex ); } } /** * @see org.ourgrid.common.specification.lexical.LexicalAnalyzer#getToken(TokenDelimiter) */ public Token getToken( TokenDelimiter delimiters ) throws LexicalException { StringToken toReturn = new StringToken(); try { Token token = toReturn.readString( this.charReader, delimiters ); return token; } catch ( IOException ioex ) { throw new LexicalException( CompilerMessages.LEXICAL_READING_SOURCE_PROBLEM( this.readingSource, ioex .getMessage() ), ioex ); } catch ( SpecialCharException scex ) { throw new LexicalException( CompilerMessages.LEXICAL_READING_SOURCE_PROBLEM( this.readingSource, scex .getMessage() ), scex ); } } /** * Will test if the line is a comment line * * @param nextNonBlankChar the char that could initialize a comment line. * @return true if the line is a comment and false otherwise. */ private boolean isComment( char nextNonBlankChar ) { if ( nextNonBlankChar == '#' ) { return true; } return false; } }