1118 lines
36 KiB
C
1118 lines
36 KiB
C
/*
|
|
* Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
/**
|
|
* @file picoktab.c
|
|
*
|
|
* symbol tables needed at runtime
|
|
*
|
|
* Copyright (C) 2008-2009 SVOX AG, Baslerstr. 30, 8048 Zuerich, Switzerland
|
|
* All rights reserved.
|
|
*
|
|
* History:
|
|
* - 2009-04-20 -- initial version
|
|
*
|
|
*/
|
|
|
|
#include "picoos.h"
|
|
#include "picodbg.h"
|
|
#include "picoknow.h"
|
|
#include "picobase.h"
|
|
#include "picoktab.h"
|
|
#include "picodata.h"
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
#if 0
|
|
}
|
|
#endif
|
|
|
|
|
|
/** @todo : the following would be better part of a knowledge base.
|
|
* Make sure it is consistent with the phoneme symbol table used in the lingware */
|
|
|
|
/* PLANE_PHONEMES */
|
|
|
|
/* PLANE_POS */
|
|
|
|
/* PLANE_PB_STRENGTHS */
|
|
|
|
/* PLANE_ACCENTS */
|
|
|
|
/* PLANE_INTERN */
|
|
#define PICOKTAB_TMPID_PHONSTART '\x26' /* 38 '&' */
|
|
#define PICOKTAB_TMPID_PHONTERM '\x23' /* 35 '#' */
|
|
|
|
|
|
/* ************************************************************/
|
|
/* fixed ids */
|
|
/* ************************************************************/
|
|
|
|
|
|
static pico_status_t ktabIdsInitialize(register picoknow_KnowledgeBase this,
|
|
picoos_Common common)
|
|
{
|
|
picoktab_FixedIds ids;
|
|
|
|
PICODBG_DEBUG(("start"));
|
|
|
|
if (NULL == this || NULL == this->subObj) {
|
|
return picoos_emRaiseException(common->em, PICO_EXC_KB_MISSING,
|
|
NULL, NULL);
|
|
}
|
|
ids = (picoktab_FixedIds) this->subObj;
|
|
|
|
ids->phonStartId = PICOKTAB_TMPID_PHONSTART;
|
|
ids->phonTermId = PICOKTAB_TMPID_PHONTERM;
|
|
return PICO_OK;
|
|
}
|
|
|
|
|
|
static pico_status_t ktabIdsSubObjDeallocate(register picoknow_KnowledgeBase this,
|
|
picoos_MemoryManager mm)
|
|
{
|
|
if (NULL != this) {
|
|
picoos_deallocate(mm, (void *) &this->subObj);
|
|
}
|
|
return PICO_OK;
|
|
}
|
|
|
|
pico_status_t picoktab_specializeIdsKnowledgeBase(picoknow_KnowledgeBase this,
|
|
picoos_Common common)
|
|
{
|
|
if (NULL == this) {
|
|
return picoos_emRaiseException(common->em, PICO_EXC_KB_MISSING,
|
|
NULL, NULL);
|
|
}
|
|
this->subDeallocate = ktabIdsSubObjDeallocate;
|
|
this->subObj = picoos_allocate(common->mm, sizeof(picoktab_fixed_ids_t));
|
|
if (NULL == this->subObj) {
|
|
return picoos_emRaiseException(common->em, PICO_EXC_OUT_OF_MEM,
|
|
NULL, NULL);
|
|
}
|
|
return ktabIdsInitialize(this, common);
|
|
}
|
|
|
|
picoktab_FixedIds picoktab_getFixedIds(picoknow_KnowledgeBase this)
|
|
{
|
|
return ((NULL == this) ? NULL : ((picoktab_FixedIds) this->subObj));
|
|
}
|
|
|
|
|
|
picoktab_FixedIds picoktab_newFixedIds(picoos_MemoryManager mm)
|
|
{
|
|
picoktab_FixedIds this = (picoktab_FixedIds) picoos_allocate(mm,sizeof(*this));
|
|
if (NULL != this) {
|
|
/* initialize */
|
|
}
|
|
return this;
|
|
}
|
|
|
|
|
|
void picoktab_disposeFixedIds(picoos_MemoryManager mm, picoktab_FixedIds * this)
|
|
{
|
|
if (NULL != (*this)) {
|
|
/* terminate */
|
|
picoos_deallocate(mm,(void *)this);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/* ************************************************************/
|
|
/* Graphs */
|
|
/* ************************************************************/
|
|
|
|
/* overview binary file format for graphs kb:
|
|
|
|
graphs-kb = NROFSENTRIES SIZEOFSENTRY ofstable graphs
|
|
|
|
NROFSENTRIES : 2 bytes, number of entries in offset table
|
|
SIZEOFSENTRY : 1 byte, size of one entry in offset table
|
|
|
|
ofstable = {OFFSET}=NROFSENTRIES (contains NROFSENTRIES entries of OFFSET)
|
|
|
|
OFFSET: SIZEOFSENTRY bytes, offset to baseaddress of graphs-kb to entry in graphs
|
|
|
|
graphs = {graph}=NROFSENTRIES (contains NROFSENTRIES entries of graph)
|
|
|
|
graph = PROPSET FROM TO [TOKENTYPE] [TOKENSUBTYPE] [VALUE] [LOWERCASE] [GRAPHSUBS1] [GRAPHSUBS2]
|
|
|
|
FROM : 1..4 unsigned bytes, UTF8 character without terminating 0
|
|
TO : 1..4 unsigned bytes, UTF8 character without terminating 0
|
|
PROPSET : 1 unsigned byte, least significant bit : has TO field
|
|
next bit : has TOKENTYPE
|
|
next bit : has TOKENSUBTYPE
|
|
next bit : has VALUE
|
|
next bit : has LOWERCASE
|
|
next bit : has GRAPHSUBS1
|
|
next bit : has GRAPHSUBS2
|
|
next bit : has PUNC
|
|
|
|
TOKENTYPE : 1 unsigned byte
|
|
TOKENSUBTYPE : 1 unsigned byte
|
|
VALUE : 1 unsigned byte
|
|
LOWERCASE : 1..4 unsigned bytes, UTF8 character without terminating 0
|
|
GRAPHSUBS1 : 1..4 unsigned bytes, UTF8 character without terminating 0
|
|
GRAPHSUBS2 : 1..4 unsigned bytes, UTF8 character without terminating 0
|
|
PUNC : 1 unsigned byte
|
|
*/
|
|
|
|
static picoos_uint32 ktab_propOffset (const picoktab_Graphs this, picoos_uint32 graphsOffset, picoos_uint32 prop);
|
|
|
|
#define KTAB_START_GRAPHS_NR_OFFSET 0
|
|
#define KTAB_START_GRAPHS_SIZE_OFFSET 2
|
|
#define KTAB_START_GRAPHS_OFFSET_TABLE 3
|
|
#define KTAB_START_GRAPHS_GRAPH_TABLE 0
|
|
|
|
/* bitmasks to extract the grapheme properties info from the property set */
|
|
#define KTAB_GRAPH_PROPSET_TO ((picoos_uint8)'\x01')
|
|
#define KTAB_GRAPH_PROPSET_TOKENTYPE ((picoos_uint8)'\x02')
|
|
#define KTAB_GRAPH_PROPSET_TOKENSUBTYPE ((picoos_uint8)'\x04')
|
|
#define KTAB_GRAPH_PROPSET_VALUE ((picoos_uint8)'\x08')
|
|
#define KTAB_GRAPH_PROPSET_LOWERCASE ((picoos_uint8)'\x010')
|
|
#define KTAB_GRAPH_PROPSET_GRAPHSUBS1 ((picoos_uint8)'\x020')
|
|
#define KTAB_GRAPH_PROPSET_GRAPHSUBS2 ((picoos_uint8)'\x040')
|
|
#define KTAB_GRAPH_PROPSET_PUNCT ((picoos_uint8)'\x080')
|
|
|
|
|
|
typedef struct ktabgraphs_subobj *ktabgraphs_SubObj;
|
|
|
|
typedef struct ktabgraphs_subobj {
|
|
picoos_uint16 nrOffset;
|
|
picoos_uint16 sizeOffset;
|
|
|
|
picoos_uint8 * offsetTable;
|
|
picoos_uint8 * graphTable;
|
|
} ktabgraphs_subobj_t;
|
|
|
|
|
|
|
|
static pico_status_t ktabGraphsInitialize(register picoknow_KnowledgeBase this,
|
|
picoos_Common common) {
|
|
ktabgraphs_subobj_t * ktabgraphs;
|
|
|
|
PICODBG_DEBUG(("start"));
|
|
|
|
if (NULL == this || NULL == this->subObj) {
|
|
return picoos_emRaiseException(common->em, PICO_EXC_KB_MISSING,
|
|
NULL, NULL);
|
|
}
|
|
ktabgraphs = (ktabgraphs_subobj_t *) this->subObj;
|
|
ktabgraphs->nrOffset = ((int)(this->base[KTAB_START_GRAPHS_NR_OFFSET])) + 256*(int)(this->base[KTAB_START_GRAPHS_NR_OFFSET+1]);
|
|
ktabgraphs->sizeOffset = (int)(this->base[KTAB_START_GRAPHS_SIZE_OFFSET]);
|
|
ktabgraphs->offsetTable = &(this->base[KTAB_START_GRAPHS_OFFSET_TABLE]);
|
|
ktabgraphs->graphTable = &(this->base[KTAB_START_GRAPHS_GRAPH_TABLE]);
|
|
return PICO_OK;
|
|
}
|
|
|
|
static pico_status_t ktabGraphsSubObjDeallocate(register picoknow_KnowledgeBase this,
|
|
picoos_MemoryManager mm) {
|
|
if (NULL != this) {
|
|
picoos_deallocate(mm, (void *) &this->subObj);
|
|
}
|
|
return PICO_OK;
|
|
}
|
|
|
|
|
|
pico_status_t picoktab_specializeGraphsKnowledgeBase(picoknow_KnowledgeBase this,
|
|
picoos_Common common) {
|
|
if (NULL == this) {
|
|
return picoos_emRaiseException(common->em, PICO_EXC_KB_MISSING,
|
|
NULL, NULL);
|
|
}
|
|
this->subDeallocate = ktabGraphsSubObjDeallocate;
|
|
this->subObj = picoos_allocate(common->mm, sizeof(ktabgraphs_subobj_t));
|
|
if (NULL == this->subObj) {
|
|
return picoos_emRaiseException(common->em, PICO_EXC_OUT_OF_MEM,
|
|
NULL, NULL);
|
|
}
|
|
return ktabGraphsInitialize(this, common);
|
|
}
|
|
|
|
|
|
picoktab_Graphs picoktab_getGraphs(picoknow_KnowledgeBase this) {
|
|
if (NULL == this) {
|
|
return NULL;
|
|
} else {
|
|
return (picoktab_Graphs) this->subObj;
|
|
}
|
|
}
|
|
|
|
|
|
/* Graphs methods */
|
|
|
|
picoos_uint8 picoktab_hasVowellikeProp(const picoktab_Graphs this,
|
|
const picoos_uint8 *graph,
|
|
const picoos_uint8 graphlenmax) {
|
|
|
|
picoos_uint8 ui8App;
|
|
picoos_uint32 graphsOffset;
|
|
ktabgraphs_subobj_t * g = (ktabgraphs_SubObj)this;
|
|
|
|
ui8App = graphlenmax; /* avoid warning "var not used in this function"*/
|
|
|
|
graphsOffset = picoktab_graphOffset (this, (picoos_uchar *)graph);
|
|
return g->graphTable[graphsOffset + ktab_propOffset (this, graphsOffset, KTAB_GRAPH_PROPSET_TOKENTYPE)] == PICODATA_ITEMINFO1_TOKTYPE_LETTERV;
|
|
}
|
|
|
|
|
|
static void ktab_getStrProp (const picoktab_Graphs this, picoos_uint32 graphsOffset, picoos_uint32 propOffset, picoos_uchar * str)
|
|
{
|
|
ktabgraphs_subobj_t * g = (ktabgraphs_SubObj)this;
|
|
picoos_uint32 i, l;
|
|
|
|
i = 0;
|
|
l = picobase_det_utf8_length(g->graphTable[graphsOffset+propOffset]);
|
|
while (i<l) {
|
|
str[i] = g->graphTable[graphsOffset+propOffset+i];
|
|
i++;
|
|
}
|
|
str[l] = 0;
|
|
}
|
|
|
|
|
|
static picoos_uint32 ktab_propOffset(const picoktab_Graphs this,
|
|
picoos_uint32 graphsOffset, picoos_uint32 prop)
|
|
/* Returns offset of property 'prop' inside the graph with offset 'graphsOffset' in graphs table;
|
|
If the property is found, a value > 0 is returned otherwise 0 */
|
|
{
|
|
picoos_uint32 n = 0;
|
|
ktabgraphs_subobj_t * g = (ktabgraphs_SubObj) this;
|
|
|
|
if ((g->graphTable[graphsOffset] & prop) == prop) {
|
|
n = n + 1; /* overread PROPSET field */
|
|
n = n + picobase_det_utf8_length(g->graphTable[graphsOffset+n]); /* overread FROM field */
|
|
if (prop > KTAB_GRAPH_PROPSET_TO) {
|
|
if ((g->graphTable[graphsOffset] & KTAB_GRAPH_PROPSET_TO)
|
|
== KTAB_GRAPH_PROPSET_TO) {
|
|
n = n + picobase_det_utf8_length(g->graphTable[graphsOffset+n]); /* overread TO field */
|
|
}
|
|
} else {
|
|
return n;
|
|
}
|
|
if (prop > KTAB_GRAPH_PROPSET_TOKENTYPE) {
|
|
if ((g->graphTable[graphsOffset] & KTAB_GRAPH_PROPSET_TOKENTYPE)
|
|
== KTAB_GRAPH_PROPSET_TOKENTYPE) {
|
|
n = n + 1; /* overread TOKENTYPE field */
|
|
}
|
|
} else {
|
|
return n;
|
|
}
|
|
if (prop > KTAB_GRAPH_PROPSET_TOKENSUBTYPE) {
|
|
if ((g->graphTable[graphsOffset] & KTAB_GRAPH_PROPSET_TOKENSUBTYPE)
|
|
== KTAB_GRAPH_PROPSET_TOKENSUBTYPE) {
|
|
n = n + 1; /* overread stokentype field */
|
|
}
|
|
} else {
|
|
return n;
|
|
}
|
|
if (prop > KTAB_GRAPH_PROPSET_VALUE) {
|
|
if ((g->graphTable[graphsOffset] & KTAB_GRAPH_PROPSET_VALUE)
|
|
== KTAB_GRAPH_PROPSET_VALUE) {
|
|
n = n + 1; /* overread value field */
|
|
}
|
|
} else {
|
|
return n;
|
|
}
|
|
if (prop > KTAB_GRAPH_PROPSET_LOWERCASE) {
|
|
if ((g->graphTable[graphsOffset] & KTAB_GRAPH_PROPSET_LOWERCASE)
|
|
== KTAB_GRAPH_PROPSET_LOWERCASE) {
|
|
n = n + picobase_det_utf8_length(g->graphTable[graphsOffset+n]); /* overread lowercase field */
|
|
}
|
|
} else {
|
|
return n;
|
|
}
|
|
if (prop > KTAB_GRAPH_PROPSET_GRAPHSUBS1) {
|
|
if ((g->graphTable[graphsOffset] & KTAB_GRAPH_PROPSET_GRAPHSUBS1)
|
|
== KTAB_GRAPH_PROPSET_GRAPHSUBS1) {
|
|
n = n + picobase_det_utf8_length(g->graphTable[graphsOffset+n]); /* overread graphsubs1 field */
|
|
}
|
|
} else {
|
|
return n;
|
|
}
|
|
if (prop > KTAB_GRAPH_PROPSET_GRAPHSUBS2) {
|
|
if ((g->graphTable[graphsOffset] & KTAB_GRAPH_PROPSET_GRAPHSUBS2)
|
|
== KTAB_GRAPH_PROPSET_GRAPHSUBS2) {
|
|
n = n + picobase_det_utf8_length(g->graphTable[graphsOffset+n]); /* overread graphsubs2 field */
|
|
}
|
|
} else {
|
|
return n;
|
|
}
|
|
if (prop > KTAB_GRAPH_PROPSET_PUNCT) {
|
|
if ((g->graphTable[graphsOffset] & KTAB_GRAPH_PROPSET_PUNCT)
|
|
== KTAB_GRAPH_PROPSET_PUNCT) {
|
|
n = n + 1; /* overread value field */
|
|
}
|
|
} else {
|
|
return n;
|
|
}
|
|
}
|
|
|
|
return n;
|
|
}
|
|
|
|
|
|
picoos_uint32 picoktab_graphOffset (const picoktab_Graphs this, picoos_uchar * utf8graph)
|
|
{ ktabgraphs_subobj_t * g = (ktabgraphs_SubObj)this;
|
|
picoos_int32 a, b, m;
|
|
picoos_uint32 graphsOffset;
|
|
picoos_uint32 propOffset;
|
|
picobase_utf8char from;
|
|
picobase_utf8char to;
|
|
picoos_bool utfGEfrom;
|
|
picoos_bool utfLEto;
|
|
|
|
if (g->nrOffset > 0) {
|
|
a = 0;
|
|
b = g->nrOffset-1;
|
|
do {
|
|
m = (a+b) / 2;
|
|
|
|
/* get offset to graph[m] */
|
|
if (g->sizeOffset == 1) {
|
|
graphsOffset = g->offsetTable[g->sizeOffset*m];
|
|
}
|
|
else {
|
|
graphsOffset = g->offsetTable[g->sizeOffset*m ] +
|
|
256*g->offsetTable[g->sizeOffset*m + 1];
|
|
/* PICODBG_DEBUG(("picoktab_graphOffset: %i %i %i %i", m, g->offsetTable[g->sizeOffset*m], g->offsetTable[g->sizeOffset*m + 1], graphsOffset));
|
|
*/
|
|
}
|
|
|
|
/* get FROM and TO field of graph[m] */
|
|
ktab_getStrProp(this, graphsOffset, 1, from);
|
|
propOffset = ktab_propOffset(this, graphsOffset, KTAB_GRAPH_PROPSET_TO);
|
|
if (propOffset > 0) {
|
|
ktab_getStrProp(this, graphsOffset, propOffset, to);
|
|
}
|
|
else {
|
|
picoos_strcpy((picoos_char *)to, (picoos_char *)from);
|
|
}
|
|
|
|
/* PICODBG_DEBUG(("picoktab_graphOffset: %i %i %i '%s' '%s' '%s'", a, m, b, from, utf8graph, to));
|
|
*/
|
|
utfGEfrom = picoos_strcmp((picoos_char *)utf8graph, (picoos_char *)from) >= 0;
|
|
utfLEto = picoos_strcmp((picoos_char *)utf8graph, (picoos_char *)to) <= 0;
|
|
|
|
if (utfGEfrom && utfLEto) {
|
|
/* PICODBG_DEBUG(("picoktab_graphOffset: utf char '%s' found", utf8graph));
|
|
*/
|
|
return graphsOffset;
|
|
}
|
|
if (!utfGEfrom) {
|
|
b = m-1;
|
|
}
|
|
else if (!utfLEto) {
|
|
a = m+1;
|
|
}
|
|
} while (a<=b);
|
|
}
|
|
PICODBG_DEBUG(("picoktab_graphOffset: utf char '%s' not found", utf8graph));
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
picoos_bool picoktab_getIntPropTokenType (const picoktab_Graphs this, picoos_uint32 graphsOffset, picoos_uint8 * stokenType)
|
|
{
|
|
picoos_uint32 propOffset;
|
|
ktabgraphs_subobj_t * g = (ktabgraphs_SubObj)this;
|
|
|
|
propOffset = ktab_propOffset(this, graphsOffset, KTAB_GRAPH_PROPSET_TOKENTYPE);
|
|
if (propOffset > 0) {
|
|
*stokenType = (picoos_uint8)(g->graphTable[graphsOffset+propOffset]);
|
|
return TRUE;
|
|
}
|
|
else {
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
picoos_bool picoktab_getIntPropTokenSubType (const picoktab_Graphs this, picoos_uint32 graphsOffset, picoos_int8 * stokenSubType)
|
|
{
|
|
picoos_uint32 propOffset;
|
|
ktabgraphs_subobj_t * g = (ktabgraphs_SubObj)this;
|
|
|
|
propOffset = ktab_propOffset(this, graphsOffset, KTAB_GRAPH_PROPSET_TOKENSUBTYPE);
|
|
if (propOffset > 0) {
|
|
*stokenSubType = (picoos_int8)(g->graphTable[graphsOffset+propOffset]);
|
|
return TRUE;
|
|
}
|
|
else {
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
picoos_bool picoktab_getIntPropValue (const picoktab_Graphs this, picoos_uint32 graphsOffset, picoos_uint32 * value)
|
|
{
|
|
picoos_uint32 propOffset;
|
|
ktabgraphs_subobj_t * g = (ktabgraphs_SubObj)this;
|
|
|
|
propOffset = ktab_propOffset(this, graphsOffset, KTAB_GRAPH_PROPSET_VALUE);
|
|
if (propOffset > 0) {
|
|
*value = (picoos_uint32)(g->graphTable[graphsOffset+propOffset]);
|
|
return TRUE;
|
|
}
|
|
else {
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
picoos_bool picoktab_getIntPropPunct (const picoktab_Graphs this, picoos_uint32 graphsOffset, picoos_uint8 * info1, picoos_uint8 * info2)
|
|
{
|
|
picoos_uint32 propOffset;
|
|
ktabgraphs_subobj_t * g = (ktabgraphs_SubObj)this;
|
|
|
|
propOffset = ktab_propOffset(this, graphsOffset, KTAB_GRAPH_PROPSET_PUNCT);
|
|
if (propOffset > 0) {
|
|
if (g->graphTable[graphsOffset+propOffset] == 2) {
|
|
*info1 = PICODATA_ITEMINFO1_PUNC_SENTEND;
|
|
}
|
|
else {
|
|
*info1 = PICODATA_ITEMINFO1_PUNC_PHRASEEND;
|
|
}
|
|
if (g->graphTable[graphsOffset+1] == '.') {
|
|
*info2 = PICODATA_ITEMINFO2_PUNC_SENT_T;
|
|
}
|
|
else if (g->graphTable[graphsOffset+1] == '?') {
|
|
*info2 = PICODATA_ITEMINFO2_PUNC_SENT_Q;
|
|
}
|
|
else if (g->graphTable[graphsOffset+1] == '!') {
|
|
*info2 = PICODATA_ITEMINFO2_PUNC_SENT_E;
|
|
}
|
|
else {
|
|
*info2 = PICODATA_ITEMINFO2_PUNC_PHRASE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
else {
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
picoos_bool picoktab_getStrPropLowercase (const picoktab_Graphs this, picoos_uint32 graphsOffset, picoos_uchar * lowercase)
|
|
{
|
|
picoos_uint32 propOffset;
|
|
|
|
propOffset = ktab_propOffset(this, graphsOffset, KTAB_GRAPH_PROPSET_LOWERCASE);
|
|
if (propOffset > 0) {
|
|
ktab_getStrProp(this, graphsOffset, propOffset, lowercase);
|
|
return TRUE;
|
|
}
|
|
else {
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
picoos_bool picoktab_getStrPropGraphsubs1 (const picoktab_Graphs this, picoos_uint32 graphsOffset, picoos_uchar * graphsubs1)
|
|
{
|
|
picoos_uint32 propOffset;
|
|
|
|
propOffset = ktab_propOffset(this, graphsOffset, KTAB_GRAPH_PROPSET_GRAPHSUBS1);
|
|
if (propOffset > 0) {
|
|
ktab_getStrProp(this, graphsOffset, propOffset, graphsubs1);
|
|
return TRUE;
|
|
}
|
|
else {
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
picoos_bool picoktab_getStrPropGraphsubs2 (const picoktab_Graphs this, picoos_uint32 graphsOffset, picoos_uchar * graphsubs2)
|
|
{
|
|
picoos_uint32 propOffset;
|
|
|
|
propOffset = ktab_propOffset(this, graphsOffset, KTAB_GRAPH_PROPSET_GRAPHSUBS2);
|
|
if (propOffset > 0) {
|
|
ktab_getStrProp(this, graphsOffset, propOffset, graphsubs2);
|
|
return TRUE;
|
|
}
|
|
else {
|
|
return FALSE;
|
|
}
|
|
}
|
|
/* *****************************************************************/
|
|
/* used for tools */
|
|
|
|
static void ktab_getUtf8 (picoos_uchar ** pos, picoos_uchar * to)
|
|
{
|
|
picoos_uint32 l;
|
|
l = picobase_det_utf8_length(**pos);
|
|
while (l>0) {
|
|
*(to++) = *((*pos)++);
|
|
l--;
|
|
}
|
|
*to = 0;
|
|
}
|
|
|
|
picoos_uint16 picoktab_graphsGetNumEntries(const picoktab_Graphs this)
|
|
{
|
|
ktabgraphs_subobj_t * g = (ktabgraphs_SubObj) this;
|
|
return g->nrOffset;
|
|
}
|
|
|
|
void picoktab_graphsGetGraphInfo(const picoktab_Graphs this,
|
|
picoos_uint16 graphIndex, picoos_uchar * from, picoos_uchar * to,
|
|
picoos_uint8 * propset,
|
|
picoos_uint8 * stokenType, picoos_uint8 * stokenSubType,
|
|
picoos_uint8 * value, picoos_uchar * lowercase,
|
|
picoos_uchar * graphsubs1, picoos_uchar * graphsubs2,
|
|
picoos_uint8 * punct) {
|
|
ktabgraphs_subobj_t * g = (ktabgraphs_SubObj) this;
|
|
picoos_uint32 graphsOffset;
|
|
picoos_uint8 * pos;
|
|
|
|
/* calculate offset of graph[graphIndex] */
|
|
if (g->sizeOffset == 1) {
|
|
graphsOffset = g->offsetTable[graphIndex];
|
|
} else {
|
|
graphsOffset = g->offsetTable[2 * graphIndex]
|
|
+ (g->offsetTable[2 * graphIndex + 1] << 8);
|
|
}
|
|
pos = &(g->graphTable[graphsOffset]);
|
|
*propset = *pos;
|
|
|
|
pos++; /* advance to FROM */
|
|
ktab_getUtf8(&pos, from); /* get FROM and advance */
|
|
if ((*propset) & KTAB_GRAPH_PROPSET_TO) {
|
|
ktab_getUtf8(&pos, to); /* get TO and advance */
|
|
} else {
|
|
picoos_strcpy((picoos_char *)to, (picoos_char *)from);
|
|
}
|
|
if ((*propset) & KTAB_GRAPH_PROPSET_TOKENTYPE) {
|
|
(*stokenType) = *(pos++); /* get TOKENTYPE and advance */
|
|
} else {
|
|
(*stokenType) = -1;
|
|
}
|
|
if ((*propset) & KTAB_GRAPH_PROPSET_TOKENSUBTYPE) {
|
|
(*stokenSubType) = *(pos++); /* get TOKENSUBTYPE and advance */
|
|
} else {
|
|
(*stokenSubType) = -1;
|
|
}
|
|
if ((*propset) & KTAB_GRAPH_PROPSET_VALUE) {
|
|
(*value) = *(pos++); /* get VALUE and advance */
|
|
} else {
|
|
(*value) = -1;
|
|
}
|
|
if ((*propset) & KTAB_GRAPH_PROPSET_LOWERCASE) {
|
|
ktab_getUtf8(&pos, lowercase); /* get LOWERCASE and advance */
|
|
} else {
|
|
lowercase[0] = NULLC;
|
|
}
|
|
if ((*propset) & KTAB_GRAPH_PROPSET_GRAPHSUBS1) {
|
|
ktab_getUtf8(&pos, graphsubs1); /* get GRAPHSUBS1 and advance */
|
|
} else {
|
|
graphsubs1[0] = NULLC;
|
|
}
|
|
if ((*propset) & KTAB_GRAPH_PROPSET_GRAPHSUBS2) {
|
|
ktab_getUtf8(&pos, graphsubs2); /* get GRAPHSUBS2 and advance */
|
|
} else {
|
|
graphsubs2[0] = NULLC;
|
|
}
|
|
if ((*propset) & KTAB_GRAPH_PROPSET_PUNCT) {
|
|
(*punct) = *(pos++); /* get PUNCT and advance */
|
|
} else {
|
|
(*punct) = -1;
|
|
}
|
|
}
|
|
|
|
/* ************************************************************/
|
|
/* Phones */
|
|
/* ************************************************************/
|
|
|
|
/* overview binary file format for phones kb:
|
|
|
|
phones-kb = specids propertytable
|
|
|
|
specids = PRIMSTRESSID1 SECSTRESSID1 SYLLBOUNDID1 PAUSEID1 WORDBOUNDID1
|
|
RESERVE1 RESERVE1 RESERVE1
|
|
|
|
propertytable = {PHONEPROP2}=256
|
|
|
|
PRIMSTRESSID1: one byte, ID of primary stress
|
|
SECSTRESSID1: one byte, ID of secondary stress
|
|
SYLLBOUNDID1: one byte, ID of syllable boundary
|
|
PAUSEID1: one byte, ID of pause
|
|
RESERVE1: reserved for future use
|
|
|
|
PHONEPROP2: one byte, max. of 256 phones directly access this table
|
|
to check a property for a phone; binary properties
|
|
encoded (1 bit per prop)
|
|
least significant bit: vowel
|
|
next bit: diphth
|
|
next bit: glott
|
|
next bit: nonsyllvowel
|
|
next bit: syllcons
|
|
3 bits spare
|
|
*/
|
|
|
|
#define KTAB_START_SPECIDS 0
|
|
#define KTAB_IND_PRIMSTRESS 0
|
|
#define KTAB_IND_SECSTRESS 1
|
|
#define KTAB_IND_SYLLBOUND 2
|
|
#define KTAB_IND_PAUSE 3
|
|
#define KTAB_IND_WORDBOUND 4
|
|
|
|
#define KTAB_START_PROPS 8
|
|
|
|
|
|
typedef struct ktabphones_subobj *ktabphones_SubObj;
|
|
|
|
typedef struct ktabphones_subobj {
|
|
picoos_uint8 *specids;
|
|
picoos_uint8 *props;
|
|
} ktabphones_subobj_t;
|
|
|
|
|
|
/* bitmasks to extract the property info from props */
|
|
#define KTAB_PPROP_VOWEL '\x01'
|
|
#define KTAB_PPROP_DIPHTH '\x02'
|
|
#define KTAB_PPROP_GLOTT '\x04'
|
|
#define KTAB_PPROP_NONSYLLVOWEL '\x08'
|
|
#define KTAB_PPROP_SYLLCONS '\x10'
|
|
|
|
|
|
static pico_status_t ktabPhonesInitialize(register picoknow_KnowledgeBase this,
|
|
picoos_Common common) {
|
|
ktabphones_subobj_t * ktabphones;
|
|
|
|
PICODBG_DEBUG(("start"));
|
|
|
|
if (NULL == this || NULL == this->subObj) {
|
|
return picoos_emRaiseException(common->em, PICO_EXC_KB_MISSING,
|
|
NULL, NULL);
|
|
}
|
|
ktabphones = (ktabphones_subobj_t *) this->subObj;
|
|
ktabphones->specids = &(this->base[KTAB_START_SPECIDS]);
|
|
ktabphones->props = &(this->base[KTAB_START_PROPS]);
|
|
return PICO_OK;
|
|
}
|
|
|
|
static pico_status_t ktabPhonesSubObjDeallocate(register picoknow_KnowledgeBase this,
|
|
picoos_MemoryManager mm) {
|
|
if (NULL != this) {
|
|
picoos_deallocate(mm, (void *) &this->subObj);
|
|
}
|
|
return PICO_OK;
|
|
}
|
|
|
|
pico_status_t picoktab_specializePhonesKnowledgeBase(picoknow_KnowledgeBase this,
|
|
picoos_Common common) {
|
|
if (NULL == this) {
|
|
return picoos_emRaiseException(common->em, PICO_EXC_KB_MISSING,
|
|
NULL, NULL);
|
|
}
|
|
this->subDeallocate = ktabPhonesSubObjDeallocate;
|
|
this->subObj = picoos_allocate(common->mm, sizeof(ktabphones_subobj_t));
|
|
if (NULL == this->subObj) {
|
|
return picoos_emRaiseException(common->em, PICO_EXC_OUT_OF_MEM,
|
|
NULL, NULL);
|
|
}
|
|
return ktabPhonesInitialize(this, common);
|
|
}
|
|
|
|
picoktab_Phones picoktab_getPhones(picoknow_KnowledgeBase this) {
|
|
if (NULL == this) {
|
|
return NULL;
|
|
} else {
|
|
return (picoktab_Phones) this->subObj;
|
|
}
|
|
}
|
|
|
|
|
|
/* Phones methods */
|
|
|
|
picoos_uint8 picoktab_hasVowelProp(const picoktab_Phones this,
|
|
const picoos_uint8 ch) {
|
|
return (KTAB_PPROP_VOWEL & ((ktabphones_SubObj)this)->props[ch]);
|
|
}
|
|
picoos_uint8 picoktab_hasDiphthProp(const picoktab_Phones this,
|
|
const picoos_uint8 ch) {
|
|
return (KTAB_PPROP_DIPHTH & ((ktabphones_SubObj)this)->props[ch]);
|
|
}
|
|
picoos_uint8 picoktab_hasGlottProp(const picoktab_Phones this,
|
|
const picoos_uint8 ch) {
|
|
return (KTAB_PPROP_GLOTT & ((ktabphones_SubObj)this)->props[ch]);
|
|
}
|
|
picoos_uint8 picoktab_hasNonsyllvowelProp(const picoktab_Phones this,
|
|
const picoos_uint8 ch) {
|
|
return (KTAB_PPROP_NONSYLLVOWEL & ((ktabphones_SubObj)this)->props[ch]);
|
|
}
|
|
picoos_uint8 picoktab_hasSyllconsProp(const picoktab_Phones this,
|
|
const picoos_uint8 ch) {
|
|
return (KTAB_PPROP_SYLLCONS & ((ktabphones_SubObj)this)->props[ch]);
|
|
}
|
|
|
|
picoos_bool picoktab_isSyllCarrier(const picoktab_Phones this,
|
|
const picoos_uint8 ch) {
|
|
picoos_uint8 props;
|
|
props = ((ktabphones_SubObj)this)->props[ch];
|
|
return (((KTAB_PPROP_VOWEL & props) &&
|
|
!(KTAB_PPROP_NONSYLLVOWEL & props))
|
|
|| (KTAB_PPROP_SYLLCONS & props));
|
|
}
|
|
|
|
picoos_bool picoktab_isPrimstress(const picoktab_Phones this,
|
|
const picoos_uint8 ch) {
|
|
return (ch == ((ktabphones_SubObj)this)->specids[KTAB_IND_PRIMSTRESS]);
|
|
}
|
|
picoos_bool picoktab_isSecstress(const picoktab_Phones this,
|
|
const picoos_uint8 ch) {
|
|
return (ch == ((ktabphones_SubObj)this)->specids[KTAB_IND_SECSTRESS]);
|
|
}
|
|
picoos_bool picoktab_isSyllbound(const picoktab_Phones this,
|
|
const picoos_uint8 ch) {
|
|
return (ch == ((ktabphones_SubObj)this)->specids[KTAB_IND_SYLLBOUND]);
|
|
}
|
|
picoos_bool picoktab_isWordbound(const picoktab_Phones this,
|
|
const picoos_uint8 ch) {
|
|
return (ch == ((ktabphones_SubObj)this)->specids[KTAB_IND_WORDBOUND]);
|
|
}
|
|
picoos_bool picoktab_isPause(const picoktab_Phones this,
|
|
const picoos_uint8 ch) {
|
|
return (ch == ((ktabphones_SubObj)this)->specids[KTAB_IND_PAUSE]);
|
|
}
|
|
|
|
picoos_uint8 picoktab_getPrimstressID(const picoktab_Phones this) {
|
|
return ((ktabphones_SubObj)this)->specids[KTAB_IND_PRIMSTRESS];
|
|
}
|
|
picoos_uint8 picoktab_getSecstressID(const picoktab_Phones this) {
|
|
return ((ktabphones_SubObj)this)->specids[KTAB_IND_SECSTRESS];
|
|
}
|
|
picoos_uint8 picoktab_getSyllboundID(const picoktab_Phones this) {
|
|
return ((ktabphones_SubObj)this)->specids[KTAB_IND_SYLLBOUND];
|
|
}
|
|
picoos_uint8 picoktab_getWordboundID(const picoktab_Phones this) {
|
|
return ((ktabphones_SubObj)this)->specids[KTAB_IND_WORDBOUND];
|
|
}
|
|
picoos_uint8 picoktab_getPauseID(const picoktab_Phones this) {
|
|
return ((ktabphones_SubObj)this)->specids[KTAB_IND_PAUSE];
|
|
}
|
|
|
|
/* ************************************************************/
|
|
/* Pos */
|
|
/* ************************************************************/
|
|
|
|
/* overview binary file format for pos kb:
|
|
|
|
pos-kb = header posids
|
|
header = {COUNT2 OFFS2}=8
|
|
posids = {POSID1 {PARTID1}0:8}1:
|
|
|
|
where POSID1 is the value of the (combined) part-of-speech symbol,
|
|
and {PARTID1} are the symbol values of its components (empty if it
|
|
is not a combined symbol). The {PARTID1} list is sorted.
|
|
Part-of-speech symbols with equal number of components are grouped
|
|
together.
|
|
|
|
The header contains information about these groups:
|
|
|
|
COUNT2 specifies the number of elements in the group, and OFFS2
|
|
specifies the offset (relative to the beginning of the kb) where
|
|
the group data starts, i.e.:
|
|
|
|
25 32 -> 25 not-combined elements, starting at offset 32
|
|
44 57 -> 44 elements composed of 2 symbols, starting at offset 57
|
|
23 189 -> 23 elements composed of 3 symbols, starting at offset 189
|
|
...
|
|
|
|
Currently, each symbol may be composed of up to 8 other symbols.
|
|
Therefore, the header has 8 entries, too. The header starts with
|
|
the unique POS list, and then in increasing order, 2 symbols, 3
|
|
symbols,...
|
|
|
|
Zur Anschauung die ge-printf-te Version:
|
|
|
|
25 32
|
|
44 57
|
|
23 189
|
|
12 281
|
|
4 341
|
|
1 365
|
|
0 0
|
|
0 0
|
|
33 |
|
|
34 |
|
|
35 |
|
|
60 |
|
|
etc.
|
|
36 | 35 60
|
|
50 | 35 95
|
|
51 | 35 97
|
|
58 | 35 120
|
|
59 | 35 131
|
|
61 | 60 75
|
|
63 | 60 95
|
|
64 | 60 97
|
|
etc.
|
|
42 | 35 60 117
|
|
44 | 35 60 131
|
|
45 | 35 73 97
|
|
48 | 35 84 97
|
|
54 | 35 97 131
|
|
56 | 35 113 120
|
|
57 | 35 117 120
|
|
62 | 60 84 122
|
|
etc.
|
|
*/
|
|
|
|
typedef struct ktabpos_subobj *ktabpos_SubObj;
|
|
|
|
typedef struct ktabpos_subobj {
|
|
picoos_uint16 nrcomb[PICOKTAB_MAXNRPOS_IN_COMB];
|
|
picoos_uint8 *nrcombstart[PICOKTAB_MAXNRPOS_IN_COMB];
|
|
} ktabpos_subobj_t;
|
|
|
|
|
|
static pico_status_t ktabPosInitialize(register picoknow_KnowledgeBase this,
|
|
picoos_Common common) {
|
|
ktabpos_subobj_t *ktabpos;
|
|
picoos_uint16 osprev;
|
|
picoos_uint16 os, pos;
|
|
picoos_uint8 i;
|
|
|
|
PICODBG_DEBUG(("start"));
|
|
|
|
if (NULL == this || NULL == this->subObj) {
|
|
return picoos_emRaiseException(common->em, PICO_EXC_KB_MISSING,
|
|
NULL, NULL);
|
|
}
|
|
ktabpos = (ktabpos_subobj_t *)this->subObj;
|
|
|
|
os = 0;
|
|
for (i = 0, pos = 0; i < PICOKTAB_MAXNRPOS_IN_COMB; i++, pos += 4) {
|
|
ktabpos->nrcomb[i] = ((picoos_uint16)(this->base[pos+1])) << 8 |
|
|
this->base[pos];
|
|
if (ktabpos->nrcomb[i] > 0) {
|
|
osprev = os;
|
|
os = ((picoos_uint16)(this->base[pos+3])) << 8 | this->base[pos+2];
|
|
ktabpos->nrcombstart[i] = &(this->base[os]);
|
|
PICODBG_TRACE(("i %d, pos %d, nr %d, osprev %d, os %d", i, pos,
|
|
ktabpos->nrcomb[i], osprev, os));
|
|
if (osprev >= os) {
|
|
/* cannot be, in a valid kb */
|
|
return picoos_emRaiseException(common->em,
|
|
PICO_EXC_FILE_CORRUPT,
|
|
NULL, NULL);
|
|
}
|
|
} else {
|
|
if (i == 0) {
|
|
/* cannot be, in a valid kb */
|
|
return picoos_emRaiseException(common->em,
|
|
PICO_EXC_FILE_CORRUPT,
|
|
NULL, NULL);
|
|
}
|
|
ktabpos->nrcombstart[i] = NULL;
|
|
}
|
|
}
|
|
return PICO_OK;
|
|
}
|
|
|
|
static pico_status_t ktabPosSubObjDeallocate(register picoknow_KnowledgeBase this,
|
|
picoos_MemoryManager mm) {
|
|
if (NULL != this) {
|
|
picoos_deallocate(mm, (void *) &this->subObj);
|
|
}
|
|
return PICO_OK;
|
|
}
|
|
|
|
pico_status_t picoktab_specializePosKnowledgeBase(picoknow_KnowledgeBase this,
|
|
picoos_Common common) {
|
|
if (NULL == this) {
|
|
return picoos_emRaiseException(common->em, PICO_EXC_KB_MISSING,
|
|
NULL, NULL);
|
|
}
|
|
this->subDeallocate = ktabPosSubObjDeallocate;
|
|
this->subObj = picoos_allocate(common->mm, sizeof(ktabpos_subobj_t));
|
|
if (NULL == this->subObj) {
|
|
return picoos_emRaiseException(common->em, PICO_EXC_OUT_OF_MEM,
|
|
NULL, NULL);
|
|
}
|
|
return ktabPosInitialize(this, common);
|
|
}
|
|
|
|
picoktab_Pos picoktab_getPos(picoknow_KnowledgeBase this) {
|
|
if (NULL == this) {
|
|
return NULL;
|
|
} else {
|
|
return (picoktab_Pos) this->subObj;
|
|
}
|
|
}
|
|
|
|
|
|
/* Pos methods */
|
|
|
|
static picoos_int16 ktab_isEqualPosGroup(const picoos_uint8 *grp1,
|
|
const picoos_uint8 *grp2,
|
|
picoos_uint8 len)
|
|
{
|
|
/* if both, grp1 and grp2 would be sorted in ascending order
|
|
we could implement a function picoktab_comparePosGroup in
|
|
a similar manner as strcmp */
|
|
|
|
picoos_uint16 i, j, equal;
|
|
|
|
equal = 1;
|
|
|
|
i = 0;
|
|
while (equal && (i < len)) {
|
|
/* search grp1[i] in grp2 */
|
|
j = 0;
|
|
while ((j < len) && (grp1[i] != grp2[j])) {
|
|
j++;
|
|
}
|
|
equal = (j < len);
|
|
i++;
|
|
}
|
|
|
|
return equal;
|
|
}
|
|
|
|
|
|
picoos_bool picoktab_isUniquePos(const picoktab_Pos this,
|
|
const picoos_uint8 pos) {
|
|
ktabpos_subobj_t *ktabpos;
|
|
picoos_uint16 i;
|
|
|
|
/* speed-up possible with e.g. binary search */
|
|
|
|
ktabpos = (ktabpos_subobj_t *)this;
|
|
PICODBG_TRACE(("pos %d, nrcombinations %d", pos, ktabpos->nrcomb[0]));
|
|
i = 0;
|
|
while ((i < ktabpos->nrcomb[0]) && (pos > ktabpos->nrcombstart[0][i])) {
|
|
PICODBG_TRACE(("compare with pos %d at position %d",
|
|
ktabpos->nrcombstart[0][i], pos, i));
|
|
i++;
|
|
}
|
|
return ((i < ktabpos->nrcomb[0]) && (pos == ktabpos->nrcombstart[0][i]));
|
|
}
|
|
|
|
|
|
picoos_bool picoktab_isPartOfPosGroup(const picoktab_Pos this,
|
|
const picoos_uint8 pos,
|
|
const picoos_uint8 posgroup)
|
|
{
|
|
ktabpos_subobj_t *ktabpos;
|
|
picoos_uint8 *grp;
|
|
picoos_uint16 i, j, n, s, grplen;
|
|
picoos_uint8 *e;
|
|
picoos_uint8 found;
|
|
|
|
ktabpos = (ktabpos_subobj_t *) this;
|
|
|
|
grp = NULL;
|
|
found = FALSE;
|
|
grplen = 0;
|
|
|
|
/* currently, a linear search is required to find 'posgroup'; the
|
|
knowledge base should be extended to allow for a faster search */
|
|
|
|
/* treat case i==0, grplen==0, ie. pos == posgroup */
|
|
if (pos == posgroup) {
|
|
found = TRUE;
|
|
}
|
|
|
|
i = 1;
|
|
while ((grp == NULL) && (i < PICOKTAB_MAXNRPOS_IN_COMB)) {
|
|
n = ktabpos->nrcomb[i]; /* number of entries */
|
|
e = ktabpos->nrcombstart[i]; /* ptr to first entry */
|
|
s = i + 2; /* size of an entry in bytes */
|
|
/* was with while starting at 0:
|
|
s = i > 0 ? i + 2 : 1;
|
|
*/
|
|
j = 0;
|
|
while ((grp == NULL) && (j < n)) {
|
|
if (posgroup == e[0]) {
|
|
grp = e + 1;
|
|
grplen = s - 1;
|
|
}
|
|
e += s;
|
|
j++;
|
|
}
|
|
i++;
|
|
}
|
|
|
|
/* test if 'pos' is contained in the components of 'posgroup' */
|
|
if (grp != NULL) {
|
|
for (i = 0; !found && (i < grplen); i++) {
|
|
if (pos == grp[i]) {
|
|
found = TRUE;
|
|
}
|
|
}
|
|
|
|
/* just a way to test picoktab_getPosGroup */
|
|
/*
|
|
PICODBG_ASSERT(picoktab_getPosGroup(this, grp, grplen) == posgroup);
|
|
*/
|
|
}
|
|
|
|
return found;
|
|
}
|
|
|
|
|
|
picoos_uint8 picoktab_getPosGroup(const picoktab_Pos this,
|
|
const picoos_uint8 *poslist,
|
|
const picoos_uint8 poslistlen)
|
|
{
|
|
picoos_uint8 poscomb;
|
|
ktabpos_subobj_t *ktabpos;
|
|
picoos_uint16 i, j, n, s;
|
|
picoos_uint8 *e;
|
|
|
|
ktabpos = (ktabpos_subobj_t *) this;
|
|
poscomb = 0;
|
|
|
|
if ((poslistlen > 0) && (poslistlen <= PICOKTAB_MAXNRPOS_IN_COMB)) {
|
|
i = poslistlen - 1;
|
|
if (i > 0) {
|
|
n = ktabpos->nrcomb[i]; /* number of entries */
|
|
e = ktabpos->nrcombstart[i]; /* ptr to first entry */
|
|
s = i + 2; /* size of an entry in bytes */
|
|
j = 0;
|
|
while (!poscomb && (j < n)) {
|
|
if (ktab_isEqualPosGroup(poslist, e + 1, poslistlen)) {
|
|
poscomb = *e;
|
|
}
|
|
e += s;
|
|
j++;
|
|
}
|
|
if (!poscomb) {
|
|
/* combination not found; shouldn't occur if lingware OK! */
|
|
/* contingency solution: take first */
|
|
PICODBG_WARN(("dynamically created POS combination not found in table; taking first (%i)",poslist[0]));
|
|
poscomb = poslist[0];
|
|
}
|
|
} else { /* not a composed POS */
|
|
poscomb = poslist[0];
|
|
}
|
|
}
|
|
|
|
return poscomb;
|
|
}
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
|
|
/* end */
|