%{/* -*-c-*- */
/*
    Clif - A C-like Interpreter Framework
    Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997 T. Hruz, L. Koren
    1998, 1999, 2000 L. Koren

    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., 675 Mass Ave, Cambridge, MA 02139, USA.

*/
/*
 * ls
 *
 * lex source for Clif's compiler
 */
#include <string.h>
#include "config.h"
#ifdef STDC_HEADERS
#include <stddef.h>
#endif
#include "global.h"
#include "mystdio.h"
#include "tables.h"
#include "token.h"
#include "dbg-out.h"

#define LG_MC	35	/* Max length of identifiers */
#define MAX_MESS 250	/* 
			 * Max size of output messages (obsolete)
			 */
char *text;
char message[MAX_MESS]; /* 
			 * Buffer of output messages (obsolete)
			 */
extern FILEATTR pf, spf[];
extern int s, char_counter;
#include "input.h"	/* 
			 * Redefining of the input function
			 */
#ifdef FLEX_SCANNER
#define YY_NO_UNPUT
extern char string_resume[];
#endif
#include "buf.h"	/* 
			 * Changes size of buffer
 			 */

#include "allocx.h"
static int find_ident PROTO((char *, int));
extern char *string PROTO((char *));
extern void s_conv PROTO((char *));
extern int dbg_symbols;

#define NL '\n'
%}
mes      ["]		
newline  [\n]
tab	 [ \t]
cifra	 [0-9]
exp	 [Ee][-+]?{cifra}+
lettr	 [A-Z_a-z]
alfa	 [A-Z_a-z0-9]
numberi  {cifra}+
numberd  ({cifra}*"."{cifra}+({exp})?)|({cifra}+"."{cifra}*({exp})?)|({cifra}+{exp})
world	 {lettr}{alfa}*
AN	 [^\/]|[^\*]\/
/* In the following there is no the " character. */
/* The $, `, @ characters are not in ANSI C Standard. */
stringc	 [-A-Z_a-z0-9=!*:% \\\(\)\n\t\.#$&'`\+,\/@\[\]\^\{\}\>\<\~\|\?;]
numberc	 '{stringc}'
hexa	 [a-fA-F0-9]
FCS	 [Ff]
LCS	 [Ll]
UCS	 [Uu]
octalnum [0-7]
s_esc_s  (\\(\'|\"|\?|\\|a|b|f|n|r|t|v))|(\"|\?)
o_esc_s  (\\{octalnum}|\\{octalnum}{octalnum}|\\{octalnum}{octalnum}{octalnum})
h_esc_s  (\\[xX]{hexa}+)
%%
{tab}	  {char_counter += yyleng; strcat (line_buf, yytext);
			/* 
			 * tabs, spaces
			 */}
{newline} {
#ifdef FLEX_SCANNER
            spf[s].line_counter++;
	    line_buf[0] = 0;
	    char_counter = 0;
#endif
	    if (dbg_symbols)
	      dbg_create ();
          }
0x{hexa}+{UCS} {
                 sscanf (yytext, "%ux", &yylval.myuint);
	         char_counter += yyleng;
	         strcat (line_buf, yytext);
	         return (NUMBERUI);
               }
0x{hexa}+{LCS} {
                 sscanf (yytext, "%lx", &yylval.mylint);
	         char_counter += yyleng;
	         strcat (line_buf, yytext);
		 return (NUMBERLI);
               }
0x{hexa}+{UCS}{LCS} {
          sscanf (yytext, "%lux", &yylval.myluint);
	  char_counter += yyleng;
	  strcat (line_buf, yytext);
	  return (NUMBERLUI);
        }
0x{hexa}+{LCS}{UCS} {
          sscanf (yytext, "%lx", &yylval.myluint);
	  char_counter += yyleng;
	  strcat (line_buf, yytext);
	  return (NUMBERLUI);
        }
0x{hexa}+ {
          sscanf (yytext, "%x", &yylval.myint);
	  char_counter += yyleng;
	  strcat (line_buf, yytext);
	  return (NUMBERI);
        }
{numberi}{UCS} {
          sscanf (yytext, "%u", &yylval.myuint);
	  char_counter += yyleng;
	  strcat (line_buf,yytext);
	  return (NUMBERUI);
	  /* 
	   * Matches integer numbers
	   */}
{numberi}{LCS} {
                 sscanf (yytext, "%ld", &yylval.mylint);
		 char_counter += yyleng;
		 strcat (line_buf, yytext);
		 return (NUMBERLI);
		 /* 
		  * Matches integer numbers
		  */}
{numberi}{UCS}{LCS} {
                      sscanf (yytext, "%lu", &yylval.myluint);
		      char_counter += yyleng;
		      strcat (line_buf, yytext);
		      return (NUMBERLUI);
			/* 
			 * Matches integer numbers
			 */}
{numberi}{LCS}{UCS} {
                      sscanf (yytext, "%lu", &yylval.myluint);
		      char_counter += yyleng;
		      strcat (line_buf, yytext);
		      return (NUMBERLUI);
			/* 
			 * Matches integer numbers
			 */}
{numberi}  {
             sscanf (yytext, "%d", &yylval.myint);
	     char_counter += yyleng;
	     strcat (line_buf,yytext);
	     return (NUMBERI);
	     /* 
	      * Matches integer numbers
	      */}
{numberd}{FCS} {
                 sscanf (yytext, "%f", &yylval.myfloat);
		 char_counter += yyleng;
		 strcat (line_buf,yytext);
		 return (NUMBERF);
		 /*
		  * Matches float numbers
		  */}
{numberd}{LCS} {
                 sscanf (yytext, "%Lf", &yylval.myldouble);
		 char_counter += yyleng;
		 strcat (line_buf, yytext);
		 return (NUMBERLD);
		 /*
		  * Matches long double numbers
		  */}
{numberd}  {
             sscanf (yytext, "%lf", &yylval.mydouble);
	     char_counter += yyleng;
	     strcat (line_buf, yytext);
	     return (NUMBERD);
	     /*
	      * Matches double numbers
	      */}
'\\0'	{char_counter += yyleng;
         yytext[0] = 0;
	 strcat (line_buf, "'\\0'");
	 yylval.mychar = 0;
	 return (NUMBERC);
        }
{LCS}?(('({s_esc_s}|{o_esc_s}|{h_esc_s})')|{numberc}) {
         int i, j;
	 char_counter += yyleng;
	 strcat (line_buf, yytext);
	 for (i = 1; yytext[i] != '\0'; i++)
	   if (yytext[i - 1] == '\\' && yytext[i] == 'X')
	     {
	       error_message (6033, "X");
	       break;
	     }
         if (yytext[0] == 'l')
	   {
	     error_message (1038, "l");
	     error_message (1039, "character");
	   }
#if 0
	 /* Constant L 'a' should be wide character constant. It seems,
	  there is no difference in representation yet. */
	 if (yytext[0] == 'L')
	   {
	     for (i = 0; yytext[i] != '\0'; i++)
	       if (yytext[i] == '\'')
		 break;
	     yytext[0] = yytext[i + 1];
	     sscanf (yytext, "%d", &yylval.myint);
	     return (NUMBERI);
	   }
#endif
	 for (i = 0; yytext[i] != '\0'; i++)
	   if (yytext[i] == '\'')
	     break;
	 for (j = i + 1, i = 0; yytext[j] != '\0'; j++, i++)
	   yytext[i] = yytext[j];
	 yytext[i] = '\0';
	 if (yytext[0] == '\\')
	   {
	     switch (yytext[1])
	       {
	       case '\'':
		 yylval.mychar = '\'';
		 break;
	       case '"':
		 yylval.mychar = '\"';
		 break;
	       case '?':
		 yylval.mychar = '\?';
		 break;
	       case '\\':
		 yylval.mychar = '\\';
		 break;
	       case 'a':
		 yylval.mychar = '\a';
		 break;
	       case 'b':
		 yylval.mychar = '\b';
		 break;
	       case 'f':
		 yylval.mychar = '\f';
		 break;
	       case 'n':
		 yylval.mychar = '\n';
		 break;
	       case 'r':
		 yylval.mychar = '\r';
		 break;
	       case 't':
		 yylval.mychar = '\t';
		 break;
	       case 'v':
		 yylval.mychar = '\v';
		 break;
	       case 'x':
		 yytext[0] = '0';
		 sscanf (yytext, "%x", (unsigned *) &yylval.mychar);
		 break;
	       default:
		 yytext[0] = '0';
		 sscanf (yytext, "%o", (unsigned *) &yylval.mychar);
		 break;
	       }
	   }
	 else
	   sscanf (yytext, "%c", &yylval.mychar);
	 return (NUMBERC);
}
{world}   {
            int i;
	    strcat (line_buf, yytext);
	    char_counter += yyleng;
	    i = find_ident (yytext, yyleng);	/* 
					 	 * Matches keywords
					 	 */
	    if (i)
	      return i;
	    else
	      {
		text = string (yytext);
		yylval.mystring = text;
		/* If the identifier just matched was previously
		   declared as typedef return it as TYPENAME; IDENT
		   otherwise. */
		if (typedef_p (text))
		  return TYPENAME;
		else
		  return IDENT;
	      }
         }
("/*"|"/*/")({AN})*"*/"	{
#ifdef FLEX_SCANNER
                          char *str;
#endif
			  char_counter += yyleng;
			  strcat (line_buf, yytext);
			  if (NULL != strstr (&yytext[2], "/*"))
			    {error_message (6005);}
			  /* 
			   * Matches and discards comments
			   */
#ifdef FLEX_SCANNER
			  str = yytext;
			  str = strstr (str, "\n");
			  while (str != NULL)
			    {
			      spf[s].line_counter++;
			      str = &str[1];
			      str = strstr (str, "\n");
			    }
#endif
                        }
load[ ]*\([ ]*  {char name[20],*tmp_p;
	         int w,ab=' ';
	     	 char_counter += yyleng;
		 strcat (line_buf, yytext);
	     	 for (w = 0; ab != ';'; w++)		
		   {
		    ab = input ();
		    name[w] = ab;
		   }
	     	 tmp_p = (char *)strchr (name,')');
	     	 if (NULL == tmp_p)
		   {
		    error_message (1004, ")");
		    return (0);
		   }
	     	 *tmp_p = '\0';
	     	 tmp_p = (char *)strchr (name,' ');
	     	 if (NULL != tmp_p)
		   {
		    *tmp_p = '\0';
		   }
	     	 char_counter += w; strcat (line_buf, name);
	     	 s++;
	     	 spf[s].fp = fopen (name, "r");
	     	 if (NULL == spf[s].fp)
		   {
		    yytext[0] = '\0'; s--;
		    strcpy (yytext, name);
		    error_message (1011);
		    return (0);
		   }
	         if (NULL == (spf[s].name = (char *)
		    allocate (strlen (name) + 1, PERM)))
	           {
		    error_message (4002);
		    return (0);
	           }
	         strcpy (spf[s].name, name);
		 spf[s].line_counter = 1;
#ifdef FLEX_SCANNER
		 yy_switch_to_buffer (yy_create_buffer (spf[s].fp,
							YY_BUF_SIZE));
#else
	         pf = spf[s];	
#endif
	        }
({LCS}?\"({stringc}|(\\\"))+\"({tab}|{newline})*)+ {int wide_string = 0;
                 char_counter += yyleng; 
		 if (yytext[0] == 'l')
		   {
		     error_message (1040);
		     error_message (1039, "string");
		   }
		 else if (yytext[0] == 'L')
		   wide_string = 1;
		 strcat (line_buf, yytext);
		 s_conv (yytext);
		 /* I do not differentiate between strings and wide
		    string literal. However, there is room for it in
		    the union. */
		 yylval.mystring = string (yytext);
		 if (wide_string)
		   return (WSTRINGC);
		 else
		   return (STRINGC);
                 }
">>="	{char_counter += yyleng; strcat (line_buf, yytext); return (RIGHT_ASSIGN);}
"<<="	{char_counter += yyleng; strcat (line_buf, yytext); return (LEFT_ASSIGN);}
"+="	{char_counter += yyleng; strcat (line_buf, yytext); return (ADD_ASSIGN);}
"-="	{char_counter += yyleng; strcat (line_buf, yytext); return (SUB_ASSIGN);}
"*="	{char_counter += yyleng; strcat (line_buf, yytext); return (MUL_ASSIGN);}
"/="	{char_counter += yyleng; strcat (line_buf, yytext); return (DIV_ASSIGN);}
"%="	{char_counter += yyleng; strcat (line_buf, yytext); return (MOD_ASSIGN);}
"&="	{char_counter += yyleng; strcat (line_buf, yytext); return (AND_ASSIGN);}
"^="	{char_counter += yyleng; strcat (line_buf, yytext); return (XOR_ASSIGN);}
"|="	{char_counter += yyleng; strcat (line_buf, yytext); return (OR_ASSIGN);}
"&&"	{char_counter += yyleng; strcat (line_buf, yytext); return (AND_A);}
"||"	{char_counter += yyleng; strcat (line_buf, yytext); return (OR_A);}
"=="	{char_counter += yyleng; strcat (line_buf, yytext); return (EQ_A);}
">=" 	{char_counter += yyleng; strcat (line_buf, yytext); return (GQ);}
"<="	{char_counter += yyleng; strcat (line_buf, yytext); return (LQ);}
"!="	{char_counter += yyleng; strcat (line_buf, yytext); return (NE_A);}
"++"	{char_counter += yyleng; strcat (line_buf, yytext); return (PP);}
"--"	{char_counter += yyleng; strcat (line_buf, yytext); return (MM);}
"!"	{char_counter += yyleng; strcat (line_buf, yytext); return (NEG_T);}
"~"	{char_counter += yyleng; strcat (line_buf, yytext); return (NEG_B);}
">>"	{char_counter += yyleng; strcat (line_buf, yytext); return (SHIR);}
"<<"	{char_counter += yyleng; strcat (line_buf, yytext); return (SHIL);}
"->"	{char_counter += yyleng; strcat (line_buf, yytext); return (PTR);}
"??="	{char_counter += yyleng;
         strcat (line_buf, "#");
	 error_message (6032);
	 return ('#');
        }
"??("	{char_counter += yyleng;
         strcat (line_buf, "[");
	 error_message (6032);
	 return ('[');
        }
"??/"	{char_counter += yyleng;
         strcat (line_buf, "\\");
	 error_message (6032);
	 return ('\\');
        }
"??)"	{char_counter += yyleng;
         strcat (line_buf, "]");
	 error_message (6032);
	 return (']');
        }
"??'"	{char_counter += yyleng;
         strcat (line_buf, "^");
	 error_message (6032);
	 return ('^');
        }
"??<"	{char_counter += yyleng;
         strcat (line_buf, "{");
	 error_message (6032);
	 return ('{');
        }
"??!"	{char_counter += yyleng;
         strcat (line_buf, "|");
	 error_message (6032);
	 return ('|');
        }
"??>"	{char_counter += yyleng;
         strcat (line_buf, "}");
	 error_message (6032);
	 return ('}');
        }
"??-"	{char_counter += yyleng;
         strcat (line_buf, "~");
	 error_message (6032);
	 return ('~');
        }

.	{char_counter += yyleng; strcat (line_buf, yytext); return (*yytext);
			 /* 
			  * Returns rest simple characters
			  */}
%%
struct el_mc {
  char *name;
  int tok;
};

extern struct el_mc *
in_word_set PROTO((register char *, register unsigned int));

/* 
 * Looks up if a identifier is not a keyword
 */
static int 
find_ident (s, len)
       char *s;
       int len;
{
  register struct el_mc *ret_val;
  ret_val = in_word_set (s, len);
  if (ret_val)
    return ret_val->tok;
  else
    return 0;
}

int 
yywrap ()
{
#ifdef FLEX_SCANNER
  return (! switch_to_buffer ());
#else
  return 1;
#endif
}

#ifndef FLEX_SCANNER
#ifdef unput
#undef unput
#endif

#define unput(c) {yytchar = (c); \
  if (NL == yytchar) \
    { \
      yylineno--; \
      spf[s].line_counter--; \
    } \
  *yysptr++ = yytchar;}
#else

void
switch_to_stdin ()
{
  s++;
  spf[s] = spf[0];
  yy_switch_to_buffer (yy_create_buffer (stdin, YY_BUF_SIZE));
  yy_set_interactive (1);
}

void
switch_to_char_buffer ()
{
  yy_scan_string (string_resume);
}

int
switch_to_buffer ()
{
  if (terminate_buffer ())
    return 0;
  else 
    {
      yy_delete_buffer (YY_CURRENT_BUFFER);
      yy_switch_to_buffer (yy_create_buffer (spf[s].fp,
					     YY_BUF_SIZE));
    }
  return 1;
}

void *
store_buffer_state ()
{
  YY_BUFFER_STATE *state;
  state = (YY_BUFFER_STATE *) allocate (sizeof (YY_BUFFER_STATE), 0);
  *state = YY_CURRENT_BUFFER;
  return ((void *) state);
}

void
flush_buffer (state)
  void *state;
{
  yy_flush_buffer (YY_CURRENT_BUFFER);
  yy_switch_to_buffer (*(YY_BUFFER_STATE *)state);
#if 0
  deallocate (state);
#endif
}

#endif /* ! FLEX_SCANNER */
