0001: /*
0002: * Copyright (c) 1998 - 2005 Versant Corporation
0003: * All rights reserved. This program and the accompanying materials
0004: * are made available under the terms of the Eclipse Public License v1.0
0005: * which accompanies this distribution, and is available at
0006: * http://www.eclipse.org/legal/epl-v10.html
0007: *
0008: * Contributors:
0009: * Versant Corporation - initial API and implementation
0010: */
0011: package com.versant.core.jdo.tools.ant;
0012:
0013: import java.io.*;
0014: import java.util.ArrayList;
0015: import java.util.Iterator;
0016:
0017: /**
0018: * Use this class like this:
0019: *
0020: * SQLScriptParser shredder = new SQLScriptParser();
0021: * ArrayList list = shredder.parse(sql,true);
0022: * for (Iterator iter = list.iterator(); iter.hasNext();) {
0023: * SQLScriptPart scriptPart = (SQLScriptPart) iter.next();
0024: * System.out.println("start = "+ scriptPart.getStart());
0025: * System.out.println("end = "+ scriptPart.getEnd());
0026: * System.out.println( scriptPart.getSql());
0027: * }
0028: * @keep-all
0029: * SQLScriptParser is a sql lexer. Created with JFlex.
0030: * The tokens returned should comply with the sql Language Specification
0031: *
0032: *
0033: */
0034: public class SQLScriptParser {
0035:
0036: /** This character denotes the end of file */
0037: final public static int YYEOF = -1;
0038:
0039: /** initial size of the lookahead buffer */
0040: final private static int YY_BUFFERSIZE = 16384;
0041:
0042: /** lexical states */
0043: final public static int YYINITIAL = 0;
0044: final public static int COMMENT = 1;
0045:
0046: /**
0047: * Translates characters to character classes
0048: */
0049: final private static char[] yycmap = { 0, 0, 0, 0, 0, 0, 0, 0, 0,
0050: 4, 13, 0, 4, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0051: 0, 0, 0, 0, 4, 10, 6, 10, 8, 10, 10, 12, 9, 9, 11, 19, 9,
0052: 20, 17, 21, 16, 16, 7, 7, 7, 7, 7, 7, 7, 7, 9, 1, 10, 10,
0053: 10, 10, 10, 0, 15, 0, 0, 18, 0, 2, 0, 0, 0, 0, 0, 0, 0, 3,
0054: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 14, 9, 10, 5, 10, 0,
0055: 15, 0, 0, 18, 0, 2, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0,
0056: 0, 0, 0, 0, 0, 0, 0, 10, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0057: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0058: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0059: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0060: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0061: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0062: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
0063:
0064: /**
0065: * Translates a state to a row index in the transition table
0066: */
0067: final private static int yy_rowMap[] = { 0, 22, 44, 66, 88, 110,
0068: 66, 132, 154, 66, 66, 176, 198, 220, 242, 264, 286, 308,
0069: 330, 44, 352, 374, 154, 176, 66, 66, 396, 418, 440, 66,
0070: 462, 484, 308, 66, 66, 506, 176, 528, 550, 66, 572, 594,
0071: 506, 616, 550, 528, 66, 638 };
0072:
0073: /**
0074: * The packed transition table of the DFA (part 0)
0075: */
0076: final private static String yy_packed0 = "\1\3\1\4\1\5\1\3\1\6\2\7\1\10\1\11"
0077: + "\1\12\1\13\1\12\1\14\1\6\1\3\1\15\1\10"
0078: + "\1\16\1\3\1\13\1\17\1\20\13\21\1\22\11\21"
0079: + "\1\23\1\3\1\0\2\3\1\0\1\3\1\0\1\3"
0080: + "\6\0\3\3\1\0\1\3\31\0\1\3\1\0\1\3"
0081: + "\1\24\1\0\1\3\1\0\1\3\6\0\3\3\1\0"
0082: + "\1\3\7\0\1\6\10\0\1\6\17\0\1\10\10\0"
0083: + "\1\10\1\25\1\26\12\0\1\27\10\0\1\27\5\0"
0084: + "\14\30\1\31\1\32\1\33\7\30\1\3\1\0\2\3"
0085: + "\1\0\1\3\1\0\1\3\4\0\1\34\1\0\3\3"
0086: + "\1\0\1\3\12\0\1\25\10\0\1\25\31\0\1\35"
0087: + "\14\0\1\36\12\0\13\21\1\37\11\21\1\40\13\21"
0088: + "\1\41\11\21\1\42\13\21\1\43\11\21\1\40\7\0"
0089: + "\1\25\10\0\1\25\1\0\1\26\26\0\2\44\1\0"
0090: + "\14\30\1\45\1\32\1\33\7\30\14\46\1\47\1\50"
0091: + "\1\51\1\46\1\52\5\46\15\35\1\0\10\35\13\21"
0092: + "\1\37\11\21\1\0\13\21\1\0\11\21\1\40\7\0"
0093: + "\1\53\10\0\1\53\5\0\14\46\1\47\1\50\1\51"
0094: + "\1\46\1\54\5\46\14\55\1\47\1\0\2\55\1\0"
0095: + "\5\55\14\46\1\56\1\50\1\51\1\46\1\54\5\46"
0096: + "\14\54\1\57\1\50\1\60\1\54\1\52\21\54\1\0"
0097: + "\1\50\1\60\24\54\1\50\1\60\7\54";
0098:
0099: /**
0100: * The transition table of the DFA
0101: */
0102: final private static int yytrans[] = yy_unpack();
0103:
0104: /* error codes */
0105: final private static int YY_UNKNOWN_ERROR = 0;
0106: final private static int YY_ILLEGAL_STATE = 1;
0107: final private static int YY_NO_MATCH = 2;
0108: final private static int YY_PUSHBACK_2BIG = 3;
0109:
0110: /* error messages for the codes above */
0111: final private static String YY_ERROR_MSG[] = {
0112: "Unkown internal scanner error",
0113: "Internal error: unknown state",
0114: "Error: could not match input",
0115: "Error: pushback value was too large" };
0116:
0117: /**
0118: * YY_ATTRIBUTE[aState] contains the attributes of state <code>aState</code>
0119: */
0120: private final static byte YY_ATTRIBUTE[] = { 1, 1, 1, 9, 1, 1, 9,
0121: 1, 1, 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 9, 9, 0,
0122: 0, 1, 9, 0, 0, 0, 9, 9, 0, 1, 0, 1, 9, 0, 0, 1, 0, 0, 1, 9,
0123: 0 };
0124:
0125: /** the input device */
0126: private java.io.Reader yy_reader;
0127:
0128: /** the current state of the DFA */
0129: private int yy_state;
0130:
0131: /** the current lexical state */
0132: private int yy_lexical_state = YYINITIAL;
0133:
0134: /** this buffer contains the current text to be matched and is
0135: the source of the yytext() string */
0136: private char yy_buffer[] = new char[YY_BUFFERSIZE];
0137:
0138: /** the textposition at the last accepting state */
0139: private int yy_markedPos;
0140:
0141: /** the textposition at the last state to be included in yytext */
0142: private int yy_pushbackPos;
0143:
0144: /** the current text position in the buffer */
0145: private int yy_currentPos;
0146:
0147: /** startRead marks the beginning of the yytext() string in the buffer */
0148: private int yy_startRead;
0149:
0150: /** endRead marks the last character in the buffer, that has been read
0151: from input */
0152: private int yy_endRead;
0153:
0154: /** number of newlines encountered up to the start of the matched text */
0155: private int yyline;
0156:
0157: /** the number of characters up to the start of the matched text */
0158: private int yychar;
0159:
0160: /**
0161: * the number of characters from the last newline up to the start of the
0162: * matched text
0163: */
0164: private int yycolumn;
0165:
0166: /**
0167: * yy_atBOL == true <=> the scanner is currently at the beginning of a line
0168: */
0169: private boolean yy_atBOL = true;
0170:
0171: /** yy_atEOF == true <=> the scanner is at the EOF */
0172: private boolean yy_atEOF;
0173:
0174: /* user code: */
0175: private int lastToken;
0176: private int nextState = YYINITIAL;
0177: private StringBuffer commentBuffer = new StringBuffer();
0178: private int commentNestCount = 0;
0179: private int commentStartLine = 0;
0180: private int commentStartChar = 0;
0181:
0182: /**
0183: * next Token method that allows you to control if whitespace and comments are
0184: * returned as tokens.
0185: */
0186: public Token getNextToken(boolean returnComments,
0187: boolean returnWhiteSpace) throws IOException {
0188: Token t = getNextToken();
0189: while (t != null
0190: && ((!returnWhiteSpace && t.isWhiteSpace()) || (!returnComments && t
0191: .isComment()))) {
0192: t = getNextToken();
0193: }
0194: return (t);
0195: }
0196:
0197: public SQLScriptParser() {
0198: }
0199:
0200: /**
0201: * Prints out tokens from a file or System.in.
0202: * If no arguments are given, System.in will be used for input.
0203: * If more arguments are given, the first argument will be used as
0204: * the name of the file to use as input
0205: *
0206: * @param args program arguments, of which the first is a filename
0207: */
0208: public static void main(String[] args) {
0209: String sql = "123456789 ;-- kdlfhjkl; sdfghjdl;fkhkdfjghl fghldfkklh flhkdfhj \n"
0210: + " lkh"
0211: + "CREATE TABLE temp_abstract1_a (\n"
0212: + " ';;;;;\\n'"
0213: + " abstract1_id INTEGER NOT NULL, /* <pk> */\n"
0214: + " abs1 VARCHAR(25), /* abs1 */\n"
0215: + " jdo_class INTEGER NOT NULL, /* <class-id> */\n"
0216: + " jdo_version SMALLINT NOT NULL, /* <opt-lock> */\n"
0217: + " abs2 VARCHAR(190), /* Abstract2.abs2 */\n"
0218: + " conc1 VARCHAR(190), /* Concrete1.conc1 */\n"
0219: + " conc2 VARCHAR(190) /* Concrete2.conc2 */\n"
0220: + ");\n"
0221: + "INSERT INTO temp_abstract1_a (abstract1_id, abs1, jdo_class, jdo_version, abs2, conc1, conc2) \n"
0222: + "SELECT abstract1_id, \n"
0223: + " CAST(abs1 AS VARCHAR(25)), \n"
0224: + " jdo_class, \n"
0225: + " jdo_version, \n"
0226: + " abs2, \n"
0227: + " conc1, \n"
0228: + " conc2\n"
0229: + " FROM abstract1;\n"
0230: + "DROP TABLE abstract1;\n"
0231: + "CREATE TABLE abstract1 (\n"
0232: + " abstract1_id INTEGER NOT NULL, /* <pk> */\n"
0233: + " abs1 VARCHAR(25), /* abs1 */\n"
0234: + " jdo_class INTEGER NOT NULL, /* <class-id> */\n"
0235: + " jdo_version SMALLINT NOT NULL, /* <opt-lock> */\n"
0236: + " abs2 VARCHAR(190), /* Abstract2.abs2 */\n"
0237: + " conc1 VARCHAR(190), /* Concrete1.conc1 */\n"
0238: + " conc2 VARCHAR(190), /* Concrete2.conc2 */\n"
0239: + " CONSTRAINT pk_abstract1 PRIMARY KEY (abstract1_id)\n"
0240: + ");\n"
0241: + "INSERT INTO abstract1 (abstract1_id, abs1, jdo_class, jdo_version, abs2, conc1, conc2) \n"
0242: + "SELECT abstract1_id, \n"
0243: + " abs1, \n"
0244: + " jdo_class, \n"
0245: + " jdo_version, \n"
0246: + " abs2, \n"
0247: + " conc1, \n"
0248: + " conc2\n"
0249: +
0250:
0251: " FROM temp_abstract1_a;\n"
0252: + "DROP TABLE temp_abstract1_a;\n"
0253: + "\n"
0254: + "ALTER TABLE emp_super_person3 ADD CONSTRAINT ref_emp_super_person3_person FOREIGN KEY (person_id) REFERENCES person(person_id);\n"
0255: + "\n"
0256: + "ALTER TABLE person3_person ADD CONSTRAINT ref_person3_person_person FOREIGN KEY (person_id) REFERENCES person(person_id);\n"
0257: + "";
0258:
0259: try {
0260: SQLScriptParser shredder = new SQLScriptParser();
0261: ArrayList list = shredder.parse(sql, true);
0262: for (Iterator iter = list.iterator(); iter.hasNext();) {
0263: SQLScriptPart scriptPart = (SQLScriptPart) iter.next();
0264: System.out.println("start = " + scriptPart.getStart());
0265: System.out.println("end = " + scriptPart.getEnd());
0266: System.out.println(scriptPart.getSql());
0267: }
0268:
0269: } catch (IOException e) {
0270: System.out.println(e.getMessage());
0271: }
0272: }
0273:
0274: public ArrayList parse(String sql, boolean eraseNewLine)
0275: throws IOException {
0276: StringReader in = new StringReader(sql + "\n;");
0277: return parse(in, eraseNewLine);
0278: }
0279:
0280: private ArrayList parse(Reader sql, boolean eraseNewLine)
0281: throws IOException {
0282: SQLScriptParser shredder = new SQLScriptParser(sql);
0283: Token t;
0284: boolean first = true;
0285: ArrayList list = new ArrayList();
0286: SQLScriptPart part = new SQLScriptPart();
0287: while ((t = shredder.getNextToken()) != null) {
0288:
0289: switch (t.getID()) {
0290: case Token.WHITE_SPACE:
0291: if (!first) {
0292: if (eraseNewLine) {
0293: part.addSql(' ');
0294: } else {
0295: part.addSql(t.getContents());
0296: }
0297: }
0298: break;
0299:
0300: case Token.COMMENT_END_OF_LINE:
0301: case Token.COMMENT_TRADITIONAL:
0302: break;
0303:
0304: case Token.RESERVED_WORD:
0305: if (!first) {
0306: list.add(part);
0307: part = new SQLScriptPart();
0308: first = true;
0309: }
0310: break;
0311:
0312: default:
0313: if (first) {
0314: part.setStart(t.getCharBegin());
0315: first = false;
0316: }
0317: part.addSql(t.getContents());
0318: part.setEnd(t.getCharEnd());
0319: break;
0320: }
0321: }
0322:
0323: return list;
0324: }
0325:
0326: /**
0327: * @keep-all
0328: */
0329: public static class SQLScriptPart {
0330: private int start;
0331: private int end;
0332: private StringBuffer sql = new StringBuffer();
0333:
0334: public int getEnd() {
0335: return end;
0336: }
0337:
0338: public void setEnd(int end) {
0339: this .end = end;
0340: }
0341:
0342: public String getSql() {
0343: return sql.toString().trim();
0344: }
0345:
0346: public void addSql(String sql) {
0347: this .sql.append(sql);
0348: }
0349:
0350: public void addSql(char sql) {
0351: this .sql.append(sql);
0352: }
0353:
0354: public int getStart() {
0355: return start;
0356: }
0357:
0358: public void setStart(int start) {
0359: this .start = start;
0360: }
0361: }
0362:
0363: /**
0364: * @keep-all
0365: * A Token is a token that is returned by a lexer that is lexing an SQL
0366: * source file. It has several attributes describing the token:
0367: * The type of token, the text of the token, the line number on which it
0368: * occurred, the number of characters into the input at which it started, and
0369: * similarly, the number of characters into the input at which it ended. <br>
0370: */
0371: public static class Token {
0372: /**
0373: * The state of the tokenizer is undefined.
0374: */
0375: public static final int UNDEFINED_STATE = -1;
0376:
0377: /**
0378: * The initial state of the tokenizer.
0379: * Anytime the tokenizer returns to this state,
0380: * the tokenizer could be restarted from that point
0381: * with side effects.
0382: */
0383: public static final int INITIAL_STATE = 0;
0384: /**
0385: * A reserved word (keyword)
0386: */
0387: public final static int RESERVED_WORD = 0x100;
0388:
0389: /**
0390: * A variable, name, or other identifier
0391: */
0392: public final static int IDENTIFIER = 0x200;
0393:
0394: /**
0395: * A string literal
0396: */
0397: public final static int LITERAL_STRING = 0x300;
0398: /**
0399: * A bit-string
0400: */
0401: public final static int LITERAL_BIT_STRING = 0x310;
0402: /**
0403: * An integer
0404: */
0405: public final static int LITERAL_INTEGER = 0x320;
0406: /**
0407: * A floating point
0408: */
0409: public final static int LITERAL_FLOAT = 0x330;
0410:
0411: /**
0412: * A separator
0413: */
0414: public final static int SEPARATOR = 0x400;
0415:
0416: /**
0417: * A separator
0418: */
0419: public final static int DOT_SEPARATOR = 0x410;
0420:
0421: /**
0422: * An operator
0423: */
0424: public final static int OPERATOR = 0x500;
0425:
0426: /**
0427: * C style comment, (except possibly nested)
0428: */
0429: public final static int COMMENT_TRADITIONAL = 0xD00;
0430:
0431: /**
0432: * a -- to end of line comment.
0433: */
0434: public final static int COMMENT_END_OF_LINE = 0xD10;
0435:
0436: /**
0437: * White space
0438: */
0439: public final static int WHITE_SPACE = 0xE00;
0440:
0441: /**
0442: * An error
0443: */
0444: public final static int ERROR = 0xF00;
0445: /**
0446: * An comment start embedded in an operator
0447: */
0448: public final static int ERROR_UNCLOSED_COMMENT = 0xF02;
0449: /**
0450: * An comment start embedded in an operator
0451: */
0452: public final static int ERROR_UNCLOSED_STRING = 0xF03;
0453: /**
0454: * An comment start embedded in an operator
0455: */
0456: public final static int ERROR_UNCLOSED_BIT_STRING = 0xF04;
0457: /**
0458: * An comment start embedded in an operator
0459: */
0460: public final static int ERROR_BAD_BIT_STRING = 0xF05;
0461:
0462: private int ID;
0463: private String contents;
0464: private int lineNumber;
0465: private int charBegin;
0466: private int charEnd;
0467: private int state;
0468:
0469: /**
0470: * Create a new token.
0471: * The constructor is typically called by the lexer
0472: *
0473: * @param ID the id number of the token
0474: * @param contents A string representing the text of the token
0475: * @param lineNumber the line number of the input on which this token started
0476: * @param charBegin the offset into the input in characters at which this token started
0477: * @param charEnd the offset into the input in characters at which this token ended
0478: */
0479: public Token(int ID, String contents, int lineNumber,
0480: int charBegin, int charEnd) {
0481: this (ID, contents, lineNumber, charBegin, charEnd,
0482: Token.UNDEFINED_STATE);
0483: }
0484:
0485: /**
0486: * Create a new token.
0487: * The constructor is typically called by the lexer
0488: *
0489: * @param ID the id number of the token
0490: * @param contents A string representing the text of the token
0491: * @param lineNumber the line number of the input on which this token started
0492: * @param charBegin the offset into the input in characters at which this token started
0493: * @param charEnd the offset into the input in characters at which this token ended
0494: * @param state the state the tokenizer is in after returning this token.
0495: */
0496: public Token(int ID, String contents, int lineNumber,
0497: int charBegin, int charEnd, int state) {
0498: this .ID = ID;
0499: this .contents = new String(contents);
0500: this .lineNumber = lineNumber;
0501: this .charBegin = charBegin;
0502: this .charEnd = charEnd;
0503: this .state = state;
0504: }
0505:
0506: /**
0507: * Get an integer representing the state the tokenizer is in after
0508: * returning this token.
0509: * Those who are interested in incremental tokenizing for performance
0510: * reasons will want to use this method to figure out where the tokenizer
0511: * may be restarted. The tokenizer starts in Token.INITIAL_STATE, so
0512: * any time that it reports that it has returned to this state, the
0513: * tokenizer may be restarted from there.
0514: */
0515: public int getState() {
0516: return state;
0517: }
0518:
0519: /**
0520: * get the ID number of this token
0521: *
0522: * @return the id number of the token
0523: */
0524: public int getID() {
0525: return ID;
0526: }
0527:
0528: /**
0529: * get the contents of this token
0530: *
0531: * @return A string representing the text of the token
0532: */
0533: public String getContents() {
0534: return (new String(contents));
0535: }
0536:
0537: /**
0538: * get the line number of the input on which this token started
0539: *
0540: * @return the line number of the input on which this token started
0541: */
0542: public int getLineNumber() {
0543: return lineNumber;
0544: }
0545:
0546: /**
0547: * get the offset into the input in characters at which this token started
0548: *
0549: * @return the offset into the input in characters at which this token started
0550: */
0551: public int getCharBegin() {
0552: return charBegin;
0553: }
0554:
0555: /**
0556: * get the offset into the input in characters at which this token ended
0557: *
0558: * @return the offset into the input in characters at which this token ended
0559: */
0560: public int getCharEnd() {
0561: return charEnd;
0562: }
0563:
0564: /**
0565: * Checks this token to see if it is a reserved word.
0566: * Reserved words are explained in <A Href=http://java.sun.com/docs/books/jls/html/>Java
0567: * Language Specification</A>.
0568: *
0569: * @return true if this token is a reserved word, false otherwise
0570: */
0571: public boolean isReservedWord() {
0572: return ((ID >> 8) == 0x1);
0573: }
0574:
0575: /**
0576: * Checks this token to see if it is an identifier.
0577: * Identifiers are explained in <A Href=http://java.sun.com/docs/books/jls/html/>Java
0578: * Language Specification</A>.
0579: *
0580: * @return true if this token is an identifier, false otherwise
0581: */
0582: public boolean isIdentifier() {
0583: return ((ID >> 8) == 0x2);
0584: }
0585:
0586: /**
0587: * Checks this token to see if it is a literal.
0588: * Literals are explained in <A Href=http://java.sun.com/docs/books/jls/html/>Java
0589: * Language Specification</A>.
0590: *
0591: * @return true if this token is a literal, false otherwise
0592: */
0593: public boolean isLiteral() {
0594: return ((ID >> 8) == 0x3);
0595: }
0596:
0597: /**
0598: * Checks this token to see if it is a Separator.
0599: * Separators are explained in <A Href=http://java.sun.com/docs/books/jls/html/>Java
0600: * Language Specification</A>.
0601: *
0602: * @return true if this token is a Separator, false otherwise
0603: */
0604: public boolean isSeparator() {
0605: return ((ID >> 8) == 0x4);
0606: }
0607:
0608: /**
0609: * Checks this token to see if it is a Operator.
0610: * Operators are explained in <A Href=http://java.sun.com/docs/books/jls/html/>Java
0611: * Language Specification</A>.
0612: *
0613: * @return true if this token is a Operator, false otherwise
0614: */
0615: public boolean isOperator() {
0616: return ((ID >> 8) == 0x5);
0617: }
0618:
0619: /**
0620: * Checks this token to see if it is a comment.
0621: *
0622: * @return true if this token is a comment, false otherwise
0623: */
0624: public boolean isComment() {
0625: return ((ID >> 8) == 0xD);
0626: }
0627:
0628: /**
0629: * Checks this token to see if it is White Space.
0630: * Usually tabs, line breaks, form feed, spaces, etc.
0631: *
0632: * @return true if this token is White Space, false otherwise
0633: */
0634: public boolean isWhiteSpace() {
0635: return ((ID >> 8) == 0xE);
0636: }
0637:
0638: /**
0639: * Checks this token to see if it is an Error.
0640: * Unfinished comments, numbers that are too big, unclosed strings, etc.
0641: *
0642: * @return true if this token is an Error, false otherwise
0643: */
0644: public boolean isError() {
0645: return ((ID >> 8) == 0xF);
0646: }
0647:
0648: /**
0649: * A description of this token. The description should
0650: * be appropriate for syntax highlighting. For example
0651: * "comment" is returned for a comment.
0652: *
0653: * @return a description of this token.
0654: */
0655: public String getDescription() {
0656: if (isReservedWord()) {
0657: return ("reservedWord");
0658: } else if (isIdentifier()) {
0659: return ("identifier");
0660: } else if (isLiteral()) {
0661: return ("literal");
0662: } else if (isSeparator()) {
0663: return ("separator");
0664: } else if (isOperator()) {
0665: return ("operator");
0666: } else if (isComment()) {
0667: return ("comment");
0668: } else if (isWhiteSpace()) {
0669: return ("whitespace");
0670: } else if (isError()) {
0671: return ("error");
0672: } else {
0673: return ("unknown");
0674: }
0675: }
0676:
0677: /**
0678: * get a String that explains the error, if this token is an error.
0679: *
0680: * @return a String that explains the error, if this token is an error, null otherwise.
0681: */
0682: public String errorString() {
0683: String s;
0684: if (isError()) {
0685: s = "Error on line " + lineNumber + ": ";
0686: switch (ID) {
0687: case ERROR:
0688: s += "Unexpected token: " + contents;
0689: break;
0690: case ERROR_UNCLOSED_COMMENT:
0691: s += "Unclosed comment: " + contents;
0692: break;
0693: case ERROR_UNCLOSED_STRING:
0694: s += "Unclosed string literal: " + contents;
0695: break;
0696: case ERROR_UNCLOSED_BIT_STRING:
0697: s += "Unclosed bit-string literal: " + contents;
0698: break;
0699: case ERROR_BAD_BIT_STRING:
0700: s += "Bit-strings can only contain 0 and 1: "
0701: + contents;
0702: break;
0703: }
0704:
0705: } else {
0706: s = null;
0707: }
0708: return (s);
0709: }
0710:
0711: /**
0712: * get a representation of this token as a human readable string.
0713: * The format of this string is subject to change and should only be used
0714: * for debugging purposes.
0715: *
0716: * @return a string representation of this token
0717: */
0718: public String toString() {
0719: return ("Token #" + Integer.toHexString(ID) + ": "
0720: + getDescription() + " Line " + lineNumber
0721: + " from " + charBegin + " to " + charEnd + " : " + contents);
0722: }
0723: }
0724:
0725: /**
0726: * Closes the current input stream, and resets the scanner to read from a new input stream.
0727: * All internal variables are reset, the old input stream cannot be reused
0728: * (content of the internal buffer is discarded and lost).
0729: * The lexical state is set to the initial state.
0730: * Subsequent tokens read from the lexer will start with the line, char, and column
0731: * values given here.
0732: *
0733: * @param reader The new input.
0734: * @param yyline The line number of the first token.
0735: * @param yychar The position (relative to the start of the stream) of the first token.
0736: * @param yycolumn The position (relative to the line) of the first token.
0737: * @throws IOException if an IOExecption occurs while switching readers.
0738: */
0739: public void reset(java.io.Reader reader, int yyline, int yychar,
0740: int yycolumn) throws IOException {
0741: yyreset(reader);
0742: this .yyline = yyline;
0743: this .yychar = yychar;
0744: this .yycolumn = yycolumn;
0745: }
0746:
0747: public void setReader(java.io.Reader in) {
0748: this .yy_reader = in;
0749: }
0750:
0751: /**
0752: * Creates a new scanner
0753: * There is also a java.io.InputStream version of this constructor.
0754: *
0755: * @param in the java.io.Reader to read input from.
0756: */
0757: public SQLScriptParser(java.io.Reader in) {
0758: this .yy_reader = in;
0759: }
0760:
0761: /**
0762: * Creates a new scanner.
0763: * There is also java.io.Reader version of this constructor.
0764: *
0765: * @param in the java.io.Inputstream to read input from.
0766: */
0767: public SQLScriptParser(java.io.InputStream in) {
0768: this (new java.io.InputStreamReader(in));
0769: }
0770:
0771: /**
0772: * Unpacks the split, compressed DFA transition table.
0773: *
0774: * @return the unpacked transition table
0775: */
0776: private static int[] yy_unpack() {
0777: int[] trans = new int[660];
0778: int offset = 0;
0779: offset = yy_unpack(yy_packed0, offset, trans);
0780: return trans;
0781: }
0782:
0783: /**
0784: * Unpacks the compressed DFA transition table.
0785: *
0786: * @param packed the packed transition table
0787: * @return the index of the last entry
0788: */
0789: private static int yy_unpack(String packed, int offset, int[] trans) {
0790: int i = 0; /* index in packed string */
0791: int j = offset; /* index in unpacked array */
0792: int l = packed.length();
0793: while (i < l) {
0794: int count = packed.charAt(i++);
0795: int value = packed.charAt(i++);
0796: value--;
0797: do
0798: trans[j++] = value;
0799: while (--count > 0);
0800: }
0801: return j;
0802: }
0803:
0804: /**
0805: * Refills the input buffer.
0806: *
0807: * @return <code>false</code>, iff there was new input.
0808: *
0809: * @exception IOException if any I/O-Error occurs
0810: */
0811: private boolean yy_refill() throws java.io.IOException {
0812:
0813: /* first: make room (if you can) */
0814: if (yy_startRead > 0) {
0815: System.arraycopy(yy_buffer, yy_startRead, yy_buffer, 0,
0816: yy_endRead - yy_startRead);
0817:
0818: /* translate stored positions */
0819: yy_endRead -= yy_startRead;
0820: yy_currentPos -= yy_startRead;
0821: yy_markedPos -= yy_startRead;
0822: yy_pushbackPos -= yy_startRead;
0823: yy_startRead = 0;
0824: }
0825:
0826: /* is the buffer big enough? */
0827: if (yy_currentPos >= yy_buffer.length) {
0828: /* if not: blow it up */
0829: char newBuffer[] = new char[yy_currentPos * 2];
0830: System.arraycopy(yy_buffer, 0, newBuffer, 0,
0831: yy_buffer.length);
0832: yy_buffer = newBuffer;
0833: }
0834:
0835: /* finally: fill the buffer with new input */
0836: int numRead = yy_reader.read(yy_buffer, yy_endRead,
0837: yy_buffer.length - yy_endRead);
0838:
0839: if (numRead < 0) {
0840: return true;
0841: } else {
0842: yy_endRead += numRead;
0843: return false;
0844: }
0845: }
0846:
0847: /**
0848: * Closes the input stream.
0849: */
0850: final public void yyclose() throws java.io.IOException {
0851: yy_atEOF = true; /* indicate end of file */
0852: yy_endRead = yy_startRead; /* invalidate buffer */
0853:
0854: if (yy_reader != null)
0855: yy_reader.close();
0856: }
0857:
0858: /**
0859: * Closes the current stream, and resets the
0860: * scanner to read from a new input stream.
0861: *
0862: * All internal variables are reset, the old input stream
0863: * <b>cannot</b> be reused (internal buffer is discarded and lost).
0864: * Lexical state is set to <tt>YY_INITIAL</tt>.
0865: *
0866: * @param reader the new input stream
0867: */
0868: final public void yyreset(java.io.Reader reader)
0869: throws java.io.IOException {
0870: yyclose();
0871: yy_reader = reader;
0872: yy_atBOL = true;
0873: yy_atEOF = false;
0874: yy_endRead = yy_startRead = 0;
0875: yy_currentPos = yy_markedPos = yy_pushbackPos = 0;
0876: yyline = yychar = yycolumn = 0;
0877: yy_lexical_state = YYINITIAL;
0878: }
0879:
0880: /**
0881: * Returns the current lexical state.
0882: */
0883: final public int yystate() {
0884: return yy_lexical_state;
0885: }
0886:
0887: /**
0888: * Enters a new lexical state
0889: *
0890: * @param newState the new lexical state
0891: */
0892: final public void yybegin(int newState) {
0893: yy_lexical_state = newState;
0894: }
0895:
0896: /**
0897: * Returns the text matched by the current regular expression.
0898: */
0899: final public String yytext() {
0900: return new String(yy_buffer, yy_startRead, yy_markedPos
0901: - yy_startRead);
0902: }
0903:
0904: /**
0905: * Returns the character at position <tt>pos</tt> from the
0906: * matched text.
0907: *
0908: * It is equivalent to yytext().charAt(pos), but faster
0909: *
0910: * @param pos the position of the character to fetch.
0911: * A value from 0 to yylength()-1.
0912: *
0913: * @return the character at position pos
0914: */
0915: final public char yycharat(int pos) {
0916: return yy_buffer[yy_startRead + pos];
0917: }
0918:
0919: /**
0920: * Returns the length of the matched text region.
0921: */
0922: final public int yylength() {
0923: return yy_markedPos - yy_startRead;
0924: }
0925:
0926: /**
0927: * Reports an error that occured while scanning.
0928: *
0929: * In a wellformed scanner (no or only correct usage of
0930: * yypushback(int) and a match-all fallback rule) this method
0931: * will only be called with things that "Can't Possibly Happen".
0932: * If this method is called, something is seriously wrong
0933: * (e.g. a JFlex bug producing a faulty scanner etc.).
0934: *
0935: * Usual syntax/scanner level error handling should be done
0936: * in error fallback rules.
0937: *
0938: * @param errorCode the code of the errormessage to display
0939: */
0940: private void yy_ScanError(int errorCode) {
0941: String message;
0942: try {
0943: message = YY_ERROR_MSG[errorCode];
0944: } catch (ArrayIndexOutOfBoundsException e) {
0945: message = YY_ERROR_MSG[YY_UNKNOWN_ERROR];
0946: }
0947:
0948: throw new Error(message);
0949: }
0950:
0951: /**
0952: * Pushes the specified amount of characters back into the input stream.
0953: *
0954: * They will be read again by then next call of the scanning method
0955: *
0956: * @param number the number of characters to be read again.
0957: * This number must not be greater than yylength()!
0958: */
0959: private void yypushback(int number) {
0960: if (number > yylength())
0961: yy_ScanError(YY_PUSHBACK_2BIG);
0962:
0963: yy_markedPos -= number;
0964: }
0965:
0966: /**
0967: * Resumes scanning until the next regular expression is matched,
0968: * the end of input is encountered or an I/O-Error occurs.
0969: *
0970: * @return the next token
0971: * @exception IOException if any I/O-Error occurs
0972: */
0973: public Token getNextToken() throws java.io.IOException {
0974: int yy_input;
0975: int yy_action;
0976:
0977: // cached fields:
0978: int yy_currentPos_l;
0979: int yy_startRead_l;
0980: int yy_markedPos_l;
0981: int yy_endRead_l = yy_endRead;
0982: char[] yy_buffer_l = yy_buffer;
0983: char[] yycmap_l = yycmap;
0984:
0985: int[] yytrans_l = yytrans;
0986: int[] yy_rowMap_l = yy_rowMap;
0987: byte[] yy_attr_l = YY_ATTRIBUTE;
0988:
0989: while (true) {
0990: yy_markedPos_l = yy_markedPos;
0991:
0992: yychar += yy_markedPos_l - yy_startRead;
0993:
0994: boolean yy_r = false;
0995: for (yy_currentPos_l = yy_startRead; yy_currentPos_l < yy_markedPos_l; yy_currentPos_l++) {
0996: switch (yy_buffer_l[yy_currentPos_l]) {
0997: case '\u000B':
0998: case '\u000C':
0999: case '\u0085':
1000: case '\u2028':
1001: case '\u2029':
1002: yyline++;
1003: yy_r = false;
1004: break;
1005: case '\r':
1006: yyline++;
1007: yy_r = true;
1008: break;
1009: case '\n':
1010: if (yy_r)
1011: yy_r = false;
1012: else {
1013: yyline++;
1014: }
1015: break;
1016: default:
1017: yy_r = false;
1018: }
1019: }
1020:
1021: if (yy_r) {
1022: // peek one character ahead if it is \n (if we have counted one line too much)
1023: boolean yy_peek;
1024: if (yy_markedPos_l < yy_endRead_l)
1025: yy_peek = yy_buffer_l[yy_markedPos_l] == '\n';
1026: else if (yy_atEOF)
1027: yy_peek = false;
1028: else {
1029: boolean eof = yy_refill();
1030: yy_markedPos_l = yy_markedPos;
1031: yy_buffer_l = yy_buffer;
1032: if (eof)
1033: yy_peek = false;
1034: else
1035: yy_peek = yy_buffer_l[yy_markedPos_l] == '\n';
1036: }
1037: if (yy_peek)
1038: yyline--;
1039: }
1040: yy_action = -1;
1041:
1042: yy_startRead_l = yy_currentPos_l = yy_currentPos = yy_startRead = yy_markedPos_l;
1043:
1044: yy_state = yy_lexical_state;
1045:
1046: yy_forAction: {
1047: while (true) {
1048:
1049: if (yy_currentPos_l < yy_endRead_l)
1050: yy_input = yy_buffer_l[yy_currentPos_l++];
1051: else if (yy_atEOF) {
1052: yy_input = YYEOF;
1053: break yy_forAction;
1054: } else {
1055: // store back cached positions
1056: yy_currentPos = yy_currentPos_l;
1057: yy_markedPos = yy_markedPos_l;
1058: boolean eof = yy_refill();
1059: // get translated positions and possibly new buffer
1060: yy_currentPos_l = yy_currentPos;
1061: yy_markedPos_l = yy_markedPos;
1062: yy_buffer_l = yy_buffer;
1063: yy_endRead_l = yy_endRead;
1064: if (eof) {
1065: yy_input = YYEOF;
1066: break yy_forAction;
1067: } else {
1068: yy_input = yy_buffer_l[yy_currentPos_l++];
1069: }
1070: }
1071: int yy_next = yytrans_l[yy_rowMap_l[yy_state]
1072: + yycmap_l[yy_input]];
1073: if (yy_next == -1)
1074: break yy_forAction;
1075: yy_state = yy_next;
1076:
1077: int yy_attributes = yy_attr_l[yy_state];
1078: if ((yy_attributes & 1) == 1) {
1079: yy_action = yy_state;
1080: yy_markedPos_l = yy_currentPos_l;
1081: if ((yy_attributes & 8) == 8)
1082: break yy_forAction;
1083: }
1084:
1085: }
1086: }
1087:
1088: // store back cached position
1089: yy_markedPos = yy_markedPos_l;
1090:
1091: switch (yy_action) {
1092:
1093: case 6:
1094: case 11:
1095: case 17: {
1096: nextState = YYINITIAL;
1097: lastToken = Token.ERROR;
1098: String text = yytext();
1099: Token t = (new Token(lastToken, text, yyline, yychar,
1100: yychar + text.length(), nextState));
1101: yybegin(nextState);
1102: return (t);
1103: }
1104: case 49:
1105: break;
1106: case 46: {
1107: nextState = YYINITIAL;
1108: lastToken = Token.LITERAL_BIT_STRING;
1109: String text = yytext();
1110: Token t = (new Token(lastToken, text, yyline, yychar,
1111: yychar + text.length(), nextState));
1112: yybegin(nextState);
1113: return (t);
1114: }
1115: case 50:
1116: break;
1117: case 8:
1118: case 10:
1119: case 14:
1120: case 15: {
1121: nextState = YYINITIAL;
1122: lastToken = Token.OPERATOR;
1123: String text = yytext();
1124: Token t = (new Token(lastToken, text, yyline, yychar,
1125: yychar + text.length(), nextState));
1126: yybegin(nextState);
1127: return (t);
1128: }
1129: case 51:
1130: break;
1131: case 25: {
1132: nextState = YYINITIAL;
1133: lastToken = Token.ERROR_UNCLOSED_STRING;
1134: String text = yytext();
1135: Token t = (new Token(lastToken, text, yyline, yychar,
1136: yychar + text.length(), nextState));
1137: yybegin(nextState);
1138: return (t);
1139: }
1140: case 52:
1141: break;
1142: case 38:
1143: case 45: {
1144: nextState = YYINITIAL;
1145: lastToken = Token.ERROR_UNCLOSED_BIT_STRING;
1146: String text = yytext();
1147: Token t = (new Token(lastToken, text, yyline, yychar,
1148: yychar + text.length(), nextState));
1149: yybegin(nextState);
1150: return (t);
1151: }
1152: case 53:
1153: break;
1154: case 34: {
1155: nextState = COMMENT;
1156: commentBuffer.append(yytext());
1157: commentNestCount++;
1158: yybegin(nextState);
1159: }
1160: case 54:
1161: break;
1162: case 9:
1163: case 13:
1164: case 22: {
1165: nextState = YYINITIAL;
1166: lastToken = Token.SEPARATOR;
1167: String text = yytext();
1168: Token t = (new Token(lastToken, text, yyline, yychar,
1169: yychar + text.length(), nextState));
1170: yybegin(nextState);
1171: return (t);
1172: }
1173: case 55:
1174: break;
1175: case 2:
1176: case 4:
1177: case 12: {
1178: nextState = YYINITIAL;
1179: lastToken = Token.IDENTIFIER;
1180: String text = yytext();
1181: Token t = (new Token(lastToken, text, yyline, yychar,
1182: yychar + text.length(), nextState));
1183: yybegin(nextState);
1184: return (t);
1185: }
1186: case 56:
1187: break;
1188: case 3:
1189: case 19: {
1190: nextState = YYINITIAL;
1191: lastToken = Token.RESERVED_WORD;
1192: String text = yytext();
1193: Token t = (new Token(lastToken, text, yyline, yychar,
1194: yychar + text.length(), nextState));
1195: yybegin(nextState);
1196: return (t);
1197: }
1198: case 57:
1199: break;
1200: case 18:
1201: case 33: {
1202: commentNestCount--;
1203: commentBuffer.append(yytext());
1204: if (commentNestCount == 0) {
1205: nextState = YYINITIAL;
1206: lastToken = Token.COMMENT_TRADITIONAL;
1207: Token t = (new Token(lastToken, commentBuffer
1208: .toString(), commentStartLine,
1209: commentStartChar, commentStartChar
1210: + commentBuffer.length(), nextState));
1211: yybegin(nextState);
1212: return (t);
1213: }
1214: }
1215: case 58:
1216: break;
1217: case 20:
1218: case 42: {
1219: nextState = YYINITIAL;
1220: lastToken = Token.LITERAL_FLOAT;
1221: String text = yytext();
1222: Token t = (new Token(lastToken, text, yyline, yychar,
1223: yychar + text.length(), nextState));
1224: yybegin(nextState);
1225: return (t);
1226: }
1227: case 59:
1228: break;
1229: case 24:
1230: case 36: {
1231: nextState = YYINITIAL;
1232: lastToken = Token.LITERAL_STRING;
1233: String text = yytext();
1234: Token t = (new Token(lastToken, text, yyline, yychar,
1235: yychar + text.length(), nextState));
1236: yybegin(nextState);
1237: return (t);
1238: }
1239: case 60:
1240: break;
1241: case 29: {
1242: nextState = COMMENT;
1243: commentBuffer.setLength(0);
1244: commentBuffer.append(yytext());
1245: commentNestCount = 1;
1246: commentStartLine = yyline;
1247: commentStartChar = yychar;
1248: yybegin(nextState);
1249: }
1250: case 61:
1251: break;
1252: case 28: {
1253: nextState = YYINITIAL;
1254: lastToken = Token.COMMENT_END_OF_LINE;
1255: String text = yytext();
1256: Token t = (new Token(lastToken, text, yyline, yychar,
1257: yychar + text.length(), nextState));
1258: yybegin(nextState);
1259: return (t);
1260: }
1261: case 62:
1262: break;
1263: case 39: {
1264: nextState = YYINITIAL;
1265: lastToken = Token.ERROR_BAD_BIT_STRING;
1266: String text = yytext();
1267: Token t = (new Token(lastToken, text, yyline, yychar,
1268: yychar + text.length(), nextState));
1269: yybegin(nextState);
1270: return (t);
1271: }
1272: case 63:
1273: break;
1274: case 1:
1275: case 16: {
1276: nextState = COMMENT;
1277: commentBuffer.append(yytext());
1278: yybegin(nextState);
1279: }
1280: case 64:
1281: break;
1282: case 0:
1283: case 5: {
1284: nextState = YYINITIAL;
1285: lastToken = Token.WHITE_SPACE;
1286: String text = yytext();
1287: Token t = (new Token(lastToken, text, yyline, yychar,
1288: yychar + text.length(), nextState));
1289: yybegin(nextState);
1290: return (t);
1291: }
1292: case 65:
1293: break;
1294: case 7: {
1295: nextState = YYINITIAL;
1296: lastToken = Token.LITERAL_INTEGER;
1297: String text = yytext();
1298: Token t = (new Token(lastToken, text, yyline, yychar,
1299: yychar + text.length(), nextState));
1300: yybegin(nextState);
1301: return (t);
1302: }
1303: case 66:
1304: break;
1305: default:
1306: if (yy_input == YYEOF && yy_startRead == yy_currentPos) {
1307: yy_atEOF = true;
1308: switch (yy_lexical_state) {
1309: case COMMENT: {
1310: nextState = YYINITIAL;
1311: lastToken = Token.ERROR_UNCLOSED_COMMENT;
1312: Token t = (new Token(lastToken, commentBuffer
1313: .toString(), commentStartLine,
1314: commentStartChar, commentStartChar
1315: + commentBuffer.length(),
1316: nextState));
1317: yybegin(nextState);
1318: return (t);
1319: }
1320: case 49:
1321: break;
1322: default:
1323: return null;
1324: }
1325: } else {
1326: yy_ScanError(YY_NO_MATCH);
1327: }
1328: }
1329: }
1330: }
1331:
1332: }
|