0001: /*
0002: * This file or a portion of this file is licensed under the terms of
0003: * the Globus Toolkit Public License, found in file GTPL, or at
0004: * http://www.globus.org/toolkit/download/license.html. This notice must
0005: * appear in redistributions of this file, with or without modification.
0006: *
0007: * Redistributions of this Software, with or without modification, must
0008: * reproduce the GTPL in: (1) the Software, or (2) the Documentation or
0009: * some other similar material which is provided with the Software (if
0010: * any).
0011: *
0012: * Copyright 1999-2004 University of Chicago and The University of
0013: * Southern California. All rights reserved.
0014: */
0015: package org.griphyn.vdl.parser;
0016:
0017: import org.griphyn.vdl.classes.*;
0018: import org.griphyn.vdl.util.Logging;
0019: import java.io.Reader;
0020: import java.io.IOException;
0021: import java.util.Collection;
0022: import java.util.ArrayList;
0023:
0024: /**
0025: * Parses the input stream and generates pool configuration map as
0026: * output.
0027: *
0028: * @author Jens-S. Vöckler
0029: * @author Yong Zhao
0030: * @version $Revision: 50 $
0031: *
0032: * @see VDLtScanner
0033: * @see VDLtToken
0034: */
0035: public class VDLtParser {
0036: /**
0037: * The access to the lexical scanner is stored here.
0038: */
0039: private VDLtScanner m_scanner = null;
0040:
0041: /**
0042: * Stores the look-ahead symbol.
0043: */
0044: private VDLtToken m_lookAhead = null;
0045:
0046: /**
0047: * Initializes the parser with an input stream to read from.
0048: * @param r is the stream opened for reading.
0049: */
0050: public VDLtParser(java.io.Reader r) throws IOException,
0051: VDLtException {
0052: m_scanner = new VDLtScanner(r);
0053: m_lookAhead = m_scanner.nextToken();
0054: }
0055:
0056: protected LFN lfn() throws IOException, VDLtException {
0057: if (!(m_lookAhead instanceof VDLtAt))
0058: throw new VDLtParserException(m_scanner,
0059: "An LFN must start with an at symbol");
0060: m_lookAhead = m_scanner.nextToken();
0061:
0062: if (!(m_lookAhead instanceof VDLtOpenBrace))
0063: throw new VDLtParserException(m_scanner,
0064: "An LFN has a brace after the at symbol");
0065: m_lookAhead = m_scanner.nextToken();
0066:
0067: if (!(m_lookAhead instanceof VDLtIdentifier))
0068: throw new VDLtParserException(m_scanner,
0069: "An LFN uses a direction identifier as first component");
0070:
0071: int direction = -1;
0072: String id = ((VDLtIdentifier) m_lookAhead).getValue();
0073: if (id.compareTo("in") == 0 || id.compareTo("input") == 0) {
0074: direction = LFN.INPUT;
0075: m_lookAhead = m_scanner.nextToken();
0076: } else if (id.compareTo("out") == 0
0077: || id.compareTo("output") == 0) {
0078: direction = LFN.OUTPUT;
0079: m_lookAhead = m_scanner.nextToken();
0080: } else if (id.compareTo("io") == 0
0081: || id.compareTo("inout") == 0) {
0082: direction = LFN.INOUT;
0083: m_lookAhead = m_scanner.nextToken();
0084: } else if (id.compareTo("none") == 0) {
0085: direction = LFN.NONE;
0086: m_lookAhead = m_scanner.nextToken();
0087: } else {
0088: // no keyword given
0089: throw new VDLtParserException(m_scanner,
0090: "A LFN needs to specify a direction");
0091: }
0092:
0093: if (!(m_lookAhead instanceof VDLtColon))
0094: throw new VDLtParserException(m_scanner,
0095: "An LFN separates the filename with a colon from the direction");
0096: m_lookAhead = m_scanner.nextToken();
0097:
0098: if (!(m_lookAhead instanceof VDLtQuotedString))
0099: throw new VDLtParserException(m_scanner,
0100: "The filename of an LFN is a quoted string");
0101: id = ((VDLtQuotedString) m_lookAhead).getValue();
0102: m_lookAhead = m_scanner.nextToken();
0103:
0104: // check for temporary hint
0105: String hint = null;
0106: if (m_lookAhead instanceof VDLtColon) {
0107: m_lookAhead = m_scanner.nextToken();
0108: if (!(m_lookAhead instanceof VDLtQuotedString))
0109: throw new VDLtParserException(m_scanner,
0110: "The temporary template of an LFN is a quoted string");
0111: hint = ((VDLtQuotedString) m_lookAhead).getValue();
0112: m_lookAhead = m_scanner.nextToken();
0113: }
0114:
0115: // check for (possibly empty) special section
0116: String rt = null;
0117: if (m_lookAhead instanceof VDLtVBar) {
0118: m_lookAhead = m_scanner.nextToken();
0119: if (m_lookAhead instanceof VDLtIdentifier) {
0120: rt = ((VDLtIdentifier) m_lookAhead).getValue();
0121: m_lookAhead = m_scanner.nextToken();
0122: } else if (m_lookAhead instanceof VDLtCloseBrace) {
0123: // empty section
0124: rt = new String();
0125: } else {
0126: throw new VDLtParserException(m_scanner, "The LFN \""
0127: + id + "\" has an invalid rt specification");
0128: }
0129: }
0130:
0131: // check for correct termination
0132: if (!(m_lookAhead instanceof VDLtCloseBrace))
0133: throw new VDLtParserException(m_scanner, "The LFN \"" + id
0134: + "\" is not terminated correctly");
0135: m_lookAhead = m_scanner.nextToken();
0136:
0137: if (rt == null) {
0138: // backward compatibility. The constructor does the "right thing":
0139: // if hint is null, the rt will be false
0140: // if hint is not null, the rt will both be true
0141: return new LFN(id, direction, hint);
0142: } else {
0143: // new format, just do the full kit
0144: boolean no_t = (rt.indexOf('t') == -1);
0145: boolean no_T = (rt.indexOf('T') == -1);
0146:
0147: return new LFN(id, direction, hint,
0148: // if "r" is present, do register
0149: rt.indexOf('r') == -1,
0150: // if "t" is present, do transfer
0151: // if "T" is present, optional transfer
0152: no_t ? (no_T ? LFN.XFER_NOT : LFN.XFER_OPTIONAL)
0153: : LFN.XFER_MANDATORY, rt.indexOf('o') != -1);
0154: }
0155: }
0156:
0157: protected Use use() throws IOException, VDLtException {
0158: Use result = new Use();
0159:
0160: if ((m_lookAhead instanceof VDLtDollar)) {
0161: m_lookAhead = m_scanner.nextToken();
0162:
0163: if (!(m_lookAhead instanceof VDLtOpenBrace))
0164: throw new VDLtParserException(m_scanner,
0165: "An bound var has a brace after the dollar");
0166: m_lookAhead = m_scanner.nextToken();
0167:
0168: if (m_lookAhead instanceof VDLtQuotedString) {
0169: // rendering supplied
0170: String temp = ((VDLtQuotedString) m_lookAhead)
0171: .getValue();
0172: m_lookAhead = m_scanner.nextToken();
0173: if (m_lookAhead instanceof VDLtColon) {
0174: // triple supplied
0175: result.setPrefix(temp);
0176: m_lookAhead = m_scanner.nextToken();
0177:
0178: if (!(m_lookAhead instanceof VDLtQuotedString))
0179: throw new VDLtParserException(m_scanner,
0180: "The rending information is \"prefix\":\"separator\":\"suffix\"");
0181: result
0182: .setSeparator(((VDLtQuotedString) m_lookAhead)
0183: .getValue());
0184: m_lookAhead = m_scanner.nextToken();
0185:
0186: if (!(m_lookAhead instanceof VDLtColon))
0187: throw new VDLtParserException(m_scanner,
0188: "The rending information is \"prefix\":\"separator\":\"suffix\"");
0189: m_lookAhead = m_scanner.nextToken();
0190:
0191: if (!(m_lookAhead instanceof VDLtQuotedString))
0192: throw new VDLtParserException(m_scanner,
0193: "The rending information is \"prefix\":\"separator\":\"suffix\"");
0194: result.setSuffix(((VDLtQuotedString) m_lookAhead)
0195: .getValue());
0196: m_lookAhead = m_scanner.nextToken();
0197:
0198: if (!(m_lookAhead instanceof VDLtVBar))
0199: throw new VDLtParserException(m_scanner,
0200: "The rending information is separated by a bar from the bound variable");
0201: m_lookAhead = m_scanner.nextToken();
0202:
0203: } else if (m_lookAhead instanceof VDLtVBar) {
0204: // just a separator
0205: result.setSeparator(temp);
0206: m_lookAhead = m_scanner.nextToken();
0207: } else
0208: throw new VDLtParserException(m_scanner,
0209: "The rending information for the bound variable is wrong");
0210: }
0211:
0212: if (!(m_lookAhead instanceof VDLtIdentifier))
0213: throw new VDLtParserException(m_scanner,
0214: "An bound var has an optional direction or the identifier");
0215:
0216: String id = ((VDLtIdentifier) m_lookAhead).getValue();
0217: if (id.compareTo("in") == 0 || id.compareTo("input") == 0) {
0218: result.setLink(LFN.INPUT);
0219: m_lookAhead = m_scanner.nextToken();
0220: } else if (id.compareTo("out") == 0
0221: || id.compareTo("output") == 0) {
0222: result.setLink(LFN.OUTPUT);
0223: m_lookAhead = m_scanner.nextToken();
0224: } else if (id.compareTo("io") == 0
0225: || id.compareTo("inout") == 0) {
0226: result.setLink(LFN.INOUT);
0227: m_lookAhead = m_scanner.nextToken();
0228: } else if (id.compareTo("none") == 0) {
0229: result.setLink(LFN.NONE);
0230: m_lookAhead = m_scanner.nextToken();
0231: }
0232:
0233: if (result.getLink() != -1) {
0234: if (!(m_lookAhead instanceof VDLtColon))
0235: throw new VDLtParserException(m_scanner,
0236: "A colon separates the direction from the identifier");
0237: m_lookAhead = m_scanner.nextToken();
0238: }
0239:
0240: if (!(m_lookAhead instanceof VDLtIdentifier))
0241: throw new VDLtParserException(m_scanner,
0242: "The bound variable must be named as identifier");
0243: result.setName(((VDLtIdentifier) m_lookAhead).getValue());
0244: m_lookAhead = m_scanner.nextToken();
0245:
0246: if (!(m_lookAhead instanceof VDLtCloseBrace))
0247: throw new VDLtParserException(
0248: m_scanner,
0249: "The bound var "
0250: + result.getName()
0251: + " is not terminated by a closing brace");
0252: m_lookAhead = m_scanner.nextToken();
0253:
0254: } else if ((m_lookAhead instanceof VDLtOpenParenthesis)) {
0255: //
0256: // abbreviated form 1, using a type-cast: (inout) var
0257: //
0258: m_lookAhead = m_scanner.nextToken();
0259: if (!(m_lookAhead instanceof VDLtIdentifier))
0260: throw new VDLtParserException(m_scanner,
0261: "An bound var has an optional direction or the identifier");
0262:
0263: String id = ((VDLtIdentifier) m_lookAhead).getValue();
0264: if (id.compareTo("in") == 0 || id.compareTo("input") == 0) {
0265: result.setLink(LFN.INPUT);
0266: m_lookAhead = m_scanner.nextToken();
0267: } else if (id.compareTo("out") == 0
0268: || id.compareTo("output") == 0) {
0269: result.setLink(LFN.OUTPUT);
0270: m_lookAhead = m_scanner.nextToken();
0271: } else if (id.compareTo("io") == 0
0272: || id.compareTo("inout") == 0) {
0273: result.setLink(LFN.INOUT);
0274: m_lookAhead = m_scanner.nextToken();
0275: } else if (id.compareTo("none") == 0) {
0276: result.setLink(LFN.NONE);
0277: m_lookAhead = m_scanner.nextToken();
0278: }
0279:
0280: if (result.getLink() != -1) {
0281: if (!(m_lookAhead instanceof VDLtCloseParenthesis))
0282: throw new VDLtParserException(m_scanner,
0283: "A closeing parenthesis finished the type-cast");
0284: m_lookAhead = m_scanner.nextToken();
0285: }
0286:
0287: if (!(m_lookAhead instanceof VDLtIdentifier))
0288: throw new VDLtParserException(m_scanner,
0289: "The bound variable must be named as identifier");
0290: result.setName(((VDLtIdentifier) m_lookAhead).getValue());
0291: m_lookAhead = m_scanner.nextToken();
0292:
0293: } else if ((m_lookAhead instanceof VDLtIdentifier)) {
0294: //
0295: // abbreviated form 2: justvar
0296: //
0297: result.setName(((VDLtIdentifier) m_lookAhead).getValue());
0298: m_lookAhead = m_scanner.nextToken();
0299: } else {
0300: throw new VDLtParserException(m_scanner,
0301: "An bound variable starts with a dollar, type-cast or identifier");
0302: }
0303:
0304: return result;
0305: }
0306:
0307: protected Text text() throws IOException, VDLtException {
0308: if (m_lookAhead instanceof VDLtQuotedString) {
0309: Text result = new Text(((VDLtQuotedString) m_lookAhead)
0310: .getValue());
0311: m_lookAhead = m_scanner.nextToken();
0312: return result;
0313: } else
0314: throw new VDLtParserException(m_scanner,
0315: "expecting a quoted string");
0316: }
0317:
0318: protected Leaf tr_leaf() throws IOException, VDLtException {
0319: if (m_lookAhead instanceof VDLtQuotedString)
0320: return text();
0321: else if ((m_lookAhead instanceof VDLtDollar)
0322: || (m_lookAhead instanceof VDLtOpenParenthesis)
0323: || (m_lookAhead instanceof VDLtIdentifier))
0324: return use();
0325: else
0326: throw new VDLtParserException(m_scanner,
0327: "the value is neither a quoted string nor a valid bound variable");
0328: }
0329:
0330: protected Scalar dv_leaf() throws IOException, VDLtException {
0331: if (m_lookAhead instanceof VDLtQuotedString)
0332: return new Scalar(text());
0333: else if (m_lookAhead instanceof VDLtAt)
0334: return new Scalar(lfn());
0335: else
0336: throw new VDLtParserException(m_scanner,
0337: "the value is neither a quoted string nor a valid LFN");
0338: }
0339:
0340: /**
0341: * internal function to parse a profile inside a TR body.
0342: * @return a memory representation of a profile instance.
0343: * @exception IOException if the reading from the stream fails,
0344: * @exception VDLtParserException if the parser detects a syntax error,
0345: * @exception VDLtScannerException if the scanner detects a lexical error.
0346: */
0347: protected Profile profile() throws IOException, VDLtException {
0348: if (!(m_lookAhead instanceof VDLtIdentifier)
0349: && ((VDLtIdentifier) m_lookAhead).getValue()
0350: .toLowerCase().compareTo("profile") != 0)
0351: throw new VDLtParserException(m_scanner,
0352: "Expecting keyword \"profile\"");
0353: m_lookAhead = m_scanner.nextToken();
0354:
0355: if (!(m_lookAhead instanceof VDLtIdentifier))
0356: throw new VDLtParserException(m_scanner,
0357: "The profile needs a profile namespace first");
0358: String namespace = ((VDLtIdentifier) m_lookAhead).getValue();
0359: m_lookAhead = m_scanner.nextToken();
0360:
0361: String name = null;
0362: int p1 = namespace.indexOf('.');
0363: int p2 = namespace.indexOf("..");
0364: if (p1 >= 0 && p1 < namespace.length()) {
0365: // read as one token what are three
0366: // Logging.instance().log( "default", 0, "Line " + m_scanner.getLineNumber() +
0367: // ": Please use :: instead of . in profile " + namespace );
0368: name = namespace.substring(p1 + 1);
0369: namespace = namespace.substring(0, p1).toLowerCase();
0370:
0371: } else if (p2 >= 0 && p2 < namespace.length()) {
0372: // read as one token what are three
0373: name = namespace.substring(p2 + 2);
0374: namespace = namespace.substring(0, p2).toLowerCase();
0375:
0376: } else {
0377: namespace = namespace.toLowerCase();
0378:
0379: // read remaining tokens
0380: if (!(m_lookAhead instanceof VDLtPeriod || m_lookAhead instanceof VDLtDoubleColon))
0381: throw new VDLtParserException(m_scanner,
0382: "The profile namespace is separated by a . or :: from the profile key");
0383: // if ( m_lookAhead instanceof VDLtPeriod )
0384: // Logging.instance().log( "default", 0, "Line " + m_scanner.getLineNumber() +
0385: // ": Please use :: instead of . in profile" );
0386: m_lookAhead = m_scanner.nextToken();
0387:
0388: if (!(m_lookAhead instanceof VDLtIdentifier))
0389: throw new VDLtParserException(m_scanner,
0390: "The profile requires a name (key)");
0391: name = ((VDLtIdentifier) m_lookAhead).getValue();
0392: m_lookAhead = m_scanner.nextToken();
0393: }
0394:
0395: if (!(m_lookAhead instanceof VDLtEquals))
0396: throw new VDLtParserException(m_scanner,
0397: "The profile value is separated by an equals from the key");
0398: m_lookAhead = m_scanner.nextToken();
0399:
0400: Collection children = new ArrayList();
0401: do {
0402: children.add(tr_leaf());
0403: } while (!(m_lookAhead instanceof VDLtSemicolon));
0404:
0405: return new Profile(namespace, name, children);
0406: }
0407:
0408: /**
0409: * internal function to parse a <code>argument</code> line.
0410: * @return a memory representation of an TR argument.
0411: * @exception IOException if the reading from the stream fails,
0412: * @exception VDLtParserException if the parser detects a syntax error,
0413: * @exception VDLtScannerException if the scanner detects a lexical error.
0414: */
0415: protected Argument argument() throws IOException, VDLtException {
0416: Argument result = new Argument();
0417: if (!(m_lookAhead instanceof VDLtIdentifier)
0418: && ((VDLtIdentifier) m_lookAhead).getValue()
0419: .toLowerCase().compareTo("argument") != 0)
0420: throw new VDLtParserException(m_scanner,
0421: "Expecting keyword \"argument\"");
0422: m_lookAhead = m_scanner.nextToken();
0423:
0424: if ((m_lookAhead instanceof VDLtIdentifier)) {
0425: // optional identifier, only used for streams
0426: result.setName(((VDLtIdentifier) m_lookAhead).getValue());
0427: m_lookAhead = m_scanner.nextToken();
0428: }
0429:
0430: if (!(m_lookAhead instanceof VDLtEquals))
0431: throw new VDLtParserException(m_scanner,
0432: "The argument value is separated by an equals from the argument");
0433: m_lookAhead = m_scanner.nextToken();
0434:
0435: do {
0436: result.addLeaf(tr_leaf());
0437: } while (!(m_lookAhead instanceof VDLtSemicolon));
0438:
0439: return result;
0440: }
0441:
0442: /**
0443: * internal function to parse a call inside a compound TR.
0444: * @return an actual argument list as used by the <code>call</code> statement.
0445: * @exception IOException if the reading from the stream fails,
0446: * @exception VDLtParserException if the parser detects a syntax error,
0447: * @exception VDLtScannerException if the scanner detects a lexical error.
0448: */
0449: protected Pass carg() throws IOException, VDLtException {
0450: if (!(m_lookAhead instanceof VDLtIdentifier))
0451: throw new VDLtParserException(m_scanner,
0452: "Expecting an identifier in call arguments");
0453: Pass result = new Pass(((VDLtIdentifier) m_lookAhead)
0454: .getValue());
0455: m_lookAhead = m_scanner.nextToken();
0456:
0457: if (!(m_lookAhead instanceof VDLtEquals))
0458: throw new VDLtParserException(m_scanner,
0459: "Missing equals sign after call arg identifier");
0460: m_lookAhead = m_scanner.nextToken();
0461:
0462: if (m_lookAhead instanceof VDLtOpenBracket) {
0463: // list value
0464: m_lookAhead = m_scanner.nextToken();
0465:
0466: List list = new List();
0467: while (!(m_lookAhead instanceof VDLtCloseBracket)) {
0468: list.addScalar(new Scalar(tr_leaf()));
0469: if (m_lookAhead instanceof VDLtComma)
0470: m_lookAhead = m_scanner.nextToken();
0471: }
0472: // reached only for closing bracket
0473: m_lookAhead = m_scanner.nextToken();
0474: result.setValue(list);
0475: } else {
0476: // scalar value
0477: result.setValue(new Scalar(tr_leaf()));
0478: }
0479:
0480: return result;
0481: }
0482:
0483: /**
0484: * internal function to parse a call inside a compound TR.
0485: * @return a memory representation of a call instance.
0486: * @exception IOException if the reading from the stream fails,
0487: * @exception VDLtParserException if the parser detects a syntax error,
0488: * @exception VDLtScannerException if the scanner detects a lexical error.
0489: */
0490: protected Call call() throws IOException, VDLtException {
0491: if (!(m_lookAhead instanceof VDLtIdentifier)
0492: && ((VDLtIdentifier) m_lookAhead).getValue()
0493: .toLowerCase().compareTo("call") != 0)
0494: throw new VDLtParserException(m_scanner,
0495: "Expecting keyword \"call\"");
0496: m_lookAhead = m_scanner.nextToken();
0497:
0498: VDLtFQDN tr = trmap();
0499: Call result = new Call(tr.getValue(1), tr.getValue(2), tr
0500: .getValue(3));
0501: result.setUsesspace(tr.getValue(0));
0502:
0503: //
0504: // actual call argument list
0505: //
0506: if (!(m_lookAhead instanceof VDLtOpenParenthesis))
0507: throw new VDLtParserException(m_scanner,
0508: "expecting an open parenthesis after the call mapping");
0509: m_lookAhead = m_scanner.nextToken();
0510:
0511: while (!(m_lookAhead instanceof VDLtCloseParenthesis)) {
0512: result.addPass(carg());
0513: if (m_lookAhead instanceof VDLtComma) {
0514: m_lookAhead = m_scanner.nextToken();
0515: if (!(m_lookAhead instanceof VDLtIdentifier))
0516: throw new VDLtParserException(m_scanner,
0517: "expecting more arguments after the comma");
0518: }
0519: }
0520: // reach this only with a closing parenthesis
0521: m_lookAhead = m_scanner.nextToken();
0522:
0523: return result;
0524: }
0525:
0526: /**
0527: * internal function to parse formal arguments employed by a TR.
0528: * @return a single formal argument
0529: * @exception IOException if the reading from the stream fails,
0530: * @exception VDLtParserException if the parser detects a syntax error,
0531: * @exception VDLtScannerException if the scanner detects a lexical error.
0532: */
0533: protected Declare farg() throws IOException, VDLtException {
0534: if (!(m_lookAhead instanceof VDLtIdentifier))
0535: throw new VDLtParserException(m_scanner,
0536: "expecting a direction or an identifier");
0537:
0538: int direction = -1;
0539: String id = ((VDLtIdentifier) m_lookAhead).getValue()
0540: .toLowerCase();
0541: if (id.compareTo("in") == 0 || id.compareTo("input") == 0) {
0542: direction = LFN.INPUT;
0543: m_lookAhead = m_scanner.nextToken();
0544: } else if (id.compareTo("out") == 0
0545: || id.compareTo("output") == 0) {
0546: direction = LFN.OUTPUT;
0547: m_lookAhead = m_scanner.nextToken();
0548: } else if (id.compareTo("io") == 0
0549: || id.compareTo("inout") == 0) {
0550: direction = LFN.INOUT;
0551: m_lookAhead = m_scanner.nextToken();
0552: } else if (id.compareTo("none") == 0) {
0553: direction = LFN.NONE;
0554: m_lookAhead = m_scanner.nextToken();
0555: } else {
0556: // no keyword given, assume none
0557: direction = LFN.NONE;
0558: }
0559:
0560: if (m_lookAhead instanceof VDLtOpenBracket)
0561: // common error I frequently commit myself
0562: throw new VDLtParserException(m_scanner,
0563: "[] not permitted after type");
0564: else if (!(m_lookAhead instanceof VDLtIdentifier))
0565: // otherwise erraneous
0566: throw new VDLtParserException(m_scanner,
0567: "expecting an identifier");
0568:
0569: id = ((VDLtIdentifier) m_lookAhead).getValue();
0570: m_lookAhead = m_scanner.nextToken();
0571:
0572: int containerType = -1;
0573: if (m_lookAhead instanceof VDLtOpenBracket) {
0574: // list container
0575: m_lookAhead = m_scanner.nextToken();
0576: if (!(m_lookAhead instanceof VDLtCloseBracket))
0577: throw new VDLtParserException(m_scanner,
0578: "expecting a closing bracket after the open bracket");
0579: else
0580: m_lookAhead = m_scanner.nextToken();
0581: containerType = Value.LIST;
0582: } else {
0583: containerType = Value.SCALAR;
0584: }
0585:
0586: Declare result = new Declare(id, containerType, direction);
0587: if (m_lookAhead instanceof VDLtEquals) {
0588: // there is a default value associated with the variable
0589: m_lookAhead = m_scanner.nextToken();
0590: if (containerType == Value.SCALAR) {
0591: // scalar default
0592: result.setValue(dv_leaf());
0593: } else {
0594: // list default within brackets
0595: List list = new List();
0596: if (!(m_lookAhead instanceof VDLtOpenBracket))
0597: throw new VDLtParserException(m_scanner,
0598: "expecting an opening bracket for vector default values");
0599: m_lookAhead = m_scanner.nextToken();
0600: while (!(m_lookAhead instanceof VDLtCloseBracket)) {
0601: list.addScalar(dv_leaf());
0602: if (m_lookAhead instanceof VDLtComma)
0603: m_lookAhead = m_scanner.nextToken();
0604: }
0605: // reach this only with a closing bracket
0606: m_lookAhead = m_scanner.nextToken();
0607: result.setValue(list);
0608: }
0609: }
0610: return result;
0611: }
0612:
0613: /**
0614: * internal function to parse temporary variables employed n a TR.
0615: * @return a single formal argument
0616: * @exception IOException if the reading from the stream fails,
0617: * @exception VDLtParserException if the parser detects a syntax error,
0618: * @exception VDLtScannerException if the scanner detects a lexical error.
0619: */
0620: protected Local targ() throws IOException, VDLtException {
0621: if (!(m_lookAhead instanceof VDLtIdentifier))
0622: throw new VDLtParserException(m_scanner,
0623: "expecting a direction or an identifier");
0624:
0625: int direction = -1;
0626: String id = ((VDLtIdentifier) m_lookAhead).getValue()
0627: .toLowerCase();
0628: if (id.compareTo("in") == 0 || id.compareTo("input") == 0) {
0629: direction = LFN.INPUT;
0630: m_lookAhead = m_scanner.nextToken();
0631: } else if (id.compareTo("out") == 0
0632: || id.compareTo("output") == 0) {
0633: direction = LFN.OUTPUT;
0634: m_lookAhead = m_scanner.nextToken();
0635: } else if (id.compareTo("io") == 0
0636: || id.compareTo("inout") == 0) {
0637: direction = LFN.INOUT;
0638: m_lookAhead = m_scanner.nextToken();
0639: } else if (id.compareTo("none") == 0) {
0640: direction = LFN.NONE;
0641: m_lookAhead = m_scanner.nextToken();
0642: } else {
0643: // no keyword given, assume none
0644: direction = LFN.NONE;
0645: }
0646:
0647: if (!(m_lookAhead instanceof VDLtIdentifier))
0648: throw new VDLtParserException(m_scanner,
0649: "expecting an identifier");
0650: id = ((VDLtIdentifier) m_lookAhead).getValue();
0651: m_lookAhead = m_scanner.nextToken();
0652:
0653: int containerType = -1;
0654: if (m_lookAhead instanceof VDLtOpenBracket) {
0655: // list container
0656: m_lookAhead = m_scanner.nextToken();
0657: if (!(m_lookAhead instanceof VDLtCloseBracket))
0658: throw new VDLtParserException(m_scanner,
0659: "expecting a closing bracket after the open bracket");
0660: else
0661: m_lookAhead = m_scanner.nextToken();
0662: containerType = Value.LIST;
0663: } else {
0664: containerType = Value.SCALAR;
0665: }
0666:
0667: // local variables must have a value to be bound at
0668: Local result = new Local(id, containerType, direction);
0669: if (!(m_lookAhead instanceof VDLtEquals))
0670: throw new VDLtParserException(m_scanner,
0671: "expecting an equal sign");
0672:
0673: m_lookAhead = m_scanner.nextToken();
0674: if (containerType == Value.SCALAR) {
0675: // scalar default
0676: result.setValue(dv_leaf());
0677: } else {
0678: // list default within brackets
0679: List list = new List();
0680: if (!(m_lookAhead instanceof VDLtOpenBracket))
0681: throw new VDLtParserException(m_scanner,
0682: "expecting an opening bracket for vector default values");
0683: m_lookAhead = m_scanner.nextToken();
0684: while (!(m_lookAhead instanceof VDLtCloseBracket)) {
0685: list.addScalar(dv_leaf());
0686: if (m_lookAhead instanceof VDLtComma)
0687: m_lookAhead = m_scanner.nextToken();
0688: }
0689: // reach this only with a closing bracket
0690: m_lookAhead = m_scanner.nextToken();
0691: result.setValue(list);
0692: }
0693: return result;
0694: }
0695:
0696: /**
0697: * internal function to parse actual arguments employed by a DV.
0698: * @return a single actual argument.
0699: * @exception IOException if the reading from the stream fails,
0700: * @exception VDLtParserException if the parser detects a syntax error,
0701: * @exception VDLtScannerException if the scanner detects a lexical error.
0702: */
0703: protected Pass aarg() throws IOException, VDLtException {
0704: if (!(m_lookAhead instanceof VDLtIdentifier))
0705: throw new VDLtParserException(m_scanner,
0706: "Expecting an identifier in actual arguments");
0707: Pass result = new Pass(((VDLtIdentifier) m_lookAhead)
0708: .getValue());
0709: m_lookAhead = m_scanner.nextToken();
0710:
0711: if (!(m_lookAhead instanceof VDLtEquals))
0712: throw new VDLtParserException(m_scanner,
0713: "Missing equals sign after actual arg identifier");
0714: m_lookAhead = m_scanner.nextToken();
0715:
0716: if (m_lookAhead instanceof VDLtOpenBracket) {
0717: // list value
0718: m_lookAhead = m_scanner.nextToken();
0719:
0720: List list = new List();
0721: while (!(m_lookAhead instanceof VDLtCloseBracket)) {
0722: list.addScalar(dv_leaf());
0723: if (m_lookAhead instanceof VDLtComma)
0724: m_lookAhead = m_scanner.nextToken();
0725: }
0726: // reached only for closing bracket
0727: m_lookAhead = m_scanner.nextToken();
0728: result.setValue(list);
0729: } else {
0730: // scalar value
0731: result.setValue(dv_leaf());
0732: }
0733:
0734: return result;
0735: }
0736:
0737: /**
0738: * internal function to parse the fully-qualified definition identifier
0739: * into memory. This is the name of a TR or DV.
0740: * @return a parsed fully-qualified identifier.
0741: * @exception IOException if the reading from the stream fails,
0742: * @exception VDLtParserException if the parser detects a syntax error,
0743: * @exception VDLtScannerException if the scanner detects a lexical error.
0744: */
0745: protected VDLtFQDN fqdn() throws IOException, VDLtException {
0746: VDLtFQDN result = new VDLtFQDN();
0747: if (!(m_lookAhead instanceof VDLtIdentifier))
0748: throw new VDLtParserException(m_scanner,
0749: "A FQDN starts with an identifier");
0750: String temp = ((VDLtIdentifier) m_lookAhead).getValue();
0751: m_lookAhead = m_scanner.nextToken();
0752:
0753: if (m_lookAhead instanceof VDLtDoubleColon) {
0754: // first part was the namespace
0755: m_lookAhead = m_scanner.nextToken();
0756: result.setValue(0, temp);
0757:
0758: if (!(m_lookAhead instanceof VDLtIdentifier))
0759: throw new VDLtParserException(m_scanner,
0760: "Expecting more identifiers after a double colon");
0761: temp = ((VDLtIdentifier) m_lookAhead).getValue();
0762: m_lookAhead = m_scanner.nextToken();
0763: }
0764:
0765: // set name (mandatory part)
0766: result.setValue(1, temp);
0767:
0768: if (m_lookAhead instanceof VDLtColon) {
0769: m_lookAhead = m_scanner.nextToken();
0770: if (!(m_lookAhead instanceof VDLtIdentifier))
0771: throw new VDLtParserException(m_scanner,
0772: "Expecting a version identifier");
0773: temp = ((VDLtIdentifier) m_lookAhead).getValue();
0774: m_lookAhead = m_scanner.nextToken();
0775:
0776: result.setValue(2, temp);
0777: }
0778:
0779: return result;
0780: }
0781:
0782: /**
0783: * internal function to parse the part after the arrow operator into
0784: * memory. It is also used for calls in compound transformations.<p>
0785: * On popular demand, the syntax slightly changed to be more permissive
0786: * with version maps. The following short-cuts are permitted:
0787: *
0788: *
0789: * @return a parsed mapping to a transformation.
0790: * @exception IOException if the reading from the stream fails,
0791: * @exception VDLtParserException if the parser detects a syntax error,
0792: * @exception VDLtScannerException if the scanner detects a lexical error.
0793: */
0794: protected VDLtFQDN trmap() throws IOException, VDLtException {
0795: VDLtFQDN result = new VDLtFQDN();
0796: if (!(m_lookAhead instanceof VDLtIdentifier))
0797: throw new VDLtParserException(m_scanner,
0798: "A TR mapping starts with an identifier");
0799: String temp = ((VDLtIdentifier) m_lookAhead).getValue();
0800: m_lookAhead = m_scanner.nextToken();
0801:
0802: if (m_lookAhead instanceof VDLtDoubleColon) {
0803: // first part was the namespace
0804: m_lookAhead = m_scanner.nextToken();
0805: result.setValue(0, temp);
0806:
0807: if (!(m_lookAhead instanceof VDLtIdentifier))
0808: throw new VDLtParserException(m_scanner,
0809: "Expecting more identifiers after a double colon");
0810: temp = ((VDLtIdentifier) m_lookAhead).getValue();
0811: m_lookAhead = m_scanner.nextToken();
0812: }
0813:
0814: // set name (mandatory part)
0815: result.setValue(1, temp);
0816:
0817: // :min,
0818: // :,max
0819: // :min,max
0820: // NEW :same
0821: //
0822: if (m_lookAhead instanceof VDLtColon) {
0823: // min and max versions as identifiers
0824: m_lookAhead = m_scanner.nextToken();
0825: if (m_lookAhead instanceof VDLtIdentifier) {
0826: // min version
0827: String minimum = ((VDLtIdentifier) m_lookAhead)
0828: .getValue();
0829: result.setValue(2, minimum);
0830: m_lookAhead = m_scanner.nextToken();
0831:
0832: // NEW branch -- same version for both
0833: if (m_lookAhead instanceof VDLtOpenParenthesis) {
0834: result.setValue(3, minimum);
0835: return result;
0836: }
0837: }
0838:
0839: if (!(m_lookAhead instanceof VDLtComma))
0840: throw new VDLtParserException(m_scanner,
0841: "Expecting a comma between min and max version");
0842:
0843: m_lookAhead = m_scanner.nextToken();
0844: if (m_lookAhead instanceof VDLtIdentifier) {
0845: // max version
0846: result.setValue(3, ((VDLtIdentifier) m_lookAhead)
0847: .getValue());
0848: m_lookAhead = m_scanner.nextToken();
0849: } else if (!(m_lookAhead instanceof VDLtOpenParenthesis))
0850: throw new VDLtParserException(m_scanner,
0851: "Excepting a max version after the comma");
0852: }
0853:
0854: return result;
0855: }
0856:
0857: /**
0858: * internal function to parse a complete transformation.
0859: * @return a derivation in memory
0860: * @exception IOException if the reading from the stream fails,
0861: * @exception VDLtParserException if the parser detects a syntax error,
0862: * @exception VDLtScannerException if the scanner detects a lexical error.
0863: */
0864: protected Derivation derivation() throws IOException, VDLtException {
0865: Derivation result = new Derivation();
0866:
0867: VDLtFQDN id = fqdn();
0868: result.setNamespace(id.getValue(0));
0869: result.setName(id.getValue(1));
0870: result.setVersion(id.getValue(2));
0871:
0872: if (!(m_lookAhead instanceof VDLtArrow))
0873: throw new VDLtParserException(m_scanner,
0874: "Expecting the map operator (arrow)");
0875: m_lookAhead = m_scanner.nextToken();
0876:
0877: id = trmap();
0878: result.setUsesspace(id.getValue(0));
0879: result.setUses(id.getValue(1));
0880: result.setMinIncludeVersion(id.getValue(2));
0881: result.setMaxIncludeVersion(id.getValue(3));
0882:
0883: //
0884: // actual argument list
0885: //
0886: if (!(m_lookAhead instanceof VDLtOpenParenthesis))
0887: throw new VDLtParserException(m_scanner,
0888: "expecting an open parenthesis to start actual argument list");
0889: m_lookAhead = m_scanner.nextToken();
0890:
0891: while (!(m_lookAhead instanceof VDLtCloseParenthesis)) {
0892: result.addPass(aarg());
0893: if (m_lookAhead instanceof VDLtComma) {
0894: m_lookAhead = m_scanner.nextToken();
0895: if (!(m_lookAhead instanceof VDLtIdentifier))
0896: throw new VDLtParserException(m_scanner,
0897: "expecting more arguments after the comma");
0898: }
0899: }
0900: // reach this only with a closing parenthesis
0901: m_lookAhead = m_scanner.nextToken();
0902:
0903: if (!(m_lookAhead instanceof VDLtSemicolon))
0904: throw new VDLtParserException(m_scanner,
0905: "expecting a semicolon to terminate a DV");
0906: m_lookAhead = m_scanner.nextToken();
0907:
0908: return result;
0909: }
0910:
0911: /**
0912: * internal function to parse a complete transformation.
0913: * @return a transformation in memory
0914: * @exception IOException if the reading from the stream fails,
0915: * @exception VDLtParserException if the parser detects a syntax error,
0916: * @exception VDLtScannerException if the scanner detects a lexical error.
0917: */
0918: protected Transformation transformation() throws IOException,
0919: VDLtException {
0920: Transformation result = new Transformation();
0921:
0922: VDLtFQDN id = fqdn();
0923: result.setNamespace(id.getValue(0));
0924: result.setName(id.getValue(1));
0925: result.setVersion(id.getValue(2));
0926:
0927: //
0928: // formal argument list
0929: //
0930: if (!(m_lookAhead instanceof VDLtOpenParenthesis))
0931: throw new VDLtParserException(m_scanner,
0932: "expecting an open parenthesis after the TR identifier");
0933: m_lookAhead = m_scanner.nextToken();
0934:
0935: while (!(m_lookAhead instanceof VDLtCloseParenthesis)) {
0936: result.addDeclare(farg());
0937: if (m_lookAhead instanceof VDLtComma) {
0938: m_lookAhead = m_scanner.nextToken();
0939: if (!(m_lookAhead instanceof VDLtIdentifier))
0940: throw new VDLtParserException(m_scanner,
0941: "expecting more formal arguments after the comma");
0942: }
0943: }
0944: // reach this only with a closing parenthesis
0945: m_lookAhead = m_scanner.nextToken();
0946:
0947: //
0948: // transformation body
0949: //
0950: if (!(m_lookAhead instanceof VDLtOpenBrace)
0951: && !(m_lookAhead instanceof VDLtSemicolon))
0952: throw new VDLtParserException(m_scanner,
0953: "expecting the TR body");
0954:
0955: if (m_lookAhead instanceof VDLtOpenBrace) {
0956: // regular transformation body, skip brace
0957: m_lookAhead = m_scanner.nextToken();
0958:
0959: while (!(m_lookAhead instanceof VDLtCloseBrace)) {
0960: if (!(m_lookAhead instanceof VDLtIdentifier))
0961: throw new VDLtParserException(
0962: m_scanner,
0963: "expecting \"profile\", \"call\", \"argument\", or "
0964: + "a temporary variable declaration inside TR body");
0965: String var = ((VDLtIdentifier) m_lookAhead).getValue()
0966: .toLowerCase();
0967: if (var.compareTo("argument") == 0) {
0968: result.addArgument(argument());
0969: } else if (var.compareTo("call") == 0) {
0970: result.addCall(call());
0971: } else if (var.compareTo("profile") == 0) {
0972: result.addProfile(profile());
0973: } else {
0974: // throw new VDLtParserException( m_scanner,
0975: // "\"" + var + "\" is not a valid keyword for a TR body" );
0976: result.addLocal(targ());
0977: }
0978:
0979: if (m_lookAhead instanceof VDLtSemicolon)
0980: m_lookAhead = m_scanner.nextToken();
0981: }
0982: // reach this only with a closing brace
0983: m_lookAhead = m_scanner.nextToken();
0984: } else {
0985: // transformation without a body, skip semicolon
0986: m_lookAhead = m_scanner.nextToken();
0987: }
0988:
0989: return result;
0990: }
0991:
0992: /**
0993: * Parses the a single definition from the input stream and
0994: * returns just the definition. The piece-by-piece parsing
0995: * allows for a more memory-efficient parsing process of
0996: * large input streams.
0997: * @return a Definition structure for one TR or DV
0998: * @exception IOException if the reading from the stream fails,
0999: * @exception VDLtParserException if the parser detects a syntax error,
1000: * @exception VDLtScannerException if the scanner detects a lexical error.
1001: * @see #parse()
1002: * @see #hasMoreTokens()
1003: */
1004: public Definition parseDefinition() throws IOException,
1005: VDLtException {
1006: if (!(m_lookAhead instanceof VDLtDefinition))
1007: throw new VDLtParserException(m_scanner,
1008: "expecting DV or TR");
1009:
1010: if (m_lookAhead instanceof VDLtDerivation) {
1011: // DV will be more frequently encountered, thus check first
1012: m_lookAhead = m_scanner.nextToken();
1013: return derivation();
1014: } else if (m_lookAhead instanceof VDLtTransformation) {
1015: // TR will not be as often
1016: m_lookAhead = m_scanner.nextToken();
1017: return transformation();
1018: } else {
1019: // this should not happen
1020: throw new VDLtParserException(m_scanner,
1021: "unknown definition");
1022: }
1023: }
1024:
1025: /**
1026: * Predicate to determine, if there are more Definition instances
1027: * to be read.
1028: * @return true, if there are potentially more tokens in the stream.
1029: * @exception IOException if the reading from the stream fails,
1030: * @exception VDLtParserException if the parser detects a syntax error,
1031: * @exception VDLtScannerException if the scanner detects a lexical error.
1032: */
1033: public boolean hasMoreTokens() throws IOException, VDLtException {
1034: return m_scanner.hasMoreTokens();
1035: }
1036:
1037: /**
1038: * Parses the complete input stream. This method will construct
1039: * the complete stream as Definitions in memory. It will gobble
1040: * a lot of memory for large input.
1041: * @return the Definitions in one structure
1042: * @exception IOException if the reading from the stream fails,
1043: * @exception VDLtParserException if the parser detects a syntax error,
1044: * @exception VDLtScannerException if the scanner detects a lexical error.
1045: * @see #parseDefinition()
1046: */
1047: public Definitions parse() throws IOException, VDLtException {
1048: Definitions result = new Definitions();
1049:
1050: do {
1051: if (m_lookAhead != null)
1052: result.addDefinition(parseDefinition());
1053: } while (m_scanner.hasMoreTokens());
1054:
1055: return result;
1056: }
1057: }
|