1 /*********************************************************************
2  *   Copyright 1993, UCAR/Unidata
3  *   See netcdf/COPYRIGHT file for copying and redistribution conditions.
4  *   $Id: ncgen.y,v 1.42 2010/05/18 21:32:46 dmh Exp $
5  *********************************************************************/
6 
7 /* yacc source for "ncgen", a netCDL parser and netCDF generator */
8 
9 %error-verbose
10 
11 %{
12 /*
13 static char SccsId[] = "$Id: ncgen.y,v 1.42 2010/05/18 21:32:46 dmh Exp $";
14 */
15 #include        "includes.h"
16 #include        "netcdf_aux.h"
17 #include        "ncgeny.h"
18 #include        "ncgen.h"
19 #ifdef USE_NETCDF4
20 #include        "ncfilter.h"
21 #endif
22 
23 /* Following are in ncdump (for now)*/
24 /* Need some (unused) definitions to get it to compile */
25 #define ncatt_t void*
26 #define ncvar_t void
27 #include "nctime.h"
28 
29 /* parser controls */
30 #define YY_NO_INPUT 1
31 
32 /* True if string a equals string b*/
33 #ifndef NCSTREQ
34 #define NCSTREQ(a, b)     (*(a) == *(b) && strcmp((a), (b)) == 0)
35 #endif
36 #define VLENSIZE  (sizeof(nc_vlen_t))
37 #define MAXFLOATDIM 4294967295.0
38 
39 /* mnemonics */
40 typedef enum Attrkind {ATTRVAR, ATTRGLOBAL, DONTKNOW} Attrkind;
41 
42 #define ISCONST 1
43 #define ISLIST 0
44 
45 typedef nc_vlen_t vlen_t;
46 
47 /* We retain the old representation of the symbol list
48    as a linked list.
49 */
50 List* symlist;
51 
52 /* Track rootgroup separately*/
53 Symbol* rootgroup;
54 
55 /* Track the group sequence */
56 static List* groupstack;
57 
58 /* Provide a separate sequence for accumulating values
59    during the parse.
60 */
61 static List* stack;
62 
63 /* track homogeneity of types for data lists*/
64 static nc_type consttype;
65 
66 /* Misc. */
67 static int stackbase;
68 static int stacklen;
69 static int count;
70 static int opaqueid; /* counter for opaque constants*/
71 static int arrayuid; /* counter for pseudo-array types*/
72 
73 char* primtypenames[PRIMNO] = {
74 "nat",
75 "byte", "char", "short",
76 "int", "float", "double",
77 "ubyte", "ushort", "uint",
78 "int64", "uint64",
79 "string"
80 };
81 
82 static int GLOBAL_SPECIAL = _NCPROPS_FLAG
83                             | _ISNETCDF4_FLAG
84                             | _SUPERBLOCK_FLAG
85                             | _FORMAT_FLAG ;
86 
87 /*Defined in ncgen.l*/
88 extern int lineno;              /* line number for error messages */
89 extern Bytebuffer* lextext;           /* name or string with escapes removed */
90 
91 extern double double_val;       /* last double value read */
92 extern float float_val;         /* last float value read */
93 extern long long int64_val;         /* last int64 value read */
94 extern int int32_val;             /* last int32 value read */
95 extern short int16_val;         /* last short value read */
96 extern unsigned long long uint64_val;         /* last int64 value read */
97 extern unsigned int uint32_val;             /* last int32 value read */
98 extern unsigned short uint16_val;         /* last short value read */
99 extern char char_val;           /* last char value read */
100 extern signed char byte_val;    /* last byte value read */
101 extern unsigned char ubyte_val;    /* last byte value read */
102 
103 /* Track definitions of dims, types, attributes, and vars*/
104 List* grpdefs;
105 List* dimdefs;
106 List* attdefs; /* variable-specific attributes*/
107 List* gattdefs; /* global attributes only*/
108 List* xattdefs; /* unknown attributes*/
109 List* typdefs;
110 List* vardefs;
111 List* condefs; /* non-dimension constants used in type defs*/
112 List* tmp;
113 
114 /* Forward */
115 static NCConstant* makeconstdata(nc_type);
116 static NCConstant* evaluate(Symbol* fcn, Datalist* arglist);
117 static NCConstant* makeenumconstref(Symbol*);
118 static void addtogroup(Symbol*);
119 static Symbol* currentgroup(void);
120 static Symbol* createrootgroup(const char*);
121 static Symbol* creategroup(Symbol*);
122 static int dupobjectcheck(nc_class,Symbol*);
123 static void setpathcurrent(Symbol* sym);
124 static Symbol* makeattribute(Symbol*,Symbol*,Symbol*,Datalist*,Attrkind);
125 static Symbol* makeprimitivetype(nc_type i);
126 static Symbol* makespecial(int tag, Symbol* vsym, Symbol* tsym, void* data, int isconst);
127 static int containsfills(Datalist* list);
128 static void vercheck(int ncid);
129 static long long extractint(NCConstant* con);
130 #ifdef USE_NETCDF4
131 static int parsefilterflag(const char* sdata0, Specialdata* special);
132 #endif
133 
134 int yylex(void);
135 
136 #ifndef NO_STDARG
137 static void yyerror(const char *fmt, ...);
138 #else
139 static void yyerror(fmt,va_alist) const char* fmt; va_dcl;
140 #endif
141 
142 /* Extern */
143 extern int lex_init(void);
144 
145 %}
146 
147 /* DECLARATIONS */
148 
149 %union {
150 Symbol* sym;
151 unsigned long  size; /* allow for zero size to indicate e.g. UNLIMITED*/
152 long           mark; /* track indices into the sequence*/
153 int            nctype; /* for tracking attribute list type*/
154 Datalist*      datalist;
155 NCConstant*    constant;
156 }
157 
158 %token <sym>
159         NC_UNLIMITED_K /* keyword for unbounded record dimension */
160         CHAR_K      /* keyword for char datatype */
161         BYTE_K      /* keyword for byte datatype */
162         SHORT_K     /* keyword for short datatype */
163         INT_K       /* keyword for int datatype */
164         FLOAT_K     /* keyword for float datatype */
165         DOUBLE_K    /* keyword for double datatype */
166         UBYTE_K     /* keyword for unsigned byte datatype */
167         USHORT_K    /* keyword for unsigned short datatype */
168         UINT_K      /* keyword for unsigned int datatype */
169         INT64_K     /* keyword for long long datatype */
170         UINT64_K    /* keyword for unsigned long long datatype */
171         STRING_K    /* keyword for string datatype */
172         IDENT       /* name for a dimension, variable, or attribute */
173         TERMSTRING  /* terminal string */
174         CHAR_CONST  /* char constant (not ever generated by ncgen.l) */
175         BYTE_CONST  /* byte constant */
176         SHORT_CONST /* short constant */
177         INT_CONST   /* int constant */
178         INT64_CONST   /* long long constant */
179         UBYTE_CONST  /* unsigned byte constant */
180         USHORT_CONST /* unsigned short constant */
181         UINT_CONST   /* unsigned int  constant */
182         UINT64_CONST   /* unsigned long long  constant */
183         FLOAT_CONST /* float constant */
184         DOUBLE_CONST/* double constant */
185         DIMENSIONS  /* keyword starting dimensions section, if any */
186         VARIABLES   /* keyword starting variables section, if any */
187         NETCDF      /* keyword declaring netcdf name */
188         DATA        /* keyword starting data section, if any */
189         TYPES
190 	COMPOUND
191         ENUM
192         OPAQUE_ /* 'OPAQUE' apparently conflicts with HDF4 code */
193         OPAQUESTRING    /* 0x<even number of hexdigits> */
194         GROUP
195 	PATH            /* / or (/IDENT)+(.IDENT)? */
196 	FILLMARKER	/* "_" as opposed to the attribute */
197 	NIL             /* NIL */
198         _FILLVALUE
199         _FORMAT
200         _STORAGE
201         _CHUNKSIZES
202         _DEFLATELEVEL
203         _SHUFFLE
204         _ENDIANNESS
205         _NOFILL
206         _FLETCHER32
207 	_NCPROPS
208 	_ISNETCDF4
209 	_SUPERBLOCK
210 	_FILTER
211 	DATASETID
212 
213 %type <sym> ident typename primtype dimd varspec
214 	    attrdecl enumid path dimref fielddim fieldspec
215 %type <sym> typeref
216 %type <sym> varref
217 %type <sym> type_var_ref
218 %type <mark> enumidlist fieldlist fields varlist dimspec dimlist field
219 	     fielddimspec fielddimlist
220 %type <constant> dataitem constdata constint conststring constbool
221 %type <constant> simpleconstant function econstref
222 %type <datalist> datalist intlist datalist1 datalist0 arglist
223 
224 
225 %start  ncdesc /* start symbol for grammar */
226 
227 %%
228 
229 /* RULES */
230 
231 ncdesc: NETCDF
232 	datasetid
233         rootgroup
234         {if (error_count > 0) YYABORT;}
235         ;
236 
237 datasetid: DATASETID {createrootgroup(datasetname);};
238 
239 rootgroup: '{'
240            groupbody
241            subgrouplist
242            '}';
243 
244 /* 2/3/08 - Allow group body with only attributes. (H/T John Storrs). */
245 groupbody:
246 		attrdecllist
247                 typesection     /* Type definitions */
248                 dimsection      /* dimension declarations */
249                 vasection       /* variable and attribute declarations */
250                 datasection     /* data for variables within the group */
251                 ;
252 
253 subgrouplist: /*empty*/ | subgrouplist namedgroup;
254 
255 namedgroup: GROUP ident '{'
256             {
257 		Symbol* id = $2;
258                 markcdf4("Group specification");
259 		if(creategroup(id) == NULL)
260                     yyerror("duplicate group declaration within parent group for %s",
261                                 id->name);
262             }
263             groupbody
264             subgrouplist
265             {listpop(groupstack);}
266             '}'
267 	    attrdecllist
268 	    ;
269 
270 typesection:    /* empty */
271                 | TYPES {}
272 		| TYPES typedecls
273 			{markcdf4("Type specification");}
274                 ;
275 
276 typedecls: type_or_attr_decl | typedecls type_or_attr_decl ;
277 
278 typename: ident
279 	    { /* Use when defining a type */
280               $1->objectclass = NC_TYPE;
281               if(dupobjectcheck(NC_TYPE,$1))
282                     yyerror("duplicate type declaration for %s",
283                             $1->name);
284               listpush(typdefs,(void*)$1);
285 	    }
286 	  ;
287 
288 type_or_attr_decl: typedecl {} | attrdecl ';' {} ;
289 
290 typedecl:
291 	  enumdecl optsemicolon
292 	| compounddecl optsemicolon
293 	| vlendecl optsemicolon
294 	| opaquedecl optsemicolon
295 	;
296 
297 optsemicolon: /*empty*/ | ';' ;
298 
299 
300 enumdecl: primtype ENUM typename
301           '{' enumidlist '}'
302               {
303 		int i;
304                 addtogroup($3); /* sets prefix*/
305                 $3->objectclass=NC_TYPE;
306                 $3->subclass=NC_ENUM;
307                 $3->typ.basetype=$1;
308                 $3->typ.size = $1->typ.size;
309                 $3->typ.alignment = $1->typ.alignment;
310                 stackbase=$5;
311                 stacklen=listlength(stack);
312                 $3->subnodes = listnew();
313                 /* Variety of field fixups*/
314 		/* 1. add in the enum values*/
315 		/* 2. make this type be their container*/
316 		/* 3. make constant names visible in the group*/
317 		/* 4. set field basetype to be same as enum basetype*/
318                 for(i=stackbase;i<stacklen;i++) {
319                    Symbol* eid = (Symbol*)listget(stack,i);
320 		   assert(eid->subclass == NC_ECONST);
321 		   addtogroup(eid);
322                    listpush($3->subnodes,(void*)eid);
323                    eid->container = $3;
324 		   eid->typ.basetype = $3->typ.basetype;
325                 }
326                 listsetlength(stack,stackbase);/* remove stack nodes*/
327               }
328           ;
329 
330 enumidlist:   enumid
331 		{$$=listlength(stack); listpush(stack,(void*)$1);}
332 	    | enumidlist ',' enumid
333 		{
334 		    int i;
335 		    $$=$1;
336 		    /* check for duplicates*/
337 		    stackbase=$1;
338 		    stacklen=listlength(stack);
339 		    for(i=stackbase;i<stacklen;i++) {
340 		      Symbol* elem = (Symbol*)listget(stack,i);
341 		      if(strcmp($3->name,elem->name)==0)
342   	                yyerror("duplicate enum declaration for %s",
343         	                 elem->name);
344 		    }
345 		    listpush(stack,(void*)$3);
346 		}
347 	    ;
348 
349 enumid: ident '=' constint
350         {
351             $1->objectclass=NC_TYPE;
352             $1->subclass=NC_ECONST;
353             $1->typ.econst=$3;
354 	    $$=$1;
355         }
356         ;
357 
358 opaquedecl: OPAQUE_ '(' INT_CONST ')' typename
359                 {
360 		    vercheck(NC_OPAQUE);
361                     addtogroup($5); /*sets prefix*/
362                     $5->objectclass=NC_TYPE;
363                     $5->subclass=NC_OPAQUE;
364                     $5->typ.typecode=NC_OPAQUE;
365                     $5->typ.size=int32_val;
366                     $5->typ.alignment=ncaux_class_alignment(NC_OPAQUE);
367                 }
368             ;
369 
370 vlendecl: typeref '(' '*' ')' typename
371                 {
372                     Symbol* basetype = $1;
373 		    vercheck(NC_VLEN);
374                     addtogroup($5); /*sets prefix*/
375                     $5->objectclass=NC_TYPE;
376                     $5->subclass=NC_VLEN;
377                     $5->typ.basetype=basetype;
378                     $5->typ.typecode=NC_VLEN;
379                     $5->typ.size=VLENSIZE;
380                     $5->typ.alignment=ncaux_class_alignment(NC_VLEN);
381                 }
382           ;
383 
384 compounddecl: COMPOUND typename '{' fields '}'
385           {
386 	    int i,j;
387 	    vercheck(NC_COMPOUND);
388             addtogroup($2);
389 	    /* check for duplicate field names*/
390 	    stackbase=$4;
391 	    stacklen=listlength(stack);
392 	    for(i=stackbase;i<stacklen;i++) {
393 	      Symbol* elem1 = (Symbol*)listget(stack,i);
394 	      for(j=i+1;j<stacklen;j++) {
395 	          Symbol* elem2 = (Symbol*)listget(stack,j);
396 	          if(strcmp(elem1->name,elem2->name)==0) {
397 	            yyerror("duplicate field declaration for %s",elem1->name);
398 		  }
399 	      }
400 	    }
401 	    $2->objectclass=NC_TYPE;
402             $2->subclass=NC_COMPOUND;
403             $2->typ.basetype=NULL;
404             $2->typ.typecode=NC_COMPOUND;
405 	    $2->subnodes = listnew();
406 	    /* Add in the fields*/
407 	    for(i=stackbase;i<stacklen;i++) {
408 	        Symbol* fsym = (Symbol*)listget(stack,i);
409 		fsym->container = $2;
410  	        listpush($2->subnodes,(void*)fsym);
411 	    }
412 	    listsetlength(stack,stackbase);/* remove stack nodes*/
413           }
414             ;
415 
416 
417 fields:   field ';' {$$=$1;}
418 	   | fields field ';' {$$=$1;}
419 	   ;
420 
421 field: typeref fieldlist
422         {
423 	    int i;
424 	    $$=$2;
425 	    stackbase=$2;
426 	    stacklen=listlength(stack);
427 	    /* process each field in the fieldlist*/
428             for(i=stackbase;i<stacklen;i++) {
429                 Symbol* f = (Symbol*)listget(stack,i);
430 		f->typ.basetype = $1;
431             }
432         }
433         ;
434 
435 primtype:         CHAR_K  { $$ = primsymbols[NC_CHAR]; }
436                 | BYTE_K  { $$ = primsymbols[NC_BYTE]; }
437                 | SHORT_K { $$ = primsymbols[NC_SHORT]; }
438                 | INT_K   { $$ = primsymbols[NC_INT]; }
439                 | FLOAT_K { $$ = primsymbols[NC_FLOAT]; }
440                 | DOUBLE_K{ $$ = primsymbols[NC_DOUBLE]; }
441                 | UBYTE_K  { vercheck(NC_UBYTE); $$ = primsymbols[NC_UBYTE]; }
442                 | USHORT_K { vercheck(NC_USHORT); $$ = primsymbols[NC_USHORT]; }
443                 | UINT_K   { vercheck(NC_UINT); $$ = primsymbols[NC_UINT]; }
444                 | INT64_K   { vercheck(NC_INT64); $$ = primsymbols[NC_INT64]; }
445                 | UINT64_K   { vercheck(NC_UINT64); $$ = primsymbols[NC_UINT64]; }
446                 | STRING_K   { vercheck(NC_STRING); $$ = primsymbols[NC_STRING]; }
447                 ;
448 
449 dimsection:     /* empty */
450                 | DIMENSIONS {}
451 		| DIMENSIONS dimdecls {}
452                 ;
453 
454 dimdecls:       dim_or_attr_decl ';'
455                 | dimdecls dim_or_attr_decl ';'
456                 ;
457 
458 dim_or_attr_decl: dimdeclist {} | attrdecl {} ;
459 
460 dimdeclist:     dimdecl
461                 | dimdeclist ',' dimdecl
462                 ;
463 
464 dimdecl:
465 	  dimd '=' constint
466               {
467 		$1->dim.declsize = (size_t)extractint($3);
468 #ifdef GENDEBUG1
469 fprintf(stderr,"dimension: %s = %llu\n",$1->name,(unsigned long long)$1->dim.declsize);
470 #endif
471 		reclaimconstant($3);
472 	      }
473         | dimd '=' NC_UNLIMITED_K
474                    {
475 		        $1->dim.declsize = NC_UNLIMITED;
476 		        $1->dim.isunlimited = 1;
477 #ifdef GENDEBUG1
478 fprintf(stderr,"dimension: %s = UNLIMITED\n",$1->name);
479 #endif
480 		   }
481                 ;
482 
483 dimd:           ident
484                    {
485                      $1->objectclass=NC_DIM;
486                      if(dupobjectcheck(NC_DIM,$1))
487                         yyerror( "Duplicate dimension declaration for %s",
488                                 $1->name);
489 		     addtogroup($1);
490 		     $$=$1;
491 		     listpush(dimdefs,(void*)$1);
492                    }
493                 ;
494 
495 vasection:      /* empty */
496                 | VARIABLES {}
497                 | VARIABLES vadecls {}
498                 ;
499 
500 vadecls:        vadecl_or_attr ';'
501                 | vadecls vadecl_or_attr ';'
502                 ;
503 
504 vadecl_or_attr: vardecl {} | attrdecl {} ;
505 
506 vardecl:        typeref varlist
507 		{
508 		    int i;
509 		    stackbase=$2;
510 		    stacklen=listlength(stack);
511 		    /* process each variable in the varlist*/
512 	            for(i=stackbase;i<stacklen;i++) {
513 	                Symbol* sym = (Symbol*)listget(stack,i);
514 			sym->objectclass = NC_VAR;
515 		        if(dupobjectcheck(NC_VAR,sym)) {
516                             yyerror("Duplicate variable declaration for %s",
517                                     sym->name);
518 			} else {
519 		  	    sym->typ.basetype = $1;
520 	                    addtogroup(sym);
521 		            listpush(vardefs,(void*)sym);
522 			    sym->var.special = ecalloc(sizeof(Specialdata));
523 			    if(sym->var.special == NULL)
524 			        derror("out of memory");
525 			}
526 		    }
527 		    listsetlength(stack,stackbase);/* remove stack nodes*/
528 		}
529                 ;
530 
531 varlist:      varspec
532 	        {$$=listlength(stack);
533                  listpush(stack,(void*)$1);
534 		}
535             | varlist ',' varspec
536 	        {$$=$1; listpush(stack,(void*)$3);}
537             ;
538 
539 varspec:        ident dimspec
540                     {
541 		    int i;
542 		    Dimset dimset;
543 		    Symbol* var = $1; /* for debugging */
544 		    stacklen=listlength(stack);
545 		    stackbase=$2;
546 		    count = stacklen - stackbase;
547 		    if(count >= NC_MAX_VAR_DIMS) {
548 			yyerror("%s has too many dimensions",$1->name);
549 			count = NC_MAX_VAR_DIMS - 1;
550 			stacklen = stackbase + count;
551 		    }
552   	            dimset.ndims = count;
553 		    /* extract the actual dimensions*/
554 		    if(dimset.ndims > 0) {
555 		        for(i=0;i<count;i++) {
556 			    Symbol* dsym = (Symbol*)listget(stack,stackbase+i);
557 			    dimset.dimsyms[i] = dsym;
558 			}
559 			var->typ.dimset = dimset;
560 		    }
561 		    var->typ.basetype = NULL; /* not yet known*/
562                     var->objectclass=NC_VAR;
563 		    listsetlength(stack,stackbase);/* remove stack nodes*/
564 		    $$ = var;
565 		    }
566                 ;
567 
568 dimspec:        /* empty */ {$$=listlength(stack);}
569                 | '(' dimlist ')' {$$=$2;}
570                 ;
571 
572 dimlist:        dimref {$$=listlength(stack); listpush(stack,(void*)$1);}
573                 | dimlist ',' dimref
574 		    {$$=$1; listpush(stack,(void*)$3);}
575                 ;
576 
577 dimref: path
578             {Symbol* dimsym = $1;
579 		dimsym->objectclass = NC_DIM;
580 		/* Find the actual dimension*/
581 		dimsym = locate(dimsym);
582 		if(dimsym == NULL) {
583 		    derror("Undefined or forward referenced dimension: %s",$1->name);
584 		    YYABORT;
585 		}
586 		$$=dimsym;
587 	    }
588 	;
589 
590 fieldlist:
591 	  fieldspec
592 	    {$$=listlength(stack);
593              listpush(stack,(void*)$1);
594 	    }
595 	| fieldlist ',' fieldspec
596 	    {$$=$1; listpush(stack,(void*)$3);}
597         ;
598 
599 fieldspec:
600 	ident fielddimspec
601 	    {
602 		int i;
603 		Dimset dimset;
604 		stackbase=$2;
605 		stacklen=listlength(stack);
606 		count = stacklen - stackbase;
607 		if(count >= NC_MAX_VAR_DIMS) {
608 		    yyerror("%s has too many dimensions",$1->name);
609 		    count = NC_MAX_VAR_DIMS - 1;
610 		    stacklen = stackbase + count;
611 		}
612   	        dimset.ndims = count;
613 		if(count > 0) {
614 		    /* extract the actual dimensions*/
615 		    for(i=0;i<count;i++) {
616 		        Symbol* dsym = (Symbol*)listget(stack,stackbase+i);
617 		        dimset.dimsyms[i] = dsym;
618 		    }
619 		    $1->typ.dimset = dimset;
620 		}
621 		$1->typ.basetype = NULL; /* not yet known*/
622                 $1->objectclass=NC_TYPE;
623                 $1->subclass=NC_FIELD;
624 		listsetlength(stack,stackbase);/* remove stack nodes*/
625 		$$ = $1;
626 	    }
627 	;
628 
629 fielddimspec:        /* empty */ {$$=listlength(stack);}
630                 | '(' fielddimlist ')' {$$=$2;}
631                 ;
632 
633 fielddimlist:
634 	  fielddim {$$=listlength(stack); listpush(stack,(void*)$1);}
635 	| fielddimlist ',' fielddim
636 	    {$$=$1; listpush(stack,(void*)$3);}
637         ;
638 
639 fielddim:
640 	  UINT_CONST
641 	    {  /* Anonymous integer dimension.
642 	         Can only occur in type definitions*/
643 	     char anon[32];
644 	     sprintf(anon,"const%u",uint32_val);
645 	     $$ = install(anon);
646 	     $$->objectclass = NC_DIM;
647 	     $$->dim.isconstant = 1;
648 	     $$->dim.declsize = uint32_val;
649 	    }
650 	| INT_CONST
651 	    {  /* Anonymous integer dimension.
652 	         Can only occur in type definitions*/
653 	     char anon[32];
654 	     if(int32_val <= 0) {
655 		derror("field dimension must be positive");
656 		YYABORT;
657 	     }
658 	     sprintf(anon,"const%d",int32_val);
659 	     $$ = install(anon);
660 	     $$->objectclass = NC_DIM;
661 	     $$->dim.isconstant = 1;
662 	     $$->dim.declsize = int32_val;
663 	    }
664 	;
665 
666 
667 /* Use this when referencing defined objects */
668 
669 varref:
670 	type_var_ref
671 	    {Symbol* vsym = $1;
672 		if(vsym->objectclass != NC_VAR) {
673 		    derror("Undefined or forward referenced variable: %s",vsym->name);
674 		    YYABORT;
675 		}
676 		$$=vsym;
677 	    }
678 	  ;
679 
680 typeref:
681 	type_var_ref
682 	    {Symbol* tsym = $1;
683 		if(tsym->objectclass != NC_TYPE) {
684 		    derror("Undefined or forward referenced type: %s",tsym->name);
685 		    YYABORT;
686 		}
687 		$$=tsym;
688 	    }
689 	;
690 
691 type_var_ref:
692 	path
693 	    {Symbol* tvsym = $1; Symbol* sym;
694 		/* disambiguate*/
695 		tvsym->objectclass = NC_VAR;
696 		sym = locate(tvsym);
697 		if(sym == NULL) {
698 		    tvsym->objectclass = NC_TYPE;
699 		    sym = locate(tvsym);
700 		    if(tvsym == NULL) {
701 		        derror("Undefined or forward referenced name: %s",$1->name);
702 		        YYABORT;
703 		    } else tvsym = sym;
704 		} else tvsym = sym;
705 		if(tvsym == NULL) {
706 		    derror("Undefined name (line %d): %s",$1->lineno,$1->name);
707 		    YYABORT;
708 		}
709 		$$=tvsym;
710 	    }
711 	| primtype {$$=$1;}
712 	;
713 
714 /* Use this for all attribute decls */
715 /* Global vs var-specific will be separated in makeattribute */
716 
717 /* Watch out; this is left recursive */
718 attrdecllist: /*empty*/ {} | attrdecl ';' attrdecllist {} ;
719 
720 attrdecl:
721 	  ':' _NCPROPS '=' conststring
722 	    {$$ = makespecial(_NCPROPS_FLAG,NULL,NULL,(void*)$4,ISCONST);}
723 	| ':' _ISNETCDF4 '=' constbool
724 	    {$$ = makespecial(_ISNETCDF4_FLAG,NULL,NULL,(void*)$4,ISCONST);}
725 	| ':' _SUPERBLOCK '=' constint
726 	    {$$ = makespecial(_SUPERBLOCK_FLAG,NULL,NULL,(void*)$4,ISCONST);}
727 	| ':' ident '=' datalist
728 	    { $$=makeattribute($2,NULL,NULL,$4,ATTRGLOBAL);}
729 	| typeref type_var_ref ':' ident '=' datalist
730 	    {Symbol* tsym = $1; Symbol* vsym = $2; Symbol* asym = $4;
731 		if(vsym->objectclass == NC_VAR) {
732 		    $$=makeattribute(asym,vsym,tsym,$6,ATTRVAR);
733 		} else {
734 		    derror("Doubly typed attribute: %s",asym->name);
735 		    YYABORT;
736 		}
737 	    }
738 	| type_var_ref ':' ident '=' datalist
739 	    {Symbol* sym = $1; Symbol* asym = $3;
740 		if(sym->objectclass == NC_VAR) {
741 		    $$=makeattribute(asym,sym,NULL,$5,ATTRVAR);
742 		} else if(sym->objectclass == NC_TYPE) {
743 		    $$=makeattribute(asym,NULL,sym,$5,ATTRGLOBAL);
744 		} else {
745 		    derror("Attribute prefix not a variable or type: %s",asym->name);
746 		    YYABORT;
747 		}
748 	    }
749 	| type_var_ref ':' _FILLVALUE '=' datalist
750 	    {$$ = makespecial(_FILLVALUE_FLAG,$1,NULL,(void*)$5,ISLIST);}
751 	| typeref type_var_ref ':' _FILLVALUE '=' datalist
752 	    {$$ = makespecial(_FILLVALUE_FLAG,$2,$1,(void*)$6,ISLIST);}
753 	| type_var_ref ':' _STORAGE '=' conststring
754 	    {$$ = makespecial(_STORAGE_FLAG,$1,NULL,(void*)$5,ISCONST);}
755 	| type_var_ref ':' _CHUNKSIZES '=' intlist
756 	    {$$ = makespecial(_CHUNKSIZES_FLAG,$1,NULL,(void*)$5,ISLIST);}
757 	| type_var_ref ':' _FLETCHER32 '=' constbool
758 	    {$$ = makespecial(_FLETCHER32_FLAG,$1,NULL,(void*)$5,ISCONST);}
759 	| type_var_ref ':' _DEFLATELEVEL '=' constint
760 	    {$$ = makespecial(_DEFLATE_FLAG,$1,NULL,(void*)$5,ISCONST);}
761 	| type_var_ref ':' _SHUFFLE '=' constbool
762 	    {$$ = makespecial(_SHUFFLE_FLAG,$1,NULL,(void*)$5,ISCONST);}
763 	| type_var_ref ':' _ENDIANNESS '=' conststring
764 	    {$$ = makespecial(_ENDIAN_FLAG,$1,NULL,(void*)$5,ISCONST);}
765 	| type_var_ref ':' _FILTER '=' conststring
766 	    {$$ = makespecial(_FILTER_FLAG,$1,NULL,(void*)$5,ISCONST);}
767 	| type_var_ref ':' _NOFILL '=' constbool
768 	    {$$ = makespecial(_NOFILL_FLAG,$1,NULL,(void*)$5,ISCONST);}
769 	| ':' _FORMAT '=' conststring
770 	    {$$ = makespecial(_FORMAT_FLAG,NULL,NULL,(void*)$4,ISCONST);}
771 	;
772 
773 path:
774 	  ident
775 	    {
776 	        $$=$1;
777                 $1->ref.is_ref=1;
778                 $1->is_prefixed=0;
779                 setpathcurrent($1);
780 	    }
781 	| PATH
782 	    {
783 	        $$=$1;
784                 $1->ref.is_ref=1;
785                 $1->is_prefixed=1;
786 	        /* path is set in ncgen.l*/
787 	    }
788 	;
789 
790 datasection:    /* empty */
791                 | DATA {}
792                 | DATA datadecls {}
793                 ;
794 
795 datadecls:      datadecl ';'
796                 | datadecls datadecl ';'
797                 ;
798 
799 datadecl:       varref '=' datalist
800                    {$1->data = $3;}
801                 ;
802 datalist:
803 	  datalist0 {$$ = $1;}
804 	| datalist1 {$$ = $1;}
805 	;
806 
807 datalist0:
808 	/*empty*/ {$$ = builddatalist(0);}
809 	;
810 
811 datalist1: /* Must have at least 1 element */
812 	  dataitem {$$ = const2list($1);}
813 	| datalist ',' dataitem
814 	    {dlappend($1,($3)); $$=$1; }
815 	;
816 
817 dataitem:
818 	  constdata {$$=$1;}
819 	| '{' datalist '}' {$$=builddatasublist($2);}
820 	;
821 
822 constdata:
823 	  simpleconstant      {$$=$1;}
824 	| OPAQUESTRING	{$$=makeconstdata(NC_OPAQUE);}
825 	| FILLMARKER	{$$=makeconstdata(NC_FILLVALUE);}
826 	| NIL   	{$$=makeconstdata(NC_NIL);}
827 	| econstref	{$$=$1;}
828 	| function
829 	;
830 
831 econstref:
832 	path {$$ = makeenumconstref($1);}
833 	;
834 
835 function:
836 	ident '(' arglist ')' {$$=evaluate($1,$3);}
837 	;
838 
839 arglist:
840 	  simpleconstant
841 	    {$$ = const2list($1);}
842 	| arglist ',' simpleconstant
843 	    {dlappend($1,($3)); $$=$1;}
844 	;
845 
846 simpleconstant:
847 	  CHAR_CONST	{$$=makeconstdata(NC_CHAR);} /* never used apparently*/
848 	| BYTE_CONST	{$$=makeconstdata(NC_BYTE);}
849 	| SHORT_CONST	{$$=makeconstdata(NC_SHORT);}
850 	| INT_CONST	{$$=makeconstdata(NC_INT);}
851 	| INT64_CONST	{$$=makeconstdata(NC_INT64);}
852 	| UBYTE_CONST	{$$=makeconstdata(NC_UBYTE);}
853 	| USHORT_CONST	{$$=makeconstdata(NC_USHORT);}
854 	| UINT_CONST	{$$=makeconstdata(NC_UINT);}
855 	| UINT64_CONST	{$$=makeconstdata(NC_UINT64);}
856 	| FLOAT_CONST	{$$=makeconstdata(NC_FLOAT);}
857 	| DOUBLE_CONST	{$$=makeconstdata(NC_DOUBLE);}
858 	| TERMSTRING	{$$=makeconstdata(NC_STRING);}
859 	;
860 
861 intlist:
862 	  constint {$$ = const2list($1);}
863 	| intlist ',' constint {$$=$1; dlappend($1,($3));}
864 	;
865 
866 constint:
867 	  INT_CONST
868 		{$$=makeconstdata(NC_INT);}
869 	| UINT_CONST
870 		{$$=makeconstdata(NC_UINT);}
871 	| INT64_CONST
872 		{$$=makeconstdata(NC_INT64);}
873 	| UINT64_CONST
874 		{$$=makeconstdata(NC_UINT64);}
875 	;
876 
877 conststring:
878 	TERMSTRING	{$$=makeconstdata(NC_STRING);}
879 	;
880 
881 constbool:
882 	  conststring {$$=$1;}
883 	| constint {$$=$1;}
884 
885 /* End OF RULES */
886 
887 /* Push all idents thru here*/
888 ident:
889 	IDENT {$$=$1;}
890 	;
891 
892 %%
893 
894 #ifndef NO_STDARG
895 static void
896 yyerror(const char *fmt, ...)
897 #else
898 static void
899 yyerror(fmt,va_alist) const char* fmt; va_dcl
900 #endif
901 {
902     va_list argv;
903     va_start(argv,fmt);
904     (void)fprintf(stderr,"%s: %s line %d: ", progname, cdlname, lineno);
905     vderror(fmt,argv);
906     va_end(argv);
907 }
908 
909 /* undefine yywrap macro, in case we are using bison instead of yacc */
910 #ifdef yywrap
911 #undef yywrap
912 #endif
913 
914 static int
ncgwrap(void)915 ncgwrap(void)                    /* returns 1 on EOF if no more input */
916 {
917     return  1;
918 }
919 
920 /* get lexical input routine generated by lex  */
921 #include "ncgenl.c"
922 
923 /* Really should init our data within this file */
924 void
parse_init(void)925 parse_init(void)
926 {
927     int i;
928     opaqueid = 0;
929     arrayuid = 0;
930     symlist = listnew();
931     stack = listnew();
932     groupstack = listnew();
933     consttype = NC_NAT;
934     grpdefs = listnew();
935     dimdefs = listnew();
936     attdefs = listnew();
937     gattdefs = listnew();
938     xattdefs = listnew();
939     typdefs = listnew();
940     vardefs = listnew();
941     condefs = listnew();
942     tmp = listnew();
943     /* Create the primitive types */
944     for(i=NC_NAT+1;i<=NC_STRING;i++) {
945         primsymbols[i] = makeprimitivetype(i);
946     }
947     lex_init();
948 }
949 
950 static Symbol*
makeprimitivetype(nc_type nctype)951 makeprimitivetype(nc_type nctype)
952 {
953     Symbol* sym = install(primtypenames[nctype]);
954     sym->objectclass=NC_TYPE;
955     sym->subclass=NC_PRIM;
956     sym->nc_id = nctype;
957     sym->typ.typecode = nctype;
958     sym->typ.size = ncsize(nctype);
959     sym->typ.nelems = 1;
960     sym->typ.alignment = ncaux_class_alignment(nctype);
961     /* Make the basetype circular so we can always ask for it */
962     sym->typ.basetype = sym;
963     sym->prefix = listnew();
964     return sym;
965 }
966 
967 /* Symbol table operations for ncgen tool */
968 /* install sname in symbol table even if it is already there */
969 Symbol*
install(const char * sname)970 install(const char *sname)
971 {
972     Symbol* sp;
973     sp = (Symbol*) ecalloc (sizeof (struct Symbol));
974     sp->name = nulldup(sname);
975     sp->lineno = lineno;
976     sp->location = currentgroup();
977     sp->container = currentgroup();
978     listpush(symlist,sp);
979     return sp;
980 }
981 
982 static Symbol*
currentgroup(void)983 currentgroup(void)
984 {
985     if(listlength(groupstack) == 0) return rootgroup;
986     return (Symbol*)listtop(groupstack);
987 }
988 
989 static Symbol*
createrootgroup(const char * dataset)990 createrootgroup(const char* dataset)
991 {
992     Symbol* gsym = install(dataset);
993     gsym->objectclass = NC_GRP;
994     gsym->container = NULL;
995     gsym->subnodes = listnew();
996     gsym->grp.is_root = 1;
997     gsym->prefix = listnew();
998     listpush(grpdefs,(void*)gsym);
999     rootgroup = gsym;
1000     return gsym;
1001 }
1002 
1003 static Symbol*
creategroup(Symbol * gsym)1004 creategroup(Symbol * gsym)
1005 {
1006     /* See if this group already exists in currentgroup */
1007     gsym->objectclass = NC_GRP;
1008     if(dupobjectcheck(NC_GRP,gsym)) {
1009         derror("Duplicate group name in same scope: %s",gsym->name);
1010 	return NULL;
1011     }
1012     addtogroup(gsym);
1013     gsym->subnodes = listnew();
1014     listpush(groupstack,(void*)gsym);
1015     listpush(grpdefs,(void*)gsym);
1016     return gsym;
1017 }
1018 
1019 static NCConstant*
makeconstdata(nc_type nctype)1020 makeconstdata(nc_type nctype)
1021 {
1022     NCConstant* con = nullconst();
1023     consttype = nctype;
1024     con->nctype = nctype;
1025     con->lineno = lineno;
1026     con->filled = 0;
1027     switch (nctype) {
1028 	case NC_CHAR: con->value.charv = char_val; break;
1029         case NC_BYTE: con->value.int8v = byte_val; break;
1030         case NC_SHORT: con->value.int16v = int16_val; break;
1031         case NC_INT: con->value.int32v = int32_val; break;
1032         case NC_FLOAT:
1033 	    con->value.floatv = float_val;
1034 	    break;
1035         case NC_DOUBLE:
1036 	    con->value.doublev = double_val;
1037 	    break;
1038         case NC_STRING: { /* convert to a set of chars*/
1039 	    size_t len;
1040 	    len = bbLength(lextext);
1041 	    con->value.stringv.len = len;
1042 	    con->value.stringv.stringv = bbExtract(lextext);
1043 	    }
1044 	    break;
1045 
1046 	/* Allow these constants even in netcdf-3 */
1047         case NC_UBYTE: con->value.uint8v = ubyte_val; break;
1048         case NC_USHORT: con->value.uint16v = uint16_val; break;
1049         case NC_UINT: con->value.uint32v = uint32_val; break;
1050         case NC_INT64: con->value.int64v = int64_val; break;
1051         case NC_UINT64: con->value.uint64v = uint64_val; break;
1052 
1053 #ifdef USE_NETCDF4
1054 	case NC_OPAQUE: {
1055 	    char* s;
1056 	    int len;
1057 	    len = bbLength(lextext);
1058 	    s = (char*)ecalloc(len+1);
1059 	    strncpy(s,bbContents(lextext),len);
1060 	    s[len] = '\0';
1061 	    con->value.opaquev.stringv = s;
1062 	    con->value.opaquev.len = len;
1063 	    } break;
1064 
1065 	case NC_NIL:
1066 	    break; /* no associated value*/
1067 #endif
1068 
1069  	case NC_FILLVALUE:
1070 	    break; /* no associated value*/
1071 
1072 	default:
1073 	    yyerror("Data constant: unexpected NC type: %s",
1074 		    nctypename(nctype));
1075 	    con->value.stringv.stringv = NULL;
1076 	    con->value.stringv.len = 0;
1077     }
1078     return con;
1079 }
1080 
1081 static NCConstant*
makeenumconstref(Symbol * refsym)1082 makeenumconstref(Symbol* refsym)
1083 {
1084     NCConstant* con = nullconst();
1085 
1086     markcdf4("Enum type");
1087     consttype = NC_ENUM;
1088     con->nctype = NC_ECONST;
1089     con->lineno = lineno;
1090     con->filled = 0;
1091     refsym->objectclass = NC_TYPE;
1092     refsym->subclass = NC_ECONST;
1093     con->value.enumv = refsym;
1094     return con;
1095 }
1096 
1097 static void
addtogroup(Symbol * sym)1098 addtogroup(Symbol* sym)
1099 {
1100     Symbol* grp = currentgroup();
1101     sym->container = grp;
1102     listpush(grp->subnodes,(void*)sym);
1103     setpathcurrent(sym);
1104 }
1105 
1106 /* Check for duplicate name of given type within current group*/
1107 static int
dupobjectcheck(nc_class objectclass,Symbol * pattern)1108 dupobjectcheck(nc_class objectclass, Symbol* pattern)
1109 {
1110     int i;
1111     Symbol* grp;
1112     if(pattern == NULL) return 0;
1113     grp = pattern->container;
1114     if(grp == NULL || grp->subnodes == NULL) return 0;
1115     for(i=0;i<listlength(grp->subnodes);i++) {
1116 	Symbol* sym = (Symbol*)listget(grp->subnodes,i);
1117 	if(!sym->ref.is_ref && sym->objectclass == objectclass
1118 	   && strcmp(sym->name,pattern->name)==0) return 1;
1119     }
1120     return 0;
1121 }
1122 
1123 static void
setpathcurrent(Symbol * sym)1124 setpathcurrent(Symbol* sym)
1125 {
1126     sym->is_prefixed = 0;
1127     sym->prefix = prefixdup(groupstack);
1128 }
1129 
1130 /* Convert an nc_type code to the corresponding Symbol*/
1131 Symbol*
basetypefor(nc_type nctype)1132 basetypefor(nc_type nctype)
1133 {
1134     return primsymbols[nctype];
1135 }
1136 
1137 static int
truefalse(NCConstant * con,int tag)1138 truefalse(NCConstant* con, int tag)
1139 {
1140     if(con->nctype == NC_STRING) {
1141 	char* sdata = con->value.stringv.stringv;
1142 	if(strncmp(sdata,"false",NC_MAX_NAME) == 0
1143            || strncmp(sdata,"0",NC_MAX_NAME) == 0)
1144 	    return 0;
1145 	else if(strncmp(sdata,"true",NC_MAX_NAME) == 0
1146            || strncmp(sdata,"1",NC_MAX_NAME) == 0)
1147 	    return 1;
1148 	else goto fail;
1149     } else if(con->value.int32v < 0 || con->value.int32v > 1)
1150 	goto fail;
1151     return con->value.int32v;
1152 
1153 fail:
1154     derror("%s: illegal value",specialname(tag));
1155     return 0;
1156 }
1157 
1158 /* Since this may be affected by the _Format attribute, which
1159    may come last, capture all the special info and sort it out
1160    in semantics.
1161 */
1162 static Symbol*
makespecial(int tag,Symbol * vsym,Symbol * tsym,void * data,int isconst)1163 makespecial(int tag, Symbol* vsym, Symbol* tsym, void* data, int isconst)
1164 {
1165     Symbol* attr = NULL;
1166     Datalist* list = NULL;
1167     NCConstant* con = NULL;
1168     NCConstant* tmp = NULL;
1169     int tf = 0;
1170     char* sdata = NULL;
1171     int idata =  -1;
1172 
1173     if((GLOBAL_SPECIAL & tag) != 0) {
1174         if(vsym != NULL) {
1175             derror("_Format: must be global attribute");
1176             vsym = NULL;
1177         }
1178     } else {
1179         if(vsym == NULL) {
1180 	    derror("%s: must have non-NULL vsym", specialname(tag));
1181 	    return NULL;
1182         }
1183     }
1184 
1185     if(tag != _FILLVALUE_FLAG && tag != _FORMAT_FLAG)
1186         /*Main.*/specials_flag++;
1187 
1188     if(isconst)
1189 	con = (NCConstant*)data;
1190     else
1191         list = (Datalist*)data;
1192 
1193     switch (tag) {
1194     case _FLETCHER32_FLAG:
1195     case _SHUFFLE_FLAG:
1196     case _ISNETCDF4_FLAG:
1197     case _NOFILL_FLAG:
1198 	tmp = nullconst();
1199 	tmp->nctype = (con->nctype == NC_STRING?NC_STRING:NC_INT);
1200 	convert1(con,tmp);
1201 	tf = truefalse(tmp,tag);
1202 	reclaimconstant(tmp);
1203 	break;
1204     case _FORMAT_FLAG:
1205     case _STORAGE_FLAG:
1206     case _NCPROPS_FLAG:
1207     case _ENDIAN_FLAG:
1208     case _FILTER_FLAG:
1209 	tmp = nullconst();
1210         tmp->nctype = NC_STRING;
1211 	convert1(con,tmp);
1212 	if(tmp->nctype == NC_STRING) {
1213 	    sdata = tmp->value.stringv.stringv;
1214 	    tmp->value.stringv.stringv = NULL;
1215 	    tmp->value.stringv.len = 0;
1216 	} else
1217 	    derror("%s: illegal value",specialname(tag));
1218 	reclaimconstant(tmp);
1219 	break;
1220     case _SUPERBLOCK_FLAG:
1221     case _DEFLATE_FLAG:
1222 	tmp = nullconst();
1223         tmp->nctype = NC_INT;
1224 	convert1(con,tmp);
1225 	if(tmp->nctype == NC_INT)
1226 	    idata = tmp->value.int32v;
1227 	else
1228 	    derror("%s: illegal value",specialname(tag));
1229 	reclaimconstant(tmp);
1230 	break;
1231     case _CHUNKSIZES_FLAG:
1232     case _FILLVALUE_FLAG:
1233 	/* Handle below */
1234 	break;
1235     default: PANIC1("unexpected special tag: %d",tag);
1236     }
1237 
1238     if(tag == _FORMAT_FLAG) {
1239 	/* Watch out: this is a global attribute */
1240 	struct Kvalues* kvalue;
1241 	int found = 0;
1242 	/* Use the table in main.c */
1243         for(kvalue = legalkinds; kvalue->name; kvalue++) {
1244           if(sdata) {
1245             if(strcmp(sdata, kvalue->name) == 0) {
1246               globalspecials._Format = kvalue->k_flag;
1247 	      /*Main.*/format_attribute = 1;
1248               found = 1;
1249               break;
1250             }
1251           }
1252 	}
1253 	if(!found)
1254 	    derror("_Format: illegal value: %s",sdata);
1255     } else if((GLOBAL_SPECIAL & tag) != 0) {
1256 	if(tag == _ISNETCDF4_FLAG)
1257 	    globalspecials._IsNetcdf4 = tf;
1258 	else if(tag == _SUPERBLOCK_FLAG)
1259 	    globalspecials._Superblock = idata;
1260 	else if(tag == _NCPROPS_FLAG) {
1261 	    globalspecials._NCProperties = sdata;
1262 	    sdata = NULL;
1263 	}
1264     } else {
1265         Specialdata* special;
1266         /* Set up special info */
1267 	if(vsym->var.special == NULL) {
1268             vsym->var.special = ecalloc(sizeof(Specialdata));
1269 	    if(vsym->var.special == NULL)
1270 	        derror("Out of memory");
1271 	}
1272         special = vsym->var.special;
1273         if(tag == _FILLVALUE_FLAG) {
1274             /* fillvalue must be a single value*/
1275 	    if(!isconst && datalistlen(list) != 1)
1276                 derror("_FillValue: must be a single (possibly compound) value",
1277                             vsym->name);
1278 	    if(isconst) {
1279 	        list = const2list(con);
1280 		con = NULL;
1281 	    }
1282             /* check that the attribute value contains no fill values*/
1283             if(containsfills(list)) {
1284                 derror("Attribute data may not contain fill values (i.e. _ )");
1285             }
1286             /* _FillValue is also a real attribute*/
1287             if(vsym->objectclass != NC_VAR) {
1288                 derror("_FillValue attribute not associated with variable: %s",vsym->name);
1289             }
1290             if(tsym  == NULL) tsym = vsym->typ.basetype;
1291             else if(vsym->typ.basetype != tsym) {
1292                 derror("_FillValue attribute type does not match variable type: %s",vsym->name);
1293             }
1294             special->_Fillvalue = clonedatalist(list);
1295 	    /* Create the corresponding attribute */
1296             attr = makeattribute(install("_FillValue"),vsym,tsym,list,ATTRVAR);
1297 	    list = NULL;
1298         } else switch (tag) {
1299 	    /* These will be output as attributes later */
1300             case _STORAGE_FLAG:
1301               if(!sdata)
1302                 derror("_Storage: illegal NULL value");
1303               else if(strcmp(sdata,"contiguous") == 0)
1304                 special->_Storage = NC_CONTIGUOUS;
1305               else if(strcmp(sdata,"chunked") == 0)
1306                 special->_Storage = NC_CHUNKED;
1307               else
1308                 derror("_Storage: illegal value: %s",sdata);
1309               special->flags |= _STORAGE_FLAG;
1310               break;
1311           case _FLETCHER32_FLAG:
1312                 special->_Fletcher32 = tf;
1313                 special->flags |= _FLETCHER32_FLAG;
1314                 break;
1315             case _DEFLATE_FLAG:
1316                 special->_DeflateLevel = idata;
1317                 special->flags |= _DEFLATE_FLAG;
1318                 break;
1319             case _SHUFFLE_FLAG:
1320                 special->_Shuffle = tf;
1321                 special->flags |= _SHUFFLE_FLAG;
1322                 break;
1323             case _ENDIAN_FLAG:
1324               if(!sdata)
1325                 derror("_Endianness: illegal NULL value");
1326               else if(strcmp(sdata,"little") == 0)
1327                 special->_Endianness = 1;
1328               else if(strcmp(sdata,"big") == 0)
1329                 special->_Endianness = 2;
1330               else
1331                 derror("_Endianness: illegal value: %s",sdata);
1332               special->flags |= _ENDIAN_FLAG;
1333               break;
1334           case _NOFILL_FLAG:
1335                 special->_Fill = (1 - tf); /* negate */
1336                 special->flags |= _NOFILL_FLAG;
1337                 break;
1338           case _CHUNKSIZES_FLAG: {
1339                 int i;
1340 		list = (isconst ? const2list(con) : list);
1341                 special->nchunks = list->length;
1342                 special->_ChunkSizes = (size_t*)ecalloc(sizeof(size_t)*special->nchunks);
1343                 for(i=0;i<special->nchunks;i++) {
1344 		    tmp = nullconst();
1345                     tmp->nctype = NC_INT;
1346                     convert1(list->data[i],tmp);
1347                     if(tmp->nctype == NC_INT) {
1348                         special->_ChunkSizes[i] = (size_t)tmp->value.int32v;
1349                     } else {
1350                         efree(special->_ChunkSizes);
1351                         derror("%s: illegal value",specialname(tag));
1352                     }
1353 		    reclaimconstant(tmp);
1354                 }
1355                 special->flags |= _CHUNKSIZES_FLAG;
1356                 /* Chunksizes => storage == chunked */
1357                 special->flags |= _STORAGE_FLAG;
1358                 special->_Storage = NC_CHUNKED;
1359                 } break;
1360           case _FILTER_FLAG:
1361 #ifdef USE_NETCDF4
1362 		/* Parse the filter spec */
1363 		if(parsefilterflag(sdata,special) == NC_NOERR)
1364                     special->flags |= _FILTER_FLAG;
1365 		else {
1366 		    efree(special->_FilterParams);
1367 		    derror("_Filter: unparseable filter spec: %s",sdata);
1368 		}
1369 #else
1370 	        derror("%s: the filter attribute requires netcdf-4 to be enabled",specialname(tag));
1371 #endif
1372                 break;
1373             default: PANIC1("makespecial: illegal token: %d",tag);
1374          }
1375     }
1376     if(sdata) efree(sdata);
1377     if(con) reclaimconstant(con);
1378     if(list) reclaimdatalist(list);
1379     return attr;
1380 }
1381 
1382 static Symbol*
makeattribute(Symbol * asym,Symbol * vsym,Symbol * tsym,Datalist * data,Attrkind kind)1383 makeattribute(Symbol* asym,
1384 		Symbol* vsym,
1385 		Symbol* tsym,
1386 		Datalist* data,
1387 		Attrkind kind) /* global var or unknown*/
1388 {
1389     asym->objectclass = NC_ATT;
1390     asym->data = data;
1391     switch (kind) {
1392     case ATTRVAR:
1393         asym->att.var = vsym;
1394         asym->typ.basetype = tsym;
1395         listpush(attdefs,(void*)asym);
1396         addtogroup(asym);
1397 	break;
1398     case ATTRGLOBAL:
1399         asym->att.var = NULL; /* NULL => NC_GLOBAL*/
1400         asym->typ.basetype = tsym;
1401         listpush(gattdefs,(void*)asym);
1402         addtogroup(asym);
1403 	break;
1404     default: PANIC1("unexpected attribute type: %d",kind);
1405     }
1406     /* finally; check that the attribute value contains no fill values*/
1407     if(containsfills(data)) {
1408 	derror("Attribute data may not contain fill values (i.e. _ ): %s",asym->name);
1409     }
1410     return asym;
1411 }
1412 
1413 static long long
extractint(NCConstant * con)1414 extractint(NCConstant* con)
1415 {
1416     switch (con->nctype) {
1417     case NC_BYTE: return (long long)(con->value.int8v);
1418     case NC_SHORT: return (long long)(con->value.int16v);
1419     case NC_INT: return (long long)(con->value.int32v);
1420     case NC_UBYTE: return (long long)(con->value.uint8v);
1421     case NC_USHORT: return (long long)(con->value.uint16v);
1422     case NC_UINT: return (long long)(con->value.uint32v);
1423     case NC_INT64: return (long long)(con->value.int64v);
1424     default:
1425 	derror("Not a signed integer type: %d",con->nctype);
1426 	break;
1427     }
1428     return 0;
1429 }
1430 
1431 static int
containsfills(Datalist * list)1432 containsfills(Datalist* list)
1433 {
1434     if(list != NULL) {
1435         int i;
1436         NCConstant** cons = list->data;
1437         for(i=0;i<list->length;i++) {
1438 	    if(cons[i]->nctype == NC_COMPOUND) {
1439 	        if(containsfills(cons[i]->value.compoundv)) return 1;
1440 	    } else if(cons[i]->nctype == NC_FILLVALUE)
1441 		return 1;
1442 	}
1443     }
1444     return 0;
1445 }
1446 
1447 /*
1448 Try to infer the file type from the
1449 kinds of constructs used in the cdl file.
1450 */
1451 static void
vercheck(int tid)1452 vercheck(int tid)
1453 {
1454     switch (tid) {
1455     case NC_UBYTE: markcdf4("netCDF4/5 type: UBYTE"); break;
1456     case NC_USHORT: markcdf4("netCDF4/5 type: USHORT"); break;
1457     case NC_UINT: markcdf4("netCDF4/5 type: UINT"); break;
1458     case NC_INT64: markcdf4("netCDF4/5 type: INT64"); break;
1459     case NC_UINT64: markcdf4("netCDF4/5 type: UINT64"); break;
1460     case NC_STRING: markcdf4("netCDF4 type: STRING"); break;
1461     case NC_VLEN: markcdf4("netCDF4 type: VLEN"); break;
1462     case NC_OPAQUE: markcdf4("netCDF4 type: OPAQUE"); break;
1463     case NC_ENUM: markcdf4("netCDF4 type: ENUM"); break;
1464     case NC_COMPOUND: markcdf4("netCDF4 type: COMPOUND"); break;
1465     default: break;
1466     }
1467 }
1468 
1469 const char*
specialname(int tag)1470 specialname(int tag)
1471 {
1472     struct Specialtoken* spp = specials;
1473     for(;spp->name;spp++) {
1474 	if(spp->tag == tag)
1475 	    return spp->name;
1476     }
1477     return "<unknown>";
1478 }
1479 
1480 #ifdef USE_NETCDF4
1481 /*
1482 Parse a filter spec string and store it in special
1483 */
1484 static int
parsefilterflag(const char * sdata,Specialdata * special)1485 parsefilterflag(const char* sdata, Specialdata* special)
1486 {
1487     int stat = NC_NOERR;
1488 
1489     if(sdata == NULL || strlen(sdata) == 0) return NC_EINVAL;
1490 
1491     stat = NC_parsefilterspec(sdata, &special->_FilterID, &special->nparams, &special->_FilterParams);
1492     if(stat)
1493         derror("Malformed filter spec: %s",sdata);
1494     return stat;
1495 }
1496 #endif
1497 
1498 /*
1499 Since the arguments are all simple constants,
1500 we can evaluate the function immediately
1501 and return its value.
1502 Note that currently, only a single value can
1503 be returned.
1504 */
1505 
1506 static NCConstant*
evaluate(Symbol * fcn,Datalist * arglist)1507 evaluate(Symbol* fcn, Datalist* arglist)
1508 {
1509     NCConstant* result = nullconst();
1510 
1511     /* prepare the result */
1512     result->lineno = fcn->lineno;
1513 
1514     if(strcasecmp(fcn->name,"time") == 0) {
1515         char* timekind = NULL;
1516         char* timevalue = NULL;
1517         result->nctype = NC_DOUBLE;
1518         result->value.doublev = 0;
1519 	/* int time([string],string) */
1520 	switch (arglist->length) {
1521 	case 2:
1522 	    if(arglist->data[1]->nctype != NC_STRING) {
1523 	        derror("Expected function signature: time([string,]string)");
1524 	        goto done;
1525 	    }
1526 	    /* fall thru */
1527 	case 1:
1528 	    if(arglist->data[0]->nctype != NC_STRING) {
1529 	        derror("Expected function signature: time([string,]string)");
1530 	        goto done;
1531 	    }
1532 	    break;
1533 	case 0:
1534 	default:
1535 	    derror("Expected function signature: time([string,]string)");
1536 	    goto done;
1537 	}
1538 	if(arglist->length == 2) {
1539 	    timekind = arglist->data[0]->value.stringv.stringv;
1540             timevalue = arglist->data[1]->value.stringv.stringv;
1541 	} else
1542             timevalue = arglist->data[0]->value.stringv.stringv;
1543 	if(timekind == NULL) { /* use cd time as the default */
1544             cdCompTime comptime;
1545 	    CdTime cdtime;
1546 	    cdCalenType timetype = cdStandard;
1547 	    cdChar2Comp(timetype,timevalue,&comptime);
1548 	    /* convert comptime to cdTime */
1549 	    cdtime.year = comptime.year;
1550 	    cdtime.month = comptime.month;
1551 	    cdtime.day = comptime.day;
1552 	    cdtime.hour = comptime.hour;
1553 	    cdtime.baseYear = 1970;
1554 	    cdtime.timeType = CdChron;
1555 	    /* convert to double value */
1556 	    Cdh2e(&cdtime,&result->value.doublev);
1557         } else {
1558 	    derror("Time conversion '%s' not supported",timekind);
1559 	    goto done;
1560 	}
1561     } else {	/* Unknown function */
1562 	derror("Unknown function name: %s",fcn->name);
1563 	goto done;
1564     }
1565 
1566 done:
1567     return result;
1568 }
1569