/* 
 * Copyright (c) 2001 Secure Software Solutions
 *
 * 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 2
 * 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, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 */

%{
#include <string.h>
#include "tokens.h"
#include "engine.h"

int plex_lineno = 1;
int pyyclength = 0;
int pyycsize = 0;
char *yypcomment = NULL;
static void gobble_string(char c);

static int  identifier(void);
static void no_match(void);
static int longstring(int);


#define YY_INPUT(buf, result, max_size)                                     \
    if (((result = fread(buf, 1, max_size, yyin)) == 0) && ferror(yyin))    \
        YY_FATAL_ERROR("input in flex scanner failed");                     \
    else {                                                                  \
        char *c, *end = (buf) + result - 1;                                 \
        for (c = (buf);  c < end;  c++) {                                   \
            if (*c == '\r') *c = ' ';                                       \
            if (*c == '\\' && *(c + 1) == '\n') {                           \
                memmove(c + 1, c + 2, end - c);                             \
                result--;                                                   \
                end--;                                                      \
                *c = '\r';                                                  \
            }                                                               \
        }                                                                   \
        if (*end == '\r') *end = ' ';                                       \
        if (*end == '\\') {                                                 \
            result--;                                                       \
            fseek(yyin, -1, SEEK_CUR);                                      \
        }                                                                   \
    }

%}

%%

[\n\r]			{ plex_lineno++; return NEWLINE; }
[ \t\v\f]		{ ; }
^[ \r\t]*"#".*\n	{ plex_lineno++; }
"#".*			{ ; }

and			{ return AND; }
assert			{ return ASSERT; }
break			{ return BREAK; }
class			{ return CLASS; }
continue		{ return CONTINUE; }
def			{ return DEF; }
del			{ return DEL; }
elif			{ return ELIF; }
else			{ return ELSE; }
except			{ return EXCEPT; }
exec			{ return EXEC; }
finally			{ return FINALLY; }
for			{ return FOR; }
from			{ return FROM; }
global			{ return GLOBAL; }
if			{ return IF; }
import			{ return IMPORT; }
in			{ return IN; }
is			{ return IS; }
lambda			{ return LAMBDA; }
not			{ return NOT; }
or			{ return OR; }
pass			{ return PASS; }
print			{ return PRINT; }
raise			{ return RAISE; }
return			{ return RETURN; }
try			{ return TRY; }
while			{ return WHILE; }

("\'") { gobble_string('\''); return SSTRING_LITERAL; }
("\"")  { gobble_string('"'); return SSTRING_LITERAL; }

\"\"\"  {return longstring('\"');}
\'\'\'  {return longstring('\'');}

0[xX][a-fA-F0-9]+(l|L)*     { return HEX_CONST; }
0[0-9]+(l|L)*               { return OCT_CONST; }
[0-9]+(l|L)*                { return DEC_CONST; }
[0-9]+[Ee][+-]?[0-9]+              { return FLOAT_CONST; }
[0-9]*"."[0-9]+([Ee][+-]?[0-9]+)?  { return FLOAT_CONST; }
[0-9]+"."[0-9]*([Ee][+-]?[0-9]+)?  { return FLOAT_CONST; }
[1-9][0-9]*(j|J)			{ return IMAG_CONST; }
[0-9]+[Ee][+-]?[0-9]+(j|J)              { return IMAG_CONST; }
[0-9]*"."[0-9]+([Ee][+-]?[0-9]+)?(j|J)  { return IMAG_CONST; }
[0-9]+"."[0-9]*([Ee][+-]?[0-9]+)?(j|J)  { return IMAG_CONST; }

[a-zA-Z_]([a-zA-Z_]|[0-9]|\$|[\r])* { return identifier(); }

">>="			{ return RIGHT_ASSIGN; }
"<<="			{ return LEFT_ASSIGN; }
"**="			{ return EXP_ASSIGN; }
"+="			{ return ADD_ASSIGN; }
"-="			{ return SUB_ASSIGN; }
"*="			{ return MUL_ASSIGN; }
"/="			{ return DIV_ASSIGN; }
"%="			{ return MOD_ASSIGN; }
"&="			{ return AND_ASSIGN; }
"|="			{ return OR_ASSIGN; }
"^="			{ return XOR_ASSIGN; }
">>"                    { return RIGHT_OP; }
"<<"                    { return LEFT_OP; }
"**"                    { return EXP_OP; }
"<="                    { return LE_OP; }
">="                    { return GE_OP; }
"=="                    { return EQ_OP; }
"!="                    { return NE_OP; }
"<>"                    { return NE_OP; }
"&"                     { return '&'; }
"~"                     { return '~'; }
"-"                     { return '-'; }
"+"                     { return '+'; }
"*"                     { return '*'; }
"/"                     { return '/'; }
"%"                     { return '%'; }
"<"                     { return '<'; }
">"                     { return '>'; }
"^"                     { return '^'; }
"|"                     { return '|'; }
 
"("			{ return '('; }
")"			{ return ')'; }
"["			{ return '['; }
"]"			{ return ']'; }
"{"			{ return '{'; }
"}"			{ return '}'; }
","			{ return ','; }
":"			{ return ':'; }
"."			{ return '.'; }
"`"			{ return '`'; }
"="			{ return '='; }
";"			{ return ';'; }

.                       { no_match(); }

%%

int yywrap(void)
{
    return 1;
}


static
void gobble_string(char which)
{

  int bslash = 0;
  char c;
  while ((c = input()) && c != -1)
  {

    switch(c)  {

      case '\\':
                 if (!bslash)
                   bslash = 1;
                 else
                   bslash = 0;
                 break;
      case '\n':
                 plex_lineno++;
                 bslash = 0;
                 break;
      default:
                 if (c == which && !bslash)  {
                   return;
                 }
                 bslash = 0;
                 break;
    }
  }
}

static
void no_match(void)
{
    fprintf(stderr, "%s:%d: warning: bad token `%s'\n", current_file, plex_lineno, yytext);
}

static
int identifier(void)
{   
    char *  c;

    while ((c = strchr(yytext, '\r')) != (char *)NULL)
    {   
        memmove(c, c + 1, strlen(c));
        plex_lineno++;
    }
    return IDENTIFIER;
}



static
int longstring(int q)
{
    char    c;

    int quotes =  0;
    int backtick = 0;
    while ((c = input()) && c != -1)
    {
        if (c != q) 
          quotes = 0;
        if (c == '\\')  {
          backtick = 1;
          continue;
        }
         
        
        if (c == q)
        {
          if (backtick)
          {
            quotes = 0;
            backtick = 0;
          } else {
            quotes++;
          }
        }   
        backtick = 0;

       if (quotes == 3)  
       {
         return LSTRING_LITERAL;
       }
       if (c == '\n' || c == '\r')
         plex_lineno++;
  
    }

    return LSTRING_LITERAL;
}










