/*
 *  smoke16/src/smoke16as.yy.l - Flex scanner for the SMOKE-16 assembler.
 *  $Revision: 1.52 $
 *  Copyright 1997-2000, Benjamin Sittler
 *
 *  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.
 *
 */

%option noyywrap
%option stack

%{
#define LEX_VERSION \
   "scanner $Revision: 1.52 $\n"

/* convert binary literal */
long stob(char *s);

#define YY_NO_UNPUT
#define YY_NO_TOP_STATE
%}

%x MULTI_COMMENT
%x COMMENT
%x STRING
%x CHARS

DIGIT	[[:digit:]]
HEX	[[:xdigit:]]
ID	[[:alpha:]_\.$][[:alnum:]_\.$]*
NID	[^[:alnum:]_\.$]

%%

<INITIAL,STRING,CHARS>\\\n	lineno++; /* eat backslashed newlines */

<INITIAL,COMMENT>\"	{ yy_push_state(STRING); return yytext[0]; }
<STRING>\"		{ yy_pop_state(); return yytext[0]; }
<INITIAL>\'		{ encoding = xencoding; yy_push_state(CHARS); return yytext[0]; }
<CHARS>\'		{ encoding = ENCODING_NATIVE; yy_pop_state(); return yytext[0]; }
<CHARS,STRING>\\[xX]{HEX}+ { long val; sscanf(yytext+2, "%lx", &val); yylval.ul = val; return CHAR; }
<CHARS,STRING>\\{DIGIT}+ { long val; sscanf(yytext+1, "%lo", &val); yylval.ul = val; return CHAR; }
<CHARS,STRING>\\a	{ yylval.ul = xchar(CTOI('\a')); return CHAR; }
<CHARS,STRING>\\b	{ yylval.ul = xchar(CTOI('\b')); return CHAR; }
<CHARS,STRING>\\f	{ yylval.ul = xchar(CTOI('\f')); return CHAR; }
<CHARS,STRING>\\n	{ yylval.ul = xchar(CTOI('\n')); return CHAR; }
<CHARS,STRING>\n	{ yylval.ul = xchar(CTOI('\n')); lineno++; return CHAR; /* count newlines */ }
<CHARS,STRING>\\r	{ yylval.ul = xchar(CTOI('\r')); return CHAR; }
<CHARS,STRING>\\t	{ yylval.ul = xchar(CTOI('\t')); return CHAR; }
<CHARS,STRING>\\v	{ yylval.ul = xchar(CTOI('\v')); return CHAR; }
<CHARS,STRING>\\\\	{ yylval.ul = xchar(CTOI('\\')); return CHAR; }
<CHARS,STRING>\\\?	{ yylval.ul = xchar(CTOI('\?')); return CHAR; }
<CHARS,STRING>\\\'	{ yylval.ul = xchar(CTOI('\'')); return CHAR; }
<CHARS,STRING>\\\"	{ yylval.ul = xchar(CTOI('\"')); return CHAR; }
<CHARS,STRING>\\.	{
                           char msg[] = "unknown character escape sequence: '\\ '";
			   
			   msg[strlen(msg)-2] = yytext[1];
			   yyerror(msg);
                        }
<CHARS,STRING>.		{ yylval.ul = xchar(CTOI(yytext[0])); return CHAR; }

<INITIAL,MULTI_COMMENT>\n\n*	{
				   lineno += strlen(yytext); /* count newlines */
				   return yytext[0];
				}

"^#"/[ \t]*[[:digit:]]	{ /* start a one-line comment of the special `# number "file"' form */
			  yy_push_state(COMMENT);
			  return '#';
			}

"//"[^\n]*	/* eat a one-line comment */
<COMMENT>[ \t]*	/* eat up whitespace in a one-line comment */

