/*
 * BPF asm code lexer
 *
 * This program is free software; you can distribute 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.
 *
 * Syntax kept close to:
 *
 * Steven McCanne and Van Jacobson. 1993. The BSD packet filter: a new
 * architecture for user-level packet capture. In Proceedings of the
 * USENIX Winter 1993 Conference Proceedings on USENIX Winter 1993
 * Conference Proceedings (USENIX'93). USENIX Association, Berkeley,
 * CA, USA, 2-2.
 *
 * Copyright 2013 Daniel Borkmann <borkmann@redhat.com>
 * Modified by Segev Finer for pybpf_asm
 * Licensed under the GNU General Public License, version 2.0 (GPLv2)
 */

%{

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>

#include <linux/filter.h>

#include "bpf_exp.yacc.h"

extern void yyerror(yyscan_t scanner, yyparse_t parser, const char *str);

%}

%option align
%option ecs

%option nounput
%option noreject
%option noinput
%option noyywrap

%option 8bit
%option caseless
%option yylineno

%option reentrant
%option bison-bridge
%option extra-type="yyparse_t"

%%

"ldb"		{ return OP_LDB; }
"ldh"		{ return OP_LDH; }
"ld"		{ return OP_LD; }
"ldi"		{ return OP_LDI; }
"ldx"		{ return OP_LDX; }
"ldxi"		{ return OP_LDXI; }
"ldxb"		{ return OP_LDXB; }
"st"		{ return OP_ST; }
"stx"		{ return OP_STX; }
"jmp"		{ return OP_JMP; }
"ja"		{ return OP_JMP; }
"jeq"		{ return OP_JEQ; }
"jneq"		{ return OP_JNEQ; }
"jne"		{ return OP_JNEQ; }
"jlt"		{ return OP_JLT; }
"jle"		{ return OP_JLE; }
"jgt"		{ return OP_JGT; }
"jge"		{ return OP_JGE; }
"jset"		{ return OP_JSET; }
"add"		{ return OP_ADD; }
"sub"		{ return OP_SUB; }
"mul"		{ return OP_MUL; }
"div"		{ return OP_DIV; }
"mod"		{ return OP_MOD; }
"neg"		{ return OP_NEG; }
"and"		{ return OP_AND; }
"xor"		{ return OP_XOR; }
"or"		{ return OP_OR; }
"lsh"		{ return OP_LSH; }
"rsh"		{ return OP_RSH; }
"ret"		{ return OP_RET; }
"tax"		{ return OP_TAX; }
"txa"		{ return OP_TXA; }

"#"?("len")	{ return K_PKT_LEN; }

"#"?("proto")	{
		yylval->number = SKF_AD_PROTOCOL;
		return extension;
	}
"#"?("type")	{
		yylval->number = SKF_AD_PKTTYPE;
		return extension;
	}
"#"?("poff")	{
		yylval->number = SKF_AD_PAY_OFFSET;
		return extension;
	}
"#"?("ifidx")	{
		yylval->number = SKF_AD_IFINDEX;
		return extension;
	}
"#"?("nla")	{
		yylval->number = SKF_AD_NLATTR;
		return extension;
	}
"#"?("nlan")	{
		yylval->number = SKF_AD_NLATTR_NEST;
		return extension;
	}
"#"?("mark")	{
		yylval->number = SKF_AD_MARK;
		return extension;
	}
"#"?("queue")	{
		yylval->number = SKF_AD_QUEUE;
		return extension;
	}
"#"?("hatype")	{
		yylval->number = SKF_AD_HATYPE;
		return extension;
	}
"#"?("rxhash")	{
		yylval->number = SKF_AD_RXHASH;
		return extension;
	}
"#"?("cpu")	{
		yylval->number = SKF_AD_CPU;
		return extension;
	}
"#"?("vlan_tci") {
		yylval->number = SKF_AD_VLAN_TAG;
		return extension;
	}
"#"?("vlan_pr")	{
		yylval->number = SKF_AD_VLAN_TAG_PRESENT;
		return extension;
	}
"#"?("vlan_avail") {
		yylval->number = SKF_AD_VLAN_TAG_PRESENT;
		return extension;
	}
"#"?("vlan_tpid") {
		yylval->number = SKF_AD_VLAN_TPID;
		return extension;
	}
"#"?("rand")	{
		yylval->number = SKF_AD_RANDOM;
		return extension;
	}

":"		{ return ':'; }
","		{ return ','; }
"#"		{ return '#'; }
"%"		{ return '%'; }
"["		{ return '['; }
"]"		{ return ']'; }
"("		{ return '('; }
")"		{ return ')'; }
"x"		{ return 'x'; }
"a"		{ return 'a'; }
"+"		{ return '+'; }
"M"		{ return 'M'; }
"*"		{ return '*'; }
"&"		{ return '&'; }

([0][x][a-fA-F0-9]+) {
			yylval->number = strtoul(yytext, NULL, 16);
			return number;
		}
([0][b][0-1]+)	{
			yylval->number = strtol(yytext + 2, NULL, 2);
			return number;
		}
(([0])|([-+]?[1-9][0-9]*)) {
			yylval->number = strtol(yytext, NULL, 10);
			return number;
		}
([0][0-7]+)	{
			yylval->number = strtol(yytext + 1, NULL, 8);
			return number;
		}
[a-zA-Z_][a-zA-Z0-9_]+ {
			yylval->label = strdup(yytext);
			return label;
		}

"/*"([^\*]|\*[^/])*"*/"		{ /* NOP */ }
";"[^\n]*			{ /* NOP */ }
^#.*				{ /* NOP */ }
[ \t]+				{ /* NOP */ }
[ \n]+				{ /* NOP */ }

.		{
			yyerror(yyscanner, yyextra, "lex unknown character");
			return YYerror;
		}

%%
