static int checkfill(Symbol* tsym, Datasrc* src) { int i,iscmpd,result; Constant* con; Symbol* original = tsym; result = 1; switch (tsym->subclass) { case NC_ENUM: case NC_OPAQUE: case NC_PRIM: con = srcnext(src); if(src == NULL) { semerror(srcline(src),"%s: malformed _FillValue",original->name); result = 0; } else if(con->nctype != tsym->typ.typecode) result = 0; /* wrong type*/ break; case NC_COMPOUND: if(!issublist(src)) {/* fail on no compound*/ semerror(srcline(src),"Compound constants must be enclosed in {..}"); } srcpush(src); for(i=0;i<listlength(tsym->subnodes);i++) { Symbol* field = (Symbol*)listget(tsym->subnodes,i); result = checkfill(field,src,original); if(!result) break; } srcpop(src); break; case NC_VLEN: if(!issublist(src)) { semerror(srcline(src),"%s: vlen instances in _FillValue must be enclosed in {...}",original->name); result = 0; } else { srcpush(src); while(srcmore(src)) { result = checkfill(tsym->typ.basetype,src,original); if(!result) break; } srcpop(src); } break; case NC_FIELD: /* Braces are optional */ if((iscmpd=issublist(src))) srcpush(src); if(tsym->typ.dimset.ndims > 0) { result = checkarray(tsym->typ.basetype,&tsym->typ.dimset,0,src,original,!TOPLEVEL); } else result = checkfill(tsym->typ.basetype,src,original); if(iscmpd) srcpop(src); break; default: PANIC1("checkfillvalue: unexpected subclass %d",tsym->subclass); } return result; }
static void cdata_primdata(Symbol* basetype, Datasrc* src, Bytebuffer* codebuf, Datalist* fillsrc) { Constant* prim; Constant target; prim = srcnext(src); if(prim == NULL) prim = &fillconstant; ASSERT(prim->nctype != NC_COMPOUND); if(prim->nctype == NC_FILLVALUE) { Datalist* filler = getfiller(basetype,fillsrc); ASSERT(filler->length == 1); srcpushlist(src,filler); bbAppend(codebuf,' '); cdata_primdata(basetype,src,codebuf,NULL); srcpop(src); goto done; } target.nctype = basetype->typ.typecode; if(target.nctype != NC_ECONST) { convert1(prim,&target); } switch (target.nctype) { case NC_ECONST: if(basetype->subclass != NC_ENUM) { semerror(prim->lineno,"Conversion to enum not supported (yet)"); } else { Datalist* econ = builddatalist(1); Symbol* enumv = prim->value.enumv; srcpushlist(src,econ); dlappend(econ,&enumv->typ.econst); cdata_primdata(enumv->typ.basetype,src,codebuf,fillsrc); srcpop(src); } break; case NC_OPAQUE: { setprimlength(&target,basetype->typ.size*2); } break; default: break; } bbCat(codebuf,cdata_const(&target)); done: return; }
static void f77data_primdata(Symbol* basetype, Datasrc* src, Bytebuffer* codebuf, Datalist* fillsrc) { Constant* prim; Constant target; prim = srcnext(src); if(prim == NULL) prim = &fillconstant; ASSERT(prim->nctype != NC_COMPOUND); if(prim->nctype == NC_FILLVALUE) { Datalist* filler = getfiller(basetype,fillsrc); ASSERT(filler->length == 1); srcpushlist(src,filler); bbAppend(codebuf,' '); f77data_primdata(basetype,src,codebuf,NULL); srcpop(src); goto done; } target.nctype = basetype->typ.typecode; convert1(prim,&target); bbCat(codebuf,f77data_const(&target)); done: return; }
static void genbin_arraydatar(Symbol* vsym, Bytebuffer* memory, nciter_t iter, Iterodom* iterodom, int index) { int i; int rank = iterodom->rank; int lastdim = (index == (rank - 1)); /* last dimension*/ int firstdim = (index == 0); int declsize = odom->dims[index].declsize; int isunlimited = (declsize == 0); Symbol* basetype = vsym->typ.basetype; Datalist* fillsrc = vsym->var.special._Fillvalue; Constant* con; ASSERT(index >= 0 && index < rank); odom->dims[index].index = 0; /* reset*/ if(isunlimited) { Constant* con; if(!firstdim) { if(!issublist(src)) { semerror(srcline(src),"Unlimited data must be enclosed in {..}"); return; } srcpush(src); /* enter the unlimited data */ } while((con=srcpeek(src))!=NULL) { if(lastdim) { genbin_data(basetype,src,fillsrc,memory); } else { genbin_arraydatar(vsym,src,odom,index+1, checkpoint,memory); } odom->dims[index].index++; if(docheckpoint) { closure->putvar(closure,odom,memory); } } odom->dims[index].datasize = odom->dims[index].index; if(!firstdim) srcpop(src); } else { /* !isunlimited*/ for(i=0;i<declsize;i++) { con = srcpeek(src); if(lastdim) { genbin_data(basetype,src,fillsrc,memory); } else { /* ! lastdim*/ (void)genbin_arraydatar(vsym,src,odom, index+1,checkpoint,memory); } odom->dims[index].index++; if(docheckpoint) { closure->putvar(closure,odom,memory); } } } }
static void genbin_data(Symbol* tsym, Datasrc* datasrc, Datalist* fillsrc, Bytebuffer* memory) { int usecmpd; Constant* con = srcpeek(datasrc); if(con == NULL || con->nctype == NC_FILLVALUE) { srcnext(datasrc); genbin_fillvalue(tsym,fillsrc,datasrc,memory); return; } switch (tsym->subclass) { case NC_ENUM: case NC_OPAQUE: case NC_PRIM: if(issublist(datasrc)) { semerror(srcline(datasrc),"Expected primitive found {..}"); } genbin_primdata(tsym,datasrc,fillsrc,memory); break; case NC_COMPOUND: genbin_compound(tsym,datasrc,fillsrc,memory); break; case NC_VLEN: { Constant* cp; nc_vlen_t ptr; if(!issublist(datasrc)) { semerror(srcline(datasrc),"Vlen data must be enclosed in {..}"); } cp = srcnext(datasrc); /* generate the nc_vlen_t instance*/ ptr.p = vlendata[cp->value.compoundv->vlen.uid].data; ptr.len = vlendata[cp->value.compoundv->vlen.uid].count; bbAppendn(memory,(char*)&ptr,sizeof(ptr)); } break; case NC_FIELD: /* enclose in braces if and only if field is an array */ usecmpd = (issublist(datasrc) && tsym->typ.dimset.ndims > 0); if(usecmpd) srcpush(datasrc); if(tsym->typ.dimset.ndims > 0) { genbin_fieldarray(tsym->typ.basetype,datasrc,&tsym->typ.dimset,0,memory); } else { genbin_data(tsym->typ.basetype,datasrc,NULL,memory); } if(usecmpd) srcpop(datasrc); break; default: PANIC1("genbin_data: unexpected subclass %d",tsym->subclass); } }
NCConstant* srcnext(Datasrc* ds) { DUMPSRC(ds,"!"); if(ds == NULL) return NULL; if(ds->index < ds->length) return &ds->data[ds->index++]; if(ds->spliced) { srcpop(ds); return srcnext(ds); } return NULL; }
void genbin_fillvalue(Symbol* tsym, Datalist* fillsrc, Datasrc* src, Bytebuffer* memory) { Datalist* list = NULL; ASSERT(tsym->objectclass == NC_TYPE); list = fillsrc; if(list == NULL) list = getfiller(tsym); srcpushlist(src,list); genbin_data(tsym,src,NULL,memory); srcpop(src); }
void gen_charfield(Datasrc* src, Odometer* odom, int index, Bytebuffer* fieldbuf) { int i; int lastdim = (index == (odom->rank - 1)); size_t declsize = odom->declsize[index]; Constant* con; ASSERT(declsize != 0); if(lastdim) { for(i=0;i<declsize;) { con = srcnext(src); if(con == NULL) break; if(!isstringable(con->nctype)) { semerror(srcline(src), "Encountered non-string constant in compound field"); return; } i += collectstring(con,declsize,fieldbuf); } if(i < declsize) i=fillstring(declsize,i,fieldbuf); } else { /* ! lastdim*/ int exploded = 0; size_t slicesize; /* Compute subslice size */ slicesize = 1; for(i=index+1;i<odom->rank;i++) slicesize *= MAX(odom->declsize[i],odom->unlimitedsize[i]); con = srcpeek(src); if(con != NULL && !isstringable(con->nctype)) { semerror(srcline(src), "Encountered non-string constant in compound field"); return; } if(con != NULL && con->value.stringv.len > slicesize) { /* Constant is larger than just our slice */ /* Explode the constant into subchunks */ exploded = stringexplode(src,slicesize); } for(i=0;i<declsize;i++) { gen_charfield(src,odom,index+1,fieldbuf); } if(exploded) srcpop(src); } }
static nc_type inferattributetype1(Datasrc* src) { nc_type result = NC_NAT; /* Recurse down any enclosing compound markers to find first non-fill "primitive"*/ while(result == NC_NAT && srcmore(src)) { if(issublist(src)) { srcpush(src); result = inferattributetype1(src); srcpop(src); } else { Constant* con = srcnext(src); if(isprimplus(con->nctype)) result = con->nctype; /* else keep looking*/ } } return result; }
void f77data_array(Symbol* vsym, Bytebuffer* databuf, Datasrc* src, Odometer* odom, int index, Datalist* fillsrc) { int i; int rank = odom->rank; int firstdim = (index == 0); /* last dimension*/ int lastdim = (index == (rank - 1)); /* last dimension*/ size_t count; Symbol* basetype = vsym->typ.basetype; int isunlimited = (odom->declsize[index] == 0); int pushed=0; ASSERT(index >= 0 && index < rank); count = odom->count[index]; if(!firstdim && isunlimited && issublist(src)) { srcpush(src); pushed = 1; } if(lastdim) { for(i=0;i<count;i++) { f77data_basetype(basetype,src,databuf,fillsrc); } } else { /* now walk count elements and generate recursively */ for(i=0;i<count;i++) { f77data_array(vsym,databuf,src,odom,index+1,fillsrc); } } if(isunlimited && pushed) srcpop(src); return; }
/* Used for compound instances */ static void genbin_compound(Symbol* tsym, Datasrc* datasrc, Datalist* fillsrc, Bytebuffer* memory) { int i; int base = bblength(memory); if(!issublist(datasrc)) { semerror(srcline(datasrc),"Compound data must be enclosed in {..}"); } /* Use this datasrc list to get values for compound fields */ srcpush(datasrc); for(i=0;i<listlength(tsym->subnodes);i++) { Symbol* field = (Symbol*)listget(tsym->subnodes,i); if(!srcmore(datasrc)) { /* generate a fill value*/ Datalist* fillsrc = getfiller(tsym); genbin_data(field,datasrc,fillsrc,memory); } else genbin_data(field,datasrc,NULL,memory); } srcpop(datasrc); /* Re: github issue 323: we may need to pad the end of the structure to make its size be a multiple of the largest alignment. */ alignto(tsym->cmpdalignment,buf,base); }
void gen_chararray(Symbol* vsym, Bytebuffer* databuf, Datasrc* src, Odometer* odom, int index) { /* Assume that all dimensions from index+1 to rank-1 are !unlimited */ int i; int rank = odom->rank; int lastdim = (index == (rank - 1)); /* last dimension*/ int firstdim = (index == 0); int isunlimited = (odom->declsize[index] == NC_UNLIMITED); int exploded = 0; Constant* con; if(lastdim) { gen_chararraysuffix(vsym,databuf,src,odom,index); return; } ASSERT(index >= 0 && index < rank); odom->index[index] = odom->start[index]; /* reset */ if(isunlimited) { size_t slicesize; Constant* con; if(!firstdim) { if(!issublist(src)) { semerror(srcline(src),"Unlimited data must be enclosed in {..}"); return; } srcpush(src); /* enter the unlimited data */ } con=srcpeek(src); /* Break up the constant if it is too large */ slicesize = odomsubarray(odom,index+1); if(con != NULL && con->value.stringv.len > slicesize) { /* Constant is larger than just our slice */ /* Explode the constant into subchunks */ exploded = stringexplode(src,slicesize); } while((con=srcpeek(src))!=NULL) { gen_chararray(vsym,databuf,src,odom,index+1); odom->index[index]++; } odom->unlimitedsize[index] = odom->index[index]; if(exploded) srcpop(src); if(!firstdim) srcpop(src); } else { /* !isunlimited*/ size_t slicesize; con = srcpeek(src); ASSERT(!lastdim); /* Break up the constant if it is too large */ slicesize = odomsubarray(odom,index+1); if(con != NULL && con->value.stringv.len > slicesize) { /* Constant is larger than just our slice */ /* Explode the constant into subchunks */ exploded = stringexplode(src,slicesize); } for(i=0;i<odom->declsize[index];i++) { gen_chararray(vsym,databuf,src,odom,index+1); } if(exploded) srcpop(src); } }
static void gen_chararraysuffix(Symbol* vsym, Bytebuffer* databuf, Datasrc* src, Odometer* odom, int index) { int i; int rank = odom->rank; int lastdim = (index == (rank - 1)); /* last dimension*/ int firstdim = (index == 0); size_t declsize = odom->declsize[index]; int isunlimited = (declsize==NC_UNLIMITED); Constant* con; ASSERT(index >= 0 && index < rank); odom->index[index] = odom->start[index]; /* reset*/ con = srcpeek(src); if(!isunlimited) { if(con != NULL && !isstringable(con->nctype)) { semerror(srcline(src), "Encountered non-string constant in char data: %s", vsym->name); return; } if(lastdim) { /* To mimic ncgen original, it appears we have to hack. I think firstdim==lastdim may work. */ for(i=0;i<declsize;) { int slen; con = srcnext(src); if(con == NULL) break; slen = collectstring(con,declsize,databuf); if(!firstdim && slen < declsize) slen=fillstring(declsize,slen,databuf); i += slen; } if(firstdim && i < declsize) i = fillstring(declsize,i,databuf); odom->index[index] = i; } else { /* ! lastdim*/ int exploded = 0; size_t slicesize = odometertotal(odom,index+1); if(con != NULL && con->nctype == NC_STRING && con->value.stringv.len > slicesize) { /* Constant is larger than just our slice */ /* Explode the constant into subchunks */ exploded = stringexplode(src,slicesize); } for(i=0;i<odom->declsize[index];i++) { gen_chararraysuffix(vsym,databuf,src,odom,index+1); odom->index[index]++; } if(exploded) srcpop(src); } } else { /* unlimited => lastdim*/ Constant* con; if(!firstdim) { if(!issublist(src)) { semerror(srcline(src),"Unlimited data must be enclosed in {..}"); return; } srcpush(src); /* enter the unlimited data */ } /* Basically, collect all the strings until we run out */ i = 0; while((con=srcnext(src))!=NULL) { i += collectstring(con,0,databuf); } odom->index[index] = i; odom->unlimitedsize[index] = odom->index[index]; if(!firstdim) srcpop(src); } }
/* Generate an instance of the basetype using datasrc */ void cdata_basetype(Symbol* tsym, Datasrc* datasrc, Bytebuffer* codebuf, Datalist* fillsrc) { int usecmpd; switch (tsym->subclass) { case NC_ENUM: case NC_OPAQUE: case NC_PRIM: if(issublist(datasrc)) { semerror(srcline(datasrc),"Expected primitive found {..}"); } bbAppend(codebuf,' '); cdata_primdata(tsym,datasrc,codebuf,fillsrc); break; case NC_COMPOUND: { int i; Constant* con; if(!isfillvalue(datasrc) && !issublist(datasrc)) {/* fail on no compound*/ semerror(srcline(datasrc),"Compound data must be enclosed in {..}"); } con = srcnext(datasrc); if(con->nctype == NC_FILLVALUE) { Datalist* filler = getfiller(tsym,fillsrc); ASSERT(filler->length == 1); con = &filler->data[0]; if(con->nctype != NC_COMPOUND) { semerror(con->lineno,"Compound data fill value is not enclosed in {..}"); } } srcpushlist(datasrc,con->value.compoundv); /* enter the sublist*/ bbAppend(codebuf,'{'); for(i=0;i<listlength(tsym->subnodes);i++) { Symbol* field = (Symbol*)listget(tsym->subnodes,i); bbAppend(codebuf,' '); cdata_basetype(field,datasrc,codebuf,NULL); } bbAppend(codebuf,'}'); srcpop(datasrc); } break; case NC_VLEN: { Constant* con; if(!isfillvalue(datasrc) && !issublist(datasrc)) {/* fail on no compound*/ semerror(con->lineno,"Vlen data must be enclosed in {..}"); } con = srcnext(datasrc); if(con->nctype == NC_FILLVALUE) { Datalist* filler = getfiller(tsym,fillsrc); ASSERT(filler->length == 1); con = &filler->data[0]; if(con->nctype != NC_COMPOUND) { semerror(con->lineno,"Vlen data fill value is not enclosed in {..}"); } } /* generate the nc_vlen_t instance*/ bbprintf0(stmt,"{%u (void*)vlen_%u}", con->value.compoundv->vlen.count, con->value.compoundv->vlen.uid); bbCatbuf(codebuf,stmt); } break; case NC_FIELD: /* enclose in braces if and only if field is an array */ usecmpd = (issublist(datasrc) && tsym->typ.dimset.ndims > 0); if(usecmpd) srcpush(datasrc); if(tsym->typ.dimset.ndims > 0) { Odometer* fullodom = newodometer(&tsym->typ.dimset,NULL,NULL); cdata_fieldarray(tsym->typ.basetype,datasrc,fullodom,0,codebuf); odometerfree(fullodom); } else { cdata_basetype(tsym->typ.basetype,datasrc,codebuf,NULL); } if(usecmpd) srcpop(datasrc); break; default: PANIC1("cdata_basetype: unexpected subclass %d",tsym->subclass); } }
static void genbin_primdata(Symbol* basetype, Datasrc* src, Datalist* fillsrc, Bytebuffer* memory) { Constant* prim; Constant target; prim = srcnext(src); if(prim == NULL || prim->nctype == NC_FILLVALUE) { genbin_fillvalue(basetype,fillsrc,src,memory); return; } target.nctype = basetype->typ.typecode; if(prim == NULL) { #ifdef GENFILL /* generate a fill value*/ nc_getfill(&target); /* fall thru*/ #else return; #endif } ASSERT(prim->nctype != NC_COMPOUND); if(target.nctype != NC_ECONST) { convert1(prim,&target); alignbuffer(&target,memory); } switch (target.nctype) { case NC_ECONST: if(basetype->subclass != NC_ENUM) { semerror(prim->lineno,"Conversion to enum not supported (yet)"); } else { Datalist* econ = builddatalist(1); srcpushlist(src,econ); dlappend(econ,&prim->value.enumv->typ.econst); genbin_primdata(prim->value.enumv->typ.basetype,src, fillsrc,memory); srcpop(src); } break; case NC_OPAQUE: { unsigned char* bytes; size_t len; setprimlength(&target,basetype->typ.size*2); bytes=makebytestring(target.value.opaquev.stringv,&len); bbAppendn(memory,(void*)bytes,len); } break; case NC_CHAR: bbAppendn(memory,&target.value.charv,sizeof(target.value.charv)); break; case NC_BYTE: bbAppendn(memory,(void*)&target.value.int8v,sizeof(target.value.int8v)); break; case NC_SHORT: bbAppendn(memory,(void*)&target.value.int16v,sizeof(target.value.int16v)); break; case NC_INT: bbAppendn(memory,(void*)&target.value.int32v,sizeof(target.value.int32v)); break; case NC_FLOAT: bbAppendn(memory,(void*)&target.value.floatv,sizeof(target.value.floatv)); break; case NC_DOUBLE: bbAppendn(memory,(void*)&target.value.doublev,sizeof(target.value.doublev)); break; case NC_UBYTE: bbAppendn(memory,(void*)&target.value.uint8v,sizeof(target.value.uint8v)); break; case NC_USHORT: bbAppendn(memory,(void*)&target.value.uint16v,sizeof(target.value.uint16v)); break; case NC_UINT: bbAppendn(memory,(void*)&target.value.uint32v,sizeof(target.value.uint32v)); break; case NC_INT64: { union SI64 { char ch[8]; long long i64;} si64; si64.i64 = target.value.int64v; bbAppendn(memory,(void*)si64.ch,sizeof(si64.ch)); } break; case NC_UINT64: { union SU64 { char ch[8]; unsigned long long i64;} su64; su64.i64 = target.value.uint64v; bbAppendn(memory,(void*)su64.ch,sizeof(su64.ch)); } break; case NC_STRING: { if(usingclassic) { bbAppendn(memory,target.value.stringv.stringv,target.value.stringv.len); } else if(target.nctype == NC_CHAR) { bbAppendn(memory,target.value.stringv.stringv,target.value.stringv.len); } else { char* ptr; int len = (size_t)target.value.stringv.len; ptr = poolalloc(len+1); /* CAREFUL: this has short lifetime*/ memcpy(ptr,target.value.stringv.stringv,len); ptr[len] = '\0'; bbAppendn(memory,(void*)&ptr,sizeof(ptr)); } } break; default: PANIC1("genbin_primdata: unexpected type: %d",target.nctype); } }