/*
 * Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
 * See included license file for license details.
 */

%option c++
/* %option prefix="Elftosb" */
%option yylineno
%option never-interactive
%option yyclass="ElftosbLexer"
%option noyywrap

%{
#include "ElftosbLexer.h"
#include <stdlib.h>
#include <limits.h>
#include <string>
#include "HexValues.h"
#include "Value.h"

using namespace elftosb;

//! Always executed before all other actions when a token is matched.
//! This action just assign the first and last lines of the token to
//! the current line. In most cases this is correct.
#define YY_USER_ACTION	do {									\
							m_location.m_firstLine = m_line;		\
							m_location.m_lastLine = m_line;		\
						} while (0);

%}

DIGIT		[0-9]
HEXDIGIT	[0-9a-fA-F]
BINDIGIT	[0-1]
IDENT		[a-zA-Z_][a-zA-Z0-9_]*
ESC			\\(x{HEXDIGIT}{2}|.)

/* start conditions */
%x blob mlcmt

%%

options			{ return TOK_OPTIONS; }
constants		{ return TOK_CONSTANTS; }
sources			{ return TOK_SOURCES; }
filters			{ return TOK_FILTERS; }
section			{ return TOK_SECTION; }
extern			{ return TOK_EXTERN; }
from			{ return TOK_FROM; }
raw				{ return TOK_RAW; }
load			{ return TOK_LOAD; }
jump			{ return TOK_JUMP; }
call			{ return TOK_CALL; }
mode			{ return TOK_MODE; }
erase           { return TOK_ERASE; }
all             { return TOK_ALL; }
if				{ return TOK_IF; }
else			{ return TOK_ELSE; }
defined			{ return TOK_DEFINED; }
info			{ return TOK_INFO; }
warning			{ return TOK_WARNING; }
error			{ return TOK_ERROR; }
sizeof			{ return TOK_SIZEOF; }
dcd				{ return TOK_DCD; }
hab				{ return TOK_HAB; }
ivt             { return TOK_IVT; }
unsecure        { return TOK_UNSECURE; }
reset           { return TOK_RESET; }
jump_sp			{ return TOK_JUMP_SP; }
enable          { return TOK_ENABLE; }
keyblob         { return TOK_KEYBLOB; }
encrypt         { return TOK_ENCRYPT; }
keywrap         { return TOK_KEYWRAP; }

[whb]/[^a-zA-Z_0-9]					{	// must be followed by any non-ident char
										int_size_t theSize;
										switch (yytext[0])
										{
											case 'w':
												theSize = kWordSize;
												break;
											case 'h':
												theSize = kHalfWordSize;
												break;
											case 'b':
												theSize = kByteSize;
												break;
										}
										m_symbolValue.m_int = new elftosb::SizedIntegerValue(0, theSize);
										return TOK_INT_SIZE;
									}
									
true|yes							{
										m_symbolValue.m_int = new elftosb::SizedIntegerValue(1, kWordSize);
										return TOK_INT_LITERAL;
									}

false|no							{
										m_symbolValue.m_int = new elftosb::SizedIntegerValue(0, kWordSize);
										return TOK_INT_LITERAL;
									}

{IDENT}								{
										m_symbolValue.m_str = new std::string(yytext);
										if (isSourceName(m_symbolValue.m_str))
										{
											return TOK_SOURCE_NAME;
										}
										else
										{
											return TOK_IDENT;
										}
									}

({DIGIT}+|0x{HEXDIGIT}+|0b{BINDIGIT}+)([ \t]*[GMK])?			{
										int base = 0;
										uint32_t value;
										int mult;
										
										// check for binary number
										if (yytext[0] == '0' && yytext[1] == 'b')
										{
											base = 2;		// this is a binary number
											yytext += 2;	// skip over the "0b"
										}
										
										// convert value
										value = (uint32_t)strtoul(yytext, NULL, base);
										
										// find multiplier
										switch (yytext[strlen(yytext) - 1])
										{
											case 'G':
												mult = 1024 * 1024 * 1024;
												break;
											case 'M':
												mult = 1024 * 1024;
												break;
											case 'K':
												mult = 1024;
												break;
											default:
												mult = 1;
												break;
										}
										
										// set resulting symbol value
										m_symbolValue.m_int = new elftosb::SizedIntegerValue(value * mult, kWordSize);
										return TOK_INT_LITERAL;
									}

