void generate_vardata(Symbol* vsym, Generator* generator, Writer writer, Bytebuffer* code) { Dimset* dimset = &vsym->typ.dimset; int rank = dimset->ndims; Symbol* basetype = vsym->typ.basetype; Datalist* filler = getfiller(vsym); const size_t* start; const size_t* count; Odometer* odom; if(vsym->data == NULL) return; /* give the buffer a running start to be large enough*/ if(!bbSetalloc(code, nciterbuffersize)) return; if(rank == 0) {/*scalar case*/ NCConstant* c0 = datalistith(vsym->data,0); generate_basetype(basetype,c0,code,filler,generator); writer(generator,vsym,code,0,NULL,NULL); } else {/*rank > 0*/ /* First, create an odometer using all of the dimensions */ odom = newodometer(dimset,NULL,NULL); start = odometerstartvector(odom); count = odometercountvector(odom); generate_array(vsym,code,filler,generator,writer); } }
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 generate_primdata(Symbol* basetype, Constant* prim, Bytebuffer* codebuf, Datalist* filler, Generator* generator) { Constant target; if(prim == NULL || isfillconst(prim)) { Datalist* fill = (filler==NULL?getfiller(basetype):filler); ASSERT(fill->length == 1); prim = datalistith(fill,0); } ASSERT(prim->nctype != NC_COMPOUND); 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(constline(prim),"Conversion to enum not supported (yet)"); } break; case NC_OPAQUE: setprimlength(&target,basetype->typ.size*2); break; default: break; } generator->constant(generator,&target,codebuf); return; }
static void processattributes(void) { int i,j; /* process global attributes*/ for(i=0;i<listlength(gattdefs);i++) { Symbol* asym = (Symbol*)listget(gattdefs,i); /* If the attribute has a zero length, then default it */ if(asym->data == NULL || asym->data->length == 0) { asym->data = builddatalist(1); emptystringconst(asym->lineno,&asym->data->data[asym->data->length]); /* force type to be NC_CHAR */ asym->typ.basetype = primsymbols[NC_CHAR]; } if(asym->typ.basetype == NULL) inferattributetype(asym); /* fill in the typecode*/ asym->typ.typecode = asym->typ.basetype->typ.typecode; } /* process per variable attributes*/ for(i=0;i<listlength(attdefs);i++) { Symbol* asym = (Symbol*)listget(attdefs,i); /* If the attribute has a zero length, then default it */ if(asym->data == NULL || asym->data->length == 0) { asym->data = builddatalist(1); emptystringconst(asym->lineno,&asym->data->data[asym->data->length]); /* force type to be NC_CHAR */ asym->typ.basetype = primsymbols[NC_CHAR]; } /* If no basetype is specified, then try to infer it; the exception if _Fillvalue, whose type is that of the containing variable. */ if(strcmp(asym->name,specialname(_FILLVALUE_FLAG)) == 0) { /* This is _Fillvalue */ asym->typ.basetype = asym->att.var->typ.basetype; /* its basetype is same as its var*/ /* put the datalist into the specials structure */ if(asym->data == NULL) { /* Generate a default fill value */ asym->data = getfiller(asym->typ.basetype); } asym->att.var->var.special._Fillvalue = asym->data; } else if(asym->typ.basetype == NULL) { inferattributetype(asym); } /* fill in the typecode*/ asym->typ.typecode = asym->typ.basetype->typ.typecode; } /* collect per-variable attributes per variable*/ for(i=0;i<listlength(vardefs);i++) { Symbol* vsym = (Symbol*)listget(vardefs,i); List* list = listnew(); for(j=0;j<listlength(attdefs);j++) { Symbol* asym = (Symbol*)listget(attdefs,j); ASSERT(asym->att.var != NULL); if(asym->att.var != vsym) continue; listpush(list,(void*)asym); } vsym->var.attributes = list; } }
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); }
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 fixeconstref(Symbol* avsym, NCConstant* con) { Symbol* basetype = NULL; Symbol* refsym = con->value.enumv; Symbol* varsym = NULL; int i; /* Figure out the proper type associated with avsym */ ASSERT(avsym->objectclass == NC_VAR || avsym->objectclass == NC_ATT); if(avsym->objectclass == NC_VAR) { basetype = avsym->typ.basetype; varsym = avsym; } else { /*(avsym->objectclass == NC_ATT)*/ basetype = avsym->typ.basetype; varsym = avsym->container; if(varsym->objectclass == NC_GRP) varsym = NULL; } if(basetype->objectclass != NC_TYPE && basetype->subclass != NC_ENUM) semerror(con->lineno,"Enumconstant associated with a non-econst type"); if(con->nctype == NC_FILLVALUE) { Datalist* filllist = NULL; NCConstant* filler = NULL; filllist = getfiller(varsym == NULL?basetype:varsym); if(filllist == NULL) semerror(con->lineno, "Cannot determine enum constant fillvalue"); filler = datalistith(filllist,0); con->value.enumv = filler->value.enumv; return; } for(i=0;i<listlength(basetype->subnodes);i++) { Symbol* econst = listget(basetype->subnodes,i); ASSERT(econst->subclass == NC_ECONST); if(strcmp(econst->name,refsym->name)==0) { con->value.enumv = econst; return; } } semerror(con->lineno,"Undefined enum or enum constant reference: %s",refsym->name); }
void generate_vardata(Symbol* vsym, Generator* generator, Writer writer, Bytebuffer* code) { Dimset* dimset = &vsym->typ.dimset; int rank = dimset->ndims; Symbol* basetype = vsym->typ.basetype; Datalist* filler = getfiller(vsym); if(vsym->data == NULL) return; /* give the buffer a running start to be large enough*/ bbSetalloc(code, nciterbuffersize); if(rank == 0) {/*scalar case*/ Constant* c0 = datalistith(vsym->data,0); generate_basetype(basetype,c0,code,filler,generator); writer(generator,vsym,code,0,NULL,NULL); } else {/*rank > 0*/ generate_array(vsym,code,filler,generator,writer); } }
/* 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); }
static void generate_primdata(Symbol* basetype, NCConstant* prim, Bytebuffer* codebuf, Datalist* filler, Generator* generator) { NCConstant target; int match; if(prim == NULL || isfillconst(prim)) { Datalist* fill = (filler==NULL?getfiller(basetype):filler); ASSERT(fill->length == 1); prim = datalistith(fill,0); } ASSERT(prim->nctype != NC_COMPOUND); /* Verify that the constant is consistent with the type */ match = 1; switch (prim->nctype) { case NC_CHAR: case NC_BYTE: case NC_SHORT: case NC_INT: case NC_FLOAT: case NC_DOUBLE: case NC_UBYTE: case NC_USHORT: case NC_UINT: case NC_INT64: case NC_UINT64: case NC_STRING: match = (basetype->subclass == NC_PRIM ? 1 : 0); break; #ifdef USE_NETCDF4 case NC_NIL: match = (basetype->subclass == NC_PRIM && basetype->typ.typecode == NC_STRING ? 1 : 0); break; case NC_OPAQUE: /* OPAQUE is also consistent with numbers */ match = (basetype->subclass == NC_OPAQUE || basetype->subclass == NC_PRIM ? 1 : 0); break; case NC_ECONST: match = (basetype->subclass == NC_ENUM ? 1 : 0); if(match) { /* Make sure this econst belongs to this enum */ Symbol* ec = prim->value.enumv; Symbol* en = ec->container; match = (en == basetype); } break; #endif default: match = 0; } if(!match) { semerror(constline(prim),"Data value is not consistent with the expected type: %s", basetype->name); } 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(constline(prim),"Conversion to enum not supported (yet)"); } break; case NC_OPAQUE: normalizeopaquelength(&target,basetype->typ.size); break; default: break; } generator->constant(generator,&target,codebuf); return; }
/* Generate an instance of the basetype */ void generate_basetype(Symbol* tsym, NCConstant* con, Bytebuffer* codebuf, Datalist* filler, Generator* generator) { Datalist* data; switch (tsym->subclass) { case NC_ENUM: case NC_OPAQUE: case NC_PRIM: if(islistconst(con)) { semerror(constline(con),"Expected primitive found {..}"); } generate_primdata(tsym,con,codebuf,filler,generator); break; case NC_COMPOUND: { int i,uid, nfields, dllen; if(con == NULL || isfillconst(con)) { Datalist* fill = (filler==NULL?getfiller(tsym):filler); ASSERT(fill->length == 1); con = &fill->data[0]; if(!islistconst(con)) semerror(con->lineno,"Compound data fill value is not enclosed in {..}"); } if(!islistconst(con)) {/* fail on no compound*/ semerror(constline(con),"Compound data must be enclosed in {..}"); } data = con->value.compoundv; nfields = listlength(tsym->subnodes); dllen = datalistlen(data); if(dllen > nfields) { semerror(con->lineno,"Datalist longer than the number of compound fields"); break; } generator->listbegin(generator,LISTCOMPOUND,listlength(tsym->subnodes),codebuf,&uid); for(i=0;i<nfields;i++) { Symbol* field = (Symbol*)listget(tsym->subnodes,i); con = datalistith(data,i); generator->list(generator,LISTCOMPOUND,uid,i,codebuf); generate_basetype(field,con,codebuf,NULL,generator); } generator->listend(generator,LISTCOMPOUND,uid,i,codebuf); } break; case NC_VLEN: { Bytebuffer* vlenbuf; int uid; size_t count; if(con == NULL || isfillconst(con)) { Datalist* fill = (filler==NULL?getfiller(tsym):filler); ASSERT(fill->length == 1); con = &fill->data[0]; if(con->nctype != NC_COMPOUND) { semerror(con->lineno,"Vlen data fill value is not enclosed in {..}"); } } if(!islistconst(con)) { semerror(constline(con),"Vlen data must be enclosed in {..}"); } data = con->value.compoundv; /* generate the nc_vlen_t instance*/ vlenbuf = bbNew(); if(tsym->typ.basetype->typ.typecode == NC_CHAR) { gen_charvlen(data,vlenbuf); generator->vlenstring(generator,vlenbuf,&uid,&count); } else { generator->listbegin(generator,LISTVLEN,data->length,codebuf,&uid); for(count=0;count<data->length;count++) { NCConstant* con; generator->list(generator,LISTVLEN,uid,count,vlenbuf); con = datalistith(data,count); generate_basetype(tsym->typ.basetype,con,vlenbuf,NULL,generator); } generator->listend(generator,LISTVLEN,uid,count,codebuf,(void*)vlenbuf); } generator->vlendecl(generator,codebuf,tsym,uid,count,vlenbuf); bbFree(vlenbuf); } break; case NC_FIELD: if(tsym->typ.dimset.ndims > 0) { /* Verify that we have a sublist (or fill situation) */ if(con != NULL && !isfillconst(con) && !islistconst(con)) semerror(constline(con),"Dimensioned fields must be enclose in {...}"); generate_fieldarray(tsym->typ.basetype,con,&tsym->typ.dimset,codebuf,filler,generator); } else { generate_basetype(tsym->typ.basetype,con,codebuf,NULL,generator); } break; default: PANIC1("generate_basetype: unexpected subclass %d",tsym->subclass); } }
static void generate_arrayr(Symbol* vsym, Bytebuffer* code, Datalist* list, Odometer* odom, int dimindex, Datalist* filler, Generator* generator ) { Symbol* basetype = vsym->typ.basetype; Dimset* dimset = &vsym->typ.dimset; int rank = dimset->ndims; int lastunlimited; int typecode = basetype->typ.typecode; lastunlimited = findlastunlimited(dimset); if(lastunlimited == rank) lastunlimited = 0; ASSERT(rank > 0); ASSERT(dimindex >= 0 && dimindex < rank); #ifdef CHARBUG ASSERT(typecode != NC_CHAR); #else /*!CHARBUG*/ if(dimindex == lastunlimited && typecode == NC_CHAR) { Bytebuffer* charbuf = bbNew(); gen_leafchararray(dimset,dimindex,list,charbuf,filler); generator->charconstant(generator,code,charbuf); bbFree(charbuf); } else #endif /*!CHARBUG*/ if(dimindex == lastunlimited) { int uid,i; Odometer* slabodom; /* build a special odometer to walk the last few dimensions (similar to case 2 above) */ slabodom = newsubodometer(odom,dimset,dimindex,rank); /* compute the starting offset in our datalist (Assumes that slabodom->index[i] == slabodom->start[i]) */ generator->listbegin(generator,LISTDATA,list->length,code,&uid); for(i=0;odometermore(slabodom);i++) { size_t offset = odometeroffset(slabodom); NCConstant* con = datalistith(list,offset); #ifdef USE_NOFILL if(nofill_flag && con == NULL) break; #endif generator->list(generator,LISTDATA,uid,i,code); generate_basetype(basetype,con,code,filler,generator); odometerincr(slabodom); } generator->listend(generator,LISTDATA,uid,i,code); odometerfree(slabodom); } else { /* If we are strictly to the left of the next unlimited then our datalist is a list of compounds representing the next unlimited; so walk the subarray from this index upto next unlimited. */ int i; Odometer* slabodom; int nextunlimited = findunlimited(dimset,dimindex+1); ASSERT((dimindex < nextunlimited && (dimset->dimsyms[nextunlimited]->dim.isunlimited))); /* build a sub odometer */ slabodom = newsubodometer(odom,dimset,dimindex,nextunlimited); /* compute the starting offset in our datalist (Assumes that slabodom->index[i] == slabodom->start[i]) */ for(i=0;odometermore(slabodom);i++) { size_t offset = odometeroffset(slabodom); NCConstant* con = datalistith(list,offset); #ifdef USE_NOFILL if(nofill_flag && con == NULL) break; #endif if(con == NULL || con->nctype == NC_FILL) { if(filler == NULL) filler = getfiller(vsym); generate_arrayr(vsym,code,filler,odom,nextunlimited,NULL,generator); } else if(!islistconst(con)) semwarn(constline(con),"Expected {...} representing unlimited list"); else { Datalist* sublist = con->value.compoundv; generate_arrayr(vsym,code,sublist,odom,nextunlimited,filler,generator); } odometerincr(slabodom); } odometerfree(slabodom); } return; }
/* Recursive helper that does the bulk of the work */ static int bin_generate_data_r(NCConstant* instance, Symbol* tsym, Datalist* fillvalue, Bytebuffer* databuf) { int stat = NC_NOERR; if(instance->nctype == NC_FILLVALUE) { /* replace with fillvalue for the type */ Datalist* filllist = (fillvalue == NULL ? getfiller(tsym) : fillvalue); ASSERT(datalistlen(filllist)==1) instance = datalistith(filllist,0); } switch (tsym->subclass) { case NC_PRIM: { switch (tsym->nc_id) { case NC_CHAR: { char* p = NULL; NCConstant* tmp = nullconst(); tmp->nctype = NC_CHAR; convert1(instance,tmp); p = &tmp->value.charv;; bbAppendn(databuf,p,sizeof(char)); reclaimconstant(tmp); } break; case NC_BYTE: { signed char* p = NULL; NCConstant* tmp = nullconst(); tmp->nctype = NC_BYTE; convert1(instance,tmp); p = &tmp->value.int8v; bbAppendn(databuf,p,sizeof(signed char)); reclaimconstant(tmp); } break; case NC_UBYTE: { unsigned char* p = NULL; NCConstant* tmp = nullconst(); tmp->nctype = NC_UBYTE; convert1(instance,tmp); p = &tmp->value.uint8v; bbAppendn(databuf,p,sizeof(unsigned char)); reclaimconstant(tmp); } break; case NC_SHORT: { short* p = NULL; NCConstant* tmp = nullconst(); tmp->nctype = NC_SHORT; convert1(instance,tmp); p = &tmp->value.int16v; bbAppendn(databuf,p,sizeof(short)); reclaimconstant(tmp); } break; case NC_USHORT: { unsigned short* p = NULL; NCConstant* tmp = nullconst(); tmp->nctype = NC_USHORT; convert1(instance,tmp); p = &tmp->value.uint16v; bbAppendn(databuf,p,sizeof(unsigned short)); reclaimconstant(tmp); } break; case NC_INT: { int* p = NULL; NCConstant* tmp = nullconst(); tmp->nctype = NC_INT; convert1(instance,tmp); p = &tmp->value.int32v; bbAppendn(databuf,p,sizeof(int)); reclaimconstant(tmp); } break; case NC_UINT: { unsigned int* p = NULL; NCConstant* tmp = nullconst(); tmp->nctype = NC_UINT; convert1(instance,tmp); p = &tmp->value.uint32v; bbAppendn(databuf,p,sizeof(unsigned int)); reclaimconstant(tmp); } break; case NC_INT64: { long long* p = NULL; NCConstant* tmp = nullconst(); tmp->nctype = NC_INT64; convert1(instance,tmp); p = &tmp->value.int64v; bbAppendn(databuf,p,sizeof(long long)); reclaimconstant(tmp); } break; case NC_UINT64: { unsigned long long* p = NULL; NCConstant* tmp = nullconst(); tmp->nctype = NC_UINT64; convert1(instance,tmp); p = &tmp->value.uint64v; bbAppendn(databuf,p,sizeof(unsigned long long)); reclaimconstant(tmp); } break; case NC_FLOAT: { float* p = NULL; NCConstant* tmp = nullconst(); tmp->nctype = NC_FLOAT; convert1(instance,tmp); p = &tmp->value.floatv; bbAppendn(databuf,p,sizeof(float)); reclaimconstant(tmp); } break; case NC_DOUBLE: { double* p = NULL; NCConstant* tmp = nullconst(); tmp->nctype = NC_DOUBLE; convert1(instance,tmp); p = &tmp->value.doublev; bbAppendn(databuf,p,sizeof(double)); reclaimconstant(tmp); } break; case NC_STRING: { char* p = NULL; NCConstant* tmp = nullconst(); tmp->nctype = NC_STRING; convert1(instance,tmp); p = emalloc(tmp->value.stringv.len+1); memcpy(p,tmp->value.stringv.stringv,tmp->value.stringv.len); p[tmp->value.stringv.len] = '\0'; bbAppendn(databuf,&p,sizeof(char*)); reclaimconstant(tmp); } break; default: stat = NC_EINTERNAL; goto done; /* Should never happen */ } break; /*switch*/ } break; /*NC_PRIM*/ case NC_ENUM: { Symbol* basetype = tsym->typ.basetype; /* Pretend */ stat = bin_generate_data_r(instance,basetype,fillvalue,databuf); } break; case NC_OPAQUE: { unsigned char* bytes = NULL; size_t len = 0; if(instance->nctype != NC_OPAQUE) {stat = NC_EBADTYPE; goto done;} /* Assume the opaque string has been normalized */ bytes=makebytestring(instance->value.opaquev.stringv,&len); if(bytes == NULL) {stat = NC_ENOMEM; goto done;} bbAppendn(databuf,(void*)bytes,len); free(bytes); } break; case NC_VLEN: { Datalist* sublist = NULL; Bytebuffer* vlendata = NULL; nc_vlen_t p; if(instance->nctype != NC_COMPOUND) { nclog(NCLOGERR,"Translating vlen: expected sublist"); stat = NC_EBADTYPE; goto done; } sublist = instance->value.compoundv; vlendata = bbNew(); if((stat = binary_generate_data(sublist,tsym->typ.basetype,NULL,vlendata))) goto done; p.len = datalistlen(sublist); p.p = bbContents(vlendata); bbAppendn(databuf,(char*)&p,sizeof(nc_vlen_t)); } break; case NC_COMPOUND: { /* The really hard one */ size_t nfields, fid, i; Datalist* cmpd = instance->value.compoundv; write_alignment(tsym->typ.cmpdalign,databuf); /* Get info about each field in turn and build it*/ nfields = listlength(tsym->subnodes); for(fid=0;fid<nfields;fid++) { Symbol* field = listget(tsym->subnodes,fid); NCConstant* fieldinstance = datalistith(cmpd,fid); int ndims = field->typ.dimset.ndims; size_t arraycount; if(ndims == 0) { ndims=1; /* fake the scalar case */ } /* compute the total number of elements in the field array */ arraycount = 1; for(i=0;i<ndims;i++) arraycount *= field->typ.dimset.dimsyms[i]->dim.declsize; write_alignment(field->typ.alignment,databuf); /* Write the instances */ for(i=0;i<arraycount;i++) { if((stat = bin_generate_data_r(fieldinstance, field->typ.basetype, NULL, databuf))) goto done; } } } break; default: stat = NC_EINTERNAL; goto done; /* Should never happen */ } done: return stat; }
static void processattributes(void) { int i,j; /* process global attributes*/ for(i=0;i<listlength(gattdefs);i++) { Symbol* asym = (Symbol*)listget(gattdefs,i); if(asym->typ.basetype == NULL) inferattributetype(asym); /* fill in the typecode*/ asym->typ.typecode = asym->typ.basetype->typ.typecode; if(asym->data != NULL && asym->data->length == 0) { NCConstant* empty = NULL; /* If the attribute has a zero length, then default it; note that it must be of type NC_CHAR */ if(asym->typ.typecode != NC_CHAR) semerror(asym->lineno,"Empty datalist can only be assigned to attributes of type char",fullname(asym)); empty = emptystringconst(asym->lineno); dlappend(asym->data,empty); } validateNIL(asym); } /* process per variable attributes*/ for(i=0;i<listlength(attdefs);i++) { Symbol* asym = (Symbol*)listget(attdefs,i); /* If no basetype is specified, then try to infer it; the exception is _Fillvalue, whose type is that of the containing variable. */ if(strcmp(asym->name,specialname(_FILLVALUE_FLAG)) == 0) { /* This is _Fillvalue */ asym->typ.basetype = asym->att.var->typ.basetype; /* its basetype is same as its var*/ /* put the datalist into the specials structure */ if(asym->data == NULL) { /* Generate a default fill value */ asym->data = getfiller(asym->typ.basetype); } if(asym->att.var->var.special->_Fillvalue != NULL) reclaimdatalist(asym->att.var->var.special->_Fillvalue); asym->att.var->var.special->_Fillvalue = clonedatalist(asym->data); } else if(asym->typ.basetype == NULL) { inferattributetype(asym); } /* fill in the typecode*/ asym->typ.typecode = asym->typ.basetype->typ.typecode; if(asym->data->length == 0) { NCConstant* empty = NULL; /* If the attribute has a zero length, and is char type, then default it */ if(asym->typ.typecode != NC_CHAR) semerror(asym->lineno,"Empty datalist can only be assigned to attributes of type char",fullname(asym)); empty = emptystringconst(asym->lineno); dlappend(asym->data,empty); } validateNIL(asym); } /* collect per-variable attributes per variable*/ for(i=0;i<listlength(vardefs);i++) { Symbol* vsym = (Symbol*)listget(vardefs,i); List* list = listnew(); for(j=0;j<listlength(attdefs);j++) { Symbol* asym = (Symbol*)listget(attdefs,j); if(asym->att.var == NULL) continue; /* ignore globals for now */ if(asym->att.var != vsym) continue; listpush(list,(void*)asym); } vsym->var.attributes = list; } }
/** The basic idea is to split the set of dimensions into groups and iterate over each group. A group is defined as the range of indices starting at an unlimited dimension upto (but not including) the next unlimited. The first group starts at index 0, even if dimension 0 is not unlimited. The last group is everything from the last unlimited dimension thru the last dimension (index rank-1). */ static void generate_arrayr(Symbol* vsym, Bytebuffer* code, Datalist* list, Odometer* odom, int dimindex, Datalist* filler, Generator* generator ) { int uid,i; Symbol* basetype = vsym->typ.basetype; Dimset* dimset = &vsym->typ.dimset; int rank = dimset->ndims; int lastunlimited = findlastunlimited(dimset); int nextunlimited = findunlimited(dimset,dimindex+1); int typecode = basetype->typ.typecode; int islastgroup = (lastunlimited == rank || dimindex >= lastunlimited || dimindex == rank-1); Odometer* subodom = NULL; ASSERT(rank > 0); ASSERT((dimindex >= 0 && dimindex < rank)); if(islastgroup) { /* Handle NC_CHAR case separately */ if(typecode == NC_CHAR) { Bytebuffer* charbuf = bbNew(); gen_chararray(dimset,dimindex,list,charbuf,filler); generator->charconstant(generator,code,charbuf); bbFree(charbuf); } else { /* build a special odometer to walk the last few dimensions */ subodom = newsubodometer(odom,dimset,dimindex,rank); generator->listbegin(generator,LISTDATA,list->length,code,&uid); for(i=0;odometermore(subodom);i++) { size_t offset = odometeroffset(subodom); NCConstant* con = datalistith(list,offset); generator->list(generator,LISTDATA,uid,i,code); generate_basetype(basetype,con,code,filler,generator); odometerincr(subodom); } generator->listend(generator,LISTDATA,uid,i,code); odometerfree(subodom); subodom = NULL; } } else {/* !islastgroup */ /* Our datalist must be a list of compounds representing the next unlimited; so walk the subarray from this index upto next unlimited. */ ASSERT((dimindex < nextunlimited)); ASSERT((isunlimited(dimset,nextunlimited))); /* build a sub odometer */ subodom = newsubodometer(odom,dimset,dimindex,nextunlimited); for(i=0;odometermore(subodom);i++) { size_t offset = odometeroffset(subodom); NCConstant* con = datalistith(list,offset); if(con == NULL || con->nctype == NC_FILL) { if(filler == NULL) filler = getfiller(vsym); generate_arrayr(vsym,code,filler,odom,nextunlimited,NULL,generator); } else if(islistconst(con)) { Datalist* sublist = compoundfor(con); generate_arrayr(vsym,code,sublist,odom,nextunlimited,filler,generator); } else { semerror(constline(con),"Expected {...} representing unlimited list"); return; } odometerincr(subodom); } odometerfree(subodom); subodom = NULL; } if(subodom != NULL) odometerfree(subodom); return; }
/* 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); } }