0001: /* ====================================================================
0002: * Tea - Copyright (c) 1997-2000 Walt Disney Internet Group
0003: * ====================================================================
0004: * The Tea Software License, Version 1.1
0005: *
0006: * Copyright (c) 2000 Walt Disney Internet Group. All rights reserved.
0007: *
0008: * Redistribution and use in source and binary forms, with or without
0009: * modification, are permitted provided that the following conditions
0010: * are met:
0011: *
0012: * 1. Redistributions of source code must retain the above copyright
0013: * notice, this list of conditions and the following disclaimer.
0014: *
0015: * 2. Redistributions in binary form must reproduce the above copyright
0016: * notice, this list of conditions and the following disclaimer in
0017: * the documentation and/or other materials provided with the
0018: * distribution.
0019: *
0020: * 3. The end-user documentation included with the redistribution,
0021: * if any, must include the following acknowledgment:
0022: * "This product includes software developed by the
0023: * Walt Disney Internet Group (http://opensource.go.com/)."
0024: * Alternately, this acknowledgment may appear in the software itself,
0025: * if and wherever such third-party acknowledgments normally appear.
0026: *
0027: * 4. The names "Tea", "TeaServlet", "Kettle", "Trove" and "BeanDoc" must
0028: * not be used to endorse or promote products derived from this
0029: * software without prior written permission. For written
0030: * permission, please contact opensource@dig.com.
0031: *
0032: * 5. Products derived from this software may not be called "Tea",
0033: * "TeaServlet", "Kettle" or "Trove", nor may "Tea", "TeaServlet",
0034: * "Kettle", "Trove" or "BeanDoc" appear in their name, without prior
0035: * written permission of the Walt Disney Internet Group.
0036: *
0037: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
0038: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
0039: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
0040: * DISCLAIMED. IN NO EVENT SHALL THE WALT DISNEY INTERNET GROUP OR ITS
0041: * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
0042: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
0043: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
0044: * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
0045: * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
0046: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
0047: * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0048: * ====================================================================
0049: *
0050: * For more information about Tea, please see http://opensource.go.com/.
0051: */
0052:
0053: package com.go.tea.compiler;
0054:
0055: import java.io.*;
0056: import java.util.Vector;
0057: import com.go.tea.parsetree.*;
0058: import com.go.trove.io.SourceReader;
0059:
0060: /******************************************************************************
0061: * A Parser creates the parse tree for a template by reading tokens emitted by
0062: * a {@link Scanner}. The parse tree represents the entire template as a
0063: * data structure composed of specialized nodes. Add an {@link ErrorListener}
0064: * to capture any syntax errors detected by the Parser.
0065: *
0066: * @author Brian S O'Neill
0067: * @version
0068: * <!--$$Revision:--> 64 <!-- $-->, <!--$$JustDate:--> 5/31/01 <!-- $-->
0069: */
0070: public class Parser {
0071: private Scanner mScanner;
0072: private CompilationUnit mUnit;
0073:
0074: private Vector mListeners = new Vector(1);
0075: private int mErrorCount = 0;
0076: private int mEOFErrorCount = 0;
0077:
0078: private MessageFormatter mFormatter;
0079:
0080: public Parser(Scanner scanner) {
0081: this (scanner, null);
0082: }
0083:
0084: public Parser(Scanner scanner, CompilationUnit unit) {
0085: mScanner = scanner;
0086: mUnit = unit;
0087: mFormatter = MessageFormatter.lookup(this );
0088: }
0089:
0090: public void addErrorListener(ErrorListener listener) {
0091: mListeners.addElement(listener);
0092: }
0093:
0094: public void removeErrorListener(ErrorListener listener) {
0095: mListeners.removeElement(listener);
0096: }
0097:
0098: private void dispatchParseError(ErrorEvent e) {
0099: mErrorCount++;
0100:
0101: synchronized (mListeners) {
0102: for (int i = 0; i < mListeners.size(); i++) {
0103: ((ErrorListener) mListeners.elementAt(i))
0104: .compileError(e);
0105: }
0106: }
0107: }
0108:
0109: private void error(String str, Token culprit) {
0110: str = mFormatter.format(str);
0111:
0112: if (culprit.getID() == Token.EOF) {
0113: if (mEOFErrorCount++ == 0) {
0114: str = mFormatter.format("error.at.end", str);
0115: } else {
0116: return;
0117: }
0118: }
0119:
0120: dispatchParseError(new ErrorEvent(this , str, culprit, mUnit));
0121: }
0122:
0123: private void error(String str, String arg, Token culprit) {
0124: str = mFormatter.format(str, arg);
0125:
0126: if (culprit.getID() == Token.EOF) {
0127: if (mEOFErrorCount++ == 0) {
0128: str = mFormatter.format("error.at.end", str);
0129: } else {
0130: return;
0131: }
0132: }
0133:
0134: dispatchParseError(new ErrorEvent(this , str, culprit, mUnit));
0135: }
0136:
0137: private void error(String str, SourceInfo info) {
0138: str = mFormatter.format(str);
0139: dispatchParseError(new ErrorEvent(this , str, info, mUnit));
0140: }
0141:
0142: /**
0143: * Returns a parse tree by its root node. The parse tree is generated
0144: * from tokens read from the scanner. Any errors encountered while
0145: * parsing are delivered by dispatching an event. Add an error listener
0146: * in order to capture parse errors.
0147: *
0148: * @return Non-null template node, even if there were errors during
0149: * parsing.
0150: * @see Parser#addErrorListener
0151: */
0152: public Template parse() throws IOException {
0153: Template t = parseTemplate();
0154:
0155: if (t != null) {
0156: return t;
0157: }
0158:
0159: return new Template(new SourceInfo(0, 0, 0), null, null, false,
0160: null);
0161: }
0162:
0163: public int getErrorCount() {
0164: return mErrorCount;
0165: }
0166:
0167: private Token read() throws IOException {
0168: return mScanner.readToken();
0169: }
0170:
0171: private Token peek() throws IOException {
0172: return mScanner.peekToken();
0173: }
0174:
0175: private void unread(Token token) throws IOException {
0176: mScanner.unreadToken(token);
0177: }
0178:
0179: private Template parseTemplate() throws IOException {
0180: Name name;
0181: Variable[] params = null;
0182: StatementList statementList;
0183:
0184: Token token = read();
0185: SourceInfo templateInfo = token.getSourceInfo();
0186:
0187: if (token.getID() != Token.TEMPLATE) {
0188: if (token.getID() == Token.STRING
0189: && peek().getID() == Token.TEMPLATE) {
0190:
0191: error("template.start", token);
0192: token = read();
0193: } else {
0194: error("template.declaration", token);
0195: }
0196: }
0197:
0198: SourceInfo nameInfo = peek().getSourceInfo();
0199: name = new Name(nameInfo, parseIdentifier());
0200:
0201: params = parseFormalParameters();
0202:
0203: // Check if a block is accepted as a parameter. Pattern is { ... }
0204: boolean subParam = false;
0205: token = peek();
0206: if (token.getID() == Token.LBRACE
0207: || token.getID() == Token.ELLIPSIS) {
0208: if (token.getID() == Token.ELLIPSIS) {
0209: error("template.substitution.lbrace", token);
0210: } else {
0211: read();
0212: token = peek();
0213: }
0214:
0215: if (token.getID() == Token.ELLIPSIS) {
0216: read();
0217: token = peek();
0218: if (token.getID() == Token.RBRACE) {
0219: read();
0220: subParam = true;
0221: } else {
0222: error("template.substitution.rbrace", token);
0223: }
0224: } else {
0225: error("template.substitution.ellipsis", token);
0226: if (token.getID() == Token.RBRACE) {
0227: read();
0228: subParam = true;
0229: }
0230: }
0231: }
0232:
0233: // Parse statements until end of file is reached.
0234: Vector v = new Vector(10, 0);
0235:
0236: SourceInfo info = peek().getSourceInfo();
0237:
0238: Statement statement = null;
0239: while (peek().getID() != Token.EOF) {
0240: statement = parseStatement();
0241: v.addElement(statement);
0242: }
0243:
0244: if (statement != null) {
0245: info = info.setEndPosition(statement.getSourceInfo());
0246: }
0247:
0248: Statement[] statements = new Statement[v.size()];
0249: v.copyInto(statements);
0250:
0251: statementList = new StatementList(info, statements);
0252:
0253: templateInfo = templateInfo.setEndPosition(statementList
0254: .getSourceInfo());
0255:
0256: return new Template(templateInfo, name, params, subParam,
0257: statementList);
0258: }
0259:
0260: private String parseIdentifier() throws IOException {
0261: Token token = read();
0262: if (token.getID() != Token.IDENT) {
0263: if (token.isReservedWord()) {
0264: error("identifier.reserved.word", token.getImage(),
0265: token);
0266: return token.getImage();
0267: } else {
0268: error("identifier.expected", token);
0269: return "";
0270: }
0271: }
0272:
0273: return token.getStringValue();
0274: }
0275:
0276: private Name parseName() throws IOException {
0277: SourceInfo info = null;
0278: StringBuffer name = new StringBuffer(20);
0279:
0280: while (true) {
0281: Token token = read();
0282: if (token.getID() != Token.IDENT) {
0283: if (info == null) {
0284: info = token.getSourceInfo();
0285: } else {
0286: info = info.setEndPosition(token.getSourceInfo());
0287: }
0288:
0289: if (token.isReservedWord()) {
0290: error("name.reserved.word", token.getImage(), token);
0291: name.append(token.getImage());
0292: } else {
0293: error("name.identifier.expected", token);
0294: break;
0295: }
0296: } else {
0297: name.append(token.getStringValue());
0298: if (info == null) {
0299: info = token.getSourceInfo();
0300: } else {
0301: info = info.setEndPosition(token.getSourceInfo());
0302: }
0303: }
0304:
0305: token = peek();
0306: if (token.getID() != Token.DOT) {
0307: break;
0308: } else {
0309: token = read();
0310: name.append('.');
0311: info = info.setEndPosition(token.getSourceInfo());
0312: }
0313: }
0314:
0315: return new Name(info, name.toString());
0316: }
0317:
0318: private TypeName parseTypeName() throws IOException {
0319: Name name = parseName();
0320:
0321: SourceInfo info = name.getSourceInfo();
0322: int dim = 0;
0323:
0324: while (peek().getID() == Token.LBRACK) {
0325: dim++;
0326: Token token = read(); // read the left bracket
0327: if (peek().getID() == Token.RBRACK) {
0328: token = read(); // read the right bracket
0329: } else {
0330: error("name.rbracket", peek());
0331: }
0332: info = info.setEndPosition(token.getSourceInfo());
0333: }
0334:
0335: return new TypeName(info, name, dim);
0336: }
0337:
0338: private Variable parseVariableDeclaration() throws IOException {
0339: TypeName typeName = parseTypeName();
0340:
0341: SourceInfo info = peek().getSourceInfo();
0342: String varName = parseIdentifier();
0343:
0344: return new Variable(info, varName, typeName);
0345: }
0346:
0347: private Variable[] parseFormalParameters() throws IOException {
0348: Token token = peek();
0349:
0350: if (token.getID() == Token.LPAREN) {
0351: read(); // read the left paren
0352: token = peek();
0353: } else {
0354: error("params.lparen", token);
0355: }
0356:
0357: Vector vars = new Vector(10, 0);
0358:
0359: if (token.getID() == Token.RPAREN) {
0360: // Empty list detected.
0361: } else {
0362: Expression expr = null;
0363: while (true) {
0364: if ((token = peek()).getID() == Token.RPAREN) {
0365: error("params.premature.end", token);
0366: break;
0367: }
0368:
0369: vars.addElement(parseVariableDeclaration());
0370:
0371: if ((token = peek()).getID() != Token.COMMA) {
0372: break;
0373: } else {
0374: read(); // read the comma
0375: }
0376: }
0377: }
0378:
0379: if (token.getID() == Token.RPAREN) {
0380: read(); // read the right paren
0381: } else {
0382: error("params.rparen.expected", token);
0383: }
0384:
0385: Variable[] variables = new Variable[vars.size()];
0386: vars.copyInto(variables);
0387:
0388: return variables;
0389: }
0390:
0391: private VariableRef parseLValue() throws IOException {
0392: return parseLValue(read());
0393: }
0394:
0395: private VariableRef parseLValue(Token token) throws IOException {
0396: String loopVarName;
0397: if (token.getID() != Token.IDENT) {
0398: if (token.isReservedWord()) {
0399: error("lvalue.reserved.word", token.getImage(), token);
0400: loopVarName = token.getImage();
0401: } else {
0402: error("lvalue.identifier.expected", token);
0403: loopVarName = "";
0404: }
0405: } else {
0406: loopVarName = token.getStringValue();
0407: }
0408:
0409: return new VariableRef(token.getSourceInfo(), loopVarName);
0410: }
0411:
0412: private Block parseBlock() throws IOException {
0413: Token token = peek();
0414: SourceInfo info = token.getSourceInfo();
0415:
0416: if (token.getID() != Token.LBRACE) {
0417: error("block.lbrace.expected", token);
0418: if (token.getID() == Token.SEMI) {
0419: read();
0420: return new Block(info, new Statement[0]);
0421: }
0422: } else {
0423: token = read(); // read the left brace
0424: }
0425:
0426: Vector v = new Vector(10, 0);
0427: Token p;
0428: while ((p = peek()).getID() != Token.RBRACE) {
0429: if (p.getID() == Token.EOF) {
0430: error("block.rbrace.expected", p);
0431: break;
0432: }
0433: v.addElement(parseStatement());
0434: }
0435: token = read(); // read the right brace
0436:
0437: Statement[] statements = new Statement[v.size()];
0438: v.copyInto(statements);
0439:
0440: info = info.setEndPosition(token.getSourceInfo());
0441:
0442: return new Block(info, statements);
0443: }
0444:
0445: private Statement parseStatement() throws IOException {
0446: Statement st = null;
0447:
0448: while (st == null) {
0449: Token token = read();
0450:
0451: switch (token.getID()) {
0452: case Token.SEMI:
0453: // If the token after the semi-colon is a right brace,
0454: // we can't simply skip it because this method
0455: // can't properly parse a right brace. Instead, return
0456: // an empty placeholder statement. The parseBlock method
0457: // will then be able to parse the right brace properly.
0458:
0459: int ID = peek().getID();
0460: if (ID == Token.RBRACE || ID == Token.EOF) {
0461: st = new Statement(token.getSourceInfo());
0462: } else {
0463: // Skip this token
0464: }
0465: break;
0466: case Token.BREAK:
0467: st = parseBreakStatement(token);
0468: break;
0469: case Token.IF:
0470: st = parseIfStatement(token);
0471: break;
0472: case Token.FOREACH:
0473: st = parseForeachStatement(token);
0474: break;
0475: case Token.IDENT:
0476: if (peek().getID() == Token.ASSIGN) {
0477: st = parseAssignmentStatement(token);
0478: } else {
0479: st = new ExpressionStatement(parseExpression(token));
0480: }
0481: break;
0482: case Token.ELLIPSIS:
0483: st = new SubstitutionStatement(token.getSourceInfo());
0484: break;
0485:
0486: case Token.EOF:
0487: error("statement.expected", token);
0488: st = new Statement(token.getSourceInfo());
0489: break;
0490:
0491: // Handle some error cases in a specialized way so that
0492: // the error message produced is more meaningful.
0493: case Token.ELSE:
0494: error("statement.misuse.else", token);
0495: st = parseBlock();
0496: break;
0497: case Token.IN:
0498: error("statement.misuse.in", token);
0499: st = new ExpressionStatement(parseExpression(token));
0500: break;
0501:
0502: case Token.REVERSE:
0503: error("statement.misuse.reverse", token);
0504: st = new ExpressionStatement(parseExpression(token));
0505: break;
0506:
0507: default:
0508: st = new ExpressionStatement(parseExpression(token));
0509: break;
0510: }
0511: }
0512:
0513: return st;
0514: }
0515:
0516: // When this is called, the keyword "break" has already been read.
0517: private BreakStatement parseBreakStatement(Token token)
0518: throws IOException {
0519: return new BreakStatement(token.getSourceInfo());
0520: }
0521:
0522: // When this is called, the keyword "if" has already been read.
0523: private IfStatement parseIfStatement(Token token)
0524: throws IOException {
0525: SourceInfo info = token.getSourceInfo();
0526:
0527: Expression condition = parseExpression();
0528:
0529: if (!(condition instanceof ParenExpression)) {
0530: error("if.condition", condition.getSourceInfo());
0531: }
0532:
0533: Block thenPart = parseBlock();
0534: Block elsePart = null;
0535:
0536: token = peek();
0537: if (token.getID() != Token.ELSE) {
0538: info = info.setEndPosition(thenPart.getSourceInfo());
0539: } else {
0540: read(); // read the else keyword
0541: token = peek();
0542: if (token.getID() == Token.IF) {
0543: elsePart = new Block(parseIfStatement(read()));
0544: } else {
0545: elsePart = parseBlock();
0546: }
0547:
0548: info = info.setEndPosition(elsePart.getSourceInfo());
0549: }
0550:
0551: return new IfStatement(info, condition, thenPart, elsePart);
0552: }
0553:
0554: // When this is called, the keyword "foreach" has already been read.
0555: private ForeachStatement parseForeachStatement(Token token)
0556: throws IOException {
0557:
0558: SourceInfo info = token.getSourceInfo();
0559:
0560: token = peek();
0561: if (token.getID() == Token.LPAREN) {
0562: read();
0563: } else {
0564: error("foreach.lparen.expected", token);
0565: }
0566:
0567: VariableRef loopVar = parseLValue();
0568:
0569: token = peek();
0570: if (token.getID() == Token.IN) {
0571: read();
0572: } else {
0573: error("foreach.in.expected", token);
0574: }
0575:
0576: Expression range = parseExpression();
0577: Expression endRange = null;
0578:
0579: token = peek();
0580: if (token.getID() == Token.DOTDOT) {
0581: read();
0582: endRange = parseExpression();
0583: token = peek();
0584: }
0585:
0586: boolean reverse = false;
0587: if (token.getID() == Token.REVERSE) {
0588: read();
0589: reverse = true;
0590: token = peek();
0591: }
0592:
0593: if (token.getID() == Token.RPAREN) {
0594: read();
0595: } else {
0596: error("foreach.rparen.expected", token);
0597: }
0598:
0599: Block body = parseBlock();
0600:
0601: info = info.setEndPosition(body.getSourceInfo());
0602:
0603: return new ForeachStatement(info, loopVar, range, endRange,
0604: reverse, body);
0605: }
0606:
0607: // When this is called, the identifier token has already been read.
0608: private AssignmentStatement parseAssignmentStatement(Token token)
0609: throws IOException {
0610:
0611: SourceInfo info = token.getSourceInfo();
0612: VariableRef lvalue = parseLValue(token);
0613:
0614: if (peek().getID() == Token.ASSIGN) {
0615: read();
0616: } else {
0617: error("assignment.equals.expected", peek());
0618: }
0619:
0620: Expression rvalue = parseExpression();
0621: info = info.setEndPosition(rvalue.getSourceInfo());
0622:
0623: return new AssignmentStatement(info, lvalue, rvalue);
0624: }
0625:
0626: /**
0627: * @param bracketed True if the list is bounded by brackets instead of
0628: * parenthesis.
0629: */
0630: private ExpressionList parseList(boolean bracketed)
0631: throws IOException {
0632: int leftID;
0633: int rightID;
0634:
0635: if (!bracketed) {
0636: leftID = Token.LPAREN;
0637: rightID = Token.RPAREN;
0638: } else {
0639: leftID = Token.LBRACK;
0640: rightID = Token.RBRACK;
0641: }
0642:
0643: Token token = peek();
0644: SourceInfo info = token.getSourceInfo();
0645:
0646: if (token.getID() == leftID) {
0647: read(); // read the left paren
0648: token = peek();
0649: } else {
0650: if (!bracketed) {
0651: error("list.lparen.expected", token);
0652: } else {
0653: error("list.lbracket.expected", token);
0654: }
0655: }
0656:
0657: Vector exprs = new Vector(10, 0);
0658: boolean done = false;
0659:
0660: if (token.getID() == rightID) {
0661: // Empty list detected
0662: } else {
0663: Expression expr = null;
0664: while (true) {
0665: token = read();
0666:
0667: if (token.getID() == rightID) {
0668: error("list.premature.end", token);
0669: info = info.setEndPosition(token.getSourceInfo());
0670: done = true;
0671: break;
0672: }
0673:
0674: expr = parseExpression(token);
0675: exprs.addElement(expr);
0676:
0677: token = peek();
0678:
0679: if (token.getID() != Token.COMMA) {
0680: break;
0681: } else {
0682: token = read(); // read the comma
0683: }
0684: }
0685:
0686: if (!done && expr != null) {
0687: info = info.setEndPosition(expr.getSourceInfo());
0688: }
0689: }
0690:
0691: if (!done) {
0692: token = peek();
0693:
0694: if (token.getID() == rightID) {
0695: token = read(); // read the right paren
0696: info = info.setEndPosition(token.getSourceInfo());
0697: } else {
0698: if (!bracketed) {
0699: error("list.rparen.expected", token);
0700: } else {
0701: error("list.rbracket.expected", token);
0702: }
0703: }
0704: }
0705:
0706: Expression[] elements = new Expression[exprs.size()];
0707: exprs.copyInto(elements);
0708:
0709: return new ExpressionList(info, elements);
0710: }
0711:
0712: private Expression parseExpression() throws IOException {
0713: return parseExpression(read());
0714: }
0715:
0716: private Expression parseExpression(Token token) throws IOException {
0717: return parseOrExpression(token);
0718: }
0719:
0720: private Expression parseOrExpression(Token token)
0721: throws IOException {
0722: SourceInfo info = token.getSourceInfo();
0723: Expression expr = parseAndExpression(token);
0724:
0725: loop: while (true) {
0726: token = peek();
0727:
0728: if (token.getID() == Token.OR) {
0729: read();
0730: Expression right = parseAndExpression(read());
0731: info = info.setEndPosition(right.getSourceInfo());
0732: expr = new OrExpression(info, token, expr, right);
0733: } else {
0734: break loop;
0735: }
0736: }
0737:
0738: return expr;
0739: }
0740:
0741: private Expression parseAndExpression(Token token)
0742: throws IOException {
0743: SourceInfo info = token.getSourceInfo();
0744: Expression expr = parseEqualityExpression(token);
0745:
0746: loop: while (true) {
0747: token = peek();
0748:
0749: if (token.getID() == Token.AND) {
0750: read();
0751: Expression right = parseEqualityExpression(read());
0752: info = info.setEndPosition(right.getSourceInfo());
0753: expr = new AndExpression(info, token, expr, right);
0754: } else {
0755: break loop;
0756: }
0757: }
0758:
0759: return expr;
0760: }
0761:
0762: private Expression parseEqualityExpression(Token token)
0763: throws IOException {
0764:
0765: SourceInfo info = token.getSourceInfo();
0766: Expression expr = parseRelationalExpression(token);
0767:
0768: loop: while (true) {
0769: token = peek();
0770:
0771: switch (token.getID()) {
0772: case Token.ASSIGN:
0773: error("equality.misuse.assign", token);
0774: token = new Token(token.getSourceInfo(), Token.EQ);
0775: case Token.EQ:
0776: case Token.NE:
0777: read();
0778: Expression right = parseRelationalExpression(read());
0779: info = info.setEndPosition(right.getSourceInfo());
0780: expr = new RelationalExpression(info, token, expr,
0781: right);
0782: break;
0783: default:
0784: break loop;
0785: }
0786: }
0787:
0788: return expr;
0789: }
0790:
0791: private Expression parseRelationalExpression(Token token)
0792: throws IOException {
0793:
0794: SourceInfo info = token.getSourceInfo();
0795: Expression expr = parseConcatenateExpression(token);
0796:
0797: loop: while (true) {
0798: token = peek();
0799:
0800: switch (token.getID()) {
0801: case Token.LT:
0802: case Token.GT:
0803: case Token.LE:
0804: case Token.GE:
0805: read();
0806: Expression right = parseConcatenateExpression(read());
0807: info = info.setEndPosition(right.getSourceInfo());
0808: expr = new RelationalExpression(info, token, expr,
0809: right);
0810: break;
0811: case Token.ISA:
0812: read();
0813: TypeName typeName = parseTypeName();
0814: info = info.setEndPosition(typeName.getSourceInfo());
0815: expr = new RelationalExpression(info, token, expr,
0816: typeName);
0817: break;
0818: default:
0819: break loop;
0820: }
0821: }
0822:
0823: return expr;
0824: }
0825:
0826: private Expression parseConcatenateExpression(Token token)
0827: throws IOException {
0828:
0829: SourceInfo info = token.getSourceInfo();
0830: Expression expr = parseAdditiveExpression(token);
0831:
0832: loop: while (true) {
0833: token = peek();
0834:
0835: if (token.getID() == Token.CONCAT) {
0836: read();
0837: Expression right = parseAdditiveExpression(read());
0838: info = info.setEndPosition(right.getSourceInfo());
0839: expr = new ConcatenateExpression(info, token, expr,
0840: right);
0841: } else {
0842: break loop;
0843: }
0844: }
0845:
0846: return expr;
0847: }
0848:
0849: private Expression parseAdditiveExpression(Token token)
0850: throws IOException {
0851:
0852: SourceInfo info = token.getSourceInfo();
0853: Expression expr = parseMultiplicativeExpression(token);
0854:
0855: loop: while (true) {
0856: token = peek();
0857:
0858: switch (token.getID()) {
0859: case Token.PLUS:
0860: case Token.MINUS:
0861: read();
0862: Expression right = parseMultiplicativeExpression(read());
0863: info = info.setEndPosition(right.getSourceInfo());
0864: expr = new ArithmeticExpression(info, token, expr,
0865: right);
0866: break;
0867: default:
0868: break loop;
0869: }
0870: }
0871:
0872: return expr;
0873: }
0874:
0875: private Expression parseMultiplicativeExpression(Token token)
0876: throws IOException {
0877:
0878: SourceInfo info = token.getSourceInfo();
0879: Expression expr = parseUnaryExpression(token);
0880:
0881: loop: while (true) {
0882: token = peek();
0883:
0884: switch (token.getID()) {
0885: case Token.MULT:
0886: case Token.DIV:
0887: case Token.MOD:
0888: read();
0889: Expression right = parseUnaryExpression(read());
0890: info = info.setEndPosition(right.getSourceInfo());
0891: expr = new ArithmeticExpression(info, token, expr,
0892: right);
0893: break;
0894: default:
0895: break loop;
0896: }
0897: }
0898:
0899: return expr;
0900: }
0901:
0902: private Expression parseUnaryExpression(Token token)
0903: throws IOException {
0904: SourceInfo info;
0905: Expression expr;
0906:
0907: switch (token.getID()) {
0908: case Token.NOT:
0909: info = token.getSourceInfo();
0910: expr = parseUnaryExpression(read());
0911: info = info.setEndPosition(expr.getSourceInfo());
0912: return new NotExpression(info, expr);
0913: case Token.MINUS:
0914: info = token.getSourceInfo();
0915: expr = parseUnaryExpression(read());
0916: info = info.setEndPosition(expr.getSourceInfo());
0917: return new NegateExpression(info, expr);
0918: }
0919:
0920: return parseLookup(token);
0921: }
0922:
0923: private Expression parseLookup(Token token) throws IOException {
0924:
0925: SourceInfo info = token.getSourceInfo();
0926: Expression expr = parseFactor(token);
0927:
0928: while (true) {
0929: token = peek();
0930:
0931: if (token.getID() == Token.DOT) {
0932: // "dot" lookup i.e.: a.b
0933:
0934: Token dot = read(); // read the dot
0935:
0936: token = read();
0937:
0938: Name lookupName;
0939: SourceInfo nameInfo = token.getSourceInfo();
0940: if (token.getID() != Token.IDENT) {
0941: if (token.isReservedWord()) {
0942: error("lookup.reserved.word", token.getImage(),
0943: token);
0944: lookupName = new Name(nameInfo, token
0945: .getImage());
0946: } else {
0947: error("lookup.identifier.expected", token);
0948: lookupName = new Name(nameInfo, null);
0949: }
0950: } else {
0951: lookupName = new Name(nameInfo, token
0952: .getStringValue());
0953: info = info.setEndPosition(nameInfo);
0954: }
0955:
0956: expr = new Lookup(info, expr, dot, lookupName);
0957: } else if (token.getID() == Token.LBRACK) {
0958: // array lookup i.e.: a[b]
0959:
0960: Token lbrack = read(); // read the left bracket
0961:
0962: token = read();
0963:
0964: if (token.getID() == Token.RBRACK) {
0965: info = info.setEndPosition(token.getSourceInfo());
0966:
0967: error("lookup.empty.brackets", token);
0968:
0969: expr = new ArrayLookup(info, expr, lbrack,
0970: new Expression(info));
0971:
0972: continue;
0973: }
0974:
0975: Expression arrayLookup = parseExpression(token);
0976:
0977: token = peek();
0978:
0979: if (token.getID() == Token.RBRACK) {
0980: read(); // read the right bracket
0981: info = info.setEndPosition(token.getSourceInfo());
0982: } else {
0983: error("lookup.rbracket.expected", token);
0984: info = info.setEndPosition(arrayLookup
0985: .getSourceInfo());
0986: }
0987:
0988: expr = new ArrayLookup(info, expr, lbrack, arrayLookup);
0989: } else {
0990: break;
0991: }
0992: }
0993:
0994: return expr;
0995: }
0996:
0997: private Expression parseFactor(Token token) throws IOException {
0998: SourceInfo info = token.getSourceInfo();
0999: Token value;
1000:
1001: switch (token.getID()) {
1002: case Token.HASH:
1003: case Token.DOUBLE_HASH:
1004: return parseNewArrayExpression(token);
1005:
1006: case Token.LPAREN:
1007: Expression expr;
1008:
1009: token = peek();
1010: if (token.getID() == Token.RPAREN) {
1011: expr = null;
1012: } else {
1013: expr = parseExpression(read());
1014: }
1015:
1016: token = peek();
1017: if (token.getID() == Token.RPAREN) {
1018: read(); // read the right paren
1019: info = info.setEndPosition(token.getSourceInfo());
1020: } else {
1021: error("factor.rparen.expected", token);
1022: info = info.setEndPosition(expr.getSourceInfo());
1023: }
1024:
1025: if (expr == null) {
1026: error("factor.empty.parens", info);
1027: expr = new Expression(info);
1028: }
1029:
1030: return new ParenExpression(info, expr);
1031:
1032: case Token.NULL:
1033: return new NullLiteral(info);
1034:
1035: case Token.TRUE:
1036: return new BooleanLiteral(info, true);
1037:
1038: case Token.FALSE:
1039: return new BooleanLiteral(info, false);
1040:
1041: case Token.CALL:
1042: Name target = parseName();
1043: info.setEndPosition(target.getSourceInfo());
1044:
1045: ExpressionList list = parseList(false);
1046: info = info.setEndPosition(list.getSourceInfo());
1047:
1048: // Check if a block is being passed in the call.
1049: Block subParam = null;
1050: if (peek().getID() == Token.LBRACE) {
1051: subParam = parseBlock();
1052: info = info.setEndPosition(subParam.getSourceInfo());
1053: }
1054:
1055: return new TemplateCallExpression(info, target, list,
1056: subParam);
1057:
1058: case Token.NUMBER:
1059: if (token.getNumericType() == 0) {
1060: error("factor.number.invalid", token);
1061: }
1062:
1063: switch (token.getNumericType()) {
1064: case 1:
1065: return new NumberLiteral(info, token.getIntValue());
1066: case 2:
1067: return new NumberLiteral(info, token.getLongValue());
1068: case 3:
1069: return new NumberLiteral(info, token.getFloatValue());
1070: case 4:
1071: default:
1072: return new NumberLiteral(info, token.getDoubleValue());
1073: }
1074:
1075: case Token.STRING:
1076: return new StringLiteral(info, token.getStringValue());
1077:
1078: case Token.IDENT:
1079: FunctionCallExpression call = parseFunctionCallExpression(token);
1080: if (call != null) {
1081: return call;
1082: } else {
1083: return new VariableRef(info, token.getStringValue());
1084: }
1085:
1086: case Token.EOF:
1087: error("factor.expression.expected", token);
1088: break;
1089:
1090: case Token.RPAREN:
1091: error("factor.rparen.unmatched", token);
1092: break;
1093:
1094: case Token.RBRACE:
1095: error("factor.rbrace.unmatched", token);
1096: break;
1097:
1098: case Token.RBRACK:
1099: error("factor.rbracket.unmatched", token);
1100: break;
1101:
1102: case Token.ASSIGN:
1103: error("factor.illegal.assignment", token);
1104: break;
1105:
1106: case Token.DOTDOT:
1107: error("factor.misuse.dotdot", token);
1108: break;
1109:
1110: default:
1111: if (token.isReservedWord()) {
1112: error("factor.reserved.word", token.getImage(), token);
1113: } else {
1114: error("factor.unexpected.token", token);
1115: }
1116: break;
1117: }
1118:
1119: return new Expression(token.getSourceInfo());
1120: }
1121:
1122: private Expression parseNewArrayExpression(Token token)
1123: throws IOException {
1124:
1125: boolean associative = (token.getID() == Token.DOUBLE_HASH);
1126:
1127: SourceInfo info = token.getSourceInfo();
1128: ExpressionList list = parseList(false);
1129: info = info.setEndPosition(list.getSourceInfo());
1130: return new NewArrayExpression(info, list, associative);
1131: }
1132:
1133: // Special parse method in that it may return null if it couldn't parse
1134: // a FunctionCallExpression. Token passed in must be an identifier.
1135: private FunctionCallExpression parseFunctionCallExpression(
1136: Token token) throws IOException {
1137:
1138: SourceInfo info = token.getSourceInfo();
1139:
1140: // Search for pattern <ident> {<dot> <ident>} <lparen>
1141: Vector lookahead = new Vector();
1142: StringBuffer name = new StringBuffer(token.getStringValue());
1143: Name target = null;
1144:
1145: while (true) {
1146: token = read();
1147: lookahead.addElement(token);
1148:
1149: if (token.getID() == Token.DOT) {
1150: name.append('.');
1151: info = info.setEndPosition(token.getSourceInfo());
1152: } else if (token.getID() == Token.LPAREN) {
1153: target = new Name(info, name.toString());
1154: unread(token);
1155: break;
1156: } else {
1157: break;
1158: }
1159:
1160: token = read();
1161: lookahead.addElement(token);
1162:
1163: if (token.getID() == Token.IDENT) {
1164: name.append(token.getStringValue());
1165: info = info.setEndPosition(token.getSourceInfo());
1166: } else {
1167: break;
1168: }
1169: }
1170:
1171: if (target == null) {
1172: // Pattern not found, unread all lookahead tokens.
1173: for (int i = lookahead.size() - 1; i >= 0; --i) {
1174: unread((Token) lookahead.elementAt(i));
1175: }
1176: return null;
1177: }
1178:
1179: ExpressionList list = parseList(false);
1180: info = info.setEndPosition(list.getSourceInfo());
1181:
1182: // Check if a block is being passed in the call.
1183: Block subParam = null;
1184: if (peek().getID() == Token.LBRACE) {
1185: subParam = parseBlock();
1186: info = info.setEndPosition(subParam.getSourceInfo());
1187: }
1188:
1189: return new FunctionCallExpression(info, target, list, subParam);
1190: }
1191:
1192: /** Test program */
1193: public static void main(String[] arg) throws Exception {
1194: Tester.test(arg);
1195: }
1196:
1197: /**************************************************************************
1198: *
1199: * @author Brian S O'Neill
1200: * @version
1201: * <!--$$Revision:--> 64 <!-- $--> 36 <!-- $$JustDate:--> 5/31/01 <!-- $-->
1202: */
1203: private static class Tester implements ErrorListener {
1204: String mFilename;
1205:
1206: public static void test(String[] arg) throws Exception {
1207: new Tester(arg[0]);
1208: }
1209:
1210: public Tester(String filename) throws Exception {
1211: mFilename = filename;
1212: Reader file = new BufferedReader(new FileReader(filename));
1213: Scanner scanner = new Scanner(new SourceReader(file, "<%",
1214: "%>"));
1215: scanner.addErrorListener(this );
1216: Parser parser = new Parser(scanner);
1217: parser.addErrorListener(this );
1218: Template tree = parser.parse();
1219:
1220: if (tree != null) {
1221: TreePrinter printer = new TreePrinter(tree);
1222: printer.writeTo(System.out);
1223: }
1224: }
1225:
1226: public void compileError(ErrorEvent e) {
1227: System.out.println(e.getDetailedErrorMessage());
1228: }
1229: }
1230: }
|