Added code to support NIL

values for strings in ncgen.
Needs test cases.
This commit is contained in:
Dennis Heimbigner 2013-07-10 20:00:48 +00:00
parent 6cd8fca60d
commit 483cbf94fe
19 changed files with 1214 additions and 1106 deletions

4
cf
View File

@ -16,8 +16,8 @@ DAP=1
#M32=1
#M64=1
#INSTALL=1
#PREFIX=/usr/local
INSTALL=1
PREFIX=/usr/local
if test "x$cmds" = x ; then
cmds=""

View File

@ -1,9 +1,12 @@
# Test c output
T=z
T=niltest
#VG=valgrind --leak-check=full
CFLAGS=-I../include -I/share/ed/local/spock/include
LDFLAGS=../liblib/.libs/libnetcdf.a -L/share/ed/local/spock/lib -lhdf5_hl -lhdf5 -lz -lcurl -lm -llber -lldap -lrt -lssl -lcrypto -ldl
#CFLAGS=-I../include -I/share/ed/local/spock/include
#LDFLAGS=../liblib/.libs/libnetcdf.a -L/share/ed/local/spock/lib -lhdf5_hl -lhdf5 -lz -lcurl -lm -llber -lldap -lrt -lssl -lcrypto -ldl
CFLAGS=-I../include -I/user/local/include
LDFLAGS=../liblib/.libs/libnetcdf.a -L/usr/local/lib -lhdf5_hl -lhdf5 -lz -lcurl -lm -lrt -ldl
CLASSPATH=".:ncCore-4.2.jar"

View File

@ -76,14 +76,20 @@ bin_constant(Generator* generator, Constant* con, Bytebuffer* buf,...)
su64.i64 = con->value.uint64v;
bbAppendn(buf,(void*)su64.ch,sizeof(su64.ch));
} break;
case NC_NIL:
case NC_STRING: {
char* ptr;
int len = (size_t)con->value.stringv.len;
ptr = (char*)malloc(len+1);
memcpy(ptr,con->value.stringv.stringv,len);
ptr[len] = '\0';
bbAppendn(buf,(void*)&ptr,sizeof(ptr));
} break;
if(len == 0 && con->value.stringv.stringv == NULL) {
char* nil = NULL;
bbAppendn(buf,(void*)&nil,sizeof(nil));
} else {
ptr = (char*)malloc(len+1);
memcpy(ptr,con->value.stringv.stringv,len);
ptr[len] = '\0';
bbAppendn(buf,(void*)&ptr,sizeof(ptr));
}
} break;
default: PANIC1("bin_constant: unexpected type: %d",con->nctype);
}

View File

