2017-01-20 00:20:31 +00:00
|
|
|
// © 2016 and later: Unicode, Inc. and others.
|
2016-06-15 18:58:17 +00:00
|
|
|
// License & terms of use: http://www.unicode.org/copyright.html
|
2002-06-25 17:23:07 +00:00
|
|
|
//
|
|
|
|
// file: rbbirb.cpp
|
|
|
|
//
|
2016-05-31 21:45:07 +00:00
|
|
|
// Copyright (C) 2002-2011, International Business Machines Corporation and others.
|
2002-06-25 17:23:07 +00:00
|
|
|
// All Rights Reserved.
|
|
|
|
//
|
|
|
|
// This file contains the RBBIRuleBuilder class implementation. This is the main class for
|
|
|
|
// building (compiling) break rules into the tables required by the runtime
|
|
|
|
// RBBI engine.
|
|
|
|
//
|
|
|
|
|
2002-09-20 01:54:48 +00:00
|
|
|
#include "unicode/utypes.h"
|
|
|
|
|
|
|
|
#if !UCONFIG_NO_BREAK_ITERATION
|
2002-06-25 17:23:07 +00:00
|
|
|
|
|
|
|
#include "unicode/brkiter.h"
|
|
|
|
#include "unicode/rbbi.h"
|
|
|
|
#include "unicode/ubrk.h"
|
|
|
|
#include "unicode/unistr.h"
|
|
|
|
#include "unicode/uniset.h"
|
|
|
|
#include "unicode/uchar.h"
|
|
|
|
#include "unicode/uchriter.h"
|
|
|
|
#include "unicode/parsepos.h"
|
|
|
|
#include "unicode/parseerr.h"
|
2017-09-19 18:17:22 +00:00
|
|
|
|
2002-06-25 17:23:07 +00:00
|
|
|
#include "cmemory.h"
|
2002-08-01 16:17:41 +00:00
|
|
|
#include "cstring.h"
|
2002-06-25 17:23:07 +00:00
|
|
|
#include "rbbirb.h"
|
|
|
|
#include "rbbinode.h"
|
|
|
|
#include "rbbiscan.h"
|
|
|
|
#include "rbbisetb.h"
|
|
|
|
#include "rbbitblb.h"
|
2002-07-22 22:02:08 +00:00
|
|
|
#include "rbbidata.h"
|
2017-09-19 18:17:22 +00:00
|
|
|
#include "uassert.h"
|
2002-06-25 17:23:07 +00:00
|
|
|
|
|
|
|
|
|
|
|
U_NAMESPACE_BEGIN
|
|
|
|
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
// Constructor.
|
|
|
|
//
|
|
|
|
//----------------------------------------------------------------------------------------
|
|
|
|
RBBIRuleBuilder::RBBIRuleBuilder(const UnicodeString &rules,
|
2008-02-17 19:13:10 +00:00
|
|
|
UParseError *parseErr,
|
2002-06-25 17:23:07 +00:00
|
|
|
UErrorCode &status)
|
2018-02-03 19:10:50 +00:00
|
|
|
: fRules(rules), fStrippedRules(rules)
|
2002-06-25 17:23:07 +00:00
|
|
|
{
|
2003-09-09 23:51:17 +00:00
|
|
|
fStatus = &status; // status is checked below
|
2008-02-17 19:13:10 +00:00
|
|
|
fParseError = parseErr;
|
2002-08-01 16:17:41 +00:00
|
|
|
fDebugEnv = NULL;
|
|
|
|
#ifdef RBBI_DEBUG
|
|
|
|
fDebugEnv = getenv("U_RBBIDEBUG");
|
|
|
|
#endif
|
2002-06-25 17:23:07 +00:00
|
|
|
|
2002-07-08 22:45:04 +00:00
|
|
|
|
2002-06-25 17:23:07 +00:00
|
|
|
fForwardTree = NULL;
|
|
|
|
fReverseTree = NULL;
|
2003-11-05 02:03:44 +00:00
|
|
|
fSafeFwdTree = NULL;
|
|
|
|
fSafeRevTree = NULL;
|
|
|
|
fDefaultTree = &fForwardTree;
|
2018-03-28 01:20:13 +00:00
|
|
|
fForwardTable = NULL;
|
2004-03-05 05:04:10 +00:00
|
|
|
fRuleStatusVals = NULL;
|
2003-10-09 01:13:08 +00:00
|
|
|
fChainRules = FALSE;
|
2003-10-17 23:30:02 +00:00
|
|
|
fLBCMNoChain = FALSE;
|
2003-12-04 02:12:42 +00:00
|
|
|
fLookAheadHardBreak = FALSE;
|
2004-03-05 05:04:10 +00:00
|
|
|
fUSetNodes = NULL;
|
|
|
|
fRuleStatusVals = NULL;
|
|
|
|
fScanner = NULL;
|
|
|
|
fSetBuilder = NULL;
|
2008-02-17 19:13:10 +00:00
|
|
|
if (parseErr) {
|
|
|
|
uprv_memset(parseErr, 0, sizeof(UParseError));
|
|
|
|
}
|
2003-09-09 23:51:17 +00:00
|
|
|
|
2004-03-05 05:04:10 +00:00
|
|
|
if (U_FAILURE(status)) {
|
|
|
|
return;
|
|
|
|
}
|
2003-09-09 23:51:17 +00:00
|
|
|
|
|
|
|
fUSetNodes = new UVector(status); // bcos status gets overwritten here
|
2004-03-05 05:04:10 +00:00
|
|
|
fRuleStatusVals = new UVector(status);
|
2002-08-28 22:24:17 +00:00
|
|
|
fScanner = new RBBIRuleScanner(this);
|
|
|
|
fSetBuilder = new RBBISetBuilder(this);
|
2003-09-09 23:51:17 +00:00
|
|
|
if (U_FAILURE(status)) {
|
|
|
|
return;
|
|
|
|
}
|
2004-03-05 05:04:10 +00:00
|
|
|
if(fSetBuilder == 0 || fScanner == 0 || fUSetNodes == 0 || fRuleStatusVals == 0) {
|
2002-08-28 22:24:17 +00:00
|
|
|
status = U_MEMORY_ALLOCATION_ERROR;
|
|
|
|
}
|
2002-06-25 17:23:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
// Destructor
|
|
|
|
//
|
|
|
|
//----------------------------------------------------------------------------------------
|
|
|
|
RBBIRuleBuilder::~RBBIRuleBuilder() {
|
|
|
|
|
2002-08-28 22:24:17 +00:00
|
|
|
int i;
|
|
|
|
for (i=0; ; i++) {
|
|
|
|
RBBINode *n = (RBBINode *)fUSetNodes->elementAt(i);
|
|
|
|
if (n==NULL) {
|
|
|
|
break;
|
|
|
|
}
|
2002-06-25 17:23:07 +00:00
|
|
|
delete n;
|
|
|
|
}
|
|
|
|
|
2002-08-28 22:24:17 +00:00
|
|
|
delete fUSetNodes;
|
2002-06-25 17:23:07 +00:00
|
|
|
delete fSetBuilder;
|
2018-03-28 01:20:13 +00:00
|
|
|
delete fForwardTable;
|
2002-06-25 17:23:07 +00:00
|
|
|
delete fForwardTree;
|
|
|
|
delete fReverseTree;
|
2003-11-05 02:03:44 +00:00
|
|
|
delete fSafeFwdTree;
|
|
|
|
delete fSafeRevTree;
|
2002-06-25 17:23:07 +00:00
|
|
|
delete fScanner;
|
2004-03-05 05:04:10 +00:00
|
|
|
delete fRuleStatusVals;
|
2002-06-25 17:23:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
// flattenData() - Collect up the compiled RBBI rule data and put it into
|
|
|
|
// the format for saving in ICU data files,
|
|
|
|
// which is also the format needed by the RBBI runtime engine.
|
|
|
|
//
|
|
|
|
//----------------------------------------------------------------------------------------
|
2002-11-30 04:41:53 +00:00
|
|
|
static int32_t align8(int32_t i) {return (i+7) & 0xfffffff8;}
|
|
|
|
|
2002-06-25 17:23:07 +00:00
|
|
|
RBBIDataHeader *RBBIRuleBuilder::flattenData() {
|
2004-03-05 05:04:10 +00:00
|
|
|
int32_t i;
|
|
|
|
|
2002-06-25 17:23:07 +00:00
|
|
|
if (U_FAILURE(*fStatus)) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2018-02-03 19:10:50 +00:00
|
|
|
// Remove whitespace from the rules to make it smaller.
|
|
|
|
// The rule parser has already removed comments.
|
|
|
|
fStrippedRules = fScanner->stripRules(fStrippedRules);
|
2003-02-17 18:06:42 +00:00
|
|
|
|
2002-06-25 17:23:07 +00:00
|
|
|
// Calculate the size of each section in the data.
|
|
|
|
// Sizes here are padded up to a multiple of 8 for better memory alignment.
|
|
|
|
// Sections sizes actually stored in the header are for the actual data
|
|
|
|
// without the padding.
|
|
|
|
//
|
|
|
|
int32_t headerSize = align8(sizeof(RBBIDataHeader));
|
2018-03-28 01:20:13 +00:00
|
|
|
int32_t forwardTableSize = align8(fForwardTable->getTableSize());
|
|
|
|
int32_t reverseTableSize = align8(fForwardTable->getSafeTableSize());
|
2002-06-25 17:23:07 +00:00
|
|
|
int32_t trieSize = align8(fSetBuilder->getTrieSize());
|
2004-03-05 05:04:10 +00:00
|
|
|
int32_t statusTableSize = align8(fRuleStatusVals->size() * sizeof(int32_t));
|
2018-02-03 19:10:50 +00:00
|
|
|
int32_t rulesSize = align8((fStrippedRules.length()+1) * sizeof(UChar));
|
2002-06-25 17:23:07 +00:00
|
|
|
|
2017-09-19 18:17:22 +00:00
|
|
|
int32_t totalSize = headerSize
|
2018-03-22 17:31:00 +00:00
|
|
|
+ forwardTableSize
|
|
|
|
+ reverseTableSize
|
2004-03-05 05:04:10 +00:00
|
|
|
+ statusTableSize + trieSize + rulesSize;
|
|
|
|
|
2002-06-25 17:23:07 +00:00
|
|
|
RBBIDataHeader *data = (RBBIDataHeader *)uprv_malloc(totalSize);
|
|
|
|
if (data == NULL) {
|
|
|
|
*fStatus = U_MEMORY_ALLOCATION_ERROR;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
uprv_memset(data, 0, totalSize);
|
|
|
|
|
|
|
|
|
2005-03-28 05:21:50 +00:00
|
|
|
data->fMagic = 0xb1a0;
|
2017-06-20 22:11:08 +00:00
|
|
|
data->fFormatVersion[0] = RBBI_DATA_FORMAT_VERSION[0];
|
|
|
|
data->fFormatVersion[1] = RBBI_DATA_FORMAT_VERSION[1];
|
|
|
|
data->fFormatVersion[2] = RBBI_DATA_FORMAT_VERSION[2];
|
|
|
|
data->fFormatVersion[3] = RBBI_DATA_FORMAT_VERSION[3];
|
2005-03-28 05:21:50 +00:00
|
|
|
data->fLength = totalSize;
|
|
|
|
data->fCatCount = fSetBuilder->getNumCharCategories();
|
2002-06-25 17:23:07 +00:00
|
|
|
|
|
|
|
data->fFTable = headerSize;
|
|
|
|
data->fFTableLen = forwardTableSize;
|
2017-09-19 18:17:22 +00:00
|
|
|
|
2018-03-22 17:31:00 +00:00
|
|
|
data->fRTable = data->fFTable + data->fFTableLen;
|
|
|
|
data->fRTableLen = reverseTableSize;
|
2017-09-19 18:17:22 +00:00
|
|
|
|
2018-03-28 01:20:13 +00:00
|
|
|
data->fTrie = data->fRTable + data->fRTableLen;
|
2002-06-25 17:23:07 +00:00
|
|
|
data->fTrieLen = fSetBuilder->getTrieSize();
|
2004-03-05 05:04:10 +00:00
|
|
|
data->fStatusTable = data->fTrie + trieSize;
|
|
|
|
data->fStatusTableLen= statusTableSize;
|
|
|
|
data->fRuleSource = data->fStatusTable + statusTableSize;
|
2018-02-03 19:10:50 +00:00
|
|
|
data->fRuleSourceLen = fStrippedRules.length() * sizeof(UChar);
|
2002-06-25 17:23:07 +00:00
|
|
|
|
|
|
|
uprv_memset(data->fReserved, 0, sizeof(data->fReserved));
|
|
|
|
|
2018-03-28 01:20:13 +00:00
|
|
|
fForwardTable->exportTable((uint8_t *)data + data->fFTable);
|
|
|
|
fForwardTable->exportSafeTable((uint8_t *)data + data->fRTable);
|
2002-06-25 17:23:07 +00:00
|
|
|
fSetBuilder->serializeTrie ((uint8_t *)data + data->fTrie);
|
2004-03-05 05:04:10 +00:00
|
|
|
|
|
|
|
int32_t *ruleStatusTable = (int32_t *)((uint8_t *)data + data->fStatusTable);
|
|
|
|
for (i=0; i<fRuleStatusVals->size(); i++) {
|
|
|
|
ruleStatusTable[i] = fRuleStatusVals->elementAti(i);
|
|
|
|
}
|
|
|
|
|
2018-02-03 19:10:50 +00:00
|
|
|
fStrippedRules.extract((UChar *)((uint8_t *)data+data->fRuleSource), rulesSize/2+1, *fStatus);
|
2002-06-25 17:23:07 +00:00
|
|
|
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-06-27 01:50:22 +00:00
|
|
|
//----------------------------------------------------------------------------------------
|
2002-06-25 17:23:07 +00:00
|
|
|
//
|
2002-06-27 01:50:22 +00:00
|
|
|
// createRuleBasedBreakIterator construct from source rules that are passed in
|
|
|
|
// in a UnicodeString
|
2002-06-25 17:23:07 +00:00
|
|
|
//
|
2002-06-27 01:50:22 +00:00
|
|
|
//----------------------------------------------------------------------------------------
|
2002-07-08 22:45:04 +00:00
|
|
|
BreakIterator *
|
2002-06-25 17:23:07 +00:00
|
|
|
RBBIRuleBuilder::createRuleBasedBreakIterator( const UnicodeString &rules,
|
2008-02-17 19:13:10 +00:00
|
|
|
UParseError *parseError,
|
2002-06-25 17:23:07 +00:00
|
|
|
UErrorCode &status)
|
|
|
|
{
|
|
|
|
//
|
|
|
|
// Read the input rules, generate a parse tree, symbol table,
|
|
|
|
// and list of all Unicode Sets referenced by the rules.
|
|
|
|
//
|
|
|
|
RBBIRuleBuilder builder(rules, parseError, status);
|
2003-09-09 23:51:17 +00:00
|
|
|
if (U_FAILURE(status)) { // status checked here bcos build below doesn't
|
2002-06-25 17:23:07 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
2018-03-17 00:34:48 +00:00
|
|
|
|
|
|
|
RBBIDataHeader *data = builder.build(status);
|
|
|
|
|
|
|
|
if (U_FAILURE(status)) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Create a break iterator from the compiled rules.
|
|
|
|
// (Identical to creation from stored pre-compiled rules)
|
|
|
|
//
|
|
|
|
// status is checked after init in construction.
|
|
|
|
RuleBasedBreakIterator *This = new RuleBasedBreakIterator(data, status);
|
|
|
|
if (U_FAILURE(status)) {
|
|
|
|
delete This;
|
|
|
|
This = NULL;
|
|
|
|
}
|
|
|
|
else if(This == NULL) { // test for NULL
|
|
|
|
status = U_MEMORY_ALLOCATION_ERROR;
|
|
|
|
}
|
|
|
|
return This;
|
|
|
|
}
|
|
|
|
|
|
|
|
RBBIDataHeader *RBBIRuleBuilder::build(UErrorCode &status) {
|
|
|
|
if (U_FAILURE(status)) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
fScanner->parse();
|
|
|
|
if (U_FAILURE(status)) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
2002-06-25 17:23:07 +00:00
|
|
|
|
|
|
|
//
|
|
|
|
// UnicodeSet processing.
|
|
|
|
// Munge the Unicode Sets to create a set of character categories.
|
2018-02-08 01:42:04 +00:00
|
|
|
// Generate the mapping tables (TRIE) from input code points to
|
2002-06-25 17:23:07 +00:00
|
|
|
// the character categories.
|
|
|
|
//
|
2018-03-17 00:34:48 +00:00
|
|
|
fSetBuilder->buildRanges();
|
2002-06-25 17:23:07 +00:00
|
|
|
|
|
|
|
//
|
|
|
|
// Generate the DFA state transition table.
|
|
|
|
//
|
2018-03-28 01:20:13 +00:00
|
|
|
fForwardTable = new RBBITableBuilder(this, &fForwardTree, status);
|
|
|
|
if (fForwardTable == nullptr) {
|
2002-06-29 09:31:05 +00:00
|
|
|
status = U_MEMORY_ALLOCATION_ERROR;
|
2018-03-17 00:34:48 +00:00
|
|
|
return nullptr;
|
2002-06-29 09:31:05 +00:00
|
|
|
}
|
2002-07-08 22:45:04 +00:00
|
|
|
|
2018-03-28 01:20:13 +00:00
|
|
|
fForwardTable->buildForwardTable();
|
2018-03-22 17:31:00 +00:00
|
|
|
optimizeTables();
|
2018-03-28 01:20:13 +00:00
|
|
|
fForwardTable->buildSafeReverseTable(status);
|
2002-06-25 17:23:07 +00:00
|
|
|
|
2018-03-22 17:31:00 +00:00
|
|
|
|
2004-03-05 17:27:42 +00:00
|
|
|
#ifdef RBBI_DEBUG
|
2018-03-17 00:34:48 +00:00
|
|
|
if (fDebugEnv && uprv_strstr(fDebugEnv, "states")) {
|
2018-03-28 01:20:13 +00:00
|
|
|
fForwardTable->printStates();
|
|
|
|
fForwardTable->printRuleStatusTable();
|
|
|
|
fForwardTable->printReverseTable();
|
2004-03-05 05:04:10 +00:00
|
|
|
}
|
2004-03-05 17:27:42 +00:00
|
|
|
#endif
|
2004-03-05 05:04:10 +00:00
|
|
|
|
2018-03-17 00:34:48 +00:00
|
|
|
fSetBuilder->buildTrie();
|
2018-02-08 01:42:04 +00:00
|
|
|
|
2002-06-25 17:23:07 +00:00
|
|
|
//
|
|
|
|
// Package up the compiled data into a memory image
|
|
|
|
// in the run-time format.
|
|
|
|
//
|
2018-03-17 00:34:48 +00:00
|
|
|
RBBIDataHeader *data = flattenData(); // returns NULL if error
|
2002-06-25 17:23:07 +00:00
|
|
|
if (U_FAILURE(status)) {
|
2018-03-17 00:34:48 +00:00
|
|
|
return nullptr;
|
2002-06-25 17:23:07 +00:00
|
|
|
}
|
2018-03-17 00:34:48 +00:00
|
|
|
return data;
|
2002-06-25 17:23:07 +00:00
|
|
|
}
|
|
|
|
|
2018-02-08 01:42:04 +00:00
|
|
|
void RBBIRuleBuilder::optimizeTables() {
|
2018-08-09 18:28:55 +00:00
|
|
|
bool didSomething;
|
|
|
|
do {
|
|
|
|
didSomething = false;
|
|
|
|
|
|
|
|
// Begin looking for duplicates with char class 3.
|
|
|
|
// Classes 0, 1 and 2 are special; they are unused, {bof} and {eof} respectively,
|
|
|
|
// and should not have other categories merged into them.
|
|
|
|
IntPair duplPair = {3, 0};
|
|
|
|
while (fForwardTable->findDuplCharClassFrom(&duplPair)) {
|
|
|
|
fSetBuilder->mergeCategories(duplPair);
|
|
|
|
fForwardTable->removeColumn(duplPair.second);
|
|
|
|
didSomething = true;
|
|
|
|
}
|
2018-04-03 23:41:28 +00:00
|
|
|
|
2018-08-09 18:28:55 +00:00
|
|
|
while (fForwardTable->removeDuplicateStates() > 0) {
|
|
|
|
didSomething = true;
|
|
|
|
}
|
|
|
|
} while (didSomething);
|
2018-02-08 01:42:04 +00:00
|
|
|
}
|
|
|
|
|
2002-06-25 17:23:07 +00:00
|
|
|
U_NAMESPACE_END
|
2002-09-20 01:54:48 +00:00
|
|
|
|
|
|
|
#endif /* #if !UCONFIG_NO_BREAK_ITERATION */
|