/*
* Copyright © 2010-2011 Rebecca G. Bettencourt / Kreative Software
* <p>
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* <a href="http://www.mozilla.org/MPL/">http://www.mozilla.org/MPL/</a>
* <p>
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
* License for the specific language governing rights and limitations
* under the License.
* <p>
* Alternatively, the contents of this file may be used under the terms
* of the GNU Lesser General Public License (the "LGPL License"), in which
* case the provisions of LGPL License are applicable instead of those
* above. If you wish to allow use of your version of this file only
* under the terms of the LGPL License and not to allow others to use
* your version of this file under the MPL, indicate your decision by
* deleting the provisions above and replace them with the notice and
* other provisions required by the LGPL License. If you do not delete
* the provisions above, a recipient may use your version of this file
* under either the MPL or the LGPL License.
* @since KSFL 1.2
* @author Rebecca G. Bettencourt, Kreative Software
*/
package com.kreative.binpack;
import java.io.IOException;
public class DFExpressionParser {
private DFExpressionLexer lexer;
public DFExpressionParser(DFExpressionLexer lexer) {
this.lexer = lexer;
}
public DFExpression parse() throws IOException {
DFExpression expr = parseExpression();
String s = lexer.getToken();
if (s != null) throw new RuntimeException("Parse error: expected end of expression but found " + s);
else return expr;
}
private int parseInt(String s) {
s = s.trim();
if ((s.startsWith("\"") && s.endsWith("\"")) || (s.startsWith("'") && s.endsWith("'"))) {
int r = 0;
for (char ch : s.substring(1, s.length()-1).toCharArray()) {
r <<= 8;
r |= ((int)ch & 0xFF);
}
return r;
}
if (s.startsWith("0x") || s.startsWith("0X")) {
return (int)Long.parseLong(s.substring(2).trim(), 16);
}
if (s.startsWith("0o") || s.startsWith("0O")) {
return (int)Long.parseLong(s.substring(2).trim(), 8);
}
if (s.startsWith("0b") || s.startsWith("0B")) {
return (int)Long.parseLong(s.substring(2).trim(), 2);
}
if (s.startsWith("0") && s.length() > 1) {
return (int)Long.parseLong(s.substring(1).trim(), 8);
}
return (int)Long.parseLong(s);
}
private DFExpression parseFactor() throws IOException {
String s = lexer.getToken();
if (s == null) {
throw new RuntimeException("Parse error: expected factor but found end of expression");
} else if (s.equals("!!")) {
return new DFUnaryExpression(DFUnaryExpression.Operation.BOOLEAN_IDENTITY, parseFactor());
} else if (s.equals("!")) {
return new DFUnaryExpression(DFUnaryExpression.Operation.BOOLEAN_NOT, parseFactor());
} else if (s.equals("~")) {
return new DFUnaryExpression(DFUnaryExpression.Operation.BITWISE_NOT, parseFactor());
} else if (s.equals("+")) {
return new DFUnaryExpression(DFUnaryExpression.Operation.IDENTITY, parseFactor());
} else if (s.equals("-")) {
return new DFUnaryExpression(DFUnaryExpression.Operation.NEGATE, parseFactor());
} else if (s.equals("(")) {
DFExpression expr = parseExpression();
s = lexer.getToken();
if (s == null || !s.equals(")")) throw new RuntimeException("Parse error: expected ) but found " + ((s == null) ? "end of expression" : s));
else return expr;
} else if (s.equals("#") || s.equalsIgnoreCase("length")) {
return new DFLengthExpression();
} else if (s.equals("@") || s.equalsIgnoreCase("position")) {
return new DFPositionExpression();
} else if (s.equals("*") || s.equalsIgnoreCase("remaining")) {
return new DFRemainingExpression();
} else if (s.startsWith("'") || s.startsWith("\"") || Character.isDigit(s.charAt(0))) {
return new DFConstantExpression(parseInt(s));
} else if (s.startsWith("`") || s.startsWith("_") || Character.isLetter(s.charAt(0))) {
if (s.startsWith("`") && s.endsWith("`")) s = s.substring(1, s.length()-1);
DFFieldExpression expr = new DFFieldExpression(s);
while (".".equals(lexer.lookToken(1))) {
lexer.getToken();
s = lexer.getToken();
if (s == null || !(s.startsWith("`") || s.startsWith("_") || Character.isLetter(s.charAt(0)))) {
throw new RuntimeException("Parse error: expected field name but found " + ((s == null) ? "end of expression" : s));
}
if (s.startsWith("`") && s.endsWith("`")) s = s.substring(1, s.length()-1);
expr = new DFFieldExpression(expr, s);
}
return expr;
} else {
throw new RuntimeException("Parse error: expected factor but found " + s);
}
}
private DFExpression parseMultiplicationExpression() throws IOException {
DFExpression expr = parseFactor();
while (true) {
String s = lexer.lookToken(1);
if (s == null) {
break;
} else if (s.equals("*")) {
lexer.getToken();
expr = new DFBinaryExpression(DFBinaryExpression.Operation.MULTIPLY, expr, parseFactor());
} else if (s.equals("/")) {
lexer.getToken();
expr = new DFBinaryExpression(DFBinaryExpression.Operation.DIVIDE, expr, parseFactor());
} else if (s.equals("%")) {
lexer.getToken();
expr = new DFBinaryExpression(DFBinaryExpression.Operation.MOD, expr, parseFactor());
} else {
break;
}
}
return expr;
}
private DFExpression parseAdditionExpression() throws IOException {
DFExpression expr = parseMultiplicationExpression();
while (true) {
String s = lexer.lookToken(1);
if (s == null) {
break;
} else if (s.equals("+")) {
lexer.getToken();
expr = new DFBinaryExpression(DFBinaryExpression.Operation.ADD, expr, parseMultiplicationExpression());
} else if (s.equals("-")) {
lexer.getToken();
expr = new DFBinaryExpression(DFBinaryExpression.Operation.SUBTRACT, expr, parseMultiplicationExpression());
} else {
break;
}
}
return expr;
}
private DFExpression parseShiftExpression() throws IOException {
DFExpression expr = parseAdditionExpression();
while (true) {
String s = lexer.lookToken(1);
if (s == null) {
break;
} else if (s.equals("<<")) {
lexer.getToken();
expr = new DFBinaryExpression(DFBinaryExpression.Operation.SHIFT_LEFT, expr, parseAdditionExpression());
} else if (s.equals(">>")) {
lexer.getToken();
expr = new DFBinaryExpression(DFBinaryExpression.Operation.SHIFT_RIGHT, expr, parseAdditionExpression());
} else if (s.equals(">>>")) {
lexer.getToken();
expr = new DFBinaryExpression(DFBinaryExpression.Operation.UNSIGNED_SHIFT_RIGHT, expr, parseAdditionExpression());
} else {
break;
}
}
return expr;
}
private DFExpression parseBitAndExpression() throws IOException {
DFExpression expr = parseShiftExpression();
while ("&".equals(lexer.lookToken(1))) {
lexer.getToken();
expr = new DFBinaryExpression(DFBinaryExpression.Operation.BITWISE_AND, expr, parseShiftExpression());
}
return expr;
}
private DFExpression parseBitXorExpression() throws IOException {
DFExpression expr = parseBitAndExpression();
while ("^".equals(lexer.lookToken(1))) {
lexer.getToken();
expr = new DFBinaryExpression(DFBinaryExpression.Operation.BITWISE_XOR, expr, parseBitAndExpression());
}
return expr;
}
private DFExpression parseBitOrExpression() throws IOException {
DFExpression expr = parseBitXorExpression();
while ("|".equals(lexer.lookToken(1))) {
lexer.getToken();
expr = new DFBinaryExpression(DFBinaryExpression.Operation.BITWISE_OR, expr, parseBitXorExpression());
}
return expr;
}
private DFExpression parseComparisonExpression() throws IOException {
DFExpression expr = parseBitOrExpression();
while (true) {
String s = lexer.lookToken(1);
if (s == null) {
break;
} else if (s.equals("<=")) {
lexer.getToken();
expr = new DFBinaryExpression(DFBinaryExpression.Operation.LESS_OR_EQUAL, expr, parseBitOrExpression());
} else if (s.equals(">=")) {
lexer.getToken();
expr = new DFBinaryExpression(DFBinaryExpression.Operation.GREATER_OR_EQUAL, expr, parseBitOrExpression());
} else if (s.equals("<")) {
lexer.getToken();
expr = new DFBinaryExpression(DFBinaryExpression.Operation.LESS_THAN, expr, parseBitOrExpression());
} else if (s.equals(">")) {
lexer.getToken();
expr = new DFBinaryExpression(DFBinaryExpression.Operation.GREATER_THAN, expr, parseBitOrExpression());
} else {
break;
}
}
return expr;
}
private DFExpression parseEqualityExpression() throws IOException {
DFExpression expr = parseComparisonExpression();
while (true) {
String s = lexer.lookToken(1);
if (s == null) {
break;
} else if (s.equals("==") || s.equals("=")) {
lexer.getToken();
expr = new DFBinaryExpression(DFBinaryExpression.Operation.EQUAL, expr, parseComparisonExpression());
} else if (s.equals("!=") || s.equals("<>")) {
lexer.getToken();
expr = new DFBinaryExpression(DFBinaryExpression.Operation.NOT_EQUAL, expr, parseComparisonExpression());
} else if (s.equals("<=>")) {
lexer.getToken();
expr = new DFBinaryExpression(DFBinaryExpression.Operation.COMPARE, expr, parseComparisonExpression());
} else {
break;
}
}
return expr;
}
private DFExpression parseAndExpression() throws IOException {
DFExpression expr = parseEqualityExpression();
while ("&&".equals(lexer.lookToken(1))) {
lexer.getToken();
expr = new DFBinaryExpression(DFBinaryExpression.Operation.BOOLEAN_AND, expr, parseEqualityExpression());
}
return expr;
}
private DFExpression parseXorExpression() throws IOException {
DFExpression expr = parseAndExpression();
while ("^^".equals(lexer.lookToken(1))) {
lexer.getToken();
expr = new DFBinaryExpression(DFBinaryExpression.Operation.BOOLEAN_XOR, expr, parseAndExpression());
}
return expr;
}
private DFExpression parseOrExpression() throws IOException {
DFExpression expr = parseXorExpression();
while ("||".equals(lexer.lookToken(1))) {
lexer.getToken();
expr = new DFBinaryExpression(DFBinaryExpression.Operation.BOOLEAN_OR, expr, parseXorExpression());
}
return expr;
}
private DFExpression parseExpression() throws IOException {
DFExpression expr = parseOrExpression();
if ("?".equals(lexer.lookToken(1))) {
lexer.getToken();
DFExpression trueCase = parseExpression();
String s = lexer.getToken();
if (s == null || !s.equals(":")) throw new RuntimeException("Parse error: expected : but found " + ((s == null) ? "end of expression" : s));
DFExpression falseCase = parseExpression();
expr = new DFTernaryExpression(DFTernaryExpression.Operation.CONDITIONAL, expr, trueCase, falseCase);
}
return expr;
}
public static void main(String[] args) {
for (String arg : args) {
try {
System.out.println(new DFExpressionParser(new DFExpressionLexer(new java.io.StringReader(arg))).parse().evaluate());
} catch (Exception e) {
System.err.println(e.getMessage());
}
}
}
}