File: codadef-expressions.html

package info (click to toggle)
coda 2.24.2-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 9,016 kB
  • sloc: ansic: 115,724; javascript: 6,732; java: 2,391; python: 1,691; yacc: 1,007; makefile: 598; lex: 204; sh: 99; fortran: 60; xml: 5
file content (935 lines) | stat: -rw-r--r-- 56,641 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
<?xml version="1.0" encoding="iso-8859-1" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">

<html>

  <head>
    <title>CODA Expressions</title>
    <link rel="stylesheet" href="../css/codadoc.css" type="text/css" />
  </head>

  <body>

    <div class="main">

      <h1>CODA Expressions</h1>

      <p>CODA comes with an advanced expression language that is able to perform calculations on product data. The expression language is primarilay used in the definitions of the product formats to formally describe how variable sizes, offsets, etc. are calculated. However, the expression language is also used within e.g. the codafind and codaeval tools to formulate queries on data products. The expression language provides a means to specify locations in a file, read values from a file and apply calculations on these values.</p>

      <p>The expression language is a basic language in ASCII format. In this document we will describe the language and provide a <a href="#bnf">formal definition</a> using the ISO/IEC 14977 EBNF (Extended Backus-Naur Form) format.</p>

      <p>The expression language knows 5 different types: <i>integer</i>, <i>float</i>, <i>string</i>, <i>boolean</i>, and <i>node</i>. <i>integer</i> and <i>float</i> represent integer and floating point values, <i>string</i> represents text data, <i>boolean</i> represents logical values (true/false), and <i>node</i> represents locations in a data file.</p>

      <p>When we talk about the 'type of an expression' we refer to the type of the value that will result from evaluating the expression. A float expression will thus result in a floating point value and a boolean expression in a true/false value.</p>

      <p>Expressions can range from being very simple (specifying just a constant value) to very complex (using various functions/operations to calculate the resulting value). An expression of one type can make use of sub-expressions of another type. For instance, a boolean expresssion can return the result of a comparison of two string expressions.</p>

      <p>In addition to expressions for each of the five data types there is also a sixth category of expressions, those that do not return any value. These expressions are referred to as <i>void</i> expressions (i.e. statements).</p>

      <p>The CODA expressions can thus be categorized in the following six groups:</p>

      <ul>
      <li><a href="#void">void expressions</a>: statements</li>
      <li><a href="#boolean">boolean expressions</a>: expressions that return either True or False</li>
      <li><a href="#integer">integer expressions</a>: expressions that return a numerical value</li>
      <li><a href="#float">float expressions</a>: expressions that return a floating point value</li>
      <li><a href="#string">string expressions</a>: expressions that return a character string</li>
      <li><a href="#node">node expressions</a>: expressions that refer to data in the product file</li>
      </ul>

      <p>It should be noted that the expression language allows arbitrary whitespace (in the form of space characters) between the components of an expression.</p>

      <h2 id="void">void expressions</h2>

      <p>void expressions are statements. They won't return a value and can only be used at the topmost level of an expression.</p>

      <h3>operators</h3>

      <p>There are two void operators. One is the sequence operator '<code>;</code>'. This operator is used to instruct the sequential execution of two or more statements. The other operator is the assignment operator '<code>=</code>', which is used to assign values to product variables.</p>

      <p>Example:</p>
      <div class="fragment"><code><i>$count</i>[0] = 100; <i>$count</i>[1] = 200; <i>$count</i>[2] = 300</code></div>
      <p>This will set the first three elements of the 1-dimensional product variable 'count' to 100, 200, and 300 respectively.</p>

      <p>Product variables can be either scalars or 1-dimensional arrays. The array subscript '<code>[]</code>' is only used for product variables that are arrays. For scalar product variables one should use e.g. '<code><i>$count</i> = 100</code>'.</p>

      <h3>functions</h3>
      
      <h5>for indexvar = integer to integer (step integer) do void</h5>

      <p>The <code>for</code> expression executes the void expression after '<code>do</code>' in a loop. The loop will terminate as soon as the index '<code>indexvar</code>' exceeds the value of the integer expression after '<code>to</code>'. The index '<code>indexvar</code>' can be any of three variables that can be used for keeping indices: <code><i>i</i></code>, <code><i>j</i></code>, or <code><i>k</i></code>. The step value is optional. The step may be negative, in which case the loop index will decrease with each step. The current value of the loop index can be used inside the void expression using the index integer expression '<code><i>i</i></code>', '<code><i>j</i></code>', or '<code><i>k</i></code>'.</p>

      <p>Example:</p>
      <div class="fragment"><code><b>for</b> <i>i</i> = 0 <b>to</b> 2 <b>do</b> <i>$count</i>[<i>i</i>] = 100 * <i>i</i></code></div>
      <p>This expression has the same effect as the example provided in the previous section.</p>

      <h2 id="boolean">boolean expressions</h2>

      <p>A boolean expression is an expression that results in a true or false value.</p>

      <h3>constant values</h3>

      <p>There are two possible constant values '<code>true</code>' and '<code>false</code>'.</p>

      <h3>operators</h3>

      <p>There are three logical operators that operate on boolean values: AND, OR, and NOT ('<code>&amp;&amp;</code>', '<code>||</code>', and '<code>!</code>'). Boolean expressions can be put between braces ( '<code>(</code>' and '<code>)</code>' ) in order to guide the evaluation order.</p>

      <p>The AND and OR expressions are lazy evaluated. This means that the second argument to AND will not be evaluated if the first argument already evaluated to false, and for OR similarly if the first argument already evaluated to true.</p>

      <p>Integer, float, and string expressions can be compared using the following relations: equality ('<code>==</code>'), inequality ('<code>!=</code>'), less than ('<code>&lt;</code>'), less than or equal ('<code>&lt;=</code>'), greater than ('<code>&gt;</code>'), or greater than or equal ('<code>&gt;=</code>'). The relative ordering of strings (to determine whether one string is larger than the other) will be based on the (unsigned) integer value of each byte character.</p>

      <p>Integers cannot be compared directly to floats. To compare a float value with an integer value, first convert the integer value to a float using the 'float()' function.</p>

      <h3>functions</h3>

      <h5>isnan(float)</h5>

      <p>Returns true if (and only if) the floating point value is NaN (the special 'Not a Number' value).</p>

      <h5>isinf(float)</h5>

      <p>Returns true if (and only if) the floating point value is +Inf or -Inf (minus or plus infinity).</p>

      <h5>ismininf(float)</h5>

      <p>Returns true if (and only if) the floating point value is -Inf (minus infinity).</p>

      <h5>isplusinf(float)</h5>

      <p>Returns true if (and only if) the floating point value is +Inf (plus infinity).</p>

      <h5>regex(string, string)</h5>

      <p>Matches a string against a regular expression pattern. The first parameter is the pattern and the second parameter is the string that it should match against.</p>

      <p>The function will return true if the pattern matches (and false otherwise).</p>

      <p>Note that if you want to use '\' characters in your pattern you should either provide the pattern as a 'raw string' (using the 'r' prefix) or use double escaping. For example, if you want to match for a "word" character (\w) you should either use 'r"\w"' or '"\\w"'</p>

      <p>The regular expression engine that is used is <a href="http://www.pcre.org/">PCRE</a>. Please refer to the manual of this software package for an overview of the syntax and options for constructing a pattern. Note that the version of PCRE that ships with CODA has been build using default options. The pattern is <i>compiled</i> with the <code>PCRE_DOTALL</code> and <code>PCRE_DOLLAR_ENDONLY</code> options.</p>

      <h5>exists(node)</h5>

      <p>With the '<code>exists</code>' function it is possible to check whether a path exists inside a product. This can be used to check the availability of optional available record fields or to just check whether a certain path exists at all. The function will only return true if it is possible to traverse the path and false otherwise.</p>

      <p>Example:</p>
      <div class="fragment"><code><b>if</b>(<b>exists</b>(/calibration), <b>int</b>(/calibration/num_values), 0)</code></div>
      <p>This will return the value of the num_values parameter if the calibration data set exists and 0 otherwise.</p>

      <h5>exists(node, boolean)</h5>

      <p>This function only works if node points to an array in the product. It will then walk the elements of the array (in ascending order) until it finds an element for which the boolean expression returns true, or, if none of the array elements match, will return false.</p>

      <p>Example:</p>
      <div class="fragment"><code><b>exists</b>(/calibration/value, <b>float</b>(.) &gt; 10.0)</code></div>
      <p>This will return true if any of the elements '/calibration/value[]' has a value > 10, and false otherwise.</p>

      <h5>all(node, boolean)</h5>

      <p>This function works just as the previous function, but will return false as soon as it finds an element for which the boolean expression returns false, or, if all elements match, will return true.</p>

      <p>Example:</p>
      <div class="fragment"><code><b>all</b>(/calibration/value, <b>float</b>(.) &gt; 10.0)</code></div>
      <p>This will return true if all of the elements '/calibration/value[]' have a value > 10, and false otherwise.</p>

      <h5>if(boolean, boolean, boolean)</h5>

      <p>If the first boolean expression argument evaluates to true the second argument is evaluated and its result returned, otherwise the third argument is evaluated and its result returned.</p>

      <h5>at(node, boolean)</h5>

      <p>Evaluate the boolean expression as provided in the second argument with the current node position moved according to the expression from the first argument. This function is recommended if evaluating the boolean expression requires multiple navigations to the same common node position.</p>

      <h5>with(indexvar = integer, boolean)</h5>

      <p>Evaluate the boolean expression as provided in the second argument while using the given <code>indexvar</code> (which can be either <code><i>i</i></code>, <code><i>j</i></code>, or <code><i>k</i></code>) as precalculated/cached value. This is useful if e.g. an expression needs to use an integer value from a product several times and you only want to read the value once.</p>

      <p>Example:</p>
      <div class="fragment"><code><b>with</b>(<i>k</i> = <b>int</b>(/data/intvalue), <i>k</i> &gt; 10 || <i>k</i> &lt; 0)</code></div>

      <p>This will be faster than using '<code><b>int</b>(/data/intvalue) &gt; 10 || <b>int</b>(/data/intvalue) &lt; 0</code>'.</p>

      <h2 id="integer">integer expressions</h2>

      <p>An integer expression is an expression that results in an integer value.</p>

      <p>All integer expressions are evaluated using a signed 64 bit integer.</p>

      <h3>constant values</h3>

      <p>Constants can be any integer number. However, it should be possible to represent the number by a 64 bit signed integer.</p>

      <h3>variables</h3>

      <p>There are two kinds of variables that can be used as integer expression: product variables and index variables. CODA only supports integer variables (i.e. variables can not contain boolean, floating point, or string data).</p>

      <p>Product variables can be seen as a caching mechanism for expression results. A product variable is a named scalar or a one-dimensional array that is attached to an open product. Note that product variables can only be referred to if they have been defined in the CODA product format definition for the open product file. The initialisation expression for a product variable is fixed and defined as part of the product format definition. Product variables are initialized the first time a value is requested from it (it will thus not impact the performance of opening a product file).<br />
      Product variables are referenced using a '<code>$</code>' character followed by the name of the product variable. If the product variable is an array then an additional (zero-based) array subscript should also be provided using '<code>[]</code>'. For example '<code>$foo</code>' will return the value of the scalar product variable 'foo' and '<code>$bar[10]</code>' will return the 11-th array element from the 1-dimensional product variable 'bar'.</p>

      <p>Inside a for loop or '<code>with</code>' function the current value of the loop/with index can be retrieved by using the corresponding '<code><i>i</i></code>', '<code><i>j</i></code>', or '<code><i>k</i></code>' expression. These are called index variables.</p>

      <h3>operators</h3>

      <p>The following operations are provided: addition ('<code>+</code>'), subtraction ('<code>-</code>'), multiplication ('<code>*</code>'), division ('<code>/</code>'), modulo ('<code>%</code>'), bitwise and ('<code>&amp;</code>'), and bitwise or ('<code>|</code>').</p>

      <p>A unary '<code>-</code>' before an integer expression can be used to turn the sign of an integer.</p>

      <p>Integer expressions can be put between braces ( '<code>(</code>' and '<code>)</code>' ) in order to guide the evaluation order.</p>

      <h3>functions</h3>

      <h5>int(bool)</h5>

      <p>Convert the boolean value to an integer value.</p>

      <p>This is equivalent to calling '<code><b>if</b>(bool, 1, 0)</code>'</p>

      <h5>int(node)</h5>

      <p>Reads the value at the node as an integer. If the node does not point to data that represents an integer value this will result in an error.</p>

      <p>When the integer is stored as an unsigned 64 bit integer the value is returned as a signed 64 bit integer by converting all values &gt;= 2^63 into negative values (e.g. 2^64 - 1 becomes -1). Integer values &gt;= 2^64 are not supported.</p>

      <h5>int(string)</h5>

      <p>Convert the string to an integer value.</p>

      <p>The rules for conversion are the same as for specifying a constant integer value in the expression language.</p>

      <h5>abs(integer)</h5>

      <p>Returns the absolute value of an integer as an integer.</p>

      <h5>max(integer, integer)</h5>

      <p>Returns the maximum of both integers.</p>

      <h5>max(node, integer)</h5>

      <p>This function only works if node points to an array in the product. It will then walk the elements of the array, evaluate the integer expression for each element and return the maximum of those results.</p>

      <h5>min(integer, integer)</h5>

      <p>Returns the minimum of both integers.</p>

      <h5>min(node, integer)</h5>

      <p>This function only works if node points to an array in the product. It will then walk the elements of the array, evaluate the integer expression for each element and return the minimum of those results.</p>

      <h5>dim(node, integer)</h5>

      <p>Will return the size of a specific dimension of the array at the given node.</p>

      <p>Example:</p>
      <div class="fragment"><code><b>numelements</b>(/calibration/value)==<b>dim</b>(/calibration/value, 0) * <b>dim</b>(/calibration/value, 1)</code></div>
      <p>This comparison should return true if '<code>/calibration/value</code>' is a two dimensional array.</p>

      <p>Note that the only CODA expression functions that deal with unflattened array dimensions are '<code>dim</code>' and '<code>num_dims</code>', all other operations treat arrays as flat arrays.</p>

      <h5>numdims(node)</h5>

      <p>Will return the number of dimensions of the array at the given node.</p>

      <p>Note that the only CODA expression functions that deal with unflattened array dimensions are '<code>dim</code>' and '<code>num_dims</code>', all other operations treat arrays as flat arrays.</p>

      <h5>numelements(node)</h5>

      <p>Will return the number of fields if the node points to a record or the number of array elements if the node points to an array. If the node points to a scalar the function will return 1.</p>

      <p>Example:</p>
      <div class="fragment"><code><b>numelements</b>(/calibration/value)==<b>int</b>(/calibration/num_values)</code></div>
      <p>This comparison should return true of the product is consistent.</p>

      <h5>count(node, boolean)</h5>

      <p>This function is similar to the <code><b>exists</b>(<i>node</i>, <i>boolean</i>)</code> function, but will return the total number of array elements for which the boolean expression evaluates to true.</p>

      <p>Example:</p>
      <div class="fragment"><code>100.0 * <b>float</b>(<b>count</b>(/calibration/value, <b>float</b>(.) > 10.0))) / <b>float</b>(<b>numelements</b>(/calibration/value))</code></div>
      <p>This calculates the percentage of values for which the value is larger than 10.</p>

      <h5>add(node, integer)</h5>

      <p>This function only works if node points to an array in the product. It will then walk the elements of the array, evaluate the integer expression for each element and return the sum of those results.</p>

      <p>Example:</p>
      <div class="fragment"><code><b>float</b>(<b>add</b>(/calibration/value, <b>int</b>(.))) / <b>float</b>(<b>numelements</b>(/calibration/value))</code></div>
      <p>This will calculate the average of the integer values in the value array.</p>

      <h5>length(string)</h5>

      <p>This function will return the length (number of characters) of the string argument.</p>

      <p>Example:</p>
      <div class="fragment"><code><b>length</b>("A String")==8</code></div>
      <p>This should always be true.</p>

      <h5>length(node)</h5>

      <p>This function only works if node points to string data. It will return the length (number of characters) of the string pointed to by the node.</p>

      <p>Example:</p>
      <div class="fragment"><code><b>length</b>(/some/data)==<b>length</b>(<b>str</b>(/some/data))</code></div>
      <p>This should always be true.</p>

      <h5>bitsize(node)</h5>

      <p>This function will return the bit size of the data item pointed to by '<code>node</code>'. If the bit size is not available (e.g. for HDF products) this function will return -1.</p>

      <h5>bytesize(node)</h5>

      <p>This function will return the byte size (rounded up) of the data item pointed to by '<code>node</code>'. If the byte size is not available (e.g. for HDF products) this function will return -1.</p>

      <h5>productversion()</h5>

      <p>This function will return the version number of the product format for the file. The version number is a CODA specific version number (the number can be found in the CODA product format definition documentation for the data file).</p>

      <h5>filesize()</h5>

      <p>This function will return the size of the file as a number of bytes.</p>

      <h5>bitoffset(node)</h5>

      <p>This function will return the bit offset of the data item pointed to by '<code>node</code>' relative to the start of the file. If the bit offset is not available (e.g. for HDF products) this function will return -1.</p>

      <h5>byteoffset(node)</h5>

      <p>This function will return the byte offset (rounded down) of the data item pointed to by '<code>node</code>' relative to the start of the file. If the byte offset is not available (e.g. for HDF products) this function will return -1.</p>

      <h5>index(node)</h5>

      <p>This function will return the 0-based index (field number or array element index) that was used to get from the parent node to the current node.</p>

      <p>Example:</p>
      <div class="fragment"><code><b>index</b>(/calibration/value[6])==6</code></div>
      <p>This should always be true.</p>

      <h5>index(node, boolean)</h5>

      <p>This function is similar to the <code><b>exists</b>(<i>node</i>, <i>boolean</i>)</code> function, but will return the 0-based array index of the first array element for which the boolean expression evaluates to true. If none of the array elements match, the function will return -1.</p>

      <h5>if(boolean, integer, integer)</h5>

      <p>If the boolean expression evaluates to true the second argument is evaluated and its result returned, otherwise the third argument is evaluated and its result returned.</p>

      <p>Example:</p>
      <div class="fragment"><code><b>if</b>(<b>float</b>(/calibration/value[0]) &lt; 0.0, -1, 1)</code></div>
      <p>This will return the sign of the first array element.</p>

      <h5>unboundindex(node, boolean)</h5>

      <p>This function has the same behavior as the <code><b>index</b>(<i>node</i>, <i>boolean</i>)</code> function, but it will not check for the array size. This function only has use for binary/ascii data where data outside the boundary can be reinterpreted as array elements this way. Since arrays are treated as unlimited arrays, you should be careful that the expression will not try to read beyond the boundary of the overall ascii/binary block of data (e.g. the size of the file). You can do this by providing an explicit termination condition (see <code><b>unboundindex(node, boolean, boolean)</b></code>) or by including a check of e.g. the <code>byteoffset</code> against the <code>filesize</code> in the boolean expression of the second argument.</p>

      <p>You should integrate the termination condition in the boolean expression of the second argument (and <i>not</i> provide an explicit termination condition as third argument) if you want the function to return the number of the last array element when the termination condition is reached.</p>

      <h5>unboundindex(node, boolean, boolean)</h5>

      <p>This function is similar to <code><b>unboundindex(node, boolean)</b></code>, but has an additional argument at the end to explicitly provide a termination condition.</p>

      <p>You should provide an explicit termination condition if you want the function to return -1 if no elements were found matching the boolean expression of the second argument.</p>

      <p>The function will, for each array element, always first evaluate the termination condition. Only if that evaluates to false will the boolean expression of the second argument be evaluated (otherwise the function will return -1).</p>

      <h5>at(node, integer)</h5>

      <p>Evaluate the integer expression as provided in the second argument with the current node position moved according to the expression from the first argument. This function is recommended if evaluating the integer expression requires multiple navigations to the same common node position.</p>

      <h5>with(indexvar = integer, integer)</h5>

      <p>Evaluate the integer expression as provided in the second argument while using the given <code>indexvar</code> (which can be either <code><i>i</i></code>, <code><i>j</i></code>, or <code><i>k</i></code>) as precalculated/cached value. This is useful if e.g. an expression needs to use an integer value from a product several times and you only want to read the value once.</p>

      <p>Example:</p>
      <div class="fragment"><code><b>with</b>(<i>k</i> = <b>int</b>(/data/intvalue), <b>if</b>(<i>k</i> &gt; 10, <i>k</i> + 10, <i>k</i> - 5))</code></div>

      <p>This will be faster than using '<code><b>if</b>(<b>int</b>(/data/intvalue) &gt; 10, <b>int</b>(/data/intvalue) + 10, <b>int</b>(/data/intvalue) - 5)</code>', since the value <code>/data/intvalue</code> will only be read once instead of 3 times.</p>

      <h2 id="float">float expressions</h2>

      <p>A float expression is an expression that results in a floating point value.</p>

      <p>All float expressions are evaluated using a IEE754 double precision floating point value.</p>

      <p>Any expression that expects a float expression as input will also except an integer expression. In these cases the resulting integer value will be silently cast to a floating point value (e.g. as if the <code>float(integer)</code> function was used).</p>

      <h3>constant values</h3>

      <p>Floating point constant values should have a '<code>.</code>' and/or an exponent. The exponent should start with either a '<code>D</code>' (fortran style) or '<code>E</code>' character (case insensitive). The special values '<code>nan</code>', and '<code>inf</code>' can be used to represent the IEEE754 special cases not-a-number and infinity.</p>

      <p>Examples:</p>

