/*
* 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;
}
}