1 /*********************************************************************
2 * Copyright 1993, UCAR/Unidata
3 * See netcdf/COPYRIGHT file for copying and redistribution conditions.
4 * $Id$
5 *********************************************************************/
6
7 /* yacc source for "ncgen", a netCDL parser and netCDF generator */
8
9 %{
10 #ifndef lint
11 static char SccsId[] = "$Id$";
12 #endif
13 #include <string.h>
14 #include <stdlib.h>
15 #include "ncgen.h"
16
17 typedef struct Symbol { /* symbol table entry */
18 char *name;
19 struct Symbol *next;
20 unsigned is_dim : 1; /* appears as netCDF dimension */
21 unsigned is_var : 1; /* appears as netCDF variable */
22 unsigned is_att : 1; /* appears as netCDF attribute */
23 int dnum; /* handle as a dimension */
24 int vnum; /* handle as a variable */
25 } *YYSTYPE1;
26
27 #define YYSTYPE YYSTYPE1
28 YYSTYPE install(), lookup();
29 YYSTYPE symlist; /* symbol table: linked list */
30
31 void init_netcdf(); /* initializes netcdf counts (e.g. nvars) */
32 void define_netcdf(); /* generates all define mode stuff */
33 void load_netcdf(); /* generates variable puts */
34 void close_netcdf(); /* generates close */
35
36 void derror(); /* varargs message emitter */
37 void *emalloc(), *erealloc(); /* malloc that checks for memory exhausted */
38 void clearout(); /* initializes symbol table */
39 void nc_getfill(); /* to get fill value for various types */
40 void nc_putfill(); /* to get fill value for various types */
41 void nc_fill(); /* fills a generic array with a value */
42 int put_variable(); /* invoke nc calls or generate code to put */
43 /* variable values */
44 extern int derror_count; /* counts errors in netcdf definition */
45 extern int lineno; /* line number for error messages */
46
47 static int not_a_string; /* whether last constant read was a string */
48 static char termstring[MAXTRST]; /* last terminal string read */
49 static double double_val; /* last double value read */
50 static float float_val; /* last float value read */
51 static nclong long_val; /* last long value read */
52 static short short_val; /* last short value read */
53 static char char_val; /* last char value read */
54 static char byte_val; /* last byte value read */
55
56 static nc_type type_code; /* holds declared type for variables */
57 static nc_type atype_code; /* holds derived type for attributes */
58 static char *netcdfname; /* to construct netcdf file name */
59 static void *att_space; /* pointer to block for attribute values */
60 static nc_type valtype; /* type code for list of attribute values */
61
62 static char *char_valp; /* pointers used to accumulate data values */
63 static char *byte_valp;
64 static short *short_valp;
65 static nclong *long_valp;
66 static float *float_valp;
67 static double *double_valp;
68 static void *rec_cur; /* pointer to where next data value goes */
69 static void *rec_start; /* start of space for a record of data */
70 %}
71
72 /* DECLARATIONS */
73
74 %token
75 NC_UNLIMITED_K /* keyword for unbounded record dimension */
76 BYTE_K /* keyword for byte datatype */
77 CHAR_K /* keyword for char datatype */
78 SHORT_K /* keyword for short datatype */
79 LONG_K /* keyword for long datatype */
80 FLOAT_K /* keyword for float datatype */
81 DOUBLE_K /* keyword for double datatype */
82 IDENT /* name for a dimension, variable, or attribute */
83 TERMSTRING /* terminal string */
84 BYTE_CONST /* byte constant */
85 CHAR_CONST /* char constant */
86 SHORT_CONST /* short constant */
87 LONG_CONST /* long constant */
88 FLOAT_CONST /* float constant */
89 DOUBLE_CONST /* double constant */
90 DIMENSIONS /* keyword starting dimensions section, if any */
91 VARIABLES /* keyword starting variables section, if any */
92 NETCDF /* keyword declaring netcdf name */
93 DATA /* keyword starting data section, if any */
94
95 %start ncdesc /* start symbol for grammar */
96
97 %%
98
99 /* RULES */
100
101 ncdesc: NETCDF
102 '{'
103 { init_netcdf(); }
104 dimsection /* dimension declarations */
105 {
106 if (ndims > H4_MAX_NC_DIMS)
107 derror("Too many dimensions");
108 }
109 vasection /* variable and attribute declarations */
110 {
111 if (derror_count == 0)
112 define_netcdf(netcdfname);
113 }
114 datasection /* data, variables loaded as encountered */
115 '}'
116 {
117 if (derror_count == 0)
118 close_netcdf();
119 }
120 ;
121 dimsection: /* empty */
122 | DIMENSIONS dimdecls
123 ;
124 dimdecls: dimdecline ';'
125 | dimdecls dimdecline ';'
126 ;
127 dimdecline: dimdecl
128 | dimdecline ',' dimdecl
129 ;
130 dimdecl: dimd '=' LONG_CONST
131 { if (long_val <= 0)
132 derror("negative dimension size");
133 dims[ndims].size = long_val;
134 ndims++;
135 }
136 | dimd '=' NC_UNLIMITED_K
137 { if (rec_dim != -1)
138 derror("only one NC_UNLIMITED dimension allowed");
139 rec_dim = ndims; /* the unlimited (record) dimension */
140 dims[ndims].size = NC_UNLIMITED;
141 ndims++;
142 }
143 ;
144 dimd: dim
145 { if ($1->is_dim == 1) {
146 derror( "duplicate dimension declaration for %s",
147 $1->name);
148 }
149 $1->is_dim = 1;
150 $1->dnum = ndims;
151 dims[ndims].name = (char *) emalloc(strlen($1->name)+1);
152 (void) strcpy(dims[ndims].name, $1->name);
153 }
154 ;
155 dim: IDENT
156 ;
157 vasection: /* empty */
158 | VARIABLES vadecls
159 ;
160 vadecls: vadecl ';'
161 | vadecls vadecl ';'
162 ;
163 vadecl: vardecl | attdecl
164 ;
165 vardecl: type varlist
166 ;
167 type: BYTE_K { type_code = NC_BYTE; }
168 | CHAR_K { type_code = NC_CHAR; }
169 | SHORT_K { type_code = NC_SHORT; }
170 | LONG_K { type_code = NC_LONG; }
171 | FLOAT_K { type_code = NC_FLOAT; }
172 | DOUBLE_K { type_code = NC_DOUBLE; }
173 ;
174 varlist: varspec
175 | varlist ',' varspec
176 ;
177 varspec: var
178 {
179 if (nvars >= H4_MAX_NC_VARS)
180 derror("too many variables");
181 nvdims = 0;
182 /* make sure variable not re-declared */
183 if ($1->is_var == 1) {
184 derror( "duplicate variable declaration for %s",
185 $1->name);
186 }
187 $1->is_var = 1;
188 $1->vnum = nvars;
189 vars[nvars].name = (char *) emalloc(strlen($1->name)+1);
190 (void) strcpy(vars[nvars].name, $1->name);
191 vars[nvars].type = type_code;
192 /* set default fill value. You can override this with
193 * the variable attribute "_FillValue". */
194 nc_getfill(type_code, &vars[nvars].fill_value);
195 vars[nvars].has_data = 0; /* has no data (yet) */
196 }
197 dimspec
198 {
199 vars[nvars].ndims = nvdims;
200 nvars++;
201 }
202 ;
203 var: IDENT
204 ;
205 dimspec: /* empty */
206 | '(' dimlist ')'
207 ;
208 dimlist: vdim
209 | dimlist ',' vdim
210 ;
211 vdim: dim
212 {
213 if (nvdims >= H4_MAX_VAR_DIMS) {
214 derror("%s has too many dimensions",vars[nvars].name);
215 }
216 if ($1->is_dim == 1)
217 dimnum = $1->dnum;
218 else {
219 derror( "%s is not declared as a dimension",
220 $1->name);
221 dimnum = ndims;
222 }
223 if (rec_dim != -1 && dimnum == rec_dim && nvdims != 0) {
224 derror("unlimited dimension must be first");
225 }
226 vars[nvars].dims[nvdims] = dimnum;
227 nvdims++;
228 }
229 ;
230 attdecl: att
231 {
232 valnum = 0;
233 valtype = NC_UNSPECIFIED;
234 /* get a large block for attributes, realloc later */
235 att_space = emalloc(H4_MAX_NC_ATTSIZE);
236 /* make all kinds of pointers point to it */
237 char_valp = (char *) att_space;
238 byte_valp = (char *) att_space;
239 short_valp = (short *) att_space;
240 long_valp = (nclong *) att_space;
241 float_valp = (float *) att_space;
242 double_valp = (double *) att_space;
243 }
244 '=' attvallist
245 {
246 if (natts >= H4_MAX_NC_ATTRS)
247 derror("too many attributes");
248 atts[natts].var = varnum ;
249 atts[natts].type = valtype;
250 atts[natts].len = valnum;
251 /* shrink space down to what was really needed */
252 att_space = erealloc(att_space, valnum*nctypelen(valtype));
253 atts[natts].val = att_space;
254 if (STREQ(atts[natts].name, _FillValue)) {
255 nc_putfill(atts[natts].type,
256 atts[natts].val,
257 &vars[atts[natts].var].fill_value);
258 }
259 natts++;
260 }
261 ;
262 att: avar ':' attr
263 | ':' attr
264 {
265 varnum = -1; /* handle of "global" attribute */
266 }
267 ;
268
269 avar: var
270 { if ($1->is_var == 1)
271 varnum = $1->vnum;
272 else {
273 derror("%s not declared as a variable, fatal error",
274 $1->name);
275 YYABORT;
276 }
277 }
278 ;
279 attr: IDENT
280 {
281 atts[natts].name = (char *) emalloc(strlen($1->name)+1);
282 (void) strcpy(atts[natts].name,$1->name);
283 }
284 ;
285 attvallist: aconst
286 | attvallist ',' aconst
287 ;
288 aconst: attconst
289 {
290 if (valtype == NC_UNSPECIFIED)
291 valtype = atype_code;
292 if (valtype != atype_code)
293 derror("values for attribute must be all of same type");
294 }
295 ;
296
297 attconst: CHAR_CONST
298 {
299 atype_code = NC_CHAR;
300 *char_valp++ = char_val;
301 valnum++;
302 }
303 | TERMSTRING
304 {
305 atype_code = NC_CHAR;
306 {
307 /* don't null-terminate attribute strings */
308 int len = strlen(termstring);
309 valnum += len;
310 (void)strncpy(char_valp,termstring,len);
311 char_valp += len;
312 }
313 }
314 | BYTE_CONST
315 {
316 atype_code = NC_BYTE;
317 *byte_valp++ = byte_val;
318 valnum++;
319 }
320 | SHORT_CONST
321 {
322 atype_code = NC_SHORT;
323 *short_valp++ = short_val;
324 valnum++;
325 }
326 | LONG_CONST
327 {
328 atype_code = NC_LONG;
329 *long_valp++ = long_val;
330 valnum++;
331 }
332 | FLOAT_CONST
333 {
334 atype_code = NC_FLOAT;
335 *float_valp++ = float_val;
336 valnum++;
337 }
338 | DOUBLE_CONST
339 {
340 atype_code = NC_DOUBLE;
341 *double_valp++ = double_val;
342 valnum++;
343 }
344 ;
345
346 datasection: /* empty */
347 | DATA datadecls
348 ;
349
350 datadecls: datadecl ';'
351 | datadecls datadecl ';'
352 ;
353 datadecl: avar
354 {
355 valtype = vars[varnum].type; /* variable type */
356 valnum = 0; /* values accumulated for variable */
357 vars[varnum].has_data = 1;
358 /* compute dimensions product (size of a "record") */
359 var_size = nctypelen(valtype);
360 if (vars[varnum].ndims == 0)
361 var_len = 1;
362 else if (vars[varnum].dims[0] == rec_dim) {
363 var_len = 1; /* one record for unlimited vars */
364 netcdf_record_number = 0;
365 }
366 else
367 var_len = dims[vars[varnum].dims[0]].size;
368 for(dimnum = 1; dimnum < vars[varnum].ndims; dimnum++)
369 var_len = var_len*dims[vars[varnum].dims[dimnum]].size;
370 /* allocate memory for a record of variable data */
371 if (var_len*var_size != (unsigned)(var_len*var_size)) {
372 derror("too much data for this machine");
373 exit(9);
374 }
375 rec_start = malloc ((unsigned)(var_len*var_size));
376 if (rec_start == 0) {
377 derror ("out of memory\n");
378 exit(3);
379 }
380 rec_cur = rec_start;
381 switch (valtype) {
382 case NC_CHAR:
383 char_valp = (char *) rec_start;
384 break;
385 case NC_BYTE:
386 byte_valp = (char *) rec_start;
387 break;
388 case NC_SHORT:
389 short_valp = (short *) rec_start;
390 break;
391 case NC_LONG:
392 long_valp = (nclong *) rec_start;
393 break;
394 case NC_FLOAT:
395 float_valp = (float *) rec_start;
396 break;
397 case NC_DOUBLE:
398 double_valp = (double *) rec_start;
399 break;
400 }
401 }
402 '=' constlist
403 {
404 if (valnum > 0 && valnum < var_len) { /* leftovers */
405 nc_fill(valtype,
406 var_len - valnum,
407 rec_cur,
408 vars[varnum].fill_value);
409 /* put out record of var_len values */
410 if (derror_count == 0)
411 put_variable(rec_start);
412 }
413 free ((char *) rec_start);
414 }
415 ;
416 constlist: dconst
417 | constlist ',' dconst
418 ;
419 dconst:
420 {
421 if(valnum >= var_len) {
422 derror("too many values for this variable");
423 exit (4);
424 }
425 not_a_string = 1;
426 }
427 const
428 {
429 if (not_a_string) {
430 switch (valtype) {
431 case NC_CHAR:
432 rec_cur = (void *) char_valp;
433 break;
434 case NC_BYTE:
435 rec_cur = (void *) byte_valp;
436 break;
437 case NC_SHORT:
438 rec_cur = (void *) short_valp;
439 break;
440 case NC_LONG:
441 rec_cur = (void *) long_valp;
442 break;
443 case NC_FLOAT:
444 rec_cur = (void *) float_valp;
445 break;
446 case NC_DOUBLE:
447 rec_cur = (void *) double_valp;
448 break;
449 }
450 }
451 if (valnum >= var_len) {
452 /* put out record of var_len elements */
453 if (derror_count == 0)
454 put_variable(rec_start);
455 /* if this variable is unbounded, reset for */
456 /* next record */
457 if (vars[varnum].dims[0] == rec_dim) {
458 valnum = 0;
459 netcdf_record_number++;
460 rec_cur = rec_start;
461 switch (valtype) {
462 case NC_CHAR:
463 char_valp = (char *) rec_start;
464 break;
465 case NC_BYTE:
466 byte_valp = (char *) rec_start;
467 break;
468 case NC_SHORT:
469 short_valp = (short *) rec_start;
470 break;
471 case NC_LONG:
472 long_valp = (nclong *) rec_start;
473 break;
474 case NC_FLOAT:
475 float_valp = (float *) rec_start;
476 break;
477 case NC_DOUBLE:
478 double_valp = (double *) rec_start;
479 break;
480 }
481 }
482 }
483 }
484 ;
485
486 const: CHAR_CONST
487 {
488 atype_code = NC_CHAR;
489 switch (valtype) {
490 case NC_CHAR:
491 *char_valp++ = char_val;
492 break;
493 case NC_BYTE:
494 *byte_valp++ = char_val;
495 break;
496 case NC_SHORT:
497 *short_valp++ = char_val;
498 break;
499 case NC_LONG:
500 *long_valp++ = char_val;
501 break;
502 case NC_FLOAT:
503 *float_valp++ = char_val;
504 break;
505 case NC_DOUBLE:
506 *double_valp++ = char_val;
507 break;
508 }
509 valnum++;
510 }
511 | TERMSTRING
512 {
513 not_a_string = 0;
514 atype_code = NC_CHAR;
515 {
516 int len = strlen(termstring);
517
518 valnum += len;
519 if(valnum > var_len) {
520 derror("string won't fit in this variable");
521 exit (5);
522 }
523 switch (valtype) {
524 case NC_CHAR:
525 (void)strncpy(char_valp,termstring,len);
526 char_valp += len;
527 rec_cur = (void *) char_valp;
528 break;
529 case NC_BYTE:
530 (void)strncpy(byte_valp,termstring,len);
531 byte_valp += len;
532 rec_cur = (void *) byte_valp;
533 break;
534 case NC_SHORT:
535 case NC_LONG:
536 case NC_FLOAT:
537 case NC_DOUBLE:
538 derror("string value invalid for %s variable",
539 nctype(valtype));
540 break;
541 }
542 }
543 }
544 | BYTE_CONST
545 {
546 atype_code = NC_BYTE;
547 switch (valtype) {
548 case NC_CHAR:
549 *char_valp++ = byte_val;
550 break;
551 case NC_BYTE:
552 *byte_valp++ = byte_val;
553 break;
554 case NC_SHORT:
555 *short_valp++ = byte_val;
556 break;
557 case NC_LONG:
558 *long_valp++ = byte_val;
559 break;
560 case NC_FLOAT:
561 *float_valp++ = byte_val;
562 break;
563 case NC_DOUBLE:
564 *double_valp++ = byte_val;
565 break;
566 }
567 valnum++;
568 }
569 | SHORT_CONST
570 {
571 atype_code = NC_SHORT;
572 switch (valtype) {
573 case NC_CHAR:
574 *char_valp++ = short_val;
575 break;
576 case NC_BYTE:
577 *byte_valp++ = short_val;
578 break;
579 case NC_SHORT:
580 *short_valp++ = short_val;
581 break;
582 case NC_LONG:
583 *long_valp++ = short_val;
584 break;
585 case NC_FLOAT:
586 *float_valp++ = short_val;
587 break;
588 case NC_DOUBLE:
589 *double_valp++ = short_val;
590 break;
591 }
592 valnum++;
593 }
594 | LONG_CONST
595 {
596 atype_code = NC_LONG;
597 switch (valtype) {
598 case NC_CHAR:
599 *char_valp++ = long_val;
600 break;
601 case NC_BYTE:
602 *byte_valp++ = long_val;
603 break;
604 case NC_SHORT:
605 *short_valp++ = long_val;
606 break;
607 case NC_LONG:
608 *long_valp++ = long_val;
609 break;
610 case NC_FLOAT:
611 *float_valp++ = long_val;
612 break;
613 case NC_DOUBLE:
614 *double_valp++ = long_val;
615 break;
616 }
617 valnum++;
618 }
619 | FLOAT_CONST
620 {
621 atype_code = NC_FLOAT;
622 switch (valtype) {
623 case NC_CHAR:
624 *char_valp++ = float_val;
625 break;
626 case NC_BYTE:
627 *byte_valp++ = float_val;
628 break;
629 case NC_SHORT:
630 *short_valp++ = float_val;
631 break;
632 case NC_LONG:
633 *long_valp++ = float_val;
634 break;
635 case NC_FLOAT:
636 *float_valp++ = float_val;
637 break;
638 case NC_DOUBLE:
639 *double_valp++ = float_val;
640 break;
641 }
642 valnum++;
643 }
644 | DOUBLE_CONST
645 {
646 atype_code = NC_DOUBLE;
647 switch (valtype) {
648 case NC_CHAR:
649 *char_valp++ = double_val;
650 break;
651 case NC_BYTE:
652 *byte_valp++ = double_val;
653 break;
654 case NC_SHORT:
655 *short_valp++ = double_val;
656 break;
657 case NC_LONG:
658 *long_valp++ = double_val;
659 break;
660 case NC_FLOAT:
661 if (double_val == FILL_DOUBLE)
662 *float_valp++ = FILL_FLOAT;
663 else
664 *float_valp++ = double_val;
665 break;
666 case NC_DOUBLE:
667 *double_valp++ = double_val;
668 break;
669 }
670 valnum++;
671 }
672 ;
673
674 /* END OF RULES */
675
676 %%
677
678 /* PROGRAMS */
679
680 /* get lexical input routine generated by lex */
681 #include "ncgenyy.c"
682
683 void derror();
684
yyerror(s)685 yyerror(s) /* called for yacc syntax error */
686 char *s;
687 {
688 derror(s);
689 }
690
691 #ifndef yywrap
692 int
yywrap()693 yywrap() /* returns 1 on EOF if no more input */
694 {
695 return 1;
696 }
697 #endif /* yywrap() */
698
699
700 /* Symbol table operations for ncgen tool */
701
lookup(sname)702 YYSTYPE lookup(sname) /* find sname in symbol table (linear search) */
703 char *sname;
704 {
705 YYSTYPE sp;
706 for (sp = symlist; sp != (YYSTYPE) 0; sp = sp -> next)
707 if (STREQ(sp -> name, sname)) {
708 return sp;
709 }
710 return 0; /* 0 ==> not found */
711 }
712
install(sname)713 YYSTYPE install(sname) /* install sname in symbol table */
714 char *sname;
715 {
716 YYSTYPE sp;
717
718 sp = (YYSTYPE) emalloc (sizeof (struct Symbol));
719 sp -> name = (char *) emalloc (strlen (sname) + 1);/* +1 for '\0' */
720 (void) strcpy (sp -> name, sname);
721 sp -> next = symlist; /* put at front of list */
722 sp -> is_dim = 0;
723 sp -> is_var = 0;
724 sp -> is_att = 0;
725 symlist = sp;
726 return sp;
727 }
728
729 void
clearout()730 clearout() /* reset symbol table to empty */
731 {
732 YYSTYPE sp, tp;
733 for (sp = symlist; sp != (YYSTYPE) 0;) {
734 tp = sp -> next;
735 free (sp -> name);
736 free ((char *) sp);
737 sp = tp;
738 }
739 symlist = 0;
740 }
741