%{

/*
 * This scanner is based on:
 *
 * cpp5.l, a C/C++ scanner written by James A. Roskind.
 * "Portions Copyright (c) 1989, 1990 James A. Roskind".
 * (http://www.idiom.com/free-compilers/,
 * ftp://ftp.infoseek.com/ftp/pub/c++grammar/,
 * ftp://ftp.sra.co.jp/.a/pub/cmd/c++grammar2.0.tar.gz)
 */

#include <expr.h>
#include <arith_tools.h>
#include <ansi-c/c_types.h>
#include <ansi-c/preprocessor_line.h>
#include <ansi-c/convert_float_literal.h>
#include <ansi-c/convert_character_literal.h>
#include <ansi-c/convert_string_literal.h>
#include <config.h>

#define PARSER ansi_c_parser
#define YYSTYPE unsigned
#undef	ECHO
#define ECHO

#include "ansi_c_parser.h"
#include "y.tab.h"

#define loc() { newstack(yyansi_clval); PARSER.set_location(stack(yyansi_clval)); }

/*** macros for easier rule definition **********************************/
%}

delimiter	[ \t\b\r]
newline		[\n\f\v]
whitespace	{delimiter}+
ws		{delimiter}*
ucletter	[A-Z]
lcletter	[a-z]
letter		({ucletter}|{lcletter})
digit		[0-9]
bindigit	[01]
octdigit	[0-7]
hexdigit	[0-9a-fA-F]
identifier	(({letter}|"_")({letter}|{digit}|"_")*)
integer		{digit}+
binary		{bindigit}+
decinteger	[1-9]{digit}*
octinteger	"0"{octdigit}*
hexinteger	"0"[xX]{hexdigit}+
decinteger_u	{decinteger}[uU]
octinteger_u	{octinteger}[uU]
hexinteger_u	{hexinteger}[uU]
decinteger_l	{decinteger}[lL]
octinteger_l	{octinteger}[lL]
hexinteger_l	{hexinteger}[lL]
decinteger_ul	{decinteger}([uU][lL]|[lL][uU])
octinteger_ul	{octinteger}([uU][lL]|[lL][uU])
hexinteger_ul	{hexinteger}([uU][lL]|[lL][uU])
decinteger_ll	{decinteger}[lL][lL]
octinteger_ll	{octinteger}[lL][lL]
hexinteger_ll	{hexinteger}[lL][lL]
decinteger_ull	{decinteger}([uU][lL][lL]|[lL][lL][uU])
octinteger_ull	{octinteger}([uU][lL][lL]|[lL][lL][uU])
hexinteger_ull	{hexinteger}([uU][lL][lL]|[lL][lL][uU])
octchar		"\\"{octdigit}{1,3}
hexchar		"\\x"{hexdigit}+
exponent	[eE][+-]?{integer}
fraction	{integer}
float1		{integer}"."{fraction}?({exponent})?
float2		"."{fraction}({exponent})?
float3		{integer}{exponent}
float		{float1}|{float2}|{float3}
float_f		{float}[fF]
float_l		{float}[lL]
bitvector	{binary}[bB]
bitvector_u	{binary}([uU][bB]|[bB][uU])
cppstart	{ws}"#"{ws}
cpplineno	{cppstart}"line"*{ws}{integer}{ws}.*{newline}
cpppragma	{cppstart}"pragma"{ws}.*
cppdirective	{cppstart}.*

