1 /*============================================================================
2 WCSLIB 7.7 - an implementation of the FITS WCS standard.
3 Copyright (C) 1995-2021, Mark Calabretta
4
5 This file is part of WCSLIB.
6
7 WCSLIB is free software: you can redistribute it and/or modify it under the
8 terms of the GNU Lesser General Public License as published by the Free
9 Software Foundation, either version 3 of the License, or (at your option)
10 any later version.
11
12 WCSLIB is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
15 more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with WCSLIB. If not, see http://www.gnu.org/licenses.
19
20 Author: Mark Calabretta, Australia Telescope National Facility, CSIRO.
21 http://www.atnf.csiro.au/people/Mark.Calabretta
22 $Id: wcsulex.l,v 7.7 2021/07/12 06:36:49 mcalabre Exp $
23 *=============================================================================
24 *
25 * wcsulex.l is a Flex description file containing the definition of a
26 * recursive, multi-buffered lexical scanner and parser for FITS units
27 * specifications.
28 *
29 * It requires Flex v2.5.4 or later.
30 *
31 * Refer to wcsunits.h for a description of the user interface and operating
32 * notes.
33 *
34 *===========================================================================*/
35
36 /* Options. */
37 %option full
38 %option never-interactive
39 %option noinput
40 %option noyywrap
41 %option outfile="wcsulex.c"
42 %option prefix="wcsulex"
43 %option reentrant
44 %option extra-type="struct wcsulex_extra *"
45
46 /* Exponents. */
47 INTEGER [+-]?[1-9][0-9]*
48 FRAC {INTEGER}"/"[1-9][0-9]*
49 FLOAT [+-]?([0-9]+\.?[0-9]*|\.[0-9]+)
50
51 /* Metric prefixes. */
52 SUB3 [munpfazy]
53 SUBPREFIX [dc]|{SUB3}
54 SUP3 [kMGTPEZY]
55 SUPPREFIX da|h|{SUP3}
56 PREFIX {SUBPREFIX}|{SUPPREFIX}
57
58 /* Basic and derived SI units. */
59 BASIC m|s|g|rad|sr|K|A|mol|cd
60 DERIVED Hz|J|W|V|N|Pa|C|[Oo]hm|S|F|Wb|T|H|lm|lx
61 SI_UNIT {BASIC}|{DERIVED}
62
63 /* Additional recognized units: all metric prefixes allowed. */
64 ADD_ALL eV|Jy|R|G|barn
65
66 /* Additional recognized units: only super-metric prefixes allowed. */
67 ADD_SUP a|yr|pc|bit|[bB]yte
68
69 /* Additional recognized units: only sub-metric prefixes allowed. */
70 ADD_SUB mag
71
72 /* Additional recognized units for which NO metric prefixes are allowed. */
73 GENERAL deg|arcmin|arcsec|mas|turn|min|h|d|cy|erg|Ry|u|D
74 ASTRO [Aa]ngstrom|AU|lyr|beam|solRad|solMass|solLum|Sun
75 DEVICE adu|bin|chan|count|ct|photon|ph|pixel|pix|voxel
76 ADD_NONE {GENERAL}|{ASTRO}|{DEVICE}
77
78 /* All additional recognized units. */
79 ADD_UNIT {ADD_ALL}|{ADD_SUP}|{ADD_SUB}|{ADD_NONE}
80
81 /* Exclusive start states. */
82 %x PAREN PREFIX UNITS EXPON FLUSH
83
84 %{
85 #include <math.h>
86 #include <setjmp.h>
87 #include <stdio.h>
88 #include <stdlib.h>
89
90 #include "wcserr.h"
91 #include "wcsmath.h"
92 #include "wcsunits.h"
93 #include "wcsutil.h"
94
95 // User data associated with yyscanner.
96 struct wcsulex_extra {
97 // Used in preempting the call to exit() by yy_fatal_error().
98 jmp_buf abort_jmp_env;
99 };
100
101 #define YY_DECL int wcsulexe_scanner(const char unitstr[], int *func, \
102 double *scale, double units[WCSUNITS_NTYPE], struct wcserr **err, \
103 yyscan_t yyscanner)
104
105 // Dummy definition to circumvent compiler warnings.
106 #define YY_INPUT(inbuff, count, bufsize) { count = YY_NULL; }
107
108 // Preempt the call to exit() by yy_fatal_error().
109 #define exit(status) longjmp(yyextra->abort_jmp_env, status);
110
111 // Internal helper functions.
112 static YY_DECL;
113
114 %}
115
116 %%
117 static const char *function = "wcsulexe_scanner";
118
119 void add(double *factor, double types[], double *expon, double *scale,
120 double units[]);
121
122 // Initialise returned values.
123 *func = 0;
124 *scale = 1.0;
125
126 for (int i = 0; i < WCSUNITS_NTYPE; i++) {
127 units[i] = 0.0;
128 }
129
130 if (err) *err = 0x0;
131
132 double types[WCSUNITS_NTYPE];
133 for (int i = 0; i < WCSUNITS_NTYPE; i++) {
134 types[i] = 0.0;
135 }
136 double expon = 1.0;
137 double factor = 1.0;
138
139 int bracket = 0;
140 int operator = 0;
141 int paren = 0;
142 int status = 0;
143
144 // Avert a flex-induced memory leak.
145 if (YY_CURRENT_BUFFER && YY_CURRENT_BUFFER->yy_input_file == stdin) {
146 yy_delete_buffer(YY_CURRENT_BUFFER, yyscanner);
147 }
148
149 yy_scan_string(unitstr, yyscanner);
150
151 // Return here via longjmp() invoked by yy_fatal_error().
152 if (setjmp(yyextra->abort_jmp_env)) {
153 return wcserr_set(WCSERR_SET(UNITSERR_PARSER_ERROR),
154 "Internal units parser error parsing '%s'", unitstr);
155 }
156
157 BEGIN(INITIAL);
158
159 #ifdef DEBUG
160 fprintf(stderr, "\n%s ->\n", unitstr);
161 #endif
162
163 ^" "+ {
164 // Pretend initial whitespace doesn't exist.
165 yy_set_bol(1);
166 }
167
168 ^"[" {
169 if (bracket++) {
170 BEGIN(FLUSH);
171 } else {
172 yy_set_bol(1);
173 }
174 }
175
176 ^10[0-9] {
177 status = wcserr_set(WCSERR_SET(UNITSERR_BAD_NUM_MULTIPLIER),
178 "Invalid exponent in '%s'", unitstr);
179 BEGIN(FLUSH);
180 }
181
182 ^10 {
183 factor = 10.0;
184 BEGIN(EXPON);
185 }
186
187 ^log" "*"(" {
188 *func = 1;
189 unput('(');
190 BEGIN(PAREN);
191 }
192
193 ^ln" "*"(" {
194 *func = 2;
195 unput('(');
196 BEGIN(PAREN);
197 }
198
199 ^exp" "*"(" {
200 *func = 3;
201 unput('(');
202 BEGIN(PAREN);
203 }
204
205 ^[*.] {
206 // Leading binary multiply.
207 status = wcserr_set(WCSERR_SET(UNITSERR_DANGLING_BINOP),
208 "Dangling binary operator in '%s'", unitstr);
209 BEGIN(FLUSH);
210 }
211
212 " "+ // Discard whitespace in INITIAL context.
213
214 sqrt" "*"(" {
215 expon /= 2.0;
216 unput('(');
217 BEGIN(PAREN);
218 }
219
220 "(" {
221 // Gather terms in parentheses.
222 yyless(0);
223 BEGIN(PAREN);
224 }
225
226 [*.] {
227 if (operator++) {
228 BEGIN(FLUSH);
229 }
230 }
231
232 ^1"/" |
233 "/" {
234 if (operator++) {
235 BEGIN(FLUSH);
236 } else {
237 expon *= -1.0;
238 }
239 }
240
241 {SI_UNIT}|{ADD_UNIT} {
242 operator = 0;
243 yyless(0);
244 BEGIN(UNITS);
245 }
246
247 {PREFIX}({SI_UNIT}|{ADD_ALL}) |
248 {SUPPREFIX}{ADD_SUP} |
249 {SUBPREFIX}{ADD_SUB} {
250 operator = 0;
251 yyless(0);
252 BEGIN(PREFIX);
253 }
254
255 "]" {
256 bracket = !bracket;
257 BEGIN(FLUSH);
258 }
259
260 . {
261 status = wcserr_set(WCSERR_SET(UNITSERR_BAD_INITIAL_SYMBOL),
262 "Invalid symbol in INITIAL context in '%s'", unitstr);
263 BEGIN(FLUSH);
264 }
265
266 <PAREN>"(" {
267 paren++;
268 operator = 0;
269 yymore();
270 }
271
272 <PAREN>")" {
273 paren--;
274 if (paren) {
275 // Not balanced yet.
276 yymore();
277
278 } else {
279 // Balanced; strip off the outer parentheses and recurse.
280 yytext[yyleng-1] = '\0';
281
282 int func_r;
283 double factor_r;
284 status = wcsulexe(yytext+1, &func_r, &factor_r, types, err);
285
286 YY_BUFFER_STATE buf = YY_CURRENT_BUFFER;
287 yy_switch_to_buffer(buf, yyscanner);
288
289 if (func_r) {
290 status = wcserr_set(WCSERR_SET(UNITSERR_FUNCTION_CONTEXT),
291 "Function in invalid context in '%s'", unitstr);
292 }
293
294 if (status) {
295 BEGIN(FLUSH);
296 } else {
297 factor *= factor_r;
298 BEGIN(EXPON);
299 }
300 }
301 }
302
303 <PAREN>[^()]+ {
304 yymore();
305 }
306
307 <PREFIX>d {
308 factor = 1e-1;
309 BEGIN(UNITS);
310 }
311
312 <PREFIX>c {
313 factor = 1e-2;
314 BEGIN(UNITS);
315 }
316
317 <PREFIX>m {
318 factor = 1e-3;
319 BEGIN(UNITS);
320 }
321
322 <PREFIX>u {
323 factor = 1e-6;
324 BEGIN(UNITS);
325 }
326
327 <PREFIX>n {
328 factor = 1e-9;
329 BEGIN(UNITS);
330 }
331
332 <PREFIX>p {
333 factor = 1e-12;
334 BEGIN(UNITS);
335 }
336
337 <PREFIX>f {
338 factor = 1e-15;
339 BEGIN(UNITS);
340 }
341
342 <PREFIX>a {
343 factor = 1e-18;
344 BEGIN(UNITS);
345 }
346
347 <PREFIX>z {
348 factor = 1e-21;
349 BEGIN(UNITS);
350 }
351
352 <PREFIX>y {
353 factor = 1e-24;
354 BEGIN(UNITS);
355 }
356
357 <PREFIX>da {
358 factor = 1e+1;
359 BEGIN(UNITS);
360 }
361
362 <PREFIX>h {
363 factor = 1e+2;
364 BEGIN(UNITS);
365 }
366
367 <PREFIX>k {
368 factor = 1e+3;
369 BEGIN(UNITS);
370 }
371
372 <PREFIX>M {
373 factor = 1e+6;
374 BEGIN(UNITS);
375 }
376
377 <PREFIX>G {
378 factor = 1e+9;
379 BEGIN(UNITS);
380 }
381
382 <PREFIX>T {
383 factor = 1e+12;
384 BEGIN(UNITS);
385 }
386
387 <PREFIX>P {
388 factor = 1e+15;
389 BEGIN(UNITS);
390 }
391
392 <PREFIX>E {
393 factor = 1e+18;
394 BEGIN(UNITS);
395 }
396
397 <PREFIX>Z {
398 factor = 1e+21;
399 BEGIN(UNITS);
400 }
401
402 <PREFIX>Y {
403 factor = 1e+24;
404 BEGIN(UNITS);
405 }
406
407 <PREFIX>. {
408 // Internal parser error.
409 status = wcserr_set(WCSERR_SET(UNITSERR_PARSER_ERROR),
410 "Internal units parser error parsing '%s'", unitstr);
411 BEGIN(FLUSH);
412 }
413
414 <UNITS>A {
415 // Ampere.
416 types[WCSUNITS_CHARGE] += 1.0;
417 types[WCSUNITS_TIME] -= 1.0;
418 BEGIN(EXPON);
419 }
420
421 <UNITS>a|yr {
422 // Julian year (annum).
423 factor *= 31557600.0;
424 types[WCSUNITS_TIME] += 1.0;
425 BEGIN(EXPON);
426 }
427
428 <UNITS>adu {
429 // Analogue-to-digital converter units.
430 types[WCSUNITS_COUNT] += 1.0;
431 BEGIN(EXPON);
432 }
433
434 <UNITS>[Aa]ngstrom {
435 // Angstrom.
436 factor *= 1e-10;
437 types[WCSUNITS_LENGTH] += 1.0;
438 BEGIN(EXPON);
439 }
440
441 <UNITS>arcmin {
442 // Minute of arc.
443 factor /= 60.0;
444 types[WCSUNITS_PLANE_ANGLE] += 1.0;
445 BEGIN(EXPON);
446 }
447
448 <UNITS>arcsec {
449 // Second of arc.
450 factor /= 3600.0;
451 types[WCSUNITS_PLANE_ANGLE] += 1.0;
452 BEGIN(EXPON);
453 }
454
455 <UNITS>AU {
456 // Astronomical unit.
457 factor *= 1.49598e+11;
458 types[WCSUNITS_LENGTH] += 1.0;
459 BEGIN(EXPON);
460 }
461
462 <UNITS>barn {
463 // Barn.
464 factor *= 1e-28;
465 types[WCSUNITS_LENGTH] += 2.0;
466 BEGIN(EXPON);
467 }
468
469 <UNITS>beam {
470 // Beam, as in Jy/beam.
471 types[WCSUNITS_BEAM] += 1.0;
472 BEGIN(EXPON);
473 }
474
475 <UNITS>bin {
476 // Bin (e.g. histogram).
477 types[WCSUNITS_BIN] += 1.0;
478 BEGIN(EXPON);
479 }
480
481 <UNITS>bit {
482 // Bit.
483 types[WCSUNITS_BIT] += 1.0;
484 BEGIN(EXPON);
485 }
486
487 <UNITS>[bB]yte {
488 // Byte.
489 factor *= 8.0;
490 types[WCSUNITS_BIT] += 1.0;
491 BEGIN(EXPON);
492 }
493
494 <UNITS>C {
495 // Coulomb.
496 types[WCSUNITS_CHARGE] += 1.0;
497 BEGIN(EXPON);
498 }
499
500 <UNITS>cd {
501 // Candela.
502 types[WCSUNITS_LUMINTEN] += 1.0;
503 BEGIN(EXPON);
504 }
505
506 <UNITS>chan {
507 // Channel.
508 types[WCSUNITS_BIN] += 1.0;
509 BEGIN(EXPON);
510 }
511
512 <UNITS>count|ct {
513 // Count.
514 types[WCSUNITS_COUNT] += 1.0;
515 BEGIN(EXPON);
516 }
517
518 <UNITS>cy {
519 // Julian century.
520 factor *= 3155760000.0;
521 types[WCSUNITS_TIME] += 1.0;
522 BEGIN(EXPON);
523 }
524
525 <UNITS>D {
526 // Debye.
527 factor *= 1e-29 / 3.0;
528 types[WCSUNITS_CHARGE] += 1.0;
529 types[WCSUNITS_LENGTH] += 1.0;
530 BEGIN(EXPON);
531 }
532
533 <UNITS>d {
534 // Day.
535 factor *= 86400.0;
536 types[WCSUNITS_TIME] += 1.0;
537 BEGIN(EXPON);
538 }
539
540 <UNITS>deg {
541 // Degree.
542 types[WCSUNITS_PLANE_ANGLE] += 1.0;
543 BEGIN(EXPON);
544 }
545
546 <UNITS>erg {
547 // Erg.
548 factor *= 1e-7;
549 types[WCSUNITS_MASS] += 1.0;
550 types[WCSUNITS_LENGTH] += 2.0;
551 types[WCSUNITS_TIME] -= 2.0;
552 BEGIN(EXPON);
553 }
554
555 <UNITS>eV {
556 // Electron volt.
557 factor *= 1.6021765e-19;
558 types[WCSUNITS_MASS] += 1.0;
559 types[WCSUNITS_LENGTH] += 2.0;
560 types[WCSUNITS_TIME] -= 2.0;
561 BEGIN(EXPON);
562 }
563
564 <UNITS>F {
565 // Farad.
566 types[WCSUNITS_MASS] -= 1.0;
567 types[WCSUNITS_LENGTH] -= 2.0;
568 types[WCSUNITS_TIME] += 3.0;
569 types[WCSUNITS_CHARGE] += 2.0;
570 BEGIN(EXPON);
571 }
572
573 <UNITS>G {
574 // Gauss.
575 factor *= 1e-4;
576 types[WCSUNITS_MASS] += 1.0;
577 types[WCSUNITS_TIME] += 1.0;
578 types[WCSUNITS_CHARGE] -= 1.0;
579 BEGIN(EXPON);
580 }
581
582 <UNITS>g {
583 // Gram.
584 factor *= 1e-3;
585 types[WCSUNITS_MASS] += 1.0;
586 BEGIN(EXPON);
587 }
588
589 <UNITS>H {
590 // Henry.
591 types[WCSUNITS_MASS] += 1.0;
592 types[WCSUNITS_LENGTH] += 2.0;
593 types[WCSUNITS_TIME] += 2.0;
594 types[WCSUNITS_CHARGE] -= 2.0;
595 BEGIN(EXPON);
596 }
597
598 <UNITS>h {
599 // Hour.
600 factor *= 3600.0;
601 types[WCSUNITS_TIME] += 1.0;
602 BEGIN(EXPON);
603 }
604
605 <UNITS>Hz {
606 // Hertz.
607 types[WCSUNITS_TIME] -= 1.0;
608 BEGIN(EXPON);
609 }
610
611 <UNITS>J {
612 // Joule.
613 types[WCSUNITS_MASS] += 1.0;
614 types[WCSUNITS_LENGTH] += 2.0;
615 types[WCSUNITS_TIME] -= 2.0;
616 BEGIN(EXPON);
617 }
618
619 <UNITS>Jy {
620 // Jansky.
621 factor *= 1e-26;
622 types[WCSUNITS_MASS] += 1.0;
623 types[WCSUNITS_TIME] -= 2.0;
624 BEGIN(EXPON);
625 }
626
627 <UNITS>K {
628 // Kelvin.
629 types[WCSUNITS_TEMPERATURE] += 1.0;
630 BEGIN(EXPON);
631 }
632
633 <UNITS>lm {
634 // Lumen.
635 types[WCSUNITS_LUMINTEN] += 1.0;
636 types[WCSUNITS_SOLID_ANGLE] += 1.0;
637 BEGIN(EXPON);
638 }
639
640 <UNITS>lx {
641 // Lux.
642 types[WCSUNITS_LUMINTEN] += 1.0;
643 types[WCSUNITS_SOLID_ANGLE] += 1.0;
644 types[WCSUNITS_LENGTH] -= 2.0;
645 BEGIN(EXPON);
646 }
647
648 <UNITS>lyr {
649 // Light year.
650 factor *= 2.99792458e8 * 31557600.0;
651 types[WCSUNITS_LENGTH] += 1.0;
652 BEGIN(EXPON);
653 }
654
655 <UNITS>m {
656 // Metre.
657 types[WCSUNITS_LENGTH] += 1.0;
658 BEGIN(EXPON);
659 }
660
661 <UNITS>mag {
662 // Stellar magnitude.
663 types[WCSUNITS_MAGNITUDE] += 1.0;
664 BEGIN(EXPON);
665 }
666
667 <UNITS>mas {
668 // Milli-arcsec.
669 factor /= 3600e+3;
670 types[WCSUNITS_PLANE_ANGLE] += 1.0;
671 BEGIN(EXPON);
672 }
673
674 <UNITS>min {
675 // Minute.
676 factor *= 60.0;
677 types[WCSUNITS_TIME] += 1.0;
678 BEGIN(EXPON);
679 }
680
681 <UNITS>mol {
682 // Mole.
683 types[WCSUNITS_MOLE] += 1.0;
684 BEGIN(EXPON);
685 }
686
687 <UNITS>N {
688 // Newton.
689 types[WCSUNITS_MASS] += 1.0;
690 types[WCSUNITS_LENGTH] += 1.0;
691 types[WCSUNITS_TIME] -= 2.0;
692 BEGIN(EXPON);
693 }
694
695 <UNITS>[Oo]hm {
696 // Ohm.
697 types[WCSUNITS_MASS] += 1.0;
698 types[WCSUNITS_LENGTH] += 2.0;
699 types[WCSUNITS_TIME] -= 1.0;
700 types[WCSUNITS_CHARGE] -= 2.0;
701 BEGIN(EXPON);
702 }
703
704 <UNITS>Pa {
705 // Pascal.
706 types[WCSUNITS_MASS] += 1.0;
707 types[WCSUNITS_LENGTH] -= 1.0;
708 types[WCSUNITS_TIME] -= 2.0;
709 BEGIN(EXPON);
710 }
711
712 <UNITS>pc {
713 // Parsec.
714 factor *= 3.0857e16;
715 types[WCSUNITS_LENGTH] += 1.0;
716 BEGIN(EXPON);
717 }
718
719 <UNITS>photon|ph {
720 // Photon.
721 types[WCSUNITS_COUNT] += 1.0;
722 BEGIN(EXPON);
723 }
724
725 <UNITS>pixel|pix {
726 // Pixel.
727 types[WCSUNITS_PIXEL] += 1.0;
728 BEGIN(EXPON);
729 }
730
731 <UNITS>R {
732 // Rayleigh.
733 factor *= 1e10 / (4.0 * PI);
734 types[WCSUNITS_LENGTH] -= 2.0;
735 types[WCSUNITS_TIME] -= 1.0;
736 types[WCSUNITS_SOLID_ANGLE] -= 1.0;
737 BEGIN(EXPON);
738 }
739
740 <UNITS>rad {
741 // Radian.
742 factor *= 180.0 / PI;
743 types[WCSUNITS_PLANE_ANGLE] += 1.0;
744 BEGIN(EXPON);
745 }
746
747 <UNITS>Ry {
748 // Rydberg.
749 factor *= 13.605692 * 1.6021765e-19;
750 types[WCSUNITS_MASS] += 1.0;
751 types[WCSUNITS_LENGTH] += 2.0;
752 types[WCSUNITS_TIME] -= 2.0;
753 BEGIN(EXPON);
754 }
755
756 <UNITS>S {
757 // Siemen.
758 types[WCSUNITS_MASS] -= 1.0;
759 types[WCSUNITS_LENGTH] -= 2.0;
760 types[WCSUNITS_TIME] += 1.0;
761 types[WCSUNITS_CHARGE] += 2.0;
762 BEGIN(EXPON);
763 }
764
765 <UNITS>s {
766 // Second.
767 types[WCSUNITS_TIME] += 1.0;
768 BEGIN(EXPON);
769 }
770
771 <UNITS>solLum {
772 // Solar luminosity.
773 factor *= 3.8268e26;
774 types[WCSUNITS_MASS] += 1.0;
775 types[WCSUNITS_LENGTH] += 2.0;
776 types[WCSUNITS_TIME] -= 3.0;
777 BEGIN(EXPON);
778 }
779
780 <UNITS>solMass {
781 // Solar mass.
782 factor *= 1.9891e30;
783 types[WCSUNITS_MASS] += 1.0;
784 BEGIN(EXPON);
785 }
786
787 <UNITS>solRad {
788 // Solar radius.
789 factor *= 6.9599e8;
790 types[WCSUNITS_LENGTH] += 1.0;
791 BEGIN(EXPON);
792 }
793
794 <UNITS>sr {
795 // Steradian.
796 types[WCSUNITS_SOLID_ANGLE] += 1.0;
797 BEGIN(EXPON);
798 }
799
800 <UNITS>Sun {
801 // Sun (with respect to).
802 types[WCSUNITS_SOLRATIO] += 1.0;
803 BEGIN(EXPON);
804 }
805
806 <UNITS>T {
807 // Tesla.
808 types[WCSUNITS_MASS] += 1.0;
809 types[WCSUNITS_TIME] += 1.0;
810 types[WCSUNITS_CHARGE] -= 1.0;
811 BEGIN(EXPON);
812 }
813
814 <UNITS>turn {
815 // Turn.
816 factor *= 360.0;
817 types[WCSUNITS_PLANE_ANGLE] += 1.0;
818 BEGIN(EXPON);
819 }
820
821 <UNITS>u {
822 // Unified atomic mass unit.
823 factor *= 1.6605387e-27;
824 types[WCSUNITS_MASS] += 1.0;
825 BEGIN(EXPON);
826 }
827
828 <UNITS>V {
829 // Volt.
830 types[WCSUNITS_MASS] += 1.0;
831 types[WCSUNITS_LENGTH] += 1.0;
832 types[WCSUNITS_TIME] -= 2.0;
833 types[WCSUNITS_CHARGE] -= 1.0;
834 BEGIN(EXPON);
835 }
836
837 <UNITS>voxel {
838 // Voxel.
839 types[WCSUNITS_VOXEL] += 1.0;
840 BEGIN(EXPON);
841 }
842
843 <UNITS>W {
844 // Watt.
845 types[WCSUNITS_MASS] += 1.0;
846 types[WCSUNITS_LENGTH] += 2.0;
847 types[WCSUNITS_TIME] -= 3.0;
848 BEGIN(EXPON);
849 }
850
851 <UNITS>Wb {
852 // Weber.
853 types[WCSUNITS_MASS] += 1.0;
854 types[WCSUNITS_LENGTH] += 2.0;
855 types[WCSUNITS_TIME] += 1.0;
856 types[WCSUNITS_CHARGE] -= 1.0;
857 BEGIN(EXPON);
858 }
859
860 <UNITS>. {
861 // Internal parser error.
862 status = wcserr_set(WCSERR_SET(UNITSERR_PARSER_ERROR),
863 "Internal units parser error parsing '%s'", unitstr);
864 BEGIN(FLUSH);
865 }
866
867 <EXPON>" "*("**"|^) {
868 // Exponentiation.
869 if (operator++) {
870 BEGIN(FLUSH);
871 }
872 }
873
874 <EXPON>" "*{INTEGER} {
875 int i;
876 sscanf(yytext, " %d", &i);
877 expon *= (double)i;
878 add(&factor, types, &expon, scale, units);
879 operator = 0;
880 BEGIN(INITIAL);
881 }
882
883 <EXPON>" "*"("" "*{INTEGER}" "*")" {
884 int i;
885 sscanf(yytext, " (%d)", &i);
886 expon *= (double)i;
887 add(&factor, types, &expon, scale, units);
888 operator = 0;
889 BEGIN(INITIAL);
890 }
891
892 <EXPON>" "*"("" "*{FRAC}" "*")" {
893 int i, j;
894 sscanf(yytext, " (%d/%d)", &i, &j);
895 expon *= (double)i / (double)j;
896 add(&factor, types, &expon, scale, units);
897 operator = 0;
898 BEGIN(INITIAL);
899 }
900
901 <EXPON>" "*"("" "*{FLOAT}" "*")" {
902 char ctmp[72];
903 sscanf(yytext, " (%s)", ctmp);
904 double dexp;
905 wcsutil_str2double(ctmp, &dexp);
906 expon *= dexp;
907 add(&factor, types, &expon, scale, units);
908 operator = 0;
909 BEGIN(INITIAL);
910 }
911
912 <EXPON>" "*[.*]" "* {
913 // Multiply.
914 if (operator++) {
915 BEGIN(FLUSH);
916 } else {
917 add(&factor, types, &expon, scale, units);
918 BEGIN(INITIAL);
919 }
920 }
921
922 <EXPON>" "*"(" {
923 // Multiply.
924 if (operator) {
925 BEGIN(FLUSH);
926 } else {
927 add(&factor, types, &expon, scale, units);
928 unput('(');
929 BEGIN(INITIAL);
930 }
931 }
932
933 <EXPON>" "+ {
934 // Multiply.
935 if (operator) {
936 BEGIN(FLUSH);
937 } else {
938 add(&factor, types, &expon, scale, units);
939 BEGIN(INITIAL);
940 }
941 }
942
943 <EXPON>" "*"/"" "* {
944 // Divide.
945 if (operator++) {
946 BEGIN(FLUSH);
947 } else {
948 add(&factor, types, &expon, scale, units);
949 expon = -1.0;
950 BEGIN(INITIAL);
951 }
952 }
953
954 <EXPON>" "*"]" {
955 add(&factor, types, &expon, scale, units);
956 bracket = !bracket;
957 BEGIN(FLUSH);
958 }
959
960 <EXPON>. {
961 status = wcserr_set(WCSERR_SET(UNITSERR_BAD_EXPON_SYMBOL),
962 "Invalid symbol in EXPON context in '%s'", unitstr);
963 BEGIN(FLUSH);
964 }
965
966 <FLUSH>.* {
967 // Discard any remaining input.
968 }
969
970 <<EOF>> {
971 // End-of-string.
972 if (YY_START == EXPON) {
973 add(&factor, types, &expon, scale, units);
974 }
975
976 if (bracket) {
977 status = wcserr_set(WCSERR_SET(UNITSERR_UNBAL_BRACKET),
978 "Unbalanced bracket in '%s'", unitstr);
979 } else if (paren) {
980 status = wcserr_set(WCSERR_SET(UNITSERR_UNBAL_PAREN),
981 "Unbalanced parenthesis in '%s'", unitstr);
982 } else if (operator == 1) {
983 status = wcserr_set(WCSERR_SET(UNITSERR_DANGLING_BINOP),
984 "Dangling binary operator in '%s'", unitstr);
985 } else if (operator) {
986 status = wcserr_set(WCSERR_SET(UNITSERR_CONSEC_BINOPS),
987 "Consecutive binary operators in '%s'", unitstr);
988 #ifdef DEBUG
989 } else {
990 fprintf(stderr, "EOS\n");
991 #endif
992 }
993
994 if (status) {
995 for (int i = 0; i < WCSUNITS_NTYPE; i++) {
996 units[i] = 0.0;
997 *scale = 0.0;
998 }
999 }
1000
1001 return status;
1002 }
1003
1004 %%
1005
1006 /*----------------------------------------------------------------------------
1007 * External interface to the scanner.
1008 *---------------------------------------------------------------------------*/
1009
1010 int wcsulexe(
1011 const char unitstr[],
1012 int *func,
1013 double *scale,
1014 double units[WCSUNITS_NTYPE],
1015 struct wcserr **err)
1016
1017 {
1018 // Function prototypes.
1019 int yylex_init_extra(YY_EXTRA_TYPE extra, yyscan_t *yyscanner);
1020 int yylex_destroy(yyscan_t yyscanner);
1021
1022 struct wcsulex_extra extra;
1023 yyscan_t yyscanner;
1024 yylex_init_extra(&extra, &yyscanner);
1025 int status = wcsulexe_scanner(unitstr, func, scale, units, err, yyscanner);
1026 yylex_destroy(yyscanner);
1027
1028 return status;
1029 }
1030
1031
1032 /*----------------------------------------------------------------------------
1033 * Accumulate a term in a units specification and reset work variables.
1034 *---------------------------------------------------------------------------*/
1035
add(double * factor,double types[],double * expon,double * scale,double units[])1036 void add(
1037 double *factor,
1038 double types[],
1039 double *expon,
1040 double *scale,
1041 double units[])
1042
1043 {
1044 *scale *= pow(*factor, *expon);
1045
1046 for (int i = 0; i < WCSUNITS_NTYPE; i++) {
1047 units[i] += *expon * types[i];
1048 types[i] = 0.0;
1049 }
1050
1051 *expon = 1.0;
1052 *factor = 1.0;
1053
1054 return;
1055 }
1056