<div class="fragment"><code><pre>
1.0
.1
-1.
1.0E-20
-.09e99
.133000D+03
1e-6
nan
inf
-inf
+inf
</pre></code></div>

      <h3>operators</h3>

      <p>The following operations are provided: addition ('<code>+</code>'), subtraction ('<code>-</code>'), multiplication ('<code>*</code>'), division ('<code>/</code>'), modulo ('<code>%</code>'), and power ('<code>^</code>').</p>

      <p>A unary '<code>-</code>' before a float expression can be used to turn the sign of the value.</p>

      <p>Float expressions can be put between braces ( '<code>(</code>' and '<code>)</code>' ) in order to guide the evaluation order.</p>

      <h3>functions</h3>

      <h5>float(node)</h5>

      <p>Reads the value at the node as a floating point value. If the node does not point to data that represents an floating point or integer value this will result in an error.</p>

      <h5>float(integer)</h5>

      <p>Convert the integer to a floating point value.</p>

      <p>For large integer values this can result in a loss of precision.</p>

      <h5>float(string)</h5>

      <p>Convert the string to a floating point value.</p>

      <p>The rules for conversion are the same as for specifying a constant floating point value in the expression language.</p>

      <h5>abs(float)</h5>

      <p>Returns the absolute value of a floating point value as a floating point value.</p>

      <h5>ceil(float)</h5>

      <p>Returns the smallest integral value not less than the argument as a floating point value.</p>

      <h5>floor(float)</h5>

      <p>Returns the largest integral value not greater than the argument as a floating point value.</p>

      <h5>round(float)</h5>

      <p>Returns the floating point value, rounded to nearest integer (halfway away from zero).</p>

      <h5>max(float, float)</h5>

      <p>Returns the maximum of both floating point values.</p>

      <h5>max(node, float)</h5>

      <p>This function only works if node points to an array in the product. It will then walk the elements of the array, evaluate the floating point expression for each element and return the maximum of those results.</p>

      <h5>min(float, float)</h5>

      <p>Returns the minimum of both floating point values.</p>

      <h5>min(node, float)</h5>

      <p>This function only works if node points to an array in the product. It will then walk the elements of the array, evaluate the floating point expression for each element and return the minimum of those results.</p>

      <h5>time(string, string)</h5>

      <p>Returns a double value giving the amount of seconds since 2000-01-01T00:00:00.000000 for the date/time string value that is provided as the first argument and using the date/time format pattern that is provided by the second argument.</p>

      <p>An overview of the time format patterns is provided in the section <a href="#timeformat">date/time format patterns</a>.</p>

      <h5>add(node, float)</h5>

      <p>This function only works if node points to an array in the product. It will then walk the elements of the array, evaluate the float expression for each element and return the sum of those results.</p>

      <p>Example:</p>
      <div class="fragment"><code><b>float</b>(<b>add</b>(/calibration/value, <b>float</b>(.))) / <b>float</b>(<b>numelements</b>(/calibration/value))</code></div>
      <p>This will calculate the average of the floating point values in the value array.</p>

      <h5>if(boolean, float, float)</h5>

      <p>If the boolean expression evaluates to true the second argument is evaluated and its result returned, otherwise the third argument is evaluated and its result returned.</p>

      <h5>at(node, float)</h5>

      <p>Evaluate the float expression as provided in the second argument with the current node position moved according to the expression from the first argument. This function is recommended if evaluating the float expression requires multiple navigations to the same common node position.</p>

      <h5>with(indexvar = integer, float)</h5>

      <p>Evaluate the float expression as provided in the second argument while using the given <code>indexvar</code> (which can be either <code><i>i</i></code>, <code><i>j</i></code>, or <code><i>k</i></code>) as precalculated/cached value. This is useful if e.g. an expression needs to use an integer value from a product several times and you only want to read the value once.</p>

      <p>Example:</p>
      <div class="fragment"><code><b>with</b>(<i>k</i> = <b>int</b>(/data/intvalue), <b>if</b>(<i>k</i> &lt;= 0, 0.0, <b>if</b>(<i>k</i> &gt;= 100, 1.0, <i>k</i> / 100.0)))</code></div>

      <p>This will be faster than using '<code><b>if</b>(<b>int</b>(/data/intvalue) &lt;= 0, 0.0, <b>if</b>(<b>int</b>(/data/intvalue) &gt;= 100, 1.0, <b>int</b>(/data/intvalue) / 100.0))</code>'.</p>

      <h2 id="string">string expressions</h2>

      <p>A string expression is an expression that results in a character string.</p>

      <p>A string value is simply a sequence of bytes. No special character encoding interpretation is used and all byte values (0-255) are allowed for a character (e.g. no special string termination character is applied).</p>

      <h3>constant values</h3>

      <p>A string constant is provided by a sequence of printable ASCII characters between double quote characters. The double quote character itself or any characters that are not ASCII printable characters can be included in string constants by using an escape sequence. An escape sequence is a '\' followed by either a character or by a 3 digit octal number of the byte value (for instance, '\060' is equal to 'A'). The following table lists the possible escape sequences that are allowed:</p>

      <table class="fancy" width="60%">
        <tr><th>Escape sequence</th><th>ASCII Character</th><th>Decimal code</th></tr>
        <tr><td align="center">\a</td><td>Bell</td><td align="right">7</td></tr>
        <tr><td align="center">\b</td><td>Backspace</td><td align="right">8</td></tr>
        <tr><td align="center">\t</td><td>Tab</td><td align="right">9</td></tr>
        <tr><td align="center">\n</td><td>Linefeed</td><td align="right">10</td></tr>
        <tr><td align="center">\v</td><td>Vertical tab</td><td align="right">11</td></tr>
        <tr><td align="center">\f</td><td>Formfeed</td><td align="right">12</td></tr>
        <tr><td align="center">\r</td><td>Carriage return</td><td align="right">13</td></tr>
        <tr><td align="center">\"</td><td>"</td><td align="right">34</td></tr>
        <tr><td align="center">\'</td><td>'</td><td align="right">39</td></tr>
        <tr><td align="center">\\</td><td>\</td><td align="right">92</td></tr>
        <tr><td align="center">\nnn</td><td>A byte value equal to the octal number 'nnn'</td><td align="right">&nbsp;</td></tr>
      </table>

      <p>Examples:</p>

