#####BASIC RULES#####
HTAB = %x09;
CR = %x0d;
LF = %x0a;
SP = %x20;
CRLF = [CR] LF;
QUOT = %x22;
HASH = %x23;
COMMA = %x2c;
DOT = %x2e;
COLON = %x3a;
SEMICOLON = %x3b;
EQ = %x3d;
UNDERSCORE = %x5f;
ALPHA = %x41-5a / %x61-7a;
DIGIT = %x30-39;
HEXDIG = DIGIT / "A" / "B" / "C" / "D" / "E" / "F" ;
VCHAR = %x21-7e;

#####COMMON RULES#####
fmtSeparator = SP / HTAB;
escSymbol = ALPHA / DIGIT / SP / %x21 / %x5c %x22 / %x23-2f / %x3a-40 / %x5b / %x5c %x5c / %x5d-60 / %x7b-7e / %x5c %x72 / %x5c %x6e / %x5c %x74;
qualifier = (ALPHA / UNDERSCORE) *(ALPHA / DIGIT / UNDERSCORE);
className = %x4c qualifier *(%x2f qualifier) ["$" qualifier] SEMICOLON;
commentSequence = %x23 *(fmtSeparator / VCHAR);
comment = *fmtSeparator commentSequence CRLF;
emptyLine = *fmtSeparator CRLF;
skipLine = comment / emptyLine;
fileName = QUOT *(ALPHA / DIGIT) DOT *(ALPHA / DIGIT) QUOT;
accessMode = "public" / "private" / "protected" / "static" / "final" / "abstract";
type = "V" / "Z" / "B" / "S" / "C" / "I" / "J" / "F" / "D" / className / "[" type;
boolValue = "true" / "false";
intDecValue = [%x2d] 1*DIGIT;
intHexValue = [%x2d] %x30 %x78 1*HEXDIG;
intValue = intHexValue / intDecValue;
strValue = QUOT *escSymbol QUOT;
value = boolValue / intValue / strValue;
label = COLON qualifier;
smaliParam = "p" intDecValue;
smaliVar   = "v" intDecValue;
smaliVarDst = smaliVar;
smaliVarInit = smaliVar;
smaliVarGroup = "{" *fmtSeparator (smaliParam / smaliVar) *fmtSeparator *(COMMA *fmtSeparator (smaliParam / smaliVar) *fmtSeparator) "}";

#####SMALI DIRECTIVE RULE#####
endDirective = ".end";
classDirective = ".class";
superDirective = ".super";
sourceDirective = ".source";
implementsDirective = ".implements";
fieldDirective = ".field";
methodDirective = ".method";
endMethodDirective = endDirective *fmtSeparator "method";
registersDirective = ".registers";
localDirective = ".local";

#####SMALI GENERAL RULES#####
smali = classHeader *(classField / skipLine) *(classMethod / skipLine);
todoStubLine = *(VCHAR / fmtSeparator);

#####SMALI HEADER RULES#####
classHeader = classDirectiveHeader superDirectiveHeader [sourceDirectiveHeader] *implementsDirectiveHeader;
classDirectiveHeader = *fmtSeparator classDirective *fmtSeparator *(accessMode *fmtSeparator) *fmtSeparator className *fmtSeparator CRLF;

superDirectiveHeader = *fmtSeparator superDirective *fmtSeparator className *fmtSeparator CRLF;

sourceDirectiveHeader = *fmtSeparator sourceDirective *fmtSeparator fileName *fmtSeparator CRLF;

implementsDirectiveHeader = *fmtSeparator implementsDirective *fmtSeparator className *fmtSeparator CRLF;

#####SMALI FIELD RULES#####
classField = *fmtSeparator fieldDirective 1*fmtSeparator *(accessMode 1*fmtSeparator) qualifier COLON type *fmtSeparator [EQ *fmtSeparator value] *fmtSeparator CRLF;

#####SMALI METHOD RULES#####
classMethod = *(fmtSeparator) methodDirective *(fmtSeparator) *(accessMode 1*fmtSeparator) (classConstructorName / qualifier) *(fmtSeparator) classMethodProto *(fmtSeparator) CRLF methodBody *(fmtSeparator) endMethodDirective *(fmtSeparator) CRLF;
classConstructorName = "constructor" *(fmtSeparator) smaliConstructorName;
classMethodProto = %x28 *type %x29 type;
methodBody = [methodLineLocals] [methodLineRegisters] *(methodLineParam / skipLine) methodLinePrologue *(methodLineNumber / methodLineLocal / cmdAny / skipLine);
methodLineLocals = *fmtSeparator ".locals" 1*fmtSeparator intValue *fmtSeparator CRLF;
methodLineParam = *fmtSeparator ".parameter" [1*fmtSeparator strValue *fmtSeparator] *fmtSeparator CRLF;
methodLinePrologue = *fmtSeparator ".prologue" *fmtSeparator CRLF;
methodLineNumber = *fmtSeparator ".line" 1*fmtSeparator intValue *fmtSeparator CRLF;
methodLineRegisters = *fmtSeparator ".registers" 1*fmtSeparator intValue *fmtSeparator CRLF;
methodLineLocal = *fmtSeparator ".local" 1*fmtSeparator todoStubLine CRLF;

smaliConstructorName = ("<init>" / "<clinit>");
smaliFieldRef = className "->" qualifier COLON type;
smaliMethodRef = className "->" (smaliConstructorName / qualifier) classMethodProto;

