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