<div class="fragment"><code><pre>
"Hello World!"
""
"Line 1\nLine 2\n"
"A string with a \000 character"
"How to quote a '\"'?"
</pre></code></div>

      <p>By default all escaped characters are interpreted and turned into their single character equivalents. However, if you precede a string constant by the letter 'r' this translation will not be performed and you will get the raw string value. For instance, '"abc \\ \" "' will be translated to 'abc \ " ', whereas 'r"abc \\ \" "' will remain as 'abc \\ \" '.</p>

      <h3>operators</h3>

      <p>Strings can be concatenated using the '<code>+</code>' operator.</p>

      <h3>functions</h3>

      <h5>str(integer)</h5>

      <p>Convert the integer value into a string value (using decimal notation).</p>

      <h5>str(node)</h5>

      <p>Reads the string value for the data element pointed to by the node parameter.</p>

      <h5>str(node, integer)</h5>

      <p>Similar to the previous function, but now limit the read to a maximum number of bytes as indicated by the second argument. Note that the length of the returned string may be less than the provided maximum if the length of the data in the product is less than the indicated maximum.</p>

      <h5>bytes(node)</h5>

      <p>Reads the data element pointed to by the node parameter as a raw byte array. This function differs from <code><b>str</b>(node)</code> because it is not restricted to reading text data, but can be used independent of the type of data at the node position, as long as the data is stored in an 'ascii' or 'binary' formatted product (e.g. it can be used to read a binary record).</p>

      <h5>bytes(node, integer)</h5>

      <p>Similar to the previous function, but now explicitly set the number of bytes that should be read (as indicated by the second argument). The function will always read the given number of bytes, even if this exceeds the length of the data item at the node position. If the number of bytes from the node position till the end of the file is less than the provided maximum, CODA will return an error.</p>

      <h5>bytes(node, integer, integer)</h5>

      <p>Similar to the previous function, but now explicitly set both the byte offset relative to the node (as second argument) and the number of bytes that should be read (as third argument). Both the offset and number of bytes may exceed the range of the data at the given node. This means that the offset can be negative and/or the offset+length may exceed that of the data item at the node position. If the range exceeds the boundaries of the file (e.g. global offset is negative or offset+length exceeds the file length), CODA will return an error.</p>

      <h5>substr(integer, integer, string)</h5>

      <p>Return a substring of the third argument, where the first argument indicates the 0-based offset and the second argument the length. The values for both the offset and length arguments should be greater or equal to 0 and the sum of the offset and length parameters should not exceed the string length of the third argument.</p>

      <p>Example:</p>
      <div class="fragment"><code>"bcd" == <b>substr</b>(1, 3, "abcdef")</code></div>
      <p>This should always be true.</p>

      <h5>ltrim(string)</h5>

      <p>Return the string with all white space characters removed from the left (=start of string).</p>

      <p>The following characters are considered white space: space, tab, newline, carriage return.</p>

      <h5>rtrim(string)</h5>

      <p>Return the string with all white space characters removed from the right (=end of string).</p>

      <p>The following characters are considered white space: space, tab, newline, carriage return.</p>

      <h5>trim(string)</h5>

      <p>Return the string with all white space characters removed from the left and right (=beginning and end of string).</p>

      <p>The following characters are considered white space: space, tab, newline, carriage return.</p>

      <h5>add(node, string)</h5>

      <p>This function only works if node points to an array in the product. It will then walk the elements of the array (in ascending order), evaluate the string expression for each element and return the concatenated string of the results.</p>

      <h5>max(string, string)</h5>

      <p>Returns the maximum of both string values.</p>

      <h5>max(node, string)</h5>

      <p>This function only works if node points to an array in the product. It will then walk the elements of the array, evaluate the string expression for each element and return the maximum of those results.</p>

      <h5>min(string, string)</h5>

      <p>Returns the minimum of both string values.</p>

      <h5>min(node, string)</h5>

      <p>This function only works if node points to an array in the product. It will then walk the elements of the array, evaluate the string expression for each element and return the minimum of those results.</p>

      <h5>regex(string, string, integer)</h5>

      <p>Matches a string against a regular expression pattern. The first parameter is the pattern, the second parameter is the string that it should match against and the third parameter is the index of the substring whos value should be returned.</p>

      <p>Note that an index value of 0 will give the full match of the pattern, and indices 1..n are the indices for the substrings.</p>

      <p>If no match for the specified substring was found an empty string will be returned.</p>

      <p>The regular expression engine that is used is <a href="http://www.pcre.org/">PCRE</a>. Please refer to the manual of this software package for an overview of the syntax and options for constructing a pattern and for an explanation of the concept of 'substrings'. Note that the version of PCRE that ships with CODA has been build using default options. The pattern is <i>compiled</i> with the <code>PCRE_DOTALL</code> and <code>PCRE_DOLLAR_ENDONLY</code> options.</p>

      <p>For example, <code>regex(r"a+(\d+)", "aaa1234aaa", 0)</code> will return <code>"aaa1234"</code> and <code>regex(r"a+(\d+)", "aaa1234aaa", 1)</code> will return <code>"1234"</code>.</p>

      <h5>regex(string, string, string)</h5>

      <p>Matches a string against a regular expression pattern. The first parameter is the pattern, the second parameter is the string that it should match against and the third parameter is the name of the substring whos value should be returned.</p>

      <p>If no match for the specified substring was found an empty string will be returned.</p>

      <p>The regular expression engine that is used is <a href="http://www.pcre.org/">PCRE</a>. Please refer to the manual of this software package for an overview of the syntax and options for constructing a pattern and for an explanation of the concept of 'substrings'. Note that the version of PCRE that ships with CODA has been build using default options. The pattern is <i>compiled</i> with the <code>PCRE_DOTALL</code> and <code>PCRE_DOLLAR_ENDONLY</code> options.</p>

      <p>For example, <code>regex(r"a+(?'foo'\d+)", "aaa1234aaa", "foo")</code> will return <code>"1234"</code>.</p>

      <h5>productformat()</h5>

      <p>Returns the name of the underlying format (e.g. 'binary', 'xml', 'hdf5') of the file. A file that can be opened by CODA will always have an associated product format.</p>

      <h5>productclass()</h5>

      <p>Returns the name of the productclass of the file. If the file does not have a productclass an empty string will be returned.</p>

      <h5>producttype()</h5>

      <p>Returns the name of the productype of the file. If the file does not have a producttype an empty string will be returned.</p>

      <h5>filename()</h5>

      <p>Returns the filename (<i>not</i> including directory path components, but including the file extension) as a string.</p>

      <h5>strtime(float)</h5>

      <p>Returns a string representation of the time value, interpreted as seconds since 2000-01-01T00:00:00.000000, using the date/time format "yyyy-MM-dd'T'HH:mm:ss.SSSSSS".</p>

      <h5>strtime(float, string)</h5>

      <p>Returns a string representation of the time value, interpreted as seconds since 2000-01-01T00:00:00.000000, using the date/time format as provided by the second argument.</p>

      <p>An overview of the time format patterns is provided in the section <a href="#timeformat">date/time format patterns</a>.</p>

      <h5>if(boolean, string, string)</h5>

      <p>If the boolean expression evaluates to true the second argument is evaluated and its result returned, otherwise the third argument is evaluated and its result returned.</p>

      <h5>at(node, string)</h5>

      <p>Evaluate the string expression as provided in the second argument with the current node position moved according to the expression from the first argument. This function is recommended if evaluating the string expression requires multiple navigations to the same common node position.</p>

      <p>Example:</p>
      <div class="fragment"><code><b>at</b>(/some/data, <b>with</b>(<i>k</i> = <b>length</b>(.), <b>substr</b>(<i>k</i> / 2, <i>k</i> - (<i>k</i> / 2), <b>str</b>(.))))</code></div>

      <p>This will be faster than using '<code><b>with</b>(<i>k</i> = <b>length</b>(/some/data), <b>substr</b>(<i>k</i> / 2, <i>k</i> - (<i>k</i> / 2), <b>str</b>(/some/data)))</code>'.</p>

      <h5>with(indexvar = integer, string)</h5>

      <p>Evaluate the string expression as provided in the second argument while using the given <code>indexvar</code> (which can be either <code><i>i</i></code>, <code><i>j</i></code>, or <code><i>k</i></code>) as precalculated/cached value. This is useful if e.g. an expression needs to use an integer value from a product several times and you only want to read the value once.</p>

      <p>Example:</p>
      <div class="fragment"><code><b>with</b>(<i>k</i> = <b>length</b>(/some/data), <b>substr</b>(<i>k</i> / 2, <i>k</i> - (<i>k</i> / 2), <b>str</b>(/some/data)))</code></div>

      <p>This will be faster than using '<code><b>substr</b>(<b>length</b>(/some/data) / 2, <b>length</b>(/some/data) - (<b>length</b>(/some/data) / 2), <b>str</b>(/some/data))</code>'.</p>

      <h2 id="node">node expressions</h2>

      <p>A node describes a path into a product file similar to XPath for XML.</p>

      <p>How to construct a path (i.e. which identifiers to use) depends entirely on the format of the data product. The basis is that a product is composed of compound elements that can be traversed using identifiers (i.e. fields in a record) or using indices (i.e. elements of an array).</p>

      <p>Within CODA the format of field names is restricted to identifiers, which means that the first character should be a-z or A-Z and all subsequent characters should be a-z, A-Z, 0-9, or _. Instead of specifying a field name, it is also possible to provide a zero-based index of the field between '{', '}'. So '<code>/first_field</code>' and '<code>/{0}</code>' are equivalent.</p>

      <p>Array indices are 0-based indices on the flattened view of an array. This means that if an array is defined as having more than one dimension the index as used in a node expression should be between 0 and the total number of array elements (exclusive). For example, for a [10,8] array, the index should be &gt;= 0 and &lt;= 79. The CODA product format definition document will always show the dimension order in such a way that the last dimension is the fastest running dimension.</p>

      <p>A node can be specified as a relative or absolute path. An absolute path starts at the root of the product and the expression starts with either '<code>/</code>', '<code>[</code>' (start of a top-level index reference), or '<code>@</code>' (start of a top-level attribute reference). Relative paths start with either '<code>.</code>', '<code>..</code>', or '<code>:</code>'. When a node starts with '<code>..</code>' this is just a shorthand for '<code>./..</code>', which refers to the parent node of the current node. The relative paths '<code>.</code>' and '<code>:</code>' both refer to the current node position but with a slightly different meaning. The '<code>:</code>' node will always refer to the node with which the evaluation was started, whereas the location of '<code>.</code>' will depend on where the expression is used (for instance, if '<code>.</code>' is used within the evaluation of the second argument of a '<code>count(node, boolean)</code>' expression it will refer to the array element in '<code>node</code>' that is being evaluated). The node position with which the evaluation is started is either equal to the node to which the expression is attached or, if the expression is not attached to a specific product parameter, it is the root of the product.</p>

      <p>There is a special node expression '<code>asciiline</code>' that can only be used in expressions for product format definitions for ASCII products. The '<code>asciiline</code>' expression can only be used as start point of a node expression and will map the view of a file to an array of strings where each string corresponds with a single line (including end of line character(s)) of the ascii file. For example the expression <code><b>bitoffset</b>(<b>asciiline</b>[<b>index</b>(<b>asciiline</b>, <b>str</b>(., 1) != "#")])</code> will give the bitoffset in the file of the first line that does not start with a '#' character.</p>

      <h2 id="timeformat">date/time format patterns</h2>

      <p>For parsing and printing date/time values in textual format, CODA uses a pattern description that is largely based on the Unicode Technical Standard #35 regarding Date Format Patterns. Note that only a very specific subset of patterns are supported and that the pattern for the abbreviated month deviates from the standard.</p>

      <p>In a date/time format pattern certain character series have special meaning and correspond to the various components of a date/time value. Characters that need to be matched literally can be included between two single quote characters ('). Any alphabetical character that is to be treated literally <i>has</i> to be included between quotes. This includes the special characters '|' and '*'. Other characters may be included between quotes (but don't have to). Two single quotes represents a literal single quote, either inside or outside single quotes.</p>

      <p>To provide a list of multiple patterns that are tried in sequence until one succeeds, provide the list of patterns separated by '|' (vertical bar) characters in a single format string. When converting a time value to a string, the first pattern of a list will be used for the conversion.</p>

      <p>A pattern for a date/time component can have a '*' appended to the format to indicate that it should use leading spaces instead of leading zeros (both for parsing and for printing).</p>

      <p>The table below provides an overview of the patterns that are supported in CODA for date/time formats:</p>

      <table class="fancy" width="60%">
        <tr><th>Pattern</th><th>Description</th></tr>
        <tr><td>yyyy</td><td>4-digit year value [0001..9999]</td></tr>
        <tr><td>MM</td><td>2-digit month value [01..12]</td></tr>
        <tr><td>MMM</td><td>3-character abbreviation of the month: "JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC".<br />Lower-case versions of these strings are also accepted when parsing.</td></tr>
        <tr><td>dd</td><td>2-digit day of month value [01..31]</td></tr>
        <tr><td>DDD</td><td>3-digit day of year value [001..366]</td></tr>
        <tr><td>HH</td><td>2-digit hour of day value [00..23]</td></tr>
        <tr><td>mm</td><td>2-digit minute of hour value [00..59]</td></tr>
        <tr><td>ss</td><td>2-digit second of minute value [00..60]<br />Note that a possible leap second value is supported in a string value, but it is not taken into account in a conversion (i.e. it is treated as '00' of the next minute) unless explicitly specified otherwise.</td></tr>
        <tr><td>S<br />SS<br />SSS<br />...<td>n-digit fraction of a second.<br />A 3-digit fraction would represent milliseconds and a 6-digit fraction would represent microseconds.<br />Values will be printed truncated (i.e. 12.159 seconds with format ss.SS will be printed as 12.15). Any digits beyond the 6th digit will be ignored when parsing (i.e. values will always be truncated at microsecond resolution).</td></tr>
      </table>

      <p>Several examples of formats and their string values for the date 4 July 2012 19:32:56.123456:</p>
      <ul>
      <li>"yyyy-MM-dd" : "2012-07-04"</li>
      <li>"yyyy MM* dd*" : "2012  7  4"</li>
      <li>"yyyy-MM-dd'T'HH:mm:ss" : "2012-07-04T19:32:56"</li>
      <li>"dd-MMM-yyyy HH:mm:ss.SSSSSS" : "04-JUL-2012 19:32:56.123456"</li>
      <li>"yyyy DDD" : "2012 186"</li>
      </ul>

      <h2 id="bnf">formal definition</h2>

      <p><pre>
