/* Lexical analyzer for calc program.

Copyright 2000, 2001, 2002 Free Software Foundation, Inc.

This file is part of the GNU MP Library.

This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 3 of the License, or (at your option) any later
version.

This program 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 General Public License for more details.

You should have received a copy of the GNU General Public License along with
this program.  If not, see http://www.gnu.org/licenses/.  */

%{
#include <string.h>
#include "calc-common.h"


#if WITH_READLINE
/* Let GNU flex use readline.  See the calcread.c redefined input() for a
   way that might work for a standard lex too.  */
#define YY_INPUT(buf,result,max_size)   \
  result = calc_input (buf, max_size);
#endif


/* Non-zero when reading the second or subsequent line of an expression,
   used to give a different prompt when using readline.  */
int  calc_more_input = 0;


const struct calc_keywords_t  calc_keywords[] = {
  { "abs",       ABS },
  { "bin",       BIN },
  { "decimal",   DECIMAL },
  { "fib",       FIB },
  { "hex",       HEX },
  { "help",      HELP },
  { "gcd",       GCD },
  { "kron",      KRON },
  { "lcm",       LCM },
  { "lucnum",    LUCNUM },
  { "nextprime", NEXTPRIME },
  { "powm",      POWM },
  { "quit",      QUIT },
  { "root",      ROOT },
  { "sqrt",      SQRT },
  { NULL }
};
%}

%%

[ \t\f] { /* white space is skipped */ }

[;\n]   { /* semicolon or newline separates statements */
          calc_more_input = 0;
          return EOS; }
\\\n    { /* escaped newlines are skipped */ }


#(([^\\\n]*)\\)+\n {
            /* comment through to escaped newline is skipped */ }
#[^\n]*\n { /* comment through to newline is a separator */
            calc_more_input = 0;
            return EOS; }
#[^\n]* {   /* comment through to EOF skipped */ }


[-+*/%()<>^!=,] { return yytext[0]; }
"<="    { return LE; }
">="    { return GE; }
"=="    { return EQ; }
"!="    { return NE; }
"<<"    { return LSHIFT; }
">>"    { return RSHIFT; }
"&&"    { return LAND; }
"||"    { return LOR; }

(0[xX])?[0-9A-F]+ {
        yylval.str = yytext;
        return NUMBER; }

[a-zA-Z][a-zA-Z0-9]* {
        int  i;

        for (i = 0; calc_keywords[i].name != NULL; i++)
          if (strcmp (yytext, calc_keywords[i].name) == 0)
            return calc_keywords[i].value;

        if (yytext[0] >= 'a' && yytext[0] <= 'z' && yytext[1] == '\0')
          {
            yylval.var = yytext[0] - 'a';
            return VARIABLE;
          }

        return BAD;
}

. { return BAD; }

%%

int
yywrap ()
{
  return 1;
}
