1 /********************************************************************
3 * Copyright (c) 2001-2010, International Business Machines Corporation and
4 * others. All Rights Reserved.
5 ********************************************************************/
7 package com.ibm.icu.text;
9 import java.util.HashSet;
10 import java.util.List;
13 import com.ibm.icu.impl.Assert;
16 * This class represents a node in the parse tree created by the RBBI Rule compiler.
22 static final int setRef = 0;
23 static final int uset = 1;
24 static final int varRef = 2;
25 static final int leafChar = 3;
26 static final int lookAhead = 4;
27 static final int tag = 5;
28 static final int endMark = 6;
29 static final int opStart = 7;
30 static final int opCat = 8;
31 static final int opOr = 9;
32 static final int opStar = 10;
33 static final int opPlus = 11;
34 static final int opQuestion = 12;
35 static final int opBreak = 13;
36 static final int opReverse = 14;
37 static final int opLParen = 15;
38 static final int nodeTypeLimit = 16; // For Assertion checking only.
40 static final String [] nodeTypeNames = {
59 // enum OpPrecedence {
60 static final int precZero = 0;
61 static final int precStart = 1;
62 static final int precLParen = 2;
63 static final int precOpOr = 3;
64 static final int precOpCat = 4;
66 int fType; // enum NodeType
70 UnicodeSet fInputSet; // For uset nodes only.
71 int fPrecedence = precZero; // enum OpPrecedence, For binary ops only.
73 String fText; // Text corresponding to this node.
74 // May be lazily evaluated when (if) needed
75 // for some node types.
76 int fFirstPos; // Position in the rule source string of the
77 // first text associated with the node.
78 // If there's a left child, this will be the same
79 // as that child's left pos.
80 int fLastPos; // Last position in the rule source string
81 // of any text associated with this node.
82 // If there's a right child, this will be the same
83 // as that child's last postion.
85 boolean fNullable; // See Aho DFA table generation algorithm
86 int fVal; // For leafChar nodes, the value.
87 // Values are the character category,
88 // corresponds to columns in the final
89 // state transition table.
91 boolean fLookAheadEnd; // For endMark nodes, set TRUE if
92 // marking the end of a look-ahead rule.
94 Set<RBBINode> fFirstPosSet; // See Aho DFA table generation algorithm
95 Set<RBBINode> fLastPosSet; // See Aho.
96 Set<RBBINode> fFollowPos; // See Aho.
98 int fSerialNum; // Debugging aids. Each node gets a unique serial number.
99 static int gLastSerial;
102 Assert.assrt(t < nodeTypeLimit);
103 fSerialNum = ++gLastSerial;
106 fFirstPosSet = new HashSet<RBBINode>();
107 fLastPosSet = new HashSet<RBBINode>();
108 fFollowPos = new HashSet<RBBINode>();
110 fPrecedence = precOpCat;
111 } else if (t == opOr) {
112 fPrecedence = precOpOr;
113 } else if (t == opStart) {
114 fPrecedence = precStart;
115 } else if (t == opLParen) {
116 fPrecedence = precLParen;
118 fPrecedence = precZero;
122 RBBINode(RBBINode other) {
123 fSerialNum = ++gLastSerial;
125 fInputSet = other.fInputSet;
126 fPrecedence = other.fPrecedence;
128 fFirstPos = other.fFirstPos;
129 fLastPos = other.fLastPos;
130 fNullable = other.fNullable;
132 fFirstPosSet = new HashSet<RBBINode>(other.fFirstPosSet);
133 fLastPosSet = new HashSet<RBBINode>(other.fLastPosSet);
134 fFollowPos = new HashSet<RBBINode>(other.fFollowPos);
137 //-------------------------------------------------------------------------
139 // cloneTree Make a copy of the subtree rooted at this node.
140 // Discard any variable references encountered along the way,
141 // and replace with copies of the variable's definitions.
142 // Used to replicate the expression underneath variable
143 // references in preparation for generating the DFA tables.
145 //-------------------------------------------------------------------------
146 RBBINode cloneTree() {
149 if (fType == RBBINode.varRef) {
150 // If the current node is a variable reference, skip over it
151 // and clone the definition of the variable instead.
152 n = fLeftChild.cloneTree();
153 } else if (fType == RBBINode.uset) {
156 n = new RBBINode(this);
157 if (fLeftChild != null) {
158 n.fLeftChild = fLeftChild.cloneTree();
159 n.fLeftChild.fParent = n;
161 if (fRightChild != null) {
162 n.fRightChild = fRightChild.cloneTree();
163 n.fRightChild.fParent = n;
171 //-------------------------------------------------------------------------
173 // flattenVariables Walk a parse tree, replacing any variable
174 // references with a copy of the variable's definition.
175 // Aside from variables, the tree is not changed.
177 // Return the root of the tree. If the root was not a variable
178 // reference, it remains unchanged - the root we started with
179 // is the root we return. If, however, the root was a variable
180 // reference, the root of the newly cloned replacement tree will
181 // be returned, and the original tree deleted.
183 // This function works by recursively walking the tree
184 // without doing anything until a variable reference is
185 // found, then calling cloneTree() at that point. Any
186 // nested references are handled by cloneTree(), not here.
188 //-------------------------------------------------------------------------
189 RBBINode flattenVariables() {
190 if (fType == varRef) {
191 RBBINode retNode = fLeftChild.cloneTree();
196 if (fLeftChild != null) {
197 fLeftChild = fLeftChild.flattenVariables();
198 fLeftChild.fParent = this;
200 if (fRightChild != null) {
201 fRightChild = fRightChild.flattenVariables();
202 fRightChild.fParent = this;
207 //-------------------------------------------------------------------------
209 // flattenSets Walk the parse tree, replacing any nodes of type setRef
210 // with a copy of the expression tree for the set. A set's
211 // equivalent expression tree is precomputed and saved as
212 // the left child of the uset node.
214 //-------------------------------------------------------------------------
216 Assert.assrt(fType != setRef);
218 if (fLeftChild != null) {
219 if (fLeftChild.fType == setRef) {
220 RBBINode setRefNode = fLeftChild;
221 RBBINode usetNode = setRefNode.fLeftChild;
222 RBBINode replTree = usetNode.fLeftChild;
223 fLeftChild = replTree.cloneTree();
224 fLeftChild.fParent = this;
226 fLeftChild.flattenSets();
230 if (fRightChild != null) {
231 if (fRightChild.fType == setRef) {
232 RBBINode setRefNode = fRightChild;
233 RBBINode usetNode = setRefNode.fLeftChild;
234 RBBINode replTree = usetNode.fLeftChild;
235 fRightChild = replTree.cloneTree();
236 fRightChild.fParent = this;
237 // delete setRefNode;
239 fRightChild.flattenSets();
244 //-------------------------------------------------------------------------
246 // findNodes() Locate all the nodes of the specified type, starting
247 // at the specified root.
249 //-------------------------------------------------------------------------
250 void findNodes(List<RBBINode> dest, int kind) {
254 if (fLeftChild != null) {
255 fLeftChild.findNodes(dest, kind);
257 if (fRightChild != null) {
258 fRightChild.findNodes(dest, kind);
264 //-------------------------------------------------------------------------
266 // print. Print out a single node, for debugging.
268 //-------------------------------------------------------------------------
270 static void printNode(RBBINode n) {
273 System.out.print (" -- null --\n");
275 RBBINode.printInt( n.fSerialNum, 10);
276 RBBINode.printString(nodeTypeNames[n.fType], 11);
277 RBBINode.printInt(n.fParent==null? 0 : n.fParent.fSerialNum, 11);
278 RBBINode.printInt(n.fLeftChild==null? 0 : n.fLeftChild.fSerialNum, 11);
279 RBBINode.printInt(n.fRightChild==null? 0 : n.fRightChild.fSerialNum, 12);
280 RBBINode.printInt(n.fFirstPos, 12);
281 RBBINode.printInt(n.fVal, 7);
283 if (n.fType == varRef) {
284 System.out.print(" " + n.fText);
287 System.out.println("");
292 // Print a String in a fixed field size.
293 // Debugging function.
295 static void printString(String s, int minWidth) {
296 for (int i = minWidth; i < 0; i++) {
297 // negative width means pad leading spaces, not fixed width.
298 System.out.print(' ');
300 for (int i = s.length(); i < minWidth; i++) {
301 System.out.print(' ');
308 // Print an int in a fixed size field.
309 // Debugging function.
312 static void printInt(int i, int minWidth) {
313 String s = Integer.toString(i);
314 printString(s, Math.max(minWidth, s.length() + 1));
319 static void printHex(int i, int minWidth) {
320 String s = Integer.toString(i, 16);
321 String leadingZeroes = "00000"
322 .substring(0, Math.max(0, 5 - s.length()));
323 s = leadingZeroes + s;
324 printString(s, minWidth);
329 // -------------------------------------------------------------------------
331 // print. Print out the tree of nodes rooted at "this"
333 // -------------------------------------------------------------------------
335 void printTree(boolean printHeading) {
337 System.out.println( "-------------------------------------------------------------------");
338 System.out.println(" Serial type Parent LeftChild RightChild position value");
341 // Only dump the definition under a variable reference if asked to.
342 // Unconditinally dump children of all other node types.
343 if (fType != varRef) {
344 if (fLeftChild != null) {
345 fLeftChild.printTree(false);
348 if (fRightChild != null) {
349 fRightChild.printTree(false);