%{
#include <ctype.h>
#include "corewar.h"
#include "asm.h"
#include "asm_parse.h"

#ifdef  YACC
extern YYSTYPE  yylval;  /* With Bison, this line isn't necessary. */
#endif  YACC

/* Flex can be done case independant.  Lex isn't so nifty.  Grrr. */
/* And while I'm at it, the whole way lex handles EOF really ticks me off. */
#ifdef  LEX
#undef  input
#define  input()  (((yytchar=yysptr>yysbuf?U(*--yysptr):getc(yyin))==10?(yylineno++,yytchar):yytchar)==EOF?0:(isupper(yytchar)?tolower(yytchar):yytchar))

int  yyrestart()  {
	return(1);
}
#endif  /* LEX */
%}

DIGIT	[0-9]
ID	[a-z_][a-z0-9_]*

%%

{DIGIT}+	{
	int  i, sum, oldsum;

	if (yyleng > STR_MAXLEN-2)  {
		yytext[STR_MAXLEN-1] = '\0';
		sprintf(cwerrstr, "String \"%s\" too long.  "
		        "Maximum length is %d characters.", yytext, STR_MAXLEN - 2);
		return(tt_nogood);
	}
	for (i = 0, sum = 0;  i < yyleng;  ++i)  {
		oldsum = sum;
		sum = (sum * 10) + yytext[i] - '0';
		if (sum/10 != oldsum)  {
			sprintf(cwerrstr, "Overflow on \"%s\".", yytext);
			return(tt_nogood);
		}
	}
	yylval.val = sum;
	return(tt_id);
	}


^"id"	{
	if (split_id)
		return(tt_progid);
	else
		return(tt_label);
}

"id"	{
	if (split_id)
		return(tt_progid);
	else {
		yylval.val = AVAL_NOGOOD;
		return(tt_id);
	}
}


dat	{ yylval.op = op_dat;  return(tt_op); }

mov	{ yylval.op = op_mov;  return(tt_op); }

add	{ yylval.op = op_add;  return(tt_op); }

sub	{ yylval.op = op_sub;  return(tt_op); }

jmp	{ yylval.op = op_jmp;  return(tt_op); }

jmz	{ yylval.op = op_jmz;  return(tt_op); }

jmn	{ yylval.op = op_jmn;  return(tt_op); }

djn	{ yylval.op = op_djn;  return(tt_op); }

cmp	{ yylval.op = op_cmp;  return(tt_op); }

spl	{ yylval.op = op_spl;  return(tt_op); }

slt	{ yylval.op = op_slt;  return(tt_op); }

equ	{ yylval.op = op_equ;  return(tt_op); }

end	{ yylval.op = op_end;  return(tt_op); }

^{ID}":"?	{
	if (yyleng > STR_MAXLEN-1)  {
		yytext[STR_MAXLEN-1] = '\0';
		sprintf(cwerrstr, "String \"%s\" too long.  "
		        "Maximum length is %d characters.", yytext, STR_MAXLEN - 2);
		return(tt_nogood);
	}
	return(tt_label);
}

{ID}	{
	if (yyleng > STR_MAXLEN-2)  {
		yytext[STR_MAXLEN-1] = '\0';
		sprintf(cwerrstr, "String \"%s\" too long.  "
		        "Maximum length is %d characters.", yytext, STR_MAXLEN - 2);
		return(tt_nogood);
	}
	yylval.val = AVAL_NOGOOD;
	return(tt_id); }

"+"	return(tt_add);

"-"	return(tt_sub);

"*"	return(tt_mul);

"/"	return(tt_div);

"("	return(tt_oparen);

")"	return(tt_cparen);

"@"	{ yylval.am = am_ind;  return(tt_am); }

"<"	{ yylval.am = am_dec;  return(tt_am); }

"#"	{ yylval.am = am_imm;  return(tt_am); }

">"	{
	if (!postinc)  {
		sprintf(cwerrstr, "Postincrement addressing is not enabled.\n");
		return(tt_nogood);
	}
	yylval.am = am_inc;
	return(tt_am); }

","	return(tt_comma);

^";name".*$	{
	if (yyleng > STR_MAXLEN-2)  {
		yytext[STR_MAXLEN-1] = '\0';
		sprintf(cwerrstr, "String \"%s\" too long.  "
		        "Maximum length is %d characters.", yytext, STR_MAXLEN - 2);
		return(tt_nogood);
	}
	return(tt_name);
	}

^";author".*$	{
	if (yyleng > STR_MAXLEN-1)  {
		yytext[STR_MAXLEN-1] = '\0';
		sprintf(cwerrstr, "String \"%s\" too long.  "
		        "Maximum length is %d characters.", yytext, STR_MAXLEN - 2);
		return(tt_nogood);
	}
	return(tt_author);
	}

^";address".*$	{
	if (yyleng > STR_MAXLEN-2)  {
		yytext[STR_MAXLEN-1] = '\0';
		sprintf(cwerrstr, "String \"%s\" too long.  "
		        "Maximum length is %d characters.", yytext, STR_MAXLEN - 2);
		return(tt_nogood);
	}
	return(tt_address);
	}

";".*$	{ /* Comment.  Strip it out. */ }

"\n"	{ ++asm_line_number; return(tt_eoln); }

[ \t]+	{ /* Whitespace.  Do nothing. */ }

":"	{
	return(tt_nogood); }

.	{
	if (isprint(yytext[0]))
		sprintf(cwerrstr, "Illegal character %d (\"%s\").",
			yytext[0], yytext);
	else
		sprintf(cwerrstr, "Illegal character %d.", yytext[0]);
	asm_error_loc(asm_line_number);
	return(tt_nogood); }
