1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
6 // Copyright (C) 2002-2016, International Business Machines Corporation and others.
7 // All Rights Reserved.
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.
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.
17 #include "unicode/utypes.h"
19 #if !UCONFIG_NO_BREAK_ITERATION
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"
30 #include "rbbirpt.h" // Contains state table for the rbbi rules parser.
31 // generated by a Perl script.
39 //------------------------------------------------------------------------------
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.)
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.
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};
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};
62 static const UChar gRuleSet_digit_char_pattern
[] = {
64 0x5b, 0x30, 0x2d, 0x39, 0x5d, 0};
66 static const UChar gRuleSet_name_start_char_pattern
[] = {
68 0x5b, 0x5f, 0x5c, 0x70, 0x7b, 0x4c, 0x7d, 0x5d, 0 };
70 static const UChar kAny
[] = {0x61, 0x6e, 0x79, 0x00}; // "any"
74 static void U_CALLCONV
RBBISetTable_deleter(void *p
) {
75 icu::RBBISetTableEl
*px
= (icu::RBBISetTableEl
*)p
;
77 // Note: px->val is owned by the linked list "fSetsListHead" in scanner.
78 // Don't delete the value nodes here.
85 //------------------------------------------------------------------------------
89 //------------------------------------------------------------------------------
90 RBBIRuleScanner::RBBIRuleScanner(RBBIRuleBuilder
*rb
)
103 fNodeStack
[0] = NULL
;
106 fReverseRule
= FALSE
;
107 fLookAheadRule
= FALSE
;
108 fNoChainInRule
= FALSE
;
115 // Do not check status until after all critical fields are sufficiently initialized
116 // that the destructor can run cleanly.
117 if (U_FAILURE(*rb
->fStatus
)) {
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 fRuleSets
[kRuleSet_rule_char
-128]
128 = UnicodeSet(UnicodeString(gRuleSet_rule_char_pattern
), *rb
->fStatus
);
129 // fRuleSets[kRuleSet_white_space-128] = [:Pattern_White_Space:]
130 fRuleSets
[kRuleSet_white_space
-128].
131 add(9, 0xd).add(0x20).add(0x85).add(0x200e, 0x200f).add(0x2028, 0x2029);
132 fRuleSets
[kRuleSet_name_char
-128]
133 = UnicodeSet(UnicodeString(gRuleSet_name_char_pattern
), *rb
->fStatus
);
134 fRuleSets
[kRuleSet_name_start_char
-128]
135 = UnicodeSet(UnicodeString(gRuleSet_name_start_char_pattern
), *rb
->fStatus
);
136 fRuleSets
[kRuleSet_digit_char
-128]
137 = UnicodeSet(UnicodeString(gRuleSet_digit_char_pattern
), *rb
->fStatus
);
138 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 *rb
->fStatus
= U_BRK_INIT_ERROR
;
144 if (U_FAILURE(*rb
->fStatus
)) {
148 fSymbolTable
= new RBBISymbolTable(this, rb
->fRules
, *rb
->fStatus
);
149 if (fSymbolTable
== NULL
) {
150 *rb
->fStatus
= U_MEMORY_ALLOCATION_ERROR
;
153 fSetTable
= uhash_open(uhash_hashUnicodeString
, uhash_compareUnicodeString
, NULL
, rb
->fStatus
);
154 if (U_FAILURE(*rb
->fStatus
)) {
157 uhash_setValueDeleter(fSetTable
, RBBISetTable_deleter
);
162 //------------------------------------------------------------------------------
166 //------------------------------------------------------------------------------
167 RBBIRuleScanner::~RBBIRuleScanner() {
169 if (fSetTable
!= NULL
) {
170 uhash_close(fSetTable
);
177 // Normally has one entry, which is the entire parse tree for the rules.
178 // If errors occured, there may be additional subtrees left on the stack.
179 while (fNodeStackPtr
> 0) {
180 delete fNodeStack
[fNodeStackPtr
];
186 //------------------------------------------------------------------------------
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.
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.
199 //------------------------------------------------------------------------------
200 UBool
RBBIRuleScanner::doParseActions(int32_t action
)
204 UBool returnVal
= TRUE
;
209 pushNewNode(RBBINode::opStart
);
215 // Scanned a '^' while on the rule start state.
216 fNoChainInRule
= TRUE
;
220 case doExprOrOperator
:
222 fixOpStack(RBBINode::precOpCat
);
223 RBBINode
*operandNode
= fNodeStack
[fNodeStackPtr
--];
224 RBBINode
*orNode
= pushNewNode(RBBINode::opOr
);
225 if (U_FAILURE(*fRB
->fStatus
)) {
228 orNode
->fLeftChild
= operandNode
;
229 operandNode
->fParent
= orNode
;
233 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.
239 fixOpStack(RBBINode::precOpCat
);
240 RBBINode
*operandNode
= fNodeStack
[fNodeStackPtr
--];
241 RBBINode
*catNode
= pushNewNode(RBBINode::opCat
);
242 if (U_FAILURE(*fRB
->fStatus
)) {
245 catNode
->fLeftChild
= operandNode
;
246 operandNode
->fParent
= catNode
;
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 pushNewNode(RBBINode::opLParen
);
260 fixOpStack(RBBINode::precLParen
);
267 // We've just scanned "$variable = "
268 // The top of the node stack has the $variable ref node.
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
274 n
= fNodeStack
[fNodeStackPtr
-1];
275 n
->fFirstPos
= fNextIndex
; // move past the '='
277 // Push a new start-of-expression node; needed to keep parse of the
278 // RHS expression happy.
279 pushNewNode(RBBINode::opStart
);
287 // We have reached the end of an assignement statement.
288 // Current scan char is the ';' that terminates the assignment.
290 // Terminate expression, leaves expression parse tree rooted in TOS node.
291 fixOpStack(RBBINode::precStart
);
293 RBBINode
*startExprNode
= fNodeStack
[fNodeStackPtr
-2];
294 RBBINode
*varRefNode
= fNodeStack
[fNodeStackPtr
-1];
295 RBBINode
*RHSExprNode
= fNodeStack
[fNodeStackPtr
];
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 RHSExprNode
->fFirstPos
= startExprNode
->fFirstPos
;
300 RHSExprNode
->fLastPos
= fScanIndex
;
301 fRB
->fRules
.extractBetween(RHSExprNode
->fFirstPos
, RHSExprNode
->fLastPos
, RHSExprNode
->fText
);
303 // Expression parse tree becomes l. child of the $variable reference node.
304 varRefNode
->fLeftChild
= RHSExprNode
;
305 RHSExprNode
->fParent
= varRefNode
;
307 // Make a symbol table entry for the $variableRef node.
308 fSymbolTable
->addEntry(varRefNode
->fText
, varRefNode
, *fRB
->fStatus
);
309 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 UErrorCode t
= *fRB
->fStatus
;
313 *fRB
->fStatus
= U_ZERO_ERROR
;
317 // Clean up the stack.
318 delete startExprNode
;
325 fixOpStack(RBBINode::precStart
); // Terminate expression, leaves expression
326 if (U_FAILURE(*fRB
->fStatus
)) { // parse tree rooted in TOS node.
330 if (fRB
->fDebugEnv
&& uprv_strstr(fRB
->fDebugEnv
, "rtree")) {printNodeStack("end of rule");}
332 U_ASSERT(fNodeStackPtr
== 1);
333 RBBINode
*thisRule
= fNodeStack
[fNodeStackPtr
];
335 // If this rule includes a look-ahead '/', add a endMark node to the
337 if (fLookAheadRule
) {
338 RBBINode
*endNode
= pushNewNode(RBBINode::endMark
);
339 RBBINode
*catNode
= pushNewNode(RBBINode::opCat
);
340 if (U_FAILURE(*fRB
->fStatus
)) {
344 catNode
->fLeftChild
= thisRule
;
345 catNode
->fRightChild
= endNode
;
346 fNodeStack
[fNodeStackPtr
] = catNode
;
347 endNode
->fVal
= fRuleNum
;
348 endNode
->fLookAheadEnd
= TRUE
;
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.
356 // Mark this node as being the root of a rule.
357 thisRule
->fRuleRoot
= TRUE
;
359 // Flag if chaining into this rule is wanted.
361 if (fRB
->fChainRules
&& // If rule chaining is enabled globally via !!chain
362 !fNoChainInRule
) { // and no '^' chain-in inhibit was on this rule
363 thisRule
->fChainIn
= TRUE
;
367 // All rule expressions are ORed together.
368 // The ';' that terminates an expression really just functions as a '|' with
369 // a low operator prededence.
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.
375 RBBINode
**destRules
= (fReverseRule
? &fRB
->fSafeRevTree
: fRB
->fDefaultTree
);
377 if (*destRules
!= NULL
) {
378 // This is not the first rule encounted.
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
383 thisRule
= fNodeStack
[fNodeStackPtr
];
384 RBBINode
*prevRules
= *destRules
;
385 RBBINode
*orNode
= pushNewNode(RBBINode::opOr
);
386 if (U_FAILURE(*fRB
->fStatus
)) {
389 orNode
->fLeftChild
= prevRules
;
390 prevRules
->fParent
= orNode
;
391 orNode
->fRightChild
= thisRule
;
392 thisRule
->fParent
= orNode
;
397 // This is the first rule encountered (for this direction).
398 // Just move its parse tree from the stack to *destRules.
399 *destRules
= fNodeStack
[fNodeStackPtr
];
401 fReverseRule
= FALSE
; // in preparation for the next rule.
402 fLookAheadRule
= FALSE
;
403 fNoChainInRule
= FALSE
;
410 error(U_BRK_RULE_SYNTAX
);
415 case doVariableNameExpectedErr
:
416 error(U_BRK_RULE_SYNTAX
);
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.
428 RBBINode
*operandNode
= fNodeStack
[fNodeStackPtr
--];
429 RBBINode
*plusNode
= pushNewNode(RBBINode::opPlus
);
430 if (U_FAILURE(*fRB
->fStatus
)) {
433 plusNode
->fLeftChild
= operandNode
;
434 operandNode
->fParent
= plusNode
;
438 case doUnaryOpQuestion
:
440 RBBINode
*operandNode
= fNodeStack
[fNodeStackPtr
--];
441 RBBINode
*qNode
= pushNewNode(RBBINode::opQuestion
);
442 if (U_FAILURE(*fRB
->fStatus
)) {
445 qNode
->fLeftChild
= operandNode
;
446 operandNode
->fParent
= qNode
;
452 RBBINode
*operandNode
= fNodeStack
[fNodeStackPtr
--];
453 RBBINode
*starNode
= pushNewNode(RBBINode::opStar
);
454 if (U_FAILURE(*fRB
->fStatus
)) {
457 starNode
->fLeftChild
= operandNode
;
458 operandNode
->fParent
= starNode
;
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.
469 n
= pushNewNode(RBBINode::setRef
);
470 if (U_FAILURE(*fRB
->fStatus
)) {
473 findSetFor(UnicodeString(fC
.fChar
), n
);
474 n
->fFirstPos
= fScanIndex
;
475 n
->fLastPos
= fNextIndex
;
476 fRB
->fRules
.extractBetween(n
->fFirstPos
, n
->fLastPos
, n
->fText
);
481 // scanned a ".", meaning match any single character.
483 n
= pushNewNode(RBBINode::setRef
);
484 if (U_FAILURE(*fRB
->fStatus
)) {
487 findSetFor(UnicodeString(TRUE
, kAny
, 3), n
);
488 n
->fFirstPos
= fScanIndex
;
489 n
->fLastPos
= fNextIndex
;
490 fRB
->fRules
.extractBetween(n
->fFirstPos
, n
->fLastPos
, n
->fText
);
495 // Scanned a '/', which identifies a look-ahead break position in a rule.
496 n
= pushNewNode(RBBINode::lookAhead
);
497 if (U_FAILURE(*fRB
->fStatus
)) {
501 n
->fFirstPos
= fScanIndex
;
502 n
->fLastPos
= fNextIndex
;
503 fRB
->fRules
.extractBetween(n
->fFirstPos
, n
->fLastPos
, n
->fText
);
504 fLookAheadRule
= TRUE
;
508 case doStartTagValue
:
509 // Scanned a '{', the opening delimiter for a tag value within a rule.
510 n
= pushNewNode(RBBINode::tag
);
511 if (U_FAILURE(*fRB
->fStatus
)) {
515 n
->fFirstPos
= fScanIndex
;
516 n
->fLastPos
= fNextIndex
;
520 // Just scanned a decimal digit that's part of a tag value
522 n
= fNodeStack
[fNodeStackPtr
];
523 uint32_t v
= u_charDigitValue(fC
.fChar
);
525 n
->fVal
= n
->fVal
*10 + v
;
530 n
= fNodeStack
[fNodeStackPtr
];
531 n
->fLastPos
= fNextIndex
;
532 fRB
->fRules
.extractBetween(n
->fFirstPos
, n
->fLastPos
, n
->fText
);
535 case doTagExpectedError
:
536 error(U_BRK_MALFORMED_RULE_TAG
);
541 // Scanning a !!option. At the start of string.
542 fOptionStart
= fScanIndex
;
547 UnicodeString
opt(fRB
->fRules
, fOptionStart
, fScanIndex
-fOptionStart
);
548 if (opt
== UNICODE_STRING("chain", 5)) {
549 fRB
->fChainRules
= TRUE
;
550 } else if (opt
== UNICODE_STRING("LBCMNoChain", 11)) {
551 fRB
->fLBCMNoChain
= TRUE
;
552 } else if (opt
== UNICODE_STRING("forward", 7)) {
553 fRB
->fDefaultTree
= &fRB
->fForwardTree
;
554 } else if (opt
== UNICODE_STRING("reverse", 7)) {
555 fRB
->fDefaultTree
= &fRB
->fReverseTree
;
556 } else if (opt
== UNICODE_STRING("safe_forward", 12)) {
557 fRB
->fDefaultTree
= &fRB
->fSafeFwdTree
;
558 } else if (opt
== UNICODE_STRING("safe_reverse", 12)) {
559 fRB
->fDefaultTree
= &fRB
->fSafeRevTree
;
560 } else if (opt
== UNICODE_STRING("lookAheadHardBreak", 18)) {
561 fRB
->fLookAheadHardBreak
= TRUE
;
562 } else if (opt
== UNICODE_STRING("quoted_literals_only", 20)) {
563 fRuleSets
[kRuleSet_rule_char
-128].clear();
564 } else if (opt
== UNICODE_STRING("unquoted_literals", 17)) {
565 fRuleSets
[kRuleSet_rule_char
-128].applyPattern(UnicodeString(gRuleSet_rule_char_pattern
), *fRB
->fStatus
);
567 error(U_BRK_UNRECOGNIZED_OPTION
);
576 case doStartVariableName
:
577 n
= pushNewNode(RBBINode::varRef
);
578 if (U_FAILURE(*fRB
->fStatus
)) {
581 n
->fFirstPos
= fScanIndex
;
584 case doEndVariableName
:
585 n
= fNodeStack
[fNodeStackPtr
];
586 if (n
==NULL
|| n
->fType
!= RBBINode::varRef
) {
587 error(U_BRK_INTERNAL_ERROR
);
590 n
->fLastPos
= fScanIndex
;
591 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 n
->fLeftChild
= fSymbolTable
->lookupNode(n
->fText
);
600 n
= fNodeStack
[fNodeStackPtr
];
601 if (n
->fLeftChild
== NULL
) {
602 error(U_BRK_UNDEFINED_VARIABLE
);
610 case doRuleErrorAssignExpr
:
611 error(U_BRK_ASSIGN_ERROR
);
619 case doScanUnicodeSet
:
624 error(U_BRK_INTERNAL_ERROR
);
628 return returnVal
&& U_SUCCESS(*fRB
->fStatus
);
634 //------------------------------------------------------------------------------
636 // Error Report a rule parse error.
637 // Only report it if no previous error has been recorded.
639 //------------------------------------------------------------------------------
640 void RBBIRuleScanner::error(UErrorCode e
) {
641 if (U_SUCCESS(*fRB
->fStatus
)) {
643 if (fRB
->fParseError
) {
644 fRB
->fParseError
->line
= fLineNum
;
645 fRB
->fParseError
->offset
= fCharNum
;
646 fRB
->fParseError
->preContext
[0] = 0;
647 fRB
->fParseError
->postContext
[0] = 0;
655 //------------------------------------------------------------------------------
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.
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.
669 //------------------------------------------------------------------------------
670 void RBBIRuleScanner::fixOpStack(RBBINode::OpPrecedence p
) {
672 // printNodeStack("entering fixOpStack()");
674 n
= fNodeStack
[fNodeStackPtr
-1]; // an operator node
675 if (n
->fPrecedence
== 0) {
676 RBBIDebugPuts("RBBIRuleScanner::fixOpStack, bad operator node");
677 error(U_BRK_INTERNAL_ERROR
);
681 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.
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 n
->fRightChild
= fNodeStack
[fNodeStackPtr
];
690 fNodeStack
[fNodeStackPtr
]->fParent
= n
;
692 // printNodeStack("looping in fixOpStack() ");
695 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 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 error(U_BRK_MISMATCHED_PAREN
);
705 fNodeStack
[fNodeStackPtr
-1] = fNodeStack
[fNodeStackPtr
];
707 // Delete the now-discarded LParen or Start node.
710 // printNodeStack("leaving fixOpStack()");
716 //------------------------------------------------------------------------------
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)
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.
731 //------------------------------------------------------------------------------
732 void RBBIRuleScanner::findSetFor(const UnicodeString
&s
, RBBINode
*node
, UnicodeSet
*setToAdopt
) {
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 el
= (RBBISetTableEl
*)uhash_get(fSetTable
, &s
);
742 node
->fLeftChild
= el
->val
;
743 U_ASSERT(node
->fLeftChild
->fType
== RBBINode::uset
);
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 if (setToAdopt
== NULL
) {
751 if (s
.compare(kAny
, -1) == 0) {
752 setToAdopt
= new UnicodeSet(0x000000, 0x10ffff);
756 setToAdopt
= new UnicodeSet(c
, c
);
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.
764 RBBINode
*usetNode
= new RBBINode(RBBINode::uset
);
765 if (usetNode
== NULL
) {
766 error(U_MEMORY_ALLOCATION_ERROR
);
769 usetNode
->fInputSet
= setToAdopt
;
770 usetNode
->fParent
= node
;
771 node
->fLeftChild
= usetNode
;
776 // Add the new uset node to the list of all uset nodes.
778 fRB
->fUSetNodes
->addElement(usetNode
, *fRB
->fStatus
);
782 // Add the new set to the set hash table.
784 el
= (RBBISetTableEl
*)uprv_malloc(sizeof(RBBISetTableEl
));
785 UnicodeString
*tkey
= new UnicodeString(s
);
786 if (tkey
== NULL
|| el
== NULL
|| setToAdopt
== NULL
) {
787 // Delete to avoid memory leak
795 error(U_MEMORY_ALLOCATION_ERROR
);
800 uhash_put(fSetTable
, el
->key
, el
, fRB
->fStatus
);
808 // Assorted Unicode character constants.
809 // Numeric because there is no portable way to enter them as literals.
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;
823 //------------------------------------------------------------------------------
825 // stripRules Return a rules string without extra spaces.
826 // (Comments are removed separately, during rule parsing.)
828 //------------------------------------------------------------------------------
829 UnicodeString
RBBIRuleScanner::stripRules(const UnicodeString
&rules
) {
830 UnicodeString strippedRules
;
831 int32_t rulesLength
= rules
.length();
832 bool skippingSpaces
= false;
834 for (int32_t idx
=0; idx
<rulesLength
; idx
= rules
.moveIndex32(idx
, 1)) {
835 UChar32 cp
= rules
.char32At(idx
);
836 bool whiteSpace
= u_hasBinaryProperty(cp
, UCHAR_PATTERN_WHITE_SPACE
);
837 if (skippingSpaces
&& whiteSpace
) {
840 strippedRules
.append(cp
);
841 skippingSpaces
= whiteSpace
;
843 return strippedRules
;
847 //------------------------------------------------------------------------------
849 // nextCharLL Low Level Next Char from rule input source.
850 // Get a char from the input character iterator,
851 // keep track of input position for error reporting.
853 //------------------------------------------------------------------------------
854 UChar32
RBBIRuleScanner::nextCharLL() {
857 if (fNextIndex
>= fRB
->fRules
.length()) {
860 ch
= fRB
->fRules
.char32At(fNextIndex
);
861 fNextIndex
= fRB
->fRules
.moveIndex32(fNextIndex
, 1);
866 (ch
== chLF
&& fLastChar
!= chCR
)) {
867 // Character is starting a new line. Bump up the line number, and
868 // reset the column to 0.
872 error(U_BRK_NEW_LINE_IN_QUOTED_STRING
);
877 // Character is not starting a new line. Except in the case of a
878 // LF following a CR, increment the column position.
888 //------------------------------------------------------------------------------
890 // nextChar for rules scanning. At this level, we handle stripping
891 // out comments and processing backslash character escapes.
892 // The rest of the rules grammar is handled at the next level up.
894 //------------------------------------------------------------------------------
895 void RBBIRuleScanner::nextChar(RBBIRuleChar
&c
) {
897 // Unicode Character constants needed for the processing done by nextChar(),
898 // in hex because literals wont work on EBCDIC machines.
900 fScanIndex
= fNextIndex
;
901 c
.fChar
= nextCharLL();
905 // check for '' sequence.
906 // These are recognized in all contexts, whether in quoted text or not.
908 if (c
.fChar
== chApos
) {
909 if (fRB
->fRules
.char32At(fNextIndex
) == chApos
) {
910 c
.fChar
= nextCharLL(); // get nextChar officially so character counts
911 c
.fEscaped
= TRUE
; // stay correct.
915 // Single quote, by itself.
916 // Toggle quoting mode.
917 // Return either '(' or ')', because quotes cause a grouping of the quoted text.
918 fQuoteMode
= !fQuoteMode
;
919 if (fQuoteMode
== TRUE
) {
924 c
.fEscaped
= FALSE
; // The paren that we return is not escaped.
934 // We are not in a 'quoted region' of the source.
936 if (c
.fChar
== chPound
) {
937 // Start of a comment. Consume the rest of it.
938 // The new-line char that terminates the comment is always returned.
939 // It will be treated as white-space, and serves to break up anything
940 // that might otherwise incorrectly clump together with a comment in
941 // the middle (a variable name, for example.)
942 int32_t commentStart
= fScanIndex
;
944 c
.fChar
= nextCharLL();
945 if (c
.fChar
== (UChar32
)-1 || // EOF
949 c
.fChar
== chLS
) {break;}
951 for (int32_t i
=commentStart
; i
<fNextIndex
-1; ++i
) {
952 fRB
->fStrippedRules
.setCharAt(i
, u
' ');
955 if (c
.fChar
== (UChar32
)-1) {
960 // check for backslash escaped characters.
961 // Use UnicodeString::unescapeAt() to handle them.
963 if (c
.fChar
== chBackSlash
) {
965 int32_t startX
= fNextIndex
;
966 c
.fChar
= fRB
->fRules
.unescapeAt(fNextIndex
);
967 if (fNextIndex
== startX
) {
968 error(U_BRK_HEX_DIGITS_EXPECTED
);
970 fCharNum
+= fNextIndex
-startX
;
973 // putc(c.fChar, stdout);
976 //------------------------------------------------------------------------------
978 // Parse RBBI rules. The state machine for rules parsing is here.
979 // The state tables are hand-written in the file rbbirpt.txt,
980 // and converted to the form used here by a perl
983 //------------------------------------------------------------------------------
984 void RBBIRuleScanner::parse() {
986 const RBBIRuleTableEl
*tableEl
;
988 if (U_FAILURE(*fRB
->fStatus
)) {
995 // Main loop for the rule parsing state machine.
996 // Runs once per state transition.
997 // Each time through optionally performs, depending on the state table,
998 // - an advance to the the next input char
999 // - an action to be performed.
1000 // - pushing or popping a state to/from the local state return stack.
1003 // Bail out if anything has gone wrong.
1004 // RBBI rule file parsing stops on the first error encountered.
1005 if (U_FAILURE(*fRB
->fStatus
)) {
1009 // Quit if state == 0. This is the normal way to exit the state machine.
1015 // Find the state table element that matches the input char from the rule, or the
1016 // class of the input character. Start with the first table row for this
1017 // state, then linearly scan forward until we find a row that matches the
1018 // character. The last row for each state always matches all characters, so
1019 // the search will stop there, if not before.
1021 tableEl
= &gRuleParseStateTable
[state
];
1023 if (fRB
->fDebugEnv
&& uprv_strstr(fRB
->fDebugEnv
, "scan")) {
1024 RBBIDebugPrintf("char, line, col = (\'%c\', %d, %d) state=%s ",
1025 fC
.fChar
, fLineNum
, fCharNum
, RBBIRuleStateNames
[state
]);
1031 if (fRB
->fDebugEnv
&& uprv_strstr(fRB
->fDebugEnv
, "scan")) { RBBIDebugPrintf("."); fflush(stdout
);}
1033 if (tableEl
->fCharClass
< 127 && fC
.fEscaped
== FALSE
&& tableEl
->fCharClass
== fC
.fChar
) {
1034 // Table row specified an individual character, not a set, and
1035 // the input character is not escaped, and
1036 // the input character matched it.
1039 if (tableEl
->fCharClass
== 255) {
1040 // Table row specified default, match anything character class.
1043 if (tableEl
->fCharClass
== 254 && fC
.fEscaped
) {
1044 // Table row specified "escaped" and the char was escaped.
1047 if (tableEl
->fCharClass
== 253 && fC
.fEscaped
&&
1048 (fC
.fChar
== 0x50 || fC
.fChar
== 0x70 )) {
1049 // Table row specified "escaped P" and the char is either 'p' or 'P'.
1052 if (tableEl
->fCharClass
== 252 && fC
.fChar
== (UChar32
)-1) {
1053 // Table row specified eof and we hit eof on the input.
1057 if (tableEl
->fCharClass
>= 128 && tableEl
->fCharClass
< 240 && // Table specs a char class &&
1058 fC
.fEscaped
== FALSE
&& // char is not escaped &&
1059 fC
.fChar
!= (UChar32
)-1) { // char is not EOF
1060 U_ASSERT((tableEl
->fCharClass
-128) < UPRV_LENGTHOF(fRuleSets
));
1061 if (fRuleSets
[tableEl
->fCharClass
-128].contains(fC
.fChar
)) {
1062 // Table row specified a character class, or set of characters,
1063 // and the current char matches it.
1068 // No match on this row, advance to the next row for this state,
1071 if (fRB
->fDebugEnv
&& uprv_strstr(fRB
->fDebugEnv
, "scan")) { RBBIDebugPuts("");}
1074 // We've found the row of the state table that matches the current input
1075 // character from the rules string.
1076 // Perform any action specified by this row in the state table.
1077 if (doParseActions((int32_t)tableEl
->fAction
) == FALSE
) {
1078 // Break out of the state machine loop if the
1079 // the action signalled some kind of error, or
1080 // the action was to exit, occurs on normal end-of-rules-input.
1084 if (tableEl
->fPushState
!= 0) {
1086 if (fStackPtr
>= kStackSize
) {
1087 error(U_BRK_INTERNAL_ERROR
);
1088 RBBIDebugPuts("RBBIRuleScanner::parse() - state stack overflow.");
1091 fStack
[fStackPtr
] = tableEl
->fPushState
;
1094 if (tableEl
->fNextChar
) {
1098 // Get the next state from the table entry, or from the
1099 // state stack if the next state was specified as "pop".
1100 if (tableEl
->fNextState
!= 255) {
1101 state
= tableEl
->fNextState
;
1103 state
= fStack
[fStackPtr
];
1105 if (fStackPtr
< 0) {
1106 error(U_BRK_INTERNAL_ERROR
);
1107 RBBIDebugPuts("RBBIRuleScanner::parse() - state stack underflow.");
1114 if (U_FAILURE(*fRB
->fStatus
)) {
1118 // If there are no forward rules set an error.
1120 if (fRB
->fForwardTree
== NULL
) {
1121 error(U_BRK_RULE_SYNTAX
);
1126 // Parsing of the input RBBI rules is complete.
1127 // We now have a parse tree for the rule expressions
1128 // and a list of all UnicodeSets that are referenced.
1131 if (fRB
->fDebugEnv
&& uprv_strstr(fRB
->fDebugEnv
, "symbols")) {fSymbolTable
->rbbiSymtablePrint();}
1132 if (fRB
->fDebugEnv
&& uprv_strstr(fRB
->fDebugEnv
, "ptree")) {
1133 RBBIDebugPrintf("Completed Forward Rules Parse Tree...\n");
1134 RBBINode::printTree(fRB
->fForwardTree
, TRUE
);
1135 RBBIDebugPrintf("\nCompleted Reverse Rules Parse Tree...\n");
1136 RBBINode::printTree(fRB
->fReverseTree
, TRUE
);
1137 RBBIDebugPrintf("\nCompleted Safe Point Forward Rules Parse Tree...\n");
1138 RBBINode::printTree(fRB
->fSafeFwdTree
, TRUE
);
1139 RBBIDebugPrintf("\nCompleted Safe Point Reverse Rules Parse Tree...\n");
1140 RBBINode::printTree(fRB
->fSafeRevTree
, TRUE
);
1146 //------------------------------------------------------------------------------
1148 // printNodeStack for debugging...
1150 //------------------------------------------------------------------------------
1152 void RBBIRuleScanner::printNodeStack(const char *title
) {
1154 RBBIDebugPrintf("%s. Dumping node stack...\n", title
);
1155 for (i
=fNodeStackPtr
; i
>0; i
--) {RBBINode::printTree(fNodeStack
[i
], TRUE
);}
1162 //------------------------------------------------------------------------------
1164 // pushNewNode create a new RBBINode of the specified type and push it
1165 // onto the stack of nodes.
1167 //------------------------------------------------------------------------------
1168 RBBINode
*RBBIRuleScanner::pushNewNode(RBBINode::NodeType t
) {
1169 if (U_FAILURE(*fRB
->fStatus
)) {
1172 if (fNodeStackPtr
>= kStackSize
- 1) {
1173 error(U_BRK_RULE_SYNTAX
);
1174 RBBIDebugPuts("RBBIRuleScanner::pushNewNode - stack overflow.");
1178 fNodeStack
[fNodeStackPtr
] = new RBBINode(t
);
1179 if (fNodeStack
[fNodeStackPtr
] == NULL
) {
1180 *fRB
->fStatus
= U_MEMORY_ALLOCATION_ERROR
;
1182 return fNodeStack
[fNodeStackPtr
];
1187 //------------------------------------------------------------------------------
1189 // scanSet Construct a UnicodeSet from the text at the current scan
1190 // position. Advance the scan position to the first character
1193 // A new RBBI setref node referring to the set is pushed onto the node
1196 // The scan position is normally under the control of the state machine
1197 // that controls rule parsing. UnicodeSets, however, are parsed by
1198 // the UnicodeSet constructor, not by the RBBI rule parser.
1200 //------------------------------------------------------------------------------
1201 void RBBIRuleScanner::scanSet() {
1207 if (U_FAILURE(*fRB
->fStatus
)) {
1211 pos
.setIndex(fScanIndex
);
1212 startPos
= fScanIndex
;
1213 UErrorCode localStatus
= U_ZERO_ERROR
;
1214 uset
= new UnicodeSet();
1216 localStatus
= U_MEMORY_ALLOCATION_ERROR
;
1218 uset
->applyPatternIgnoreSpace(fRB
->fRules
, pos
, fSymbolTable
, localStatus
);
1220 if (U_FAILURE(localStatus
)) {
1221 // TODO: Get more accurate position of the error from UnicodeSet's return info.
1222 // UnicodeSet appears to not be reporting correctly at this time.
1224 RBBIDebugPrintf("UnicodeSet parse postion.ErrorIndex = %d\n", pos
.getIndex());
1231 // Verify that the set contains at least one code point.
1233 U_ASSERT(uset
!=NULL
);
1234 if (uset
->isEmpty()) {
1235 // This set is empty.
1236 // Make it an error, because it almost certainly is not what the user wanted.
1237 // Also, avoids having to think about corner cases in the tree manipulation code
1238 // that occurs later on.
1239 error(U_BRK_RULE_EMPTY_SET
);
1245 // Advance the RBBI parse postion over the UnicodeSet pattern.
1246 // Don't just set fScanIndex because the line/char positions maintained
1247 // for error reporting would be thrown off.
1250 if (fNextIndex
>= i
) {
1256 if (U_SUCCESS(*fRB
->fStatus
)) {
1259 n
= pushNewNode(RBBINode::setRef
);
1260 if (U_FAILURE(*fRB
->fStatus
)) {
1263 n
->fFirstPos
= startPos
;
1264 n
->fLastPos
= fNextIndex
;
1265 fRB
->fRules
.extractBetween(n
->fFirstPos
, n
->fLastPos
, n
->fText
);
1266 // findSetFor() serves several purposes here:
1267 // - Adopts storage for the UnicodeSet, will be responsible for deleting.
1268 // - Mantains collection of all sets in use, needed later for establishing
1269 // character categories for run time engine.
1270 // - Eliminates mulitiple instances of the same set.
1271 // - Creates a new uset node if necessary (if this isn't a duplicate.)
1272 findSetFor(n
->fText
, n
, uset
);
1279 #endif /* #if !UCONFIG_NO_BREAK_ITERATION */