touched up rex.c

This commit is contained in:
hyung-hwan 2010-05-11 07:15:55 +00:00
parent b0a03e0b4d
commit 57c56594a5
5 changed files with 282 additions and 245 deletions

View File

@ -1,5 +1,5 @@
/*
* $Id: lda.h 323 2010-04-05 12:50:01Z hyunghwan.chung $
* $Id: lda.h 327 2010-05-10 13:15:55Z hyunghwan.chung $
*
Copyright 2006-2009 Chung, Hyung-Hwan.
This file is part of QSE.
@ -344,16 +344,30 @@ void qse_lda_clear (
qse_lda_t* lda
);
void qse_lda_walk (
/**
* The qse_lda_walk() function calls the @a walker function for each
* element in the array beginning from the first. The @a walker function
* should return one of #QSE_LDA_WALK_FORWARD, #QSE_LDA_WALK_BACKWARD,
* #QSE_LDA_WALK_STOP.
* @return number of calls to the @a walker fucntion made
*/
qse_size_t qse_lda_walk (
qse_lda_t* lda,
qse_lda_walker_t walker,
void* arg
void* ctx
);
void qse_lda_rwalk (
/**
* The qse_lda_rwalk() function calls the @a walker function for each
* element in the array beginning from the last. The @a walker function
* should return one of #QSE_LDA_WALK_FORWARD, #QSE_LDA_WALK_BACKWARD,
* #QSE_LDA_WALK_STOP.
* @return number of calls to the @a walker fucntion made
*/
qse_size_t qse_lda_rwalk (
qse_lda_t* lda,
qse_lda_walker_t walker,
void* arg
void* ctx
);
/**

View File

@ -1,5 +1,5 @@
/*
* $Id: map.h 287 2009-09-15 10:01:02Z hyunghwan.chung $
* $Id: map.h 327 2010-05-10 13:15:55Z hyunghwan.chung $
*
Copyright 2006-2009 Chung, Hyung-Hwan.
This file is part of QSE.
@ -323,43 +323,32 @@ void qse_map_setscale (
);
/******/
/****f* Common/qse_map_getcopier
* NAME
* qse_map_getcopier - get a data copier
* PARAMETERS
* * id - QSE_MAP_KEY or QSE_MAP_VAL
* SYNOPSIS
/**
* The qse_map_getcopier() function gets a data copier.
*/
qse_map_copier_t qse_map_getcopier (
qse_map_t* map,
qse_map_id_t id
qse_map_id_t id /**< QSE_MAP_KEY or QSE_MAP_VAL */
);
/*****/
/****f* Common/qse_map_setcopier
* NAME
* qse_map_setcopier - specify how to clone an element
*
* DESCRIPTION
/**
* The qse_map_setcopier() function specifies how to clone an element.
* A special copier QSE_MAP_COPIER_INLINE is provided. This copier enables
* you to copy the data inline to the internal node. No freeer is invoked
* when the node is freeed.
*
* You may set the copier to QSE_NULL to perform no special operation
* when the data pointer is rememebered.
*
* SYNOPSIS
*/
void qse_map_setcopier (
qse_map_t* map /* a map */,
qse_map_id_t id /* QSE_MAP_KEY or QSE_MAP_VAL */,
qse_map_copier_t copier /* an element copier */
qse_map_t* map, /**< a map */
qse_map_id_t id, /**< QSE_MAP_KEY or QSE_MAP_VAL */
qse_map_copier_t copier /**< element copier */
);
/******/
qse_map_freeer_t qse_map_getfreeer (
qse_map_t* map /* a map */,
qse_map_id_t id /* QSE_MAP_KEY or QSE_MAP_VAL */
qse_map_t* map, /**< map */
qse_map_id_t id /**< QSE_MAP_KEY or QSE_MAP_VAL */
);
/**
@ -494,10 +483,10 @@ void qse_map_clear (
);
/* traverse a map */
void qse_map_walk (
qse_size_t qse_map_walk (
qse_map_t* map /* a map */,
qse_map_walker_t walker /* the pointer to the function for each pair */,
void* arg /* a pointer to user-specific data */
void* ctx /* a pointer to user-specific data */
);
/* get the pointer to the first pair in the map. */

View File

@ -1,5 +1,5 @@
/*
* $Id: lda.c 323 2010-04-05 12:50:01Z hyunghwan.chung $
* $Id: lda.c 327 2010-05-10 13:15:55Z hyunghwan.chung $
*
Copyright 2006-2009 Chung, Hyung-Hwan.
This file is part of QSE.
@ -514,59 +514,69 @@ void qse_lda_clear (lda_t* lda)
lda->size = 0;
}
void qse_lda_walk (lda_t* lda, walker_t walker, void* arg)
size_t qse_lda_walk (lda_t* lda, walker_t walker, void* ctx)
{
qse_lda_walk_t w = QSE_LDA_WALK_FORWARD;
size_t i = 0;
size_t i = 0, nwalks = 0;
if (lda->size <= 0) return;
if (lda->size <= 0) return 0;
while (1)
{
if (lda->node[i] != QSE_NULL)
w = walker (lda, i, arg);
{
w = walker (lda, i, ctx);
nwalks++;
}
if (w == QSE_LDA_WALK_STOP) return;
if (w == QSE_LDA_WALK_STOP) break;
if (w == QSE_LDA_WALK_FORWARD)
{
i++;
if (i >= lda->size) return;
if (i >= lda->size) break;
}
if (w == QSE_LDA_WALK_BACKWARD)
{
if (i <= 0) return;
if (i <= 0) break;
i--;
}
}
return nwalks;
}
void qse_lda_rwalk (lda_t* lda, walker_t walker, void* arg)
size_t qse_lda_rwalk (lda_t* lda, walker_t walker, void* ctx)
{
qse_lda_walk_t w = QSE_LDA_WALK_BACKWARD;
size_t i;
size_t i, nwalks = 0;
if (lda->size <= 0) return;
if (lda->size <= 0) return 0;
i = lda->size - 1;
while (1)
{
if (lda->node[i] != QSE_NULL)
w = walker (lda, i, arg);
{
w = walker (lda, i, ctx);
nwalks++;
}
if (w == QSE_LDA_WALK_STOP) return;
if (w == QSE_LDA_WALK_STOP) break;
if (w == QSE_LDA_WALK_FORWARD)
{
i++;
if (i >= lda->size) return;
if (i >= lda->size) break;
}
if (w == QSE_LDA_WALK_BACKWARD)
{
if (i <= 0) return;
if (i <= 0) break;
i--;
}
}
return nwalks;
}
size_t qse_lda_pushstack (lda_t* lda, void* dptr, size_t dlen)

View File

@ -1,5 +1,5 @@
/*
* $Id: map.c 289 2009-09-16 06:35:29Z hyunghwan.chung $
* $Id: map.c 327 2010-05-10 13:15:55Z hyunghwan.chung $
*
Copyright 2006-2009 Chung, Hyung-Hwan.
This file is part of QSE.
@ -572,9 +572,9 @@ void qse_map_clear (map_t* map)
}
void qse_map_walk (map_t* map, walker_t walker, void* arg)
size_t qse_map_walk (map_t* map, walker_t walker, void* arg)
{
size_t i;
size_t i, nwalks = 0;
pair_t* pair, * next;
for (i = 0; i < map->capa; i++)
@ -584,10 +584,14 @@ void qse_map_walk (map_t* map, walker_t walker, void* arg)
while (pair != QSE_NULL)
{
next = NEXT(pair);
if (walker(map, pair, arg) == QSE_MAP_WALK_STOP) return;
if (walker(map, pair, arg) == QSE_MAP_WALK_STOP)
return nwalks;
nwalks++;
pair = next;
}
}
return nwalks;
}
pair_t* qse_map_getfirstpair (map_t* map, size_t* buckno)

View File

@ -1,5 +1,5 @@
/*
* $Id: rex.c 326 2010-05-09 13:44:39Z hyunghwan.chung $
* $Id: rex.c 327 2010-05-10 13:15:55Z hyunghwan.chung $
*
Copyright 2006-2009 Chung, Hyung-Hwan.
This file is part of QSE.
@ -910,6 +910,36 @@ static qse_rex_node_t* comp_atom (comp_t* com)
return atom;
}
#if 0
static qse_rex_node_t* zero_or_more (comp_t* c, qse_rex_node_t* atom)
{
qse_rex_node_t* b;
b = newbranchnode (c, QSE_NULL, atom);
if (b == QSE_NULL) return QSE_NULL;
atom->occ.min = 1;
atom->occ.max = 1;
atom->next = b;
return b;
}
static qse_rex_node_t* one_or_more (comp_t* c, qse_rex_node_t* atom)
{
qse_rex_node_t* b;
b = newbranchnode (c, atom, QSE_NULL);
atom->occ.min = 1;
atom->occ.max = 1;
atom->next = b;
TODO: return b as the tail....
return atom;
}
#endif
static qse_rex_node_t* pseudo_group (comp_t* c, qse_rex_node_t* atom)
{
qse_rex_node_t* g, *ge, * b;
@ -962,20 +992,41 @@ static qse_rex_node_t* comp_branch (comp_t* c, pair_t* pair)
{
qse_rex_node_t* atom = comp_atom (c);
if (atom == QSE_NULL) return QSE_NULL;
if (atom->occ.min <= 0)
{
/*
* Given an atom, this function encloses it with a pseudogroup
* head and a psuedo-group tail. the pseudogroup head is
* followed by a branch that conntects to the pseudogroup tail
* and the atom given. The atom given gets connected to the
* pseudogroup tail.
* Head -> BR -> Tail
* -> ORG(atom) -> Tail
*/
atom = pseudo_group (c, atom);
#if 0
if (atom->occ.max >= OCC_MAX)
{
/*
* +-----------next--+
* v |
* BR --alter----> ORG(atom)
* |
* +----next------------------->
*
*/
atom = zero_or_more (c, atom);
}
else
{
#endif
/*
* Given an atom, enclose it with a
* pseudogroup head and a psuedogroup
* tail. the head is followed by a
* branch that conntects to the tail
* and the atom given. The atom given
* gets connected to the tail.
* Head -> BR -> Tail
* -> ORG(atom) -> Tail
*/
atom = pseudo_group (c, atom);
}
if (atom == QSE_NULL) return QSE_NULL;
#if 0
}
#endif
if (pair->tail == QSE_NULL)
{
@ -1340,22 +1391,21 @@ static int addcands (
exec_t* e, group_t* group, qse_rex_node_t* prevnode,
qse_rex_node_t* candnode, const qse_char_t* mptr)
{
qse_rex_node_t* curcand = candnode;
warpback:
#ifndef DONOT_SKIP_NOP
/* skip all NOP nodes */
while (candnode != QSE_NULL && candnode->id == QSE_REX_NODE_NOP)
candnode = candnode->next;
#endif
while (curcand != QSE_NULL && curcand->id == QSE_REX_NODE_NOP)
curcand = curcand->next;
/* nothing to add */
if (candnode == QSE_NULL) return 0;
if (curcand == QSE_NULL) return 0;
switch (candnode->id)
switch (curcand->id)
{
case QSE_REX_NODE_END:
{
/*qse_printf (QSE_T("== ADDING THE END(MATCH) NODE MEANING MATCH FOUND == \n"));*/
if (e->matchend == QSE_NULL || mptr >= e->matchend)
e->matchend = mptr;
e->nmatches++;
@ -1373,52 +1423,33 @@ warpback:
if (gx == QSE_NULL) return -1;
}
#if 0
refupgroupstack (group);
refupgroupstack (gx);
n = addcands (e, group,
prevnode, candnode->next, mptr);
if (n >= 0)
{
n = addcands (e, gx,
prevnode, candnode->u.b.alter, mptr);
}
refdowngroupstack (gx, e->rex->mmgr);
refdowngroupstack (group, e->rex->mmgr);
if (n <= -1) return -1;
break;
#endif
refupgroupstack (gx);
n = addcands (e, gx,
prevnode, candnode->u.b.alter, mptr);
prevnode, curcand->u.b.alter, mptr);
refdowngroupstack (gx, e->rex->mmgr);
if (n <= -1) return -1;
candnode = candnode->next;
curcand = curcand->next;
goto warpback;
}
case QSE_REX_NODE_GROUP:
{
int n;
qse_rex_node_t* front;
group_t* gx;
#ifdef XTRA_DEBUG
qse_printf (QSE_T("DEBUG: GROUP %p(pseudo=%d) PREV %p\n"),
candnode, candnode->u.g.pseudo, prevnode);
curcand, curcand->u.g.pseudo, prevnode);
#endif
if (candnode->u.g.pseudo)
if (curcand->u.g.pseudo)
{
candnode = candnode->u.g.head;
curcand = curcand->u.g.head;
goto warpback;
}
/* skip all NOP nodes */
front = candnode->u.g.head;
front = curcand->u.g.head;
while (front->id == QSE_REX_NODE_NOP)
front = front->next;
@ -1429,22 +1460,18 @@ warpback:
* regardless of its occurrence.
* however, this will never be reached
* as it has been removed in comp() */
candnode = candnode->next;
curcand = curcand->next;
goto warpback;
}
gx = groupstackpush (e, group, candnode);
gx = groupstackpush (e, group, curcand);
if (gx == QSE_NULL) return -1;
/* add the first node in the group to
* the candidate array */
refupgroupstack (gx);
n = addcands (e, gx, prevnode, front, mptr);
refdowngroupstack (gx, e->rex->mmgr);
if (n <= -1) return -1;
break;
group = gx;
curcand = front;
goto warpback;
}
case QSE_REX_NODE_GROUPEND:
@ -1456,12 +1483,12 @@ warpback:
#ifdef XTRA_DEBUG
qse_printf (QSE_T("DEBUG: GROUPEND %p(pseudo=%d) PREV %p\n"),
candnode, candnode->u.ge.pseudo, prevnode);
curcand, curcand->u.ge.pseudo, prevnode);
#endif
if (candnode->u.ge.pseudo)
if (curcand->u.ge.pseudo)
{
candnode = candnode->u.ge.group->next;
curcand = curcand->u.ge.group->next;
goto warpback;
}
@ -1469,7 +1496,7 @@ warpback:
group != QSE_NULL && group->next != QSE_NULL,
"GROUPEND must be paired up with GROUP");
if (prevnode == candnode)
if (prevnode == curcand)
{
/* consider a pattern like (x*)*.
* when GROUPEND is reached, an 'if' block
@ -1488,7 +1515,7 @@ warpback:
occ = top->occ;
node = top->node;
QSE_ASSERTX (node == candnode->u.ge.group,
QSE_ASSERTX (node == curcand->u.ge.group,
"The GROUP node in the group stack must be the "
"one pairing up with the GROUPEND node."
);
@ -1539,7 +1566,7 @@ warpback:
prevnode->id == QSE_REX_NODE_GROUPEND)
n = addcands (e, gx, prevnode, node->next, mptr);
else
n = addcands (e, gx, candnode, node->next, mptr);
n = addcands (e, gx, curcand, node->next, mptr);
refdowngroupstack (gx, e->rex->mmgr);
if (n <= -1) return -1;
@ -1548,18 +1575,9 @@ warpback:
if (occ < node->occ.max)
{
/* repeat itself. */
/* BEGIN avoid recursion */
#if 0
refupgroupstack (group);
n = addcands (e, group, prevnode, node->u.g.head, mptr);
refdowngroupstack (group, e->rex->mmgr);
if (n <= -1) return -1;
#endif
prevnode = candnode;
candnode = node->u.g.head;
prevnode = curcand;
curcand = node->u.g.head;
goto warpback;
/* END avoid recursion */
}
break;
@ -1570,7 +1588,7 @@ warpback:
int n;
if (group) refupgroupstack (group);
n = addsimplecand (e, group, candnode, 1, mptr);
n = addsimplecand (e, group, curcand, 1, mptr);
if (group) refdowngroupstack (group, e->rex->mmgr);
if (n <= -1) return -1;
@ -1664,152 +1682,142 @@ static int charset_matched (exec_t* e, qse_rex_node_t* node, qse_char_t c)
return matched;
}
static int match (exec_t* e)
static qse_lda_walk_t walk_cands_for_match (
qse_lda_t* lda, qse_size_t index, void* ctx)
{
qse_size_t i;
exec_t* e = (exec_t*)ctx;
cand_t* cand = QSE_LDA_DPTR(lda,index);
qse_rex_node_t* node = cand->node;
const qse_char_t* nmptr = QSE_NULL;
QSE_ASSERT (QSE_LDA_SIZE(&e->cand.set[e->cand.active]) > 0);
for (i = 0; i < QSE_LDA_SIZE(&e->cand.set[e->cand.active]); i++)
switch (node->id)
{
cand_t* cand = QSE_LDA_DPTR(&e->cand.set[e->cand.active],i);
qse_rex_node_t* node = cand->node;
const qse_char_t* nmptr = QSE_NULL;
switch (node->id)
{
#ifdef DONOT_SKIP_NOP
case QSE_REX_NODE_NOP:
case QSE_REX_NODE_BOL:
if (cand->mptr == e->str.ptr)
{
/* the next match pointer remains
* the same as ^ matches a position,
* not a character. */
nmptr = cand->mptr;
break;
#endif
#ifdef XTRA_DEBUG
qse_printf (QSE_T("DEBUG: matched <^>\n"));
#endif
}
break;
case QSE_REX_NODE_BOL:
if (cand->mptr == e->str.ptr)
{
/* the next match pointer remains
* the same as ^ matches a position,
* not a character. */
nmptr = cand->mptr;
#ifdef XTRA_DEBUG
qse_printf (QSE_T("DEBUG: matched <^>\n"));
#endif
}
break;
case QSE_REX_NODE_EOL:
if (cand->mptr >= e->str.end)
{
/* the next match pointer remains
* the same as $ matches a position,
* not a character. */
nmptr = cand->mptr;
#ifdef XTRA_DEBUG
qse_printf (QSE_T("DEBUG: matched <$>\n"));
#endif
}
break;
case QSE_REX_NODE_EOL:
if (cand->mptr >= e->str.end)
{
/* the next match pointer remains
* the same as $ matches a position,
* not a character. */
nmptr = cand->mptr;
#ifdef XTRA_DEBUG
qse_printf (QSE_T("DEBUG: matched <$>\n"));
#endif
}
break;
case QSE_REX_NODE_ANY:
if (cand->mptr < e->sub.end)
{
/* advance the match pointer to the
* next chracter.*/
nmptr = cand->mptr + 1;
#ifdef XTRA_DEBUG
qse_printf (QSE_T("DEBUG: matched <.>\n"));
#endif
}
break;
case QSE_REX_NODE_ANY:
if (cand->mptr < e->sub.end)
case QSE_REX_NODE_CHAR:
{
if (cand->mptr < e->sub.end)
{
int equal;
equal =(e->rex->option & QSE_REX_IGNORECASE)?
(QSE_TOUPPER(node->u.c) == QSE_TOUPPER(*cand->mptr)):
(node->u.c == *cand->mptr) ;
if (equal)
{
/* advance the match pointer to the
* next chracter.*/
nmptr = cand->mptr + 1;
#ifdef XTRA_DEBUG
qse_printf (QSE_T("DEBUG: matched <.>\n"));
#endif
}
break;
case QSE_REX_NODE_CHAR:
{
if (cand->mptr < e->sub.end)
{
int equal;
equal =(e->rex->option & QSE_REX_IGNORECASE)?
(QSE_TOUPPER(node->u.c) == QSE_TOUPPER(*cand->mptr)):
(node->u.c == *cand->mptr) ;
if (equal)
{
/* advance the match pointer to the
* next chracter.*/
nmptr = cand->mptr + 1;
}
#ifdef XTRA_DEBUG
qse_printf (QSE_T("DEBUG: matched %c\n"), node->u.c);
#endif
}
break;
}
case QSE_REX_NODE_CSET:
{
if (cand->mptr < e->sub.end &&
charset_matched(e, node, *cand->mptr))
{
/* advance the match pointer
* to the next chracter.*/
nmptr = cand->mptr + 1;
}
break;
}
default:
{
QSE_ASSERTX (0,
"SHOUL NEVER HAPPEN - node ID must be"
"one of QSE_REX_NODE_BOL, "
"QSE_REX_NODE_EOL, "
"QSE_REX_NODE_ANY, "
"QSE_REX_NODE_CHAR, "
"QSE_REX_NODE_CSET, "
"QSE_REX_NODE_NOP");
break;
#ifdef XTRA_DEBUG
qse_printf (QSE_T("DEBUG: matched %c\n"), node->u.c);
#endif
}
break;
}
if (nmptr != QSE_NULL)
case QSE_REX_NODE_CSET:
{
int n;
if (cand->occ >= node->occ.min)
if (cand->mptr < e->sub.end &&
charset_matched(e, node, *cand->mptr))
{
group_t* gx;
if (cand->occ < node->occ.max && cand->group != QSE_NULL)
{
gx = dupgroupstack (e, cand->group);
if (gx == QSE_NULL) return -1;
}
else gx = cand->group;
/* move on to the next candidate */
refupgroupstack (gx);
n = addcands (e, gx, node, node->next, nmptr);
refdowngroupstack (gx, e->rex->mmgr);
if (n <= -1) return -1;
/* advance the match pointer
* to the next chracter.*/
nmptr = cand->mptr + 1;
}
if (cand->occ < node->occ.max)
{
/* repeat itself more */
refupgroupstack (cand->group);
n = addsimplecand (e, cand->group, node, cand->occ+1, nmptr);
refdowngroupstack (cand->group, e->rex->mmgr);
break;
}
if (n <= -1) return -1;
}
default:
{
QSE_ASSERTX (0,
"SHOULD NEVER HAPPEN - node ID must be"
"one of QSE_REX_NODE_BOL, "
"QSE_REX_NODE_EOL, "
"QSE_REX_NODE_ANY, "
"QSE_REX_NODE_CHAR, "
"QSE_REX_NODE_CSET, "
"QSE_REX_NODE_NOP");
break;
}
}
return 0;
if (nmptr != QSE_NULL)
{
int n;
if (cand->occ >= node->occ.min)
{
group_t* gx;
if (cand->occ < node->occ.max && cand->group != QSE_NULL)
{
gx = dupgroupstack (e, cand->group);
if (gx == QSE_NULL) return QSE_LDA_WALK_STOP;
}
else gx = cand->group;
/* move on to the next candidate */
refupgroupstack (gx);
n = addcands (e, gx, node, node->next, nmptr);
refdowngroupstack (gx, e->rex->mmgr);
if (n <= -1) return QSE_LDA_WALK_STOP;
}
if (cand->occ < node->occ.max)
{
/* repeat itself more */
refupgroupstack (cand->group);
n = addsimplecand (
e, cand->group,
node, cand->occ + 1, nmptr);
refdowngroupstack (cand->group, e->rex->mmgr);
if (n <= -1) return QSE_LDA_WALK_STOP;
}
}
return QSE_LDA_WALK_FORWARD;
}
static int exec (exec_t* e)
@ -1828,7 +1836,7 @@ static int exec (exec_t* e)
/* the first node must be the START node */
QSE_ASSERT (e->rex->code->id == QSE_REX_NODE_START);
/* addcands() collects a set of candidates into the pending set */
/* collect an initial set of candidates into the pending set */
n = addcands (
e, /* execution structure */
QSE_NULL, /* doesn't belong to any groups yet */
@ -1840,6 +1848,8 @@ static int exec (exec_t* e)
do
{
qse_size_t ncands_active;
/* swap the pending and active set indices.
* the pending set becomes active after which the match()
* function tries each candidate in it. New candidates
@ -1849,7 +1859,8 @@ static int exec (exec_t* e)
e->cand.pending = e->cand.active;
e->cand.active = tmp;
if (QSE_LDA_SIZE(&e->cand.set[e->cand.active]) <= 0)
ncands_active = QSE_LDA_SIZE(&e->cand.set[e->cand.active]);
if (ncands_active <= 0)
{
/* we can't go on with no candidates in the
* active set. */
@ -1863,7 +1874,7 @@ static int exec (exec_t* e)
{
int i;
qse_printf (QSE_T("SET="));
for (i = 0; i < QSE_LDA_SIZE(&e->cand.set[e->cand.active]); i++)
for (i = 0; i < ncands_active; i++)
{
cand_t* cand = QSE_LDA_DPTR(&e->cand.set[e->cand.active],i);
qse_rex_node_t* node = cand->node;
@ -1881,7 +1892,15 @@ static int exec (exec_t* e)
}
#endif
if (match (e) <= -1) return -1;
if (qse_lda_walk (
&e->cand.set[e->cand.active],
walk_cands_for_match, e) != ncands_active)
{
/* if the number of walks is different the number of
* candidates, traversal must have been aborted for
* an error. */
return -1;
}
}
while (1);
@ -1910,6 +1929,7 @@ static int comp_cand (qse_lda_t* lda,
{
cand_t* c1 = (cand_t*)dptr1;
cand_t* c2 = (cand_t*)dptr2;
//qse_printf (QSE_T("%p(%d) %p(%d), %p %p, %d %d\n"), c1->node,c1->node->id, c2->node,c1->node->id, c1->mptr, c2->mptr, (int)c1->occ, (int)c2->occ);
return (c1->node == c2->node &&
c1->mptr == c2->mptr &&
c1->occ == c2->occ)? 0: 1;