/******************************************************************************* SiJaPP - Simple Java PreProcessor Copyright (C) 2003 Manuel Linsmayer This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *******************************************************************************/ package sijapp; import java.util.Vector; public class Scanner { // Alphabetic character test private static boolean isAlpha(char c) { return (((c >= 'A') && (c <= 'Z')) || ((c >= 'a') && (c <= 'z'))); } // Numeric character test private static boolean isNumeric(char c) { return ((c >= '0') && (c <= '9')); } // Whitespace test private static boolean isWhitespace(char c) { return ((c == ' ') || (c == '\t')); } // Exclamation markt test private static boolean isExclamationMark(char c) { return (c == '!'); } // Quote test private static boolean isQuote(char c) { return (c == '"'); } // Pound test private static boolean isPound(char c) { return (c == '#'); } // Ampersand test private static boolean isAmpersand(char c) { return (c == '&'); } // Opening parenthesis test private static boolean isOpeningParenthesis(char c) { return (c == '('); } // Closing parenthesis test private static boolean isClosingParenthesis(char c) { return (c == ')'); } // Dot test private static boolean isDot(char c) { return (c == '.'); } // Equals sign test private static boolean isEqualsSign(char c) { return (c == '='); } // Backslash test private static boolean isBackslash(char c) { return (c == '\\'); } // Underscore private static boolean isUnderscore(char c) { return (c == '_'); } // Vertical bar test private static boolean isVerticalBar(char c) { return (c == '|'); } // Scanner public static Token[] scan(String s) throws SijappException { // Look for SiJaPP statement if (s.indexOf("#sijapp") == -1) { return (new Token[0]); } // Crop anything to the left StringBuffer buf = new StringBuffer(s.substring(s.indexOf("#sijapp")) + " "); // Vector Vector tokens = new Vector(); // Required string buffers StringBuffer ident = null; StringBuffer string = null; // State variable int state = 0; // Exit flag boolean exit = false; // Scanner main loop do { // Get next character char ch = buf.charAt(0); buf.deleteCharAt(0); // Deterministic finite automaton, see README file switch (state) { case 0: if (Scanner.isPound(ch)) { ident = new StringBuffer(); state = 1; break; } else if (Scanner.isAlpha(ch) || Scanner.isUnderscore(ch)) { ident = new StringBuffer(); ident.append(ch); state = 3; break; } else if (Scanner.isDot(ch)) { state = 4; break; } else if (Scanner.isQuote(ch)) { string = new StringBuffer(); state = 5; break; } else if (Scanner.isWhitespace(ch)) { state = 8; break; } else if (Scanner.isOpeningParenthesis(ch)) { state = 9; break; } else if (Scanner.isClosingParenthesis(ch)) { state = 10; break; } else if (Scanner.isEqualsSign(ch)) { state = 11; break; } else if (Scanner.isExclamationMark(ch)) { state = 12; break; } else if (Scanner.isAmpersand(ch)) { state = 14; break; } else if (Scanner.isVerticalBar(ch)) { state = 15; break; } else { throw (new SijappException("Syntax error")); } case 1: if (Scanner.isAlpha(ch) || Scanner.isUnderscore(ch)) { ident.append(ch); state = 2; break; } else { tokens.add(new Token(Token.T_MAGIC_END, null)); exit = true; buf.insert(0, ch); state = 0; break; } case 2: if (Scanner.isAlpha(ch) || Scanner.isNumeric(ch) || Scanner.isUnderscore(ch)) { ident.append(ch); state = 2; break; } else { if (ident.toString().equals("sijapp")) { tokens.add(new Token(Token.T_MAGIC_BEGIN, null)); buf.insert(0, ch); state = 0; break; } else { throw (new SijappException("Syntax error")); } } case 3: if (Scanner.isAlpha(ch) || Scanner.isNumeric(ch) || Scanner.isUnderscore(ch)) { ident.append(ch); state = 3; break; } else { if (ident.toString().equals("true")) { tokens.add(new Token(Token.T_BOOL, new Boolean(true))); } else if (ident.toString().equals("false")) { tokens.add(new Token(Token.T_BOOL, new Boolean(false))); } else if (ident.toString().equals("cond") || ident.toString().equals("condition")) { tokens.add(new Token(Token.T_CMD1_COND, null)); } else if (ident.toString().equals("echo")) { tokens.add(new Token(Token.T_CMD1_ECHO, null)); } else if (ident.toString().equals("env") || ident.toString().equals("environment")) { tokens.add(new Token(Token.T_CMD1_ENV, null)); } else if (ident.toString().equals("exit")) { tokens.add(new Token(Token.T_CMD1_EXIT, null)); } else if (ident.toString().equals("if") || ident.toString().equals("If")) { tokens.add(new Token(Token.T_CMD2_IF, null)); } else if (ident.toString().equals("elseif")) { tokens.add(new Token(Token.T_CMD2_ELSEIF, null)); } else if (ident.toString().equals("else")) { tokens.add(new Token(Token.T_CMD2_ELSE, null)); } else if (ident.toString().equals("end")) { tokens.add(new Token(Token.T_CMD2_END, null)); } else if (ident.toString().equals("def") || ident.toString().equals("define")) { tokens.add(new Token(Token.T_CMD2_DEF, null)); } else if (ident.toString().equals("undef") || ident.toString().equals("undefine")) { tokens.add(new Token(Token.T_CMD2_UNDEF, null)); } else if (ident.toString().equals("is")) { tokens.add(new Token(Token.T_EXPR_EQ, null)); } else if (ident.toString().equals("isnot")) { tokens.add(new Token(Token.T_EXPR_NEQ, null)); } else if (ident.toString().equals("not")) { tokens.add(new Token(Token.T_EXPR_NOT, null)); } else if (ident.toString().equals("and")) { tokens.add(new Token(Token.T_EXPR_AND, null)); } else if (ident.toString().equals("or")) { tokens.add(new Token(Token.T_EXPR_OR, null)); } else if (ident.toString().equals("defined")) { tokens.add(new Token(Token.T_EXPR_DEF, null)); } else { tokens.add(new Token(Token.T_IDENT, ident.toString())); } buf.insert(0, ch); state = 0; break; } case 4: tokens.add(new Token(Token.T_SEP, null)); buf.insert(0, ch); state = 0; break; case 5: if (Scanner.isQuote(ch)) { state = 6; break; } else if (Scanner.isBackslash(ch)) { state = 7; break; } else { string.append(ch); state = 5; break; } case 6: tokens.add(new Token(Token.T_STRING, string.toString())); buf.insert(0, ch); state = 0; break; case 7: if (Scanner.isQuote(ch) || Scanner.isBackslash(ch)) { string.append(ch); state = 5; break; } else { throw (new SijappException("Syntax error")); } case 8: buf.insert(0, ch); state = 0; break; case 9: tokens.add(new Token(Token.T_EXPR_PRS_LEFT, null)); buf.insert(0, ch); state = 0; break; case 10: tokens.add(new Token(Token.T_EXPR_PRS_RIGHT, null)); buf.insert(0, ch); state = 0; break; case 11: tokens.add(new Token(Token.T_EXPR_EQ, null)); buf.insert(0, ch); state = 0; break; case 12: if (Scanner.isEqualsSign(ch)) { state = 13; break; } else { tokens.add(new Token(Token.T_EXPR_NOT, null)); break; } case 13: tokens.add(new Token(Token.T_EXPR_NEQ, null)); buf.insert(0, ch); state = 0; break; case 14: tokens.add(new Token(Token.T_EXPR_AND, null)); buf.insert(0, ch); state = 0; break; case 15: tokens.add(new Token(Token.T_EXPR_OR, null)); buf.insert(0, ch); state = 0; break; } } while (!exit && (buf.length() > 0)); // Return tokens as array Token[] ret = new Token[tokens.size()]; tokens.copyInto(ret); return (ret); } /****************************************************************************/ /****************************************************************************/ /****************************************************************************/ public static class Token { // Tokens public static final int T_MAGIC_BEGIN = 1; public static final int T_MAGIC_END = 2; public static final int T_IDENT = 3; public static final int T_STRING = 4; public static final int T_BOOL = 5; public static final int T_SEP = 6; public static final int T_CMD1_COND = 7; public static final int T_CMD1_ECHO = 8; public static final int T_CMD1_ENV = 9; public static final int T_CMD1_EXIT = 10; public static final int T_CMD2_IF = 11; public static final int T_CMD2_ELSEIF = 12; public static final int T_CMD2_ELSE = 13; public static final int T_CMD2_END = 14; public static final int T_CMD2_DEF = 15; public static final int T_CMD2_UNDEF = 16; public static final int T_EXPR_PRS_LEFT = 17; public static final int T_EXPR_PRS_RIGHT = 18; public static final int T_EXPR_EQ = 19; public static final int T_EXPR_NEQ = 20; public static final int T_EXPR_NOT = 21; public static final int T_EXPR_AND = 22; public static final int T_EXPR_OR = 23; public static final int T_EXPR_DEF = 24; /**************************************************************************/ // Token type private int type; // Token value private Object value; // Constructor public Token(int type, Object value) { this.type = type; this.value = value; } // Returns the token type public int getType() { return (this.type); } // Returns the token value public Object getValue() { return (this.value); } } }