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