diff --git a/src/lib/automate/automate.c b/src/lib/automate/automate.c index 4461017..485ebb0 100644 --- a/src/lib/automate/automate.c +++ b/src/lib/automate/automate.c @@ -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; + 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,36 +58,27 @@ 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; + len = strlen(pString); + buffer = realloc(buffer, len+1); + 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; - l = dotPtr.n; + pCtx[c].dot = pAutomate->dCurrent; + dotPtr = pAutomate->dot[pCtx[c].dot]; + i = ( pCtx[c].index == strIndex ) ? pCtx[c].path : 0; + l = dotPtr.n; /* (2) If no more path for this branch -> exit */ @@ -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 ){ + // 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; pAutomate->dCurrent = dotPtr.dot[i]; - strIndex += recursive; - pathmem[c] = 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; } @@ -205,15 +229,18 @@ unsigned int browse(struct Automate* pAutomate, const char* pString, const char } - ptr = NULL; + 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); - return strIndex; + (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; } diff --git a/src/lib/automate/automate.h b/src/lib/automate/automate.h index 46d0829..612b48a 100644 --- a/src/lib/automate/automate.h +++ b/src/lib/automate/automate.h @@ -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 Current + * @path Current min path + * @index Current stirng index + * + * @return context 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 Current working automate * @pString String to test - * @pDepth Padding + * @pCtx Already browsed context * * @return offset 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 Automate pointer + * + */ + void destroyAutomate(struct Automate* pAutomate); + /* Merges an automate into another * * @pMaster Master automate that contains @pSlave * @pSlaveIndex Slave automate index into @pMaster * + * @return status 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 diff --git a/src/linter.c b/src/linter.c index 08ff17d..543a86c 100644 --- a/src/linter.c +++ b/src/linter.c @@ -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 */