[update] automate can contain himself (pointer) and browse to it

[todo] manage case where you have to go backwards into self (included self automate)
This commit is contained in:
xdrm-brackets 2017-05-17 08:54:15 +02:00
parent bae568e3f5
commit a92714a289
3 changed files with 258 additions and 107 deletions

View File

@ -11,29 +11,45 @@
struct AutomateContext getContext(const char pDot, const char pPath, const unsigned int pIndex){
struct AutomateContext rtn;
unsigned int browse(struct Automate* pAutomate, const char* pString, const char pDepth){
rtn.dot = pDot;
rtn.path = pPath;
rtn.index = pIndex;
printf("%s>>> [browsing %s]\n", pad(pDepth), pAutomate->name);
return rtn;
}
unsigned int browse(struct Automate* pAutomate, const char* pString, struct AutomateContext* pCtx, unsigned int* pStep){
printf(">>> [browsing %s]\n", pAutomate->name);
/* [0] Initialize variables
=========================================================*/
unsigned int strIndex = 0; // String current char index
unsigned int recursive;
unsigned int c, len, i, l, a, A; // counters
char* buffer = malloc(1);
char* ptr = NULL;
struct AutomateDot dotPtr;
char* ptr = NULL;
char* buffer = malloc(1);
unsigned int recursive = 0;
char* pathmem = malloc( sizeof(char) ); // will contain edge number for each dot
unsigned int* indexmem = malloc( sizeof(unsigned int) ); // will contain offset of @pString for each dot
char* dotmem = malloc( sizeof(char) );
pAutomate->path = realloc(pAutomate->path, 1 );
unsigned int foreignStep = 0;
struct AutomateContext* foreignCtx = malloc( sizeof(struct AutomateContext) );
foreignCtx[0] = getContext(0, 0, 0);
struct Automate* aPtr = NULL;
pCtx = realloc(pCtx, sizeof(struct AutomateContext) * (*pStep+1) );
/* [1] merge automates
=========================================================*/
while( pAutomate->aedges > 0 )
mergeAutomate(pAutomate, pAutomate->aedges-1);
if( pAutomate->aedges > 0 )
for( l = pAutomate->aedges-1 ; l > 0 ; l-- )
mergeAutomate(pAutomate, l);
@ -42,35 +58,26 @@ unsigned int browse(struct Automate* pAutomate, const char* pString, const char
/* [2] For each char
=========================================================*/
c = 0;
len = strlen(pString);
buffer = realloc(buffer, len+1);
pAutomate->dCurrent = 0;
pAutomate->steps = 0;
c = *pStep;
pAutomate->dCurrent = pCtx[c].dot;
strIndex = pCtx[c].index;
/* (1) For each char try to match
---------------------------------------------------------*/
c = 0;
strIndex = 0;
pathmem[0] = 0;
pAutomate->path[0] = 0;
while( pAutomate->dCurrent != pAutomate->dFinal && strIndex <= len ){
pAutomate->steps++;
(ADB&&0x01) && printf("%s\b * step %d (remaining '%s')\n", pad(pDepth), pAutomate->steps, pString+strIndex);
/* (2) Initialize local data
---------------------------------------------------------*/
/* (1) Check current state choices */
dotmem[c] = pAutomate->dCurrent;
dotPtr = pAutomate->dot[dotmem[c]];
i = ( indexmem[c] == strIndex ) ? pathmem[c] : 0;
// indexmem[c] = strIndex;
pCtx[c].dot = pAutomate->dCurrent;
dotPtr = pAutomate->dot[pCtx[c].dot];
i = ( pCtx[c].index == strIndex ) ? pCtx[c].path : 0;
l = dotPtr.n;
@ -86,16 +93,16 @@ unsigned int browse(struct Automate* pAutomate, const char* pString, const char
/* (1) If STRING match */
if( dotPtr.type[i] == DIRECT_T ){
(ADB&&0x01) && printf("%s> q%d --d0--> q%d ?\n", pad(pDepth+1), dotmem[c], dotPtr.dot[i]);
(ADB&&0x01) && printf("> q%d --d0--> q%d ?\n", pCtx[c].dot, dotPtr.dot[i]);
pAutomate->dCurrent = dotPtr.dot[i];
pathmem[c] = i;
pCtx[c].path = i;
break;
/* (2) If STRING match */
}else if( dotPtr.type[i] == STRING_T ){
(ADB&&0x01) && printf("%s> q%d --s%d--> q%d ?\n", pad(pDepth+1), dotmem[c], dotPtr.edge[i], dotPtr.dot[i]);
(ADB&&0x01) && printf("> q%d --s%d--> q%d ?\n", pCtx[c].dot, dotPtr.edge[i], dotPtr.dot[i]);
ptr = pAutomate->sedge[dotPtr.edge[i]];
strncpy(buffer, pString+strIndex, strlen(ptr));
@ -104,28 +111,28 @@ unsigned int browse(struct Automate* pAutomate, const char* pString, const char
if( strcmp(buffer, ptr) == 0 ){
pAutomate->dCurrent = dotPtr.dot[i];
strIndex += strlen(ptr);
pathmem[c] = i;
pCtx[c].path = i;
break;
}
/* (3) If RANGE match */
}else if( dotPtr.type[i] == RANGE_T ){
(ADB&&0x01) && printf("%s> q%d --r%d--> q%d ?\n", pad(pDepth+1), dotmem[c], dotPtr.edge[i], dotPtr.dot[i]);
(ADB&&0x01) && printf("> q%d --r%d--> q%d ?\n", pCtx[c].dot, dotPtr.edge[i], dotPtr.dot[i]);
ptr = pAutomate->redge[dotPtr.edge[i]];
if( pString[strIndex] >= ptr[0] && pString[strIndex] <= ptr[1] ){
pAutomate->dCurrent = dotPtr.dot[i];
strIndex += 1;
pathmem[c] = i;
pCtx[c].path = i;
break;
}
/* (4) If LIST match */
}else if( dotPtr.type[i] == LIST_T ){
(ADB&&0x01) && printf("%s> q%d --l%d--> q%d ?\n", pad(pDepth+1), dotmem[c], dotPtr.edge[i], dotPtr.dot[i]);
(ADB&&0x01) && printf("> q%d --l%d--> q%d ?\n", pCtx[c].dot, dotPtr.edge[i], dotPtr.dot[i]);
ptr = pAutomate->ledge[dotPtr.edge[i]];
@ -139,24 +146,47 @@ unsigned int browse(struct Automate* pAutomate, const char* pString, const char
if( a < A ){
pAutomate->dCurrent = dotPtr.dot[i];
strIndex += 1;
pathmem[c] = i;
pCtx[c].path = i;
break;
}
/* (5) If AUTOMATE match */
}else if( dotPtr.type[i] == AUTOMATE_T ){
(ADB&&0x01) && printf("%s> q%d --a%d--> q%d ?\n", pad(pDepth+1), dotmem[c], dotPtr.edge[i], dotPtr.dot[i]);
(ADB&&0x01) && printf("> q%d --a%d--> q%d ?\n", pCtx[c].dot, dotPtr.edge[i], dotPtr.dot[i]);
aPtr = pAutomate->aedge[dotPtr.edge[i]];
recursive = browse(&pAutomate->aedge[dotPtr.edge[i]], pString+strIndex, pDepth+1);
foreignStep = 0;
foreignCtx = realloc(foreignCtx, sizeof(struct AutomateContext));
foreignCtx[0] = getContext(0, 0, 0);
if( pAutomate->aedge[dotPtr.edge[i]].steps > 0 )
pAutomate->steps += pAutomate->aedge[dotPtr.edge[i]].steps-1;
while( foreignStep != 0 || foreignCtx[foreignStep].path < aPtr->dot[foreignCtx[foreignStep].dot].n ){
if( pAutomate->aedge[dotPtr.edge[i]].dCurrent == pAutomate->aedge[dotPtr.edge[i]].dFinal ){
pAutomate->dCurrent = dotPtr.dot[i];
// printf("browse start -> index: '%s'\n", pString+strIndex);
recursive = browse(aPtr, pString+strIndex, foreignCtx, &foreignStep);
// printf("browsed end -> index: %d/%d - state: %d/%d\n", recursive, (int)strlen(pString+strIndex), aPtr->dCurrent, aPtr->dFinal);
// If correct -> exit from while()
if( aPtr->dCurrent == aPtr->dFinal )
break;
// If have to go backwards
if( recursive == foreignCtx[foreignStep].index && foreignCtx[foreignStep].dot == aPtr->dCurrent && i >= l ){
// {1} if not first branch -> go previous //
if( foreignStep > 0 )
foreignStep--;
// {2} else next path of previous branch //
foreignCtx[foreignStep].path++;
foreignCtx = realloc(foreignCtx, sizeof(struct AutomateContext) * (foreignStep+1) );
}
}
if( aPtr->dCurrent == aPtr->dFinal ){
pCtx[c].path = i;
strIndex += recursive;
pathmem[c] = i;
pAutomate->dCurrent = dotPtr.dot[i];
break;
}
@ -168,36 +198,30 @@ unsigned int browse(struct Automate* pAutomate, const char* pString, const char
/* (4) Next dot or previous if locked
---------------------------------------------------------*/
/* (1) If no char procesed && same dot && no action performed */
if( strIndex == indexmem[c] && dotmem[c] == pAutomate->dCurrent && i >= l ){
if( strIndex == pCtx[c].index && pCtx[c].dot == pAutomate->dCurrent && i >= l ){
// {1} if not first branch -> go previous //
if( c > 0 )
c--;
// {2} else next path of previous branch //
strIndex = indexmem[c];
pathmem[c]++;
pAutomate->dCurrent = dotmem[c];
(ADB&&0x01) && printf("%s< not\n", pad(pDepth+1));
(ADB&&0x01) && printf("%s* back to q%d:%d\n", pad(pDepth+1), dotmem[c], pathmem[c]);
strIndex = pCtx[c].index;
pCtx[c].path++;
pAutomate->dCurrent = pCtx[c].dot;
(ADB&&0x01) && printf("< not\n");
(ADB&&0x01) && printf("* back to q%d:%d\n", pCtx[c].dot, pCtx[c].path);
pCtx = realloc(pCtx, sizeof(struct AutomateContext) * (c+1) );
/* (2) Next branch + reset data (if already browsed in other path) */
}else{
(ADB&&0x01) && printf("%s< yes\n", pad(pDepth+1));
(ADB&&0x01) && printf("< yes\n");
c++;
pathmem = realloc(pathmem, sizeof(char) * (c+1) );
indexmem = realloc(indexmem, sizeof(unsigned int) * (c+1) );
dotmem = realloc(dotmem, sizeof(char) * (c+1) );
pCtx = realloc(pCtx, sizeof(struct AutomateContext) * (c+1) );
pAutomate->n = c;
pAutomate->path = realloc(pAutomate->path, sizeof(char) * (c+1) );
pAutomate->path[c] = pAutomate->dCurrent;
indexmem[c] = strIndex;
pathmem[c] = 0;
pCtx[c].index = strIndex;
pCtx[c].path = 0;
}
@ -207,14 +231,17 @@ unsigned int browse(struct Automate* pAutomate, const char* pString, const char
ptr = NULL;
free(buffer);
free(pathmem);
free(indexmem);
free(dotmem);
free(foreignCtx);
(ADB&&0x01) && printf("%s>>> [done %s = %d/%d]\n", pad(pDepth), pAutomate->name, pAutomate->dCurrent, pAutomate->dFinal);
(ADB&&0x01) && printf(">>> [done %s = %d/%d]\n", pAutomate->name, pAutomate->dCurrent, pAutomate->dFinal);
*pStep = ( c == *pStep ) ? *pStep : c-1;
if( strIndex == 0 )
return 0;
else
return strIndex;
}
@ -326,7 +353,7 @@ void debug(const struct Automate pAutomate){
else if( pAutomate.dot[a].type[b] == RANGE_T )
printf(" * q%d match range '%s'\n", pAutomate.dot[a].dot[b], pAutomate.redge[pAutomate.dot[a].edge[b]]);
else if( pAutomate.dot[a].type[b] == AUTOMATE_T )
printf(" * q%d match automate '%s'\n", pAutomate.dot[a].dot[b], pAutomate.aedge[pAutomate.dot[a].edge[b]].name);
printf(" * q%d match automate '%s'\n", pAutomate.dot[a].dot[b], ((struct Automate*)pAutomate.aedge[pAutomate.dot[a].edge[b]])->name);
}
@ -360,8 +387,6 @@ struct Automate createAutomate(const char* pName){
automate.dCurrent = 0;
automate.dFinal = 0;
automate.n = 0;
/* [2] First allocation
=========================================================*/
automate.dot = malloc( 0 );
@ -369,7 +394,6 @@ struct Automate createAutomate(const char* pName){
automate.redge = malloc( 0 );
automate.ledge = malloc( 0 );
automate.aedge = malloc( 0 );
automate.path = malloc( 0 );
automate.name = malloc( strlen(pName) + 1 );
strcpy(automate.name, pName);
@ -380,11 +404,83 @@ struct Automate createAutomate(const char* pName){
}
void mergeAutomate(struct Automate* pMaster, const char pSlaveIndex){
void destroyAutomate(struct Automate* pAutomate){
/* [0] Initialize variables
=========================================================*/
char d, e;
/* [1] Destroy edges
=========================================================*/
/* (1) String Edges
---------------------------------------------------------*/
for( e = 0 ; e < pAutomate->sedges ; e++ )
free(pAutomate->sedge[e]);
free(pAutomate->sedge);
/* (2) List Edges
---------------------------------------------------------*/
for( e = 0 ; e < pAutomate->ledges ; e++ )
free(pAutomate->ledge[e]);
free(pAutomate->ledge);
/* (3) Range Edges
---------------------------------------------------------*/
for( e = 0 ; e < pAutomate->redges ; e++ )
free(pAutomate->redge[e]);
free(pAutomate->redge);
/* (4) Automate Edges
---------------------------------------------------------*/
free(pAutomate->aedge);
/* [2] Destroy dots
=========================================================*/
for( d = 0 ; d < pAutomate->dots ; d++ ){
free(pAutomate->dot[d].type);
free(pAutomate->dot[d].dot);
free(pAutomate->dot[d].edge);
free(&pAutomate->dot[d]);
}
free(pAutomate->dot);
/* [3] Destroy main pointer
=========================================================*/
free(pAutomate);
}
char mergeAutomate(struct Automate* pMaster, const char pSlaveIndex){
/* (1) If no such @pSlave -> abort */
if( pSlaveIndex >= pMaster->aedges ){
(ADB&0x01) && printf(" (!) merge error: no such slave automate\n");
return 0;
}
/* (2) If @pSlave == @pMaster -> do not do anything */
if( pMaster->aedge[pSlaveIndex] == pMaster ){
(ADB&0x01) && printf(" (!) merge error: slave is master\n");
return 0;
}
/* [0] Initialize variables
=========================================================*/
char a, d, e, dot, edge, edges, dotOffset, rtn, next_dot;
int sub;
char sedges = pMaster->sedges;
char ledges = pMaster->ledges;
@ -392,14 +488,18 @@ void mergeAutomate(struct Automate* pMaster, const char pSlaveIndex){
char aedges = pMaster->aedges;
char dots = pMaster->dots;
char final = pMaster->dFinal;
struct Automate* pSlave = &pMaster->aedge[pSlaveIndex];
struct Automate* pSlave = pMaster->aedge[pSlaveIndex];
while( pSlave->aedges > 0 )
mergeAutomate(pSlave, pSlave->aedges-1);
/* [1] Merge automates recursively
=========================================================*/
if( pSlave->aedges > 1 )
for( sub = pSlave->aedges-1 ; sub >= 0 ; sub-- )
if( sub != pSlaveIndex )
mergeAutomate(pMaster->aedge[pSlaveIndex], sub);
/* [1] Merge @pSlave edges into @pMaster edges
/* [2] Merge @pSlave edges into @pMaster edges
=========================================================*/
/* (1) String edges (sedges) */
for( a = 0 ; a < pSlave->sedges ; a++ ){
@ -421,12 +521,12 @@ void mergeAutomate(struct Automate* pMaster, const char pSlaveIndex){
/* (4) Automate edges (aedges) */
for( a = 0 ; a < pSlave->aedges ; a++ ){
rtn = addAutomateTransition(pMaster, &pSlave->aedge[a]);
rtn = addAutomateTransition(pMaster, pSlave->aedge[a]);
(ADB&0x01) && printf("merge SLAVE.automate.%d into MASTER.automate.%d\n", a, rtn) ;
}
/* [2] For each use of @pSlave in pMaster, replace
/* [3] For each use of @pSlave in pMaster, replace
=========================================================*/
/* (1) For each fot of @pMaster */
for( dot = 0 ; dot < dots ; dot++ ){
@ -493,10 +593,22 @@ void mergeAutomate(struct Automate* pMaster, const char pSlaveIndex){
}
/* [3] Clean @pMaster
/* [4] Clean @pMaster
=========================================================*/
/* (1) Remove @pSlave form @pMaster */
pMaster->aedge = realloc(pMaster->aedge, sizeof(struct Automate) * --pMaster->aedges);
// {1} Destroy @pSlave //
destroyAutomate(pMaster->aedge[pSlaveIndex]);
// {2} Shift back next automates //
for( d = pSlaveIndex+1 ; d < pMaster->aedges ; d++ )
memcpy(&pMaster->aedge[d-1], &pMaster->aedge[d], sizeof(struct Automate));
// {3} Decrement automate edges count //
pMaster->aedges--;
// {4} Free last automate //
pMaster->aedge = realloc(pMaster->aedge, sizeof(struct Automate) * pMaster->aedges);
/* (2) Keep old @pMaster.dFinal */
(ADB&&0x01) && printf("restauring final to %d\n", final);
@ -505,6 +617,8 @@ void mergeAutomate(struct Automate* pMaster, const char pSlaveIndex){
(ADB&0x01) && printf("SLAVE.%s successfully merged into MASTER.%s\n\n", pSlave->name, pMaster->name) ;
return 1;
}
@ -602,12 +716,12 @@ char addAutomateTransition(struct Automate* pAutomate, struct Automate* pAedge){
/* [1] Reallocate memory for aedge
=========================================================*/
pAutomate->aedge = realloc(pAutomate->aedge, sizeof(struct Automate) * pAutomate->aedges );
pAutomate->aedge = realloc(pAutomate->aedge, sizeof(void*) * pAutomate->aedges );
/* [2] Create the aedge
=========================================================*/
memcpy(&pAutomate->aedge[index], pAedge, sizeof(struct Automate));
pAutomate->aedge[index] = pAedge;
return index;
}

View File

@ -24,7 +24,13 @@
} AutomateType;
#define ADB 0x00
#define ADB 0x01
struct AutomateContext{
char dot;
char path;
unsigned int index;
};
struct AutomateDot{
char n; // number of edges
@ -44,31 +50,40 @@
char** sedge; // string edges
char** redge; // range edges (between char[0] and char[1])
char** ledge; // list edges (in one of the given char-s)
struct Automate* aedge; // automate edges
void** aedge; // automate (pointer) edges
char dCurrent; // current dot index
char dFinal; // final dot index
unsigned int steps; // number of steps
char* name; // automate name
char* path; // automate path
unsigned int n; // automate path length
};
/* Creates an automate context
*
* @dot<char> Current
* @path<char> Current min path
* @index<unsigned int> Current stirng index
*
* @return context<struct AutomateContext> The created context
*
*/
struct AutomateContext getContext(const char pDot, const char pPath, const unsigned int pIndex);
/* Try to browse an automate with a string
*
* @pAutomate<struct Automate*> Current working automate
* @pString<const char*> String to test
* @pDepth<const char> Padding
* @pCtx<struct AutomateContext*> Already browsed context
*
* @return offset<int> The @pString offset browsed to
*
* @NOTE: Automate.dCurrent is equal to Automate.dFinal if final state reached
*
*/
unsigned int browse(struct Automate* pAutomate, const char* pString, const char pDepth);
unsigned int browse(struct Automate* pAutomate, const char* pString, struct AutomateContext* pCtx, unsigned int* pStep);
/* Builds an automate from a regexp
@ -95,14 +110,22 @@
*/
struct Automate createAutomate(const char* pName);
/* Destroys an automate
*
* @pAutomate<struct Automate*> Automate pointer
*
*/
void destroyAutomate(struct Automate* pAutomate);
/* Merges an automate into another
*
* @pMaster<struct Automate*> Master automate that contains @pSlave
* @pSlaveIndex<const char> Slave automate index into @pMaster
*
* @return status<char> 1 on success ; 0 on failure
*
*/
void mergeAutomate(struct Automate* pMaster, const char pSlaveIndex);
char mergeAutomate(struct Automate* pMaster, const char pSlaveIndex);
/* Adds a dot to an automate

View File

@ -104,23 +104,37 @@ int main(int argc, char* argv[]){
linkDots(&array, 1, 3, AUTOMATE_T, 0); // q1 --a0--> q3
linkDots(&array, 1, 3, STRING_T, 1); // q1 --s1--> q3
char str[80] = {0};
strcpy(str, "[null, \"abc\", \"def\", false, true, 12, -1.2, .54, -.3, 5., \"bla\\\"blo\\rbla\\n\"]\0");
clock_t start, stop;
unsigned int browsed = 0;
start = clock(); browsed = browse(&array, str, 0); stop = clock();
printf("browse '%s': %d/%d\n", str, browsed, (int) strlen(str));
printf(" (*) final_state: %d/%d\n", array.dCurrent, array.dFinal);
printf(" (*) in %d steps\n", array.steps);
struct Automate test = createAutomate("test");
addDot(&test); // q0
addDot(&test); // q1
addDot(&test); // q2
addDot(&test); // q3
addStringTransition(&test, "a\0"); // s0
addStringTransition(&test, "b\0"); // s0
addAutomateTransition(&test, &test); // a1
linkDots(&test, 0, 1, STRING_T, 0); // q0 --s0--> q1
linkDots(&test, 1, 2, AUTOMATE_T, 0); // q1 --s0--> q2
linkDots(&test, 1, 2, DIRECT_T, 1); // q1 --d0--> q2
linkDots(&test, 2, 3, STRING_T, 1); // q1 --s1--> q2
debug(test);
char str[80] = {0};
clock_t start, stop;
unsigned int step = 0;
struct AutomateContext* ctx = malloc( sizeof(struct AutomateContext) * 1 );
ctx[0] = getContext(0, 0, 0);
strcpy(str, "aaabbb\0");
start = clock();
unsigned int browsed = browse(&test, str, ctx, &step); stop = clock();
// printf("browse '%s': %d/%d\n", str, ctx[step].index, (int) strlen(str));
printf(" (*) final_state: %d/%d\n", test.dCurrent, test.dFinal);
printf(" (*) read: %d/%d\n", browsed, (int)strlen(str));
printf(" (*) in %.3lf seconds\n\n", (double)(stop-start)/CLOCKS_PER_SEC);
for( c = 0 ; c < array.n ; c++ ){
if( c > 0 )
printf(" -> ");
printf("q%d", array.path[c]);
}
printf("\n");
exit(0);
/* Build RegExp */