simple_escape [abfnrtv'"?\\]
octal_escape  [0-7]{1,3}
hex_escape "x"[0-9a-fA-F]+

escape_sequence [\\]({simple_escape}|{octal_escape}|{hex_escape})
c_char [^'\\\n]|{escape_sequence}
s_char [^"\\\n]|{escape_sequence}

%x GRAMMAR
%x COMMENT1
%x COMMENT2
%x MSC_ASM
%x MSC_DECLSPEC
%x GCC_ATTRIBUTE

%{
void ansi_c_scanner_init()
{
  YY_FLUSH_BUFFER;
  BEGIN(0);
}
%}

%%

<INITIAL>.|\n	{ BEGIN(GRAMMAR);
		  yyless(0);		/* start again with this character */
		  //yy_current_buffer->yy_at_bol = 1; /* at beginning of line */
		  switch(PARSER.grammar)
		   {
                   case ansi_c_parsert::EXPRESSION: return TOK_PARSE_EXPRESSION;
                   case ansi_c_parsert::LANGUAGE: return TOK_PARSE_LANGUAGE;
		   default: assert(0);
		   }
		 }

<GRAMMAR>"/*"	{ BEGIN(COMMENT1); }	/* begin C comment state */

<COMMENT1>{
   "*/"		{ BEGIN(GRAMMAR); }	/* end comment state, back GRAMMAR */
   "/*"		{ yyansi_cerror("Probably nested comments"); }
   <<EOF>>	{ yyansi_cerror("Unterminated comment"); return(TOK_SCANNER_ERROR); }
   [^*/\n]*	{ /* ignore every char except '*' and NL (performance!) */ }
   .		{ } /* all single characters within comments are ignored */
   \n		{ } 
	}

<GRAMMAR>"//"	{ BEGIN(COMMENT2); }	/* begin C++ comment state */

<COMMENT2>{
   \n		{ BEGIN(GRAMMAR); }	/* end comment state, back GRAMMAR */
   .*		{ } /* all characters within comments are ignored */
	}

<GRAMMAR>"L"?[']{c_char}+['] { 
                  loc();
                  convert_character_literal(yytext, stack(yyansi_clval));
                  PARSER.set_location(stack(yyansi_clval));
                  return TOK_CHARACTER;
                }

<GRAMMAR>"L"?["]{s_char}*["] {
                  loc();
                  convert_string_literal(yytext, stack(yyansi_clval));
                  PARSER.set_location(stack(yyansi_clval));
                  return TOK_STRING;
                }

<GRAMMAR>{newline}	{ } /* skipped */
<GRAMMAR>{whitespace}	{ } /* skipped */

<GRAMMAR>{cpplineno}	{
                  preprocessor_line(yytext, PARSER.line_no, PARSER.filename);
                  PARSER.line_no--;
		 }
<GRAMMAR>{cpppragma}	{
                  #if 0
		  TmpString.form(
			"'pragma' directive found:" GL_WARN_MSG_NEWLINE
			"%s" GL_WARN_MSG_NEWLINE
			"Directive ignored",
			&PRS_text[0]);
		  PRS_PrintWarning(GL_WARN_INFORMATIVE, TmpString.chars());
		  TmpString = "";
                  #endif
		 }
<GRAMMAR>{cppdirective}	{
		  yyansi_cerror("Preprocessor directive found");
		  return(TOK_SCANNER_ERROR);
		 }

%{
/*** keywords ***/
%}

<GRAMMAR>{
"auto"		{ loc(); return TOK_AUTO; }
"_Bool"		{ loc(); return TOK_BOOL; }
"break"		{ loc(); return TOK_BREAK; }
"case"		{ loc(); return TOK_CASE; }
"char"		{ loc(); return TOK_CHAR; }
"const"		{ loc(); return TOK_CONST; }
"continue"	{ loc(); return TOK_CONTINUE; }
"default"	{ loc(); return TOK_DEFAULT; }
"do"		{ loc(); return TOK_DO; }
"double"	{ loc(); return TOK_DOUBLE; }
"else"		{ loc(); return TOK_ELSE; }
"enum"		{ loc(); PARSER.tag_following=true; return TOK_ENUM; }
"extern"	{ loc(); return TOK_EXTERN; }
"float"		{ loc(); return TOK_FLOAT; }
"for"		{ loc(); return TOK_FOR; }
"goto"		{ loc(); return TOK_GOTO; }
"if"		{ loc(); return TOK_IF; }
"inline"	{ loc(); return TOK_INLINE; }
"int"		{ loc(); return TOK_INT; }
"long"		{ loc(); return TOK_LONG; }
"register"	{ loc(); return TOK_REGISTER; }
"return"	{ loc(); return TOK_RETURN; }
"short" 	{ loc(); return TOK_SHORT; }
"signed"	{ loc(); return TOK_SIGNED; }
"sizeof"	{ loc(); return TOK_SIZEOF; }
"static"	{ loc(); return TOK_STATIC; }
"struct"	{ loc(); PARSER.tag_following=true; return TOK_STRUCT; }
"switch"	{ loc(); return TOK_SWITCH; }
"typedef"	{ loc(); return TOK_TYPEDEF; }
"union"		{ loc(); PARSER.tag_following=true; return TOK_UNION; }
"unsigned"	{ loc(); return TOK_UNSIGNED; }
"void"		{ loc(); return TOK_VOID; }
"volatile"	{ loc(); return TOK_VOLATILE; }
"while"		{ loc(); return TOK_WHILE; }

"__int8"        { loc(); return TOK_INT8; }
"__int16"       { loc(); return TOK_INT16; }
"__int32"       { loc(); return TOK_INT32; }
"__int64"       { loc(); return TOK_INT64; }
"__ptr32"       { loc(); return TOK_PTR32; }
"__ptr64"       { loc(); return TOK_PTR64; }

%{
/* note: "wchar_t" should be in the list above, but it is left out */
/*       because it is a 'typedef' in some standard header files   */
%}

"__asm"         { BEGIN(MSC_ASM); }
"asm"           { loc(); return TOK_ASM; }

"__declspec"    { BEGIN(MSC_DECLSPEC); }

"__attribute"   { BEGIN(GCC_ATTRIBUTE); PARSER.parenthesis_counter=0; }
"__attribute__" { BEGIN(GCC_ATTRIBUTE); PARSER.parenthesis_counter=0; }

"__aligned"     { /* ignore */ }
"__aligned__"   { /* ignore */ }

"__extension__" { /* ignore */ }

"__restrict"    { /* ignore */ }

"_cdecl"        { /* ignore */ }
"__cdecl"       { /* ignore */ }
"__cdecl__"     { /* ignore */ }
"_stdcall"      { /* ignore */ }
"__stdcall"     { /* ignore */ }
"_fastcall"     { /* ignore */ }
"__fastcall"    { /* ignore */ }

"__const"       { loc(); return TOK_CONST; }
"__const__"     { loc(); return TOK_CONST; }

"__signed"      { loc(); return TOK_SIGNED; }
"__signed__"    { loc(); return TOK_SIGNED; }

"__volatile"    { loc(); return TOK_VOLATILE; }
"__volatile__"  { loc(); return TOK_VOLATILE; }

"typeof"        { loc(); return TOK_TYPEOF; }
"__typeof"      { loc(); return TOK_TYPEOF; }
"__typeof__"    { loc(); return TOK_TYPEOF; }

"__inline"	{ loc(); return TOK_INLINE; }
"__inline__"	{ loc(); return TOK_INLINE; }
}

<MSC_ASM>[^}]*  { /* Throw away */ }
<MSC_ASM>"}"    { BEGIN(GRAMMAR); }

<MSC_DECLSPEC>[^)]*  { /* Throw away */ }
<MSC_DECLSPEC>")"    { BEGIN(GRAMMAR); }

<GCC_ATTRIBUTE>")"    { PARSER.parenthesis_counter--;
                        if(PARSER.parenthesis_counter==0)
                          BEGIN(GRAMMAR); }
<GCC_ATTRIBUTE>"("    { PARSER.parenthesis_counter++; }
<GCC_ATTRIBUTE>.      { /* Throw away */ }

<GRAMMAR>{
"->"		{ loc(); return TOK_ARROW; }
"++"		{ loc(); return TOK_INCR; }
"--"		{ loc(); return TOK_DECR; }
"<<"		{ loc(); return TOK_SHIFTLEFT; }
">>"		{ loc(); return TOK_SHIFTRIGHT; }
"<="		{ loc(); return TOK_LE; }
">="		{ loc(); return TOK_GE; }
"=="		{ loc(); return TOK_EQ; }
"!="		{ loc(); return TOK_NE; }
"&&"		{ loc(); return TOK_ANDAND; }
"||"		{ loc(); return TOK_OROR; }
"..."		{ loc(); return TOK_ELLIPSIS; }

"*="		{ loc(); return TOK_MULTASSIGN; }
"/="		{ loc(); return TOK_DIVASSIGN; }
"%="		{ loc(); return TOK_MODASSIGN; }
"+="		{ loc(); return TOK_PLUSASSIGN; }
"-="		{ loc(); return TOK_MINUSASSIGN; }
"<<="		{ loc(); return TOK_SLASSIGN; }
">>="		{ loc(); return TOK_SRASSIGN; }
"&="		{ loc(); return TOK_ANDASSIGN; }
"^="		{ loc(); return TOK_EORASSIGN; }
"|="		{ loc(); return TOK_ORASSIGN; }
}

<GRAMMAR>{
{identifier}	{ loc();

                  std::string base_name(yytext);
                  std::string identifier(base_name);
                  
                  ansi_c_id_classt result=
                    PARSER.lookup(identifier, PARSER.tag_following);
                  PARSER.tag_following=false;
                  
                  stack(yyansi_clval).id("symbol");
                  stack(yyansi_clval).set("#base_name", base_name);
                  stack(yyansi_clval).set("identifier", identifier);
                  stack(yyansi_clval).set("#id_class", result);

                  if(result==ANSI_C_TYPEDEF)
                    return TOK_TYPEDEFNAME;
                  else
                    return TOK_IDENTIFIER;
		}

{decinteger}	{ loc();
                  stack(yyansi_clval).id("constant");
                  stack(yyansi_clval).type()=typet("integer");
                  stack(yyansi_clval).set("value", yytext);
		  return(TOK_INTEGER);
		}
{octinteger}	{ loc();
                  stack(yyansi_clval).id("constant");
                  stack(yyansi_clval).type()=typet("integer");
                  stack(yyansi_clval).set("#cformat", yytext);
                  stack(yyansi_clval).set("#hex_or_oct", true);
                  mp_integer value=string2integer(yytext, 8);
                  stack(yyansi_clval).set("value", integer2string(value));
		  return(TOK_INTEGER);
		}
{hexinteger}	{ loc();
                  stack(yyansi_clval).id("constant");
                  stack(yyansi_clval).type()=typet("integer");
                  stack(yyansi_clval).set("#cformat", yytext);
                  stack(yyansi_clval).set("#hex_or_oct", true);
                  std::string hex(yytext, 2, std::string::npos);
                  mp_integer value=string2integer(hex, 16);
                  stack(yyansi_clval).set("value", integer2string(value));
		  return(TOK_INTEGER);
		}
{decinteger_u}	{ loc();
                  stack(yyansi_clval).id("constant");
                  stack(yyansi_clval).type()=typet("integer");
                  stack(yyansi_clval).type().set("#unsigned", true);
                  stack(yyansi_clval).set("value", yytext);
		  return(TOK_INTEGER);
		}
{octinteger_u}	{ loc();
                  stack(yyansi_clval).id("constant");
                  stack(yyansi_clval).type()=typet("integer");
                  stack(yyansi_clval).type().set("#unsigned", true);
                  stack(yyansi_clval).set("#cformat", yytext);
                  stack(yyansi_clval).set("#hex_or_oct", true);
                  mp_integer value=string2integer(yytext, 8);
                  stack(yyansi_clval).set("value", integer2string(value));
		  return(TOK_INTEGER);
		}
{hexinteger_u}	{ loc();
                  stack(yyansi_clval).id("constant");
                  stack(yyansi_clval).type()=typet("integer");
                  stack(yyansi_clval).type().set("#unsigned", true);
                  stack(yyansi_clval).set("#cformat", yytext);
                  stack(yyansi_clval).set("#hex_or_oct", true);
                  std::string hex(yytext, 2, std::string::npos);
                  mp_integer value=string2integer(hex, 16);
                  stack(yyansi_clval).set("value", integer2string(value));
		  return(TOK_INTEGER);
		}
{decinteger_l}	{ loc();
                  stack(yyansi_clval).id("constant");
                  stack(yyansi_clval).type()=typet("integer");
                  stack(yyansi_clval).type().set("#width", "long");
                  stack(yyansi_clval).set("value", yytext);
		  return(TOK_INTEGER);
		}
{octinteger_l}	{ loc();
                  stack(yyansi_clval).id("constant");
                  stack(yyansi_clval).type()=typet("integer");
                  stack(yyansi_clval).type().set("#width", "long");
                  stack(yyansi_clval).set("#cformat", yytext);
                  stack(yyansi_clval).set("#hex_or_oct", true);
                  mp_integer value=string2integer(yytext, 8);
                  stack(yyansi_clval).set("value", integer2string(value));
		  return(TOK_INTEGER);
		}
{hexinteger_l}	{ loc();
                  stack(yyansi_clval).id("constant");
                  stack(yyansi_clval).type()=typet("integer");
                  stack(yyansi_clval).type().set("#width", "long");
                  stack(yyansi_clval).set("#cformat", yytext);
                  stack(yyansi_clval).set("#hex_or_oct", true);
                  std::string hex(yytext, 2, std::string::npos);
                  mp_integer value=string2integer(hex, 16);
                  stack(yyansi_clval).set("value", integer2string(value));
		  return(TOK_INTEGER);
		}
{decinteger_ul}	{ loc();
                  stack(yyansi_clval).id("constant");
                  stack(yyansi_clval).type()=typet("integer");
                  stack(yyansi_clval).type().set("#width", "long");
                  stack(yyansi_clval).type().set("#unsigned", true);
                  stack(yyansi_clval).set("value", yytext);
		  return(TOK_INTEGER);
		}
{octinteger_ul}	{ loc();
                  stack(yyansi_clval).id("constant");
                  stack(yyansi_clval).type()=typet("integer");
                  stack(yyansi_clval).type().set("#width", "long");
                  stack(yyansi_clval).type().set("#unsigned", true);
                  stack(yyansi_clval).set("#cformat", yytext);
                  stack(yyansi_clval).set("#hex_or_oct", true);
                  mp_integer value=string2integer(yytext, 8);
                  stack(yyansi_clval).set("value", integer2string(value));
		  return(TOK_INTEGER);
		}
{hexinteger_ul}	{ loc();
                  stack(yyansi_clval).id("constant");
                  stack(yyansi_clval).type()=typet("integer");
                  stack(yyansi_clval).type().set("#width", "long");
                  stack(yyansi_clval).type().set("#unsigned", true);
                  stack(yyansi_clval).set("#cformat", yytext);
                  stack(yyansi_clval).set("#hex_or_oct", true);
                  std::string hex(yytext, 2, std::string::npos);
                  mp_integer value=string2integer(hex, 16);
                  stack(yyansi_clval).set("value", integer2string(value));
		  return(TOK_INTEGER);
		}
{decinteger_ll}	{ loc();
                  stack(yyansi_clval).id("constant");
                  stack(yyansi_clval).type()=typet("integer");
                  stack(yyansi_clval).type().set("#width", "longlong");
                  stack(yyansi_clval).set("value", yytext);
		  return(TOK_INTEGER);
		}
{octinteger_ll}	{ loc();
                  stack(yyansi_clval).id("constant");
                  stack(yyansi_clval).type()=typet("integer");
                  stack(yyansi_clval).type().set("#width", "longlong");
                  stack(yyansi_clval).set("#cformat", yytext);
                  stack(yyansi_clval).set("#hex_or_oct", true);
                  mp_integer value=string2integer(yytext, 8);
                  stack(yyansi_clval).set("value", integer2string(value));
		  return(TOK_INTEGER);
		}
{hexinteger_ll}	{ loc();
                  stack(yyansi_clval).id("constant");
                  stack(yyansi_clval).type()=typet("integer");
                  stack(yyansi_clval).type().set("#width", "longlong");
                  stack(yyansi_clval).set("#cformat", yytext);
                  stack(yyansi_clval).set("#hex_or_oct", true);
                  std::string hex(yytext, 2, std::string::npos);
                  mp_integer value=string2integer(hex, 16);
                  stack(yyansi_clval).set("value", integer2string(value));
		  return(TOK_INTEGER);
		}
{decinteger_ull} { loc();
                  stack(yyansi_clval).id("constant");
                  stack(yyansi_clval).type()=typet("integer");
                  stack(yyansi_clval).type().set("#width", "longlong");
                  stack(yyansi_clval).type().set("#unsigned", true);
                  stack(yyansi_clval).set("value", yytext);
		  return(TOK_INTEGER);
		 }
{octinteger_ull} { loc();
                  stack(yyansi_clval).id("constant");
                  stack(yyansi_clval).type()=typet("integer");
                  stack(yyansi_clval).type().set("#width", "longlong");
                  stack(yyansi_clval).type().set("#unsigned", true);
                  stack(yyansi_clval).set("#cformat", yytext);
                  stack(yyansi_clval).set("#hex_or_oct", true);
                  mp_integer value=string2integer(yytext, 8);
                  stack(yyansi_clval).set("value", integer2string(value));
		  return(TOK_INTEGER);
		}

{float}		{ loc();
                  convert_float_literal(yytext, stack(yyansi_clval));
                  PARSER.set_location(stack(yyansi_clval));
		  return(TOK_FLOATING);
		}
{float_f}	{ loc();
                  convert_float_literal(yytext, stack(yyansi_clval));
                  PARSER.set_location(stack(yyansi_clval));
		  return(TOK_FLOATING);
		}
{float_l}	{ loc();
                  convert_float_literal(yytext, stack(yyansi_clval));
                  PARSER.set_location(stack(yyansi_clval));
		  return(TOK_FLOATING);
		}

.		{ loc(); PARSER.tag_following=false; return(yytext[0]); }
}

<<EOF>>		{ yyterminate(); /* done! */ }

%%

int yywrap() { return 1; }
