/***************************** LICENSE START ***********************************

 Copyright 2012 ECMWF and INPE. This software is distributed under the terms
 of the Apache License version 2.0. In applying this license, ECMWF does not
 waive the privileges and immunities granted to it by virtue of its status as
 an Intergovernmental Organization or submit itself to any jurisdiction.

 ***************************** LICENSE END *************************************/

%{
#include <setjmp.h>
#include <stdarg.h>

static char blank[256];
static int  blanks;
static FILE *file;
static char *tmp;
extern char* marstmp();

static jmp_buf env;
#define exit(a)        jumpexit(a)
#define fprintf        jumpprtf

static void jumpexit(int n)
{
	longjmp(env,1);
}

static void jumpprtf(FILE *f,char *fmt,...)
{
	va_list list;
	char buf[1024];
	int len;
	va_start(list,fmt);
	vsprintf(buf, fmt, list);
	va_end(list);

	len = strlen(buf);
	if(len && buf[len-1] == '\n')
		buf[len-1] = 0;
	yyerror(buf);
}
%}

BLANK   [ \t\n]+
IDENT   [_A-Za-z]+[_0-9A-Za-z]*
NUMB1   [0-9]+[\.]?[0-9]*
NUMB2   [0-9]*[\.]?[0-9]+
EXP     [eE][+\-]?[0-9]+
NUMB    {NUMB1}|{NUMB2}
EXPNUMB {NUMB1}{EXP}|{NUMB2}{EXP}

TIME1   [0-2][0-9]:[0-5][0-9]
TIME2   [0-2][0-9]:[0-5][0-9]:[0-5][0-9]
TIME    {TIME1}|{TIME2}

DATE2   [12][0-9][0-9][0-9]-[01][0-9]-[0-3][0-9]
DATE4   [12][0-9][0-9][0-9]-[0-3][0-9][0-9]
DATE    {DATE2}|{DATE4}

%s SOURCE

%%

<SOURCE>end{BLANK}inline  {
                            BEGIN INITIAL;
                            fclose(file);
                            yylval.str = tmp;
                            return ENDINLINE;
                            }

<SOURCE>.            fwrite(yytext,1,yyleng,file);
<SOURCE>{BLANK}      fwrite(yytext,1,yyleng,file);

<INITIAL>"if"        return IF;
<INITIAL>"then"      return THEN;
<INITIAL>"else"      return ELSE;
<INITIAL>"and"       return AND;
<INITIAL>"not"       return NOT;
<INITIAL>"or"        return OR;
<INITIAL>"function"  return FUNCTION;
<INITIAL>"return"    return RETURN;
<INITIAL>"end"       return END;
<INITIAL>"while"     return WHILE;
<INITIAL>"global"    return GLOBAL;
<INITIAL>"do"        return DO;
<INITIAL>"on"        return ON;
<INITIAL>"for"       return FOR;
<INITIAL>"to"        return TO;
<INITIAL>"by"        return BY;
<INITIAL>"in"        return IN;
<INITIAL>"of"        return OF;
<INITIAL>"case"      return CASE;
<INITIAL>"otherwise" return OTHERWISE;
<INITIAL>"repeat"    return REPEAT;
<INITIAL>"until"     return UNTIL;
<INITIAL>"loop"      return LOOP;
<INITIAL>"when"      return WHEN;
<INITIAL>"include"   return INCLUDE;
<INITIAL>"extern"    return EXTERN;
<INITIAL>"tell"      return TELL;
<INITIAL>"task"      return TASK;
<INITIAL>"nil"       return NIL;
<INITIAL>"object"    return OBJECT;
<INITIAL>"import"    return IMPORT;
<INITIAL>"export"    return EXPORT;
<INITIAL>inline[ \t]*\n  {
                        BEGIN SOURCE;
                        tmp  = (char*)strdup(marstmp());
                        file = fopen(tmp,"w");
                        return INLINE;
                     }
<INITIAL>"->"        return ARROW;
<INITIAL>"<>"        return NE;
<INITIAL>">="        return GE;
<INITIAL>"<="        return LE;
<INITIAL>"\*\*"      return '^';

<INITIAL>\#          {
                        int c;
                        while((c = input()) && (c != '\n') && (c != EOF) )
                            ;
                     }


<INITIAL>\"|\'       {
                        int c,q = yytext[0];

                        yyleng = 0;

                        while((c = input()) && c != q && c != '\n' && c != EOF)
                        {
                            if(c == '\\') yytext[yyleng++] = input();
                            else yytext[yyleng++] =  c;
                        }


                        yytext[yyleng++] = 0;
                        yylval.str = (char*)strdup(yytext);
                        return STRING;
                     }

<INITIAL>{DATE}      { yylval.str = (char*)strdup(yytext); return DATE; }
<INITIAL>{TIME}      { yylval.str = (char*)strdup(yytext); return TIME; }
<INITIAL>{IDENT}     { yylval.str = (char*)strdup(yytext); return WORD; }
<INITIAL>{NUMB}      { yylval.str = (char*)strdup(yytext); return NUMBER; }
<INITIAL>{EXPNUMB}   { yylval.str = (char*)strdup(yytext); return NUMBER; }
<INITIAL>{BLANK}     ;
<INITIAL>.           return *yytext;
%%

#ifndef BEAUTIFY

#define MAXINCLUDE 10

/* FLEX scanner modification according */
/* to Linux 'flex' man page section    */
/* titled 'MULTIPLE INPUT BUFFERS'.    */
/*                         (010810/vk) */

#ifdef FLEX_SCANNER
static YY_BUFFER_STATE fstack[MAXINCLUDE];
#else
static FILE *fstack[MAXINCLUDE];
#endif

static int   ftop = 0;


static void include(char *name)
{
   FILE* fin;

   if( ftop == MAXINCLUDE )
     {
        yyerror( "Includes nested too deeply" );
        return;
     }

#ifdef FLEX_SCANNER
   fin = fopen( name, "r" );
   if ( fin )
     {
        fstack[ftop++] = YY_CURRENT_BUFFER;
        yyin = fin;
        yy_switch_to_buffer( yy_create_buffer( yyin, YY_BUF_SIZE ) );
        BEGIN(INITIAL);
     }
   else
     {
	perror(name);
        yyerror( "Cannot include file" );
     }
#else
    fstack[ftop++] = yyin;
    yyin = fopen(name,"r");
    if(yyin == nullptr)
	{
		perror(name);
		yyerror("Cannot include file");
		yyin = fstack[--ftop];
	}
#endif
}

int yywrap()
{
    if(ftop)
    {
#ifdef FLEX_SCANNER
        yy_delete_buffer( YY_CURRENT_BUFFER );
        yy_switch_to_buffer( fstack[--ftop] );
#else
        yyin = fstack[--ftop];
#endif
        return 0;
    }
    return 1;
}


void start_inline()
{
}

int parse_macro(void)
{
	if(setjmp(env))
		return 1;
	return yyparse();
}

#endif
