/********************************************************************* * Copyright 2018, UCAR/Unidata * See netcdf/COPYRIGHT file for copying and redistribution conditions. * $Id: ncgen.y,v 1.34 2010/03/31 18:18:41 dmh Exp $ *********************************************************************/ /* yacc source for "ncgen", a netCDL parser and netCDF generator */ %{ #ifdef sccs static char SccsId[] = "$Id: ncgen.y,v 1.34 2010/03/31 18:18:41 dmh Exp $"; #endif #include "config.h" #include #include #include #include "netcdf.h" #include "generic.h" #include "ncgen.h" #include "genlib.h" /* for grow_darray() et al */ typedef struct Symbol { /* symbol table entry */ char *name; struct Symbol *next; unsigned is_dim : 1; /* appears as netCDF dimension */ unsigned is_var : 1; /* appears as netCDF variable */ unsigned is_att : 1; /* appears as netCDF attribute */ int dnum; /* handle as a dimension */ int vnum; /* handle as a variable */ } *YYSTYPE1; /* True if string a equals string b*/ #ifndef STREQ #define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0) #endif #define NC_UNSPECIFIED ((nc_type)0) /* unspecified (as yet) type */ #define YYSTYPE YYSTYPE1 YYSTYPE symlist; /* symbol table: linked list */ extern int derror_count; /* counts errors in netcdf definition */ extern int lineno; /* line number for error messages */ static int not_a_string; /* whether last constant read was a string */ static char termstring[MAXTRST]; /* last terminal string read */ static double double_val; /* last double value read */ static float float_val; /* last float value read */ static int int_val; /* last int value read */ static short short_val; /* last short value read */ static char char_val; /* last char value read */ static signed char byte_val; /* last byte value read */ static nc_type type_code; /* holds declared type for variables */ static nc_type atype_code; /* holds derived type for attributes */ static char *netcdfname; /* to construct netcdf file name */ static void *att_space; /* pointer to block for attribute values */ static nc_type valtype; /* type code for list of attribute values */ static char *char_valp; /* pointers used to accumulate data values */ static signed char *byte_valp; static short *short_valp; static int *int_valp; static float *float_valp; static double *double_valp; static void *rec_cur; /* pointer to where next data value goes */ static void *rec_start; /* start of space for data */ /* Forward declarations */ void defatt(void); void equalatt(void); #ifdef YYLEX_PARAM int yylex(YYLEX_PARAM); #else int yylex(void); #endif #ifdef vms void yyerror(char*); #else int yyerror(char*); #endif %} /* DECLARATIONS */ %token NC_UNLIMITED_K /* keyword for unbounded record dimension */ BYTE_K /* keyword for byte datatype */ CHAR_K /* keyword for char datatype */ SHORT_K /* keyword for short datatype */ INT_K /* keyword for int datatype */ FLOAT_K /* keyword for float datatype */ DOUBLE_K /* keyword for double datatype */ IDENT /* name for a dimension, variable, or attribute */ TERMSTRING /* terminal string */ BYTE_CONST /* byte constant */ CHAR_CONST /* char constant */ SHORT_CONST /* short constant */ INT_CONST /* int constant */ FLOAT_CONST /* float constant */ DOUBLE_CONST /* double constant */ DIMENSIONS /* keyword starting dimensions section, if any */ VARIABLES /* keyword starting variables section, if any */ NETCDF /* keyword declaring netcdf name */ DATA /* keyword starting data section, if any */ FILLVALUE /* fill value, from _FillValue attribute or default */ %start ncdesc /* start symbol for grammar */ %% /* RULES */ ncdesc: NETCDF '{' { init_netcdf(); } dimsection /* dimension declarations */ vasection /* variable and attribute declarations */ { if (derror_count == 0) define_netcdf(netcdfname); if (derror_count > 0) exit(6); } datasection /* data, variables loaded as encountered */ '}' { if (derror_count == 0) close_netcdf(); } ; dimsection: /* empty */ | DIMENSIONS dimdecls ; dimdecls: dimdecline ';' | dimdecls dimdecline ';' ; dimdecline: dimdecl | dimdecline ',' dimdecl ; dimdecl: dimd '=' INT_CONST { if (int_val <= 0) derror("dimension length must be positive"); dims[ndims].size = (size_t)int_val; ndims++; } | dimd '=' DOUBLE_CONST { /* for rare case where 2^31 < dimsize < 2^32 */ if (double_val <= 0) derror("dimension length must be positive"); if (double_val > 4294967295.0) derror("dimension too large"); if (double_val - (size_t) double_val > 0) derror("dimension length must be an integer"); dims[ndims].size = (size_t) double_val; ndims++; } | dimd '=' NC_UNLIMITED_K { if (rec_dim != -1) derror("only one NC_UNLIMITED dimension allowed"); rec_dim = ndims; /* the unlimited (record) dimension */ dims[ndims].size = NC_UNLIMITED; ndims++; } ; dimd: dim { if ($1->is_dim == 1) { derror( "duplicate dimension declaration for %s", $1->name); } $1->is_dim = 1; $1->dnum = ndims; /* make sure dims array will hold dimensions */ grow_darray(ndims, /* must hold ndims+1 dims */ &dims); /* grow as needed */ dims[ndims].name = (char *) emalloc(strlen($1->name)+1); (void) strcpy(dims[ndims].name, $1->name); /* name for use in generated Fortran and C variables */ dims[ndims].lname = decodify($1->name); } ; dim: IDENT ; vasection: /* empty */ | VARIABLES vadecls | gattdecls ; vadecls: vadecl ';' | vadecls vadecl ';' ; vadecl: vardecl | attdecl | gattdecl ; gattdecls: gattdecl ';' | gattdecls gattdecl ';' ; vardecl: type varlist ; type: BYTE_K { type_code = NC_BYTE; } | CHAR_K { type_code = NC_CHAR; } | SHORT_K { type_code = NC_SHORT; } | INT_K { type_code = NC_INT; } | FLOAT_K { type_code = NC_FLOAT; } | DOUBLE_K{ type_code = NC_DOUBLE; } ; varlist: varspec | varlist ',' varspec ; varspec: var { static struct vars dummyvar; dummyvar.name = "dummy"; dummyvar.type = NC_DOUBLE; dummyvar.ndims = 0; dummyvar.dims = 0; dummyvar.fill_value.doublev = NC_FILL_DOUBLE; dummyvar.has_data = 0; nvdims = 0; /* make sure variable not re-declared */ if ($1->is_var == 1) { derror( "duplicate variable declaration for %s", $1->name); } $1->is_var = 1; $1->vnum = nvars; /* make sure vars array will hold variables */ grow_varray(nvars, /* must hold nvars+1 vars */ &vars); /* grow as needed */ vars[nvars] = dummyvar; /* to make Purify happy */ vars[nvars].name = (char *) emalloc(strlen($1->name)+1); (void) strcpy(vars[nvars].name, $1->name); /* name for use in generated Fortran and C variables */ vars[nvars].lname = decodify($1->name); vars[nvars].type = type_code; /* set default fill value. You can override this with * the variable attribute "_FillValue". */ nc_getfill(type_code, &vars[nvars].fill_value); vars[nvars].has_data = 0; /* has no data (yet) */ } dimspec { vars[nvars].ndims = nvdims; nvars++; } ; var: IDENT ; dimspec: /* empty */ | '(' dimlist ')' ; dimlist: vdim | dimlist ',' vdim ; vdim: dim { if (nvdims >= NC_MAX_VAR_DIMS) { derror("%s has too many dimensions",vars[nvars].name); } if ($1->is_dim == 1) dimnum = $1->dnum; else { derror( "%s is not declared as a dimension", $1->name); dimnum = ndims; } if (rec_dim != -1 && dimnum == rec_dim && nvdims != 0) { derror("unlimited dimension must be first"); } grow_iarray(nvdims, /* must hold nvdims+1 ints */ &vars[nvars].dims); /* grow as needed */ vars[nvars].dims[nvdims] = dimnum; nvdims++; } ; attdecl: att { defatt(); } '=' attvallist { equalatt(); } ; gattdecl: gatt { defatt(); } '=' attvallist { equalatt(); } ; att: avar ':' attr gatt: ':' attr { varnum = NC_GLOBAL; /* handle of "global" attribute */ } ; avar: var { if ($1->is_var == 1) varnum = $1->vnum; else { derror("%s not declared as a variable, fatal error", $1->name); YYABORT; } } ; attr: IDENT { /* make sure atts array will hold attributes */ grow_aarray(natts, /* must hold natts+1 atts */ &atts); /* grow as needed */ atts[natts].name = (char *) emalloc(strlen($1->name)+1); (void) strcpy(atts[natts].name,$1->name); /* name for use in generated Fortran and C variables */ atts[natts].lname = decodify($1->name); } ; attvallist: aconst | attvallist ',' aconst ; aconst: attconst { if (valtype == NC_UNSPECIFIED) valtype = atype_code; if (valtype != atype_code) derror("values for attribute must be all of same type"); } ; attconst: CHAR_CONST { atype_code = NC_CHAR; *char_valp++ = char_val; valnum++; } | TERMSTRING { atype_code = NC_CHAR; { /* don't null-terminate attribute strings */ size_t len = strlen(termstring); if (len == 0) /* need null if that's only value */ len = 1; (void)strncpy(char_valp,termstring,len); valnum += len; char_valp += len; } } | BYTE_CONST { atype_code = NC_BYTE; *byte_valp++ = byte_val; valnum++; } | SHORT_CONST { atype_code = NC_SHORT; *short_valp++ = short_val; valnum++; } | INT_CONST { atype_code = NC_INT; *int_valp++ = int_val; valnum++; } | FLOAT_CONST { atype_code = NC_FLOAT; *float_valp++ = float_val; valnum++; } | DOUBLE_CONST { atype_code = NC_DOUBLE; *double_valp++ = double_val; valnum++; } ; datasection: /* empty */ | DATA datadecls | DATA ; datadecls: datadecl ';' | datadecls datadecl ';' ; datadecl: avar { valtype = vars[varnum].type; /* variable type */ valnum = 0; /* values accumulated for variable */ vars[varnum].has_data = 1; /* compute dimensions product */ var_size = nctypesize(valtype); if (vars[varnum].ndims == 0) { /* scalar */ var_len = 1; } else if (vars[varnum].dims[0] == rec_dim) { var_len = 1; /* one record for unlimited vars */ } else { var_len = dims[vars[varnum].dims[0]].size; } for(dimnum = 1; dimnum < vars[varnum].ndims; dimnum++) var_len = var_len*dims[vars[varnum].dims[dimnum]].size; /* allocate memory for variable data */ if (var_len*var_size != (size_t)(var_len*var_size)) { derror("variable %s too large for memory", vars[varnum].name); exit(9); } rec_len = var_len; rec_start = malloc ((size_t)(rec_len*var_size)); if (rec_start == 0) { derror ("out of memory\n"); exit(3); } rec_cur = rec_start; switch (valtype) { case NC_CHAR: char_valp = (char *) rec_start; break; case NC_BYTE: byte_valp = (signed char *) rec_start; break; case NC_SHORT: short_valp = (short *) rec_start; break; case NC_INT: int_valp = (int *) rec_start; break; case NC_FLOAT: float_valp = (float *) rec_start; break; case NC_DOUBLE: double_valp = (double *) rec_start; break; default: break; } } '=' constlist { if (valnum < var_len) { /* leftovers */ nc_fill(valtype, var_len - valnum, rec_cur, vars[varnum].fill_value); } /* put out var_len values */ /* vars[varnum].nrecs = valnum / rec_len; */ vars[varnum].nrecs = var_len / rec_len; if (derror_count == 0) put_variable(rec_start); free ((char *) rec_start); } ; constlist: dconst | constlist ',' dconst ; dconst: { if(valnum >= var_len) { if (vars[varnum].dims[0] != rec_dim) { /* not recvar */ derror("too many values for this variable, %d >= %d", valnum, var_len); exit (4); } else { /* a record variable, so grow data container and increment var_len by multiple of record size */ ptrdiff_t rec_inc = (char *)rec_cur - (char *)rec_start; var_len = rec_len * (1 + valnum / rec_len); rec_start = erealloc(rec_start, var_len*var_size); rec_cur = (char *)rec_start + rec_inc; char_valp = (char *) rec_cur; byte_valp = (signed char *) rec_cur; short_valp = (short *) rec_cur; int_valp = (int *) rec_cur; float_valp = (float *) rec_cur; double_valp = (double *) rec_cur; } } not_a_string = 1; } const { if (not_a_string) { switch (valtype) { case NC_CHAR: rec_cur = (void *) char_valp; break; case NC_BYTE: rec_cur = (void *) byte_valp; break; case NC_SHORT: rec_cur = (void *) short_valp; break; case NC_INT: rec_cur = (void *) int_valp; break; case NC_FLOAT: rec_cur = (void *) float_valp; break; case NC_DOUBLE: rec_cur = (void *) double_valp; break; default: break; } } } ; const: CHAR_CONST { atype_code = NC_CHAR; switch (valtype) { case NC_CHAR: *char_valp++ = char_val; break; case NC_BYTE: *byte_valp++ = char_val; break; case NC_SHORT: *short_valp++ = char_val; break; case NC_INT: *int_valp++ = char_val; break; case NC_FLOAT: *float_valp++ = char_val; break; case NC_DOUBLE: *double_valp++ = char_val; break; default: break; } valnum++; } | TERMSTRING { not_a_string = 0; atype_code = NC_CHAR; { size_t len = strlen(termstring); if(valnum + len > var_len) { if (vars[varnum].dims[0] != rec_dim) { derror("too many values for this variable, %d>%d", valnum+len, var_len); exit (5); } else {/* a record variable so grow it */ ptrdiff_t rec_inc = (char *)rec_cur - (char *)rec_start; var_len += rec_len * (len + valnum - var_len)/rec_len; rec_start = erealloc(rec_start, var_len*var_size); rec_cur = (char *)rec_start + rec_inc; char_valp = (char *) rec_cur; } } switch (valtype) { case NC_CHAR: { int ld; size_t i, sl; (void)strncpy(char_valp,termstring,len); ld = vars[varnum].ndims-1; if (ld > 0) {/* null-fill to size of last dim */ sl = dims[vars[varnum].dims[ld]].size; for (i =len;i next) if (STREQ(sp -> name, sname)) { return sp; } return 0; /* 0 ==> not found */ } YYSTYPE install( /* install sname in symbol table */ const char *sname) { YYSTYPE sp; sp = (YYSTYPE) emalloc (sizeof (struct Symbol)); sp -> name = (char *) emalloc (strlen (sname) + 1);/* +1 for '\0' */ (void) strcpy (sp -> name, sname); sp -> next = symlist; /* put at front of list */ sp -> is_dim = 0; sp -> is_var = 0; sp -> is_att = 0; symlist = sp; return sp; } void clearout(void) /* reset symbol table to empty */ { YYSTYPE sp, tp; for (sp = symlist; sp != (YYSTYPE) 0;) { tp = sp -> next; free (sp -> name); free ((char *) sp); sp = tp; } symlist = 0; } /* get lexical input routine generated by lex */ /* Keep compile quiet */ #define YY_NO_UNPUT #define YY_NO_INPUT #include "ncgenl.c"