[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[netCDF #YRL-141737]: NetCDF-4.0 make check error
- Subject: [netCDF #YRL-141737]: NetCDF-4.0 make check error
- Date: Fri, 10 Oct 2008 10:24:07 -0600
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