alpha =
    'a'|'b'|'c'|'d'|'e'|'f'|'g'|'h'|'i'|'j'|'k'|'l'|'m'|
    'n'|'o'|'p'|'q'|'r'|'s'|'t'|'u'|'v'|'w'|'x'|'y'|'z'|
    'A'|'B'|'C'|'D'|'E'|'F'|'G'|'H'|'I'|'J'|'K'|'L'|'M'|
    'N'|'O'|'P'|'Q'|'R'|'S'|'T'|'U'|'V'|'W'|'X'|'Y'|'Z' ;

character = alpha | digit |
    ' '|'!'|'"'|'#'|'$'|'%'|'&amp;'|"'"|'('|')'|'*'|'+'|','|
    '-'|'.'|'/'|':'|';'|'&lt;'|'='|'&gt;'|'?'|'@'|'['|'\'|']'|
    '^'|'_'|'`'|'{'|'|'|'}'|'~' ;

identifier = alpha, [{alpha | digit | '_'}] ;

indexvar = 'i'|'j'|'k'

digit = '0'|'1'|'2'|'3'|'4'|'5'|'6'|'7'|'8'|'9' ;
sign = '+'|'-' ;

intvalue = {digit} ;

floatvalue = (intvalue, '.', [intvalue] | '.', intvalue), [('E' | 'e' | 'D' | 'd'), [sign], intvalue] ;

