[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[netCDF #YRL-141737]: NetCDF-4.0 make check error



I see that there are a number of constant forms
missing. I will add them to the code base.
Good catch!

Chen Zhang wrote:
> New Client Reply: NetCDF-4.0 make check error
>
> Russ,
>
> Thank you for this "pre-alpha" ncgen4.
>
> When I used unsigned integers and int64 types in CDL, I met some
> problems. For example, put ushort type in CDL, such as "ushort
> Angle(size); Angle:_FillValue = 9999s;" didn't work. Where "9999s"
> should be "9999us" for ushort, but the suffix "us" wasn't supported by
> ncgen4. I modified two files "ncgen.l" and "ncgen.y" (see attached
> files) in ncgen4 to solve the above issues, now it works better.
>
> Thanks,
> Chen
>
>
> Unidata netCDF Support said the following on 10/3/2008 5:08 PM:
>> Chen,
>>
>> Here is the "pre-alpha" version of ncgen4.  Although our licensing
>> says you can redistribute this, we would prefer just referring
>> other potential users to us, and we'll make the latest version
>> available with all the caveats about alpha level software.
>>
>> --Russ
>>
>> Russ Rew                                         UCAR Unidata Program
>> address@hidden                     http://www.unidata.ucar.edu
>>
>>
>>
>> Ticket Details
>> ===================
>> Ticket ID: YRL-141737
>> Department: Support netCDF
>> Priority: Normal
>> Status: Closed
>
> %{
> /*********************************************************************
>  *   Copyright 1993, UCAR/Unidata
>  *   See netcdf/COPYRIGHT file for copying and redistribution conditions.
>  *   $Id: ncgen.l,v 1.1.1.1 2008/09/30 15:21:51 dmh Exp $
>  *********************************************************************/
>
> /* Problems:
> 1. Ideally, we assume the input is true ut8.
>    Unfortunately, we may actually get iso-latin-8859-1.
>    This means that there will be ambiguity about the characters
>    in the range 128-255 because they will look like n-byte unicode
>    when they are 1-byte 8859 characters. Because of our encoding,
>    8859 characters above 128 will be handles as n-byte utf8 and so
>    will probably not lex correctly.
>    Solution: assume utf8 and note in the documentation that
>    ISO8859 is specifically unsupported.
> 2. The netcdf function NC_check_name in string.c must be modified to
>    conform to the use of UTF8.
> 3. We actually have three tests for UTF8 of increasing correctness
>    (in the sense that the least correct will allow some sequences that
>     are technically illegal UTF8).
>    The tests are derived from the table at
>           http://www.w3.org/2005/03/23-lex-U
>    We include lexical definitions for all three, but use the second version.
> */
>
> /* lex specification for tokens for ncgen */
>
> /* Fill value used by ncdump from version 2.4 and later.  Should match
>    definition of FILL_STRING in ../ncdump/vardata.h */
> #define FILL_STRING "_"
> #define XDR_INT32_MIN (-2147483647-1)
> #define XDR_INT32_MAX 2147483647
> #define XDR_INT64_MIN  (-9223372036854775807LL-1)
> #define XDR_INT64_MAX  (9223372036854775807LL)
>
> char errstr[100];             /* for short error messages */
>
> int lineno;              /* line number for error messages */
> char* lextext;           /* name or string with escapes removed */
>
> #include <stdio.h>
> #include <ctype.h>
>
> #define YY_BREAK                /* defining as nothing eliminates unreachable
>                                  statement warnings from flex output,
>                                    but make sure every action ends with
>                                    "return" or "break"! */
>
> double double_val;             /* last double value read */
> float float_val;               /* last float value read */
> long long int64_val;           /* last int64 value read */
> int int32_val;                 /* last int32 value read */
> short int16_val;               /* last short value read */
> unsigned long long uint64_val; /* last int64 value read */
> unsigned int uint32_val;       /* last int32 value read */
> unsigned short uint16_val;     /* last short value read */
> char char_val;                 /* last char value read */
> char byte_val;                 /* last byte value read */
> unsigned char ubyte_val;       /* last byte value read */
>
> static Symbol* makepath(char* text);
>
> %}
>
> %p 6000
>
> /* The most correct (validating) version of UTF8 character set
>    (Taken from: http://www.w3.org/2005/03/23-lex-U)
>
> The lines of the expression cover the UTF8 characters as follows:
> 1. non-overlong 2-byte
> 2. excluding overlongs
> 3. straight 3-byte
> 4. excluding surrogates
> 5. straight 3-byte
> 6. planes 1-3
> 7. planes 4-15
> 8. plane 16
>
> UTF8   ([\xC2-\xDF][\x80-\xBF])                       \
>      | (\xE0[\xA0-\xBF][\x80-\xBF])                   \
>      | ([\xE1-\xEC][\x80-\xBF][\x80-\xBF])            \
>      | (\xED[\x80-\x9F][\x80-\xBF])                   \
>      | ([\xEE-\xEF][\x80-\xBF][\x80-\xBF])            \
>      | (\xF0[\x90-\xBF][\x80-\xBF][\x80-\xBF])        \
>      | ([\xF1-\xF3][\x80-\xBF][\x80-\xBF][\x80-\xBF]) \
>      | (\xF4[\x80-\x8F][\x80-\xBF][\x80-\xBF])        \
>
> */
>
> /* Wish there was some way to ifdef lex files */
>
> /*The most relaxed version of UTF8 (not used)
> UTF8 ([\xC0-\xD6].)|([\xE0-\xEF]..)|([\xF0-\xF7]...)
> */
>
> /*The partially relaxed version of UTF8, and the one used here */
> UTF8
([\xC0-\xD6][\x80-\xBF])|([\xE0-\xEF][\x80-\xBF][\x80-\xBF])|([\xF0-\xF7][\x80-\xBF][\x80-\xBF][\x80-\xBF])
>
> /* The old definition of ID
> ID ([A-Za-z_]|{UTF8})([A-Z.@#\[\]a-z_0-9+-]|{UTF8})*
> */
>
> /* Don't permit control characters or '/' in names, but other special
>    chars OK if escaped.  Note that to preserve backwards
>    compatibility, none of the characters _.@+- should be escaped, as
>    they were previously permitted in names without escaping.  */
>
> idescaped \\[ !"#$%&'()*,:;<=>?\[\\\]^`{|}~]
> numescaped \\[0-9]
>
> /* New definition to conform to a subset of string.c */
> ID ([a-zA-Z_]|{UTF8}|{numescaped})([a-zA-Z0-9_.@+-]|{UTF8}|{idescaped})*
>
> escaped               \\.
>
> /* Note: this definition of string will work for utf8 as well,
>    although it is a very relaxed definition
> */
> nonquotes     ([^"\\]|{escaped})*
> exp           ([eE][+-]?[0-9]+)
>
> OPAQUESTRING  (0[xX][0-9A-Fa-f]*)
>
> PATH    ([/]|([/]{ID})([/]{ID})*)
>
> %%
> \/\/.*                        { /* comment */
>                           break;
>                         }
>
> \/\*.*\*\/            { /* comment */
>                           break;
>                         }
>
> \"{nonquotes}\"               {
>                        /* In netcdf4, this will be used in a variety
>                             of places, so only remove escapes */
> /*
> if(yyleng > MAXTRST) {
> yyerror("string too long, truncated\n");
> yytext[MAXTRST-1] = '\0';
> }
> */
>                       if(lextext != NULL) free(lextext);
>                       lextext = emalloc(1+4*yyleng); /* should be max
>                                                              needed */
>                       /* Assumes expand escapes also does normalization */
>                       expand_escapes(lextext,(char *)yytext,yyleng);
>                       return (TERMSTRING);
>                       }
>
> {OPAQUESTRING}        { /* drop leading 0x; pad to event number of chars */
>               char* p = yytext+2;
>               int len = yyleng - 2;
>               int padlen = len;
>               if((padlen % 2) == 1) padlen++;
>               if(lextext != NULL) free(lextext);
>               lextext = emalloc(1+padlen);
>               strncpy(lextext,p,len+1); //include null
>               lextext[len] = '0'; // assume padding
>               lextext[padlen] = '\0'; // make sure null terminated
>               // convert all chars to lower case
>               for(p=lextext;*p;p++) *p = tolower(*p);
>               return (OPAQUESTRING);
>               }
>
> [cC]ompound|[sS]truct|[sS]tructure|STRUCT|COMPOUND|STRUCTURE {return
(COMPOUND);}
> enum|ENUM                             {return (ENUM);}
> opaque|OPAQUE                         {return (OPAQUE);}
>
> float|FLOAT|real|REAL {return (FLOAT_K);}
> char|CHAR             {return (CHAR_K);}
> byte|BYTE             {return (BYTE_K);}
> ubyte|UBYTE           {return (UBYTE_K);}
> short|SHORT           {return (SHORT_K);}
> ushort|USHORT         {return (USHORT_K);}
> long|LONG|int|INT|integer|INTEGER     {return (INT_K);}
> ulong|ULONG|uint|UINT|uinteger|UINTEGER       {return (UINT_K);}
> int64|INT64           {return (INT64_K);}
> uint64|UINT64         {return (UINT64_K);}
> double|DOUBLE         {return (DOUBLE_K);}
> unlimited|UNLIMITED   {int32_val = -1;
>                        return (NC_UNLIMITED_K);}
>
> group:|GROUP:         {return (GROUP);}
> types:|TYPES:         {return (TYPES);}
> dimensions:|DIMENSIONS:       {return (DIMENSIONS);}
> variables:|VARIABLES: {return (VARIABLES);}
> data:|DATA:           {return (DATA);}
> (netcdf|NETCDF|netCDF)  {return (NETCDF);}
>
> DoubleInf|NaN|-?Infinity { /* missing value (pre-2.4 backward compatibility)
*/
>                 if (yytext[0] == '-') {
>                   double_val = -NC_FILL_DOUBLE;
>                 } else {
>                   double_val = NC_FILL_DOUBLE;
>                 }
>               return (DOUBLE_CONST);
>               }
> FloatInf|NaNf|-?Infinityf|-?Inff {/* missing value (pre-2.4 backward
compatibility)*/
>                 if (yytext[0] == '-') {
>                   float_val = -NC_FILL_FLOAT;
>                 } else {
>                   float_val = NC_FILL_FLOAT;
>                 }
>               return (FLOAT_CONST);
>               }
>
> {PATH}                {
>               if(lextext != NULL) free(lextext);
>               lextext = emalloc(1+4*yyleng); /* should be max needed */
>               strncpy(lextext,(char*)yytext,yyleng+1); // include null
>               yylval.sym = makepath(lextext);
>               return (PATH);
>               }
>
>
> {ID}          {
>               if(lextext != NULL) free(lextext);
>               lextext = emalloc(1+4*yyleng); /* should be max needed */
>               strncpy(lextext,(char*)yytext,yyleng+1); // include null
>               deescapify(lextext);
>                 if (STREQ((char *)lextext, FILL_STRING)) return (FILLVALUE);
>               yylval.sym = install(lextext);
>               return (IDENT);
>               }
>
> \n            {
>               lineno++ ;
>                 break;
>               }
>
> [+-]?[0-9]*[0-9]([uU]|[dD][uU])[Bb]  {
>                 int ii;
>                 if (sscanf((char*)yytext, "%d", &ii) != 1) {
>                     sprintf(errstr,"bad ubyte constant: %s",(char*)yytext);
>                     yyerror(errstr);
>                 }
>                 ubyte_val = ii;
>                 if (ii != (int)ubyte_val) {
>                     sprintf(errstr,"ubyte constant out of range (0,255):
%s",(char*)yytext);
>                     yyerror(errstr);
>                 }
>                 return (UBYTE_CONST);
>                 }
>
> [+-]?[0-9]*[0-9][Bb]  {
>                 int ii;
>               if (sscanf((char*)yytext, "%d", &ii) != 1) {
>                   sprintf(errstr,"bad byte constant: %s",(char*)yytext);
>                   yyerror(errstr);
>               }
>                 byte_val = ii;
>               if (ii != (int)byte_val) {
>                   sprintf(errstr,"byte constant out of range (-128,127):
%s",(char*)yytext);
>                   yyerror(errstr);
>               }
>               return (BYTE_CONST);
>                 }
>
> [+-]?[0-9]*\.[0-9]*{exp}?[LlDd]?|[+-]?[0-9]*{exp}[LlDd]? {
>               if (sscanf((char*)yytext, "%le", &double_val) != 1) {
>                   sprintf(errstr,"bad long or double constant:
%s",(char*)yytext);
>                   yyerror(errstr);
>               }
>                 return (DOUBLE_CONST);
>                 }
> [+-]?[0-9]*\.[0-9]*{exp}?[Ff]|[+-]?[0-9]*{exp}[Ff] {
>               if (sscanf((char*)yytext, "%e", &float_val) != 1) {
>                   sprintf(errstr,"bad float constant: %s",(char*)yytext);
>                   yyerror(errstr);
>               }
>                 return (FLOAT_CONST);
>                 }
> [+]?[0-9]+[uU][sS]|0[xX][0-9a-fA-F]+[uU][sS] {
>                 if (sscanf((char*)yytext, "%hd", &uint16_val) != 1) {
>                     sprintf(errstr,"bad ushort constant: %s",(char*)yytext);
>                     yyerror(errstr);
>                 }
>                 return (USHORT_CONST);
>                 }
> [+-]?[0-9]+[sS]|0[xX][0-9a-fA-F]+[sS] {
>               if (sscanf((char*)yytext, "%hd", &int16_val) != 1) {
>                   sprintf(errstr,"bad short constant: %s",(char*)yytext);
>                   yyerror(errstr);
>               }
>               return (SHORT_CONST);
>               }
>
>
> [+-]?([1-9][0-9]*|0)[zZ] {
>                 char *ptr;
>                 errno = 0;
>                 double_val = strtod((char*)yytext, &ptr);
>                 if (errno != 0 && double_val == 0.0) {
>                     sprintf(errstr,"bad numerical constant:
%s",(char*)yytext);
>                     yyerror(errstr);
>                 }
>                     int64_val = (long long) double_val;
>                     return INT64_CONST;
>                 }
>
> [+]?([1-9][0-9]*|0)[uU][zZ] {
>                 char *ptr;
>                 errno = 0;
>                 double_val = strtod((char*)yytext, &ptr);
>                 if (errno != 0 && double_val == 0.0) {
>                     sprintf(errstr,"bad numerical constant:
%s",(char*)yytext);
>                     yyerror(errstr);
>                 }
>                     uint64_val = (unsigned long long) double_val;
>                     return UINT64_CONST;
>                 }
>
> [+]?([1-9][0-9]*|0)[uU][iI] {
>                 char *ptr;
>                 errno = 0;
>                 double_val = strtod((char*)yytext, &ptr);
>                 if (errno != 0 && double_val == 0.0) {
>                     sprintf(errstr,"bad numerical constant:
%s",(char*)yytext);
>                     yyerror(errstr);
>                 }
>                     uint32_val = (unsigned int) double_val;
>                     return UINT_CONST;
>                 }
>
> [+-]?([1-9][0-9]*|0)[lL]? {
>               char *ptr;
>                 errno = 0;
>               double_val = strtod((char*)yytext, &ptr);
>               if (errno != 0 && double_val == 0.0) {
>                   sprintf(errstr,"bad numerical constant: %s",(char*)yytext);
>                   yyerror(errstr);
>               }
>                 if (double_val < XDR_INT32_MIN ||double_val > XDR_INT32_MAX)
{
>                     return DOUBLE_CONST;
>                 } else {
>                     int32_val = (int) double_val;
>                     return INT_CONST;
>                 }
>               }
> 0[xX]?[0-9a-fA-F]+[lL]? {
>               char *ptr;
>                 long long_val;
>                 errno = 0;
>               long_val = strtol((char*)yytext, &ptr, 0);
>               if (errno != 0) {
>                   sprintf(errstr,"bad long constant: %s",(char*)yytext);
>                   yyerror(errstr);
>               }
>                 if (long_val < XDR_INT32_MIN || long_val > XDR_INT32_MAX) {
>                     double_val = (double) long_val;
>                     return DOUBLE_CONST;
>                 } else {
>                     int32_val = (int) long_val;
>                     return INT_CONST;
>                 }
>               }
> \'[^\\]\'          {
>               (void) sscanf((char*)&yytext[1],"%c",&byte_val);
>               return (BYTE_CONST);
>                 }
> \'\\[0-7][0-7]?[0-7]?\'  {
>               byte_val = (char) strtol((char*)&yytext[2], (char **) 0, 8);
>               return (BYTE_CONST);
>                 }
> \'\\[xX][0-9a-fA-F][0-9a-fA-F]?\'  {
>               byte_val = (char) strtol((char*)&yytext[3], (char **) 0, 16);
>               return (BYTE_CONST);
>                 }
> \'\\.\'        {
>              switch ((char)yytext[2]) {
>                 case 'a': byte_val = '\007'; break; /* not everyone under-
>                                                      * stands '\a' yet */
>                 case 'b': byte_val = '\b'; break;
>                 case 'f': byte_val = '\f'; break;
>                 case 'n': byte_val = '\n'; break;
>                 case 'r': byte_val = '\r'; break;
>                 case 't': byte_val = '\t'; break;
>                 case 'v': byte_val = '\v'; break;
>                 case '\\': byte_val = '\\'; break;
>                 case '?': byte_val = '\177'; break;
>                 case '\'': byte_val = '\''; break;
>                 default: byte_val = (char)yytext[2];
>                  }
>               return (BYTE_CONST);
>                 }
>
> [ \r\t\f]+    { /* whitespace */
>                 break;
>               }
> .             {/* Note: this next rule will not work for UTF8 characters */
>               return (yytext[0]) ;
>               }
> %%
> int
> lex_init(void)
> {
>     lineno = 1;
>     lextext = NULL;
>     if(0) unput(0); // keep -Wall quiet
>     return 0;
> }
>
> static Symbol*
> makepath(char* text)
> {
>     // Convert path to a sequence of symbols
>     // use last name as symbol name (with '/' as exception)
>     Symbol* sym;
>     Sequence* prefix = sqNew();
>     // walk the path converting to a sequence of symbols
>     if(strcmp(text,"/")==0) {
>       // special case of root reference
>       sym = rootgroup;
>     } else {
>       // split the text into IDENT chunks, convert to symbols
>       // and add to prefix, except the last
>       char *ident, *p;
>       int c;
>       ident=text+1; p=ident; // skip leading '/'
>       while((c=*p)) {
>           switch (c) {
>           case '/':
>               *p='\0';
>               deescapify(ident);
>               sym = install(ident);
>               sym->objectclass = NC_GRP; // must be a group ref
>               sym->is_ref = 1;
>               sqPush(prefix,(elem_t)sym);
>               ident=p+1; p=ident;
>               break;
>           case '\\': p++; if(*p == '/') p++; break;
>           default: p++; break;
>           }
>       }
>       assert(sqLength(prefix) > 0);
>       // last symbol is one we return; turn rest into the symbol's prefix
>       sqPop(prefix);
>       sym->prefix = prefix;
>       sym->is_prefixed = 1;
>       sym->objectclass = NC_NAT; //make caller set correctly
>     }
>     free(text);
>     return sym;
> }
>
> /*********************************************************************
>  *   Copyright 1993, UCAR/Unidata
>  *   See netcdf/COPYRIGHT file for copying and redistribution conditions.
>  *   $Id: ncgen.y,v 1.2 2008/09/30 16:14:22 dmh Exp $
>  *********************************************************************/
>
> /*
> Issues:
>       1. when to deescape strings (esp names)
>       2. handling of fill values
> */
>
>
> /* yacc source for "ncgen", a netCDL parser and netCDF generator */
>
> %{
> /*
> static char SccsId[] = "$Id: ncgen.y,v 1.2 2008/09/30 16:14:22 dmh Exp $";
> */
> #include        <stdlib.h>
> #include        <string.h>
> #include        <assert.h>
> #include        "netcdf.h"
> #include        "ncgen.h"
> #include        "genlib.h"      /* for grow_darray() et al */
> #include        "util.h"
> #include        "debug.h"
>
> /* parser controls */
> #define YY_NO_INPUT 1
>
>
> /* True if string a equals string b*/
> #define STREQ(a, b)     (*(a) == *(b) && strcmp((a), (b)) == 0)
> #define VLENSIZE  (sizeof(nc_vlen_t))
> #define MAXFLOATDIM 4294967295.0
> #define PRIMNO (NC_STRING - NC_NAT + 1)
>
> /* mnemonic */
> typedef enum Attrkind {ATTRVAR, ATTRGLOBAL, DONTKNOW} Attrkind;
>
> typedef nc_vlen_t vlen_t;
>
> /* We retain the old representation of the symbol list
>    as a linked list.
> */
> Symbol* symlist;
>
> // Track rootgroup separately
> Symbol* rootgroup;
>
> /* Track the group sequence */
> static Sequence* groupstack;
>
> /* Provide a separate sequence for accumulating values
>    during the parse.
> */
> static Sequence* stack;
>
> static Sequence* datalist;
>
> static nc_type consttype; // track homogeneity of types for data lists
>
> /* Misc. */
> static int i,j; // loop counters
> static int stackbase;
> static int stacklen;
> static int count;
> static int opaqueid; // counter for opaque constants
>
> Symbol* primsymbols[PRIMNO];
>
> char* primtypenames[PRIMNO] = {
> "nat",
> "byte", "char", "short",
> "int", "float", "double",
> "ubyte", "ushort", "uint",
> "int64", "uint64",
> "string"
> };
>
> //Defined in ncgen.l
> extern int lineno;              /* line number for error messages */
> extern char* lextext;           /* name or string with escapes removed */
>
> extern double double_val;       /* last double value read */
> extern float float_val;         /* last float value read */
> extern long long int64_val;         /* last int64 value read */
> extern int int32_val;             /* last int32 value read */
> extern short int16_val;         /* last short value read */
> extern unsigned long long uint64_val;         /* last int64 value read */
> extern unsigned int uint32_val;             /* last int32 value read */
> extern unsigned short uint16_val;         /* last short value read */
> extern char char_val;           /* last char value read */
> extern char byte_val;    /* last byte value read */
> extern unsigned char ubyte_val;    /* last byte value read */
>
> // Track definitions of dims, types, attributes, and vars
> Sequence* grpdefs;
> Sequence* dimdefs;
> Sequence* attdefs; // variable-specific attributes
> Sequence* gattdefs; // global attributes only
> Sequence* xattdefs; // unknown attributes
> Sequence* typdefs;
> Sequence* vardefs;
> Sequence* condefs; // non-dimension constants used in type defs
>
> /* Forward */
> //static void mark(Mark);
> //static Datalist* makeattrconst(nc_type);
> static Datalist* makedataconst(nc_type);
> static Datalist* makeenumconst(Symbol*);
> static void addtogroup(Symbol*);
> static Symbol* getunlimiteddim(void);
> static Symbol* currentgroup(void);
> static Symbol* createrootgroup(void);
> static Symbol* creategroup(Symbol*);
> static int dupobjectcheck(nc_class,Symbol*);
> static void setpathcurrent(Symbol* sym);
> static char* primtypename(nc_type nctype);
> static Symbol* makeattribute(Symbol*,Symbol*,Symbol*,Sequence*,Attrkind);
> //static int isnesteddatalist(Datalist* dlist);
>
> int yylex(void);
>
> #ifndef NO_STDARG
> static void yyerror(const char *fmt, ...);
> #else
> static void yyerror(fmt,va_alist) const char* fmt; va_dcl;
> #endif
>
> /* Extern */
> extern int lex_init(void);
>
> %}
>
> /* DECLARATIONS */
>
> %union {
> Symbol* sym;
> unsigned long  size; // allow for zero size to indicate e.g. UNLIMITED
> long  mark; // track indices into the sequence
> int   nctype; // for tracking attribute list type
> struct Datalist* datalist;
> Sequence* dataseq;
> }
>
> %token <sym>
>         NC_UNLIMITED_K /* keyword for unbounded record dimension */
>         CHAR_K      /* keyword for char datatype */
>         BYTE_K      /* keyword for byte 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 */
>         UBYTE_K      /* keyword for unsigned byte datatype */
>         USHORT_K     /* keyword for unsigned short datatype */
>         UINT_K       /* keyword for unsigned int datatype */
>         INT64_K       /* keyword for long long datatype */
>         UINT64_K       /* keyword for unsigned long long datatype */
>         IDENT       /* name for a dimension, variable, or attribute */
>         TERMSTRING  /* terminal string */
>         BYTE_CONST  /* byte constant */
>         CHAR_CONST  /* char constant (not ever generated by ncgen.l) */
>         SHORT_CONST /* short constant */
>         INT_CONST   /* int constant */
>         FLOAT_CONST /* float constant */
>         DOUBLE_CONST /* double constant */
>         UBYTE_CONST  /* ubyte constant */
>         USHORT_CONST /* ushort constant */
>         UINT_CONST   /* uint constant */
>         INT64_CONST   /* int64 constant */
>         UINT64_CONST   /* uint64 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 */
>         TYPES
>       COMPOUND
>         ENUM
>         OPAQUE
>         OPAQUESTRING    /* 0x<even number of hexdigits> */
>         GROUP
>       PATH            /* / or (/IDENT)+ */
>
> %type <sym> typename varref typeref type_var_ref primtype dimd varspec
>           attdecl gattdecl enumid path dimref fielddim fieldspec
> %type <mark> enumidlist fieldlist fields varlist dimspec dimlist field
>            fielddimspec fielddimlist
> %type <dataseq> datalist
> %type <datalist> dataconst dataset
>
> %start  ncdesc /* start symbol for grammar */
>
> %%
>
> /* RULES */
>
> ncdesc: NETCDF
>         datasetname
>         rootgroup
>         {if (derror_count > 0) exit(6);}
>         ;
>
> datasetname: IDENT {datasetname = strdup($1->name);}
>
> rootgroup: '{'
>            groupbody
>            subgrouplist
>            '}';
>
> groupbody:
>                 typesection     /* Type definitions */
>                 dimsection      /* dimension declarations */
>                 vasection       /* variable and attribute declarations */
>                 datasection     /* data for variables within the group */
>                 ;
>
> subgrouplist: /* empty */ | subgrouplist namedgroup  ;
>
> namedgroup: GROUP IDENT '{'
>             {
>                 if(usingclassic()) {verror("Group specification");}
>               if(creategroup($2) == NULL)
>                     yyerror("duplicate group declaration within parent group
for %s",
>                                 $2->name);
>             }
>             groupbody
>             subgrouplist
>             {sqPop(groupstack);}
>             '}';
>
> typesection:    /* empty */
>                 | TYPES
>               | TYPES
>                 {
>                     if(usingclassic())
>                       verror("Type specification");
>               }
>                 typedecls
>                 ;
>
> typedecls: type_attr_decl | typedecls type_attr_decl ;
>
>
> typename: IDENT
>           { /* Use when defining a type */
>               $1->objectclass = NC_TYPE;
>               if(dupobjectcheck(NC_TYPE,$1))
>                     yyerror("duplicate type declaration for %s",
>                             $1->name);
>               sqPush(typdefs,(elem_t)$1);
>           }
>         ;
>
> type_attr_decl: typedecl | gattdecl ';' ;
>
> typedecl: enumdecl ';' | compounddecl ';' | vlendecl ';' | opaquedecl ';' ;
>
> enumdecl: primtype ENUM typename
>           '{' enumidlist '}'
>               {
>                 addtogroup($3); // sets prefix
>                 $3->objectclass=NC_TYPE;
>                 $3->subclass=NC_ENUM;
>                 $3->typ.basetype=$1;
>                 $3->typ.size = $1->typ.size;
>                 stackbase=$5;
>                 stacklen=sqLength(stack);
>                 $3->subnodes = sqNew();
>                 // Variety of field fixups
>               // 1. add in the enum values
>               // 2. make this type be their container
>               // 3. make constant names visible in the group
>               // 4. set field basetype to be same as enum basetype
>                 for(i=stackbase;i<stacklen;i++) {
>                    Symbol* eid = (Symbol*)sqGet(stack,i);
>                  assert(eid->subclass == NC_ECONST);
>                  addtogroup(eid);
>                    sqPush($3->subnodes,(elem_t)eid);
>                    eid->container = $3;
>                  eid->typ.basetype = $3->typ.basetype;
>                 }
>                 sqSetlength(stack,stackbase);// remove stack nodes
>               }
>           ;
>
> enumidlist:   enumid
>               {$$=sqLength(stack); sqPush(stack,(elem_t)$1);}
>           | enumidlist ',' enumid
>               {
>                   $$=$1;
>                   // check for duplicates
>                   stackbase=$1;
>                   stacklen=sqLength(stack);
>                   for(i=stackbase;i<stacklen;i++) {
>                     Symbol* elem = (Symbol*)sqGet(stack,i);
>                     if(strcmp($3->name,elem->name)==0)
>                       yyerror("duplicate enum declaration for %s",
>                                elem->name);
>                   }
>                   sqPush(stack,(elem_t)$3);
>               }
>           ;
>
> enumid: IDENT '=' dataconst
>         {
>             $1->objectclass=NC_TYPE;
>             $1->subclass=NC_ECONST;
>             $1->typ.econst=$3;
>           $$=$1;
>         }
>         ;
>
> opaquedecl: OPAQUE '(' INT_CONST ')' typename
>                 {
>                     addtogroup($5); //sets prefix
>                     $5->objectclass=NC_TYPE;
>                     $5->subclass=NC_OPAQUE;
>                     $5->typ.typecode=NC_OPAQUE;
>                     $5->typ.size=int32_val;
>                 }
>             ;
>
> vlendecl: typeref '(' '*' ')' typename
>                 {
>                     addtogroup($5); //sets prefix
>                     Symbol* basetype = $1;
>                     $5->objectclass=NC_TYPE;
>                     $5->subclass=NC_VLEN;
>                     $5->typ.basetype=basetype;
>                     $5->typ.typecode=NC_VLEN;
>                     $5->typ.size=VLENSIZE;
>                 }
>           ;
>
> compounddecl: COMPOUND typename '{' fields '}'
>           {
>             addtogroup($2);
>           // check for duplicate field names
>           stackbase=$4;
>           stacklen=sqLength(stack);
>           for(i=stackbase;i<stacklen;i++) {
>             Symbol* elem1 = (Symbol*)sqGet(stack,i);
>             for(j=i+1;j<stacklen;j++) {
>                 Symbol* elem2 = (Symbol*)sqGet(stack,j);
>                 if(strcmp(elem1->name,elem2->name)==0) {
>                   yyerror("duplicate field declaration for %s",elem1->name);
>                 }
>             }
>           }
>           $2->objectclass=NC_TYPE;
>             $2->subclass=NC_COMPOUND;
>             $2->typ.basetype=NULL;
>             $2->typ.typecode=NC_COMPOUND;
>           $2->subnodes = sqNew();
>           // Add in the fields
>           for(i=stackbase;i<stacklen;i++) {
>               Symbol* fsym = (Symbol*)sqGet(stack,i);
>               fsym->container = $2;
>               sqPush($2->subnodes,(elem_t)fsym);
>           }
>           sqSetlength(stack,stackbase);// remove stack nodes
>           }
>             ;
>
>
> fields:   field ';' {$$=$1;}
>          | fields field ';' {$$=$1;}
>          ;
>
> field: typeref fieldlist
>         {
>           $$=$2;
>           stackbase=$2;
>           stacklen=sqLength(stack);
> //fix: move this check into semantics.c
>             // 2. check that none of the fields have an unlimited dimension;
>             //    this a consequence of the fact that the netCDF extended
>             //    interface does not allow reading/writing of individual
>             //    fields in a struct:only the whole struct can be
read/written.
>             for(i=stackbase;i<stacklen;i++) {
>                 Symbol* v = (Symbol*)sqGet(stack,i);
>                 v->typ.basetype=$1;
> #ifdef IGNORE
>               if(v->var.dimset.ndims > 0 ) {
>                   int j;
>                   for(j=0;j<v->var.dimset.ndims;j++) {
>                       if(v->var.dimset.dimsyms[j]->dim.size == NC_UNLIMITED)
{
>                           yyerror("Compound field dimensions may not be
UNLIMITED: %s (dimension %d); Use VLEN type instead.",v->name,j);
>                           break;
>                       }
>                   }
>               }
> #endif
>             }
>         }
>         ;
>
> primtype:         CHAR_K  { $$ = primsymbols[NC_CHAR]; }
>                 | BYTE_K  { $$ = primsymbols[NC_BYTE]; }
>                 | SHORT_K { $$ = primsymbols[NC_SHORT]; }
>                 | INT_K   { $$ = primsymbols[NC_INT]; }
>                 | FLOAT_K { $$ = primsymbols[NC_FLOAT]; }
>                 | DOUBLE_K{ $$ = primsymbols[NC_DOUBLE]; }
>                 | UBYTE_K  { $$ = primsymbols[NC_UBYTE]; }
>                 | USHORT_K { $$ = primsymbols[NC_USHORT]; }
>                 | UINT_K   { $$ = primsymbols[NC_UINT]; }
>                 | INT64_K   { $$ = primsymbols[NC_INT64]; }
>                 | UINT64_K   { $$ = primsymbols[NC_UINT64]; }
>                 ;
>
> dimsection:     /* empty */
>                 | DIMENSIONS
>               | DIMENSIONS dimdecls
>                 ;
>
> dimdecls:       dim_attr_decl ';'
>                 | dimdecls dim_attr_decl ';'
>                 ;
>
> dim_attr_decl: dimdeclist | gattdecl ;
>
> dimdeclist:     dimdecl
>                 | dimdeclist ',' dimdecl
>                 ;
>
> dimdecl:        dimd '=' INT_CONST
>                    { if (int32_val <= 0)
>                          yyerror("dimension length must be positive");
>                      $1->dim.size = (size_t)int32_val;
>                      $1->dim.datasize = $1->dim.size;
>                    }
>                 | dimd '=' DOUBLE_CONST
>                    { /* for rare case where 2^31 < dimsize < 2^32 */
>                        if (double_val <= 0)
>                          yyerror("dimension length must be positive");
>                        if (double_val > MAXFLOATDIM)
>                          yyerror("dimension too large");
>                        if (double_val - (size_t) double_val > 0)
>                          yyerror("dimension length must be an integer");
>                        $1->dim.size = (size_t)double_val;
>                        $1->dim.datasize = $1->dim.size;
>                    }
>                 | dimd '=' NC_UNLIMITED_K
>                    {
>                        if(usingclassic()) {
>                        // check for multiple UNLIMITED decls
>                          if(getunlimiteddim() != NULL)
>                           verror("Type specification");
>                      }
>                      $1->dim.size = NC_UNLIMITED;
>                  }
>                 ;
>
> dimd:           IDENT
>                    {
>                      $1->objectclass=NC_DIM;
>                      if(dupobjectcheck(NC_DIM,$1))
>                         yyerror( "Duplicate dimension declaration for %s",
>                                 $1->name);
>                    addtogroup($1);
>                    $$=$1;
>                    sqPush(dimdefs,(elem_t)$1);
>                    }
>                 ;
>
> vasection:      /* empty */
>                 | VARIABLES
>                 | VARIABLES vadecls
>                 ;
>
> vadecls:        vadecl ';'
>                 | vadecls vadecl ';'
>                 ;
>
> vadecl:         vardecl | attdecl ;
>
> vardecl:        typeref varlist
>               {
>                   stackbase=$2;
>                   stacklen=sqLength(stack);
>                   for(i=stackbase;i<stacklen;i++) {
>                       Symbol* sym = (Symbol*)sqGet(stack,i);
>                       sym->objectclass = NC_VAR;
>                       if(dupobjectcheck(NC_VAR,$1))
>                             yyerror("Duplicate variable declaration for %s",
>                                     sym->name);
>                       sym->typ.basetype = $1;
>                       addtogroup(sym);
>                       sqPush(vardefs,(elem_t)sym);
>                   }
>                   sqSetlength(stack,stackbase);// remove stack nodes
>               }
>                 ;
>
> varlist:      varspec
>               {$$=sqLength(stack);
>                  sqPush(stack,(elem_t)$1);
>               }
>             | varlist ',' varspec
>               {$$=$1; sqPush(stack,(elem_t)$3);}
>             ;
>
> varspec:        IDENT dimspec
>                     {
>                     $1->objectclass=NC_VAR;
>                   stackbase=$2;
>                   stacklen=sqLength(stack);
>                   count = stacklen - stackbase;
>                   if(count >= NC_MAX_VAR_DIMS) {
>                       yyerror("%s has too many dimensions",$1->name);
>                       count = NC_MAX_VAR_DIMS - 1;
>                       stacklen = stackbase + count;
>                   }
>                   $1->var.dimset.ndims = count;
>                   // extract the actual dimensions
>                   if($1->var.dimset.ndims > 0) {
>                       for(i=0;i<count;i++) {
>                           Symbol* dsym = (Symbol*)sqGet(stack,stackbase+i);
>                           $1->var.dimset.dimsyms[i] = dsym;
>                       }
>                   }
>                   sqSetlength(stack,stackbase);// remove stack nodes
>                    }
>                 ;
>
> dimspec:        /* empty */ {$$=sqLength(stack);}
>                 | '(' dimlist ')' {$$=$2;}
>                 ;
>
> dimlist:        dimref {$$=sqLength(stack); sqPush(stack,(elem_t)$1);}
>                 | dimlist ',' dimref
>                   {$$=$1; sqPush(stack,(elem_t)$3);}
>                 ;
>
> dimref: path
>             {
>            $1->objectclass = NC_DIM;
>            $1->is_ref=1;
>            $1->ref=NULL;
>            $$=$1;
>           }
>       ;
>
> fieldlist:
>         fieldspec
>           {$$=sqLength(stack);
>              sqPush(stack,(elem_t)$1);
>           }
>       | fieldlist ',' fieldspec
>           {$$=$1; sqPush(stack,(elem_t)$3);}
>         ;
>
> fieldspec:
>       IDENT fielddimspec
>           {
>                 $1->objectclass=NC_TYPE;
>                 $1->subclass=NC_FIELD;
>               stackbase=$2;
>               stacklen=sqLength(stack);
>               count = stacklen - stackbase;
>               if(count >= NC_MAX_VAR_DIMS) {
>                   yyerror("%s has too many dimensions",$1->name);
>                   count = NC_MAX_VAR_DIMS - 1;
>                   stacklen = stackbase + count;
>               }
>               $1->var.dimset.ndims = count;
>               // extract the actual dimensions
>               for(i=0;i<count;i++) {
>                   Symbol* dsym = (Symbol*)sqGet(stack,stackbase+i);
>                   $1->var.dimset.dimsyms[i] = dsym;
>               }
>               sqSetlength(stack,stackbase);// remove stack nodes
>               $$ = $1;
>           }
>       ;
>
> fielddimspec:        /* empty */ {$$=sqLength(stack);}
>                 | '(' fielddimlist ')' {$$=$2;}
>                 ;
>
> fielddimlist:
>         fielddim {$$=sqLength(stack); sqPush(stack,(elem_t)$1);}
>       | fielddimlist ',' fielddim
>           {$$=$1; sqPush(stack,(elem_t)$3);}
>         ;
>
> fielddim:
>       INT_CONST
>           {  /* Anonymous integer dimension.
>                Can only occur in type definitions*/
>            char anon[32];
>            sprintf(anon,"const%d",int32_val);
>            $$ = install(anon);
>            $$->objectclass = NC_DIM;
>            $$->dim.isconstant = 1;
>            $$->dim.size = int32_val;
>            $$->dim.datasize = $$->dim.size;
>           }
>       ;
>
>
> /* Use this when referencing defined objects */
>
> varref: path {$$=$1; $$->objectclass=NC_VAR;} ;
>
> typeref:
>         path {$$=$1; $$->objectclass=NC_TYPE;}
>       | primtype {$$=$1;}
>       ;
>
> type_var_ref:
>         path {$$=$1; $$->objectclass=NC_NAT;} /* Unknown at this point*/
>       | primtype {$$=$1;}
>       ;
>
> /* Use this when the attribute might be global or local */
> attdecl:
>         typeref varref ':' IDENT '=' datalist
>           {$$=makeattribute($4,$2,$1,$6,ATTRVAR);}
>       | type_var_ref ':' IDENT '=' datalist
>           { $$=makeattribute($3,$1,NULL,$5,DONTKNOW);}
>       | ':' IDENT '=' datalist
>           { $$=makeattribute($2,NULL,NULL,$4,ATTRGLOBAL);}
>         ;
>
> gattdecl:
>         typeref ':' IDENT '=' datalist
>           { $$=makeattribute($3,NULL,$1,$5,ATTRGLOBAL);}
>       | ':' IDENT '=' datalist
>           { $$=makeattribute($2,NULL,NULL,$4,ATTRGLOBAL);}
>       ;
>
> path:
>         IDENT
>           {
>               $$=$1;
>                 $1->is_ref=1;
>                 setpathcurrent($1);
>           }
>       | PATH
>           {
>               $$=$1;
>                 $1->is_ref=1;
>               // path is set in ncgen.l
>           }
>       ;
>
> datasection:    /* empty */
>                 | DATA
>                 | DATA datadecls
>                 ;
>
> datadecls:      datadecl ';'
>                 | datadecls datadecl ';'
>                 ;
>
> datadecl:       varref '=' datalist
>                    {$1->data = makedatalist(NC_VAR,$3);}
>                 ;
>
> datalist:
>         dataset {$$=sqNew(); sqPush($$,(elem_t)$1);}
>       | datalist ',' dataset {$$=$1; sqPush($$,(elem_t)$3);}
>       ;
>
> dataset:
>         dataconst {$$=$1;}
>       | '{' datalist '}' {$$ = makedatalist(NC_COMPOUND,$2);}
>       ;
>
> dataconst:
>         CHAR_CONST {$$=makedataconst(NC_CHAR);} // never used apparently
>       | BYTE_CONST {$$=makedataconst(NC_BYTE);}
>       | SHORT_CONST {$$=makedataconst(NC_SHORT);}
>       | INT_CONST {$$=makedataconst(NC_INT);}
>       | FLOAT_CONST {$$=makedataconst(NC_FLOAT);}
>       | DOUBLE_CONST {$$=makedataconst(NC_DOUBLE);}
>         | UBYTE_CONST {$$=makedataconst(NC_UBYTE);}
>         | USHORT_CONST {$$=makedataconst(NC_USHORT);}
>         | UINT_CONST {$$=makedataconst(NC_UINT);}
>         | INT64_CONST {$$=makedataconst(NC_INT64);}
>         | UINT64_CONST {$$=makedataconst(NC_UINT64);}
>       | TERMSTRING {$$=makedataconst(NC_STRING);}
>       | OPAQUESTRING {$$=makedataconst(NC_OPAQUE);}
>       | path {$$=makeenumconst($1);}
>       | FILLVALUE  {$$=makedataconst(NC_FILLVALUE);}
>       ;
>
> /* End OF RULES */
>
> %%
>
> #ifndef NO_STDARG
> static void
> yyerror(const char *fmt, ...)
> #else
> static void
> yyerror(fmt,va_alist) const char* fmt; va_dcl
> #endif
> {
>     va_list argv;
>     vastart(argv,fmt);
>     (void)fprintf(stderr,"%s: %s line %d: ", progname, cdlname, lineno);
>     vderror(fmt,argv);
> }
>
> /* undefine yywrap macro, in case we are using bison instead of yacc */
> #ifdef yywrap
> #undef yywrap
> #endif
>
> static int
> yywrap(void)                    /* returns 1 on EOF if no more input */
> {
>     return  1;
> }
>
> /* get lexical input routine generated by lex  */
> #include "ncgenyy.c"
>
> /* Really should init our data within this file */
> void
> parse_init(void)
> {
>     int i;
>     derror_count=0;
>     opaqueid = 0;
>     symlist = NULL;
>     stack = sqNew();
>     datalist = NULL;
>     groupstack = sqNew();
>     consttype = NC_NAT;
>     grpdefs = sqNew();
>     dimdefs = sqNew();
>     attdefs = sqNew();
>     gattdefs = sqNew();
>     xattdefs = sqNew();
>     typdefs = sqNew();
>     vardefs = sqNew();
>     condefs = sqNew();
>     createrootgroup();
>     /* Create the primitive types */
>     for(i=NC_NAT+1;i<=NC_STRING;i++) {
>         Symbol* sym = install(primtypenames[i]);
>       sym->objectclass=NC_TYPE;
>       sym->subclass=NC_PRIM;
>       sym->ncid = i;
>       sym->typ.basetype = NULL;
>       sym->typ.typecode = i;
>       sym->typ.size = ncsize(i);
>       sym->prefix = sqNew();
>       primsymbols[i] = sym;
>     }
>     lex_init();
> }
>
> /* Symbol table operations for ncgen tool */
>
> /* install sname in symbol table */
> Symbol*
> install(const char *sname)
> {
>     Symbol* sp;
>     sp = (Symbol*) emalloc (sizeof (struct Symbol));
>     memset((void*)sp,0,sizeof(struct Symbol));
>     sp->name = nulldup(sname);
>     sp->next = symlist;
>     sp->lineno = lineno;
>     sp->container = currentgroup();
>     symlist = sp;
>     return sp;
> }
>
> static Symbol*
> getunlimiteddim(void)
> {
>     Symbol* sp;
>     for(sp=symlist;sp;sp=sp->next) {
>         if(sp->objectclass == NC_DIM && sp->dim.size == -1) return sp;
>     }
>     return NULL;                        /* 0 ==> not found */
> }
>
> static Symbol*
> currentgroup(void)
> {
>     if(sqLength(groupstack) == 0) return rootgroup;
>     return (Symbol*)sqTop(groupstack);
> }
>
> static Symbol*
> createrootgroup(void)
> {
>     Symbol* gsym = install(ROOTGROUPNAME);
>     gsym->objectclass = NC_GRP;
>     gsym->container = NULL;
>     gsym->subnodes = sqNew();
>     gsym->grp.is_root = 1;
>     gsym->prefix = sqNew();
>     sqPush(grpdefs,(elem_t)gsym);
>     rootgroup = gsym;
>     return gsym;
> }
>
> static Symbol*
> creategroup(Symbol * gsym)
> {
>     /* See if this group already exists in currentgroup */
>     gsym->objectclass = NC_GRP;
>     gsym->container = currentgroup();
>     if(dupobjectcheck(NC_GRP,gsym)) {return NULL;}
>     setpathcurrent(gsym);
>     gsym->subnodes = sqNew();
>     sqPush(gsym->container->subnodes,(elem_t)gsym);
>     sqPush(groupstack,(elem_t)gsym);
>     sqPush(grpdefs,(elem_t)gsym);
>     return gsym;
> }
>
> #ifdef IGNORE
> static void
> mark(Mark beginend)
> {
>     Datalist* ci = makedatalist();
>     ci->lineno = lineno;
>     ci->tag = NC_COMPOUND;
>     ci->nctype = NC_COMPOUND;
>     ci->value.mark = beginend;
>     sqPush(datalist,(elem_t)ci);
> }
>
> #endif
>
> static Datalist*
> makedataconst(nc_type nctype)
> {
>     Datalist* ci;
>     // Note that although NC_STRING does not exist
>     // for netcdf classic, string constants exist
>     // and will be treated as sequences of characters
>     if(usingclassic() && !isclassicprim(nctype)) {
>         verror("Illegal type: %s",primtypename(nctype));
>     }
>     consttype = nctype;
>     ci = makedatalist(NC_PRIM,NULL);
>     ci->nctype = nctype;
>     switch (nctype) {
>       case NC_CHAR: ci->value.charv = char_val; break;
>         case NC_BYTE: ci->value.int8v = byte_val; break;
>         case NC_SHORT: ci->value.int16v = int16_val; break;
>         case NC_INT: ci->value.int32v = int32_val; break;
>         case NC_FLOAT: ci->value.floatv = float_val; break;
>         case NC_DOUBLE: ci->value.doublev = double_val; break;
>         case NC_UBYTE: ci->value.uint8v = ubyte_val; break;
>         case NC_USHORT: ci->value.uint16v = uint16_val; break;
>         case NC_UINT: ci->value.uint32v = uint32_val; break;
>         case NC_INT64: ci->value.int64v = int64_val; break;
>         case NC_UINT64: ci->value.uint64v = uint64_val; break;
>         case NC_STRING: { // convert to a set of chars
>           int len;
>           ci->tag = NC_PRIM;
>           ci->nctype = NC_STRING;
>           len = strlen(lextext);
>           if(len == 0) len = 1;
>           ci->value.stringv.len = len;
>           ci->value.stringv.stringv = strdup(lextext);
>           } break;
>       case NC_OPAQUE: {
>           char* s;
>           int len,padlen;
>           len = strlen(lextext);
>           padlen = len;
>           if(padlen < 16) padlen = 16;
>           if((padlen % 2) == 1) padlen++;
>           s = (char*)emalloc(padlen+1);
>           memset((void*)s,'0',padlen);
>           s[padlen]='\0';
>           strncpy(s,lextext,len);
>           ci->value.opaquev.stringv = s;
>           ci->value.opaquev.len = padlen;
>           s = (char*)emalloc(16);
>           sprintf(s,"opaqueconst%03d",++opaqueid);
>           ci->value.opaquev.lname = s;
>           } break;
>
>       case NC_FILLVALUE:
>           break; // no associated value
>
>       default:
>           yyerror("Data constant: unexpected NC type: %s",
>                   nctypename(nctype));
>           ci->value.stringv.stringv = NULL;
>           ci->value.stringv.len = 0;
>     }
>     return ci;
> }
>
> static Datalist*
> makeenumconst(Symbol* econst)
> {
>     Datalist* ci;
>     if(usingclassic()) {
>         verror("Illegal type: enum");
>     }
>     consttype = NC_ENUM;
>     ci = makedatalist(NC_PRIM,NULL);
>     ci->nctype = NC_ECONST;
>     ci->value.enumv = econst;
>     // fix up econst to be a ref to an econst
>     econst->objectclass = NC_TYPE;
>     econst->subclass = NC_ECONST;
>     return ci;
> }
>
> static void
> addtogroup(Symbol* sym)
> {
>     Symbol* grp = currentgroup();
>     sym->container = currentgroup();
>     sqPush(grp->subnodes,(elem_t)sym);
>     setpathcurrent(sym);
> }
>
> // Check for duplicate name of given type within current group
> static int
> dupobjectcheck(nc_class objectclass, Symbol* pattern)
> {
>     Symbol* grp;
>     if(pattern == NULL) return 0;
>     grp = pattern->container;
>     if(grp == NULL) return 0;
>     for(i=0;i<sqLength(grp->subnodes);i++) {
>       Symbol* sym = (Symbol*)sqGet(grp->subnodes,i);
>       if(!sym->is_ref && sym->objectclass == objectclass
>          && strcmp(sym->name,pattern->name)==0) return 1;
>     }
>     return 0;
> }
>
> static void
> setpathcurrent(Symbol* sym)
> {
>     sym->is_prefixed = 0;
>     sym->prefix = prefixdup(groupstack);
> }
>
> // Convert an nc_type code to the corresponding Symbol
> Symbol*
> basetypefor(nc_type nctype)
> {
>     return primsymbols[nctype];
> }
>
> static char*
> primtypename(nc_type nctype)
> {
>     if(isprim(nctype)) return primtypenames[nctype];
>     return "nc_<UNKNOWN>";
> }
>
> #ifdef IGNORE
> // Return 1 if the attribute datalist has nested compound elements
> static int
> isnesteddatalist(Datalist* dlist)
> {
>     int i;
>     Sequence* set = dlist->datalist;
>     for(i=0;i<sqLength(set);i++) {
>       Datalist* d = (Datalist*)sqGet(set,i);
>       if(d->tag == NC_COMPOUND) return 1;
>     }
>     return 0;
> }
>
> static Symbol*
> makeintconst(int value)
> {
>     Symbol* sym;
>     char tmp[256];
>     int i;
>     sprintf(tmp,"int%d",value);
>     // see if already defined
>     for(i=0;i<sqLength(condefs);i++) {
>       Symbol* csym = (Symbol*)sqGet(condefs,i);
>       if(csym->con.nctype == NC_INT && csym->con.value.int32v == int32_val)
>           return csym;
>     }
>     sym = install(tmp);
>     sym->objectclass = NC_CONST;
>     sym->con.nctype = NC_INT;
>     sym->con.value.int32v = int32_val;
>     sqPush(condefs,(elem_t)sym);
>     return sym;
> }
> #endif
>
> static Symbol*
> makeattribute(Symbol* asym,
>               Symbol* vsym,
>               Symbol* tsym,
>               Sequence* datalist,
>               Attrkind kind) // global var or unknown
> {
>     asym->objectclass = NC_ATT;
>     asym->data = makedatalist(NC_ATT,datalist);
>     // BTW,check for nesting when using classic
> //    if(usingclassic() && isnesteddatalist(asym->data))
> //    verror("{...} within attribute data list");
>     addtogroup(asym);
>     switch (kind) {
>     case DONTKNOW:
>       // We won't know until semantic processing
>         asym->att.unknown = vsym;
>         sqPush(xattdefs,(elem_t)asym);
>       break;
>     case ATTRVAR:
>         asym->att.var = vsym;
>         asym->typ.basetype = tsym;
>         sqPush(attdefs,(elem_t)asym);
>       break;
>     case ATTRGLOBAL:
>         asym->att.var = NULL; // NULL => NC_GLOBAL
>         asym->typ.basetype = tsym;
>         sqPush(gattdefs,(elem_t)asym);
>       break;
>     }
>     return asym;
> }
>
>
>
>
> Ticket Details
> ===================
> Ticket ID: YRL-141737
> Department: Support netCDF
> Priority: Normal
> Status: Open
> Link:
https://www.unidata.ucar.edu/esupport/staff/index.php?_m=tickets&_a=viewticket&ticketid=7539



Ticket Details
===================
Ticket ID: YRL-141737
Department: Support netCDF
Priority: Normal
Status: Open