/* * 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.syntactical; import org.ourgrid.common.specification.CodesTable; import org.ourgrid.common.specification.CompilerMessages; import org.ourgrid.common.specification.TokenDelimiter; 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.lexical.LexicalAnalyzer; import org.ourgrid.common.specification.lexical.LexicalException; import org.ourgrid.common.specification.semantic.SemanticAnalyzer; import org.ourgrid.common.specification.semantic.exception.SemanticException; import org.ourgrid.common.specification.token.Token; /** * @see org.ourgrid.common.specification.syntactical.SyntacticalDerivationTree Created on * 21/05/2004 */ public class CommonSyntacticalAnalyzer implements SyntacticalAnalyzer { private static transient final org.apache.log4j.Logger LOG = org.apache.log4j.Logger .getLogger( CommonSyntacticalAnalyzer.class ); private LexicalAnalyzer lexical; private Grammar grammar; private SyntacticalDerivationTree sdt; private SemanticAnalyzer semantic; private CodesTable codesTable; private Token token; private Symbol actualSymbol; public static final int MODE_NORMAL = 0; public static final int MODE_READLINE = 1; public static final int MODE_READSTRING = 2; /** * The constructor. * * @param lexical A lexical analyzer from where will be gotten the tokens * from source. * @param grammar The grammar entity that knows validat the language * sources. * @param semantic A semantic analyzer that will handle the execution of the * semantic actions found as special token at grammar. */ public CommonSyntacticalAnalyzer( LexicalAnalyzer lexical, Grammar grammar, SemanticAnalyzer semantic ) { this.lexical = lexical; this.grammar = grammar; this.semantic = null; this.codesTable = CodesTable.getInstance(); this.sdt = new SyntacticalDerivationTree( grammar.getEndOfSourceSymbol(), grammar.getInitialSymbol() ); this.semantic = semantic; } /** * @see org.ourgrid.common.specification.syntactical.SyntacticalAnalyzer#startCompilation() */ public void startCompilation() throws SyntacticalException { try { this.token = lexical.getToken(); while ( !sdt.top().equals( grammar.getEndOfSourceSymbol() ) ) { if ( !sdt.top().equals( Symbol.EMPTY ) && !sdt.top().isSemanticAction() ) { this.actualSymbol = this.getSymbolFromToken(); } if ( sdt.top().isTerminal() ) { // will check if the stack top and actual symbol are equals checkSymbolsState(); } else if ( sdt.top().isSemanticAction() ) { executeSemanticAction(); } else { // sdt.top is a non terminal symbol! prepareRuleToFollow(); } } } catch ( LexicalException lex ) { throw new SyntacticalException( lex.getMessage(), lex ); } catch ( SemanticException sex ) { throw new SyntacticalException( sex.getMessage(), sex ); } } /* * Checks if the terminal symbol at the stack top and the symbol from source * are equals. @throws LexicalException @throws SyntacticalException */ private void checkSymbolsState() throws SyntacticalException, SemanticException { if ( actualSymbol.equals( sdt.top() ) ) { sdt.pop(); getNewToken(); } else if ( sdt.top().equals( Symbol.EMPTY ) ) { sdt.pop(); } else { LOG.error( "The stack top and the next symbol should be equals." ); throw new SyntacticalException( CompilerMessages.SYNTACTICAL_COMPILATION_PROBLEM( token, sdt.top() .getValue() ) ); } } /* * It will call the functions of the lexical module checking before wich one * is more adequated on the actual situation. @throws SyntacticalException * Wraps a lexical exception occured when getting a token from the lexical * analyzer. */ private void getNewToken() throws SyntacticalException, SemanticException { while ( sdt.top().isSemanticAction() ) this.executeSemanticAction(); int operationalMode = this.semantic.getOperationMode(); try { if ( operationalMode == MODE_NORMAL ) token = lexical.getToken(); else if ( operationalMode == MODE_READSTRING ) { TokenDelimiter delim = new TokenDelimiter(); delim.addDelimiter( '\n' ); delim.addDelimiter( ' ' ); delim.addDelimiter( '\t' ); token = lexical.getToken( delim ); } else if ( operationalMode == MODE_READLINE ) { TokenDelimiter delim = new TokenDelimiter(); delim.addDelimiter( '\n' ); token = lexical.getToken( delim ); } } catch ( LexicalException lex ) { throw new SyntacticalException( lex.getMessage(), lex ); } } /* * Will search for a rule to follow based at the informations of the symbol * at the stack top and the last token read. @throws SyntacticalException If * any rule to follow was not found. */ private void prepareRuleToFollow() throws SyntacticalException, SemanticException { Rule toFollow = grammar.getRule( sdt.top(), actualSymbol ); if ( toFollow != null ) { // will push the body of the rule at stack sdt.pop(); sdt.pushRule( toFollow ); } else if ( actualSymbol.getValue().equals( "\\n" ) ) { // If did not // found a rule // but the // actual token // is a // end-of-line // symbol getNewToken(); } else { LOG.error( "The stack top and the next symbol are non_terminal and should find a rule to follow." ); throw new SyntacticalException( CompilerMessages.SYNTACTICAL_COMPILATION_PROBLEM( token, sdt.top() .getValue() ) ); } } /* * Will execute the semantic action at the top of the stack. @throws * SemanticException If it could not execute the semantic action. */ private void executeSemanticAction() throws SemanticException { Symbol action = sdt.pop(); semantic.performAction( action.getValue(), token ); } /* * Will get the right symbol from a token. It means that if it is necessary * it will "transform" the token to the right symbol. */ private Symbol getSymbolFromToken() { if ( token == null ) { return Symbol.EOF; } Symbol toReturn = grammar.getSymbol( token.getSymbol() ); if ( toReturn != null ) { grammar.getRule( sdt.top(), toReturn ); codesTable.getType( token.getSymbol() ); } else { toReturn = grammar.getSymbol( CodesTable.STRING ); } return toReturn; } }