2 *******************************************************************************
3 * Copyright (C) 2007-2008, International Business Machines Corporation and
4 * others. All Rights Reserved.
5 *******************************************************************************
9 * Modification History:
11 * Date Name Description
12 *******************************************************************************
16 #include "unicode/uniset.h"
17 #include "unicode/utypes.h"
18 #include "unicode/ures.h"
19 #include "unicode/plurrule.h"
24 #include "plurrule_impl.h"
31 // TODO(claireho): remove stdio
35 #if !UCONFIG_NO_FORMATTING
40 #define ARRAY_SIZE(array) (int32_t)(sizeof array / sizeof array[0])
42 static const UChar PLURAL_KEYWORD_ZERO
[] = {LOW_Z
,LOW_E
,LOW_R
,LOW_O
, 0};
43 static const UChar PLURAL_KEYWORD_ONE
[]={LOW_O
,LOW_N
,LOW_E
,0};
44 static const UChar PLURAL_KEYWORD_TWO
[]={LOW_T
,LOW_W
,LOW_O
,0};
45 static const UChar PLURAL_KEYWORD_FEW
[]={LOW_F
,LOW_E
,LOW_W
,0};
46 static const UChar PLURAL_KEYWORD_MANY
[]={LOW_M
,LOW_A
,LOW_N
,LOW_Y
,0};
47 static const UChar PLURAL_KEYWORD_OTHER
[]={LOW_O
,LOW_T
,LOW_H
,LOW_E
,LOW_R
,0};
48 static const UChar PLURAL_DEFAULT_RULE
[]={LOW_O
,LOW_T
,LOW_H
,LOW_E
,LOW_R
,COLON
,SPACE
,LOW_N
,0};
49 static const UChar PK_IN
[]={LOW_I
,LOW_N
,0};
50 static const UChar PK_NOT
[]={LOW_N
,LOW_O
,LOW_T
,0};
51 static const UChar PK_IS
[]={LOW_I
,LOW_S
,0};
52 static const UChar PK_MOD
[]={LOW_M
,LOW_O
,LOW_D
,0};
53 static const UChar PK_AND
[]={LOW_A
,LOW_N
,LOW_D
,0};
54 static const UChar PK_OR
[]={LOW_O
,LOW_R
,0};
55 static const UChar PK_VAR_N
[]={LOW_N
,0};
56 static const UChar PK_WITHIN
[]={LOW_W
,LOW_I
,LOW_T
,LOW_H
,LOW_I
,LOW_N
,0};
58 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(PluralRules
)
59 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(PluralKeywordEnumeration
)
61 PluralRules::PluralRules(UErrorCode
& status
)
64 mParser(new RuleParser())
67 status
= U_MEMORY_ALLOCATION_ERROR
;
71 PluralRules::PluralRules(const PluralRules
& other
)
74 mParser(new RuleParser())
79 PluralRules::~PluralRules() {
85 PluralRules::clone() const {
86 return new PluralRules(*this);
90 PluralRules::operator=(const PluralRules
& other
) {
93 if (other
.mRules
==NULL
) {
97 mRules
= new RuleChain(*other
.mRules
);
100 mParser
= new RuleParser();
106 PluralRules
* U_EXPORT2
107 PluralRules::createRules(const UnicodeString
& description
, UErrorCode
& status
) {
110 PluralRules
*newRules
= new PluralRules(status
);
111 if ( (newRules
!= NULL
)&& U_SUCCESS(status
) ) {
112 newRules
->parseDescription((UnicodeString
&)description
, rules
, status
);
113 if (U_SUCCESS(status
)) {
114 newRules
->addRules(rules
);
117 if (U_FAILURE(status
)) {
126 PluralRules
* U_EXPORT2
127 PluralRules::createDefaultRules(UErrorCode
& status
) {
128 return createRules(PLURAL_DEFAULT_RULE
, status
);
131 PluralRules
* U_EXPORT2
132 PluralRules::forLocale(const Locale
& locale
, UErrorCode
& status
) {
134 status
= U_ZERO_ERROR
;
135 PluralRules
*newObj
= new PluralRules(status
);
139 UnicodeString locRule
= newObj
->getRuleFromResource(locale
, status
);
140 if ((locRule
.length() != 0) && U_SUCCESS(status
)) {
141 newObj
->parseDescription(locRule
, rChain
, status
);
142 if (U_SUCCESS(status
)) {
143 newObj
->addRules(rChain
);
146 if (U_FAILURE(status
)||(locRule
.length() == 0)) {
147 // use default plural rule
148 status
= U_ZERO_ERROR
;
149 UnicodeString defRule
= UnicodeString(PLURAL_DEFAULT_RULE
);
150 newObj
->parseDescription(defRule
, rChain
, status
);
151 newObj
->addRules(rChain
);
158 PluralRules::select(int32_t number
) const {
159 if (mRules
== NULL
) {
160 return PLURAL_DEFAULT_RULE
;
163 return mRules
->select(number
);
168 PluralRules::select(double number
) const {
169 if (mRules
== NULL
) {
170 return PLURAL_DEFAULT_RULE
;
173 return mRules
->select(number
);
178 PluralRules::getKeywords(UErrorCode
& status
) const {
179 if (U_FAILURE(status
)) return NULL
;
180 StringEnumeration
* nameEnumerator
= new PluralKeywordEnumeration(mRules
, status
);
181 return nameEnumerator
;
186 PluralRules::isKeyword(const UnicodeString
& keyword
) const {
187 if ( keyword
== PLURAL_KEYWORD_OTHER
) {
195 return mRules
->isKeyword(keyword
);
201 PluralRules::getKeywordOther() const {
202 return PLURAL_KEYWORD_OTHER
;
206 PluralRules::operator==(const PluralRules
& other
) const {
208 UBool sameList
= TRUE
;
209 const UnicodeString
*ptrKeyword
;
210 UErrorCode status
= U_ZERO_ERROR
;
212 if ( this == &other
) {
215 StringEnumeration
* myKeywordList
= getKeywords(status
);
216 StringEnumeration
* otherKeywordList
=other
.getKeywords(status
);
218 if (myKeywordList
->count(status
)!=otherKeywordList
->count(status
)) {
222 myKeywordList
->reset(status
);
223 while (sameList
&& (ptrKeyword
=myKeywordList
->snext(status
))!=NULL
) {
224 if (!other
.isKeyword(*ptrKeyword
)) {
228 otherKeywordList
->reset(status
);
229 while (sameList
&& (ptrKeyword
=otherKeywordList
->snext(status
))!=NULL
) {
230 if (!this->isKeyword(*ptrKeyword
)) {
234 delete myKeywordList
;
235 delete otherKeywordList
;
241 if ((limit
=this->getRepeatLimit()) != other
.getRepeatLimit()) {
244 UnicodeString myKeyword
, otherKeyword
;
245 for (int32_t i
=0; i
<limit
; ++i
) {
246 myKeyword
= this->select(i
);
247 otherKeyword
= other
.select(i
);
248 if (myKeyword
!=otherKeyword
) {
256 PluralRules::parseDescription(UnicodeString
& data
, RuleChain
& rules
, UErrorCode
&status
)
261 tokenType prevType
=none
;
262 RuleChain
*ruleChain
=NULL
;
263 AndConstraint
*curAndConstraint
=NULL
;
264 OrConstraint
*orNode
=NULL
;
265 RuleChain
*lastChain
=NULL
;
267 UnicodeString ruleData
= data
.toLower();
268 while (ruleIndex
< ruleData
.length()) {
269 mParser
->getNextToken(ruleData
, &ruleIndex
, token
, type
, status
);
270 if (U_FAILURE(status
)) {
273 mParser
->checkSyntax(prevType
, type
, status
);
274 if (U_FAILURE(status
)) {
279 curAndConstraint
= curAndConstraint
->add();
283 while (lastChain
->next
!=NULL
) {
284 lastChain
= lastChain
->next
;
286 orNode
=lastChain
->ruleHeader
;
287 while (orNode
->next
!= NULL
) {
288 orNode
= orNode
->next
;
290 orNode
->next
= new OrConstraint();
293 curAndConstraint
= orNode
->add();
296 curAndConstraint
->rangeHigh
=-1;
299 curAndConstraint
->notIn
=TRUE
;
302 curAndConstraint
->rangeHigh
=PLURAL_RANGE_HIGH
;
303 curAndConstraint
->integerOnly
= TRUE
;
306 curAndConstraint
->rangeHigh
=PLURAL_RANGE_HIGH
;
309 if ( (curAndConstraint
->op
==AndConstraint::MOD
)&&
310 (curAndConstraint
->opNum
== -1 ) ) {
311 curAndConstraint
->opNum
=getNumberValue(token
);
314 if (curAndConstraint
->rangeLow
== -1) {
315 curAndConstraint
->rangeLow
=getNumberValue(token
);
318 curAndConstraint
->rangeHigh
=getNumberValue(token
);
323 curAndConstraint
->op
=AndConstraint::MOD
;
326 if (ruleChain
==NULL
) {
330 while (ruleChain
->next
!=NULL
){
331 ruleChain
=ruleChain
->next
;
333 ruleChain
=ruleChain
->next
=new RuleChain();
335 orNode
= ruleChain
->ruleHeader
= new OrConstraint();
336 curAndConstraint
= orNode
->add();
337 ruleChain
->keyword
= token
;
347 PluralRules::getNumberValue(const UnicodeString
& token
) const {
351 i
= token
.extract(0, token
.length(), digits
, ARRAY_SIZE(digits
), US_INV
);
354 return((int32_t)atoi(digits
));
359 PluralRules::getNextLocale(const UnicodeString
& localeData
, int32_t* curIndex
, UnicodeString
& localeName
) {
363 while (i
< localeData
.length()) {
364 if ( (localeData
.charAt(i
)!= SPACE
) && (localeData
.charAt(i
)!= COMMA
) ) {
370 while (i
< localeData
.length()) {
371 if ( (localeData
.charAt(i
)== SPACE
) || (localeData
.charAt(i
)== COMMA
) ) {
374 localeName
+=localeData
.charAt(i
++);
381 PluralRules::getRepeatLimit() const {
383 return mRules
->getRepeatLimit();
392 PluralRules::addRules(RuleChain
& rules
) {
393 RuleChain
*newRule
= new RuleChain(rules
);
394 this->mRules
=newRule
;
395 newRule
->setRepeatLimit();
399 PluralRules::getRuleFromResource(const Locale
& locale
, UErrorCode
& errCode
) {
400 UnicodeString emptyStr
;
402 errCode
= U_ZERO_ERROR
;
403 UResourceBundle
*rb
=ures_openDirect(NULL
, "plurals", &errCode
);
404 if(U_FAILURE(errCode
)) {
405 /* total failure, not even root could be opened */
408 UResourceBundle
*locRes
=ures_getByKey(rb
, "locales", NULL
, &errCode
);
409 if(U_FAILURE(errCode
)) {
414 const char *curLocaleName
=locale
.getName();
415 const UChar
* s
= ures_getStringByKey(locRes
, curLocaleName
, &resLen
, &errCode
);
418 // Check parent locales.
419 UErrorCode status
= U_ZERO_ERROR
;
420 char parentLocaleName
[ULOC_FULLNAME_CAPACITY
];
421 const char *curLocaleName
=locale
.getName();
422 int32_t localeNameLen
=0;
423 uprv_strcpy(parentLocaleName
, curLocaleName
);
425 while ((localeNameLen
=uloc_getParent(parentLocaleName
, parentLocaleName
,
426 ULOC_FULLNAME_CAPACITY
, &status
)) > 0) {
428 s
= ures_getStringByKey(locRes
, parentLocaleName
, &resLen
, &status
);
430 errCode
= U_ZERO_ERROR
;
433 status
= U_ZERO_ERROR
;
444 u_UCharsToChars(s
, setKey
, resLen
+ 1);
445 // printf("\n PluralRule: %s\n", setKey);
448 UResourceBundle
*ruleRes
=ures_getByKey(rb
, "rules", NULL
, &errCode
);
449 if(U_FAILURE(errCode
)) {
455 UResourceBundle
*setRes
= ures_getByKey(ruleRes
, setKey
, NULL
, &errCode
);
456 if (U_FAILURE(errCode
)) {
463 int32_t numberKeys
= ures_getSize(setRes
);
466 for(int32_t i
=0; i
<numberKeys
; ++i
) {
469 s
=ures_getNextString(setRes
, &resLen
, (const char**)&key
, &errCode
);
470 keyLen
= uprv_strlen(key
);
471 u_charsToUChars(key
, result
+len
, keyLen
);
474 uprv_memcpy(result
+len
, s
, resLen
*sizeof(UChar
));
476 result
[len
++]=SEMI_COLON
;
479 u_UCharsToChars(result
, setKey
, len
);
480 // printf(" Rule: %s\n", setKey);
486 return UnicodeString(result
);
490 AndConstraint::AndConstraint() {
491 op
= AndConstraint::NONE
;
501 AndConstraint::AndConstraint(const AndConstraint
& other
) {
503 this->opNum
=other
.opNum
;
504 this->rangeLow
=other
.rangeLow
;
505 this->rangeHigh
=other
.rangeHigh
;
506 this->integerOnly
=other
.integerOnly
;
507 this->notIn
=other
.notIn
;
508 if (other
.next
==NULL
) {
512 this->next
= new AndConstraint(*other
.next
);
516 AndConstraint::~AndConstraint() {
524 AndConstraint::isFulfilled(double number
) {
529 value
= (int32_t)value
% opNum
;
531 if ( rangeHigh
== -1 ) {
532 if ( rangeLow
== -1 ) {
533 result
= TRUE
; // empty rule
536 if ( value
== rangeLow
) {
545 if ((rangeLow
<= value
) && (value
<= rangeHigh
)) {
547 if ( value
!= (int32_t)value
) {
571 AndConstraint::updateRepeatLimit(int32_t maxLimit
) {
574 return uprv_max(opNum
, maxLimit
);
577 if ( rangeHigh
== -1 ) {
578 return(rangeLow
>maxLimit
? rangeLow
: maxLimit
);
579 return uprv_max(rangeLow
, maxLimit
);
582 return uprv_max(rangeHigh
, maxLimit
);
591 this->next
= new AndConstraint();
595 OrConstraint::OrConstraint() {
600 OrConstraint::OrConstraint(const OrConstraint
& other
) {
601 if ( other
.childNode
== NULL
) {
602 this->childNode
= NULL
;
605 this->childNode
= new AndConstraint(*(other
.childNode
));
607 if (other
.next
== NULL
) {
611 this->next
= new OrConstraint(*(other
.next
));
615 OrConstraint::~OrConstraint() {
616 if (childNode
!=NULL
) {
627 OrConstraint
*curOrConstraint
=this;
629 while (curOrConstraint
->next
!=NULL
) {
630 curOrConstraint
= curOrConstraint
->next
;
632 curOrConstraint
->next
= NULL
;
633 curOrConstraint
->childNode
= new AndConstraint();
635 return curOrConstraint
->childNode
;
639 OrConstraint::isFulfilled(double number
) {
640 OrConstraint
* orRule
=this;
643 while (orRule
!=NULL
&& !result
) {
645 AndConstraint
* andRule
= orRule
->childNode
;
646 while (andRule
!=NULL
&& result
) {
647 result
= andRule
->isFulfilled(number
);
648 andRule
=andRule
->next
;
650 orRule
= orRule
->next
;
657 RuleChain::RuleChain() {
663 RuleChain::RuleChain(const RuleChain
& other
) {
664 this->repeatLimit
= other
.repeatLimit
;
665 this->keyword
=other
.keyword
;
666 if (other
.ruleHeader
!= NULL
) {
667 this->ruleHeader
= new OrConstraint(*(other
.ruleHeader
));
670 this->ruleHeader
= NULL
;
672 if (other
.next
!= NULL
) {
673 this->next
= new RuleChain(*other
.next
);
681 RuleChain::~RuleChain() {
685 if ( ruleHeader
!= NULL
) {
691 RuleChain::select(double number
) const {
693 if ( ruleHeader
!= NULL
) {
694 if (ruleHeader
->isFulfilled(number
)) {
698 if ( next
!= NULL
) {
699 return next
->select(number
);
702 return PLURAL_KEYWORD_OTHER
;
708 RuleChain::dumpRules(UnicodeString
& result
) {
709 UChar digitString
[16];
711 if ( ruleHeader
!= NULL
) {
713 OrConstraint
* orRule
=ruleHeader
;
714 while ( orRule
!= NULL
) {
715 AndConstraint
* andRule
=orRule
->childNode
;
716 while ( andRule
!= NULL
) {
717 if ( (andRule
->op
==AndConstraint::NONE
) && (andRule
->rangeHigh
==-1) ) {
718 result
+= UNICODE_STRING_SIMPLE(" n is ");
719 if (andRule
->notIn
) {
720 result
+= UNICODE_STRING_SIMPLE("not ");
722 uprv_itou(digitString
,16, andRule
->rangeLow
,10,0);
723 result
+= UnicodeString(digitString
);
726 if (andRule
->op
==AndConstraint::MOD
) {
727 result
+= UNICODE_STRING_SIMPLE(" n mod ");
728 uprv_itou(digitString
,16, andRule
->opNum
,10,0);
729 result
+= UnicodeString(digitString
);
732 result
+= UNICODE_STRING_SIMPLE(" n ");
734 if (andRule
->rangeHigh
==-1) {
735 if (andRule
->notIn
) {
736 result
+= UNICODE_STRING_SIMPLE(" is not ");
737 uprv_itou(digitString
,16, andRule
->rangeLow
,10,0);
738 result
+= UnicodeString(digitString
);
741 result
+= UNICODE_STRING_SIMPLE(" is ");
742 uprv_itou(digitString
,16, andRule
->rangeLow
,10,0);
743 result
+= UnicodeString(digitString
);
747 if (andRule
->notIn
) {
748 if ( andRule
->integerOnly
) {
749 result
+= UNICODE_STRING_SIMPLE(" not in ");
752 result
+= UNICODE_STRING_SIMPLE(" not within ");
754 uprv_itou(digitString
,16, andRule
->rangeLow
,10,0);
755 result
+= UnicodeString(digitString
);
756 result
+= UNICODE_STRING_SIMPLE(" .. ");
757 uprv_itou(digitString
,16, andRule
->rangeHigh
,10,0);
758 result
+= UnicodeString(digitString
);
761 if ( andRule
->integerOnly
) {
762 result
+= UNICODE_STRING_SIMPLE(" in ");
765 result
+= UNICODE_STRING_SIMPLE(" within ");
767 uprv_itou(digitString
,16, andRule
->rangeLow
,10,0);
768 result
+= UnicodeString(digitString
);
769 result
+= UNICODE_STRING_SIMPLE(" .. ");
770 uprv_itou(digitString
,16, andRule
->rangeHigh
,10,0);
774 if ( (andRule
=andRule
->next
) != NULL
) {
778 if ( (orRule
= orRule
->next
) != NULL
) {
783 if ( next
!= NULL
) {
784 next
->dumpRules(result
);
789 RuleChain::getRepeatLimit () {
794 RuleChain::setRepeatLimit () {
797 if ( next
!= NULL
) {
798 next
->setRepeatLimit();
799 limit
= next
->repeatLimit
;
802 if ( ruleHeader
!= NULL
) {
803 OrConstraint
* orRule
=ruleHeader
;
804 while ( orRule
!= NULL
) {
805 AndConstraint
* andRule
=orRule
->childNode
;
806 while ( andRule
!= NULL
) {
807 limit
= andRule
->updateRepeatLimit(limit
);
808 andRule
= andRule
->next
;
810 orRule
= orRule
->next
;
817 RuleChain::getKeywords(int32_t capacityOfKeywords
, UnicodeString
* keywords
, int32_t& arraySize
) const {
818 if ( arraySize
< capacityOfKeywords
-1 ) {
819 keywords
[arraySize
++]=keyword
;
822 return U_BUFFER_OVERFLOW_ERROR
;
825 if ( next
!= NULL
) {
826 return next
->getKeywords(capacityOfKeywords
, keywords
, arraySize
);
834 RuleChain::isKeyword(const UnicodeString
& keywordParam
) const {
835 if ( keyword
== keywordParam
) {
839 if ( next
!= NULL
) {
840 return next
->isKeyword(keywordParam
);
848 RuleParser::RuleParser() {
849 UErrorCode err
=U_ZERO_ERROR
;
850 const UnicodeString idStart
=UNICODE_STRING_SIMPLE("[[a-z]]");
851 const UnicodeString idContinue
=UNICODE_STRING_SIMPLE("[[a-z][A-Z][_][0-9]]");
852 idStartFilter
= new UnicodeSet(idStart
, err
);
853 idContinueFilter
= new UnicodeSet(idContinue
, err
);
856 RuleParser::~RuleParser() {
857 delete idStartFilter
;
858 delete idContinueFilter
;
862 RuleParser::checkSyntax(tokenType prevType
, tokenType curType
, UErrorCode
&status
)
864 if (U_FAILURE(status
)) {
870 if (curType
!=tKeyword
) {
871 status
= U_UNEXPECTED_TOKEN
;
875 if (curType
!= tIs
&& curType
!= tMod
&& curType
!= tIn
&&
876 curType
!= tNot
&& curType
!= tWithin
) {
877 status
= U_UNEXPECTED_TOKEN
;
887 if (curType
!= tColon
) {
888 status
= U_UNEXPECTED_TOKEN
;
892 if (curType
!= tVariableN
) {
893 status
= U_UNEXPECTED_TOKEN
;
897 if ( curType
!= tNumber
&& curType
!= tNot
) {
898 status
= U_UNEXPECTED_TOKEN
;
902 if (curType
!= tNumber
&& curType
!= tIn
&& curType
!= tWithin
) {
903 status
= U_UNEXPECTED_TOKEN
;
912 if (curType
!= tNumber
&& curType
!= tVariableN
) {
913 status
= U_UNEXPECTED_TOKEN
;
917 if (curType
!= tDot
&& curType
!= tSemiColon
&& curType
!= tIs
&& curType
!= tNot
&&
918 curType
!= tIn
&& curType
!= tWithin
&& curType
!= tAnd
&& curType
!= tOr
)
920 status
= U_UNEXPECTED_TOKEN
;
924 status
= U_UNEXPECTED_TOKEN
;
930 RuleParser::getNextToken(const UnicodeString
& ruleData
,
932 UnicodeString
& token
,
936 int32_t curIndex
= *ruleIndex
;
938 tokenType prevType
=none
;
940 while (curIndex
<ruleData
.length()) {
941 ch
= ruleData
.charAt(curIndex
);
942 if ( !inRange(ch
, type
) ) {
943 status
= U_ILLEGAL_CHARACTER
;
948 if ( *ruleIndex
!= curIndex
) { // letter
949 token
=UnicodeString(ruleData
, *ruleIndex
, curIndex
-*ruleIndex
);
952 getKeyType(token
, type
, status
);
956 *ruleIndex
=*ruleIndex
+1;
958 break; // consective space
961 if ( *ruleIndex
!= curIndex
) {
962 token
=UnicodeString(ruleData
, *ruleIndex
, curIndex
-*ruleIndex
);
965 getKeyType(token
, type
, status
);
969 *ruleIndex
=curIndex
+1;
973 if ((type
==prevType
)||(prevType
==none
)) {
979 if ((type
==prevType
)||(prevType
==none
)) {
984 *ruleIndex
=curIndex
+1;
988 if (prevType
==none
) { // first dot
993 if ( *ruleIndex
!= curIndex
) {
994 token
=UnicodeString(ruleData
, *ruleIndex
, curIndex
-*ruleIndex
);
995 *ruleIndex
=curIndex
; // letter
997 getKeyType(token
, type
, status
);
1000 else { // two consective dots
1001 *ruleIndex
=curIndex
+2;
1007 status
= U_UNEXPECTED_TOKEN
;
1012 if ( curIndex
>=ruleData
.length() ) {
1013 if ( (type
== tLetter
)||(type
== tNumber
) ) {
1014 token
=UnicodeString(ruleData
, *ruleIndex
, curIndex
-*ruleIndex
);
1015 getKeyType(token
, type
, status
);
1017 *ruleIndex
= ruleData
.length();
1022 RuleParser::inRange(UChar ch
, tokenType
& type
) {
1023 if ((ch
>=CAP_A
) && (ch
<=CAP_Z
)) {
1024 // we assume all characters are in lower case already.
1027 if ((ch
>=LOW_A
) && (ch
<=LOW_Z
)) {
1031 if ((ch
>=U_ZERO
) && (ch
<=U_NINE
)) {
1056 RuleParser::getKeyType(const UnicodeString
& token
, tokenType
& keyType
, UErrorCode
&status
)
1058 if ( keyType
==tNumber
) {
1060 else if (token
==PK_VAR_N
) {
1061 keyType
= tVariableN
;
1063 else if (token
==PK_IS
) {
1066 else if (token
==PK_AND
) {
1069 else if (token
==PK_IN
) {
1072 else if (token
==PK_WITHIN
) {
1075 else if (token
==PK_NOT
) {
1078 else if (token
==PK_MOD
) {
1081 else if (token
==PK_OR
) {
1084 else if ( isValidKeyword(token
) ) {
1088 status
= U_UNEXPECTED_TOKEN
;
1093 RuleParser::isValidKeyword(const UnicodeString
& token
) {
1094 if ( token
.length()==0 ) {
1097 if ( idStartFilter
->contains(token
.charAt(0) )==TRUE
) {
1099 for (i
=1; i
< token
.length(); i
++) {
1100 if (idContinueFilter
->contains(token
.charAt(i
))== FALSE
) {
1111 PluralKeywordEnumeration::PluralKeywordEnumeration(RuleChain
*header
, UErrorCode
& status
) :
1112 fKeywordNames(status
)
1114 RuleChain
*node
=header
;
1115 UBool addKeywordOther
=true;
1118 fKeywordNames
.removeAllElements();
1120 fKeywordNames
.addElement(new UnicodeString(node
->keyword
), status
);
1121 if (node
->keyword
== PLURAL_KEYWORD_OTHER
) {
1122 addKeywordOther
= false;
1127 if (addKeywordOther
) {
1128 fKeywordNames
.addElement(new UnicodeString(PLURAL_KEYWORD_OTHER
), status
);
1132 const UnicodeString
*
1133 PluralKeywordEnumeration::snext(UErrorCode
& status
) {
1134 if (U_SUCCESS(status
) && pos
< fKeywordNames
.size()) {
1135 return (const UnicodeString
*)fKeywordNames
.elementAt(pos
++);
1141 PluralKeywordEnumeration::reset(UErrorCode
& /*status*/) {
1146 PluralKeywordEnumeration::count(UErrorCode
& /*status*/) const {
1147 return fKeywordNames
.size();
1150 PluralKeywordEnumeration::~PluralKeywordEnumeration() {
1152 for (int32_t i
=0; i
<fKeywordNames
.size(); ++i
) {
1153 if ((s
=(UnicodeString
*)fKeywordNames
.elementAt(i
))!=NULL
) {
1162 #endif /* #if !UCONFIG_NO_FORMATTING */