/* $Id$
 * vim:tabstop=8 shiftwidth=8 textwidth=72:
 * Scanner for intermediate code.
 *
 * Copyright (C) 2008-2009 FAUmachine Team <info@faumachine.org>.
 * This program is free software. You can redistribute it and/or modify it
 * under the terms of the GNU General Public License, either version 2 of
 * the License, or (at your option) any later version. See COPYING.
 */

/* options */
%option case-insensitive
%option noyywrap
%option nounput
%option yylineno
%option noinput

/* start conditions */
/* tokens found in annotations, most will be thrown away */
%x ANNOTATION
/* any specification in the form name=int | name="string" found in
 * annotations */
%x ANNOTATION_SPEC

%{
#include <assert.h>
#include <stdlib.h>
#include "fauhdli_private.h"
#include "icparser.h"
#include "glue-log.h"
#include "fauhdlstring.h"

#define YY_DECL \
int yylex(\
	const struct fauhdli *instance, \
	const char *filename\
)
%}

char		[a-zA-Z]
id_char		[_a-zA-Z0-9]
digit		[0-9]
pos_number	{digit}{digit}*
number		-?{pos_number}
fraction	\.{pos_number}
integer 	\${number}L
real		\${number}{fraction}?F
identifier	{id_char}*{char}{id_char}*
ref_str		{id_char}*
reference	\"{ref_str}\"
label		{identifier}:
target		@{identifier}
ws_char		[ \t]
whitespace	{ws_char}*
register	%reg_{pos_number}
type_spec_i	i
type_spec_f	f
type_spec_p	p

a_name		{identifier}
a_string	{reference}
a_int		[0-9]+
a_spec_int	{a_name}={a_int}
a_spec_string	{a_name}={a_string}
a_spec		{a_spec_int}|{a_spec_string}

%%
<*>"\n"		{  yylloc.first_line++; }
<*>{whitespace}	{}
<ANNOTATION>"}" {	
			BEGIN(INITIAL);
		}
<ANNOTATION>{a_spec}	{
			BEGIN(ANNOTATION_SPEC);
			yyless(0);
		}
<ANNOTATION_SPEC>"=" {
			return t_AnnotateEqSym;
		}
<ANNOTATION_SPEC>{a_name} {
			yylval.text = fauhdlstrdup(yytext,
						instance->callbacks.malloc);
			return t_AnnotateName;
		}
<ANNOTATION_SPEC>{a_string} {
			yylval.text = fauhdlstrdup(&yytext[1],
						instance->callbacks.malloc);
			yylval.text[strlen(yylval.text) - 1] = '\0';
			BEGIN(ANNOTATION);
			return t_AnnotateString;
		}
<ANNOTATION_SPEC>{a_int} {
			yylval.annotate_int = atoi(yytext);
			BEGIN(ANNOTATION);
			return t_AnnotateInt;
		}
<ANNOTATION>.	{ 	/* anything unmatched is ok in annotations as
			   well, and won't result in a token */
		}
"("		{	return t_LeftParen; }
")"		{	return t_RightParen; }
"["		{	return t_LeftBracket; }
"]"		{	return t_RightBracket; }
","		{ 	return t_Comma; }
":"		{	return t_Colon; }
":="		{ 	return t_ValAssign; }
"->"		{	return t_Arrow; }
;		{ 	return t_Semicolon; }
".registers"	{	return t_Registers; }
".text"		{ 	return t_CodeSegment; }
".stack"	{ 	return t_StackSegment; }
".transfer"	{	return t_TransferSegment; }
".types"	{	return t_TypeSegment; }
"{"		{	
			BEGIN(ANNOTATION);
		}
is		{	return t_IS; }
mov		{ 	return t_MOV; }
abort		{	return t_ABORT; }
add		{ 	return t_ADD; }
sub		{ 	return t_SUB; }
imul		{ 	return t_IMUL; }
div		{	return t_DIV; }
call		{ 	return t_CALL; }
return  	{ 	return t_RETURN; }
proc		{	return t_PROC; }
update  	{ 	return t_UPDATE; }
getsig		{	return t_GETSIG; }
gettime		{	return t_GETSIMTIME; }
jmp		{ 	return t_JMP; }
je		{ 	return t_JE; }
jb		{ 	return t_JB; }
jbe		{ 	return t_JBE; }
jne		{ 	return t_JNE; }
aoffset 	{ 	return t_AOFFSET; }
roffset 	{ 	return t_ROFFSET; }
data		{ 	return t_DATA; }
type		{ 	return t_TYPE; }
container	{ 	return t_CONTAINER; }
signal		{	return t_SIGNAL; }
driver		{ 	return t_DRIVER; }
variable	{	return t_VARIABLE; }
connect		{	return t_CONNECT; }
end		{	return t_END; }
begintr		{	return t_BEGINTRANSFER; }
endtr		{	return t_ENDTRANSFER; }
getparm		{	return t_GETPARAM; }
setparm		{	return t_SETPARAM; }
resolvedby	{	return t_RESOLVEDBY; }
suspend		{	return t_SUSPEND; }
wakeon		{	return t_WAKEON; }
wakeat		{	return t_WAKEAT; }
log		{	return t_LOG; }
{type_spec_i}	{	return t_TypeSpecInt; }
{type_spec_f}	{	return t_TypeSpecFloat; }
{type_spec_p}	{	return t_TypeSpecPointer; }
{register}	{	yylval.number = atol(&yytext[5]);
			return t_Register;
		}
{label}		{	yylval.text = fauhdlstrdup(yytext,
						instance->callbacks.malloc);
			/* drop trailing ":" */
			yylval.text[strlen(yylval.text) - 1] = '\0';
		  	return t_Label; 
		}
{identifier}	{	yylval.text = fauhdlstrdup(yytext, 
						instance->callbacks.malloc);
			return t_Identifier;
		}
{reference}	{	/* remove quotes */
			yylval.text = fauhdlstrdup(&yytext[1],
						instance->callbacks.malloc);
			yylval.text[strlen(yylval.text) - 1] = '\0';
			return t_Reference;
		}
{integer}	{	
			yylval.univ_int = atoll(&yytext[1]);
			return t_Int; 
		}
{real}		{	yylval.univ_real = atof(&yytext[1]);
			return t_Float; 
		}
{pos_number}	{	yylval.univ_int = atoll(yytext);
			return t_PosNumber;
		}
{target}	{
			yylval.text = fauhdlstrdup(&yytext[1],
						instance->callbacks.malloc);
		  	return t_Target; 
		}
.		{ 	
			instance->callbacks.log(
				FAUHDLI_LOG_ERROR, "fauhdli", "scanner",
				"%s:%d: invalid character '%c' in stream.\n",
				filename, yylineno, yytext[0]);
			return t_Invalid;
		}