<INITIAL,COMMENT>"0"[xX]{HEX}+	{ long val; sscanf(yytext+2, "%lx", &val); yylval.ul = val; return NUMBER; }
<INITIAL,COMMENT>"0"[bB][01]+	{ yylval.ul = stob(yytext+2); return NUMBER; }
<INITIAL,COMMENT>"0"{DIGIT}*	{ long val; sscanf(yytext, "%lo", &val); yylval.ul = val; return NUMBER; }
<INITIAL,COMMENT>{DIGIT}+	{ long val; sscanf(yytext, "%ld", &val); yylval.ul = val; return NUMBER; }
<INITIAL,COMMENT>"#"[^\n]*	/* eat a one-line comment */

<COMMENT>[^\n][^\n]*	return '#'; /* munch */

<COMMENT>\n\n*	{ /* end a one-line comment */
	   lineno += strlen(yytext);
	   yy_pop_state();
	   return '\n'; /* count newlines */
	}

"/*"	yy_push_state(MULTI_COMMENT); /* start a multi-line comment */

<MULTI_COMMENT>"*/"	yy_pop_state(); /* end a multi-line comment */

<MULTI_COMMENT>.	/* eat multi-line comments */

mov/{NID}	{ return MOV; }
ld/{NID}	{ return LD; }
st/{NID}	{ return ST; }
lds/{NID}	{ return LDS; }
sts/{NID}	{ return STS; }
ldi/{NID}	{ return LDI; }
movb/{NID}	{ return MOVB; }
ldb/{NID}	{ return LDB; }
stb/{NID}	{ return STB; }
ldbi/{NID}	{ return LDBI; }
add/{NID}	{ return ADD; }
addi/{NID}	{ return ADDI; }
sub/{NID}	{ return SUB; }
subi/{NID}	{ return SUBI; }
sethi/{NID}	{ yylval.ul=0x7000; return SETHI; }
cmp/{NID}	{ yylval.ul=0xf100; return CMP; }
cmpl/{NID}	{ yylval.ul=0x1000; return CMP; }
and/{NID}	{ yylval.ul=0x4000; return OP_3REG; }
or/{NID}	{ return OR; }
xor/{NID}	{ yylval.ul=0xb000; return OP_3REG; }
not/{NID}	{ yylval.ul=0xf000; return NOT; }
rol/{NID}	{ yylval.ul=0x2000; return SHIFT; }
ror/{NID}	{ yylval.ul=0x3000; return SHIFT; }
sl/{NID}	{ yylval.ul=0x8000; return SHIFT; }
sla/{NID}	{ yylval.ul=0x8000; return SHIFT; }
sll/{NID}	{ yylval.ul=0x8000; return SHIFT; }
sr/{NID}	{ yylval.ul=0x9000; return SHIFT; }
sra/{NID}	{ yylval.ul=0x9000; return SHIFT; }
srl/{NID}	{ yylval.ul=0xa000; return SHIFT; }
bl|bc/{NID}	{ yylval.ul=0xf600; return B; }
bge|bnc/{NID}	{ yylval.ul=0xf900; return B; }
be|bz/{NID}	{ yylval.ul=0xf700; return B; }
bne|bnz/{NID}	{ yylval.ul=0xf800; return B; }
bg/{NID}	{ yylval.ul=0xfa00; return B; }
b/{NID}	{ yylval.ul=0xfb00; return B; }
jal/{NID}	{ yylval.ul=0xc000; return JAL; }
j/{NID}	{ yylval.ul=0xc000; return J; }
call/{NID}	{ yylval.ul=0xc000; return CALL; }
ret/{NID}	{ yylval.ul=0xc000; return RET; }
int/{NID}	{ yylval.ul=0xfc00; return INT; }
iret/{NID}	{ yylval.ul=0xffff; return OP16; }
nop/{NID}	{ yylval.ul=0xfff0; return OP16; }
push/{NID}	{ return PUSH; }
pop/{NID}	{ return POP; }

