1 /* 2 * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package java.util.regex; 27 28 import java.util.HashMap; 29 import java.util.regex.Pattern.CharPredicate; 30 import java.util.regex.CharPredicates; 31 import static java.util.regex.ASCII.*; 32 33 /** 34 * A utility class to print out the pattern node tree. 35 */ 36 37 class PrintPattern { 38 39 private static HashMap<Pattern.Node, Integer> ids = new HashMap<>(); 40 41 private static void print(Pattern.Node node, String text, int depth) { 42 if (!ids.containsKey(node)) 43 ids.put(node, ids.size()); 44 print("%6d:%" + (depth==0? "": depth<<1) + "s<%s>", ids.get(node), "", text); 45 if (ids.containsKey(node.next)) 46 print(" (=>%d)", ids.get(node.next)); 47 print("%n"); 48 } 49 50 private static void print(String s, int depth) { 51 print(" %" + (depth==0?"":depth<<1) + "s<%s>%n", "", s); 52 } 53 54 private static void print(String fmt, Object ... args) { 55 System.err.printf(fmt, args); 56 } 57 58 private static String toStringCPS(int[] cps) { 59 StringBuilder sb = new StringBuilder(cps.length); 60 for (int cp : cps) 61 sb.append(toStringCP(cp)); 62 return sb.toString(); 63 } 64 65 private static String toStringCP(int cp) { 66 return (isPrint(cp) ? "" + (char)cp 67 : "\\u" + Integer.toString(cp, 16)); 68 } 69 70 private static String toStringRange(int min, int max) { 71 if (max == Pattern.MAX_REPS) { 72 if (min == 0) 73 return " * "; 74 else if (min == 1) 75 return " + "; 76 return "{" + min + ", max}"; 77 } 78 return "{" + min + ", " + max + "}"; 79 } 80 81 private static String toStringCtype(int type) { 82 switch(type) { 83 case UPPER: return "ASCII.UPPER"; 84 case LOWER: return "ASCII.LOWER"; 85 case DIGIT: return "ASCII.DIGIT"; 86 case SPACE: return "ASCII.SPACE"; 87 case PUNCT: return "ASCII.PUNCT"; 88 case CNTRL: return "ASCII.CNTRL"; 89 case BLANK: return "ASCII.BLANK"; 90 case UNDER: return "ASCII.UNDER"; 91 case ASCII: return "ASCII.ASCII"; 92 case ALPHA: return "ASCII.ALPHA"; 93 case ALNUM: return "ASCII.ALNUM"; 94 case GRAPH: return "ASCII.GRAPH"; 95 case WORD: return "ASCII.WORD"; 96 case XDIGIT: return "ASCII.XDIGIT"; 97 default: return "ASCII ?"; 98 } 99 } 100 101 private static String toString(Pattern.Node node) { 102 String name = node.getClass().getName(); 103 return name.substring(name.lastIndexOf('$') + 1); 104 } 105 106 static HashMap<CharPredicate, String> pmap; 107 static { 108 pmap = new HashMap<>(); 109 pmap.put(Pattern.ALL, "All"); 110 pmap.put(Pattern.DOT, "Dot"); 111 pmap.put(Pattern.UNIXDOT, "UnixDot"); 112 pmap.put(Pattern.VertWS, "VertWS"); 113 pmap.put(Pattern.HorizWS, "HorizWS"); 114 115 pmap.put(CharPredicates.ASCII_DIGIT, "ASCII.DIGIT"); 116 pmap.put(CharPredicates.ASCII_WORD, "ASCII.WORD"); 117 pmap.put(CharPredicates.ASCII_SPACE, "ASCII.SPACE"); 118 } 119 120 static void walk(Pattern.Node node, int depth) { 121 depth++; 122 while(node != null) { 123 String name = toString(node); 124 String str; 125 if (node instanceof Pattern.Prolog) { 126 print(node, name, depth); 127 // print the loop here 128 Pattern.Loop loop = ((Pattern.Prolog)node).loop; 129 name = toString(loop); 130 str = name + " " + toStringRange(loop.cmin, loop.cmax); 131 print(loop, str, depth); 132 walk(loop.body, depth); 133 print("/" + name, depth); 134 node = loop; 135 } else if (node instanceof Pattern.Loop) { 136 return; // stop here, body.next -> loop 137 } else if (node instanceof Pattern.Curly) { 138 Pattern.Curly c = (Pattern.Curly)node; 139 str = "Curly " + c.type + " " + toStringRange(c.cmin, c.cmax); 140 print(node, str, depth); 141 walk(c.atom, depth); 142 print("/Curly", depth); 143 } else if (node instanceof Pattern.GroupCurly) { 144 Pattern.GroupCurly gc = (Pattern.GroupCurly)node; 145 str = "GroupCurly " + gc.groupIndex / 2 + 146 ", " + gc.type + " " + toStringRange(gc.cmin, gc.cmax); 147 print(node, str, depth); 148 walk(gc.atom, depth); 149 print("/GroupCurly", depth); 150 } else if (node instanceof Pattern.GroupHead) { 151 Pattern.GroupHead head = (Pattern.GroupHead)node; 152 Pattern.GroupTail tail = head.tail; 153 print(head, "Group.head " + (tail.groupIndex / 2), depth); 154 walk(head.next, depth); 155 print(tail, "/Group.tail " + (tail.groupIndex / 2), depth); 156 node = tail; 157 } else if (node instanceof Pattern.GroupTail) { 158 return; // stopper 159 } else if (node instanceof Pattern.Ques) { 160 print(node, "Ques " + ((Pattern.Ques)node).type, depth); 161 walk(((Pattern.Ques)node).atom, depth); 162 print("/Ques", depth); 163 } else if (node instanceof Pattern.Branch) { 164 Pattern.Branch b = (Pattern.Branch)node; 165 print(b, name, depth); 166 int i = 0; 167 while (true) { 168 if (b.atoms[i] != null) { 169 walk(b.atoms[i], depth); 170 } else { 171 print(" (accepted)", depth); 172 } 173 if (++i == b.size) 174 break; 175 print("-branch.separator-", depth); 176 } 177 node = b.conn; 178 print(node, "/Branch", depth); 179 } else if (node instanceof Pattern.BranchConn) { 180 return; 181 } else if (node instanceof Pattern.CharProperty) { 182 str = pmap.get(((Pattern.CharProperty)node).predicate); 183 if (str == null) 184 str = toString(node); 185 else 186 str = "Single \"" + str + "\""; 187 print(node, str, depth); 188 } else if (node instanceof Pattern.SliceNode) { 189 str = name + " \"" + 190 toStringCPS(((Pattern.SliceNode)node).buffer) + "\""; 191 print(node, str, depth); 192 } else if (node instanceof Pattern.CharPropertyGreedy) { 193 Pattern.CharPropertyGreedy gcp = (Pattern.CharPropertyGreedy)node; 194 String pstr = pmap.get(gcp.predicate); 195 if (pstr == null) 196 pstr = gcp.predicate.toString(); 197 else 198 pstr = "Single \"" + pstr + "\""; 199 str = name + " " + pstr + ((gcp.cmin == 0) ? "*" : "+"); 200 print(node, str, depth); 201 } else if (node instanceof Pattern.BackRef) { 202 str = "GroupBackRef " + ((Pattern.BackRef)node).groupIndex / 2; 203 print(node, str, depth); 204 } else if (node instanceof Pattern.LastNode) { 205 print(node, "END", depth); 206 } else if (node == Pattern.accept) { 207 return; 208 } else { 209 print(node, name, depth); 210 } 211 node = node.next; 212 } 213 } 214 215 public static void main(String[] args) { 216 Pattern p = Pattern.compile(args[0]); 217 System.out.println(" Pattern: " + p); 218 walk(p.root, 0); 219 } 220 }