]> gitweb.fperrin.net Git - Dictionary.git/blob - jars/icu4j-4_2_1-src/src/com/ibm/icu/text/RBBIRuleBuilder.java
icu4jsrc
[Dictionary.git] / jars / icu4j-4_2_1-src / src / com / ibm / icu / text / RBBIRuleBuilder.java
1 //\r
2 //    Copyright (C) 2002-2007, International Business Machines Corporation and others.\r
3 //    All Rights Reserved.\r
4 //\r
5 //\r
6 \r
7 package com.ibm.icu.text;\r
8 import java.util.HashMap;\r
9 import java.util.List;\r
10 import java.util.ArrayList;\r
11 import java.util.Map;\r
12 import java.io.OutputStream;\r
13 import java.io.DataOutputStream;\r
14 import java.io.IOException;\r
15 import com.ibm.icu.impl.Assert;\r
16 import com.ibm.icu.impl.ICUDebug;\r
17 \r
18 class RBBIRuleBuilder {\r
19     //   This is the main class for building (compiling) break rules into the tables\r
20     //    required by the runtime RBBI engine.\r
21     //\r
22     \r
23     String fDebugEnv;              // controls debug trace output\r
24     String fRules;                 // The rule string that we are compiling\r
25     RBBIRuleScanner fScanner;      // The scanner.\r
26 \r
27     \r
28     //\r
29     //  There are four separate parse trees generated, one for each of the\r
30     //    forward rules, reverse rules, safe forward rules and safe reverse rules.\r
31     //  This array references the root of each of the trees.\r
32     //  \r
33     RBBINode[]         fTreeRoots = new RBBINode[4];\r
34     static final int   fForwardTree = 0;  // Indexes into the above fTreeRoots array\r
35     static final int   fReverseTree = 1;  //   for each of the trees.\r
36     static final int   fSafeFwdTree = 2;  //   (in C, these are pointer variables and\r
37     static final int   fSafeRevTree = 3;  //    there is no array.)\r
38     int fDefaultTree = fForwardTree;      // For rules not qualified with a !\r
39                                           //   the tree to which they belong to.\r
40 \r
41     boolean fChainRules;                  // True for chained Unicode TR style rules.\r
42                                           // False for traditional regexp rules.\r
43 \r
44     boolean fLBCMNoChain;                 // True:  suppress chaining of rules on\r
45                                           //   chars with LineBreak property == CM.\r
46 \r
47     boolean fLookAheadHardBreak;          // True:  Look ahead matches cause an\r
48                                           // immediate break, no continuing for the\r
49                                           // longest match.\r
50 \r
51     RBBISetBuilder fSetBuilder;           // Set and Character Category builder.\r
52     List fUSetNodes;                      // Vector of all uset nodes.\r
53     RBBITableBuilder fForwardTables;      // State transition tables\r
54     RBBITableBuilder fReverseTables;\r
55     RBBITableBuilder fSafeFwdTables;\r
56     RBBITableBuilder fSafeRevTables;\r
57 \r
58     //\r
59     // Status {tag} values.   These structures are common to all of the rule sets (Forward, Reverse, etc.).\r
60     //\r
61     Map fStatusSets = new HashMap();      // Status value sets encountered so far.\r
62                                           //  Map Key is the set of values.\r
63                                           //  Map Value is the runtime array index.\r
64 \r
65     List fRuleStatusVals;                 // List of Integer objects.  Has same layout as the\r
66                                           //   runtime array of status (tag) values - \r
67                                           //     number of values in group 1\r
68                                           //        first status value in group 1\r
69                                           //        2nd status value in group 1\r
70                                           //        ...\r
71                                           //     number of values in group 2\r
72                                           //        first status value in group 2\r
73                                           //        etc.\r
74                                           //\r
75     // Error codes from ICU4C.\r
76     //    using these simplified the porting, and consolidated the\r
77     //    creation of Java exceptions\r
78     //\r
79     static final int U_BRK_ERROR_START = 0x10200;\r
80     /**< Start of codes indicating Break Iterator failures */\r
81     \r
82     static final int U_BRK_INTERNAL_ERROR = 0x10201;\r
83     /**< An internal error (bug) was detected.             */\r
84     \r
85     static final int U_BRK_HEX_DIGITS_EXPECTED = 0x10202;\r
86     /**< Hex digits expected as part of a escaped char in a rule. */\r
87     \r
88     static final int U_BRK_SEMICOLON_EXPECTED = 0x10203;\r
89     /**< Missing ';' at the end of a RBBI rule.            */\r
90     \r
91     static final int U_BRK_RULE_SYNTAX = 0x10204;\r
92     /**< Syntax error in RBBI rule.                        */\r
93     \r
94     static final int U_BRK_UNCLOSED_SET = 0x10205;\r
95     /**< UnicodeSet witing an RBBI rule missing a closing ']'.  */\r
96     \r
97     static final int U_BRK_ASSIGN_ERROR = 0x10206;\r
98     /**< Syntax error in RBBI rule assignment statement.   */\r
99     \r
100     static final int U_BRK_VARIABLE_REDFINITION = 0x10207;\r
101     /**< RBBI rule $Variable redefined.                    */\r
102     \r
103     static final int U_BRK_MISMATCHED_PAREN = 0x10208;\r
104     /**< Mis-matched parentheses in an RBBI rule.          */\r
105     \r
106     static final int U_BRK_NEW_LINE_IN_QUOTED_STRING = 0x10209;\r
107     /**< Missing closing quote in an RBBI rule.            */\r
108     \r
109     static final int U_BRK_UNDEFINED_VARIABLE = 0x1020a;\r
110     /**< Use of an undefined $Variable in an RBBI rule.    */\r
111     \r
112     static final int U_BRK_INIT_ERROR = 0x1020b;\r
113     /**< Initialization failure.  Probable missing ICU Data. */\r
114     \r
115     static final int U_BRK_RULE_EMPTY_SET = 0x1020c;\r
116     /**< Rule contains an empty Unicode Set.               */\r
117     \r
118     static final int U_BRK_UNRECOGNIZED_OPTION = 0x1020d;\r
119     /**< !!option in RBBI rules not recognized.            */\r
120     \r
121     static final int U_BRK_MALFORMED_RULE_TAG = 0x1020e;\r
122     /**< The {nnn} tag on a rule is mal formed             */\r
123     static final int U_BRK_MALFORMED_SET = 0x1020f;\r
124     \r
125     static final int U_BRK_ERROR_LIMIT = 0x10210;\r
126     /**< This must always be the last value to indicate the limit for Break Iterator failures */\r
127 \r
128 \r
129     //----------------------------------------------------------------------------------------\r
130     //\r
131     //  Constructor.\r
132     //\r
133     //----------------------------------------------------------------------------------------\r
134     RBBIRuleBuilder(String rules)\r
135     {\r
136         fDebugEnv       = ICUDebug.enabled("rbbi") ?\r
137                             ICUDebug.value("rbbi") : null;\r
138         fRules          = rules;\r
139         fUSetNodes      = new ArrayList();\r
140         fRuleStatusVals = new ArrayList();\r
141         fScanner        = new RBBIRuleScanner(this);\r
142         fSetBuilder     = new RBBISetBuilder(this);\r
143     }\r
144 \r
145     //----------------------------------------------------------------------------------------\r
146     //\r
147     //   flattenData() -  Collect up the compiled RBBI rule data and put it into\r
148     //                    the format for saving in ICU data files,\r
149     //\r
150     //                    See the ICU4C file common/rbidata.h for a detailed description.\r
151     //\r
152     //----------------------------------------------------------------------------------------\r
153     static final int align8(int i)\r
154     {\r
155         return (i + 7) & 0xfffffff8;\r
156     }\r
157 \r
158     void flattenData(OutputStream os) throws IOException {\r
159         DataOutputStream dos = new DataOutputStream(os);\r
160         int i;\r
161 \r
162         //  Remove comments and whitespace from the rules to make it smaller.\r
163         String strippedRules = RBBIRuleScanner.stripRules(fRules);\r
164 \r
165         // Calculate the size of each section in the data in bytes.\r
166         //   Sizes here are padded up to a multiple of 8 for better memory alignment.\r
167         //   Sections sizes actually stored in the header are for the actual data\r
168         //     without the padding.\r
169         //\r
170         int headerSize       = 24 * 4;     // align8(sizeof(RBBIDataHeader));\r
171         int forwardTableSize = align8(fForwardTables.getTableSize());\r
172         int reverseTableSize = align8(fReverseTables.getTableSize());\r
173         int safeFwdTableSize = align8(fSafeFwdTables.getTableSize());\r
174         int safeRevTableSize = align8(fSafeRevTables.getTableSize());\r
175         int trieSize         = align8(fSetBuilder.getTrieSize());\r
176         int statusTableSize  = align8(fRuleStatusVals.size() * 4);\r
177         int rulesSize        = align8((strippedRules.length()) * 2);\r
178         int totalSize        = headerSize + forwardTableSize + reverseTableSize\r
179                                 + safeFwdTableSize + safeRevTableSize\r
180                                 + statusTableSize + trieSize + rulesSize;\r
181         int outputPos = 0;               // Track stream position, starting from RBBIDataHeader.\r
182 \r
183         //\r
184         // Write out an ICU Data Header\r
185         //   TODO:  actually create a real header, rather than just a placeholder.\r
186         //           The empty placeholder is ok for compile-and-go from within ICU4J.\r
187         //           Replicating the ICU4C genbrk tool for building .brk resources would need a real header.\r
188         //\r
189         byte[] ICUDataHeader = new byte[0x80];\r
190         dos.write(ICUDataHeader);\r
191 \r
192         //\r
193         // Write out the RBBIDataHeader\r
194         //\r
195         int[] header = new int[RBBIDataWrapper.DH_SIZE];                 // sizeof struct RBBIDataHeader\r
196         header[RBBIDataWrapper.DH_MAGIC]         = 0xb1a0;\r
197         header[RBBIDataWrapper.DH_FORMATVERSION] = 0x03010000;           // uint8_t fFormatVersion[4];\r
198         header[RBBIDataWrapper.DH_LENGTH]        = totalSize;            // fLength, the total size of all rule sections.\r
199         header[RBBIDataWrapper.DH_CATCOUNT]      = fSetBuilder.getNumCharCategories(); // fCatCount.\r
200         header[RBBIDataWrapper.DH_FTABLE]        = headerSize;           // fFTable\r
201         header[RBBIDataWrapper.DH_FTABLELEN]     = forwardTableSize;     // fTableLen\r
202         header[RBBIDataWrapper.DH_RTABLE]        = header[RBBIDataWrapper.DH_FTABLE] + forwardTableSize; // fRTable\r
203         header[RBBIDataWrapper.DH_RTABLELEN]     = reverseTableSize;     // fRTableLen\r
204         header[RBBIDataWrapper.DH_SFTABLE]       = header[RBBIDataWrapper.DH_RTABLE]\r
205                                                      + reverseTableSize; // fSTable\r
206         header[RBBIDataWrapper.DH_SFTABLELEN]    = safeFwdTableSize;     // fSTableLen\r
207         header[RBBIDataWrapper.DH_SRTABLE]       = header[RBBIDataWrapper.DH_SFTABLE]\r
208                                                      + safeFwdTableSize; // fSRTable\r
209         header[RBBIDataWrapper.DH_SRTABLELEN]    = safeRevTableSize;     // fSRTableLen\r
210         header[RBBIDataWrapper.DH_TRIE]          = header[RBBIDataWrapper.DH_SRTABLE]\r
211                                                      + safeRevTableSize; // fTrie\r
212         header[RBBIDataWrapper.DH_TRIELEN]       = fSetBuilder.getTrieSize(); // fTrieLen\r
213         header[RBBIDataWrapper.DH_STATUSTABLE]   = header[RBBIDataWrapper.DH_TRIE]\r
214                                                      + header[RBBIDataWrapper.DH_TRIELEN];\r
215         header[RBBIDataWrapper.DH_STATUSTABLELEN] = statusTableSize; // fStatusTableLen\r
216         header[RBBIDataWrapper.DH_RULESOURCE]    = header[RBBIDataWrapper.DH_STATUSTABLE]\r
217                                                      + statusTableSize;\r
218         header[RBBIDataWrapper.DH_RULESOURCELEN] = strippedRules.length() * 2;\r
219         for (i = 0; i < header.length; i++) {\r
220             dos.writeInt(header[i]);\r
221             outputPos += 4;\r
222         }\r
223 \r
224         // Write out the actual state tables.\r
225         short[] tableData;\r
226         tableData = fForwardTables.exportTable();\r
227         Assert.assrt(outputPos == header[4]);\r
228         for (i = 0; i < tableData.length; i++) {\r
229             dos.writeShort(tableData[i]);\r
230             outputPos += 2;\r
231         }\r
232 \r
233         tableData = fReverseTables.exportTable();\r
234         Assert.assrt(outputPos == header[6]);\r
235         for (i = 0; i < tableData.length; i++) {\r
236             dos.writeShort(tableData[i]);\r
237             outputPos += 2;\r
238         }\r
239 \r
240         Assert.assrt(outputPos == header[8]);\r
241         tableData = fSafeFwdTables.exportTable();\r
242         for (i = 0; i < tableData.length; i++) {\r
243             dos.writeShort(tableData[i]);\r
244             outputPos += 2;\r
245         }\r
246 \r
247         Assert.assrt(outputPos == header[10]);\r
248         tableData = fSafeRevTables.exportTable();\r
249         for (i = 0; i < tableData.length; i++) {\r
250             dos.writeShort(tableData[i]);\r
251             outputPos += 2;\r
252         }\r
253 \r
254         // write out the Trie table\r
255         Assert.assrt(outputPos == header[12]);\r
256         fSetBuilder.serializeTrie(os);\r
257         outputPos += header[13];\r
258         while (outputPos % 8 != 0) { // pad to an 8 byte boundary\r
259             dos.write(0);\r
260             outputPos += 1;\r
261         }\r
262 \r
263         // Write out the status {tag} table.\r
264         Assert.assrt(outputPos == header[16]);\r
265         for (i = 0; i < fRuleStatusVals.size(); i++) {\r
266             Integer val = (Integer) fRuleStatusVals.get(i);\r
267             dos.writeInt(val.intValue());\r
268             outputPos += 4;\r
269         }\r
270 \r
271         while (outputPos % 8 != 0) { // pad to an 8 byte boundary\r
272             dos.write(0);\r
273             outputPos += 1;\r
274         }\r
275 \r
276         // Write out the stripped rules (rules with extra spaces removed\r
277         //   These go last in the data area, even though they are not last in the header.\r
278         Assert.assrt(outputPos == header[14]);\r
279         dos.writeChars(strippedRules);\r
280         outputPos += strippedRules.length() * 2;\r
281         while (outputPos % 8 != 0) { // pad to an 8 byte boundary\r
282             dos.write(0);\r
283             outputPos += 1;\r
284         }\r
285     }\r
286 \r
287     //----------------------------------------------------------------------------------------\r
288     //\r
289     //  compileRules          compile source rules, placing the compiled form into a output stream\r
290     //                        The compiled form is identical to that from ICU4C (Big Endian).\r
291     //\r
292     //----------------------------------------------------------------------------------------\r
293     static void compileRules(String rules, OutputStream os) throws IOException\r
294     {\r
295         //\r
296         // Read the input rules, generate a parse tree, symbol table,\r
297         // and list of all Unicode Sets referenced by the rules.\r
298         //\r
299         RBBIRuleBuilder builder = new RBBIRuleBuilder(rules);\r
300         builder.fScanner.parse();\r
301 \r
302         //\r
303         // UnicodeSet processing.\r
304         //    Munge the Unicode Sets to create a set of character categories.\r
305         //    Generate the mapping tables (TRIE) from input 32-bit characters to\r
306         //    the character categories.\r
307         //\r
308         builder.fSetBuilder.build();\r
309 \r
310         //\r
311         //   Generate the DFA state transition table.\r
312         //\r
313         builder.fForwardTables = new RBBITableBuilder(builder, fForwardTree);\r
314         builder.fReverseTables = new RBBITableBuilder(builder, fReverseTree);\r
315         builder.fSafeFwdTables = new RBBITableBuilder(builder, fSafeFwdTree);\r
316         builder.fSafeRevTables = new RBBITableBuilder(builder, fSafeRevTree);\r
317         builder.fForwardTables.build();\r
318         builder.fReverseTables.build();\r
319         builder.fSafeFwdTables.build();\r
320         builder.fSafeRevTables.build();\r
321         if (builder.fDebugEnv != null\r
322                 && builder.fDebugEnv.indexOf("states") >= 0) {\r
323             builder.fForwardTables.printRuleStatusTable();\r
324         }\r
325 \r
326         //\r
327         //   Package up the compiled data, writing it to an output stream\r
328         //      in the serialization format.  This is the same as the ICU4C runtime format.\r
329         //\r
330         builder.flattenData(os);\r
331     }\r
332 }\r