/* * This file or a portion of this file is licensed under the terms of * the Globus Toolkit Public License, found in file GTPL, or at * http://www.globus.org/toolkit/download/license.html. This notice must * appear in redistributions of this file, with or without modification. * * Redistributions of this Software, with or without modification, must * reproduce the GTPL in: (1) the Software, or (2) the Documentation or * some other similar material which is provided with the Software (if * any). * * Copyright 1999-2004 University of Chicago and The University of * Southern California. All rights reserved. */ package org.griphyn.vdl.parser; import org.griphyn.vdl.classes.*; import org.griphyn.vdl.util.Logging; import java.io.Reader; import java.io.IOException; import java.util.Collection; import java.util.ArrayList; /** * Parses the input stream and generates pool configuration map as * output. * * @author Jens-S. Vöckler * @author Yong Zhao * @version $Revision$ * * @see VDLtScanner * @see VDLtToken */ public class VDLtParser { /** * The access to the lexical scanner is stored here. */ private VDLtScanner m_scanner = null; /** * Stores the look-ahead symbol. */ private VDLtToken m_lookAhead = null; /** * Initializes the parser with an input stream to read from. * @param r is the stream opened for reading. */ public VDLtParser( java.io.Reader r ) throws IOException, VDLtException { m_scanner = new VDLtScanner(r); m_lookAhead = m_scanner.nextToken(); } protected LFN lfn() throws IOException, VDLtException { if ( ! (m_lookAhead instanceof VDLtAt) ) throw new VDLtParserException( m_scanner, "An LFN must start with an at symbol" ); m_lookAhead = m_scanner.nextToken(); if ( ! (m_lookAhead instanceof VDLtOpenBrace) ) throw new VDLtParserException( m_scanner, "An LFN has a brace after the at symbol" ); m_lookAhead = m_scanner.nextToken(); if ( ! (m_lookAhead instanceof VDLtIdentifier) ) throw new VDLtParserException( m_scanner, "An LFN uses a direction identifier as first component" ); int direction = -1; String id = ((VDLtIdentifier) m_lookAhead).getValue(); if ( id.compareTo("in")==0 || id.compareTo("input")==0 ) { direction = LFN.INPUT; m_lookAhead = m_scanner.nextToken(); } else if ( id.compareTo("out")==0 || id.compareTo("output")==0 ) { direction = LFN.OUTPUT; m_lookAhead = m_scanner.nextToken(); } else if ( id.compareTo("io")==0 || id.compareTo("inout")==0 ) { direction = LFN.INOUT; m_lookAhead = m_scanner.nextToken(); } else if ( id.compareTo("none")==0 ) { direction = LFN.NONE; m_lookAhead = m_scanner.nextToken(); } else { // no keyword given throw new VDLtParserException( m_scanner, "A LFN needs to specify a direction" ); } if ( ! (m_lookAhead instanceof VDLtColon) ) throw new VDLtParserException( m_scanner, "An LFN separates the filename with a colon from the direction" ); m_lookAhead = m_scanner.nextToken(); if ( ! (m_lookAhead instanceof VDLtQuotedString) ) throw new VDLtParserException( m_scanner, "The filename of an LFN is a quoted string" ); id = ((VDLtQuotedString) m_lookAhead).getValue(); m_lookAhead = m_scanner.nextToken(); // check for temporary hint String hint = null; if ( m_lookAhead instanceof VDLtColon ) { m_lookAhead = m_scanner.nextToken(); if ( ! (m_lookAhead instanceof VDLtQuotedString) ) throw new VDLtParserException( m_scanner, "The temporary template of an LFN is a quoted string" ); hint = ((VDLtQuotedString) m_lookAhead).getValue(); m_lookAhead = m_scanner.nextToken(); } // check for (possibly empty) special section String rt = null; if ( m_lookAhead instanceof VDLtVBar ) { m_lookAhead = m_scanner.nextToken(); if ( m_lookAhead instanceof VDLtIdentifier ) { rt = ((VDLtIdentifier) m_lookAhead).getValue(); m_lookAhead = m_scanner.nextToken(); } else if ( m_lookAhead instanceof VDLtCloseBrace ) { // empty section rt = new String(); } else { throw new VDLtParserException( m_scanner, "The LFN \"" + id + "\" has an invalid rt specification" ); } } // check for correct termination if ( ! (m_lookAhead instanceof VDLtCloseBrace) ) throw new VDLtParserException( m_scanner, "The LFN \"" + id + "\" is not terminated correctly" ); m_lookAhead = m_scanner.nextToken(); if ( rt == null ) { // backward compatibility. The constructor does the "right thing": // if hint is null, the rt will be false // if hint is not null, the rt will both be true return new LFN( id, direction, hint ); } else { // new format, just do the full kit boolean no_t = ( rt.indexOf('t') == -1 ); boolean no_T = ( rt.indexOf('T') == -1 ); return new LFN( id, direction, hint, // if "r" is present, do register rt.indexOf('r') == -1, // if "t" is present, do transfer // if "T" is present, optional transfer no_t ? ( no_T ? LFN.XFER_NOT : LFN.XFER_OPTIONAL ) : LFN.XFER_MANDATORY, rt.indexOf('o') != -1 ); } } protected Use use() throws IOException, VDLtException { Use result = new Use(); if ( (m_lookAhead instanceof VDLtDollar) ) { m_lookAhead = m_scanner.nextToken(); if ( ! (m_lookAhead instanceof VDLtOpenBrace) ) throw new VDLtParserException( m_scanner, "An bound var has a brace after the dollar" ); m_lookAhead = m_scanner.nextToken(); if ( m_lookAhead instanceof VDLtQuotedString ) { // rendering supplied String temp = ((VDLtQuotedString) m_lookAhead).getValue(); m_lookAhead = m_scanner.nextToken(); if ( m_lookAhead instanceof VDLtColon ) { // triple supplied result.setPrefix(temp); m_lookAhead = m_scanner.nextToken(); if ( ! (m_lookAhead instanceof VDLtQuotedString) ) throw new VDLtParserException( m_scanner, "The rending information is \"prefix\":\"separator\":\"suffix\"" ); result.setSeparator( ((VDLtQuotedString) m_lookAhead).getValue() ); m_lookAhead = m_scanner.nextToken(); if ( ! (m_lookAhead instanceof VDLtColon) ) throw new VDLtParserException( m_scanner, "The rending information is \"prefix\":\"separator\":\"suffix\"" ); m_lookAhead = m_scanner.nextToken(); if ( ! (m_lookAhead instanceof VDLtQuotedString) ) throw new VDLtParserException( m_scanner, "The rending information is \"prefix\":\"separator\":\"suffix\"" ); result.setSuffix( ((VDLtQuotedString) m_lookAhead).getValue() ); m_lookAhead = m_scanner.nextToken(); if ( ! (m_lookAhead instanceof VDLtVBar) ) throw new VDLtParserException( m_scanner, "The rending information is separated by a bar from the bound variable" ); m_lookAhead = m_scanner.nextToken(); } else if ( m_lookAhead instanceof VDLtVBar ) { // just a separator result.setSeparator(temp); m_lookAhead = m_scanner.nextToken(); } else throw new VDLtParserException( m_scanner, "The rending information for the bound variable is wrong" ); } if ( ! (m_lookAhead instanceof VDLtIdentifier) ) throw new VDLtParserException( m_scanner, "An bound var has an optional direction or the identifier" ); String id = ((VDLtIdentifier) m_lookAhead).getValue(); if ( id.compareTo("in")==0 || id.compareTo("input")==0 ) { result.setLink(LFN.INPUT); m_lookAhead = m_scanner.nextToken(); } else if ( id.compareTo("out")==0 || id.compareTo("output")==0 ) { result.setLink(LFN.OUTPUT); m_lookAhead = m_scanner.nextToken(); } else if ( id.compareTo("io")==0 || id.compareTo("inout")==0 ) { result.setLink(LFN.INOUT); m_lookAhead = m_scanner.nextToken(); } else if ( id.compareTo("none")==0 ) { result.setLink(LFN.NONE); m_lookAhead = m_scanner.nextToken(); } if ( result.getLink() != -1 ) { if ( ! (m_lookAhead instanceof VDLtColon) ) throw new VDLtParserException( m_scanner, "A colon separates the direction from the identifier" ); m_lookAhead = m_scanner.nextToken(); } if ( ! (m_lookAhead instanceof VDLtIdentifier) ) throw new VDLtParserException( m_scanner, "The bound variable must be named as identifier" ); result.setName( ((VDLtIdentifier) m_lookAhead).getValue() ); m_lookAhead = m_scanner.nextToken(); if ( ! (m_lookAhead instanceof VDLtCloseBrace) ) throw new VDLtParserException( m_scanner, "The bound var " + result.getName() + " is not terminated by a closing brace" ); m_lookAhead = m_scanner.nextToken(); } else if ( (m_lookAhead instanceof VDLtOpenParenthesis) ) { // // abbreviated form 1, using a type-cast: (inout) var // m_lookAhead = m_scanner.nextToken(); if ( ! (m_lookAhead instanceof VDLtIdentifier) ) throw new VDLtParserException( m_scanner, "An bound var has an optional direction or the identifier" ); String id = ((VDLtIdentifier) m_lookAhead).getValue(); if ( id.compareTo("in")==0 || id.compareTo("input")==0 ) { result.setLink(LFN.INPUT); m_lookAhead = m_scanner.nextToken(); } else if ( id.compareTo("out")==0 || id.compareTo("output")==0 ) { result.setLink(LFN.OUTPUT); m_lookAhead = m_scanner.nextToken(); } else if ( id.compareTo("io")==0 || id.compareTo("inout")==0 ) { result.setLink(LFN.INOUT); m_lookAhead = m_scanner.nextToken(); } else if ( id.compareTo("none")==0 ) { result.setLink(LFN.NONE); m_lookAhead = m_scanner.nextToken(); } if ( result.getLink() != -1 ) { if ( ! (m_lookAhead instanceof VDLtCloseParenthesis) ) throw new VDLtParserException( m_scanner, "A closeing parenthesis finished the type-cast" ); m_lookAhead = m_scanner.nextToken(); } if ( ! (m_lookAhead instanceof VDLtIdentifier) ) throw new VDLtParserException( m_scanner, "The bound variable must be named as identifier" ); result.setName( ((VDLtIdentifier) m_lookAhead).getValue() ); m_lookAhead = m_scanner.nextToken(); } else if ( (m_lookAhead instanceof VDLtIdentifier) ) { // // abbreviated form 2: justvar // result.setName( ((VDLtIdentifier) m_lookAhead).getValue() ); m_lookAhead = m_scanner.nextToken(); } else { throw new VDLtParserException( m_scanner, "An bound variable starts with a dollar, type-cast or identifier" ); } return result; } protected Text text() throws IOException, VDLtException { if ( m_lookAhead instanceof VDLtQuotedString ) { Text result = new Text( ((VDLtQuotedString) m_lookAhead).getValue() ); m_lookAhead = m_scanner.nextToken(); return result; } else throw new VDLtParserException( m_scanner, "expecting a quoted string" ); } protected Leaf tr_leaf() throws IOException, VDLtException { if ( m_lookAhead instanceof VDLtQuotedString ) return text(); else if ( (m_lookAhead instanceof VDLtDollar) || (m_lookAhead instanceof VDLtOpenParenthesis) || (m_lookAhead instanceof VDLtIdentifier) ) return use(); else throw new VDLtParserException( m_scanner, "the value is neither a quoted string nor a valid bound variable" ); } protected Scalar dv_leaf() throws IOException, VDLtException { if ( m_lookAhead instanceof VDLtQuotedString ) return new Scalar( text() ); else if ( m_lookAhead instanceof VDLtAt ) return new Scalar( lfn() ); else throw new VDLtParserException( m_scanner, "the value is neither a quoted string nor a valid LFN" ); } /** * internal function to parse a profile inside a TR body. * @return a memory representation of a profile instance. * @exception IOException if the reading from the stream fails, * @exception VDLtParserException if the parser detects a syntax error, * @exception VDLtScannerException if the scanner detects a lexical error. */ protected Profile profile() throws IOException, VDLtException { if ( ! (m_lookAhead instanceof VDLtIdentifier) && ((VDLtIdentifier) m_lookAhead).getValue().toLowerCase().compareTo("profile") != 0 ) throw new VDLtParserException( m_scanner, "Expecting keyword \"profile\"" ); m_lookAhead = m_scanner.nextToken(); if ( ! (m_lookAhead instanceof VDLtIdentifier) ) throw new VDLtParserException( m_scanner, "The profile needs a profile namespace first" ); String namespace = ((VDLtIdentifier) m_lookAhead).getValue(); m_lookAhead = m_scanner.nextToken(); String name = null; int p1 = namespace.indexOf('.'); int p2 = namespace.indexOf(".."); if ( p1 >= 0 && p1 < namespace.length() ) { // read as one token what are three // Logging.instance().log( "default", 0, "Line " + m_scanner.getLineNumber() + // ": Please use :: instead of . in profile " + namespace ); name = namespace.substring(p1+1); namespace = namespace.substring(0,p1).toLowerCase(); } else if ( p2 >= 0 && p2 < namespace.length() ) { // read as one token what are three name = namespace.substring(p2+2); namespace = namespace.substring(0,p2).toLowerCase(); } else { namespace = namespace.toLowerCase(); // read remaining tokens if ( ! (m_lookAhead instanceof VDLtPeriod || m_lookAhead instanceof VDLtDoubleColon) ) throw new VDLtParserException( m_scanner, "The profile namespace is separated by a . or :: from the profile key" ); // if ( m_lookAhead instanceof VDLtPeriod ) // Logging.instance().log( "default", 0, "Line " + m_scanner.getLineNumber() + // ": Please use :: instead of . in profile" ); m_lookAhead = m_scanner.nextToken(); if ( ! (m_lookAhead instanceof VDLtIdentifier) ) throw new VDLtParserException( m_scanner, "The profile requires a name (key)" ); name = ((VDLtIdentifier) m_lookAhead).getValue(); m_lookAhead = m_scanner.nextToken(); } if ( ! (m_lookAhead instanceof VDLtEquals) ) throw new VDLtParserException( m_scanner, "The profile value is separated by an equals from the key" ); m_lookAhead = m_scanner.nextToken(); Collection children = new ArrayList(); do { children.add( tr_leaf() ); } while ( ! (m_lookAhead instanceof VDLtSemicolon) ); return new Profile( namespace, name, children ); } /** * internal function to parse a <code>argument</code> line. * @return a memory representation of an TR argument. * @exception IOException if the reading from the stream fails, * @exception VDLtParserException if the parser detects a syntax error, * @exception VDLtScannerException if the scanner detects a lexical error. */ protected Argument argument() throws IOException, VDLtException { Argument result = new Argument(); if ( ! (m_lookAhead instanceof VDLtIdentifier) && ((VDLtIdentifier) m_lookAhead).getValue().toLowerCase().compareTo("argument") != 0 ) throw new VDLtParserException( m_scanner, "Expecting keyword \"argument\"" ); m_lookAhead = m_scanner.nextToken(); if ( (m_lookAhead instanceof VDLtIdentifier) ) { // optional identifier, only used for streams result.setName( ((VDLtIdentifier) m_lookAhead).getValue() ); m_lookAhead = m_scanner.nextToken(); } if ( ! (m_lookAhead instanceof VDLtEquals) ) throw new VDLtParserException( m_scanner, "The argument value is separated by an equals from the argument" ); m_lookAhead = m_scanner.nextToken(); do { result.addLeaf( tr_leaf() ); } while ( ! (m_lookAhead instanceof VDLtSemicolon) ); return result; } /** * internal function to parse a call inside a compound TR. * @return an actual argument list as used by the <code>call</code> statement. * @exception IOException if the reading from the stream fails, * @exception VDLtParserException if the parser detects a syntax error, * @exception VDLtScannerException if the scanner detects a lexical error. */ protected Pass carg() throws IOException, VDLtException { if ( ! (m_lookAhead instanceof VDLtIdentifier) ) throw new VDLtParserException( m_scanner, "Expecting an identifier in call arguments" ); Pass result = new Pass( ((VDLtIdentifier) m_lookAhead).getValue() ); m_lookAhead = m_scanner.nextToken(); if ( ! (m_lookAhead instanceof VDLtEquals) ) throw new VDLtParserException( m_scanner, "Missing equals sign after call arg identifier" ); m_lookAhead = m_scanner.nextToken(); if ( m_lookAhead instanceof VDLtOpenBracket ) { // list value m_lookAhead = m_scanner.nextToken(); List list = new List(); while ( ! (m_lookAhead instanceof VDLtCloseBracket) ) { list.addScalar( new Scalar(tr_leaf()) ); if ( m_lookAhead instanceof VDLtComma ) m_lookAhead = m_scanner.nextToken(); } // reached only for closing bracket m_lookAhead = m_scanner.nextToken(); result.setValue( list ); } else { // scalar value result.setValue( new Scalar(tr_leaf()) ); } return result; } /** * internal function to parse a call inside a compound TR. * @return a memory representation of a call instance. * @exception IOException if the reading from the stream fails, * @exception VDLtParserException if the parser detects a syntax error, * @exception VDLtScannerException if the scanner detects a lexical error. */ protected Call call() throws IOException, VDLtException { if ( ! (m_lookAhead instanceof VDLtIdentifier) && ((VDLtIdentifier) m_lookAhead).getValue().toLowerCase().compareTo("call") != 0 ) throw new VDLtParserException( m_scanner, "Expecting keyword \"call\"" ); m_lookAhead = m_scanner.nextToken(); VDLtFQDN tr = trmap(); Call result = new Call( tr.getValue(1), tr.getValue(2), tr.getValue(3) ); result.setUsesspace( tr.getValue(0) ); // // actual call argument list // if ( ! (m_lookAhead instanceof VDLtOpenParenthesis) ) throw new VDLtParserException( m_scanner, "expecting an open parenthesis after the call mapping" ); m_lookAhead = m_scanner.nextToken(); while ( ! (m_lookAhead instanceof VDLtCloseParenthesis) ) { result.addPass( carg() ); if ( m_lookAhead instanceof VDLtComma ) { m_lookAhead = m_scanner.nextToken(); if ( ! (m_lookAhead instanceof VDLtIdentifier) ) throw new VDLtParserException( m_scanner, "expecting more arguments after the comma" ); } } // reach this only with a closing parenthesis m_lookAhead = m_scanner.nextToken(); return result; } /** * internal function to parse formal arguments employed by a TR. * @return a single formal argument * @exception IOException if the reading from the stream fails, * @exception VDLtParserException if the parser detects a syntax error, * @exception VDLtScannerException if the scanner detects a lexical error. */ protected Declare farg() throws IOException, VDLtException { if ( ! (m_lookAhead instanceof VDLtIdentifier) ) throw new VDLtParserException( m_scanner, "expecting a direction or an identifier" ); int direction = -1; String id = ((VDLtIdentifier) m_lookAhead).getValue().toLowerCase(); if ( id.compareTo("in")==0 || id.compareTo("input")==0 ) { direction = LFN.INPUT; m_lookAhead = m_scanner.nextToken(); } else if ( id.compareTo("out")==0 || id.compareTo("output")==0 ) { direction = LFN.OUTPUT; m_lookAhead = m_scanner.nextToken(); } else if ( id.compareTo("io")==0 || id.compareTo("inout")==0 ) { direction = LFN.INOUT; m_lookAhead = m_scanner.nextToken(); } else if ( id.compareTo("none")==0 ) { direction = LFN.NONE; m_lookAhead = m_scanner.nextToken(); } else { // no keyword given, assume none direction = LFN.NONE; } if ( m_lookAhead instanceof VDLtOpenBracket ) // common error I frequently commit myself throw new VDLtParserException( m_scanner, "[] not permitted after type" ); else if ( ! (m_lookAhead instanceof VDLtIdentifier) ) // otherwise erraneous throw new VDLtParserException( m_scanner, "expecting an identifier" ); id = ((VDLtIdentifier) m_lookAhead).getValue(); m_lookAhead = m_scanner.nextToken(); int containerType = -1; if ( m_lookAhead instanceof VDLtOpenBracket ) { // list container m_lookAhead = m_scanner.nextToken(); if ( ! (m_lookAhead instanceof VDLtCloseBracket) ) throw new VDLtParserException(m_scanner, "expecting a closing bracket after the open bracket"); else m_lookAhead = m_scanner.nextToken(); containerType = Value.LIST; } else { containerType = Value.SCALAR; } Declare result = new Declare( id, containerType, direction ); if ( m_lookAhead instanceof VDLtEquals ) { // there is a default value associated with the variable m_lookAhead = m_scanner.nextToken(); if ( containerType == Value.SCALAR ) { // scalar default result.setValue( dv_leaf() ); } else { // list default within brackets List list = new List(); if ( ! (m_lookAhead instanceof VDLtOpenBracket) ) throw new VDLtParserException( m_scanner, "expecting an opening bracket for vector default values" ); m_lookAhead = m_scanner.nextToken(); while ( ! (m_lookAhead instanceof VDLtCloseBracket) ) { list.addScalar( dv_leaf() ); if ( m_lookAhead instanceof VDLtComma ) m_lookAhead = m_scanner.nextToken(); } // reach this only with a closing bracket m_lookAhead = m_scanner.nextToken(); result.setValue( list ); } } return result; } /** * internal function to parse temporary variables employed n a TR. * @return a single formal argument * @exception IOException if the reading from the stream fails, * @exception VDLtParserException if the parser detects a syntax error, * @exception VDLtScannerException if the scanner detects a lexical error. */ protected Local targ() throws IOException, VDLtException { if ( ! (m_lookAhead instanceof VDLtIdentifier) ) throw new VDLtParserException( m_scanner, "expecting a direction or an identifier" ); int direction = -1; String id = ((VDLtIdentifier) m_lookAhead).getValue().toLowerCase(); if ( id.compareTo("in")==0 || id.compareTo("input")==0 ) { direction = LFN.INPUT; m_lookAhead = m_scanner.nextToken(); } else if ( id.compareTo("out")==0 || id.compareTo("output")==0 ) { direction = LFN.OUTPUT; m_lookAhead = m_scanner.nextToken(); } else if ( id.compareTo("io")==0 || id.compareTo("inout")==0 ) { direction = LFN.INOUT; m_lookAhead = m_scanner.nextToken(); } else if ( id.compareTo("none")==0 ) { direction = LFN.NONE; m_lookAhead = m_scanner.nextToken(); } else { // no keyword given, assume none direction = LFN.NONE; } if ( ! (m_lookAhead instanceof VDLtIdentifier) ) throw new VDLtParserException( m_scanner, "expecting an identifier" ); id = ((VDLtIdentifier) m_lookAhead).getValue(); m_lookAhead = m_scanner.nextToken(); int containerType = -1; if ( m_lookAhead instanceof VDLtOpenBracket ) { // list container m_lookAhead = m_scanner.nextToken(); if ( ! (m_lookAhead instanceof VDLtCloseBracket) ) throw new VDLtParserException(m_scanner, "expecting a closing bracket after the open bracket"); else m_lookAhead = m_scanner.nextToken(); containerType = Value.LIST; } else { containerType = Value.SCALAR; } // local variables must have a value to be bound at Local result = new Local( id, containerType, direction ); if ( ! (m_lookAhead instanceof VDLtEquals) ) throw new VDLtParserException( m_scanner, "expecting an equal sign" ); m_lookAhead = m_scanner.nextToken(); if ( containerType == Value.SCALAR ) { // scalar default result.setValue( dv_leaf() ); } else { // list default within brackets List list = new List(); if ( ! (m_lookAhead instanceof VDLtOpenBracket) ) throw new VDLtParserException( m_scanner, "expecting an opening bracket for vector default values" ); m_lookAhead = m_scanner.nextToken(); while ( ! (m_lookAhead instanceof VDLtCloseBracket) ) { list.addScalar( dv_leaf() ); if ( m_lookAhead instanceof VDLtComma ) m_lookAhead = m_scanner.nextToken(); } // reach this only with a closing bracket m_lookAhead = m_scanner.nextToken(); result.setValue( list ); } return result; } /** * internal function to parse actual arguments employed by a DV. * @return a single actual argument. * @exception IOException if the reading from the stream fails, * @exception VDLtParserException if the parser detects a syntax error, * @exception VDLtScannerException if the scanner detects a lexical error. */ protected Pass aarg() throws IOException, VDLtException { if ( ! (m_lookAhead instanceof VDLtIdentifier) ) throw new VDLtParserException( m_scanner, "Expecting an identifier in actual arguments" ); Pass result = new Pass( ((VDLtIdentifier) m_lookAhead).getValue() ); m_lookAhead = m_scanner.nextToken(); if ( ! (m_lookAhead instanceof VDLtEquals) ) throw new VDLtParserException( m_scanner, "Missing equals sign after actual arg identifier" ); m_lookAhead = m_scanner.nextToken(); if ( m_lookAhead instanceof VDLtOpenBracket ) { // list value m_lookAhead = m_scanner.nextToken(); List list = new List(); while ( ! (m_lookAhead instanceof VDLtCloseBracket) ) { list.addScalar( dv_leaf() ); if ( m_lookAhead instanceof VDLtComma ) m_lookAhead = m_scanner.nextToken(); } // reached only for closing bracket m_lookAhead = m_scanner.nextToken(); result.setValue( list ); } else { // scalar value result.setValue( dv_leaf() ); } return result; } /** * internal function to parse the fully-qualified definition identifier * into memory. This is the name of a TR or DV. * @return a parsed fully-qualified identifier. * @exception IOException if the reading from the stream fails, * @exception VDLtParserException if the parser detects a syntax error, * @exception VDLtScannerException if the scanner detects a lexical error. */ protected VDLtFQDN fqdn() throws IOException, VDLtException { VDLtFQDN result = new VDLtFQDN(); if ( ! (m_lookAhead instanceof VDLtIdentifier) ) throw new VDLtParserException( m_scanner, "A FQDN starts with an identifier" ); String temp = ((VDLtIdentifier) m_lookAhead).getValue(); m_lookAhead = m_scanner.nextToken(); if ( m_lookAhead instanceof VDLtDoubleColon ) { // first part was the namespace m_lookAhead = m_scanner.nextToken(); result.setValue( 0, temp ); if ( ! (m_lookAhead instanceof VDLtIdentifier) ) throw new VDLtParserException( m_scanner, "Expecting more identifiers after a double colon" ); temp = ((VDLtIdentifier) m_lookAhead).getValue(); m_lookAhead = m_scanner.nextToken(); } // set name (mandatory part) result.setValue( 1, temp ); if ( m_lookAhead instanceof VDLtColon ) { m_lookAhead = m_scanner.nextToken(); if ( ! (m_lookAhead instanceof VDLtIdentifier) ) throw new VDLtParserException( m_scanner, "Expecting a version identifier" ); temp = ((VDLtIdentifier) m_lookAhead).getValue(); m_lookAhead = m_scanner.nextToken(); result.setValue( 2, temp ); } return result; } /** * internal function to parse the part after the arrow operator into * memory. It is also used for calls in compound transformations.<p> * On popular demand, the syntax slightly changed to be more permissive * with version maps. The following short-cuts are permitted: * * * @return a parsed mapping to a transformation. * @exception IOException if the reading from the stream fails, * @exception VDLtParserException if the parser detects a syntax error, * @exception VDLtScannerException if the scanner detects a lexical error. */ protected VDLtFQDN trmap() throws IOException, VDLtException { VDLtFQDN result = new VDLtFQDN(); if ( ! (m_lookAhead instanceof VDLtIdentifier) ) throw new VDLtParserException( m_scanner, "A TR mapping starts with an identifier" ); String temp = ((VDLtIdentifier) m_lookAhead).getValue(); m_lookAhead = m_scanner.nextToken(); if ( m_lookAhead instanceof VDLtDoubleColon ) { // first part was the namespace m_lookAhead = m_scanner.nextToken(); result.setValue( 0, temp ); if ( ! (m_lookAhead instanceof VDLtIdentifier) ) throw new VDLtParserException( m_scanner, "Expecting more identifiers after a double colon" ); temp = ((VDLtIdentifier) m_lookAhead).getValue(); m_lookAhead = m_scanner.nextToken(); } // set name (mandatory part) result.setValue( 1, temp ); // :min, // :,max // :min,max // NEW :same // if ( m_lookAhead instanceof VDLtColon ) { // min and max versions as identifiers m_lookAhead = m_scanner.nextToken(); if ( m_lookAhead instanceof VDLtIdentifier ) { // min version String minimum = ((VDLtIdentifier) m_lookAhead).getValue(); result.setValue( 2, minimum ); m_lookAhead = m_scanner.nextToken(); // NEW branch -- same version for both if ( m_lookAhead instanceof VDLtOpenParenthesis ) { result.setValue( 3, minimum ); return result; } } if ( ! (m_lookAhead instanceof VDLtComma) ) throw new VDLtParserException( m_scanner, "Expecting a comma between min and max version" ); m_lookAhead = m_scanner.nextToken(); if ( m_lookAhead instanceof VDLtIdentifier ) { // max version result.setValue( 3, ((VDLtIdentifier) m_lookAhead).getValue() ); m_lookAhead = m_scanner.nextToken(); } else if ( ! (m_lookAhead instanceof VDLtOpenParenthesis) ) throw new VDLtParserException( m_scanner, "Excepting a max version after the comma" ); } return result; } /** * internal function to parse a complete transformation. * @return a derivation in memory * @exception IOException if the reading from the stream fails, * @exception VDLtParserException if the parser detects a syntax error, * @exception VDLtScannerException if the scanner detects a lexical error. */ protected Derivation derivation() throws IOException, VDLtException { Derivation result = new Derivation(); VDLtFQDN id = fqdn(); result.setNamespace( id.getValue(0) ); result.setName( id.getValue(1) ); result.setVersion( id.getValue(2) ); if ( ! (m_lookAhead instanceof VDLtArrow) ) throw new VDLtParserException( m_scanner, "Expecting the map operator (arrow)" ); m_lookAhead = m_scanner.nextToken(); id = trmap(); result.setUsesspace( id.getValue(0) ); result.setUses( id.getValue(1) ); result.setMinIncludeVersion( id.getValue(2) ); result.setMaxIncludeVersion( id.getValue(3) ); // // actual argument list // if ( ! (m_lookAhead instanceof VDLtOpenParenthesis) ) throw new VDLtParserException( m_scanner, "expecting an open parenthesis to start actual argument list" ); m_lookAhead = m_scanner.nextToken(); while ( ! (m_lookAhead instanceof VDLtCloseParenthesis) ) { result.addPass( aarg() ); if ( m_lookAhead instanceof VDLtComma ) { m_lookAhead = m_scanner.nextToken(); if ( ! (m_lookAhead instanceof VDLtIdentifier) ) throw new VDLtParserException( m_scanner, "expecting more arguments after the comma" ); } } // reach this only with a closing parenthesis m_lookAhead = m_scanner.nextToken(); if ( ! (m_lookAhead instanceof VDLtSemicolon) ) throw new VDLtParserException( m_scanner, "expecting a semicolon to terminate a DV" ); m_lookAhead = m_scanner.nextToken(); return result; } /** * internal function to parse a complete transformation. * @return a transformation in memory * @exception IOException if the reading from the stream fails, * @exception VDLtParserException if the parser detects a syntax error, * @exception VDLtScannerException if the scanner detects a lexical error. */ protected Transformation transformation() throws IOException, VDLtException { Transformation result = new Transformation(); VDLtFQDN id = fqdn(); result.setNamespace( id.getValue(0) ); result.setName( id.getValue(1) ); result.setVersion( id.getValue(2) ); // // formal argument list // if ( ! (m_lookAhead instanceof VDLtOpenParenthesis) ) throw new VDLtParserException( m_scanner, "expecting an open parenthesis after the TR identifier" ); m_lookAhead = m_scanner.nextToken(); while ( ! (m_lookAhead instanceof VDLtCloseParenthesis) ) { result.addDeclare( farg() ); if ( m_lookAhead instanceof VDLtComma ) { m_lookAhead = m_scanner.nextToken(); if ( ! (m_lookAhead instanceof VDLtIdentifier) ) throw new VDLtParserException( m_scanner, "expecting more formal arguments after the comma" ); } } // reach this only with a closing parenthesis m_lookAhead = m_scanner.nextToken(); // // transformation body // if ( ! (m_lookAhead instanceof VDLtOpenBrace) && ! (m_lookAhead instanceof VDLtSemicolon) ) throw new VDLtParserException( m_scanner, "expecting the TR body" ); if ( m_lookAhead instanceof VDLtOpenBrace ) { // regular transformation body, skip brace m_lookAhead = m_scanner.nextToken(); while ( ! (m_lookAhead instanceof VDLtCloseBrace) ) { if ( ! (m_lookAhead instanceof VDLtIdentifier) ) throw new VDLtParserException( m_scanner, "expecting \"profile\", \"call\", \"argument\", or " + "a temporary variable declaration inside TR body" ); String var = ((VDLtIdentifier) m_lookAhead).getValue().toLowerCase(); if ( var.compareTo( "argument" )==0 ) { result.addArgument( argument() ); } else if ( var.compareTo("call")==0 ) { result.addCall( call() ); } else if ( var.compareTo("profile")==0 ) { result.addProfile( profile() ); } else { // throw new VDLtParserException( m_scanner, // "\"" + var + "\" is not a valid keyword for a TR body" ); result.addLocal( targ() ); } if ( m_lookAhead instanceof VDLtSemicolon ) m_lookAhead = m_scanner.nextToken(); } // reach this only with a closing brace m_lookAhead = m_scanner.nextToken(); } else { // transformation without a body, skip semicolon m_lookAhead = m_scanner.nextToken(); } return result; } /** * Parses the a single definition from the input stream and * returns just the definition. The piece-by-piece parsing * allows for a more memory-efficient parsing process of * large input streams. * @return a Definition structure for one TR or DV * @exception IOException if the reading from the stream fails, * @exception VDLtParserException if the parser detects a syntax error, * @exception VDLtScannerException if the scanner detects a lexical error. * @see #parse() * @see #hasMoreTokens() */ public Definition parseDefinition() throws IOException, VDLtException { if ( ! (m_lookAhead instanceof VDLtDefinition) ) throw new VDLtParserException( m_scanner, "expecting DV or TR" ); if ( m_lookAhead instanceof VDLtDerivation ) { // DV will be more frequently encountered, thus check first m_lookAhead = m_scanner.nextToken(); return derivation(); } else if ( m_lookAhead instanceof VDLtTransformation ) { // TR will not be as often m_lookAhead = m_scanner.nextToken(); return transformation(); } else { // this should not happen throw new VDLtParserException( m_scanner, "unknown definition" ); } } /** * Predicate to determine, if there are more Definition instances * to be read. * @return true, if there are potentially more tokens in the stream. * @exception IOException if the reading from the stream fails, * @exception VDLtParserException if the parser detects a syntax error, * @exception VDLtScannerException if the scanner detects a lexical error. */ public boolean hasMoreTokens() throws IOException, VDLtException { return m_scanner.hasMoreTokens(); } /** * Parses the complete input stream. This method will construct * the complete stream as Definitions in memory. It will gobble * a lot of memory for large input. * @return the Definitions in one structure * @exception IOException if the reading from the stream fails, * @exception VDLtParserException if the parser detects a syntax error, * @exception VDLtScannerException if the scanner detects a lexical error. * @see #parseDefinition() */ public Definitions parse() throws IOException, VDLtException { Definitions result = new Definitions(); do { if ( m_lookAhead != null ) result.addDefinition( parseDefinition() ); } while ( m_scanner.hasMoreTokens() ); return result; } }