From cd756d6006fca9b53c4280bf9fb4deeef11f3ab9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jindra=20Pet=F8=EDk?= Date: Sun, 9 Feb 2014 19:23:38 +0100 Subject: [PATCH] Complex conditions for types in generic tag editor --- .../decompiler/flash/gui/GenericTagPanel.java | 37 +- .../parser/ConditionEvaluator.java | 142 ++++ .../annotations/parser/ConditionLexer.java | 684 ++++++++++++++++++ .../annotations/parser/ConditionToken.java | 40 + .../parser/ConditionTokenType.java | 31 + .../annotations/parser/ParseException.java | 29 + .../types/annotations/parser/conditions.flex | 85 +++ 7 files changed, 1035 insertions(+), 13 deletions(-) create mode 100644 trunk/src/com/jpexs/decompiler/flash/types/annotations/parser/ConditionEvaluator.java create mode 100644 trunk/src/com/jpexs/decompiler/flash/types/annotations/parser/ConditionLexer.java create mode 100644 trunk/src/com/jpexs/decompiler/flash/types/annotations/parser/ConditionToken.java create mode 100644 trunk/src/com/jpexs/decompiler/flash/types/annotations/parser/ConditionTokenType.java create mode 100644 trunk/src/com/jpexs/decompiler/flash/types/annotations/parser/ParseException.java create mode 100644 trunk/src/com/jpexs/decompiler/flash/types/annotations/parser/conditions.flex diff --git a/trunk/src/com/jpexs/decompiler/flash/gui/GenericTagPanel.java b/trunk/src/com/jpexs/decompiler/flash/gui/GenericTagPanel.java index 7e3ad5535..12e8a86c2 100644 --- a/trunk/src/com/jpexs/decompiler/flash/gui/GenericTagPanel.java +++ b/trunk/src/com/jpexs/decompiler/flash/gui/GenericTagPanel.java @@ -27,6 +27,8 @@ import com.jpexs.decompiler.flash.tags.Tag; import com.jpexs.decompiler.flash.types.annotations.Calculated; import com.jpexs.decompiler.flash.types.annotations.Conditional; import com.jpexs.decompiler.flash.types.annotations.SWFType; +import com.jpexs.decompiler.flash.types.annotations.parser.ConditionEvaluator; +import com.jpexs.decompiler.flash.types.annotations.parser.ParseException; import java.awt.BorderLayout; import java.awt.Component; import java.lang.reflect.Array; @@ -36,6 +38,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.JEditorPane; @@ -287,28 +290,36 @@ public class GenericTagPanel extends JPanel implements ChangeListener { p += f.getName(); Conditional cond = f.getAnnotation(Conditional.class); if (cond != null) { - String condVals[] = cond.value(); - if (condVals != null) { - for (String condVal : condVals) { //TODO: complex conditions + ConditionEvaluator ev=new ConditionEvaluator(cond); + + try { + Set fieldNames=ev.getFields(); + Map fields=new HashMap<>(); + for(String fld:fieldNames){ String ckey = ""; if (!par.equals("")) { ckey = par + "."; - } - ckey += condVal; + } + ckey += fld; if (editors.containsKey(ckey)) { GenericTagEditor editor = editors.get(ckey); Object val = editor.getChangedValue(); + fields.put(fld, true); if (val instanceof Boolean) { - if (conditionMet) { - conditionMet = (Boolean) val; - } + fields.put(fld, (Boolean)val); } - ((Component) dependentEditor).setVisible(conditionMet); - dependentLabel.setVisible(conditionMet); - dependentTypeLabel.setVisible(conditionMet); - } + } } - } + boolean ok = ev.eval(fields); + if(conditionMet){ + conditionMet = ok; + } + ((Component) dependentEditor).setVisible(conditionMet); + dependentLabel.setVisible(conditionMet); + dependentTypeLabel.setVisible(conditionMet); + } catch (ParseException ex) { + Logger.getLogger(GenericTagPanel.class.getName()).log(Level.SEVERE, "Invalid condition", ex); + } } if (!conditionMet) { break; diff --git a/trunk/src/com/jpexs/decompiler/flash/types/annotations/parser/ConditionEvaluator.java b/trunk/src/com/jpexs/decompiler/flash/types/annotations/parser/ConditionEvaluator.java new file mode 100644 index 000000000..d261f8e7f --- /dev/null +++ b/trunk/src/com/jpexs/decompiler/flash/types/annotations/parser/ConditionEvaluator.java @@ -0,0 +1,142 @@ +/* + * Copyright (C) 2014 JPEXS + * + * 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 3 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, see . + */ +package com.jpexs.decompiler.flash.types.annotations.parser; + +import com.jpexs.decompiler.flash.types.annotations.Conditional; +import java.io.IOException; +import java.io.StringReader; +import java.util.EmptyStackException; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.Stack; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * + * @author JPEXS + */ +public class ConditionEvaluator { + + private Conditional cond; + + public ConditionEvaluator(Conditional cond) { + this.cond = cond; + } + + private void expressionRest(Map fields, Stack stack, ConditionLexer lex) throws IOException, ParseException { + ConditionToken tok = lex.lex(); + if (tok == null) { + return; + } + switch (tok.type) { + case AND: + Boolean andOp1 = stack.pop(); + expression(fields, stack, lex); + Boolean andOp2 = stack.pop(); + stack.push(andOp1 && andOp2); + break; + case OR: + Boolean orOp1 = stack.pop(); + expression(fields, stack, lex); + Boolean orOp2 = stack.pop(); + stack.push(orOp1 || orOp2); + break; + default: + lex.pushback(tok); + } + + } + + private void expression(Map fields, Stack stack, ConditionLexer lex) throws IOException, ParseException { + ConditionToken tok = lex.yylex(); + if (tok == null) { + return; + } + switch (tok.type) { + case FIELD: + if (!fields.containsKey(tok.value)) { + throw new ParseException("Field not found", lex.yyline()); + } else { + stack.push(fields.get(tok.value)); + } + expressionRest(fields, stack, lex); + break; + case NOT: + expression(fields, stack, lex); + Boolean invOp = stack.pop(); + stack.push(!invOp); + break; + case PARENT_OPEN: + expression(fields, stack, lex); + tok = lex.yylex(); + if (tok.type != ConditionTokenType.PARENT_CLOSE) { + throw new ParseException("End of parent expected", lex.yyline()); + } + expressionRest(fields, stack, lex); + break; + default: + throw new ParseException("Expression expected", lex.yyline()); + } + } + + public boolean eval(Map fields) throws ParseException { + ConditionLexer lex = new ConditionLexer(new StringReader(prepareCond())); + + Stack stack = new Stack<>(); + + try { + expression(fields, stack, lex); + } catch (IOException | EmptyStackException ex) { + throw new ParseException("Invalid condition", lex.yyline()); + } + if (stack.size() != 1) { + throw new ParseException("Invalid condition", lex.yyline()); + } + + return stack.pop(); + } + + private String prepareCond() { + String vals[] = cond.value(); + if (vals == null || vals.length == 0) { + return ""; + } + String val = vals[0]; + for (int i = 1; i < vals.length; i++) { + val = val + "," + vals[i]; + } + return val; + } + + public Set getFields() throws ParseException { + Set ret = new HashSet<>(); + ConditionLexer lex = new ConditionLexer(new StringReader(prepareCond())); + ConditionToken tok; + try { + while ((tok = lex.yylex()) != null) { + if (tok.type == ConditionTokenType.FIELD) { + ret.add(tok.value); + } + } + } catch (IOException ex) { + throw new ParseException("Invalid condition", lex.yyline()); + } + return ret; + } +} diff --git a/trunk/src/com/jpexs/decompiler/flash/types/annotations/parser/ConditionLexer.java b/trunk/src/com/jpexs/decompiler/flash/types/annotations/parser/ConditionLexer.java new file mode 100644 index 000000000..ff6a124a7 --- /dev/null +++ b/trunk/src/com/jpexs/decompiler/flash/types/annotations/parser/ConditionLexer.java @@ -0,0 +1,684 @@ +/* The following code was generated by JFlex 1.5.0-SNAPSHOT */ + +/* + * Copyright (C) 2010-2014 PEXS + * + * 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 3 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, see . + */ +package com.jpexs.decompiler.flash.types.annotations.parser; + +import java.util.Stack; + + +/** + * This class is a scanner generated by + * JFlex 1.5.0-SNAPSHOT + * from the specification file D:/Dropbox/Programovani/JavaSE/FFDec/trunk/src/com/jpexs/decompiler/flash/types/annotations/parser/conditions.flex + */ +public final class ConditionLexer { + + /** This character denotes the end of file */ + public static final int YYEOF = -1; + + /** initial size of the lookahead buffer */ + private static final int ZZ_BUFFERSIZE = 16384; + + /** lexical states */ + public static final int YYINITIAL = 0; + + /** + * ZZ_LEXSTATE[l] is the state in the DFA for the lexical state l + * ZZ_LEXSTATE[l+1] is the state in the DFA for the lexical state l + * at the beginning of a line + * l is of the form l = 2*k, k a non negative integer + */ + private static final int ZZ_LEXSTATE[] = { + 0, 0 + }; + + /** + * Translates characters to character classes + */ + private static final String ZZ_CMAP_PACKED = + "\12\0\1\10\1\10\1\10\1\10\23\0\1\5\4\0\1\3\1\0"+ + "\1\6\1\7\2\0\1\4\1\0\1\1\1\0\12\1\7\0\32\1"+ + "\4\0\1\1\1\0\32\1\1\0\1\2\10\0\1\10\u1fa2\0\1\10"+ + "\1\10\udfd6\0"; + + /** + * Translates characters to character classes + */ + private static final char [] ZZ_CMAP = zzUnpackCMap(ZZ_CMAP_PACKED); + + /** + * Translates DFA states to action switch labels. + */ + private static final int [] ZZ_ACTION = zzUnpackAction(); + + private static final String ZZ_ACTION_PACKED_0 = + "\1\0\1\1\1\2\1\3\2\4\1\5\1\6\1\7"+ + "\1\3"; + + private static int [] zzUnpackAction() { + int [] result = new int[10]; + int offset = 0; + offset = zzUnpackAction(ZZ_ACTION_PACKED_0, offset, result); + return result; + } + + private static int zzUnpackAction(String packed, int offset, int [] result) { + int i = 0; /* index in packed string */ + int j = offset; /* index in unpacked array */ + int l = packed.length(); + while (i < l) { + int count = packed.charAt(i++); + int value = packed.charAt(i++); + do result[j++] = value; while (--count > 0); + } + return j; + } + + + /** + * Translates a state to a row index in the transition table + */ + private static final int [] ZZ_ROWMAP = zzUnpackRowMap(); + + private static final String ZZ_ROWMAP_PACKED_0 = + "\0\0\0\11\0\22\0\33\0\44\0\11\0\11\0\11"+ + "\0\11\0\11"; + + private static int [] zzUnpackRowMap() { + int [] result = new int[10]; + int offset = 0; + offset = zzUnpackRowMap(ZZ_ROWMAP_PACKED_0, offset, result); + return result; + } + + private static int zzUnpackRowMap(String packed, int offset, int [] result) { + int i = 0; /* index in packed string */ + int j = offset; /* index in unpacked array */ + int l = packed.length(); + while (i < l) { + int high = packed.charAt(i++) << 16; + result[j++] = high | packed.charAt(i++); + } + return j; + } + + /** + * The transition table of the DFA + */ + private static final int [] ZZ_TRANS = zzUnpackTrans(); + + private static final String ZZ_TRANS_PACKED_0 = + "\1\2\1\3\1\4\1\5\1\6\1\7\1\10\1\11"+ + "\13\0\1\3\11\0\1\12\11\0\1\6\5\0"; + + private static int [] zzUnpackTrans() { + int [] result = new int[45]; + int offset = 0; + offset = zzUnpackTrans(ZZ_TRANS_PACKED_0, offset, result); + return result; + } + + private static int zzUnpackTrans(String packed, int offset, int [] result) { + int i = 0; /* index in packed string */ + int j = offset; /* index in unpacked array */ + int l = packed.length(); + while (i < l) { + int count = packed.charAt(i++); + int value = packed.charAt(i++); + value--; + do result[j++] = value; while (--count > 0); + } + return j; + } + + + /* error codes */ + private static final int ZZ_UNKNOWN_ERROR = 0; + private static final int ZZ_NO_MATCH = 1; + private static final int ZZ_PUSHBACK_2BIG = 2; + + /* error messages for the codes above */ + private static final String ZZ_ERROR_MSG[] = { + "Unkown internal scanner error", + "Error: could not match input", + "Error: pushback value was too large" + }; + + /** + * ZZ_ATTRIBUTE[aState] contains the attributes of state aState + */ + private static final int [] ZZ_ATTRIBUTE = zzUnpackAttribute(); + + private static final String ZZ_ATTRIBUTE_PACKED_0 = + "\1\0\1\11\3\1\5\11"; + + private static int [] zzUnpackAttribute() { + int [] result = new int[10]; + int offset = 0; + offset = zzUnpackAttribute(ZZ_ATTRIBUTE_PACKED_0, offset, result); + return result; + } + + private static int zzUnpackAttribute(String packed, int offset, int [] result) { + int i = 0; /* index in packed string */ + int j = offset; /* index in unpacked array */ + int l = packed.length(); + while (i < l) { + int count = packed.charAt(i++); + int value = packed.charAt(i++); + do result[j++] = value; while (--count > 0); + } + return j; + } + + /** the input device */ + private java.io.Reader zzReader; + + /** the current state of the DFA */ + private int zzState; + + /** the current lexical state */ + private int zzLexicalState = YYINITIAL; + + /** this buffer contains the current text to be matched and is + the source of the yytext() string */ + private char zzBuffer[] = new char[ZZ_BUFFERSIZE]; + + /** the textposition at the last accepting state */ + private int zzMarkedPos; + + /** the current text position in the buffer */ + private int zzCurrentPos; + + /** startRead marks the beginning of the yytext() string in the buffer */ + private int zzStartRead; + + /** endRead marks the last character in the buffer, that has been read + from input */ + private int zzEndRead; + + /** number of newlines encountered up to the start of the matched text */ + private int yyline; + + /** the number of characters up to the start of the matched text */ + private int yychar; + + /** + * the number of characters from the last newline up to the start of the + * matched text + */ + private int yycolumn; + + /** + * zzAtBOL == true <=> the scanner is currently at the beginning of a line + */ + private boolean zzAtBOL = true; + + /** zzAtEOF == true <=> the scanner is at the EOF */ + private boolean zzAtEOF; + + /** denotes if the user-EOF-code has already been executed */ + private boolean zzEOFDone; + + /* user code: */ + + + /** + * Create an empty lexer, yyrset will be called later to reset and assign + * the reader + */ + public ConditionLexer() { + + } + + public int yychar() { + return yychar; + } + + public int yyline() { + return yyline+1; + } + + private Stack pushedBack=new Stack(); + + public void pushback(ConditionToken symb) { + pushedBack.push(symb); + } + + public ConditionToken lex() throws java.io.IOException, ParseException{ + ConditionToken ret=null; + if(!pushedBack.isEmpty()){ + ret = pushedBack.pop(); + }else{ + ret = yylex(); + } + return ret; + } + + + + /** + * Creates a new scanner + * There is also a java.io.InputStream version of this constructor. + * + * @param in the java.io.Reader to read input from. + */ + public ConditionLexer(java.io.Reader in) { + this.zzReader = in; + } + + /** + * Creates a new scanner. + * There is also java.io.Reader version of this constructor. + * + * @param in the java.io.Inputstream to read input from. + */ + public ConditionLexer(java.io.InputStream in) { + this(new java.io.InputStreamReader + (in, java.nio.charset.Charset.forName("UTF-8"))); + } + + /** + * Unpacks the compressed character translation table. + * + * @param packed the packed character translation table + * @return the unpacked character translation table + */ + private static char [] zzUnpackCMap(String packed) { + char [] map = new char[0x10000]; + int i = 0; /* index in packed string */ + int j = 0; /* index in unpacked array */ + while (i < 64) { + int count = packed.charAt(i++); + char value = packed.charAt(i++); + do map[j++] = value; while (--count > 0); + } + return map; + } + + + /** + * Refills the input buffer. + * + * @return false, iff there was new input. + * + * @exception java.io.IOException if any I/O-Error occurs + */ + private boolean zzRefill() throws java.io.IOException { + + /* first: make room (if you can) */ + if (zzStartRead > 0) { + System.arraycopy(zzBuffer, zzStartRead, + zzBuffer, 0, + zzEndRead-zzStartRead); + + /* translate stored positions */ + zzEndRead-= zzStartRead; + zzCurrentPos-= zzStartRead; + zzMarkedPos-= zzStartRead; + zzStartRead = 0; + } + + /* is the buffer big enough? */ + if (zzCurrentPos >= zzBuffer.length) { + /* if not: blow it up */ + char newBuffer[] = new char[zzCurrentPos*2]; + System.arraycopy(zzBuffer, 0, newBuffer, 0, zzBuffer.length); + zzBuffer = newBuffer; + } + + /* finally: fill the buffer with new input */ + int numRead = zzReader.read(zzBuffer, zzEndRead, + zzBuffer.length-zzEndRead); + + if (numRead > 0) { + zzEndRead+= numRead; + return false; + } + // unlikely but not impossible: read 0 characters, but not at end of stream + if (numRead == 0) { + int c = zzReader.read(); + if (c == -1) { + return true; + } else { + zzBuffer[zzEndRead++] = (char) c; + return false; + } + } + + // numRead < 0 + return true; + } + + + /** + * Closes the input stream. + */ + public final void yyclose() throws java.io.IOException { + zzAtEOF = true; /* indicate end of file */ + zzEndRead = zzStartRead; /* invalidate buffer */ + + if (zzReader != null) + zzReader.close(); + } + + + /** + * Resets the scanner to read from a new input stream. + * Does not close the old reader. + * + * All internal variables are reset, the old input stream + * cannot be reused (internal buffer is discarded and lost). + * Lexical state is set to ZZ_INITIAL. + * + * Internal scan buffer is resized down to its initial length, if it has grown. + * + * @param reader the new input stream + */ + public final void yyreset(java.io.Reader reader) { + zzReader = reader; + zzAtBOL = true; + zzAtEOF = false; + zzEOFDone = false; + zzEndRead = zzStartRead = 0; + zzCurrentPos = zzMarkedPos = 0; + yyline = yychar = yycolumn = 0; + zzLexicalState = YYINITIAL; + if (zzBuffer.length > ZZ_BUFFERSIZE) + zzBuffer = new char[ZZ_BUFFERSIZE]; + } + + + /** + * Returns the current lexical state. + */ + public final int yystate() { + return zzLexicalState; + } + + + /** + * Enters a new lexical state + * + * @param newState the new lexical state + */ + public final void yybegin(int newState) { + zzLexicalState = newState; + } + + + /** + * Returns the text matched by the current regular expression. + */ + public final String yytext() { + return new String( zzBuffer, zzStartRead, zzMarkedPos-zzStartRead ); + } + + + /** + * Returns the character at position pos from the + * matched text. + * + * It is equivalent to yytext().charAt(pos), but faster + * + * @param pos the position of the character to fetch. + * A value from 0 to yylength()-1. + * + * @return the character at position pos + */ + public final char yycharat(int pos) { + return zzBuffer[zzStartRead+pos]; + } + + + /** + * Returns the length of the matched text region. + */ + public final int yylength() { + return zzMarkedPos-zzStartRead; + } + + + /** + * Reports an error that occured while scanning. + * + * In a wellformed scanner (no or only correct usage of + * yypushback(int) and a match-all fallback rule) this method + * will only be called with things that "Can't Possibly Happen". + * If this method is called, something is seriously wrong + * (e.g. a JFlex bug producing a faulty scanner etc.). + * + * Usual syntax/scanner level error handling should be done + * in error fallback rules. + * + * @param errorCode the code of the errormessage to display + */ + private void zzScanError(int errorCode) { + String message; + try { + message = ZZ_ERROR_MSG[errorCode]; + } + catch (ArrayIndexOutOfBoundsException e) { + message = ZZ_ERROR_MSG[ZZ_UNKNOWN_ERROR]; + } + + throw new Error(message); + } + + + /** + * Pushes the specified amount of characters back into the input stream. + * + * They will be read again by then next call of the scanning method + * + * @param number the number of characters to be read again. + * This number must not be greater than yylength()! + */ + public void yypushback(int number) { + if ( number > yylength() ) + zzScanError(ZZ_PUSHBACK_2BIG); + + zzMarkedPos -= number; + } + + + /** + * Resumes scanning until the next regular expression is matched, + * the end of input is encountered or an I/O-Error occurs. + * + * @return the next token + * @exception java.io.IOException if any I/O-Error occurs + */ + public ConditionToken yylex() throws java.io.IOException, ParseException { + int zzInput; + int zzAction; + + // cached fields: + int zzCurrentPosL; + int zzMarkedPosL; + int zzEndReadL = zzEndRead; + char [] zzBufferL = zzBuffer; + char [] zzCMapL = ZZ_CMAP; + + int [] zzTransL = ZZ_TRANS; + int [] zzRowMapL = ZZ_ROWMAP; + int [] zzAttrL = ZZ_ATTRIBUTE; + + while (true) { + zzMarkedPosL = zzMarkedPos; + + yychar+= zzMarkedPosL-zzStartRead; + + boolean zzR = false; + for (zzCurrentPosL = zzStartRead; zzCurrentPosL < zzMarkedPosL; + zzCurrentPosL++) { + switch (zzBufferL[zzCurrentPosL]) { + case '\u000B': + case '\u000C': + case '\u0085': + case '\u2028': + case '\u2029': + yyline++; + yycolumn = 0; + zzR = false; + break; + case '\r': + yyline++; + yycolumn = 0; + zzR = true; + break; + case '\n': + if (zzR) + zzR = false; + else { + yyline++; + yycolumn = 0; + } + break; + default: + zzR = false; + yycolumn++; + } + } + + if (zzR) { + // peek one character ahead if it is \n (if we have counted one line too much) + boolean zzPeek; + if (zzMarkedPosL < zzEndReadL) + zzPeek = zzBufferL[zzMarkedPosL] == '\n'; + else if (zzAtEOF) + zzPeek = false; + else { + boolean eof = zzRefill(); + zzEndReadL = zzEndRead; + zzMarkedPosL = zzMarkedPos; + zzBufferL = zzBuffer; + if (eof) + zzPeek = false; + else + zzPeek = zzBufferL[zzMarkedPosL] == '\n'; + } + if (zzPeek) yyline--; + } + zzAction = -1; + + zzCurrentPosL = zzCurrentPos = zzStartRead = zzMarkedPosL; + + zzState = ZZ_LEXSTATE[zzLexicalState]; + + // set up zzAction for empty match case: + int zzAttributes = zzAttrL[zzState]; + if ( (zzAttributes & 1) == 1 ) { + zzAction = zzState; + } + + + zzForAction: { + while (true) { + + if (zzCurrentPosL < zzEndReadL) + zzInput = zzBufferL[zzCurrentPosL++]; + else if (zzAtEOF) { + zzInput = YYEOF; + break zzForAction; + } + else { + // store back cached positions + zzCurrentPos = zzCurrentPosL; + zzMarkedPos = zzMarkedPosL; + boolean eof = zzRefill(); + // get translated positions and possibly new buffer + zzCurrentPosL = zzCurrentPos; + zzMarkedPosL = zzMarkedPos; + zzBufferL = zzBuffer; + zzEndReadL = zzEndRead; + if (eof) { + zzInput = YYEOF; + break zzForAction; + } + else { + zzInput = zzBufferL[zzCurrentPosL++]; + } + } + int zzNext = zzTransL[ zzRowMapL[zzState] + zzCMapL[zzInput] ]; + if (zzNext == -1) break zzForAction; + zzState = zzNext; + + zzAttributes = zzAttrL[zzState]; + if ( (zzAttributes & 1) == 1 ) { + zzAction = zzState; + zzMarkedPosL = zzCurrentPosL; + if ( (zzAttributes & 8) == 8 ) break zzForAction; + } + + } + } + + // store back cached position + zzMarkedPos = zzMarkedPosL; + + switch (zzAction < 0 ? zzAction : ZZ_ACTION[zzAction]) { + case 1: + { + } + case 8: break; + case 2: + { return new ConditionToken(ConditionTokenType.FIELD,yytext()); + } + case 9: break; + case 3: + { return new ConditionToken(ConditionTokenType.OR,yytext()); + } + case 10: break; + case 4: + { return new ConditionToken(ConditionTokenType.AND,yytext()); + } + case 11: break; + case 5: + { return new ConditionToken(ConditionTokenType.NOT,yytext()); + } + case 12: break; + case 6: + { return new ConditionToken(ConditionTokenType.PARENT_OPEN,yytext()); + } + case 13: break; + case 7: + { return new ConditionToken(ConditionTokenType.PARENT_CLOSE,yytext()); + } + case 14: break; + default: + if (zzInput == YYEOF && zzStartRead == zzCurrentPos) { + zzAtEOF = true; + switch (zzLexicalState) { + case YYINITIAL: { + return null; + } + case 11: break; + default: + return null; + } + } + else { + zzScanError(ZZ_NO_MATCH); + } + } + } + } + + +} diff --git a/trunk/src/com/jpexs/decompiler/flash/types/annotations/parser/ConditionToken.java b/trunk/src/com/jpexs/decompiler/flash/types/annotations/parser/ConditionToken.java new file mode 100644 index 000000000..6be92a5c1 --- /dev/null +++ b/trunk/src/com/jpexs/decompiler/flash/types/annotations/parser/ConditionToken.java @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2014 JPEXS + * + * 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 3 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, see . + */ + +package com.jpexs.decompiler.flash.types.annotations.parser; + +/** + * + * @author JPEXS + */ +public class ConditionToken { + public String value; + public ConditionTokenType type; + + public ConditionToken(ConditionTokenType type,String value) { + this.value = value; + this.type = type; + } + + @Override + public String toString() { + return type.toString()+(value!=null?"["+value+"]":""); + } + + + +} diff --git a/trunk/src/com/jpexs/decompiler/flash/types/annotations/parser/ConditionTokenType.java b/trunk/src/com/jpexs/decompiler/flash/types/annotations/parser/ConditionTokenType.java new file mode 100644 index 000000000..4ff90dcd5 --- /dev/null +++ b/trunk/src/com/jpexs/decompiler/flash/types/annotations/parser/ConditionTokenType.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2014 JPEXS + * + * 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 3 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, see . + */ + +package com.jpexs.decompiler.flash.types.annotations.parser; + +/** + * + * @author JPEXS + */ +public enum ConditionTokenType { + FIELD, + OR, + AND, + PARENT_OPEN, + PARENT_CLOSE, + NOT +} diff --git a/trunk/src/com/jpexs/decompiler/flash/types/annotations/parser/ParseException.java b/trunk/src/com/jpexs/decompiler/flash/types/annotations/parser/ParseException.java new file mode 100644 index 000000000..092a633bb --- /dev/null +++ b/trunk/src/com/jpexs/decompiler/flash/types/annotations/parser/ParseException.java @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2010-2014 JPEXS + * + * 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 3 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, see . + */ +package com.jpexs.decompiler.flash.types.annotations.parser; + +public class ParseException extends Exception { + + public long line; + public String text; + + public ParseException(String text, long line) { + super("ParseException:" + text + " on line " + line); + this.line = line; + this.text = text; + } +} diff --git a/trunk/src/com/jpexs/decompiler/flash/types/annotations/parser/conditions.flex b/trunk/src/com/jpexs/decompiler/flash/types/annotations/parser/conditions.flex new file mode 100644 index 000000000..81e8a0023 --- /dev/null +++ b/trunk/src/com/jpexs/decompiler/flash/types/annotations/parser/conditions.flex @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2010-2014 PEXS + * + * 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 3 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, see . + */ +package com.jpexs.decompiler.flash.types.annotations.parser; + +import java.util.Stack; + +%% + +%public +%class ConditionLexer +%final +%unicode +%char +%line +%column +%type ConditionToken +%throws ParseException + +%{ + + + /** + * Create an empty lexer, yyrset will be called later to reset and assign + * the reader + */ + public ConditionLexer() { + + } + + public int yychar() { + return yychar; + } + + public int yyline() { + return yyline+1; + } + + private Stack pushedBack=new Stack(); + + public void pushback(ConditionToken symb) { + pushedBack.push(symb); + } + + public ConditionToken lex() throws java.io.IOException, ParseException{ + ConditionToken ret=null; + if(!pushedBack.isEmpty()){ + ret = pushedBack.pop(); + }else{ + ret = yylex(); + } + return ret; + } + +%} + +Field = [A-Za-z0-9_\.]+ + +%% + + { + {Field} { + return new ConditionToken(ConditionTokenType.FIELD,yytext()); + } + "||" | "|" { return new ConditionToken(ConditionTokenType.OR,yytext()); } + "&&" | "," | "&" { return new ConditionToken(ConditionTokenType.AND,yytext()); } + "!" { return new ConditionToken(ConditionTokenType.NOT,yytext()); } + "(" { return new ConditionToken(ConditionTokenType.PARENT_OPEN,yytext()); } + ")" { return new ConditionToken(ConditionTokenType.PARENT_CLOSE,yytext()); } + . { } + <> {return null;} +} \ No newline at end of file