#####SMALI COMMANDS RULES#####
cmdAny =  cmdConst4;
cmdAny =/ cmdConstString;
cmdAny =/ cmdGoto;
cmdAny =/ cmdIfEq;
cmdAny =/ cmdIfEqz;
cmdAny =/ cmdIfNe;
cmdAny =/ cmdIfNez;
cmdAny =/ cmdIget;
cmdAny =/ cmdIgetObject;
cmdAny =/ cmdIgetWide;
cmdAny =/ cmdInvokeDirect;
cmdAny =/ cmdInvokeStatic;
cmdAny =/ cmdInvokeVirtual;
cmdAny =/ cmdIput;
cmdAny =/ cmdIputObject;
cmdAny =/ cmdIputWide;
cmdAny =/ cmdLabel;
cmdAny =/ cmdMove;
cmdAny =/ cmdMoveResultObject;
cmdAny =/ cmdNewInstance;
cmdAny =/ cmdNop;
cmdAny =/ cmdReturn;
cmdAny =/ cmdReturnObject;
cmdAny =/ cmdReturnVoid;
cmdAny =/ cmdReturnWide;
cmdAny =/ cmdSputObject;

cmdConst4           = *fmtSeparator "const/4" 1*fmtSeparator smaliVarInit *fmtSeparator COMMA *fmtSeparator intValue *fmtSeparator [commentSequence] CRLF;
cmdConstString      = *fmtSeparator "const-string" 1*fmtSeparator smaliVarInit *fmtSeparator COMMA *fmtSeparator strValue *fmtSeparator [commentSequence] CRLF;
cmdGoto             = *fmtSeparator "goto" 1*fmtSeparator label *fmtSeparator [commentSequence] CRLF;
cmdIfEq             = *fmtSeparator "if-eq" 1*fmtSeparator (smaliVar / smaliParam) *fmtSeparator COMMA *fmtSeparator (smaliVar / smaliParam) *fmtSeparator COMMA *fmtSeparator label *fmtSeparator [commentSequence] CRLF;
cmdIfEqz            = *fmtSeparator "if-eqz" 1*fmtSeparator (smaliVar / smaliParam) *fmtSeparator COMMA *fmtSeparator label *fmtSeparator [commentSequence] CRLF;
cmdIfNe             = *fmtSeparator "if-ne" 1*fmtSeparator (smaliVar / smaliParam) *fmtSeparator COMMA *fmtSeparator (smaliVar / smaliParam) *fmtSeparator COMMA *fmtSeparator label *fmtSeparator [commentSequence] CRLF;
cmdIfNez            = *fmtSeparator "if-nez" 1*fmtSeparator (smaliVar / smaliParam) *fmtSeparator COMMA *fmtSeparator label *fmtSeparator [commentSequence] CRLF;
cmdIget             = *fmtSeparator "iget" 1*fmtSeparator smaliVarDst *fmtSeparator COMMA *fmtSeparator (smaliVar / smaliParam) *fmtSeparator COMMA *fmtSeparator smaliFieldRef *fmtSeparator [commentSequence] CRLF;
cmdIgetObject       = *fmtSeparator "iget-object" 1*fmtSeparator todoStubLine *fmtSeparator [commentSequence] CRLF;
cmdIgetWide         = *fmtSeparator "iget-wide" 1*fmtSeparator todoStubLine *fmtSeparator [commentSequence] CRLF;
cmdInvokeDirect     = *fmtSeparator "invoke-direct" 1*fmtSeparator smaliVarGroup *fmtSeparator COMMA *fmtSeparator smaliMethodRef *fmtSeparator [commentSequence] CRLF;
cmdInvokeStatic     = *fmtSeparator "invoke-static" 1*fmtSeparator smaliVarGroup *fmtSeparator COMMA *fmtSeparator smaliMethodRef *fmtSeparator [commentSequence] CRLF;
cmdInvokeVirtual    = *fmtSeparator "invoke-virtual" 1*fmtSeparator smaliVarGroup *fmtSeparator COMMA *fmtSeparator smaliMethodRef *fmtSeparator [commentSequence] CRLF;
cmdIput             = *fmtSeparator "iput" 1*fmtSeparator todoStubLine *fmtSeparator [commentSequence] CRLF;
cmdIputObject       = *fmtSeparator "iput-object" 1*fmtSeparator todoStubLine *fmtSeparator [commentSequence] CRLF;
cmdIputWide         = *fmtSeparator "iput-wide" 1*fmtSeparator todoStubLine *fmtSeparator [commentSequence] CRLF;
cmdLabel            = *fmtSeparator label *fmtSeparator [commentSequence] CRLF;
cmdMove             = *fmtSeparator "move" 1*fmtSeparator smaliVarDst *fmtSeparator COMMA *fmtSeparator (smaliVar / smaliParam) *fmtSeparator [commentSequence] CRLF;
cmdMoveResultObject = *fmtSeparator "move-result-object" 1*fmtSeparator smaliVarDst *fmtSeparator [commentSequence] CRLF;
cmdNewInstance      = *fmtSeparator "new-instance" 1*fmtSeparator todoStubLine *fmtSeparator [commentSequence] CRLF;
cmdNop              = *fmtSeparator "nop" *fmtSeparator [commentSequence] CRLF;
cmdReturn           = *fmtSeparator "return" 1*fmtSeparator smaliVar *fmtSeparator [commentSequence] CRLF;
cmdReturnObject     = *fmtSeparator "return-object" 1*fmtSeparator smaliVar *fmtSeparator [commentSequence] CRLF;
cmdReturnVoid       = *fmtSeparator "return-void" *fmtSeparator [commentSequence] CRLF;
cmdReturnWide       = *fmtSeparator "return-wide" 1*fmtSeparator smaliVar *fmtSeparator [commentSequence] CRLF;
cmdSputObject       = *fmtSeparator "sput-object" 1*fmtSeparator todoStubLine *fmtSeparator [commentSequence] CRLF;
