1 /* Copyright (c) 2001-2007, The HSQL Development Group 2 * All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are met: 6 * 7 * Redistributions of source code must retain the above copyright notice, this 8 * list of conditions and the following disclaimer. 9 * 10 * Redistributions in binary form must reproduce the above copyright notice, 11 * this list of conditions and the following disclaimer in the documentation 12 * and/or other materials provided with the distribution. 13 * 14 * Neither the name of the HSQL Development Group nor the names of its 15 * contributors may be used to endorse or promote products derived from this 16 * software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL HSQL DEVELOPMENT GROUP, HSQLDB.ORG, 22 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 23 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 26 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 32 package org.hsqldb.util.preprocessor; 33 34 /* $Id: Parser.java 610 2008-12-22 15:54:18Z unsaved $ */ 35 36 /** 37 * Simple preprocessor directive parser. <p> 38 * 39 * @author boucherb@users 40 * @version 1.8.1 41 * @since 1.8.1 42 */ 43 class Parser { 44 45 Defines defines; 46 Tokenizer tokenizer; 47 Parser(Defines defines, Tokenizer tokenizer)48 Parser(Defines defines, Tokenizer tokenizer) { 49 this.defines = defines; 50 this.tokenizer = tokenizer; 51 } 52 parseExpression()53 boolean parseExpression() throws PreprocessorException { 54 boolean result = parseTerm(); 55 56 while (true) { 57 switch(this.tokenizer.getTokenType()) { 58 case Token.OR : { 59 this.tokenizer.next(); 60 61 result = result | parseTerm(); 62 63 break; 64 } 65 case Token.XOR : { 66 this.tokenizer.next(); 67 68 result = result ^ parseTerm(); 69 70 break; 71 } 72 73 default : { 74 return result; 75 } 76 } 77 } 78 } 79 parseTerm()80 boolean parseTerm() throws PreprocessorException { 81 boolean result = parseFactor(); 82 83 while (this.tokenizer.isToken(Token.AND)) { 84 this.tokenizer.next(); 85 86 result = result & parseFactor(); 87 } 88 89 return result; 90 } 91 parseFactor()92 boolean parseFactor() throws PreprocessorException { 93 boolean result; 94 95 switch(this.tokenizer.getTokenType()) { 96 case Token.IDENT : { 97 String ident = this.tokenizer.getIdent(); 98 int type = this.tokenizer.next(); 99 100 if ((type == Token.EOI) || (type == Token.RPAREN) || 101 Token.isLogicalOperator(type)) { 102 result = this.defines.isDefined(ident); 103 } else if (Token.isComparisonOperator(type)) { 104 result = parseComparison(ident, type); 105 } else { 106 throw new PreprocessorException("Logical or comparison " 107 + "operator token required at position " 108 + this.tokenizer.getStartIndex() 109 + " in [" 110 + this.tokenizer.getSource() 111 + "]"); // NOI18N 112 } 113 114 break; 115 } 116 case Token.NOT :{ 117 this.tokenizer.next(); 118 119 result = !parseFactor(); 120 121 break; 122 } 123 case Token.LPAREN : { 124 this.tokenizer.next(); 125 126 result = parseExpression(); 127 128 if (!this.tokenizer.isToken(Token.RPAREN)) { 129 throw new PreprocessorException("RPAREN token required at " 130 + "position " 131 + this.tokenizer.getStartIndex() 132 + " in [" 133 + this.tokenizer.getSource() 134 + "]"); // NOI18N 135 } 136 137 this.tokenizer.next(); 138 139 break; 140 } 141 default : { 142 throw new PreprocessorException("IDENT, NOT or LPAREN " 143 + "token required at position " 144 + this.tokenizer.getStartIndex() 145 + " in [" 146 + this.tokenizer.getSource() 147 + "]"); // NOI18N 148 } 149 } 150 151 return result; 152 } 153 parseComparison(String ident, int opType)154 boolean parseComparison(String ident, int opType) 155 throws PreprocessorException { 156 // checkIsComparisonOperator(opType); 157 158 boolean result; 159 Object lhs = this.defines.getDefintion(ident); 160 int pos = this.tokenizer.getStartIndex(); 161 Object rhs = parseValue(); 162 163 if (lhs == null) { 164 throw new PreprocessorException("IDENT " + ident 165 + " is not defined at position" 166 + pos 167 + "in [" 168 + this.tokenizer.getSource() 169 + "]"); // NOI18N 170 } 171 172 switch(opType) { 173 case Token.EQ :{ 174 result = (compare(lhs, rhs) == 0); 175 176 break; 177 } 178 case Token.LT : { 179 result = (compare(lhs, rhs) < 0); 180 181 break; 182 } 183 case Token.LTE : { 184 result = (compare(lhs, rhs) <= 0); 185 186 break; 187 } 188 case Token.GT : { 189 result = (compare(lhs, rhs) > 0); 190 191 break; 192 } 193 case Token.GTE : { 194 result = (compare(lhs, rhs) >= 0); 195 196 break; 197 } 198 default : { 199 // Stupid compiler trick. 200 // Can't actually happen because this case will cause an 201 // exception to be thrown in method parseFactor (or in 202 // method checkIsComparisonOperator when uncommented) 203 throw new PreprocessorException("Internal error"); // NOI18N 204 } 205 } 206 207 this.tokenizer.next(); 208 209 return result; 210 } 211 212 // void checkIsComparisonOperator(int opType) throws PreprocessorException { 213 // if (!Token.isComparisonOperator(opType)) { 214 // throw new PreprocessorException("Comparison " 215 // + "operator token required at position " 216 // + tokenizer.getBeginIndex() 217 // + " in [" 218 // + tokenizer.getSource() 219 // + "]"); // NOI18N 220 // } 221 // } 222 compare(Object o1, Object o2)223 static int compare(Object o1, Object o2) { 224 // nulls are basically 'illegal' so yes: 225 // we want to throw NPE here if o1 or o2 is null 226 if (o1 instanceof Comparable) { 227 return (o1.getClass().isAssignableFrom(o2.getClass())) 228 ? ((Comparable)o1).compareTo(o2) 229 : String.valueOf(o1).compareTo(String.valueOf(o2)); 230 } else { 231 return o1.toString().compareTo(o2.toString()); 232 } 233 } 234 parseValue()235 Object parseValue() throws PreprocessorException { 236 Object value; 237 238 switch(this.tokenizer.next()) { 239 case Token.IDENT : { 240 String ident = this.tokenizer.getIdent(); 241 242 value = this.defines.getDefintion(ident); 243 244 if (value == null) { 245 throw new PreprocessorException("IDENT " + ident 246 + " is not defined at position" 247 + this.tokenizer.getStartIndex() 248 + "in [" 249 + this.tokenizer.getSource() 250 + "]"); // NOI18N 251 } 252 253 break; 254 } 255 case Token.STRING : { 256 value = this.tokenizer.getString(); 257 258 break; 259 } 260 case Token.NUMBER : { 261 value = this.tokenizer.getNumber(); 262 263 break; 264 } 265 default :{ 266 throw new PreprocessorException("IDENT, STRING" 267 + "or NUMBER token required at position " 268 + this.tokenizer.getStartIndex() 269 + " in: [" 270 + this.tokenizer.getSource() 271 + "]"); // NOI18N 272 } 273 } 274 275 return value; 276 } 277 } 278