"Fossies" - the Fresh Open Source Software Archive

Member "udunits-2.2.28/lib/parser.y" (7 Dec 2020, 14939 Bytes) of package /linux/privat/udunits-2.2.28.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Bison source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. See also the latest Fossies "Diffs" side-by-side code changes report for "parser.y": 2.2.26_vs_2.2.28.

    1 %{
    2 /*
    3  * Copyright 2020 University Corporation for Atmospheric Research. All rights
    4  * reserved.
    5  *
    6  * This file is part of the UDUNITS-2 package.  See the file COPYRIGHT
    7  * in the top-level source-directory of the package for copying and
    8  * redistribution conditions.
    9  */
   10 /*
   11  * bison(1)-based parser for decoding formatted unit specifications.
   12  *
   13  * This module is thread-compatible but not thread-safe: multi-threaded access
   14  * must be externally synchronized.
   15  */
   16 
   17 /*LINTLIBRARY*/
   18 
   19 #include "config.h"
   20 
   21 #include "prefix.h"
   22 #include "udunits2.h"
   23 
   24 #include <assert.h>
   25 #include <ctype.h>
   26 #include <errno.h>
   27 #include <stddef.h>
   28 #include <stdio.h>
   29 #include <stdlib.h>
   30 #include <string.h>
   31 #ifndef _MSC_VER
   32 #include <strings.h>
   33 #endif
   34 
   35 extern int utlex (void);
   36 
   37 static ut_unit*     _finalUnit; /* fully-parsed specification */
   38 static ut_system*   _unitSystem;    /* The unit-system to use */
   39 static char*        _errorMessage;  /* last error-message */
   40 static ut_encoding  _encoding;  /* encoding of string to be parsed */
   41 static int      _restartScanner;/* restart scanner? */
   42 static int      _isTime;        /* product_exp is time? */
   43 
   44 
   45 /*
   46  * Removes leading and trailing whitespace from a string.
   47  *
   48  * Arguments:
   49  *  string      NUL-terminated string.  Will be modified if it
   50  *                      contains whitespace.
   51  *  encoding    The character-encoding of "string".
   52  * Returns:
   53  *      "string"
   54  */
   55 char*
   56 ut_trim(
   57     char* const         string,
   58     const ut_encoding   encoding)
   59 {
   60     static const char*  asciiSpace = " \t\n\r\f\v";
   61     static const char*  latin1Space = " \t\n\r\f\v\xa0";    /* add NBSP */
   62     const char*     whiteSpace;
   63     char*       start;
   64     char*       stop;
   65     size_t              len;
   66 
   67     whiteSpace =
   68     encoding == UT_LATIN1
   69         ? latin1Space
   70         : asciiSpace;
   71 
   72     start = string + strspn(string, whiteSpace);
   73 
   74     for (stop = start + strlen(start); stop > start; --stop)
   75      if (strchr(whiteSpace, stop[-1]) == NULL)
   76         break;
   77 
   78     len = stop - start;
   79 
   80     (void)memmove(string, start, len);
   81 
   82     string[len] = 0;
   83 
   84     ut_set_status(UT_SUCCESS);
   85 
   86     return start;
   87 }
   88 
   89 
   90 /*
   91  *  YACC error routine:
   92  */
   93 void
   94 uterror(
   95     char            *s)
   96 {
   97     static char*    nomem = "uterror(): out of memory";
   98 
   99     if (_errorMessage != NULL && _errorMessage != nomem)
  100     free(_errorMessage);
  101 
  102     _errorMessage = strdup(s);
  103 
  104     if (_errorMessage == NULL)
  105     _errorMessage = nomem;
  106 }
  107 
  108 /**
  109  * Parses an integer value into broken-down clock-time. The value is assumed to
  110  * have the form H[H[MM[SS]]].
  111  *
  112  * @param[in]  value   The integer value.
  113  * @param[out] hour    The hour field.
  114  * @param[out] minute  The minute field. Set to zero if appropriate.
  115  * @param[out] second  The second field. Set to zero if appropriate.
  116  */
  117 static void to_clock(
  118     unsigned long       value,
  119     unsigned* const     hour,
  120     unsigned* const     minute,
  121     unsigned* const     second)
  122 {
  123     if (value > 0)
  124         while (value < 10000)
  125             value *= 10;
  126 
  127     *hour = value / 10000;
  128     *minute = (value % 10000) / 100;
  129     *second = value % 100;
  130 }
  131 
  132 /**
  133  * Converts an integer value into a timezone offset as used by this package.
  134  *
  135  * @param[in]  value  The integer value. Must correspond to [+|-]H[H[MM]].
  136  * @param[out] time   The corresponding time as used by this package.
  137  * @retval     0      Success. "*time" is set.
  138  * @retval     -1     The integer value is invalid.
  139  */
  140 static int timezone_to_time(
  141     const long    value,
  142     double* const time)
  143 {
  144     unsigned hour, minute, second;
  145 
  146     if (value < -2400 || value > 2400)
  147         return -1;
  148 
  149     to_clock(value < 0 ? -value : value, &hour, &minute, &second);
  150 
  151     if (hour > 24 || minute >= 60)
  152         return -1;
  153 
  154     *time = (value >= 0)
  155             ? ut_encode_clock(hour, minute, second)
  156             : -ut_encode_clock(hour, minute, second);
  157 
  158     return 0;
  159 }
  160 
  161 /**
  162  * Converts an integer value into a time as used by this package.
  163  *
  164  * @param[in]  value  The integer value. Must correspond to H[H[MM[SS]]].
  165  * @param[out] time   The corresponding time as used by this package.
  166  * @retval     0      Success. "*time" is set.
  167  * @retval     -1     The integer value is invalid.
  168  */
  169 static int clock_to_time(
  170     const long    value,
  171     double* const time)
  172 {
  173     unsigned hour, minute, second;
  174 
  175     if (value < 0)
  176         return -1;
  177 
  178     to_clock(value, &hour, &minute, &second);
  179 
  180     if (hour > 24 || minute >= 60 || second > 60) /* allow leap second */
  181         return -1;
  182 
  183     *time = ut_encode_clock(hour, minute, second);
  184 
  185     return 0;
  186 }
  187 
  188 /**
  189  * Indicates if a unit is a (non-offset) time unit.
  190  *
  191  * @param[in] unit      The unit to be checked.
  192  * @retval    0         If and only if the unit is not a time unit.
  193  */
  194 static int isTime(
  195     const ut_unit* const unit)
  196 {
  197     ut_status   prev = ut_get_status();
  198     ut_unit*    second = ut_get_unit_by_name(_unitSystem, "second");
  199     int         isTime = ut_are_convertible(unit, second);
  200 
  201     ut_free(second);
  202     ut_set_status(prev);
  203     return isTime;
  204 }
  205 
  206 %}
  207 
  208 %union {
  209     char*   id;         /* identifier */
  210     ut_unit*    unit;           /* "unit" structure */
  211     double  rval;           /* floating-point numerical value */
  212     long    ival;           /* integer numerical value */
  213 }
  214 
  215 %token      ERR
  216 %token      SHIFT
  217 %token      MULTIPLY
  218 %token      DIVIDE
  219 %token  <ival>  INT
  220 %token  <ival>  EXPONENT
  221 %token  <rval>  REAL
  222 %token  <id>    ID
  223 %token  <rval>  DATE
  224 %token  <rval>  CLOCK
  225 %token  <rval>  TIMESTAMP
  226 %token  <rval>  LOGREF
  227 
  228 %type   <unit>  unit_spec
  229 %type   <unit>  shift_exp
  230 %type   <unit>  product_exp
  231 %type   <unit>  power_exp
  232 %type   <unit>  basic_exp
  233 %type   <rval>  timestamp
  234 %type   <rval>  number
  235 
  236 %%
  237 
  238 unit_spec:      /* nothing */ {
  239             _finalUnit = ut_get_dimensionless_unit_one(_unitSystem);
  240             YYACCEPT;
  241         } |
  242         shift_exp {
  243             _finalUnit = $1;
  244             YYACCEPT;
  245         } |
  246         error {
  247             YYABORT;
  248         }
  249         ;
  250 
  251 shift_exp:  product_exp {
  252             $$ = $1;
  253         } |
  254         product_exp SHIFT REAL {
  255             $$ = ut_offset($1, $3);
  256             ut_free($1);
  257             if ($$ == NULL)
  258             YYERROR;
  259         } |
  260         product_exp SHIFT INT {
  261             $$ = ut_offset($1, $3);
  262             ut_free($1);
  263             if ($$ == NULL)
  264             YYERROR;
  265         } |
  266         product_exp SHIFT timestamp {
  267             $$ = ut_offset_by_time($1, $3);
  268             ut_free($1);
  269             if ($$ == NULL)
  270             YYERROR;
  271         } |
  272         product_exp SHIFT error {
  273             ut_status   prev = ut_get_status();
  274             ut_free($1);
  275             ut_set_status(prev);
  276             YYERROR;
  277         }
  278         ;
  279 
  280 product_exp:    power_exp {
  281             $$ = $1;
  282                     _isTime = isTime($$);
  283         } |
  284         product_exp power_exp   {
  285             $$ = ut_multiply($1, $2);
  286                     _isTime = isTime($$);
  287             ut_free($1);
  288             ut_free($2);
  289             if ($$ == NULL)
  290             YYERROR;
  291         } |
  292         product_exp error   {
  293             ut_status   prev = ut_get_status();
  294             ut_free($1);
  295             ut_set_status(prev);
  296             YYERROR;
  297         } |
  298         product_exp MULTIPLY power_exp  {
  299             $$ = ut_multiply($1, $3);
  300                     _isTime = isTime($$);
  301             ut_free($1);
  302             ut_free($3);
  303             if ($$ == NULL)
  304             YYERROR;
  305         } |
  306         product_exp MULTIPLY error  {
  307             ut_status   prev = ut_get_status();
  308             ut_free($1);
  309             ut_set_status(prev);
  310             YYERROR;
  311         } |
  312         product_exp DIVIDE power_exp    {
  313             $$ = ut_divide($1, $3);
  314                     _isTime = isTime($$);
  315             ut_free($1);
  316             ut_free($3);
  317             if ($$ == NULL)
  318             YYERROR;
  319         } |
  320         product_exp DIVIDE error    {
  321             ut_status   prev = ut_get_status();
  322             ut_free($1);
  323             ut_set_status(prev);
  324             YYERROR;
  325         }
  326         ;
  327 
  328 power_exp:  basic_exp {
  329             $$ = $1;
  330         } |
  331         basic_exp INT {
  332             $$ = ut_raise($1, $2);
  333             ut_free($1);
  334             if ($$ == NULL)
  335             YYERROR;
  336         } |
  337         basic_exp EXPONENT {
  338             $$ = ut_raise($1, $2);
  339             ut_free($1);
  340             if ($$ == NULL)
  341             YYERROR;
  342         } |
  343         basic_exp error {
  344             ut_status   prev = ut_get_status();
  345             ut_free($1);
  346             ut_set_status(prev);
  347             YYERROR;
  348         }
  349         ;
  350 
  351 basic_exp:  ID {
  352             double  prefix = 1;
  353             ut_unit*    unit = NULL;
  354             char*   cp = $1;
  355             int     symbolPrefixSeen = 0;
  356 
  357             while (*cp) {
  358             size_t  nchar;
  359             double  value;
  360 
  361             unit = ut_get_unit_by_name(_unitSystem, cp);
  362 
  363             if (unit != NULL)
  364                 break;
  365 
  366             unit = ut_get_unit_by_symbol(_unitSystem, cp);
  367 
  368             if (unit != NULL)
  369                 break;
  370 
  371             if (utGetPrefixByName(_unitSystem, cp, &value, &nchar)
  372                 == UT_SUCCESS) {
  373                 prefix *= value;
  374                 cp += nchar;
  375             }
  376             else {
  377                 if (!symbolPrefixSeen &&
  378                     utGetPrefixBySymbol(_unitSystem, cp, &value,
  379                     &nchar) == UT_SUCCESS) {
  380                 symbolPrefixSeen = 1;
  381                 prefix *= value;
  382                 cp += nchar;
  383                 }
  384                 else {
  385                 break;
  386                 }
  387             }
  388             }
  389 
  390             free($1);
  391 
  392             if (unit == NULL) {
  393             ut_set_status(UT_UNKNOWN);
  394             YYERROR;
  395             }
  396 
  397             $$ = ut_scale(prefix, unit);
  398 
  399             ut_free(unit);
  400 
  401             if ($$ == NULL)
  402             YYERROR;
  403         } |
  404         '(' shift_exp ')' {
  405             $$ = $2;
  406         } |
  407         '(' shift_exp error {
  408             ut_status   status = ut_get_status();
  409             ut_free($2);
  410             ut_set_status(status);
  411             YYERROR;
  412         } |
  413         LOGREF product_exp ')' {
  414             $$ = ut_log($1, $2);
  415             ut_free($2);
  416             if ($$ == NULL)
  417             YYERROR;
  418         } |
  419         LOGREF product_exp error {
  420             ut_status   status = ut_get_status();
  421             ut_free($2);
  422             ut_set_status(status);
  423             YYERROR;
  424         } |
  425         number {
  426             $$ = ut_scale($1,
  427                         ut_get_dimensionless_unit_one(_unitSystem));
  428         }
  429         ;
  430 
  431 number:     INT {
  432             $$ = $1;
  433         } |
  434         REAL {
  435             $$ = $1;
  436         }
  437         ;
  438 
  439 timestamp:  DATE {
  440             $$ = $1;
  441         } |
  442         DATE CLOCK {
  443             $$ = $1 + $2;
  444         } |
  445         DATE CLOCK CLOCK {
  446             $$ = $1 + ($2 - $3);
  447         } |
  448         DATE CLOCK ID {
  449             int error = 0;
  450 
  451             if (strcasecmp($3, "UTC") != 0 &&
  452                 strcasecmp($3, "GMT") != 0 &&
  453                 strcasecmp($3, "Z") != 0) {
  454             ut_set_status(UT_UNKNOWN);
  455             error = 1;
  456             }
  457 
  458             free($3);
  459 
  460             if (!error) {
  461             $$ = $1 + $2;
  462             }
  463             else {
  464             YYERROR;
  465             }
  466         } |
  467         TIMESTAMP {
  468             $$ = $1;
  469         } |
  470         TIMESTAMP CLOCK {
  471             $$ = $1 - $2;
  472         } |
  473         TIMESTAMP ID {
  474             int error = 0;
  475 
  476             if (strcasecmp($2, "UTC") != 0 &&
  477                 strcasecmp($2, "GMT") != 0 &&
  478                 strcasecmp($2, "Z") != 0) {
  479             ut_set_status(UT_UNKNOWN);
  480             error = 1;
  481             }
  482 
  483             free($2);
  484 
  485             if (!error) {
  486             $$ = $1;
  487             }
  488             else {
  489             YYERROR;
  490             }
  491         }
  492         ;
  493 
  494 %%
  495 
  496 #define yymaxdepth  utmaxdepth
  497 #define yylval      utlval
  498 #define yychar      utchar
  499 #define yypact      utpact
  500 #define yyr1        utr1
  501 #define yyr2        utr2
  502 #define yydef       utdef
  503 #define yychk       utchk
  504 #define yypgo       utpgo
  505 #define yyact       utact
  506 #define yyexca      utexca
  507 #define yyerrflag   uterrflag
  508 #define yynerrs     utnerrs
  509 #define yyps        utps
  510 #define yypv        utpv
  511 #define yys     uts
  512 #define yy_yys      utyys
  513 #define yystate     utstate
  514 #define yytmp       uttmp
  515 #define yyv     utv
  516 #define yy_yyv      utyyv
  517 #define yyval       utval
  518 #define yylloc      utlloc
  519 #define yyreds      utreds
  520 #define yytoks      uttoks
  521 #define yylhs       utyylhs
  522 #define yydefred    utyydefred
  523 #define yydgoto     utyydgoto
  524 #define yysindex    utyysindex
  525 #define yyrindex    utyyrindex
  526 #define yygindex    utyygindex
  527 #define yytable     utyytable
  528 #define yycheck     utyycheck
  529 #define yyname      utyyname
  530 #define yyrule      utyyrule
  531 
  532 #include "scanner.c"
  533 
  534 
  535 /*
  536  * Converts a string in the Latin-1 character set (ISO 8859-1) to the UTF-8
  537  * character set.
  538  *
  539  * Arguments:
  540  *      latin1String    Pointer to the string to be converted.  May be freed
  541  *                      upon return.
  542  * Returns:
  543  *      NULL            Failure.  ut_handle_error_message() was called.
  544  *      else            Pointer to UTF-8 representation of "string".  Must not
  545  *                      be freed.  Subsequent calls may overwrite.
  546  */
  547 static const char*
  548 latin1ToUtf8(
  549     const char* const   latin1String)
  550 {
  551     static char*                utf8String = NULL;
  552     static size_t               bufSize = 0;
  553     size_t                      size;
  554     const unsigned char*        in;
  555     unsigned char*              out;
  556 
  557     assert(latin1String != NULL);
  558 
  559     size = 2 * strlen(latin1String) + 1;
  560 
  561     if (size > bufSize) {
  562         char*   buf = realloc(utf8String, size);
  563 
  564         if (buf != NULL) {
  565             utf8String = buf;
  566             bufSize = size;
  567         }
  568         else {
  569             ut_handle_error_message("Couldn't allocate %ld-byte buffer: %s",
  570                 (unsigned long)size, strerror(errno));
  571             return NULL;
  572         }
  573     }
  574 
  575     if (utf8String) {
  576         for (in = (const unsigned char*)latin1String,
  577                 out = (unsigned char*)utf8String; *in; ++in) {
  578 #           define IS_ASCII(c) (((c) & 0x80) == 0)
  579 
  580             if (IS_ASCII(*in)) {
  581                 *out++ = *in;
  582             }
  583             else {
  584                 *out++ = 0xC0 | ((0xC0 & *in) >> 6);
  585                 *out++ = 0x80 | (0x3F & *in);
  586             }
  587         }
  588 
  589         *out = 0;
  590     }
  591 
  592     return utf8String;
  593 }
  594 
  595 
  596 /*
  597  * Returns the binary representation of a unit corresponding to a string
  598  * representation.
  599  *
  600  * Arguments:
  601  *  system      Pointer to the unit-system in which the parsing will
  602  *          occur.
  603  *  string      The string to be parsed (e.g., "millimeters").  There
  604  *          should be no leading or trailing whitespace in the
  605  *          string.  See ut_trim().
  606  *  encoding    The encoding of "string".
  607  * Returns:
  608  *  NULL        Failure.  "ut_get_status()" will be one of
  609  *              UT_BAD_ARG      "system" or "string" is NULL.
  610  *              UT_SYNTAX       "string" contained a syntax
  611  *                      error.
  612  *              UT_UNKNOWN      "string" contained an unknown
  613  *                      identifier.
  614  *              UT_OS       Operating-system failure.  See
  615  *                      "errno".
  616  *  else        Pointer to the unit corresponding to "string".
  617  */
  618 ut_unit*
  619 ut_parse(
  620     const ut_system* const  system,
  621     const char* const       string,
  622     ut_encoding         encoding)
  623 {
  624     ut_unit*    unit = NULL;        /* failure */
  625 
  626     if (system == NULL || string == NULL) {
  627     ut_set_status(UT_BAD_ARG);
  628     }
  629     else {
  630         const char*     utf8String;
  631 
  632         if (encoding != UT_LATIN1) {
  633             utf8String = string;
  634         }
  635         else {
  636             utf8String = latin1ToUtf8(string);
  637             encoding = UT_UTF8;
  638 
  639             if (utf8String == NULL)
  640                 ut_set_status(UT_OS);
  641         }
  642 
  643         if (utf8String != NULL) {
  644             YY_BUFFER_STATE buf = ut_scan_string(utf8String);
  645 
  646             _unitSystem = (ut_system*)system;
  647             _encoding = encoding;
  648             _restartScanner = 1;
  649 
  650 #if YYDEBUG
  651             utdebug = 0;
  652             ut_flex_debug = 0;
  653 #endif
  654 
  655             _finalUnit = NULL;
  656 
  657             if (utparse() == 0) {
  658                 int       status;
  659                 ptrdiff_t n = yy_c_buf_p  - buf->yy_ch_buf;
  660 
  661                 if (n >= strlen(utf8String)) {
  662                     unit = _finalUnit;  /* success */
  663                     status = UT_SUCCESS;
  664                 }
  665                 else {
  666                     /*
  667                      * Parsing terminated before the end of the string.
  668                      */
  669                     ut_free(_finalUnit);
  670                     status = UT_SYNTAX;
  671                 }
  672 
  673                 ut_set_status(status);
  674             }
  675 
  676             ut_delete_buffer(buf);
  677         }                               /* utf8String != NULL */
  678     }                                   /* valid arguments */
  679 
  680     return unit;
  681 }