1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3 //
4 //  file:  rbbistbl.cpp    Implementation of the ICU RBBISymbolTable class
5 //
6 /*
7 ***************************************************************************
8 *   Copyright (C) 2002-2014 International Business Machines Corporation
9 *   and others. All rights reserved.
10 ***************************************************************************
11 */
12 
13 #include "unicode/utypes.h"
14 
15 #if !UCONFIG_NO_BREAK_ITERATION
16 
17 #include "unicode/unistr.h"
18 #include "unicode/uniset.h"
19 #include "unicode/uchar.h"
20 #include "unicode/parsepos.h"
21 
22 #include "cstr.h"
23 #include "rbbinode.h"
24 #include "rbbirb.h"
25 #include "umutex.h"
26 
27 
28 //
29 //  RBBISymbolTableEntry_deleter    Used by the UHashTable to delete the contents
30 //                                  when the hash table is deleted.
31 //
32 U_CDECL_BEGIN
RBBISymbolTableEntry_deleter(void * p)33 static void U_CALLCONV RBBISymbolTableEntry_deleter(void *p) {
34     icu::RBBISymbolTableEntry *px = (icu::RBBISymbolTableEntry *)p;
35     delete px;
36 }
37 U_CDECL_END
38 
39 
40 
41 U_NAMESPACE_BEGIN
42 
RBBISymbolTable(RBBIRuleScanner * rs,const UnicodeString & rules,UErrorCode & status)43 RBBISymbolTable::RBBISymbolTable(RBBIRuleScanner *rs, const UnicodeString &rules, UErrorCode &status)
44     :fRules(rules), fRuleScanner(rs), ffffString(UChar(0xffff))
45 {
46     fHashTable       = NULL;
47     fCachedSetLookup = NULL;
48 
49     fHashTable = uhash_open(uhash_hashUnicodeString, uhash_compareUnicodeString, NULL, &status);
50     // uhash_open checks status
51     if (U_FAILURE(status)) {
52         return;
53     }
54     uhash_setValueDeleter(fHashTable, RBBISymbolTableEntry_deleter);
55 }
56 
57 
58 
~RBBISymbolTable()59 RBBISymbolTable::~RBBISymbolTable()
60 {
61     uhash_close(fHashTable);
62 }
63 
64 
65 //
66 //  RBBISymbolTable::lookup       This function from the abstract symbol table inteface
67 //                                looks up a variable name and returns a UnicodeString
68 //                                containing the substitution text.
69 //
70 //                                The variable name does NOT include the leading $.
71 //
lookup(const UnicodeString & s) const72 const UnicodeString  *RBBISymbolTable::lookup(const UnicodeString& s) const
73 {
74     RBBISymbolTableEntry  *el;
75     RBBINode              *varRefNode;
76     RBBINode              *exprNode;
77     RBBINode              *usetNode;
78     const UnicodeString   *retString;
79     RBBISymbolTable       *This = (RBBISymbolTable *)this;   // cast off const
80 
81     el = (RBBISymbolTableEntry *)uhash_get(fHashTable, &s);
82     if (el == NULL) {
83         return NULL;
84     }
85 
86     varRefNode = el->val;
87     exprNode   = varRefNode->fLeftChild;     // Root node of expression for variable
88     if (exprNode->fType == RBBINode::setRef) {
89         // The $variable refers to a single UnicodeSet
90         //   return the ffffString, which will subsequently be interpreted as a
91         //   stand-in character for the set by RBBISymbolTable::lookupMatcher()
92         usetNode = exprNode->fLeftChild;
93         This->fCachedSetLookup = usetNode->fInputSet;
94         retString = &ffffString;
95     }
96     else
97     {
98         // The variable refers to something other than just a set.
99         // return the original source string for the expression
100         retString = &exprNode->fText;
101         This->fCachedSetLookup = NULL;
102     }
103     return retString;
104 }
105 
106 
107 
108 //
109 //  RBBISymbolTable::lookupMatcher   This function from the abstract symbol table
110 //                                   interface maps a single stand-in character to a
111 //                                   pointer to a Unicode Set.   The Unicode Set code uses this
112 //                                   mechanism to get all references to the same $variable
113 //                                   name to refer to a single common Unicode Set instance.
114 //
115 //    This implementation cheats a little, and does not maintain a map of stand-in chars
116 //    to sets.  Instead, it takes advantage of the fact that  the UnicodeSet
117 //    constructor will always call this function right after calling lookup(),
118 //    and we just need to remember what set to return between these two calls.
lookupMatcher(UChar32 ch) const119 const UnicodeFunctor *RBBISymbolTable::lookupMatcher(UChar32 ch) const
120 {
121     UnicodeSet *retVal = NULL;
122     RBBISymbolTable *This = (RBBISymbolTable *)this;   // cast off const
123     if (ch == 0xffff) {
124         retVal = fCachedSetLookup;
125         This->fCachedSetLookup = 0;
126     }
127     return retVal;
128 }
129 
130 //
131 // RBBISymbolTable::parseReference   This function from the abstract symbol table interface
132 //                                   looks for a $variable name in the source text.
133 //                                   It does not look it up, only scans for it.
134 //                                   It is used by the UnicodeSet parser.
135 //
136 //                                   This implementation is lifted pretty much verbatim
137 //                                   from the rules based transliterator implementation.
138 //                                   I didn't see an obvious way of sharing it.
139 //
parseReference(const UnicodeString & text,ParsePosition & pos,int32_t limit) const140 UnicodeString   RBBISymbolTable::parseReference(const UnicodeString& text,
141                                                 ParsePosition& pos, int32_t limit) const
142 {
143     int32_t start = pos.getIndex();
144     int32_t i = start;
145     UnicodeString result;
146     while (i < limit) {
147         UChar c = text.charAt(i);
148         if ((i==start && !u_isIDStart(c)) || !u_isIDPart(c)) {
149             break;
150         }
151         ++i;
152     }
153     if (i == start) { // No valid name chars
154         return result; // Indicate failure with empty string
155     }
156     pos.setIndex(i);
157     text.extractBetween(start, i, result);
158     return result;
159 }
160 
161 
162 
163 //
164 // RBBISymbolTable::lookupNode      Given a key (a variable name), return the
165 //                                  corresponding RBBI Node.  If there is no entry
166 //                                  in the table for this name, return NULL.
167 //
lookupNode(const UnicodeString & key) const168 RBBINode       *RBBISymbolTable::lookupNode(const UnicodeString &key) const{
169 
170     RBBINode             *retNode = NULL;
171     RBBISymbolTableEntry *el;
172 
173     el = (RBBISymbolTableEntry *)uhash_get(fHashTable, &key);
174     if (el != NULL) {
175         retNode = el->val;
176     }
177     return retNode;
178 }
179 
180 
181 //
182 //    RBBISymbolTable::addEntry     Add a new entry to the symbol table.
183 //                                  Indicate an error if the name already exists -
184 //                                    this will only occur in the case of duplicate
185 //                                    variable assignments.
186 //
addEntry(const UnicodeString & key,RBBINode * val,UErrorCode & err)187 void            RBBISymbolTable::addEntry  (const UnicodeString &key, RBBINode *val, UErrorCode &err) {
188     RBBISymbolTableEntry *e;
189     /* test for buffer overflows */
190     if (U_FAILURE(err)) {
191         return;
192     }
193     e = (RBBISymbolTableEntry *)uhash_get(fHashTable, &key);
194     if (e != NULL) {
195         err = U_BRK_VARIABLE_REDFINITION;
196         return;
197     }
198 
199     e = new RBBISymbolTableEntry;
200     if (e == NULL) {
201         err = U_MEMORY_ALLOCATION_ERROR;
202         return;
203     }
204     e->key = key;
205     e->val = val;
206     uhash_put( fHashTable, &e->key, e, &err);
207 }
208 
209 
RBBISymbolTableEntry()210 RBBISymbolTableEntry::RBBISymbolTableEntry() : UMemory(), key(), val(NULL) {}
211 
~RBBISymbolTableEntry()212 RBBISymbolTableEntry::~RBBISymbolTableEntry() {
213     // The "val" of a symbol table entry is a variable reference node.
214     // The l. child of the val is the rhs expression from the assignment.
215     // Unlike other node types, children of variable reference nodes are not
216     //    automatically recursively deleted.  We do it manually here.
217     delete val->fLeftChild;
218     val->fLeftChild = NULL;
219 
220     delete  val;
221 
222     // Note: the key UnicodeString is destructed by virtue of being in the object by value.
223 }
224 
225 
226 //
227 //  RBBISymbolTable::print    Debugging function, dump out the symbol table contents.
228 //
229 #ifdef RBBI_DEBUG
rbbiSymtablePrint() const230 void RBBISymbolTable::rbbiSymtablePrint() const {
231     RBBIDebugPrintf("Variable Definitions Symbol Table\n"
232            "Name                  Node         serial  String Val\n"
233            "-------------------------------------------------------------------\n");
234 
235     int32_t pos = UHASH_FIRST;
236     const UHashElement  *e   = NULL;
237     for (;;) {
238         e = uhash_nextElement(fHashTable,  &pos);
239         if (e == NULL ) {
240             break;
241         }
242         RBBISymbolTableEntry  *s   = (RBBISymbolTableEntry *)e->value.pointer;
243 
244         RBBIDebugPrintf("%-19s   %8p %7d ", CStr(s->key)(), (void *)s->val, s->val->fSerialNum);
245         RBBIDebugPrintf(" %s\n", CStr(s->val->fLeftChild->fText)());
246     }
247 
248     RBBIDebugPrintf("\nParsed Variable Definitions\n");
249     pos = -1;
250     for (;;) {
251         e = uhash_nextElement(fHashTable,  &pos);
252         if (e == NULL ) {
253             break;
254         }
255         RBBISymbolTableEntry  *s   = (RBBISymbolTableEntry *)e->value.pointer;
256         RBBIDebugPrintf("%s\n", CStr(s->key)());
257         RBBINode::printTree(s->val, TRUE);
258         RBBINode::printTree(s->val->fLeftChild, FALSE);
259         RBBIDebugPrintf("\n");
260     }
261 }
262 #endif
263 
264 
265 
266 
267 
268 U_NAMESPACE_END
269 
270 #endif /* #if !UCONFIG_NO_BREAK_ITERATION */
271