"%"(r0|0)/{NID}	{ yylval.ul=0; return REG; }
"%"(r1|t0|1)/{NID}	{ yylval.ul=1; return REG; }
"%"(r2|t1|2)/{NID}	{ yylval.ul=2; return REG; }
"%"(r3|t2|3)/{NID}	{ yylval.ul=3; return REG; }
"%"(r4|t3|4)/{NID}	{ yylval.ul=4; return REG; }
"%"(r5|t4|5)/{NID}	{ yylval.ul=5; return REG; }
"%"(r6|t5|6)/{NID}	{ yylval.ul=6; return REG; }
"%"(r7|t6|7)/{NID}	{
                          if (! allow_r7)
                             yyerror("register %r7/%t6/%7 is reserved -- override with assembler option -r7");
                          yylval.ul=7;
                          return REG;
                        }
"%"(r8|a0|8)/{NID}	{ yylval.ul=8; return REG; }
"%"(r9|a1|9)/{NID}	{ yylval.ul=9; return REG; }
"%"(r10|a2|10)/{NID}	{ yylval.ul=10; return REG; }
"%"(r11|a3|11)/{NID}	{ yylval.ul=11; return REG; }
"%"(r12|fp|12)/{NID}	{ yylval.ul=12; return REG; }
"%"(r13|sp|13)/{NID}	{ yylval.ul=13; return REG; }
"%"(r14|ra|14)/{NID}	{ yylval.ul=14; return REG; }
"%"(r15|gp|15)/{NID}	{ yylval.ul=15; return REG; }

"%"(s0|pc)/{NID}	{ yylval.ul=0; return SREG; }
"%"(s1|ps)/{NID}	{ yylval.ul=1; return SREG; }
"%"(s2|pt)/{NID}	{ yylval.ul=2; return SREG; }
"%"(s3|tt)/{NID}	{ yylval.ul=3; return SREG; }

"%lo"/{NID}	{ return LO; }
"%hi"/{NID}	{ return HI; }
"%lo16"/{NID}	{ return LO16; }
"%hi16"/{NID}	{ return HI16; }

".align"/{NID}		{ return _ALIGN; }
".ascii"/{NID}		{ return _ASCII; }
".asciz"|".asciiz"/{NID}	{ return _ASCIIZ; }
".string"/{NID}		{ return _STRING; }
".zstring"|".stringz"/{NID}	{ return _ZSTRING; }
".byte"/{NID}			{ return _BYTE; }
".short"|".half"|".hword"/{NID} { return _WORD; }
".int"|".word"/{NID}		{ return _WORD; }
".long"|".dword"/{NID}	{ return _LONG; }
".text"/{NID}			{ yylval.ul=SECT_TEXT; return SECT_ID; }
".data"/{NID}			{ yylval.ul=SECT_DATA; return SECT_ID; }
".rodata"|".rdata"/{NID}	{ yylval.ul=SECT_RDATA; return SECT_ID; }
".bss"/{NID}			{ yylval.ul=SECT_BSS; return SECT_ID; }
".abs"/{NID}			{ yylval.ul=SECT_ABS; return SECT_ID; }
".skip"|".space"|".zero"/{NID} { return _SPACE; }
".lcomm"/{NID}		{ return _LCOMM; }
".comm"/{NID}			{ return _COMM; }
".globl"|".global"/{NID}	{ return _GLOBAL; }
".set"/{NID}			{ return _SET; }
".line"|".ln"/{NID}		{ return _LINE; }
".app-file"|".file"/{NID}	{ return _FILE; }

{ID}	{
          if(isconst(yytext)) {
	    yylval.ul = getconst(yytext);
	    return NUMBER;
	  }
          if (! (yylval.string = strdup(yytext))) {
            perror("strdup");
            cleanup(), exit(1);
          }
	  return SYMBOL;
	}

[ \t]*	/* eat up whitespace */

;;*	return '\n';
.	return yytext[0];

%%

/* convert binary literal */
long stob(char *s) {
   unsigned long val = 0UL;

   while (*s)
      val = (val << 1) + (*s ++ == '1');
   return val;
}
