cmData.h/c : Initial debugging and testing of cmDataParser.

This commit is contained in:
kpl 2013-11-15 16:44:05 -08:00
parent fd56025468
commit 2e1c77f150
2 changed files with 131 additions and 116 deletions

233
cmData.c
View File

@ -34,6 +34,9 @@ void _cmDataFreeArray( cmData_t* p )
void _cmDataFree( cmData_t* p ) void _cmDataFree( cmData_t* p )
{ {
if( p == NULL )
return;
if( cmDataIsStruct(p) ) if( cmDataIsStruct(p) )
{ {
cmData_t* cp = p->u.child; cmData_t* cp = p->u.child;
@ -2391,9 +2394,12 @@ typedef struct
cmDtRC_t _cmDpSyntaxErrV( cmDataParserCtx_t* c, const cmChar_t* fmt, va_list vl ) cmDtRC_t _cmDpSyntaxErrV( cmDataParserCtx_t* c, const cmChar_t* fmt, va_list vl )
{ {
cmChar_t* s0 = NULL; cmChar_t* s0 = NULL;
cmChar_t* s1 = NULL;
s0 = cmTsVPrintfP(s0,fmt,vl); s0 = cmTsVPrintfP(s0,fmt,vl);
cmDtRC_t rc = cmErrMsg(&c->p->err,kSyntaxErrDtRC,"Syntax error on line %i. %s",cmLexCurrentLineNumber(c->p->lexH),cmStringNullGuard(s0)); s1 = cmMemAllocStrN(cmLexTokenText(c->p->lexH),cmLexTokenCharCount(c->p->lexH));
cmDtRC_t rc = cmErrMsg(&c->p->err,kSyntaxErrDtRC,"Syntax error on line %i column:%i token:'%s'. %s",cmLexCurrentLineNumber(c->p->lexH),cmLexCurrentColumnNumber(c->p->lexH),s1,cmStringNullGuard(s0));
cmMemFree(s0); cmMemFree(s0);
cmMemFree(s1);
return rc; return rc;
} }
@ -2412,18 +2418,41 @@ cmDtRC_t _cmDpPopStack( cmDataParserCtx_t* c, cmData_t** pp )
if((vp = cmStackTop(c->p->stH)) == NULL ) if((vp = cmStackTop(c->p->stH)) == NULL )
return _cmDpSyntaxErr(c,"Stack underflow."); return _cmDpSyntaxErr(c,"Stack underflow.");
if( cmStackPop(c->p->stH,1) != kOkStRC )
return _cmDpSyntaxErr(c,"Stack pop failed.");
*pp = *(cmData_t**)vp; *pp = *(cmData_t**)vp;
//printf("pop: %p\n",*pp);
return kOkDtRC; return kOkDtRC;
} }
cmDtRC_t _cmDpStoreArrayEle( cmDataParserCtx_t* c, void* dp, unsigned byteCnt ) cmDtRC_t _cmDpPushStack( cmDataParserCtx_t* c, cmData_t* np )
{ {
char* vp = cmMemResize(char, c->cnp->u.vp, c->cnp->cnt+byteCnt); //printf("push:%p\n",np);
memcpy(vp + c->cnp->cnt,dp,byteCnt); // store the current node
if( cmStackPush(c->p->stH, &np, 1 ) != kOkStRC )
return _cmDpSyntaxErr(c,"Parser stack push failed.");
return kOkDtRC;
}
cmDtRC_t _cmDpStoreArrayEle( cmDataParserCtx_t* c, void* dp, unsigned eleByteCnt, unsigned tid )
{
if( c->cnp->tid == kVoidPtrDtId )
c->cnp->tid = tid;
else
if( c->cnp->tid != tid )
return _cmDpSyntaxErr(c,"Mixed types were detected in an array list.");
unsigned newByteCnt = (c->cnp->cnt+1)*eleByteCnt;
char* vp = cmMemResizeP(char, c->cnp->u.vp, newByteCnt);
memcpy(vp + c->cnp->cnt*eleByteCnt,dp,eleByteCnt);
c->cnp->u.vp = vp; c->cnp->u.vp = vp;
c->cnp->cnt += byteCnt; c->cnp->cnt += 1;
c->flags = kValueExpFl | kCommaExpFl; c->flags = kValueExpFl | kCommaExpFl;
@ -2432,14 +2461,17 @@ cmDtRC_t _cmDpStoreArrayEle( cmDataParserCtx_t* c, void* dp, unsigned byteCnt )
cmDtRC_t _cmDataParserOpenPair( cmDataParserCtx_t* c ) cmDtRC_t _cmDataParserOpenPair( cmDataParserCtx_t* c )
{ {
cmDtRC_t rc = kOkDtRC;
assert( c->cnp->tid == kRecordDtId ); assert( c->cnp->tid == kRecordDtId );
// create a pair with a 'null' value which will be replaced when the pair's value is parsed
cmData_t* nnp = cmDataAllocNull(NULL); cmData_t* nnp = cmDataAllocNull(NULL);
cmData_t* pnp = cmDataAllocPairLabelN( c->cnp, cmLexTokenText(c->p->lexH), cmLexTokenCharCount(c->p->lexH), nnp ); cmData_t* pnp = cmDataAllocPairLabelN( c->cnp, cmLexTokenText(c->p->lexH), cmLexTokenCharCount(c->p->lexH), nnp );
// store the current node // store the current node
if( cmStackPush(c->p->stH, &c->cnp, 1 ) != kOkStRC ) if((rc = _cmDpPushStack(c,c->cnp)) != kOkDtRC )
return _cmDpSyntaxErr(c,"Parser stack push failed."); return rc;
// make the new pair the current node // make the new pair the current node
c->cnp = pnp; c->cnp = pnp;
@ -2447,7 +2479,7 @@ cmDtRC_t _cmDataParserOpenPair( cmDataParserCtx_t* c )
// pair openings must be followed by a colon. // pair openings must be followed by a colon.
c->flags = kColonExpFl; c->flags = kColonExpFl;
return kOkDtRC; return rc;
} }
cmDtRC_t _cmDataParserClosePair( cmDataParserCtx_t* c ) cmDtRC_t _cmDataParserClosePair( cmDataParserCtx_t* c )
@ -2492,6 +2524,11 @@ cmDtRC_t _cmDpStoreValue( cmDataParserCtx_t* c, cmData_t* np, const cmChar_t* ty
default: default:
rc = _cmDpSyntaxErr(c,"A '%s' value was found outside of a valid container.",typeLabel); rc = _cmDpSyntaxErr(c,"A '%s' value was found outside of a valid container.",typeLabel);
// Free the new data node because it was not attached and will
// otherwise be lost
cmDataFree(np);
} }
c->flags |= kCommaExpFl; c->flags |= kCommaExpFl;
@ -2502,13 +2539,28 @@ cmDtRC_t _cmDpStoreValue( cmDataParserCtx_t* c, cmData_t* np, const cmChar_t* ty
cmDtRC_t _cmDataParserReal( cmDataParserCtx_t* c ) cmDtRC_t _cmDataParserReal( cmDataParserCtx_t* c )
{ {
cmDtRC_t rc = kOkDtRC; cmDtRC_t rc = kOkDtRC;
double val = cmLexTokenDouble(c->p->lexH); bool floatFl = cmLexTokenIsSinglePrecision(c->p->lexH);
double dval;
float fval;
if( c->cnp->tid == kVoidPtrDtId ) if( floatFl )
rc = _cmDpStoreArrayEle(c,&val,sizeof(val)); fval = cmLexTokenFloat(c->p->lexH);
else else
rc = _cmDpStoreValue(c,cmDataAllocDouble(NULL,val),"real"); dval = cmLexTokenDouble(c->p->lexH);
if( cmDataIsPtr(c->cnp) )
{
if( floatFl )
rc = _cmDpStoreArrayEle(c,&fval,sizeof(fval),kFloatPtrDtId);
else
rc = _cmDpStoreArrayEle(c,&dval,sizeof(dval),kDoublePtrDtId);
}
else
{
cmData_t* np = floatFl ? cmDataAllocFloat(NULL,fval) : cmDataAllocDouble(NULL,dval);
rc = _cmDpStoreValue(c,np,"real");
}
return rc; return rc;
} }
@ -2516,11 +2568,15 @@ cmDtRC_t _cmDataParserInt( cmDataParserCtx_t* c )
{ {
cmDtRC_t rc = kOkDtRC; cmDtRC_t rc = kOkDtRC;
int val = cmLexTokenInt(c->p->lexH); int val = cmLexTokenInt(c->p->lexH);
bool unsignedFl = cmLexTokenIsUnsigned(c->p->lexH);
if( c->cnp->tid == kVoidPtrDtId ) if( cmDataIsPtr(c->cnp) )
rc = _cmDpStoreArrayEle(c,&val,sizeof(val)); rc = _cmDpStoreArrayEle(c,&val,sizeof(val),unsignedFl ? kUIntPtrDtId : kIntPtrDtId);
else else
rc = _cmDpStoreValue(c,cmDataAllocInt(NULL,val),"int"); {
cmData_t* np = unsignedFl ? cmDataAllocUInt(NULL,val) : cmDataAllocInt(NULL,val);
rc = _cmDpStoreValue(c,np,"int");
}
return rc; return rc;
} }
@ -2542,155 +2598,102 @@ cmDtRC_t _cmDataParserString( cmDataParserCtx_t* c )
cmDtRC_t _cmDataParserOpenRecd( cmDataParserCtx_t* c ) cmDtRC_t _cmDataParserOpenRecd( cmDataParserCtx_t* c )
{ {
cmDtRC_t rc = kOkDtRC;
// records are values - so we must be expecting a value // records are values - so we must be expecting a value
if( cmIsFlag(c->flags,kValueExpFl) == false ) if( cmIsFlag(c->flags,kValueExpFl) == false )
return _cmDpSyntaxErr(c,"Unexpected '{'."); return _cmDpSyntaxErr(c,"Unexpected '{'.");
// store the current node // store the current node
if( cmStackPush(c->p->stH, &c->cnp, 1 ) != kOkStRC ) if((rc = _cmDpPushStack(c,c->cnp)) != kOkDtRC )
return _cmDpSyntaxErr(c,"Parser stack push failed."); return rc;
// alloc a new record and make it the current node // alloc a new record and make it the current node
if( (c->cnp = cmDataRecdAlloc(c->cnp)) == NULL ) if( (c->cnp = cmDataRecdAlloc(NULL)) == NULL )
return _cmDpSyntaxErr(c,"'recd' allocate failed."); return _cmDpSyntaxErr(c,"'recd' allocate failed.");
// new records must be followed by an id token. // new records must be followed by an id token.
c->flags = kIdExpFl; c->flags = kIdExpFl;
return kOkDtRC; return rc;
}
cmDtRC_t _cmDataParserCloseContainer( cmDataParserCtx_t* c, const cmChar_t* typeLabelStr )
{
cmDtRC_t rc;
cmData_t* np = c->cnp;
// make the parent node the new current node
if((rc = _cmDpPopStack(c,&c->cnp)) != kOkDtRC )
return rc;
return _cmDpStoreValue(c,np,typeLabelStr);
} }
cmDtRC_t _cmDataParserCloseRecd( cmDataParserCtx_t* c ) cmDtRC_t _cmDataParserCloseRecd( cmDataParserCtx_t* c )
{ {
cmDtRC_t rc; assert( c->cnp->tid == kRecordDtId );
// make the parent node the new curren node return _cmDataParserCloseContainer(c,"record");
if((rc = _cmDpPopStack(c,&c->cnp)) != kOkDtRC )
return rc;
switch( c->cnp->tid )
{
case kPairDtId:
// if the parent node is a pair then close it
rc = _cmDataParserClosePair(c);
break;
case kListDtId:
// parent node is a list - so expect another value
c->flags = kValueExpFl;
break;
default:
return _cmDpSyntaxErr(c,"'records' may only be contained in other records or heterogenous arrays.");
}
c->flags |= kCommaExpFl;
return rc;
} }
cmDtRC_t _cmDataParserOpenList( cmDataParserCtx_t* c ) cmDtRC_t _cmDataParserOpenList( cmDataParserCtx_t* c )
{ {
cmDtRC_t rc = kOkDtRC;
// lists are values - so we must be expecting a value // lists are values - so we must be expecting a value
if( cmIsFlag(c->flags,kValueExpFl) == false ) if( cmIsFlag(c->flags,kValueExpFl) == false )
return _cmDpSyntaxErr(c,"Unexpected '('."); return _cmDpSyntaxErr(c,"Unexpected '('.");
// store the current node // store the current node
if( cmStackPush(c->p->stH, &c->cnp, 1 ) != kOkStRC ) if((rc = _cmDpPushStack(c,c->cnp)) != kOkDtRC )
return _cmDpSyntaxErr(c,"Parser stack push failed."); return rc;
// create a new list // create a new list
if( (c->cnp = cmDataListAlloc(c->cnp)) == NULL ) if( (c->cnp = cmDataListAlloc(NULL)) == NULL )
return _cmDpSyntaxErr(c,"'list' allocate failed."); return _cmDpSyntaxErr(c,"'list' allocate failed.");
// new lists must be followed by a value // new lists must be followed by a value
c->flags = kValueExpFl; c->flags = kValueExpFl;
return kOkDtRC; return rc;
} }
cmDtRC_t _cmDataParserCloseList( cmDataParserCtx_t* c ) cmDtRC_t _cmDataParserCloseList( cmDataParserCtx_t* c )
{ {
cmDtRC_t rc; assert( c->cnp->tid == kListDtId );
return _cmDataParserCloseContainer(c,"list");
// make the list's parent the current node
if((rc = _cmDpPopStack(c,&c->cnp)) != kOkDtRC )
return rc;
switch( c->cnp->tid )
{
case kPairDtId:
// if the list's parent is a pair then close it
rc = _cmDataParserClosePair(c);
break;
case kListDtId:
// the list's parent is another list so expect a value
c->flags = kValueExpFl;
break;
default:
return _cmDpSyntaxErr(c,"'lists' may only be contained in other records or lists.");
}
c->flags |= kCommaExpFl;
return rc;
} }
cmDtRC_t _cmDataParserOpenArray( cmDataParserCtx_t* c ) cmDtRC_t _cmDataParserOpenArray( cmDataParserCtx_t* c )
{ {
cmDtRC_t rc = kOkDtRC;
// arrays are values - so we must be expecting a value // arrays are values - so we must be expecting a value
if( cmIsFlag(c->flags,kValueExpFl) == false ) if( cmIsFlag(c->flags,kValueExpFl) == false )
return _cmDpSyntaxErr(c,"Unexpected '('."); return _cmDpSyntaxErr(c,"Unexpected '('.");
// store the current node // store the current node
if( cmStackPush(c->p->stH, &c->cnp, 1 ) != kOkStRC ) if((rc = _cmDpPushStack(c,c->cnp)) != kOkDtRC )
return _cmDpSyntaxErr(c,"Parser stack push failed."); return rc;
// create a new array // create a new array
if( (c->cnp = cmDataSetVoidAllocPtr(c->cnp, NULL, 0 )) == NULL ) if( (c->cnp = cmDataVoidAllocPtr(NULL, NULL, 0 )) == NULL )
return _cmDpSyntaxErr(c,"'array' allocate failed."); return _cmDpSyntaxErr(c,"'array' allocate failed.");
// new arrays must be followed by a value // new arrays must be followed by a value
c->flags = kValueExpFl; c->flags = kValueExpFl;
return kOkDtRC; return rc;
} }
cmDtRC_t _cmDataParserCloseArray( cmDataParserCtx_t* c ) cmDtRC_t _cmDataParserCloseArray( cmDataParserCtx_t* c )
{ {
cmDtRC_t rc; assert( cmDataIsPtr(c->cnp) );
// make the arrays parent the current node return _cmDataParserCloseContainer(c,"array");
if((rc = _cmDpPopStack(c,&c->cnp)) != kOkDtRC )
return rc;
switch( c->cnp->tid )
{
case kPairDtId:
// the arrays parent is a pair - so close it
rc = _cmDataParserClosePair(c);
break;
case kListDtId:
// the arrays parent is a list - so expect a value
c->flags = kValueExpFl;
break;
default:
return _cmDpSyntaxErr(c,"'arrays' may only be contained in other records or lists.");
}
c->flags |= kCommaExpFl;
return rc;
} }
cmDtRC_t _cmDataParserOnColon( cmDataParserCtx_t* c ) cmDtRC_t _cmDataParserOnColon( cmDataParserCtx_t* c )
@ -2726,17 +2729,17 @@ cmDtRC_t cmDataParserExec( cmDataParserH_t h, const cmChar_t* text, cmData_t** p
cmDataParser_t* p = _cmDataParserHandleToPtr(h); cmDataParser_t* p = _cmDataParserHandleToPtr(h);
unsigned tokenId; unsigned tokenId;
cmDataParserCtx_t ctx; cmDataParserCtx_t ctx;
cmData_t* root = cmDataRecdAlloc(NULL);
ctx.cnp = NULL; // current node ptr ctx.cnp = root;
ctx.p = p; ctx.p = p;
ctx.flags = kValueExpFl; ctx.flags = kIdExpFl;
if( cmLexSetTextBuffer(p->lexH,text,strlen(text)) != kOkLexRC ) if( cmLexSetTextBuffer(p->lexH,text,strlen(text)) != kOkLexRC )
return cmErrMsg(&p->err,kLexFailDtRC,"The data object lexer failed during reset."); return cmErrMsg(&p->err,kLexFailDtRC,"The data object lexer failed during reset.");
cmStackClear(p->stH,false); cmStackClear(p->stH,false);
while((tokenId = cmLexGetNextToken(p->lexH)) != kEofLexTId ) while(rc==kOkDtRC && (tokenId = cmLexGetNextToken(p->lexH)) != kEofLexTId )
{ {
switch(tokenId) switch(tokenId)
{ {
@ -2745,9 +2748,6 @@ cmDtRC_t cmDataParserExec( cmDataParserH_t h, const cmChar_t* text, cmData_t** p
break; break;
case kIntLexTId: // decimal integer case kIntLexTId: // decimal integer
rc = _cmDataParserInt(&ctx);
break;
case kHexLexTId: // hexidecimal integer case kHexLexTId: // hexidecimal integer
rc = _cmDataParserInt(&ctx); rc = _cmDataParserInt(&ctx);
break; break;
@ -2806,7 +2806,13 @@ cmDtRC_t cmDataParserExec( cmDataParserH_t h, const cmChar_t* text, cmData_t** p
if( rc == kOkDtRC ) if( rc == kOkDtRC )
*pp = ctx.cnp; *pp = ctx.cnp;
else
{
if( ctx.cnp != root )
cmDataUnlinkAndFree(ctx.cnp);
cmDataUnlinkAndFree(root);
}
return rc; return rc;
} }
@ -2913,7 +2919,10 @@ cmDtRC_t cmDataParserTest( cmCtx_t* ctx )
const cmChar_t text[] = const cmChar_t text[] =
{ {
"{ f0:1.23 f1:\"hey\" " //0 1 2 3
//0123456789012345678901234567890123
"f0:1.23 f1:\"hey\" f2:( a b c ) f3:[ 0f 1f 2f ]"
//"f0:1.23 f1:\"hey\""
}; };
cmErrSetup(&err,&ctx->rpt,"Data Parser Tester"); cmErrSetup(&err,&ctx->rpt,"Data Parser Tester");

View File

@ -544,6 +544,12 @@ extern "C" {
cmDtRC_t cmDataParserCreate( cmCtx_t* ctx, cmDataParserH_t* hp ); cmDtRC_t cmDataParserCreate( cmCtx_t* ctx, cmDataParserH_t* hp );
cmDtRC_t cmDataParserDestroy( cmDataParserH_t* hp ); cmDtRC_t cmDataParserDestroy( cmDataParserH_t* hp );
bool cmDataParserIsValid( cmDataParserH_t h ); bool cmDataParserIsValid( cmDataParserH_t h );
// Parse a text representation into a 'record' type.
// Note that the text is wrapped with implied curly braces
// (e.g. "{ text }"). The contents of the text should therefore
// fit the record syntax (e.g. the first token should be a
// 'pair' label.
cmDtRC_t cmDataParserExec( cmDataParserH_t h, const cmChar_t* text, cmData_t** pp ); cmDtRC_t cmDataParserExec( cmDataParserH_t h, const cmChar_t* text, cmData_t** pp );
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------