/*============================================================================ WCSLIB 4.3 - an implementation of the FITS WCS standard. Copyright (C) 1995-2007, Mark Calabretta This file is part of WCSLIB. WCSLIB is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. WCSLIB is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with WCSLIB. If not, see . Correspondence concerning WCSLIB may be directed to: Internet email: mcalabre@atnf.csiro.au Postal address: Dr. Mark Calabretta Australia Telescope National Facility, CSIRO PO Box 76 Epping NSW 1710 AUSTRALIA Author: Mark Calabretta, Australia Telescope National Facility http://www.atnf.csiro.au/~mcalabre/index.html $Id: wcsulex.l,v 4.3 2007/12/27 05:41:36 cal103 Exp $ *============================================================================= * * wcsulex.l is a Flex description file containing the definition of a * recursive, multi-buffered lexical scanner that parses FITS units * specifications. * * It requires Flex v2.5.4 or later. * * Refer to wcsunits.h for a description of the user interface and operating * notes. * *===========================================================================*/ /* Options. */ %option full %option never-interactive %option noyywrap %option outfile="wcsulex.c" %option prefix="wcsulex" /* Exponents. */ INTEGER [+-]?[1-9][0-9]* FRAC {INTEGER}"/"[1-9][0-9]* FLOAT [+-]?([0-9]+\.?[0-9]*|\.[0-9]+) /* Metric prefixes. */ SUB3 [munpfazy] SUBPREFIX [dc]|{SUB3} SUP3 [kMGTPEZY] SUPPREFIX da|h|{SUP3} PREFIX {SUBPREFIX}|{SUPPREFIX} /* Basic and derived SI units. */ BASIC m|s|g|rad|sr|K|A|mol|cd DERIVED Hz|J|W|V|N|Pa|C|[Oo]hm|S|F|Wb|T|H|lm|lx SI_UNIT {BASIC}|{DERIVED} /* Additional recognized units: all metric prefixes allowed. */ ADD_ALL eV|Jy|R|G|barn /* Additional recognized units: only super-metric prefixes. */ ADD_SUP a|yr|pc|bit|[bB]yte /* Additional recognized units: only sub-metric prefixes allowed. */ ADD_SUB mag /* Additional recognized units for which NO metric prefixes are allowed. */ GENERAL deg|arcmin|arcsec|mas|d|h|min|erg|Ry|u|D ASTRO [Aa]ngstrom|AU|lyr|beam|solRad|solMass|solLum|Sun DEVICE adu|bin|chan|count|ct|photon|ph|pixel|pix|voxel ADD_NONE {GENERAL}|{ASTRO}|{DEVICE} /* All additional recognized units. */ ADD_UNIT {ADD_ALL}|{ADD_SUP}|{ADD_SUB}|{ADD_NONE} /* Exclusive start states. */ %x PAREN PREFIX UNITS EXPON FLUSH %{ /* To get the prototype for fileno() from stdio.h when gcc is invoked with * -std=c89 (same as -ansi) or -std=c99 since we do not define YY_INPUT. */ #define _POSIX_SOURCE 1 #include #include #include "wcsmath.h" #include "wcsunits.h" #define YY_DECL int wcsulex(const char unitstr[], int *func, double *scale, \ double units[]) #ifdef DEBUG /* Print text as it is matched. */ #define YY_USER_ACTION printf("Rule %03d: \"%s\"\n", yy_act, yytext); #endif void wcsulex_add(double *factor, double types[], double *expon, double *scale, double units[]); %} %% int bracket = 0; int operator = 0; int paren = 0; int status = 0; int func_r, i, j; double dexp, expon, factor, factor_r, types[WCSUNITS_NTYPE]; YY_BUFFER_STATE buf; int yylex_destroy(void); *func = 0; for (i = 0; i < WCSUNITS_NTYPE; i++) { units[i] = 0.0; types[i] = 0.0; } expon = 1.0; factor = 1.0; *scale = 1.0; yy_scan_string(unitstr); BEGIN(INITIAL); #ifdef DEBUG printf("\n%s ->\n", unitstr); #endif ^" "+ { /* Rule 001: Pretend initial whitespace doesn't exist. */ yy_set_bol(1); } ^"[" { /* Rule 002. */ if (bracket++) { BEGIN(FLUSH); } else { yy_set_bol(1); } } ^10[0-9] { /* Rule 003. */ status = 1; BEGIN(FLUSH); } ^10 { /* Rule 004. */ factor = 10.0; BEGIN(EXPON); } ^log" "*"(" { /* Rule 005. */ *func = 1; unput('('); BEGIN(PAREN); } ^ln" "*"(" { /* Rule 006. */ *func = 2; unput('('); BEGIN(PAREN); } ^exp" "*"(" { /* Rule 007. */ *func = 3; unput('('); BEGIN(PAREN); } ^[*.] { /* Rule 008: Leading binary multiply. */ status = 2; BEGIN(FLUSH); } " "+ /* Rule 009: Discard whitespace in INITIAL context. */ sqrt" "*"(" { /* Rule 010. */ expon /= 2.0; unput('('); BEGIN(PAREN); } "(" { /* Rule 011: Gather terms in parentheses. */ yyless(0); BEGIN(PAREN); } [*.] { /* Rule 012. */ if (operator++) { BEGIN(FLUSH); } } "/" { /* Rule 013. */ if (operator++) { BEGIN(FLUSH); } else if (*yytext == '/') { expon *= -1.0; } } {SI_UNIT}|{ADD_UNIT} { /* Rule 014. */ operator = 0; yyless(0); BEGIN(UNITS); } {PREFIX}({SI_UNIT}|{ADD_ALL}) | {SUPPREFIX}{ADD_SUP} | {SUBPREFIX}{ADD_SUB} { /* Rules 015-017. */ operator = 0; yyless(0); BEGIN(PREFIX); } "]" { /* Rule 018. */ bracket = !bracket; BEGIN(FLUSH); } . { /* Rule 019. */ status = 3; BEGIN(FLUSH); } "(" { /* Rule 020. */ paren++; operator = 0; yymore(); } ")" { /* Rule 022. */ paren--; if (paren) { /* Not balanced yet. */ yymore(); } else { /* Balanced; strip off the outer parentheses and recurse. */ yytext[yyleng-1] = '\0'; buf = YY_CURRENT_BUFFER; status = wcsulex(yytext+1, &func_r, &factor_r, types); yy_switch_to_buffer(buf); if (func_r) { status = 4; } if (status) { BEGIN(FLUSH); } else { factor *= factor_r; BEGIN(EXPON); } } } [^()]+ { /* Rule 022. */ yymore(); } d { /* Rule 023. */ factor = 1e-1; BEGIN(UNITS); } c { /* Rule 024. */ factor = 1e-2; BEGIN(UNITS); } m { /* Rule 025. */ factor = 1e-3; BEGIN(UNITS); } u { /* Rule 026. */ factor = 1e-6; BEGIN(UNITS); } n { /* Rule 027. */ factor = 1e-9; BEGIN(UNITS); } p { /* Rule 028. */ factor = 1e-12; BEGIN(UNITS); } f { /* Rule 029. */ factor = 1e-15; BEGIN(UNITS); } a { /* Rule 030. */ factor = 1e-18; BEGIN(UNITS); } z { /* Rule 031. */ factor = 1e-21; BEGIN(UNITS); } y { /* Rule 032. */ factor = 1e-24; BEGIN(UNITS); } da { /* Rule 033. */ factor = 1e+1; BEGIN(UNITS); } h { /* Rule 034. */ factor = 1e+2; BEGIN(UNITS); } k { /* Rule 035. */ factor = 1e+3; BEGIN(UNITS); } M { /* Rule 036. */ factor = 1e+6; BEGIN(UNITS); } G { /* Rule 037. */ factor = 1e+9; BEGIN(UNITS); } T { /* Rule 038. */ factor = 1e+12; BEGIN(UNITS); } P { /* Rule 039. */ factor = 1e+15; BEGIN(UNITS); } E { /* Rule 040. */ factor = 1e+18; BEGIN(UNITS); } Z { /* Rule 041. */ factor = 1e+21; BEGIN(UNITS); } Y { /* Rule 042. */ factor = 1e+24; BEGIN(UNITS); } . { /* Rule 043: Internal parser error. */ status = 9; BEGIN(FLUSH); } A { /* Rule 044: Ampere. */ types[WCSUNITS_CHARGE] += 1.0; types[WCSUNITS_TIME] -= 1.0; BEGIN(EXPON); } a|yr { /* Rule 045: Year (annum). */ factor *= 31557600.0; types[WCSUNITS_TIME] += 1.0; BEGIN(EXPON); } adu { /* Rule 046: Analogue-to-digital converter units. */ types[WCSUNITS_COUNT] += 1.0; BEGIN(EXPON); } [Aa]ngstrom { /* Rule 047: Angstrom. */ factor *= 1e-10; types[WCSUNITS_LENGTH] += 1.0; BEGIN(EXPON); } arcmin { /* Rule 048: Minute of arc. */ factor /= 60.0; types[WCSUNITS_PLANE_ANGLE] += 1.0; BEGIN(EXPON); } arcsec { /* Rule 049: Second of arc. */ factor /= 3600.0; types[WCSUNITS_PLANE_ANGLE] += 1.0; BEGIN(EXPON); } AU { /* Rule 050: Astronomical unit. */ factor *= 1.49598e+11; types[WCSUNITS_LENGTH] += 1.0; BEGIN(EXPON); } barn { /* Rule 051: Barn. */ factor *= 1e-28; types[WCSUNITS_LENGTH] += 2.0; BEGIN(EXPON); } beam { /* Rule 052: Beam, as in Jy/beam. */ types[WCSUNITS_BEAM] += 1.0; BEGIN(EXPON); } bin { /* Rule 053: Bin (e.g. histogram). */ types[WCSUNITS_BIN] += 1.0; BEGIN(EXPON); } bit { /* Rule 054: Bit. */ types[WCSUNITS_BIT] += 1.0; BEGIN(EXPON); } [bB]yte { /* Rule 055: Byte. */ factor *= 8.0; types[WCSUNITS_BIT] += 1.0; BEGIN(EXPON); } C { /* Rule 056: Coulomb. */ types[WCSUNITS_CHARGE] += 1.0; BEGIN(EXPON); } cd { /* Rule 057: Candela. */ types[WCSUNITS_LUMINTEN] += 1.0; BEGIN(EXPON); } chan { /* Rule 058: Channel. */ types[WCSUNITS_BIN] += 1.0; BEGIN(EXPON); } count|ct { /* Rule 059: Count. */ types[WCSUNITS_COUNT] += 1.0; BEGIN(EXPON); } D { /* Rule 060: Debye. */ factor *= 1e-29 / 3.0; types[WCSUNITS_CHARGE] += 1.0; types[WCSUNITS_LENGTH] += 1.0; BEGIN(EXPON); } d { /* Rule 061: Day. */ factor *= 86400.0; types[WCSUNITS_TIME] += 1.0; BEGIN(EXPON); } deg { /* Rule 062: Degree. */ types[WCSUNITS_PLANE_ANGLE] += 1.0; BEGIN(EXPON); } erg { /* Rule 063: Erg. */ factor *= 1e-7; types[WCSUNITS_MASS] += 1.0; types[WCSUNITS_LENGTH] += 2.0; types[WCSUNITS_TIME] -= 2.0; BEGIN(EXPON); } eV { /* Rule 064: Electron volt. */ factor *= 1.6021765e-19; types[WCSUNITS_MASS] += 1.0; types[WCSUNITS_LENGTH] += 2.0; types[WCSUNITS_TIME] -= 2.0; BEGIN(EXPON); } F { /* Rule 065: Farad. */ types[WCSUNITS_MASS] -= 1.0; types[WCSUNITS_LENGTH] -= 2.0; types[WCSUNITS_TIME] += 3.0; types[WCSUNITS_CHARGE] += 2.0; BEGIN(EXPON); } G { /* Rule 066: Gauss. */ factor *= 1e-4; types[WCSUNITS_MASS] += 1.0; types[WCSUNITS_TIME] += 1.0; types[WCSUNITS_CHARGE] -= 1.0; BEGIN(EXPON); } g { /* Rule 067: Gram. */ factor *= 1e-3; types[WCSUNITS_MASS] += 1.0; BEGIN(EXPON); } H { /* Rule 068: Henry. */ types[WCSUNITS_MASS] += 1.0; types[WCSUNITS_LENGTH] += 2.0; types[WCSUNITS_TIME] += 2.0; types[WCSUNITS_CHARGE] -= 2.0; BEGIN(EXPON); } h { /* Rule 069: Hour. */ factor *= 3600.0; types[WCSUNITS_TIME] += 1.0; BEGIN(EXPON); } Hz { /* Rule 070: Hertz. */ types[WCSUNITS_TIME] -= 1.0; BEGIN(EXPON); } J { /* Rule 071: Joule. */ types[WCSUNITS_MASS] += 1.0; types[WCSUNITS_LENGTH] += 2.0; types[WCSUNITS_TIME] -= 2.0; BEGIN(EXPON); } Jy { /* Rule 072: Jansky. */ factor *= 1e-26; types[WCSUNITS_MASS] += 1.0; types[WCSUNITS_TIME] -= 2.0; BEGIN(EXPON); } K { /* Rule 073: Kelvin. */ types[WCSUNITS_TEMPERATURE] += 1.0; BEGIN(EXPON); } lm { /* Rule 074: Lumen. */ types[WCSUNITS_LUMINTEN] += 1.0; types[WCSUNITS_SOLID_ANGLE] += 1.0; BEGIN(EXPON); } lx { /* Rule 075: Lux. */ types[WCSUNITS_LUMINTEN] += 1.0; types[WCSUNITS_SOLID_ANGLE] += 1.0; types[WCSUNITS_LENGTH] -= 2.0; BEGIN(EXPON); } lyr { /* Rule 076: Light year. */ factor *= 2.99792458e8 * 31557600.0; types[WCSUNITS_LENGTH] += 1.0; BEGIN(EXPON); } m { /* Rule 077: Metre. */ types[WCSUNITS_LENGTH] += 1.0; BEGIN(EXPON); } mag { /* Rule 078: Stellar magnitude. */ types[WCSUNITS_MAGNITUDE] += 1.0; BEGIN(EXPON); } mas { /* Rule 079: Milli-arcsec. */ factor /= 3600e+3; types[WCSUNITS_PLANE_ANGLE] += 1.0; BEGIN(EXPON); } min { /* Rule 080: Minute. */ factor *= 60.0; types[WCSUNITS_TIME] += 1.0; BEGIN(EXPON); } mol { /* Rule 081: Mole. */ types[WCSUNITS_MOLE] += 1.0; BEGIN(EXPON); } N { /* Rule 082: Newton. */ types[WCSUNITS_MASS] += 1.0; types[WCSUNITS_LENGTH] += 1.0; types[WCSUNITS_TIME] -= 2.0; BEGIN(EXPON); } [Oo]hm { /* Rule 083: Ohm. */ types[WCSUNITS_MASS] += 1.0; types[WCSUNITS_LENGTH] += 2.0; types[WCSUNITS_TIME] -= 1.0; types[WCSUNITS_CHARGE] -= 2.0; BEGIN(EXPON); } Pa { /* Rule 084: Pascal. */ types[WCSUNITS_MASS] += 1.0; types[WCSUNITS_LENGTH] -= 1.0; types[WCSUNITS_TIME] -= 2.0; BEGIN(EXPON); } pc { /* Rule 085: Parsec. */ factor *= 3.0857e16; types[WCSUNITS_LENGTH] += 1.0; BEGIN(EXPON); } photon|ph { /* Rule 086: Photon. */ types[WCSUNITS_COUNT] += 1.0; BEGIN(EXPON); } pixel|pix { /* Rule 087: Pixel. */ types[WCSUNITS_PIXEL] += 1.0; BEGIN(EXPON); } R { /* Rule 088: Rayleigh. */ factor *= 1e10 / (4.0 * PI); types[WCSUNITS_LENGTH] -= 2.0; types[WCSUNITS_TIME] -= 1.0; types[WCSUNITS_SOLID_ANGLE] -= 1.0; BEGIN(EXPON); } rad { /* Rule 089: Radian. */ factor *= 180.0 / PI; types[WCSUNITS_PLANE_ANGLE] += 1.0; BEGIN(EXPON); } Ry { /* Rule 090: Rydberg. */ factor *= 13.605692 * 1.6021765e-19; types[WCSUNITS_MASS] += 1.0; types[WCSUNITS_LENGTH] += 2.0; types[WCSUNITS_TIME] -= 2.0; BEGIN(EXPON); } S { /* Rule 091: Siemen. */ types[WCSUNITS_MASS] -= 1.0; types[WCSUNITS_LENGTH] -= 2.0; types[WCSUNITS_TIME] += 1.0; types[WCSUNITS_CHARGE] += 2.0; BEGIN(EXPON); } s { /* Rule 092: Second. */ types[WCSUNITS_TIME] += 1.0; BEGIN(EXPON); } solLum { /* Rule 093: Solar luminosity. */ factor *= 3.8268e26; types[WCSUNITS_MASS] += 1.0; types[WCSUNITS_LENGTH] += 2.0; types[WCSUNITS_TIME] -= 3.0; BEGIN(EXPON); } solMass { /* Rule 094: Solar mass. */ factor *= 1.9891e30; types[WCSUNITS_MASS] += 1.0; BEGIN(EXPON); } solRad { /* Rule 095: Solar radius. */ factor *= 6.9599e8; types[WCSUNITS_LENGTH] += 1.0; BEGIN(EXPON); } sr { /* Rule 096: Steradian. */ types[WCSUNITS_SOLID_ANGLE] += 1.0; BEGIN(EXPON); } Sun { /* Rule 097: Sun (with respect to). */ types[WCSUNITS_SOLRATIO] += 1.0; BEGIN(EXPON); } T { /* Rule 098: Tesla. */ types[WCSUNITS_MASS] += 1.0; types[WCSUNITS_TIME] += 1.0; types[WCSUNITS_CHARGE] -= 1.0; BEGIN(EXPON); } u { /* Rule 099: Unified atomic mass unit. */ factor *= 1.6605387e-27; types[WCSUNITS_MASS] += 1.0; BEGIN(EXPON); } V { /* Rule 100: Volt. */ types[WCSUNITS_MASS] += 1.0; types[WCSUNITS_LENGTH] += 1.0; types[WCSUNITS_TIME] -= 2.0; types[WCSUNITS_CHARGE] -= 1.0; BEGIN(EXPON); } voxel { /* Rule 101: Voxel. */ types[WCSUNITS_VOXEL] += 1.0; BEGIN(EXPON); } W { /* Rule 102: Watt. */ types[WCSUNITS_MASS] += 1.0; types[WCSUNITS_LENGTH] += 2.0; types[WCSUNITS_TIME] -= 3.0; BEGIN(EXPON); } Wb { /* Rule 103: Weber. */ types[WCSUNITS_MASS] += 1.0; types[WCSUNITS_LENGTH] += 2.0; types[WCSUNITS_TIME] += 1.0; types[WCSUNITS_CHARGE] -= 1.0; BEGIN(EXPON); } . { /* Rule 104: Internal parser error. */ status = 9; BEGIN(FLUSH); } " "*("**"|^) { /* Rule 105: Exponentiation. */ if (operator++) { BEGIN(FLUSH); } } " "*{INTEGER} { /* Rule 106. */ sscanf(yytext, " %d", &i); expon *= (double)i; wcsulex_add(&factor, types, &expon, scale, units); operator = 0; BEGIN(INITIAL); } " "*"("" "*{INTEGER}" "*")" { /* Rule 107. */ sscanf(yytext, " (%d)", &i); expon *= (double)i; wcsulex_add(&factor, types, &expon, scale, units); operator = 0; BEGIN(INITIAL); } " "*"("" "*{FRAC}" "*")" { /* Rule 108. */ sscanf(yytext, " (%d/%d)", &i, &j); expon *= (double)i / (double)j; wcsulex_add(&factor, types, &expon, scale, units); operator = 0; BEGIN(INITIAL); } " "*"("" "*{FLOAT}" "*")" { /* Rule 109. */ sscanf(yytext, " (%lf)", &dexp); expon *= dexp; wcsulex_add(&factor, types, &expon, scale, units); operator = 0; BEGIN(INITIAL); } " "*[.*]" "* { /* Rule 110: Multiply. */ if (operator++) { BEGIN(FLUSH); } else { wcsulex_add(&factor, types, &expon, scale, units); BEGIN(INITIAL); } } " "*"(" { /* Rule 111: Multiply. */ if (operator) { BEGIN(FLUSH); } else { wcsulex_add(&factor, types, &expon, scale, units); unput('('); BEGIN(INITIAL); } } " "+ { /* Rule 112: Multiply. */ if (operator) { BEGIN(FLUSH); } else { wcsulex_add(&factor, types, &expon, scale, units); BEGIN(INITIAL); } } " "*"/"" "* { /* Rule 113: Divide. */ if (operator++) { BEGIN(FLUSH); } else { wcsulex_add(&factor, types, &expon, scale, units); expon = -1.0; BEGIN(INITIAL); } } " "*"]" { /* Rule 114. */ wcsulex_add(&factor, types, &expon, scale, units); bracket = !bracket; BEGIN(FLUSH); } . { /* Rule 115. */ status = 5; BEGIN(FLUSH); } .* { /* Rule 116: Discard any remaining input. */ } <> { /* Rule unnumbered: End-of-string. */ if (YY_START == EXPON) { wcsulex_add(&factor, types, &expon, scale, units); } yylex_destroy(); if (bracket) { status = 6; } else if (paren) { status = 7; } else if (operator) { status = (operator == 1) ? 2 : 8; #ifdef DEBUG } else { printf("EOS\n"); #endif } if (status) { for (i = 0; i < WCSUNITS_NTYPE; i++) { units[i] = 0.0; *scale = 0.0; } } return status; } %% /*---------------------------------------------------------------------------- * Accumulate a term in a units specification and reset work variables. *---------------------------------------------------------------------------*/ void wcsulex_add( double *factor, double types[], double *expon, double *scale, double units[]) { int i; *scale *= pow(*factor, *expon); for (i = 0; i < WCSUNITS_NTYPE; i++) { units[i] += *expon * types[i]; types[i] = 0.0; } *expon = 1.0; *factor = 1.0; return; }