Frames | No Frames |
1: /* node.java -- 2: Copyright (C) 2005 Free Software Foundation, Inc. 3: 4: This file is part of GNU Classpath. 5: 6: GNU Classpath is free software; you can redistribute it and/or modify 7: it under the terms of the GNU General Public License as published by 8: the Free Software Foundation; either version 2, or (at your option) 9: any later version. 10: 11: GNU Classpath is distributed in the hope that it will be useful, but 12: WITHOUT ANY WARRANTY; without even the implied warranty of 13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14: General Public License for more details. 15: 16: You should have received a copy of the GNU General Public License 17: along with GNU Classpath; see the file COPYING. If not, write to the 18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 19: 02110-1301 USA. 20: 21: Linking this library statically or dynamically with other modules is 22: making a combined work based on this library. Thus, the terms and 23: conditions of the GNU General Public License cover the whole 24: combination. 25: 26: As a special exception, the copyright holders of this library give you 27: permission to link this library with independent modules to produce an 28: executable, regardless of the license terms of these independent 29: modules, and to copy and distribute the resulting executable under 30: terms of your choice, provided that you also meet, for each linked 31: independent module, the terms and conditions of the license of that 32: module. An independent module is a module which is not derived from 33: or based on this library. If you modify this library, you may extend 34: this exception to your version of the library, but you are not 35: obligated to do so. If you do not wish to do so, delete this 36: exception statement from your version. */ 37: 38: 39: package gnu.javax.swing.text.html.parser.models; 40: 41: import java.io.Serializable; 42: 43: /** 44: * Part of the internal representation of the content model. 45: * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) 46: */ 47: public class node 48: implements Serializable 49: { 50: private static final long serialVersionUID = 1; 51: 52: /** 53: * The token to match (can be instance of list). 54: */ 55: public Object token; 56: 57: /** 58: * True for the node that cannot be visited again. 59: */ 60: public boolean _closed; 61: 62: /** 63: * The binary operation for this node. 64: */ 65: public char binary; 66: 67: /** 68: * The unary opeation for this node. 69: */ 70: public char unary; 71: 72: /** 73: * The number of times the node already was visited. 74: */ 75: public int visits; 76: 77: /** 78: * The previous node in content model (used for closing nodes). 79: */ 80: public node previous; 81: 82: /** 83: * Creates a new node. 84: * @param binary_operator The operator, connecting all nodes in the list. 85: * The nodes, connected by the different operators, must be arranged into 86: * the different lists. 87: * @param unary_operator The unary operator for this node or zero if 88: * no such was specified. 89: * @param token The token to match. This can be either a string or 90: * the new instance of the list. 91: * @param a_previous The previous node in the list, null for the first 92: * node. This is used for propagating the closing operation for the 93: * comma delimited list. 94: */ 95: public node(char binary_operator, char unary_operator, Object a_token) 96: { 97: if (a_token != null) 98: if (a_token.getClass().equals(node.class)) 99: throw new Error("Creating node in node is redundant and ineffective."); 100: 101: binary = binary_operator; 102: unary = unary_operator; 103: token = a_token; 104: } 105: 106: /** 107: * Checks if this node is in the closed state. 108: * @return True if the node is closed. 109: */ 110: public boolean isClosed() 111: { 112: return _closed; 113: } 114: 115: /** 116: * Check if closing this node means closing the previous node. 117: */ 118: public boolean closePrevious() 119: { 120: return binary == ','; 121: } 122: 123: /** 124: * Return the token object if it could match as a next token in 125: * a token list of null if it could not. 126: * @return 127: */ 128: public Object findFreeNode() 129: { 130: boolean ok; 131: if (isClosed() || silenceAllowed()) 132: return null; 133: 134: // Try if the node would stay valid after a one more visit. 135: visits++; 136: ok = valid(); 137: visits--; 138: 139: if (ok) 140: { 141: if (token instanceof node) 142: return ((node) token).findFreeNode(); 143: else 144: return token; 145: } 146: else 147: return null; 148: } 149: 150: /** 151: * Check if the current situation is such that the node must be closed 152: * now. 153: */ 154: public boolean mustClose() 155: { 156: switch (unary) 157: { 158: case 0 : 159: return true; 160: 161: case '*' : 162: return false; 163: 164: case '+' : 165: return false; 166: 167: case '?' : 168: return visits <= 1; 169: 170: default : 171: throw new Error("Invalid unary operation " + unary + " ( '" + 172: (char) unary + "' )" 173: ); 174: } 175: } 176: 177: /** 178: * Do the match operation with the given token. This sets various 179: * flags. 180: * @param token The token to match. 181: * @return true if the the token matches node, false if it does not match 182: * or if the node is closed. 183: */ 184: public boolean performMatch(Object a_token) 185: { 186: if (isClosed()) 187: return false; 188: 189: boolean matches = compare(a_token); 190: if (matches) 191: matches(); 192: 193: return matches; 194: } 195: 196: /** 197: * Prepares the node for matching against a new list of tokens. 198: */ 199: public void reset() 200: { 201: _closed = false; 202: visits = 0; 203: } 204: 205: /** 206: * Check if the provided token can match this node. 207: * In the case of match, the node state changes, moving 208: * current position after the matched token. However if this method 209: * returns a suggested new token to insert before the provided one, 210: * the state of the list does not change. 211: * @return Boolean.TRUE if the match is found, 212: * Boolean.FALSE if the match is not possible and no token can be 213: * inserted to make the match valid. Otherwise, returns the 214: * token object that can be inserted before the last token in the 215: * list, probably (not for sure) making the match valid. 216: */ 217: public Object show(Object x) 218: { 219: if (compare(x)) 220: return performMatch(x) ? Boolean.TRUE : Boolean.FALSE; 221: 222: Object recommended = findFreeNode(); 223: return recommended != null ? recommended : Boolean.FALSE; 224: } 225: 226: /** 227: * Check if it would be a valid case if this node is visited zero times. 228: * Nodes with unary operator * or ? need not be matched to make a 229: * model valid. 230: */ 231: public boolean silenceAllowed() 232: { 233: return unary == '?' || unary == '*'; 234: } 235: 236: /** 237: * Returns a string representation of the list. 238: * @return String representation, similar to BNF expression. 239: */ 240: public String toString() 241: { 242: StringBuffer b = new StringBuffer(); 243: 244: b.append(token); 245: if (unary != 0) 246: b.append((char) unary); 247: else 248: b.append('\''); 249: 250: return b.toString(); 251: } 252: 253: /** 254: * Check if the node state is valid. 255: */ 256: public boolean valid() 257: { 258: switch (unary) 259: { 260: case 0 : 261: if (binary == '|') 262: return true; 263: else 264: return visits == 1; 265: 266: case '*' : 267: return true; 268: 269: case '+' : 270: return visits > 0; 271: 272: case '?' : 273: return visits <= 1; 274: 275: default : 276: throw new Error("Invalid unary operation " + unary + " ( '" + 277: (char) unary + "' )" 278: ); 279: } 280: } 281: 282: public boolean validPreliminary() 283: { 284: return visits == 0 || valid(); 285: } 286: 287: /** 288: * Closes this node and, if closePrevious() returs true, calls close() for 289: * the previous node. 290: */ 291: protected void close() 292: { 293: _closed = true; 294: if (previous != null && closePrevious()) 295: previous.close(); 296: } 297: 298: /** 299: * Compare the provided token object with the token object of this node. 300: */ 301: protected boolean compare(Object a_token) 302: { 303: if (token instanceof Object[]) 304: throw new Error("Invalid token object, probably the 'list' " + 305: "should be used. " 306: ); 307: 308: if (token instanceof node[]) 309: throw new Error("Do not use 'node' for the array of nodes, use 'list'. "); 310: 311: if (token instanceof node) 312: { 313: return ((node) token).performMatch(a_token); 314: } 315: 316: boolean rt = false; 317: 318: if (token == a_token) 319: rt = true; 320: if (token.equals(a_token)) 321: rt = true; 322: if (token.toString().equalsIgnoreCase(a_token.toString())) 323: rt = true; 324: 325: return rt; 326: } 327: 328: /** 329: * Fire the changes that must happen then the token matches this node. 330: */ 331: protected void matches() 332: { 333: visits++; 334: if (mustClose()) 335: close(); 336: } 337: }