/src/icu/source/common/rbbiscan.cpp
Line  | Count  | Source (jump to first uncovered line)  | 
1  |  | // © 2016 and later: Unicode, Inc. and others.  | 
2  |  | // License & terms of use: http://www.unicode.org/copyright.html  | 
3  |  | //  | 
4  |  | //  file:  rbbiscan.cpp  | 
5  |  | //  | 
6  |  | //  Copyright (C) 2002-2016, International Business Machines Corporation and others.  | 
7  |  | //  All Rights Reserved.  | 
8  |  | //  | 
9  |  | //  This file contains the Rule Based Break Iterator Rule Builder functions for  | 
10  |  | //   scanning the rules and assembling a parse tree.  This is the first phase  | 
11  |  | //   of compiling the rules.  | 
12  |  | //  | 
13  |  | //  The overall of the rules is managed by class RBBIRuleBuilder, which will  | 
14  |  | //  create and use an instance of this class as part of the process.  | 
15  |  | //  | 
16  |  |  | 
17  |  | #include "unicode/utypes.h"  | 
18  |  |  | 
19  |  | #if !UCONFIG_NO_BREAK_ITERATION  | 
20  |  |  | 
21  |  | #include "unicode/unistr.h"  | 
22  |  | #include "unicode/uniset.h"  | 
23  |  | #include "unicode/uchar.h"  | 
24  |  | #include "unicode/uchriter.h"  | 
25  |  | #include "unicode/parsepos.h"  | 
26  |  | #include "unicode/parseerr.h"  | 
27  |  | #include "cmemory.h"  | 
28  |  | #include "cstring.h"  | 
29  |  |  | 
30  |  | #include "rbbirpt.h"   // Contains state table for the rbbi rules parser.  | 
31  |  |                        //   generated by a Perl script.  | 
32  |  | #include "rbbirb.h"  | 
33  |  | #include "rbbinode.h"  | 
34  |  | #include "rbbiscan.h"  | 
35  |  | #include "rbbitblb.h"  | 
36  |  |  | 
37  |  | #include "uassert.h"  | 
38  |  |  | 
39  |  | //------------------------------------------------------------------------------  | 
40  |  | //  | 
41  |  | // Unicode Set init strings for each of the character classes needed for parsing a rule file.  | 
42  |  | //               (Initialized with hex values for portability to EBCDIC based machines.  | 
43  |  | //                Really ugly, but there's no good way to avoid it.)  | 
44  |  | //  | 
45  |  | //              The sets are referred to by name in the rbbirpt.txt, which is the  | 
46  |  | //              source form of the state transition table for the RBBI rule parser.  | 
47  |  | //  | 
48  |  | //------------------------------------------------------------------------------  | 
49  |  | static const UChar gRuleSet_rule_char_pattern[]       = { | 
50  |  |  // Characters that may appear as literals in patterns without escaping or quoting.  | 
51  |  |  //   [    ^      [    \     p     {      Z     }     \     u    0      0    2      0 | 
52  |  |     0x5b, 0x5e, 0x5b, 0x5c, 0x70, 0x7b, 0x5a, 0x7d, 0x5c, 0x75, 0x30, 0x30, 0x32, 0x30,  | 
53  |  |  //   -    \      u    0     0     7      f     ]     -     [    \      p  | 
54  |  |     0x2d, 0x5c, 0x75, 0x30, 0x30, 0x37, 0x66, 0x5d, 0x2d, 0x5b, 0x5c, 0x70,  | 
55  |  |  //   {     L     }    ]     -     [      \     p     {     N    }      ]     ] | 
56  |  |     0x7b, 0x4c, 0x7d, 0x5d, 0x2d, 0x5b, 0x5c, 0x70, 0x7b, 0x4e, 0x7d, 0x5d, 0x5d, 0};  | 
57  |  |  | 
58  |  | static const UChar gRuleSet_name_char_pattern[]       = { | 
59  |  | //    [    _      \    p     {     L      }     \     p     {    N      }     ] | 
60  |  |     0x5b, 0x5f, 0x5c, 0x70, 0x7b, 0x4c, 0x7d, 0x5c, 0x70, 0x7b, 0x4e, 0x7d, 0x5d, 0};  | 
61  |  |  | 
62  |  | static const UChar gRuleSet_digit_char_pattern[] = { | 
63  |  | //    [    0      -    9     ]  | 
64  |  |     0x5b, 0x30, 0x2d, 0x39, 0x5d, 0};  | 
65  |  |  | 
66  |  | static const UChar gRuleSet_name_start_char_pattern[] = { | 
67  |  | //    [    _      \    p     {     L      }     ] | 
68  |  |     0x5b, 0x5f, 0x5c, 0x70, 0x7b, 0x4c, 0x7d, 0x5d, 0 };  | 
69  |  |  | 
70  |  | static const UChar kAny[] = {0x61, 0x6e, 0x79, 0x00};  // "any" | 
71  |  |  | 
72  |  |  | 
73  |  | U_CDECL_BEGIN  | 
74  | 0  | static void U_CALLCONV RBBISetTable_deleter(void *p) { | 
75  | 0  |     icu::RBBISetTableEl *px = (icu::RBBISetTableEl *)p;  | 
76  | 0  |     delete px->key;  | 
77  |  |     // Note:  px->val is owned by the linked list "fSetsListHead" in scanner.  | 
78  |  |     //        Don't delete the value nodes here.  | 
79  | 0  |     uprv_free(px);  | 
80  | 0  | }  | 
81  |  | U_CDECL_END  | 
82  |  |  | 
83  |  | U_NAMESPACE_BEGIN  | 
84  |  |  | 
85  |  | //------------------------------------------------------------------------------  | 
86  |  | //  | 
87  |  | //  Constructor.  | 
88  |  | //  | 
89  |  | //------------------------------------------------------------------------------  | 
90  |  | RBBIRuleScanner::RBBIRuleScanner(RBBIRuleBuilder *rb)  | 
91  | 0  | { | 
92  | 0  |     fRB                 = rb;  | 
93  | 0  |     fScanIndex          = 0;  | 
94  | 0  |     fNextIndex          = 0;  | 
95  | 0  |     fQuoteMode          = FALSE;  | 
96  | 0  |     fLineNum            = 1;  | 
97  | 0  |     fCharNum            = 0;  | 
98  | 0  |     fLastChar           = 0;  | 
99  |  |       | 
100  | 0  |     fStateTable         = NULL;  | 
101  | 0  |     fStack[0]           = 0;  | 
102  | 0  |     fStackPtr           = 0;  | 
103  | 0  |     fNodeStack[0]       = NULL;  | 
104  | 0  |     fNodeStackPtr       = 0;  | 
105  |  | 
  | 
106  | 0  |     fReverseRule        = FALSE;  | 
107  | 0  |     fLookAheadRule      = FALSE;  | 
108  | 0  |     fNoChainInRule      = FALSE;  | 
109  |  | 
  | 
110  | 0  |     fSymbolTable        = NULL;  | 
111  | 0  |     fSetTable           = NULL;  | 
112  | 0  |     fRuleNum            = 0;  | 
113  | 0  |     fOptionStart        = 0;  | 
114  |  |  | 
115  |  |     // Do not check status until after all critical fields are sufficiently initialized  | 
116  |  |     //   that the destructor can run cleanly.  | 
117  | 0  |     if (U_FAILURE(*rb->fStatus)) { | 
118  | 0  |         return;  | 
119  | 0  |     }  | 
120  |  |  | 
121  |  |     //  | 
122  |  |     //  Set up the constant Unicode Sets.  | 
123  |  |     //     Note:  These could be made static, lazily initialized, and shared among  | 
124  |  |     //            all instances of RBBIRuleScanners.  BUT this is quite a bit simpler,  | 
125  |  |     //            and the time to build these few sets should be small compared to a  | 
126  |  |     //            full break iterator build.  | 
127  | 0  |     fRuleSets[kRuleSet_rule_char-128]  | 
128  | 0  |         = UnicodeSet(UnicodeString(gRuleSet_rule_char_pattern),       *rb->fStatus);  | 
129  |  |     // fRuleSets[kRuleSet_white_space-128] = [:Pattern_White_Space:]  | 
130  | 0  |     fRuleSets[kRuleSet_white_space-128].  | 
131  | 0  |         add(9, 0xd).add(0x20).add(0x85).add(0x200e, 0x200f).add(0x2028, 0x2029);  | 
132  | 0  |     fRuleSets[kRuleSet_name_char-128]  | 
133  | 0  |         = UnicodeSet(UnicodeString(gRuleSet_name_char_pattern),       *rb->fStatus);  | 
134  | 0  |     fRuleSets[kRuleSet_name_start_char-128]  | 
135  | 0  |         = UnicodeSet(UnicodeString(gRuleSet_name_start_char_pattern), *rb->fStatus);  | 
136  | 0  |     fRuleSets[kRuleSet_digit_char-128]  | 
137  | 0  |         = UnicodeSet(UnicodeString(gRuleSet_digit_char_pattern),      *rb->fStatus);  | 
138  | 0  |     if (*rb->fStatus == U_ILLEGAL_ARGUMENT_ERROR) { | 
139  |  |         // This case happens if ICU's data is missing.  UnicodeSet tries to look up property  | 
140  |  |         //   names from the init string, can't find them, and claims an illegal argument.  | 
141  |  |         //   Change the error so that the actual problem will be clearer to users.  | 
142  | 0  |         *rb->fStatus = U_BRK_INIT_ERROR;  | 
143  | 0  |     }  | 
144  | 0  |     if (U_FAILURE(*rb->fStatus)) { | 
145  | 0  |         return;  | 
146  | 0  |     }  | 
147  |  |  | 
148  | 0  |     fSymbolTable = new RBBISymbolTable(this, rb->fRules, *rb->fStatus);  | 
149  | 0  |     if (fSymbolTable == NULL) { | 
150  | 0  |         *rb->fStatus = U_MEMORY_ALLOCATION_ERROR;  | 
151  | 0  |         return;  | 
152  | 0  |     }  | 
153  | 0  |     fSetTable    = uhash_open(uhash_hashUnicodeString, uhash_compareUnicodeString, NULL, rb->fStatus);  | 
154  | 0  |     if (U_FAILURE(*rb->fStatus)) { | 
155  | 0  |         return;  | 
156  | 0  |     }  | 
157  | 0  |     uhash_setValueDeleter(fSetTable, RBBISetTable_deleter);  | 
158  | 0  | }  | 
159  |  |  | 
160  |  |  | 
161  |  |  | 
162  |  | //------------------------------------------------------------------------------  | 
163  |  | //  | 
164  |  | //  Destructor  | 
165  |  | //  | 
166  |  | //------------------------------------------------------------------------------  | 
167  | 0  | RBBIRuleScanner::~RBBIRuleScanner() { | 
168  | 0  |     delete fSymbolTable;  | 
169  | 0  |     if (fSetTable != NULL) { | 
170  | 0  |          uhash_close(fSetTable);  | 
171  | 0  |          fSetTable = NULL;  | 
172  |  | 
  | 
173  | 0  |     }  | 
174  |  |  | 
175  |  |  | 
176  |  |     // Node Stack.  | 
177  |  |     //   Normally has one entry, which is the entire parse tree for the rules.  | 
178  |  |     //   If errors occurred, there may be additional subtrees left on the stack.  | 
179  | 0  |     while (fNodeStackPtr > 0) { | 
180  | 0  |         delete fNodeStack[fNodeStackPtr];  | 
181  | 0  |         fNodeStackPtr--;  | 
182  | 0  |     }  | 
183  |  | 
  | 
184  | 0  | }  | 
185  |  |  | 
186  |  | //------------------------------------------------------------------------------  | 
187  |  | //  | 
188  |  | //  doParseAction        Do some action during rule parsing.  | 
189  |  | //                       Called by the parse state machine.  | 
190  |  | //                       Actions build the parse tree and Unicode Sets,  | 
191  |  | //                       and maintain the parse stack for nested expressions.  | 
192  |  | //  | 
193  |  | //                       TODO:  unify EParseAction and RBBI_RuleParseAction enum types.  | 
194  |  | //                              They represent exactly the same thing.  They're separate  | 
195  |  | //                              only to work around enum forward declaration restrictions  | 
196  |  | //                              in some compilers, while at the same time avoiding multiple  | 
197  |  | //                              definitions problems.  I'm sure that there's a better way.  | 
198  |  | //  | 
199  |  | //------------------------------------------------------------------------------  | 
200  |  | UBool RBBIRuleScanner::doParseActions(int32_t action)  | 
201  | 0  | { | 
202  | 0  |     RBBINode *n       = NULL;  | 
203  |  | 
  | 
204  | 0  |     UBool   returnVal = TRUE;  | 
205  |  | 
  | 
206  | 0  |     switch (action) { | 
207  |  |  | 
208  | 0  |     case doExprStart:  | 
209  | 0  |         pushNewNode(RBBINode::opStart);  | 
210  | 0  |         fRuleNum++;  | 
211  | 0  |         break;  | 
212  |  |  | 
213  |  |  | 
214  | 0  |     case doNoChain:  | 
215  |  |         // Scanned a '^' while on the rule start state.  | 
216  | 0  |         fNoChainInRule = TRUE;  | 
217  | 0  |         break;  | 
218  |  |  | 
219  |  |  | 
220  | 0  |     case doExprOrOperator:  | 
221  | 0  |         { | 
222  | 0  |             fixOpStack(RBBINode::precOpCat);  | 
223  | 0  |             RBBINode  *operandNode = fNodeStack[fNodeStackPtr--];  | 
224  | 0  |             RBBINode  *orNode      = pushNewNode(RBBINode::opOr);  | 
225  | 0  |             if (U_FAILURE(*fRB->fStatus)) { | 
226  | 0  |                 break;  | 
227  | 0  |             }  | 
228  | 0  |             orNode->fLeftChild     = operandNode;  | 
229  | 0  |             operandNode->fParent   = orNode;  | 
230  | 0  |         }  | 
231  | 0  |         break;  | 
232  |  |  | 
233  | 0  |     case doExprCatOperator:  | 
234  |  |         // concatenation operator.  | 
235  |  |         // For the implicit concatenation of adjacent terms in an expression that are  | 
236  |  |         //   not separated by any other operator.  Action is invoked between the  | 
237  |  |         //   actions for the two terms.  | 
238  | 0  |         { | 
239  | 0  |             fixOpStack(RBBINode::precOpCat);  | 
240  | 0  |             RBBINode  *operandNode = fNodeStack[fNodeStackPtr--];  | 
241  | 0  |             RBBINode  *catNode     = pushNewNode(RBBINode::opCat);  | 
242  | 0  |             if (U_FAILURE(*fRB->fStatus)) { | 
243  | 0  |                 break;  | 
244  | 0  |             }  | 
245  | 0  |             catNode->fLeftChild    = operandNode;  | 
246  | 0  |             operandNode->fParent   = catNode;  | 
247  | 0  |         }  | 
248  | 0  |         break;  | 
249  |  |  | 
250  | 0  |     case doLParen:  | 
251  |  |         // Open Paren.  | 
252  |  |         //   The openParen node is a dummy operation type with a low precedence,  | 
253  |  |         //     which has the affect of ensuring that any real binary op that  | 
254  |  |         //     follows within the parens binds more tightly to the operands than  | 
255  |  |         //     stuff outside of the parens.  | 
256  | 0  |         pushNewNode(RBBINode::opLParen);  | 
257  | 0  |         break;  | 
258  |  |  | 
259  | 0  |     case doExprRParen:  | 
260  | 0  |         fixOpStack(RBBINode::precLParen);  | 
261  | 0  |         break;  | 
262  |  |  | 
263  | 0  |     case doNOP:  | 
264  | 0  |         break;  | 
265  |  |  | 
266  | 0  |     case doStartAssign:  | 
267  |  |         // We've just scanned "$variable = "  | 
268  |  |         // The top of the node stack has the $variable ref node.  | 
269  |  |  | 
270  |  |         // Save the start position of the RHS text in the StartExpression node  | 
271  |  |         //   that precedes the $variableReference node on the stack.  | 
272  |  |         //   This will eventually be used when saving the full $variable replacement  | 
273  |  |         //   text as a string.  | 
274  | 0  |         n = fNodeStack[fNodeStackPtr-1];  | 
275  | 0  |         n->fFirstPos = fNextIndex;              // move past the '='  | 
276  |  |  | 
277  |  |         // Push a new start-of-expression node; needed to keep parse of the  | 
278  |  |         //   RHS expression happy.  | 
279  | 0  |         pushNewNode(RBBINode::opStart);  | 
280  | 0  |         break;  | 
281  |  |  | 
282  |  |  | 
283  |  |  | 
284  |  |  | 
285  | 0  |     case doEndAssign:  | 
286  | 0  |         { | 
287  |  |             // We have reached the end of an assignment statement.  | 
288  |  |             //   Current scan char is the ';' that terminates the assignment.  | 
289  |  |  | 
290  |  |             // Terminate expression, leaves expression parse tree rooted in TOS node.  | 
291  | 0  |             fixOpStack(RBBINode::precStart);  | 
292  |  | 
  | 
293  | 0  |             RBBINode *startExprNode  = fNodeStack[fNodeStackPtr-2];  | 
294  | 0  |             RBBINode *varRefNode     = fNodeStack[fNodeStackPtr-1];  | 
295  | 0  |             RBBINode *RHSExprNode    = fNodeStack[fNodeStackPtr];  | 
296  |  |  | 
297  |  |             // Save original text of right side of assignment, excluding the terminating ';'  | 
298  |  |             //  in the root of the node for the right-hand-side expression.  | 
299  | 0  |             RHSExprNode->fFirstPos = startExprNode->fFirstPos;  | 
300  | 0  |             RHSExprNode->fLastPos  = fScanIndex;  | 
301  | 0  |             fRB->fRules.extractBetween(RHSExprNode->fFirstPos, RHSExprNode->fLastPos, RHSExprNode->fText);  | 
302  |  |  | 
303  |  |             // Expression parse tree becomes l. child of the $variable reference node.  | 
304  | 0  |             varRefNode->fLeftChild = RHSExprNode;  | 
305  | 0  |             RHSExprNode->fParent   = varRefNode;  | 
306  |  |  | 
307  |  |             // Make a symbol table entry for the $variableRef node.  | 
308  | 0  |             fSymbolTable->addEntry(varRefNode->fText, varRefNode, *fRB->fStatus);  | 
309  | 0  |             if (U_FAILURE(*fRB->fStatus)) { | 
310  |  |                 // This is a round-about way to get the parse position set  | 
311  |  |                 //  so that duplicate symbols error messages include a line number.  | 
312  | 0  |                 UErrorCode t = *fRB->fStatus;  | 
313  | 0  |                 *fRB->fStatus = U_ZERO_ERROR;  | 
314  | 0  |                 error(t);  | 
315  | 0  |             }  | 
316  |  |  | 
317  |  |             // Clean up the stack.  | 
318  | 0  |             delete startExprNode;  | 
319  | 0  |             fNodeStackPtr-=3;  | 
320  | 0  |             break;  | 
321  | 0  |         }  | 
322  |  |  | 
323  | 0  |     case doEndOfRule:  | 
324  | 0  |         { | 
325  | 0  |         fixOpStack(RBBINode::precStart);      // Terminate expression, leaves expression  | 
326  | 0  |         if (U_FAILURE(*fRB->fStatus)) {       //   parse tree rooted in TOS node. | 
327  | 0  |             break;  | 
328  | 0  |         }  | 
329  |  | #ifdef RBBI_DEBUG  | 
330  |  |         if (fRB->fDebugEnv && uprv_strstr(fRB->fDebugEnv, "rtree")) {printNodeStack("end of rule");} | 
331  |  | #endif  | 
332  | 0  |         U_ASSERT(fNodeStackPtr == 1);  | 
333  | 0  |         RBBINode *thisRule = fNodeStack[fNodeStackPtr];  | 
334  |  |  | 
335  |  |         // If this rule includes a look-ahead '/', add a endMark node to the  | 
336  |  |         //   expression tree.  | 
337  | 0  |         if (fLookAheadRule) { | 
338  | 0  |             RBBINode  *endNode        = pushNewNode(RBBINode::endMark);  | 
339  | 0  |             RBBINode  *catNode        = pushNewNode(RBBINode::opCat);  | 
340  | 0  |             if (U_FAILURE(*fRB->fStatus)) { | 
341  | 0  |                 break;  | 
342  | 0  |             }  | 
343  | 0  |             fNodeStackPtr -= 2;  | 
344  | 0  |             catNode->fLeftChild       = thisRule;  | 
345  | 0  |             catNode->fRightChild      = endNode;  | 
346  | 0  |             fNodeStack[fNodeStackPtr] = catNode;  | 
347  | 0  |             endNode->fVal             = fRuleNum;  | 
348  | 0  |             endNode->fLookAheadEnd    = TRUE;  | 
349  | 0  |             thisRule                  = catNode;  | 
350  |  |  | 
351  |  |             // TODO: Disable chaining out of look-ahead (hard break) rules.  | 
352  |  |             //   The break on rule match is forced, so there is no point in building up  | 
353  |  |             //   the state table to chain into another rule for a longer match.  | 
354  | 0  |         }  | 
355  |  |  | 
356  |  |         // Mark this node as being the root of a rule.  | 
357  | 0  |         thisRule->fRuleRoot = TRUE;  | 
358  |  |  | 
359  |  |         // Flag if chaining into this rule is wanted.  | 
360  |  |         //      | 
361  | 0  |         if (fRB->fChainRules &&         // If rule chaining is enabled globally via !!chain  | 
362  | 0  |                 !fNoChainInRule) {      //     and no '^' chain-in inhibit was on this rule | 
363  | 0  |             thisRule->fChainIn = TRUE;  | 
364  | 0  |         }  | 
365  |  |  | 
366  |  |  | 
367  |  |         // All rule expressions are ORed together.  | 
368  |  |         // The ';' that terminates an expression really just functions as a '|' with  | 
369  |  |         //   a low operator prededence.  | 
370  |  |         //  | 
371  |  |         // Each of the four sets of rules are collected separately.  | 
372  |  |         //  (forward, reverse, safe_forward, safe_reverse)  | 
373  |  |         //  OR this rule into the appropriate group of them.  | 
374  |  |         //  | 
375  | 0  |         RBBINode **destRules = (fReverseRule? &fRB->fSafeRevTree : fRB->fDefaultTree);  | 
376  |  | 
  | 
377  | 0  |         if (*destRules != NULL) { | 
378  |  |             // This is not the first rule encountered.  | 
379  |  |             // OR previous stuff  (from *destRules)  | 
380  |  |             // with the current rule expression (on the Node Stack)  | 
381  |  |             //  with the resulting OR expression going to *destRules  | 
382  |  |             //  | 
383  | 0  |                        thisRule    = fNodeStack[fNodeStackPtr];  | 
384  | 0  |             RBBINode  *prevRules   = *destRules;  | 
385  | 0  |             RBBINode  *orNode      = pushNewNode(RBBINode::opOr);  | 
386  | 0  |             if (U_FAILURE(*fRB->fStatus)) { | 
387  | 0  |                 break;  | 
388  | 0  |             }  | 
389  | 0  |             orNode->fLeftChild     = prevRules;  | 
390  | 0  |             prevRules->fParent     = orNode;  | 
391  | 0  |             orNode->fRightChild    = thisRule;  | 
392  | 0  |             thisRule->fParent      = orNode;  | 
393  | 0  |             *destRules             = orNode;  | 
394  | 0  |         }  | 
395  | 0  |         else  | 
396  | 0  |         { | 
397  |  |             // This is the first rule encountered (for this direction).  | 
398  |  |             // Just move its parse tree from the stack to *destRules.  | 
399  | 0  |             *destRules = fNodeStack[fNodeStackPtr];  | 
400  | 0  |         }  | 
401  | 0  |         fReverseRule   = FALSE;   // in preparation for the next rule.  | 
402  | 0  |         fLookAheadRule = FALSE;  | 
403  | 0  |         fNoChainInRule = FALSE;  | 
404  | 0  |         fNodeStackPtr  = 0;  | 
405  | 0  |         }  | 
406  | 0  |         break;  | 
407  |  |  | 
408  |  |  | 
409  | 0  |     case doRuleError:  | 
410  | 0  |         error(U_BRK_RULE_SYNTAX);  | 
411  | 0  |         returnVal = FALSE;  | 
412  | 0  |         break;  | 
413  |  |  | 
414  |  |  | 
415  | 0  |     case doVariableNameExpectedErr:  | 
416  | 0  |         error(U_BRK_RULE_SYNTAX);  | 
417  | 0  |         break;  | 
418  |  |  | 
419  |  |  | 
420  |  |     //  | 
421  |  |     //  Unary operands  + ? *  | 
422  |  |     //    These all appear after the operand to which they apply.  | 
423  |  |     //    When we hit one, the operand (may be a whole sub expression)  | 
424  |  |     //    will be on the top of the stack.  | 
425  |  |     //    Unary Operator becomes TOS, with the old TOS as its one child.  | 
426  | 0  |     case doUnaryOpPlus:  | 
427  | 0  |         { | 
428  | 0  |             RBBINode  *operandNode = fNodeStack[fNodeStackPtr--];  | 
429  | 0  |             RBBINode  *plusNode    = pushNewNode(RBBINode::opPlus);  | 
430  | 0  |             if (U_FAILURE(*fRB->fStatus)) { | 
431  | 0  |                 break;  | 
432  | 0  |             }  | 
433  | 0  |             plusNode->fLeftChild   = operandNode;  | 
434  | 0  |             operandNode->fParent   = plusNode;  | 
435  | 0  |         }  | 
436  | 0  |         break;  | 
437  |  |  | 
438  | 0  |     case doUnaryOpQuestion:  | 
439  | 0  |         { | 
440  | 0  |             RBBINode  *operandNode = fNodeStack[fNodeStackPtr--];  | 
441  | 0  |             RBBINode  *qNode       = pushNewNode(RBBINode::opQuestion);  | 
442  | 0  |             if (U_FAILURE(*fRB->fStatus)) { | 
443  | 0  |                 break;  | 
444  | 0  |             }  | 
445  | 0  |             qNode->fLeftChild      = operandNode;  | 
446  | 0  |             operandNode->fParent   = qNode;  | 
447  | 0  |         }  | 
448  | 0  |         break;  | 
449  |  |  | 
450  | 0  |     case doUnaryOpStar:  | 
451  | 0  |         { | 
452  | 0  |             RBBINode  *operandNode = fNodeStack[fNodeStackPtr--];  | 
453  | 0  |             RBBINode  *starNode    = pushNewNode(RBBINode::opStar);  | 
454  | 0  |             if (U_FAILURE(*fRB->fStatus)) { | 
455  | 0  |                 break;  | 
456  | 0  |             }  | 
457  | 0  |             starNode->fLeftChild   = operandNode;  | 
458  | 0  |             operandNode->fParent   = starNode;  | 
459  | 0  |         }  | 
460  | 0  |         break;  | 
461  |  |  | 
462  | 0  |     case doRuleChar:  | 
463  |  |         // A "Rule Character" is any single character that is a literal part  | 
464  |  |         // of the regular expression.  Like a, b and c in the expression "(abc*) | [:L:]"  | 
465  |  |         // These are pretty uncommon in break rules; the terms are more commonly  | 
466  |  |         //  sets.  To keep things uniform, treat these characters like as  | 
467  |  |         // sets that just happen to contain only one character.  | 
468  | 0  |         { | 
469  | 0  |             n = pushNewNode(RBBINode::setRef);  | 
470  | 0  |             if (U_FAILURE(*fRB->fStatus)) { | 
471  | 0  |                 break;  | 
472  | 0  |             }  | 
473  | 0  |             findSetFor(UnicodeString(fC.fChar), n);  | 
474  | 0  |             n->fFirstPos = fScanIndex;  | 
475  | 0  |             n->fLastPos  = fNextIndex;  | 
476  | 0  |             fRB->fRules.extractBetween(n->fFirstPos, n->fLastPos, n->fText);  | 
477  | 0  |             break;  | 
478  | 0  |         }  | 
479  |  |  | 
480  | 0  |     case doDotAny:  | 
481  |  |         // scanned a ".", meaning match any single character.  | 
482  | 0  |         { | 
483  | 0  |             n = pushNewNode(RBBINode::setRef);  | 
484  | 0  |             if (U_FAILURE(*fRB->fStatus)) { | 
485  | 0  |                 break;  | 
486  | 0  |             }  | 
487  | 0  |             findSetFor(UnicodeString(TRUE, kAny, 3), n);  | 
488  | 0  |             n->fFirstPos = fScanIndex;  | 
489  | 0  |             n->fLastPos  = fNextIndex;  | 
490  | 0  |             fRB->fRules.extractBetween(n->fFirstPos, n->fLastPos, n->fText);  | 
491  | 0  |             break;  | 
492  | 0  |         }  | 
493  |  |  | 
494  | 0  |     case doSlash:  | 
495  |  |         // Scanned a '/', which identifies a look-ahead break position in a rule.  | 
496  | 0  |         n = pushNewNode(RBBINode::lookAhead);  | 
497  | 0  |         if (U_FAILURE(*fRB->fStatus)) { | 
498  | 0  |             break;  | 
499  | 0  |         }  | 
500  | 0  |         n->fVal      = fRuleNum;  | 
501  | 0  |         n->fFirstPos = fScanIndex;  | 
502  | 0  |         n->fLastPos  = fNextIndex;  | 
503  | 0  |         fRB->fRules.extractBetween(n->fFirstPos, n->fLastPos, n->fText);  | 
504  | 0  |         fLookAheadRule = TRUE;  | 
505  | 0  |         break;  | 
506  |  |  | 
507  |  |  | 
508  | 0  |     case doStartTagValue:  | 
509  |  |         // Scanned a '{', the opening delimiter for a tag value within a rule. | 
510  | 0  |         n = pushNewNode(RBBINode::tag);  | 
511  | 0  |         if (U_FAILURE(*fRB->fStatus)) { | 
512  | 0  |             break;  | 
513  | 0  |         }  | 
514  | 0  |         n->fVal      = 0;  | 
515  | 0  |         n->fFirstPos = fScanIndex;  | 
516  | 0  |         n->fLastPos  = fNextIndex;  | 
517  | 0  |         break;  | 
518  |  |  | 
519  | 0  |     case doTagDigit:  | 
520  |  |         // Just scanned a decimal digit that's part of a tag value  | 
521  | 0  |         { | 
522  | 0  |             n = fNodeStack[fNodeStackPtr];  | 
523  | 0  |             uint32_t v = u_charDigitValue(fC.fChar);  | 
524  | 0  |             U_ASSERT(v < 10);  | 
525  | 0  |             n->fVal = n->fVal*10 + v;  | 
526  | 0  |             break;  | 
527  | 0  |         }  | 
528  |  |  | 
529  | 0  |     case doTagValue:  | 
530  | 0  |         n = fNodeStack[fNodeStackPtr];  | 
531  | 0  |         n->fLastPos = fNextIndex;  | 
532  | 0  |         fRB->fRules.extractBetween(n->fFirstPos, n->fLastPos, n->fText);  | 
533  | 0  |         break;  | 
534  |  |  | 
535  | 0  |     case doTagExpectedError:  | 
536  | 0  |         error(U_BRK_MALFORMED_RULE_TAG);  | 
537  | 0  |         returnVal = FALSE;  | 
538  | 0  |         break;  | 
539  |  |  | 
540  | 0  |     case doOptionStart:  | 
541  |  |         // Scanning a !!option.   At the start of string.  | 
542  | 0  |         fOptionStart = fScanIndex;  | 
543  | 0  |         break;  | 
544  |  |  | 
545  | 0  |     case doOptionEnd:  | 
546  | 0  |         { | 
547  | 0  |             UnicodeString opt(fRB->fRules, fOptionStart, fScanIndex-fOptionStart);  | 
548  | 0  |             if (opt == UNICODE_STRING("chain", 5)) { | 
549  | 0  |                 fRB->fChainRules = TRUE;  | 
550  | 0  |             } else if (opt == UNICODE_STRING("LBCMNoChain", 11)) { | 
551  | 0  |                 fRB->fLBCMNoChain = TRUE;  | 
552  | 0  |             } else if (opt == UNICODE_STRING("forward", 7)) { | 
553  | 0  |                 fRB->fDefaultTree   = &fRB->fForwardTree;  | 
554  | 0  |             } else if (opt == UNICODE_STRING("reverse", 7)) { | 
555  | 0  |                 fRB->fDefaultTree   = &fRB->fReverseTree;  | 
556  | 0  |             } else if (opt == UNICODE_STRING("safe_forward", 12)) { | 
557  | 0  |                 fRB->fDefaultTree   = &fRB->fSafeFwdTree;  | 
558  | 0  |             } else if (opt == UNICODE_STRING("safe_reverse", 12)) { | 
559  | 0  |                 fRB->fDefaultTree   = &fRB->fSafeRevTree;  | 
560  | 0  |             } else if (opt == UNICODE_STRING("lookAheadHardBreak", 18)) { | 
561  | 0  |                 fRB->fLookAheadHardBreak = TRUE;  | 
562  | 0  |             } else if (opt == UNICODE_STRING("quoted_literals_only", 20)) { | 
563  | 0  |                 fRuleSets[kRuleSet_rule_char-128].clear();  | 
564  | 0  |             } else if (opt == UNICODE_STRING("unquoted_literals",  17)) { | 
565  | 0  |                 fRuleSets[kRuleSet_rule_char-128].applyPattern(UnicodeString(gRuleSet_rule_char_pattern), *fRB->fStatus);  | 
566  | 0  |             } else { | 
567  | 0  |                 error(U_BRK_UNRECOGNIZED_OPTION);  | 
568  | 0  |             }  | 
569  | 0  |         }  | 
570  | 0  |         break;  | 
571  |  |  | 
572  | 0  |     case doReverseDir:  | 
573  | 0  |         fReverseRule = TRUE;  | 
574  | 0  |         break;  | 
575  |  |  | 
576  | 0  |     case doStartVariableName:  | 
577  | 0  |         n = pushNewNode(RBBINode::varRef);  | 
578  | 0  |         if (U_FAILURE(*fRB->fStatus)) { | 
579  | 0  |             break;  | 
580  | 0  |         }  | 
581  | 0  |         n->fFirstPos = fScanIndex;  | 
582  | 0  |         break;  | 
583  |  |  | 
584  | 0  |     case doEndVariableName:  | 
585  | 0  |         n = fNodeStack[fNodeStackPtr];  | 
586  | 0  |         if (n==NULL || n->fType != RBBINode::varRef) { | 
587  | 0  |             error(U_BRK_INTERNAL_ERROR);  | 
588  | 0  |             break;  | 
589  | 0  |         }  | 
590  | 0  |         n->fLastPos = fScanIndex;  | 
591  | 0  |         fRB->fRules.extractBetween(n->fFirstPos+1, n->fLastPos, n->fText);  | 
592  |  |         // Look the newly scanned name up in the symbol table  | 
593  |  |         //   If there's an entry, set the l. child of the var ref to the replacement expression.  | 
594  |  |         //   (We also pass through here when scanning assignments, but no harm is done, other  | 
595  |  |         //    than a slight wasted effort that seems hard to avoid.  Lookup will be null)  | 
596  | 0  |         n->fLeftChild = fSymbolTable->lookupNode(n->fText);  | 
597  | 0  |         break;  | 
598  |  |  | 
599  | 0  |     case doCheckVarDef:  | 
600  | 0  |         n = fNodeStack[fNodeStackPtr];  | 
601  | 0  |         if (n->fLeftChild == NULL) { | 
602  | 0  |             error(U_BRK_UNDEFINED_VARIABLE);  | 
603  | 0  |             returnVal = FALSE;  | 
604  | 0  |         }  | 
605  | 0  |         break;  | 
606  |  |  | 
607  | 0  |     case doExprFinished:  | 
608  | 0  |         break;  | 
609  |  |  | 
610  | 0  |     case doRuleErrorAssignExpr:  | 
611  | 0  |         error(U_BRK_ASSIGN_ERROR);  | 
612  | 0  |         returnVal = FALSE;  | 
613  | 0  |         break;  | 
614  |  |  | 
615  | 0  |     case doExit:  | 
616  | 0  |         returnVal = FALSE;  | 
617  | 0  |         break;  | 
618  |  |  | 
619  | 0  |     case doScanUnicodeSet:  | 
620  | 0  |         scanSet();  | 
621  | 0  |         break;  | 
622  |  |  | 
623  | 0  |     default:  | 
624  | 0  |         error(U_BRK_INTERNAL_ERROR);  | 
625  | 0  |         returnVal = FALSE;  | 
626  | 0  |         break;  | 
627  | 0  |     }  | 
628  | 0  |     return returnVal && U_SUCCESS(*fRB->fStatus);  | 
629  | 0  | }  | 
630  |  |  | 
631  |  |  | 
632  |  |  | 
633  |  |  | 
634  |  | //------------------------------------------------------------------------------  | 
635  |  | //  | 
636  |  | //  Error         Report a rule parse error.  | 
637  |  | //                Only report it if no previous error has been recorded.  | 
638  |  | //  | 
639  |  | //------------------------------------------------------------------------------  | 
640  | 0  | void RBBIRuleScanner::error(UErrorCode e) { | 
641  | 0  |     if (U_SUCCESS(*fRB->fStatus)) { | 
642  | 0  |         *fRB->fStatus = e;  | 
643  | 0  |         if (fRB->fParseError) { | 
644  | 0  |             fRB->fParseError->line  = fLineNum;  | 
645  | 0  |             fRB->fParseError->offset = fCharNum;  | 
646  | 0  |             fRB->fParseError->preContext[0] = 0;  | 
647  | 0  |             fRB->fParseError->postContext[0] = 0;  | 
648  | 0  |         }  | 
649  | 0  |     }  | 
650  | 0  | }  | 
651  |  |  | 
652  |  |  | 
653  |  |  | 
654  |  |  | 
655  |  | //------------------------------------------------------------------------------  | 
656  |  | //  | 
657  |  | //  fixOpStack   The parse stack holds partially assembled chunks of the parse tree.  | 
658  |  | //               An entry on the stack may be as small as a single setRef node,  | 
659  |  | //               or as large as the parse tree  | 
660  |  | //               for an entire expression (this will be the one item left on the stack  | 
661  |  | //               when the parsing of an RBBI rule completes.  | 
662  |  | //  | 
663  |  | //               This function is called when a binary operator is encountered.  | 
664  |  | //               It looks back up the stack for operators that are not yet associated  | 
665  |  | //               with a right operand, and if the precedence of the stacked operator >=  | 
666  |  | //               the precedence of the current operator, binds the operand left,  | 
667  |  | //               to the previously encountered operator.  | 
668  |  | //  | 
669  |  | //------------------------------------------------------------------------------  | 
670  | 0  | void RBBIRuleScanner::fixOpStack(RBBINode::OpPrecedence p) { | 
671  | 0  |     RBBINode *n;  | 
672  |  |     // printNodeStack("entering fixOpStack()"); | 
673  | 0  |     for (;;) { | 
674  | 0  |         n = fNodeStack[fNodeStackPtr-1];   // an operator node  | 
675  | 0  |         if (n->fPrecedence == 0) { | 
676  | 0  |             RBBIDebugPuts("RBBIRuleScanner::fixOpStack, bad operator node"); | 
677  | 0  |             error(U_BRK_INTERNAL_ERROR);  | 
678  | 0  |             return;  | 
679  | 0  |         }  | 
680  |  |  | 
681  | 0  |         if (n->fPrecedence < p || n->fPrecedence <= RBBINode::precLParen) { | 
682  |  |             // The most recent operand goes with the current operator,  | 
683  |  |             //   not with the previously stacked one.  | 
684  | 0  |             break;  | 
685  | 0  |         }  | 
686  |  |             // Stack operator is a binary op  ( '|' or concatenation)  | 
687  |  |             //   TOS operand becomes right child of this operator.  | 
688  |  |             //   Resulting subexpression becomes the TOS operand.  | 
689  | 0  |             n->fRightChild = fNodeStack[fNodeStackPtr];  | 
690  | 0  |             fNodeStack[fNodeStackPtr]->fParent = n;  | 
691  | 0  |             fNodeStackPtr--;  | 
692  |  |         // printNodeStack("looping in fixOpStack()   "); | 
693  | 0  |     }  | 
694  |  |  | 
695  | 0  |     if (p <= RBBINode::precLParen) { | 
696  |  |         // Scan is at a right paren or end of expression.  | 
697  |  |         //  The scanned item must match the stack, or else there was an error.  | 
698  |  |         //  Discard the left paren (or start expr) node from the stack,  | 
699  |  |             //  leaving the completed (sub)expression as TOS.  | 
700  | 0  |             if (n->fPrecedence != p) { | 
701  |  |                 // Right paren encountered matched start of expression node, or  | 
702  |  |                 // end of expression matched with a left paren node.  | 
703  | 0  |                 error(U_BRK_MISMATCHED_PAREN);  | 
704  | 0  |             }  | 
705  | 0  |             fNodeStack[fNodeStackPtr-1] = fNodeStack[fNodeStackPtr];  | 
706  | 0  |             fNodeStackPtr--;  | 
707  |  |             // Delete the now-discarded LParen or Start node.  | 
708  | 0  |             delete n;  | 
709  | 0  |     }  | 
710  |  |     // printNodeStack("leaving fixOpStack()"); | 
711  | 0  | }  | 
712  |  |  | 
713  |  |  | 
714  |  |  | 
715  |  |  | 
716  |  | //------------------------------------------------------------------------------  | 
717  |  | //  | 
718  |  | //   findSetFor    given a UnicodeString,  | 
719  |  | //                  - find the corresponding Unicode Set  (uset node)  | 
720  |  | //                         (create one if necessary)  | 
721  |  | //                  - Set fLeftChild of the caller's node (should be a setRef node)  | 
722  |  | //                         to the uset node  | 
723  |  | //                 Maintain a hash table of uset nodes, so the same one is always used  | 
724  |  | //                    for the same string.  | 
725  |  | //                 If a "to adopt" set is provided and we haven't seen this key before,  | 
726  |  | //                    add the provided set to the hash table.  | 
727  |  | //                 If the string is one (32 bit) char in length, the set contains  | 
728  |  | //                    just one element which is the char in question.  | 
729  |  | //                 If the string is "any", return a set containing all chars.  | 
730  |  | //  | 
731  |  | //------------------------------------------------------------------------------  | 
732  | 0  | void RBBIRuleScanner::findSetFor(const UnicodeString &s, RBBINode *node, UnicodeSet *setToAdopt) { | 
733  |  | 
  | 
734  | 0  |     RBBISetTableEl   *el;  | 
735  |  |  | 
736  |  |     // First check whether we've already cached a set for this string.  | 
737  |  |     // If so, just use the cached set in the new node.  | 
738  |  |     //   delete any set provided by the caller, since we own it.  | 
739  | 0  |     el = (RBBISetTableEl *)uhash_get(fSetTable, &s);  | 
740  | 0  |     if (el != NULL) { | 
741  | 0  |         delete setToAdopt;  | 
742  | 0  |         node->fLeftChild = el->val;  | 
743  | 0  |         U_ASSERT(node->fLeftChild->fType == RBBINode::uset);  | 
744  | 0  |         return;  | 
745  | 0  |     }  | 
746  |  |  | 
747  |  |     // Haven't seen this set before.  | 
748  |  |     // If the caller didn't provide us with a prebuilt set,  | 
749  |  |     //   create a new UnicodeSet now.  | 
750  | 0  |     if (setToAdopt == NULL) { | 
751  | 0  |         if (s.compare(kAny, -1) == 0) { | 
752  | 0  |             setToAdopt = new UnicodeSet(0x000000, 0x10ffff);  | 
753  | 0  |         } else { | 
754  | 0  |             UChar32 c;  | 
755  | 0  |             c = s.char32At(0);  | 
756  | 0  |             setToAdopt = new UnicodeSet(c, c);  | 
757  | 0  |         }  | 
758  | 0  |     }  | 
759  |  |  | 
760  |  |     //  | 
761  |  |     // Make a new uset node to refer to this UnicodeSet  | 
762  |  |     // This new uset node becomes the child of the caller's setReference node.  | 
763  |  |     //  | 
764  | 0  |     RBBINode *usetNode    = new RBBINode(RBBINode::uset);  | 
765  | 0  |     if (usetNode == NULL) { | 
766  | 0  |         error(U_MEMORY_ALLOCATION_ERROR);  | 
767  | 0  |         return;  | 
768  | 0  |     }  | 
769  | 0  |     usetNode->fInputSet   = setToAdopt;  | 
770  | 0  |     usetNode->fParent     = node;  | 
771  | 0  |     node->fLeftChild      = usetNode;  | 
772  | 0  |     usetNode->fText = s;  | 
773  |  |  | 
774  |  |  | 
775  |  |     //  | 
776  |  |     // Add the new uset node to the list of all uset nodes.  | 
777  |  |     //  | 
778  | 0  |     fRB->fUSetNodes->addElementX(usetNode, *fRB->fStatus);  | 
779  |  |  | 
780  |  |  | 
781  |  |     //  | 
782  |  |     // Add the new set to the set hash table.  | 
783  |  |     //  | 
784  | 0  |     el      = (RBBISetTableEl *)uprv_malloc(sizeof(RBBISetTableEl));  | 
785  | 0  |     UnicodeString *tkey = new UnicodeString(s);  | 
786  | 0  |     if (tkey == NULL || el == NULL || setToAdopt == NULL) { | 
787  |  |         // Delete to avoid memory leak  | 
788  | 0  |         delete tkey;  | 
789  | 0  |         tkey = NULL;  | 
790  | 0  |         uprv_free(el);  | 
791  | 0  |         el = NULL;  | 
792  | 0  |         delete setToAdopt;  | 
793  | 0  |         setToAdopt = NULL;  | 
794  |  | 
  | 
795  | 0  |         error(U_MEMORY_ALLOCATION_ERROR);  | 
796  | 0  |         return;  | 
797  | 0  |     }  | 
798  | 0  |     el->key = tkey;  | 
799  | 0  |     el->val = usetNode;  | 
800  | 0  |     uhash_put(fSetTable, el->key, el, fRB->fStatus);  | 
801  |  | 
  | 
802  | 0  |     return;  | 
803  | 0  | }  | 
804  |  |  | 
805  |  |  | 
806  |  |  | 
807  |  | //  | 
808  |  | //  Assorted Unicode character constants.  | 
809  |  | //     Numeric because there is no portable way to enter them as literals.  | 
810  |  | //     (Think EBCDIC).  | 
811  |  | //  | 
812  |  | static const UChar      chCR        = 0x0d;      // New lines, for terminating comments.  | 
813  |  | static const UChar      chLF        = 0x0a;  | 
814  |  | static const UChar      chNEL       = 0x85;      //    NEL newline variant  | 
815  |  | static const UChar      chLS        = 0x2028;    //    Unicode Line Separator  | 
816  |  | static const UChar      chApos      = 0x27;      //  single quote, for quoted chars.  | 
817  |  | static const UChar      chPound     = 0x23;      // '#', introduces a comment.  | 
818  |  | static const UChar      chBackSlash = 0x5c;      // '\'  introduces a char escape  | 
819  |  | static const UChar      chLParen    = 0x28;  | 
820  |  | static const UChar      chRParen    = 0x29;  | 
821  |  |  | 
822  |  |  | 
823  |  | //------------------------------------------------------------------------------  | 
824  |  | //  | 
825  |  | //  stripRules    Return a rules string without extra spaces.  | 
826  |  | //                (Comments are removed separately, during rule parsing.)  | 
827  |  | //  | 
828  |  | //------------------------------------------------------------------------------  | 
829  | 0  | UnicodeString RBBIRuleScanner::stripRules(const UnicodeString &rules) { | 
830  | 0  |     UnicodeString strippedRules;  | 
831  | 0  |     int32_t rulesLength = rules.length();  | 
832  |  | 
  | 
833  | 0  |     for (int32_t idx=0; idx<rulesLength; idx = rules.moveIndex32(idx, 1)) { | 
834  | 0  |         UChar32 cp = rules.char32At(idx);  | 
835  | 0  |         bool whiteSpace = u_hasBinaryProperty(cp, UCHAR_PATTERN_WHITE_SPACE);  | 
836  | 0  |         if (whiteSpace) { | 
837  | 0  |             continue;  | 
838  | 0  |         }  | 
839  | 0  |         strippedRules.append(cp);  | 
840  | 0  |     }  | 
841  | 0  |     return strippedRules;  | 
842  | 0  | }  | 
843  |  |  | 
844  |  |  | 
845  |  | //------------------------------------------------------------------------------  | 
846  |  | //  | 
847  |  | //  nextCharLL    Low Level Next Char from rule input source.  | 
848  |  | //                Get a char from the input character iterator,  | 
849  |  | //                keep track of input position for error reporting.  | 
850  |  | //  | 
851  |  | //------------------------------------------------------------------------------  | 
852  | 0  | UChar32  RBBIRuleScanner::nextCharLL() { | 
853  | 0  |     UChar32  ch;  | 
854  |  | 
  | 
855  | 0  |     if (fNextIndex >= fRB->fRules.length()) { | 
856  | 0  |         return (UChar32)-1;  | 
857  | 0  |     }  | 
858  | 0  |     ch         = fRB->fRules.char32At(fNextIndex);  | 
859  | 0  |     if (U_IS_SURROGATE(ch)) { | 
860  | 0  |         error(U_ILLEGAL_CHAR_FOUND);  | 
861  | 0  |         return U_SENTINEL;  | 
862  | 0  |     }  | 
863  | 0  |     fNextIndex = fRB->fRules.moveIndex32(fNextIndex, 1);  | 
864  |  | 
  | 
865  | 0  |     if (ch == chCR ||  | 
866  | 0  |         ch == chNEL ||  | 
867  | 0  |         ch == chLS   ||  | 
868  | 0  |         (ch == chLF && fLastChar != chCR)) { | 
869  |  |         // Character is starting a new line.  Bump up the line number, and  | 
870  |  |         //  reset the column to 0.  | 
871  | 0  |         fLineNum++;  | 
872  | 0  |         fCharNum=0;  | 
873  | 0  |         if (fQuoteMode) { | 
874  | 0  |             error(U_BRK_NEW_LINE_IN_QUOTED_STRING);  | 
875  | 0  |             fQuoteMode = FALSE;  | 
876  | 0  |         }  | 
877  | 0  |     }  | 
878  | 0  |     else { | 
879  |  |         // Character is not starting a new line.  Except in the case of a  | 
880  |  |         //   LF following a CR, increment the column position.  | 
881  | 0  |         if (ch != chLF) { | 
882  | 0  |             fCharNum++;  | 
883  | 0  |         }  | 
884  | 0  |     }  | 
885  | 0  |     fLastChar = ch;  | 
886  | 0  |     return ch;  | 
887  | 0  | }  | 
888  |  |  | 
889  |  |  | 
890  |  | //------------------------------------------------------------------------------  | 
891  |  | //  | 
892  |  | //   nextChar     for rules scanning.  At this level, we handle stripping  | 
893  |  | //                out comments and processing backslash character escapes.  | 
894  |  | //                The rest of the rules grammar is handled at the next level up.  | 
895  |  | //  | 
896  |  | //------------------------------------------------------------------------------  | 
897  | 0  | void RBBIRuleScanner::nextChar(RBBIRuleChar &c) { | 
898  |  |  | 
899  |  |     // Unicode Character constants needed for the processing done by nextChar(),  | 
900  |  |     //   in hex because literals wont work on EBCDIC machines.  | 
901  |  | 
  | 
902  | 0  |     fScanIndex = fNextIndex;  | 
903  | 0  |     c.fChar    = nextCharLL();  | 
904  | 0  |     c.fEscaped = FALSE;  | 
905  |  |  | 
906  |  |     //  | 
907  |  |     //  check for '' sequence.  | 
908  |  |     //  These are recognized in all contexts, whether in quoted text or not.  | 
909  |  |     //  | 
910  | 0  |     if (c.fChar == chApos) { | 
911  | 0  |         if (fRB->fRules.char32At(fNextIndex) == chApos) { | 
912  | 0  |             c.fChar    = nextCharLL();        // get nextChar officially so character counts  | 
913  | 0  |             c.fEscaped = TRUE;                //   stay correct.  | 
914  | 0  |         }  | 
915  | 0  |         else  | 
916  | 0  |         { | 
917  |  |             // Single quote, by itself.  | 
918  |  |             //   Toggle quoting mode.  | 
919  |  |             //   Return either '('  or ')', because quotes cause a grouping of the quoted text. | 
920  | 0  |             fQuoteMode = !fQuoteMode;  | 
921  | 0  |             if (fQuoteMode == TRUE) { | 
922  | 0  |                 c.fChar = chLParen;  | 
923  | 0  |             } else { | 
924  | 0  |                 c.fChar = chRParen;  | 
925  | 0  |             }  | 
926  | 0  |             c.fEscaped = FALSE;      // The paren that we return is not escaped.  | 
927  | 0  |             return;  | 
928  | 0  |         }  | 
929  | 0  |     }  | 
930  |  |  | 
931  | 0  |     if (fQuoteMode) { | 
932  | 0  |         c.fEscaped = TRUE;  | 
933  | 0  |     }  | 
934  | 0  |     else  | 
935  | 0  |     { | 
936  |  |         // We are not in a 'quoted region' of the source.  | 
937  |  |         //  | 
938  | 0  |         if (c.fChar == chPound) { | 
939  |  |             // Start of a comment.  Consume the rest of it.  | 
940  |  |             //  The new-line char that terminates the comment is always returned.  | 
941  |  |             //  It will be treated as white-space, and serves to break up anything  | 
942  |  |             //    that might otherwise incorrectly clump together with a comment in  | 
943  |  |             //    the middle (a variable name, for example.)  | 
944  | 0  |             int32_t commentStart = fScanIndex;  | 
945  | 0  |             for (;;) { | 
946  | 0  |                 c.fChar = nextCharLL();  | 
947  | 0  |                 if (c.fChar == (UChar32)-1 ||  // EOF  | 
948  | 0  |                     c.fChar == chCR     ||  | 
949  | 0  |                     c.fChar == chLF     ||  | 
950  | 0  |                     c.fChar == chNEL    ||  | 
951  | 0  |                     c.fChar == chLS)       {break;} | 
952  | 0  |             }  | 
953  | 0  |             for (int32_t i=commentStart; i<fNextIndex-1; ++i) { | 
954  | 0  |                 fRB->fStrippedRules.setCharAt(i, u' ');  | 
955  | 0  |             }  | 
956  | 0  |         }  | 
957  | 0  |         if (c.fChar == (UChar32)-1) { | 
958  | 0  |             return;  | 
959  | 0  |         }  | 
960  |  |  | 
961  |  |         //  | 
962  |  |         //  check for backslash escaped characters.  | 
963  |  |         //  Use UnicodeString::unescapeAt() to handle them.  | 
964  |  |         //  | 
965  | 0  |         if (c.fChar == chBackSlash) { | 
966  | 0  |             c.fEscaped = TRUE;  | 
967  | 0  |             int32_t startX = fNextIndex;  | 
968  | 0  |             c.fChar = fRB->fRules.unescapeAt(fNextIndex);  | 
969  | 0  |             if (fNextIndex == startX) { | 
970  | 0  |                 error(U_BRK_HEX_DIGITS_EXPECTED);  | 
971  | 0  |             }  | 
972  | 0  |             fCharNum += fNextIndex-startX;  | 
973  | 0  |         }  | 
974  | 0  |     }  | 
975  |  |     // putc(c.fChar, stdout);  | 
976  | 0  | }  | 
977  |  |  | 
978  |  | //------------------------------------------------------------------------------  | 
979  |  | //  | 
980  |  | //  Parse RBBI rules.   The state machine for rules parsing is here.  | 
981  |  | //                      The state tables are hand-written in the file rbbirpt.txt,  | 
982  |  | //                      and converted to the form used here by a perl  | 
983  |  | //                      script rbbicst.pl  | 
984  |  | //  | 
985  |  | //------------------------------------------------------------------------------  | 
986  | 0  | void RBBIRuleScanner::parse() { | 
987  | 0  |     uint16_t                state;  | 
988  | 0  |     const RBBIRuleTableEl  *tableEl;  | 
989  |  | 
  | 
990  | 0  |     if (U_FAILURE(*fRB->fStatus)) { | 
991  | 0  |         return;  | 
992  | 0  |     }  | 
993  |  |  | 
994  | 0  |     state = 1;  | 
995  | 0  |     nextChar(fC);  | 
996  |  |     //  | 
997  |  |     // Main loop for the rule parsing state machine.  | 
998  |  |     //   Runs once per state transition.  | 
999  |  |     //   Each time through optionally performs, depending on the state table,  | 
1000  |  |     //      - an advance to the the next input char  | 
1001  |  |     //      - an action to be performed.  | 
1002  |  |     //      - pushing or popping a state to/from the local state return stack.  | 
1003  |  |     //  | 
1004  | 0  |     for (;;) { | 
1005  |  |         //  Bail out if anything has gone wrong.  | 
1006  |  |         //  RBBI rule file parsing stops on the first error encountered.  | 
1007  | 0  |         if (U_FAILURE(*fRB->fStatus)) { | 
1008  | 0  |             break;  | 
1009  | 0  |         }  | 
1010  |  |  | 
1011  |  |         // Quit if state == 0.  This is the normal way to exit the state machine.  | 
1012  |  |         //  | 
1013  | 0  |         if (state == 0) { | 
1014  | 0  |             break;  | 
1015  | 0  |         }  | 
1016  |  |  | 
1017  |  |         // Find the state table element that matches the input char from the rule, or the  | 
1018  |  |         //    class of the input character.  Start with the first table row for this  | 
1019  |  |         //    state, then linearly scan forward until we find a row that matches the  | 
1020  |  |         //    character.  The last row for each state always matches all characters, so  | 
1021  |  |         //    the search will stop there, if not before.  | 
1022  |  |         //  | 
1023  | 0  |         tableEl = &gRuleParseStateTable[state];  | 
1024  |  |         #ifdef RBBI_DEBUG  | 
1025  |  |             if (fRB->fDebugEnv && uprv_strstr(fRB->fDebugEnv, "scan")) { | 
1026  |  |                 RBBIDebugPrintf("char, line, col = (\'%c\', %d, %d)    state=%s ", | 
1027  |  |                     fC.fChar, fLineNum, fCharNum, RBBIRuleStateNames[state]);  | 
1028  |  |             }  | 
1029  |  |         #endif  | 
1030  |  | 
  | 
1031  | 0  |         for (;;) { | 
1032  |  |             #ifdef RBBI_DEBUG  | 
1033  |  |                 if (fRB->fDebugEnv && uprv_strstr(fRB->fDebugEnv, "scan")) { RBBIDebugPrintf("."); fflush(stdout);} | 
1034  |  |             #endif  | 
1035  | 0  |             if (tableEl->fCharClass < 127 && fC.fEscaped == FALSE &&   tableEl->fCharClass == fC.fChar) { | 
1036  |  |                 // Table row specified an individual character, not a set, and  | 
1037  |  |                 //   the input character is not escaped, and  | 
1038  |  |                 //   the input character matched it.  | 
1039  | 0  |                 break;  | 
1040  | 0  |             }  | 
1041  | 0  |             if (tableEl->fCharClass == 255) { | 
1042  |  |                 // Table row specified default, match anything character class.  | 
1043  | 0  |                 break;  | 
1044  | 0  |             }  | 
1045  | 0  |             if (tableEl->fCharClass == 254 && fC.fEscaped)  { | 
1046  |  |                 // Table row specified "escaped" and the char was escaped.  | 
1047  | 0  |                 break;  | 
1048  | 0  |             }  | 
1049  | 0  |             if (tableEl->fCharClass == 253 && fC.fEscaped &&  | 
1050  | 0  |                 (fC.fChar == 0x50 || fC.fChar == 0x70 ))  { | 
1051  |  |                 // Table row specified "escaped P" and the char is either 'p' or 'P'.  | 
1052  | 0  |                 break;  | 
1053  | 0  |             }  | 
1054  | 0  |             if (tableEl->fCharClass == 252 && fC.fChar == (UChar32)-1)  { | 
1055  |  |                 // Table row specified eof and we hit eof on the input.  | 
1056  | 0  |                 break;  | 
1057  | 0  |             }  | 
1058  |  |  | 
1059  | 0  |             if (tableEl->fCharClass >= 128 && tableEl->fCharClass < 240 &&   // Table specs a char class &&  | 
1060  | 0  |                 fC.fEscaped == FALSE &&                                      //   char is not escaped &&  | 
1061  | 0  |                 fC.fChar != (UChar32)-1) {                                   //   char is not EOF | 
1062  | 0  |                 U_ASSERT((tableEl->fCharClass-128) < UPRV_LENGTHOF(fRuleSets));  | 
1063  | 0  |                 if (fRuleSets[tableEl->fCharClass-128].contains(fC.fChar)) { | 
1064  |  |                     // Table row specified a character class, or set of characters,  | 
1065  |  |                     //   and the current char matches it.  | 
1066  | 0  |                     break;  | 
1067  | 0  |                 }  | 
1068  | 0  |             }  | 
1069  |  |  | 
1070  |  |             // No match on this row, advance to the next  row for this state,  | 
1071  | 0  |             tableEl++;  | 
1072  | 0  |         }  | 
1073  | 0  |         if (fRB->fDebugEnv && uprv_strstr(fRB->fDebugEnv, "scan")) { RBBIDebugPuts("");} | 
1074  |  |  | 
1075  |  |         //  | 
1076  |  |         // We've found the row of the state table that matches the current input  | 
1077  |  |         //   character from the rules string.  | 
1078  |  |         // Perform any action specified  by this row in the state table.  | 
1079  | 0  |         if (doParseActions((int32_t)tableEl->fAction) == FALSE) { | 
1080  |  |             // Break out of the state machine loop if the  | 
1081  |  |             //   the action signalled some kind of error, or  | 
1082  |  |             //   the action was to exit, occurs on normal end-of-rules-input.  | 
1083  | 0  |             break;  | 
1084  | 0  |         }  | 
1085  |  |  | 
1086  | 0  |         if (tableEl->fPushState != 0) { | 
1087  | 0  |             fStackPtr++;  | 
1088  | 0  |             if (fStackPtr >= kStackSize) { | 
1089  | 0  |                 error(U_BRK_INTERNAL_ERROR);  | 
1090  | 0  |                 RBBIDebugPuts("RBBIRuleScanner::parse() - state stack overflow."); | 
1091  | 0  |                 fStackPtr--;  | 
1092  | 0  |             }  | 
1093  | 0  |             fStack[fStackPtr] = tableEl->fPushState;  | 
1094  | 0  |         }  | 
1095  |  | 
  | 
1096  | 0  |         if (tableEl->fNextChar) { | 
1097  | 0  |             nextChar(fC);  | 
1098  | 0  |         }  | 
1099  |  |  | 
1100  |  |         // Get the next state from the table entry, or from the  | 
1101  |  |         //   state stack if the next state was specified as "pop".  | 
1102  | 0  |         if (tableEl->fNextState != 255) { | 
1103  | 0  |             state = tableEl->fNextState;  | 
1104  | 0  |         } else { | 
1105  | 0  |             state = fStack[fStackPtr];  | 
1106  | 0  |             fStackPtr--;  | 
1107  | 0  |             if (fStackPtr < 0) { | 
1108  | 0  |                 error(U_BRK_INTERNAL_ERROR);  | 
1109  | 0  |                 RBBIDebugPuts("RBBIRuleScanner::parse() - state stack underflow."); | 
1110  | 0  |                 fStackPtr++;  | 
1111  | 0  |             }  | 
1112  | 0  |         }  | 
1113  |  | 
  | 
1114  | 0  |     }  | 
1115  |  | 
  | 
1116  | 0  |     if (U_FAILURE(*fRB->fStatus)) { | 
1117  | 0  |         return;  | 
1118  | 0  |     }  | 
1119  |  |       | 
1120  |  |     // If there are no forward rules set an error.  | 
1121  |  |     //  | 
1122  | 0  |     if (fRB->fForwardTree == NULL) { | 
1123  | 0  |         error(U_BRK_RULE_SYNTAX);  | 
1124  | 0  |         return;  | 
1125  | 0  |     }  | 
1126  |  |  | 
1127  |  |     //  | 
1128  |  |     // Parsing of the input RBBI rules is complete.  | 
1129  |  |     // We now have a parse tree for the rule expressions  | 
1130  |  |     // and a list of all UnicodeSets that are referenced.  | 
1131  |  |     //  | 
1132  |  | #ifdef RBBI_DEBUG  | 
1133  |  |     if (fRB->fDebugEnv && uprv_strstr(fRB->fDebugEnv, "symbols")) {fSymbolTable->rbbiSymtablePrint();} | 
1134  |  |     if (fRB->fDebugEnv && uprv_strstr(fRB->fDebugEnv, "ptree")) { | 
1135  |  |         RBBIDebugPrintf("Completed Forward Rules Parse Tree...\n"); | 
1136  |  |         RBBINode::printTree(fRB->fForwardTree, TRUE);  | 
1137  |  |         RBBIDebugPrintf("\nCompleted Reverse Rules Parse Tree...\n"); | 
1138  |  |         RBBINode::printTree(fRB->fReverseTree, TRUE);  | 
1139  |  |         RBBIDebugPrintf("\nCompleted Safe Point Forward Rules Parse Tree...\n"); | 
1140  |  |         RBBINode::printTree(fRB->fSafeFwdTree, TRUE);  | 
1141  |  |         RBBIDebugPrintf("\nCompleted Safe Point Reverse Rules Parse Tree...\n"); | 
1142  |  |         RBBINode::printTree(fRB->fSafeRevTree, TRUE);  | 
1143  |  |     }  | 
1144  |  | #endif  | 
1145  | 0  | }  | 
1146  |  |  | 
1147  |  |  | 
1148  |  | //------------------------------------------------------------------------------  | 
1149  |  | //  | 
1150  |  | //  printNodeStack     for debugging...  | 
1151  |  | //  | 
1152  |  | //------------------------------------------------------------------------------  | 
1153  |  | #ifdef RBBI_DEBUG  | 
1154  |  | void RBBIRuleScanner::printNodeStack(const char *title) { | 
1155  |  |     int i;  | 
1156  |  |     RBBIDebugPrintf("%s.  Dumping node stack...\n", title); | 
1157  |  |     for (i=fNodeStackPtr; i>0; i--) {RBBINode::printTree(fNodeStack[i], TRUE);} | 
1158  |  | }  | 
1159  |  | #endif  | 
1160  |  |  | 
1161  |  |  | 
1162  |  |  | 
1163  |  |  | 
1164  |  | //------------------------------------------------------------------------------  | 
1165  |  | //  | 
1166  |  | //  pushNewNode   create a new RBBINode of the specified type and push it  | 
1167  |  | //                onto the stack of nodes.  | 
1168  |  | //  | 
1169  |  | //------------------------------------------------------------------------------  | 
1170  | 0  | RBBINode  *RBBIRuleScanner::pushNewNode(RBBINode::NodeType  t) { | 
1171  | 0  |     if (U_FAILURE(*fRB->fStatus)) { | 
1172  | 0  |         return NULL;  | 
1173  | 0  |     }  | 
1174  | 0  |     if (fNodeStackPtr >= kStackSize - 1) { | 
1175  | 0  |         error(U_BRK_RULE_SYNTAX);  | 
1176  | 0  |         RBBIDebugPuts("RBBIRuleScanner::pushNewNode - stack overflow."); | 
1177  | 0  |         return NULL;  | 
1178  | 0  |     }  | 
1179  | 0  |     fNodeStackPtr++;  | 
1180  | 0  |     fNodeStack[fNodeStackPtr] = new RBBINode(t);  | 
1181  | 0  |     if (fNodeStack[fNodeStackPtr] == NULL) { | 
1182  | 0  |         *fRB->fStatus = U_MEMORY_ALLOCATION_ERROR;  | 
1183  | 0  |     }  | 
1184  | 0  |     return fNodeStack[fNodeStackPtr];  | 
1185  | 0  | }  | 
1186  |  |  | 
1187  |  |  | 
1188  |  |  | 
1189  |  | //------------------------------------------------------------------------------  | 
1190  |  | //  | 
1191  |  | //  scanSet    Construct a UnicodeSet from the text at the current scan  | 
1192  |  | //             position.  Advance the scan position to the first character  | 
1193  |  | //             after the set.  | 
1194  |  | //  | 
1195  |  | //             A new RBBI setref node referring to the set is pushed onto the node  | 
1196  |  | //             stack.  | 
1197  |  | //  | 
1198  |  | //             The scan position is normally under the control of the state machine  | 
1199  |  | //             that controls rule parsing.  UnicodeSets, however, are parsed by  | 
1200  |  | //             the UnicodeSet constructor, not by the RBBI rule parser.  | 
1201  |  | //  | 
1202  |  | //------------------------------------------------------------------------------  | 
1203  | 0  | void RBBIRuleScanner::scanSet() { | 
1204  | 0  |     UnicodeSet    *uset;  | 
1205  | 0  |     ParsePosition  pos;  | 
1206  | 0  |     int            startPos;  | 
1207  | 0  |     int            i;  | 
1208  |  | 
  | 
1209  | 0  |     if (U_FAILURE(*fRB->fStatus)) { | 
1210  | 0  |         return;  | 
1211  | 0  |     }  | 
1212  |  |  | 
1213  | 0  |     pos.setIndex(fScanIndex);  | 
1214  | 0  |     startPos = fScanIndex;  | 
1215  | 0  |     UErrorCode localStatus = U_ZERO_ERROR;  | 
1216  | 0  |     uset = new UnicodeSet();  | 
1217  | 0  |     if (uset == NULL) { | 
1218  | 0  |         localStatus = U_MEMORY_ALLOCATION_ERROR;  | 
1219  | 0  |     } else { | 
1220  | 0  |         uset->applyPatternIgnoreSpace(fRB->fRules, pos, fSymbolTable, localStatus);  | 
1221  | 0  |     }  | 
1222  | 0  |     if (U_FAILURE(localStatus)) { | 
1223  |  |         //  TODO:  Get more accurate position of the error from UnicodeSet's return info.  | 
1224  |  |         //         UnicodeSet appears to not be reporting correctly at this time.  | 
1225  |  |         #ifdef RBBI_DEBUG  | 
1226  |  |             RBBIDebugPrintf("UnicodeSet parse position.ErrorIndex = %d\n", pos.getIndex()); | 
1227  |  |         #endif  | 
1228  | 0  |         error(localStatus);  | 
1229  | 0  |         delete uset;  | 
1230  | 0  |         return;  | 
1231  | 0  |     }  | 
1232  |  |  | 
1233  |  |     // Verify that the set contains at least one code point.  | 
1234  |  |     //  | 
1235  | 0  |     U_ASSERT(uset!=NULL);  | 
1236  | 0  |     if (uset->isEmpty()) { | 
1237  |  |         // This set is empty.  | 
1238  |  |         //  Make it an error, because it almost certainly is not what the user wanted.  | 
1239  |  |         //  Also, avoids having to think about corner cases in the tree manipulation code  | 
1240  |  |         //   that occurs later on.  | 
1241  | 0  |         error(U_BRK_RULE_EMPTY_SET);  | 
1242  | 0  |         delete uset;  | 
1243  | 0  |         return;  | 
1244  | 0  |     }  | 
1245  |  |  | 
1246  |  |  | 
1247  |  |     // Advance the RBBI parse position over the UnicodeSet pattern.  | 
1248  |  |     //   Don't just set fScanIndex because the line/char positions maintained  | 
1249  |  |     //   for error reporting would be thrown off.  | 
1250  | 0  |     i = pos.getIndex();  | 
1251  | 0  |     for (;;) { | 
1252  | 0  |         if (fNextIndex >= i) { | 
1253  | 0  |             break;  | 
1254  | 0  |         }  | 
1255  | 0  |         nextCharLL();  | 
1256  | 0  |     }  | 
1257  |  | 
  | 
1258  | 0  |     if (U_SUCCESS(*fRB->fStatus)) { | 
1259  | 0  |         RBBINode         *n;  | 
1260  |  | 
  | 
1261  | 0  |         n = pushNewNode(RBBINode::setRef);  | 
1262  | 0  |         if (U_FAILURE(*fRB->fStatus)) { | 
1263  | 0  |             return;  | 
1264  | 0  |         }  | 
1265  | 0  |         n->fFirstPos = startPos;  | 
1266  | 0  |         n->fLastPos  = fNextIndex;  | 
1267  | 0  |         fRB->fRules.extractBetween(n->fFirstPos, n->fLastPos, n->fText);  | 
1268  |  |         //  findSetFor() serves several purposes here:  | 
1269  |  |         //     - Adopts storage for the UnicodeSet, will be responsible for deleting.  | 
1270  |  |         //     - Maintains collection of all sets in use, needed later for establishing  | 
1271  |  |         //          character categories for run time engine.  | 
1272  |  |         //     - Eliminates mulitiple instances of the same set.  | 
1273  |  |         //     - Creates a new uset node if necessary (if this isn't a duplicate.)  | 
1274  | 0  |         findSetFor(n->fText, n, uset);  | 
1275  | 0  |     }  | 
1276  |  | 
  | 
1277  | 0  | }  | 
1278  |  |  | 
1279  | 0  | int32_t RBBIRuleScanner::numRules() { | 
1280  | 0  |     return fRuleNum;  | 
1281  | 0  | }  | 
1282  |  |  | 
1283  |  | U_NAMESPACE_END  | 
1284  |  |  | 
1285  |  | #endif /* #if !UCONFIG_NO_BREAK_ITERATION */  |