%{

/*
 * lex(1) specification for tokens for the Unidata units package, udunits.
 */

#ifndef _XOPEN_SOURCE
#   define _XOPEN_SOURCE
#endif
#ifndef _ANSI_C_SOURCE
#   define _ANSI_C_SOURCE
#endif

#include <udposix.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <errno.h>
#include <math.h>
#include <time.h>
#include "udunits.h"
#include "utprivate.h"	/* private definitions */
#include "utparse.h"	/* #include "udunits.h" before this one */
#include "utscan.h"

%}

space		([ \t])
integer		([+-]?[0-9]+)
exp		([eE][+-]?[0-9]+)
real		([+-]?[0-9]*("."[0-9]*{exp}?|{exp}))
year		([+-]?[0-9]{1,4})
month		(0?[1-9]|1[0-2])
day		(0?[1-9]|[1-2][0-9]|30|31)
hour		([0-1]?[0-9]|2[0-3])
minute		([0-5]?[0-9])
second		(({minute}|60)("."[0-9]*)?)
name		(%|[a-zA-Z][a-zA-Z_]*([0-9]+[a-zA-Z_]+)*)

%Start		shift_seen date_seen time_seen

%%

"#".* {
    /* comment */ ;
}

{space}*("@"|after|AFTER|from|FROM|since|SINCE|ref|REF){space}* {
    BEGIN shift_seen;
    return SHIFT;
}

{space}*(per|PER|"/"){space}* {
    BEGIN 0;
    return DIVIDE;
}

"-"|"."|"*"|{space}+ {
    BEGIN 0;
    return MULTIPLY;
}

"^"|"**" {
    BEGIN 0;
    return EXPONENT;
}

<shift_seen>{year}"-"{month}"-"{day}T?{space}* {
    int		year;
    int		month;
    int		day;

    (void) sscanf((char*)yytext, "%d-%d-%d", &year, &month, &day);
    yylval.rval	= utencdate(year, month, day);

    BEGIN date_seen;
    return DATE;
}

<shift_seen>now{space}* {
    time_t	now;
    struct tm	*tp;

    errno	= 0;
    if (time(&now) == -1) {
	(void) fprintf(stderr, "udunits(3): Can't get current time. %s\n",
		       strerror(errno));
	return ERR;
    }

    if ((tp = gmtime(&now)) == NULL) {
	(void) fprintf(stderr, "udunits(3): can't get UTC time\n");
	return ERR;
    }
    yylval.rval	= utencdate(1900+tp->tm_year, 1+tp->tm_mon, tp->tm_mday) +
		  utencclock(tp->tm_hour, tp->tm_min, (double)tp->tm_sec);

    BEGIN 0;
    return REAL;
}

<date_seen>{hour}(":"{minute}(":"{second})?)?{space}* {
    int		hour;
    int		minute	= 0;
    double	second	= 0.0;

    (void) sscanf((char*)yytext, "%d:%d:%lf", &hour, &minute, &second);
    yylval.rval	= utencclock(hour, minute, second);

    BEGIN time_seen;
    return TIME;
}

<date_seen>[0-2][0-9][0-5][0-9]{space}* {
    int		hour;
    int		minute;

    (void) sscanf((char*)yytext, "%2d%2d", &hour, &minute);
    if (hour >= 24 || minute >= 60)
	return ERR;
    yylval.rval	= utencclock(hour, minute, 0.0);

    BEGIN time_seen;
    return TIME;
}

<date_seen>([0-9][0-5][0-9]){space}* {
    int		hour;
    int		minute;

    (void) sscanf((char*)yytext, "%1d%2d", &hour, &minute);
    if (minute >= 60)
	return ERR;
    yylval.rval	= utencclock(hour, minute, 0.0);

    BEGIN time_seen;
    return TIME;
}

<time_seen>UTC{space}* {
    yylval.rval	= 0;

    BEGIN 0;
    return ZONE;
}

<time_seen>([+-]?{hour}":"{minute}){space}* {
    int		hour;
    int		minute;

    (void) sscanf((char*)yytext, "%d:%d", &hour, &minute);
    if (hour < 0)
	minute	= -minute;

    yylval.rval	= utencclock(hour, minute, 0.0);

    BEGIN 0;
    return ZONE;
}

<time_seen>([+-]?{hour}":"?){space}* {
    int		hour;

    (void) sscanf((char*)yytext, "%d", &hour);

    yylval.rval	= utencclock(hour, 0, 0.0);

    BEGIN 0;
    return ZONE;
}

<time_seen>([+-]{hour}{minute}){space}* {
    int		zone;
    int		hour;
    int		minute;

    (void) sscanf((char*)yytext, "%d", &zone);
    minute	= zone < 0
		    ? -(-zone % 100)
		    :    zone % 100;
    hour	= (zone - minute) / 100;

    yylval.rval	= utencclock(hour, minute, 0.0);

    BEGIN 0;
    return ZONE;
}

{name} {
    if (strlen((char*)yytext) > UT_NAMELEN-1)
	(void) fprintf(stderr, "udunits(3): Name `%s' too long; truncated\n",
		       yytext);
    (void) strncpy(yylval.name, (char*)yytext, UT_NAMELEN-1);
    yylval.name[UT_NAMELEN-1]	= 0;

    BEGIN 0;
    return NAME;
}

{integer} {
    int		status;

    errno	= 0;
    yylval.ival = atol((char*)yytext);
    if (errno == 0) {
	status	= INT;
    } else {
	(void) fputs("udunits(3): Invalid integer\n", stderr);
	status	= ERR;
    }

    BEGIN 0;
    return status;
}

{real} {
    int		status;

    errno	= 0;
    yylval.rval = atof((char*)yytext);
    if (errno == 0) {
	status	= REAL;
    } else {
	(void) fputs("udunits(3): Invalid real\n", stderr);
	status	= ERR;
    }

    BEGIN 0;
    return status;
}

")" {
    BEGIN 0;
    return yytext[0];
}

. {
    return yytext[0];
}

%%

    void
utLexReset()
{
    BEGIN 0;
}


syntax highlighted by Code2HTML, v. 0.9.1