stringvalue = '"', [{character-('\', '"') | '\' character}], '"' ;

voidexpr =
    '$' identifier '=' intexpr |
    '$' identifier '[' intexpr ']' '=' intexpr |
    voidexpr ';' voidexpr |
    'for' indexvar '=' intexpr 'to' intexpr 'do' voidexpr |
    'for' indexvar '=' intexpr 'to' intexpr 'step' intexpr 'do' voidexpr |
    'for' indexvar '=' intexpr 'to' intexpr 'step' intexpr 'do' voidexpr |
    'goto' '(' node ')' |
    'with', '(', indexvar, '=', intexpr, ',', voidexpr, ')' ;

boolexpr =
    'true' |
    'false' |
    boolexpr, '&amp;&amp;', boolexpr |
    boolexpr, '||', boolexpr |
    '!', boolexpr |
    intexpr, '==', intexpr |
    intexpr, '!=', intexpr |
    intexpr, '&gt;', intexpr |
    intexpr, '&gt;=', intexpr |
    intexpr, '&lt;', intexpr |
    intexpr, '&lt;=', intexpr |
    floatexpr, '==', floatexpr |
    floatexpr, '==', intexpr |
    intexpr, '==', floatexpr |
    floatexpr, '!=', floatexpr |
    floatexpr, '!=', intexpr |
    intexpr, '!=', floatexpr |
    floatexpr, '&gt;', floatexpr |
    floatexpr, '&gt;', intexpr |
    intexpr, '&gt;', floatexpr |
    floatexpr, '&gt;=', floatexpr |
    floatexpr, '&gt;=', intexpr |
    intexpr, '&gt;=', floatexpr |
    floatexpr, '&lt;', floatexpr |
    floatexpr, '&lt;', intexpr |
    intexpr, '&lt;', floatexpr |
    floatexpr, '&lt;=', floatexpr |
    floatexpr, '&lt;=', intexpr |
    intexpr, '&lt;=', floatexpr |
    stringexpr, '==', stringexpr |
    stringexpr, '!=', stringexpr |
    stringexpr, '&gt;', stringexpr |
    stringexpr, '&gt;=', stringexpr |
    stringexpr, '&lt;', stringexpr |
    stringexpr, '&lt;=', stringexpr |
    '(', boolexpr, ')' |
    'regex', '(', stringexpr, ',', stringexpr ')' |
    'exists', '(', node, ')' |
    'exists', '(', node, ',', boolexpr, ')' |
    'all', '(', node, ',', boolexpr, ')' |
    'if', '(' boolexpr, ',', boolexpr, ',', boolexpr, ')' |
    'with', '(', indexvar, '=', intexpr, ',', boolexpr, ')' ;

intexpr = 
    intvalue |
    'int', '(', intexpr, ')' |
    'int', '(', boolexpr, ')' |
    'int', '(', node, ')' |
    'int', '(', stringexpr, ')' |
    '$', identifier |
    '$', identifier, '[', intexpr, ']' |
    indexvar |
    '-', intexpr |
    '+', intexpr |
    intexpr, '+', intexpr |
    intexpr, '-', intexpr |
    intexpr, '*', intexpr |
    intexpr, '/', intexpr |
    intexpr, '%', intexpr |
    intexpr, '&amp;', intexpr |
    intexpr, '|', intexpr |
    '(', intexpr, ')' |
    'abs', '(', intexpr, ')' |
    'max', '(', node, ',', intexpr, ')' |
    'max', '(', intexpr, ',', intexpr, ')' |
    'min', '(', node, ',', intexpr, ')' |
    'min', '(', intexpr, ',', intexpr, ')' |
    'dim', '(', node, ',', intexpr ')' |
    'numdims', '(', node, ')' |
    'numelements', '(', node, ')' |
    'count', '(' node, ',', boolexpr, ')' |
    'add', '(' node, ',', intexpr, ')' |
    'length', '(', stringexpr, ')' |
    'length', '(', node, ')' |
    'bitsize', '(', node, ')' |
    'bytesize', '(', node, ')' |
    'productversion', '(', ')' |
    'filesize', '(', ')' |
    'bitoffset', '(', node, ')' |
    'byteoffset', '(', node, ')' |
    'index', '(', node, ')' |
    'index', '(', node, ',', boolexpr, ')' |
    'if', '(', boolexpr, ',', intexpr, ',' intexpr, ')' |
    'unboundindex', '(', node, ',', boolexpr, ')' |
    'unboundindex', '(', node, ',', boolexpr, ',', boolexpr, ')' |
    'at', '(', node, ',', intexpr, ')' |
    'with', '(', indexvar, '=', intexpr, ',', intexpr, ')' ;

floatexpr = 
    floatvalue |
    'nan' |
    'inf' |
    'float', '(', floatexpr, ')' |
    'float', '(', node, ')' |
    'float', '(', intexpr, ')' |
    'float', '(', stringexpr, ')' |
    '-', floatexpr |
    '+', floatexpr |
    floatexpr, '+', floatexpr |
    floatexpr, '+', intexpr |
    intexpr, '+', floatexpr |
    floatexpr, '-', floatexpr |
    floatexpr, '-', intexpr |
    intexpr, '-', floatexpr |
    floatexpr, '*', floatexpr |
    floatexpr, '*', intexpr |
    intexpr, '*', floatexpr |
    floatexpr, '/', floatexpr |
    floatexpr, '/', intexpr |
    intexpr, '/', floatexpr |
    floatexpr, '%', floatexpr |
    floatexpr, '%', intexpr |
    intexpr, '%', floatexpr |
    floatexpr, '^', floatexpr |
    floatexpr, '^', intexpr |
    intexpr, '^', floatexpr |
    intexpr, '^', intexpr |
    '(', floatexpr, ')' |
    'abs', '(', floatexpr, ')' |
    'ceil', '(', floatexpr, ')' |
    'floor', '(', floatexpr, ')' |
    'round', '(', floatexpr, ')' |
    'max', '(', node, ',', floatexpr, ')' |
    'max', '(', floatexpr, ',', floatexpr, ')' |
    'max', '(', floatexpr, ',', intexpr, ')' |
    'max', '(', intexpr, ',', floatexpr, ')' |
    'min', '(', node, ',', floatexpr, ')' |
    'min', '(', floatexpr, ',', floatexpr, ')' |
    'min', '(', floatexpr, ',', intexpr, ')' |
    'min', '(', intexpr, ',', floatexpr, ')' |
    'time', '(', stringepxr, ',', stringexpr, ')' |
    'add', '(' node, ',', floatexpr, ')' |
    'if', '(' boolexpr, ',', floatexpr, ',', floatexpr, ')' |
    'if', '(' boolexpr, ',', floatexpr, ',', intexpr, ')' |
    'if', '(' boolexpr, ',', intexpr, ',', floatexpr, ')' |
    'with', '(', indexvar, '=', intexpr, ',', floatexpr, ')' ;

stringexpr = 
    stringvalue |
    'r', stringvalue |
    'str', '(', stringexpr, ')' |
    'str', '(', node, ')' |
    'str', '(', node, ',', intexpr, ')' |
    'bytes', '(', node, ')' |
    'bytes', '(', node, ',', intexpr, ')' |
    'bytes', '(', node, ',', intexpr, ',', intexpr, ')' |
    stringexpr, '+', stringexpr |
    'substr', '(', intexpr, ',', intexpr, ',', stringexpr, ')' |
    'ltrim', '(', stringexpr, ')' |
    'rtrim', '(', stringexpr, ')' |
    'trim', '(', stringexpr, ')' |
    'add', '(', node, ',', stringexpr, ')' |
    'max', '(', node, ',', stringexpr, ')' |
    'max', '(', stringexpr, ',', stringexpr, ')' |
    'min', '(', node, ',', stringexpr, ')' |
    'min', '(', stringexpr, ',', stringexpr, ')' |
    'regex', '(', stringexpr, ',', stringexpr, ',', intexpr ')' |
    'regex', '(', stringexpr, ',', stringexpr, ',', stringexpr ')' |
    'productformat', '(', ')' |
    'productclass', '(', ')' |
    'producttype', '(', ')' |
    'filename', '(', ')' |
    'strtime', '(', intexpr, ')' |
    'strtime', '(', floatexpr, ')' |
    'strtime', '(', intexpr, ',', stringexpr ')' |
    'strtime', '(', floatexpr, ',', stringexpr ')' |
    'if', '(' boolexpr, ',', stringexpr, ',', stringexpr, ')' |
    'with', '(', indexvar, '=', intexpr, ',', stringexpr, ')' ;

rootnode = '/'

nonrootnode =
    '.' |
    ':' |
    '..' |
    'asciiline' |
    rootnode, identifier |
    rootnode, '{', intexpr, '}' |
    nonrootnode, '/..' |
    nonrootnode, '/', identifier |
    nonrootnode, '/', '{', intexpr, '}' |
    '[', intexpr, ']' |
    node, '[', intexpr, ']' |
    '@', identifier |
    '@', '{', intexpr, '}' |
    node, '@', identifier |
    node, '@', '{', intexpr, '}' ;

node =
    rootnode |
    nonrootnode ;
</pre></p>

      <div class="footer">
        <hr />
        <p>Copyright &copy; 2007-2022 <b>s<span class="soft-red">[</span>&amp;<span class="soft-red">]</span>t</b>, The Netherlands.</p>
      </div>

    </div>

  </body>

</html>