\'(.|ESC)\'|\'(.|ESC){2}\'|\'(.|ESC){4}\'		{
										uint32_t value = 0;
										int_size_t theSize;
										int len = strlen(yytext);
										if (len >= 3)
										{
											value = yytext[1];
											theSize = kByteSize;
										}
										if (len >= 4)
										{
											value = (value << 8) | yytext[2];
											theSize = kHalfWordSize;
										}
										if (len >= 6)
										{
											value = (value << 8) | yytext[3];
											value = (value << 8) | yytext[4];
											theSize = kWordSize;
										}
										m_symbolValue.m_int = new elftosb::SizedIntegerValue(value, theSize);
										return TOK_INT_LITERAL;
									}

\$[\.\*a-zA-Z0-9_\[\]\^\?\-]+					{
										// remove $ from string
										m_symbolValue.m_str = new std::string(&yytext[1]);
										return TOK_SECTION_NAME;
									}


"/*"                                { BEGIN(mlcmt); }

"{{"								{
										m_blob = new Blob();
										m_blobFirstLine = yylineno;
										BEGIN(blob);
									}

"{"									{ return '{'; }

"}"									{ return '}'; }

"("									{ return '('; }

")"									{ return ')'; }

"["									{ return '['; }

"]"									{ return ']'; }

"="									{ return '='; }

","									{ return ','; }

":"									{ return ':'; }

";"									{ return ';'; }

"."									{ return '.'; }

">"									{ return '>'; }

".."								{ return TOK_DOT_DOT; }

"+"									{ return '+'; }

"-"									{ return '-'; }

"*"									{ return '*'; }

"/"									{ return '/'; }

"%"									{ return '%'; }

"~"									{ return '~'; }

"^"									{ return '^'; }

"<<"								{ return TOK_LSHIFT; }

">>"								{ return TOK_RSHIFT; }

"&"									{ return '&'; }

"|"									{ return '|'; }

"**"								{ return TOK_POWER; }

"<"									{ return '<'; }

">="								{ return TOK_GEQ; }

"<="								{ return TOK_LEQ; }

"=="								{ return TOK_EQ; }

"!="								{ return TOK_NEQ; }

"&&"								{ return TOK_AND; }

"||"								{ return TOK_OR; }

"!"									{ return '!'; }

"@"									{ return '@'; }


\"(ESC|[^\"])*\"					{
										// get rid of quotes
										yytext++;
										yytext[strlen(yytext) - 1] = 0;
//										processStringEscapes(yytext, yytext);
										m_symbolValue.m_str = new std::string(yytext);
										return TOK_STRING_LITERAL;
									}

<blob>{HEXDIGIT}{2}					{
										uint8_t x = (hexCharToInt(yytext[0]) << 4) | hexCharToInt(yytext[1]);
										m_blob->append(&x, 1);
									}

<blob>"}}"							{
										BEGIN(INITIAL);
										m_symbolValue.m_blob = m_blob;
										m_blob = NULL;
										m_location.m_firstLine = m_blobFirstLine;
										return TOK_BLOB;
									}

<mlcmt>\*\/                         {
                                        // end of multi-line comment, return to initial state
                                        BEGIN(INITIAL);
                                    }


(#|\/\/).*$							/* absorb single-line comment */

<*>[ \t]							/* eat up whitespace in all states */

<*>(\r\n|\r|\n)						{
										/* eat up whitespace and count lines in all states */
										m_line++;
									}

<mlcmt>.                            /* ignore all other chars in a multi-line comment */

<*>.								{
										/* all other chars produce errors */
										char msg[50];
										sprintf(msg, "unexpected character '%c' on line %d", yytext[0], m_line);
										LexerError(msg);
									}

%%

// verbatim code copied to the bottom of the output


