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