/*
* 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 */