@ -81,13 +81,19 @@ c_constant(Generator* generator, Constant* con, Bytebuffer* buf,...)
case NC_ECONST:
bbprintf(codetmp,"%s",cname(con->value.enumv));
break;
case NC_NIL:
case NC_STRING: { /* handle separately */
char* escaped = escapify(con->value.stringv.stringv,
if(con->value.stringv.len == 0 && con->value.stringv.stringv == NULL) {
char* nil = NULL;
bbprintf(codetmp,"NULL");
} else {
char* escaped = escapify(con->value.stringv.stringv,
'"',con->value.stringv.len);
special = poolalloc(1+2+strlen(escaped));
strcpy(special,"\"");
strcat(special,escaped);
strcat(special,"\"");
special = poolalloc(1+2+strlen(escaped));
strcpy(special,"\"");
strcat(special,escaped);
strcat(special,"\"");
}
} break;
case NC_OPAQUE: {
char* p;

View File

@ -540,6 +540,12 @@ case CASE(NC_OPAQUE,NC_OPAQUE):
tmp.opaquev.len = src->value.opaquev.len;
tmp.opaquev.stringv[tmp.opaquev.len] = '\0';
break;
case CASE(NC_NIL,NC_NIL):
break; /* probably will never happen */
case CASE(NC_NIL,NC_STRING):
tmp.stringv.len = 0;
tmp.stringv.stringv = NULL;
break;
/* We are missing all CASE(X,NC_ECONST) cases*/

View File

@ -18,6 +18,8 @@ extern int lvsnprintf(char*, size_t, const char*, va_list);
Constant nullconstant;
Constant fillconstant;
Datalist nildatalist; // to support NIL keyword
Bytebuffer* codebuffer;
Bytebuffer* codetmp;
Bytebuffer* stmt;

View File

@ -120,6 +120,8 @@ int srcline(Datasrc* ds);
#define isfillconst(con) ((con)!=NULL && (con)->nctype == NC_FILLVALUE)
#define constline(con) (con==NULL?0:(con)->lineno)
#define isnilconst(con) ((con)!=NULL && (con)->nctype == NC_NIL)
Constant* emptystringconst(int,Constant*);
Constant cloneconstant(Constant* con); /* shallow clone*/
@ -157,6 +159,7 @@ Constant* srcpeek(Datasrc*);
extern Constant nullconstant;
extern Constant fillconstant;
extern Constant nilconstant;
/* From genchar.c */
void gen_charattr(Datalist*, Bytebuffer*);

View File

@ -1,7 +1,7 @@
# test: ../ncdump/cdl4/ref_const_test.cdl
# test: ../ncdump/cdl4/ref_tst_chardata.cdl
K="-k3"
F="fail.cdl"
F="niltest.cdl"
#B="-B12"
DBG="-d"
#DBG="-D2"

View File

@ -455,11 +455,11 @@ genbin_writeattr(Generator* generator, Symbol* asym, Bytebuffer* databuf,
} break;
#ifdef USE_NETCDF4
case NC_STRING: {
const char** data;
const char** data;
data = (const char**)bbContents(databuf);
stat = nc_put_att_string(grpid,varid,asym->name,
bbLength(databuf)/sizeof(char*),
data);
bbLength(databuf)/sizeof(char*),
data);
} break;
case NC_UBYTE: {
unsigned char* data = (unsigned char*)bbContents(databuf);

View File

@ -948,18 +948,18 @@ genc_writevar(Generator* generator, Symbol* vsym, Bytebuffer* code,
}
if(rank == 0) {
codelined(1,"size_t zero = 0;");
codelined(1,"size_t count = 0;");
/* We make the data be an array so we do not need to
ampersand it later => we need an outer pair of braces
*/
commify(code); /* insert commas at proper places */
bbprintf0(stmt,"%sstatic %s %s_data[1] = {%s};\n",
commify(code); /* insert commas at proper places */
bbprintf0(stmt,"%sstatic %s %s_data[1] = {%s};\n",
indented(1),
ctypename(basetype),
cname(vsym),
bbContents(code));
codedump(stmt);
bbprintf0(stmt,"%sstat = nc_put_var1(%s, %s, &zero, %s_data);\n",
bbprintf0(stmt,"%sstat = nc_put_var1(%s, %s, &count, %s_data);\n",
indented(1),
groupncid(vsym->container),
varncid(vsym),
@ -1055,27 +1055,26 @@ genc_writeattr(Generator* generator, Symbol* asym, Bytebuffer* code,
cquotestring(code,'"');
} else {
/* All other cases */
/* Dump any vlen decls first */
List* vlendecls;
generator_getstate(generator,(void**)&vlendecls);
if(vlendecls != NULL && listlength(vlendecls) > 0) {
int i;
for(i=0;i<listlength(vlendecls);i++) {
Bytebuffer* decl = (Bytebuffer*)listget(vlendecls,i);
codelined(1,bbContents(decl));
bbFree(decl);
}
listfree(vlendecls);
generator_reset(generator,NULL);
}
/* Dump any vlen decls first */
List* vlendecls;
generator_getstate(generator,(void**)&vlendecls);
if(vlendecls != NULL && listlength(vlendecls) > 0) {
int i;
for(i=0;i<listlength(vlendecls);i++) {
Bytebuffer* decl = (Bytebuffer*)listget(vlendecls,i);
codelined(1,bbContents(decl));
bbFree(decl);
}
listfree(vlendecls);
generator_reset(generator,NULL);
}
commify(code);
bbprintf0(stmt,"%sstatic const %s %s_att[%ld] = ",
indented(1),
ctypename(basetype),
cname(asym),
asym->data->length
);
indented(1),
ctypename(basetype),
cname(asym),
asym->data->length
);
codedump(stmt);
codepartial("{");
codedump(code);

View File

@ -58,7 +58,7 @@ generate_attrdata(Symbol* asym, Generator* generator, Writer writer, Bytebuffer*
Symbol* basetype = asym->typ.basetype;
nc_type typecode = basetype->typ.typecode;
if(typecode == NC_CHAR) {
if(typecode == NC_CHAR) {
gen_charattr(asym->data,codebuf);
} else {
int uid;

View File

@ -359,6 +359,9 @@ distinguished variable attribute named `_FillValue'. The
types of constants need not match the type declared for a variable;
coercions are done to convert integers to floating point, for example.
The constant `_' can be used to designate the fill value for a variable.
If the type of the variable is explicitly `string', then the special
constant `NIL` can be used to represent a nil string, which is not the
same as a zero length string.
.SS "Primitive Data Types"
.LP
.RS
@ -594,6 +597,8 @@ type to ensure the proper choice.
String constants are assumed to always be UTF-8 encoded. This
specifically means that the string constant may actually
contain multi-byte UTF-8 characters.
The special constant `NIL` can be used to represent a nil string, which is not the
same as a zero length string.
.LP
\fIOpaque\fP constants are represented as
sequences of hexadecimal digits preceded by 0X or 0x: 0xaa34ffff,
@ -646,24 +651,25 @@ The type being referenced (t1) is the one within group g2, which in
turn is nested in group g1.
The similarity of this notation to Unix file paths is deliberate,
and one can consider groups as a form of directory structure.
.HP
1. When name is not prefixed, then scope rules are applied to locate the
.LP
When name is not prefixed, then scope rules are applied to locate the
specified declaration. Currently, there are three rules: one for dimensions,
one for types and enumeration constants, and one for all others.
.HP
2. When an unprefixed name of a dimension is used (as in a variable declaration),
ncgen first looks in the immediately enclosing group for the dimension.
If it is not found there, then it looks in the group enclosing this group.
This continues up the group hierarchy until the dimension is found,
or there are no more groups to search.
1. When an unprefixed name of a dimension is used (as in a
variable declaration), ncgen first looks in the immediately
enclosing group for the dimension. If it is not found
there, then it looks in the group enclosing this group.
This continues up the group hierarchy until the dimension is
found, or there are no more groups to search.
.HP
3. For all other names, only the immediately enclosing group is searched.
.LP
When an unprefixed name of a type or an enumeration constant
2. When an unprefixed name of a type or an enumeration constant
is used, ncgen searches the group tree using a pre-order depth-first
search. This essentially means that it will find the matching declaration
that precedes the reference textually in the cdl file and that
is "highest" in the group hierarchy.
.HP
3. For all other names, only the immediately enclosing group is searched.
.LP
One final note. Forward references are not allowed.
This means that specifying, for example,

View File

@ -41,7 +41,9 @@
#define NC_LIST NC_COMPOUND /* alias */
/* Extend nc types with generic fill value*/
#define NC_FILLVALUE 31
#define NC_FILLVALUE 31
/* Extend nc types with NIL value*/
#define NC_NIL 32
/* Must be a better way to do this */
#ifndef INFINITE

View File

@ -258,6 +258,16 @@ NaNf|nanf { /* missing value (pre-2.4 backward compatibility) */
return lexdebug(FLOAT_CONST);
}
NIL|nil|Nil {
#ifdef USE_NETCDF4
if(c_flag != 0 || binary_flag != 0)
return lexdebug(NIL);
yyerror("NIL only allowed for netcdf-4 and for -lc or -lb");
#else
yyerror("NIL only allowed for netcdf-4 and for -lc or -lb");
#endif
}
{PATH} {
bbClear(lextext);
bbAppendn(lextext,(char*)yytext,yyleng+1); /* include null */

View File

@ -162,7 +162,7 @@ Constant constant;
UINT_CONST /* unsigned long long constant */
UINT64_CONST /* unsigned int constant */
FLOAT_CONST /* float constant */
DOUBLE_CONST /* double constant */
DOUBLE_CONST/* double constant */
DIMENSIONS /* keyword starting dimensions section, if any */
VARIABLES /* keyword starting variables section, if any */
NETCDF /* keyword declaring netcdf name */
@ -175,6 +175,7 @@ Constant constant;
GROUP
PATH /* / or (/IDENT)+ */
FILLMARKER /* "_" as opposed to the attribute */
NIL /* NIL */
_FILLVALUE
_FORMAT
_STORAGE
@ -805,6 +806,7 @@ constdata:
simpleconstant {$$=$1;}
| OPAQUESTRING {$$=makeconstdata(NC_OPAQUE);}
| FILLMARKER {$$=makeconstdata(NC_FILLVALUE);}
| NIL {$$=makeconstdata(NC_NIL);}
| path {$$=makeenumconst($1);}
| function
;
@ -1042,11 +1044,14 @@ makeconstdata(nc_type nctype)
con.value.opaquev.stringv = s;
con.value.opaquev.len = len;
} break;
case NC_NIL:
break; /* no associated value*/
#endif
case NC_FILLVALUE:
break; /* no associated value*/
default:
yyerror("Data constant: unexpected NC type: %s",
nctypename(nctype));

File diff suppressed because it is too large Load Diff

View File

@ -83,16 +83,17 @@ extern int ncgdebug;
GROUP = 292,
PATH = 293,
FILLMARKER = 294,
_FILLVALUE = 295,
_FORMAT = 296,
_STORAGE = 297,
_CHUNKSIZES = 298,
_DEFLATELEVEL = 299,
_SHUFFLE = 300,
_ENDIANNESS = 301,
_NOFILL = 302,
_FLETCHER32 = 303,
DATASETID = 304
NIL = 295,
_FILLVALUE = 296,
_FORMAT = 297,
_STORAGE = 298,
_CHUNKSIZES = 299,
_DEFLATELEVEL = 300,
_SHUFFLE = 301,
_ENDIANNESS = 302,
_NOFILL = 303,
_FLETCHER32 = 304,
DATASETID = 305
};
#endif
@ -112,7 +113,7 @@ Constant constant;
/* Line 2077 of yacc.c */
#line 116 "ncgen.tab.h"
#line 117 "ncgen.tab.h"
} YYSTYPE;
# define YYSTYPE_IS_TRIVIAL 1
# define yystype YYSTYPE /* obsolescent; will be withdrawn */

File diff suppressed because it is too large Load Diff

View File

@ -20,8 +20,8 @@ static void processspecials(void);
static void processunlimiteddims(void);
static void inferattributetype(Symbol* asym);
static void validateNIL(Symbol* sym);
static void checkconsistency(void);
static void validate(void);
static int tagvlentypes(Symbol* tsym);
static Symbol* uniquetreelocate(Symbol* refsym, Symbol* root);
@ -53,8 +53,6 @@ processsemantics(void)
processunlimiteddims();
/* check internal consistency*/
checkconsistency();
/* do any needed additional semantic checks*/
validate();
}
/*
@ -445,6 +443,8 @@ processvars(void)
if(usingclassic && j != 0)
semerror(vsym->lineno,"Variable: %s: UNLIMITED must be in first dimension only",fullname(vsym));
}
/* validate uses of NIL */
validateNIL(vsym);
}
}
}
@ -583,29 +583,24 @@ processattributes(void)
/* 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;
if(asym->data->length == 0) {
/* 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));
asym->data = builddatalist(1);
emptystringconst(asym->lineno,&asym->data->data[asym->data->length]);
}
validateNIL(asym);
}
/* 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
the exception is _Fillvalue, whose type is that of the
containing variable.
*/
if(strcmp(asym->name,specialname(_FILLVALUE_FLAG)) == 0) {
@ -622,6 +617,14 @@ processattributes(void)
}
/* fill in the typecode*/
asym->typ.typecode = asym->typ.basetype->typ.typecode;
if(asym->data->length == 0) {
/* 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));
asym->data = builddatalist(1);
emptystringconst(asym->lineno,&asym->data->data[asym->data->length]);
}
validateNIL(asym);
}
/* collect per-variable attributes per variable*/
for(i=0;i<listlength(vardefs);i++) {
@ -708,6 +711,34 @@ inferattributetype(Symbol* asym)
asym->typ.basetype = basetypefor(nctype);
}
#ifdef USE_NETCDF4
/* recursive helper for validataNIL */
static void
validateNILr(Datalist* src)
{
int i;
for(i=0;i<src->length;i++) {
Constant* con = datalistith(src,i);
if(isnilconst(con))
semerror(con->lineno,"NIL data can only be assigned to variables or attributes of type string");
else if(islistconst(con)) /* recurse */
validateNILr(con->value.compoundv);
}
}
#endif
static void
validateNIL(Symbol* sym)
{
#ifdef USE_NETCDF4
Datalist* datalist = sym->data;
if(sym->data == NULL || datalist->length == 0) return;
if(sym->typ.typecode == NC_STRING) return;
validateNILr(sym->data);
#endif
}
/* Find name within group structure*/
Symbol*
lookupgroup(List* prefix)
@ -826,16 +857,6 @@ checkconsistency(void)
}
}
static void
validate(void)
{
int i;
for(i=0;i<listlength(vardefs);i++) {
Symbol* sym = (Symbol*)listget(vardefs,i);
if(sym->var.special._Fillvalue != NULL) {
}
}
}
static void
computeunlimitedsizes(Dimset* dimset, int dimindex, Datalist* data, int ischar)
{