smali/smalidea/src/main/antlr3/smalideaParser.g
2015-01-21 09:32:00 -08:00

777 lines
22 KiB
Plaintext

/*
* [The "BSD licence"]
* Copyright (c) 2010 Ben Gruver
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
parser grammar smalideaParser;
options {
tokenVocab=smaliParser;
}
@header {
package org.jf.smalidea;
import com.intellij.lang.PsiBuilder;
import com.intellij.lang.PsiBuilder.Marker;
import org.jf.smalidea.psi.SmaliElementTypes;
}
@members {
private PsiBuilder psiBuilder;
public void setPsiBuilder(PsiBuilder psiBuilder) {
this.psiBuilder = psiBuilder;
}
public Marker mark() {
return psiBuilder.mark();
}
protected void syncToFollows(boolean acceptEof) {
BitSet follow = computeErrorRecoverySet();
int mark = input.mark();
Marker marker = null;
try {
int token = input.LA(1);
while (!follow.member(token)) {
if (token == Token.EOF) {
if (acceptEof) {
break;
}
input.rewind(mark);
mark = -1;
marker = null;
return;
}
if (marker == null) {
marker = mark();
}
input.consume();
token = input.LA(1);
}
} finally {
if (mark != -1) {
input.release(mark);
}
if (marker != null) {
marker.error("Unexpected tokens");
}
}
}
@Override
protected Object recoverFromMismatchedToken(IntStream input, int ttype, BitSet follow)
throws RecognitionException
{
RecognitionException e = null;
// if next token is what we are looking for then "delete" this token
if ( mismatchIsUnwantedToken(input, ttype) ) {
e = new UnwantedTokenException(ttype, input);
/*
System.err.println("recoverFromMismatchedToken deleting "+
((TokenStream)input).LT(1)+
" since "+((TokenStream)input).LT(2)+" is what we want");
*/
beginResync();
Marker mark = mark();
input.consume(); // simply delete extra token
mark.error(getErrorMessage(e, tokenNames));
endResync();
reportError(e, true); // report after consuming so AW sees the token in the exception
// we want to return the token we're actually matching
Object matchedSymbol = getCurrentInputSymbol(input);
input.consume(); // move past ttype token as if all were ok
return matchedSymbol;
}
// can't recover with single token deletion, try insertion
if ( mismatchIsMissingToken(input, follow) ) {
Object inserted = getMissingSymbol(input, e, ttype, follow);
Marker mark = mark();
e = new MissingTokenException(ttype, input, inserted);
mark.error(getErrorMessage(e, tokenNames));
reportError(e, true); // report after inserting so AW sees the token in the exception
return inserted;
}
// even that didn't work; must throw the exception
e = new MismatchedTokenException(ttype, input);
throw e;
}
@Override
public void reportError(RecognitionException e) {
reportError(e, false);
}
public void reportError(RecognitionException e, boolean alreadyReported) {
// if we've already reported an error and have not matched a token
// yet successfully, don't report any errors.
if ( state.errorRecovery ) {
//System.err.print("[SPURIOUS] ");
return;
}
state.syntaxErrors++; // don't count spurious
state.errorRecovery = true;
if (!alreadyReported) {
displayRecognitionError(this.getTokenNames(), e);
}
}
@Override
public void displayRecognitionError(String[] tokenNames, RecognitionException e) {
Marker mark = psiBuilder.mark();
mark.error(getErrorMessage(e, tokenNames));
}
}
sync[boolean toEof]
@init { syncToFollows($toEof); }
: /*epsilon*/;
smali_file
:
(
( class_spec
| super_spec
| implements_spec
| source_spec
| method
| field
| annotation
)
sync[true]
)+
EOF;
class_spec
@init { Marker marker = mark(); }
: CLASS_DIRECTIVE access_list CLASS_DESCRIPTOR;
finally { marker.done(SmaliElementTypes.CLASS_STATEMENT); }
super_spec
@init { Marker marker = mark(); }
: SUPER_DIRECTIVE CLASS_DESCRIPTOR;
finally { marker.done(SmaliElementTypes.SUPER_STATEMENT); }
implements_spec
@init { Marker marker = mark(); }
: IMPLEMENTS_DIRECTIVE CLASS_DESCRIPTOR;
finally { marker.done(SmaliElementTypes.IMPLEMENTS_STATEMENT); }
source_spec
@init { Marker marker = mark(); }
: SOURCE_DIRECTIVE string_literal;
finally { marker.done(SmaliElementTypes.SOURCE_STATEMENT); }
access_list
: ACCESS_SPEC*;
/*When there are annotations immediately after a field definition, we don't know whether they are field annotations
or class annotations until we determine if there is an .end field directive. In either case, we still "consume" and parse
the annotations. If it turns out that they are field annotations, we include them in the I_FIELD AST. Otherwise, we
add them to the $smali_file::classAnnotations list*/
field
@init {
Marker marker = mark();
Marker annotationsMarker = null;
boolean classAnnotations = true;
}
: FIELD_DIRECTIVE
access_list
member_name COLON nonvoid_type_descriptor (EQUAL literal)?
( END_FIELD_DIRECTIVE
| (ANNOTATION_DIRECTIVE)=> ( {annotationsMarker = mark();}
((ANNOTATION_DIRECTIVE)=> annotation)+
(END_FIELD_DIRECTIVE {classAnnotations = false;})?
)
| /*epsilon*/
);
finally {
if (annotationsMarker != null) {
if (classAnnotations) {
marker.doneBefore(SmaliElementTypes.FIELD, annotationsMarker);
annotationsMarker.drop();
} else {
annotationsMarker.drop();
marker.done(SmaliElementTypes.FIELD);
}
} else {
marker.done(SmaliElementTypes.FIELD);
}
}
method
@init { Marker marker = mark(); }
: METHOD_DIRECTIVE access_list member_name method_prototype statements_and_directives
END_METHOD_DIRECTIVE;
finally { marker.done(SmaliElementTypes.METHOD); }
statements_and_directives
: (
( ordered_method_item
| registers_directive
| catch_directive
| catchall_directive
| parameter_directive
| annotation
)
sync[false]
)*;
/* Method items whose order/location is important */
ordered_method_item
: label
| instruction
| debug_directive;
registers_directive
: (
REGISTERS_DIRECTIVE integral_literal
| LOCALS_DIRECTIVE integral_literal
);
param_list_or_id
: PARAM_LIST_OR_ID_START primitive_type+ PARAM_LIST_OR_ID_END;
/*identifiers are much more general than most languages. Any of the below can either be
the indicated type OR an identifier, depending on the context*/
simple_name
: SIMPLE_NAME
| ACCESS_SPEC
| VERIFICATION_ERROR_TYPE
| POSITIVE_INTEGER_LITERAL
| NEGATIVE_INTEGER_LITERAL
| FLOAT_LITERAL_OR_ID
| DOUBLE_LITERAL_OR_ID
| BOOL_LITERAL
| NULL_LITERAL
| REGISTER
| param_list_or_id
| PRIMITIVE_TYPE
| VOID_TYPE
| ANNOTATION_VISIBILITY
| INSTRUCTION_FORMAT10t
| INSTRUCTION_FORMAT10x
| INSTRUCTION_FORMAT10x_ODEX
| INSTRUCTION_FORMAT11x
| INSTRUCTION_FORMAT12x_OR_ID
| INSTRUCTION_FORMAT21c_FIELD
| INSTRUCTION_FORMAT21c_FIELD_ODEX
| INSTRUCTION_FORMAT21c_STRING
| INSTRUCTION_FORMAT21c_TYPE
| INSTRUCTION_FORMAT21t
| INSTRUCTION_FORMAT22c_FIELD
| INSTRUCTION_FORMAT22c_FIELD_ODEX
| INSTRUCTION_FORMAT22c_TYPE
| INSTRUCTION_FORMAT22cs_FIELD
| INSTRUCTION_FORMAT22s_OR_ID
| INSTRUCTION_FORMAT22t
| INSTRUCTION_FORMAT23x
| INSTRUCTION_FORMAT31i_OR_ID
| INSTRUCTION_FORMAT31t
| INSTRUCTION_FORMAT35c_METHOD
| INSTRUCTION_FORMAT35c_METHOD_ODEX
| INSTRUCTION_FORMAT35c_TYPE
| INSTRUCTION_FORMAT35mi_METHOD
| INSTRUCTION_FORMAT35ms_METHOD
| INSTRUCTION_FORMAT51l;
member_name
: simple_name
| MEMBER_NAME;
method_prototype
: OPEN_PAREN param_list CLOSE_PAREN type_descriptor;
param_list
: PARAM_LIST_START nonvoid_type_descriptor* PARAM_LIST_END
| PARAM_LIST_OR_ID_START primitive_type* PARAM_LIST_OR_ID_END
| nonvoid_type_descriptor*;
primitive_type
@init { Marker marker = mark(); }
: PRIMITIVE_TYPE;
finally { marker.done(SmaliElementTypes.PRIMITIVE_TYPE); }
type_descriptor
: VOID_TYPE
| primitive_type
| CLASS_DESCRIPTOR
| ARRAY_DESCRIPTOR;
nonvoid_type_descriptor
: primitive_type
| CLASS_DESCRIPTOR
| ARRAY_DESCRIPTOR;
reference_type_descriptor
: CLASS_DESCRIPTOR
| ARRAY_DESCRIPTOR;
null_literal
@init { Marker marker = mark(); }
: NULL_LITERAL;
finally { marker.done(SmaliElementTypes.LITERAL); }
bool_literal
@init { Marker marker = mark(); }
: BOOL_LITERAL;
finally { marker.done(SmaliElementTypes.LITERAL); }
byte_literal
@init { Marker marker = mark(); }
: BYTE_LITERAL;
finally { marker.done(SmaliElementTypes.LITERAL); }
char_literal
@init { Marker marker = mark(); }
: CHAR_LITERAL;
finally { marker.done(SmaliElementTypes.LITERAL); }
short_literal
@init { Marker marker = mark(); }
: SHORT_LITERAL;
finally { marker.done(SmaliElementTypes.LITERAL); }
integer_literal
@init { Marker marker = mark(); }
: POSITIVE_INTEGER_LITERAL
| NEGATIVE_INTEGER_LITERAL;
finally { marker.done(SmaliElementTypes.LITERAL); }
long_literal
@init { Marker marker = mark(); }
: LONG_LITERAL;
finally { marker.done(SmaliElementTypes.LITERAL); }
float_literal
@init { Marker marker = mark(); }
: FLOAT_LITERAL_OR_ID
| FLOAT_LITERAL;
finally { marker.done(SmaliElementTypes.LITERAL); }
double_literal
@init { Marker marker = mark(); }
: DOUBLE_LITERAL_OR_ID
| DOUBLE_LITERAL;
finally { marker.done(SmaliElementTypes.LITERAL); }
string_literal
@init { Marker marker = mark(); }
: STRING_LITERAL;
finally { marker.done(SmaliElementTypes.LITERAL); }
array_literal
@init { Marker marker = mark(); }
: OPEN_BRACE (literal (COMMA literal)* | ) CLOSE_BRACE;
finally { marker.done(SmaliElementTypes.LITERAL); }
enum_literal
@init { Marker marker = mark(); }
: ENUM_DIRECTIVE reference_type_descriptor ARROW simple_name COLON reference_type_descriptor;
finally { marker.done(SmaliElementTypes.LITERAL); }
type_field_method_literal
@init { Marker marker = mark(); }
: reference_type_descriptor
( ARROW
( member_name COLON nonvoid_type_descriptor
| member_name method_prototype
)
| /* epsilon */
)
| primitive_type
| VOID_TYPE;
finally { marker.done(SmaliElementTypes.LITERAL); }
subannotation
@init { Marker marker = mark(); }
: SUBANNOTATION_DIRECTIVE CLASS_DESCRIPTOR annotation_element* END_SUBANNOTATION_DIRECTIVE;
finally { marker.done(SmaliElementTypes.LITERAL); }
literal
: long_literal
| integer_literal
| short_literal
| byte_literal
| float_literal
| double_literal
| char_literal
| string_literal
| bool_literal
| null_literal
| array_literal
| subannotation
| type_field_method_literal
| enum_literal;
integral_literal
: long_literal
| integer_literal
| short_literal
| char_literal
| byte_literal;
fixed_32bit_literal
: long_literal
| integer_literal
| short_literal
| byte_literal
| float_literal
| char_literal
| bool_literal;
fixed_literal
: integer_literal
| long_literal
| short_literal
| byte_literal
| float_literal
| double_literal
| char_literal
| bool_literal;
annotation_element
: simple_name EQUAL literal;
annotation
@init { Marker marker = mark(); }
: ANNOTATION_DIRECTIVE ANNOTATION_VISIBILITY CLASS_DESCRIPTOR
annotation_element* END_ANNOTATION_DIRECTIVE;
finally { marker.done(SmaliElementTypes.ANNOTATION); }
fully_qualified_method
: reference_type_descriptor ARROW member_name method_prototype;
fully_qualified_field
: reference_type_descriptor ARROW member_name COLON nonvoid_type_descriptor;
label
: COLON simple_name;
label_ref
: COLON simple_name;
register_list
: REGISTER (COMMA REGISTER)*
| /* epsilon */;
register_range
: (REGISTER (DOTDOT REGISTER)?)?;
verification_error_reference
: CLASS_DESCRIPTOR | fully_qualified_field | fully_qualified_method;
catch_directive
: CATCH_DIRECTIVE nonvoid_type_descriptor OPEN_BRACE label_ref DOTDOT label_ref CLOSE_BRACE label_ref;
catchall_directive
: CATCHALL_DIRECTIVE OPEN_BRACE label_ref DOTDOT label_ref CLOSE_BRACE label_ref;
/*When there are annotations immediately after a parameter definition, we don't know whether they are parameter annotations
or method annotations until we determine if there is an .end parameter directive. In either case, we still "consume" and parse
the annotations. If it turns out that they are parameter annotations, we include them in the I_PARAMETER AST. Otherwise, we
add them to the $statements_and_directives::methodAnnotations list*/
parameter_directive
: PARAMETER_DIRECTIVE REGISTER (COMMA string_literal)?
({input.LA(1) == ANNOTATION_DIRECTIVE}? annotation)*
( END_PARAMETER_DIRECTIVE
| /*epsilon*/
);
debug_directive
: line_directive
| local_directive
| end_local_directive
| restart_local_directive
| prologue_directive
| epilogue_directive
| source_directive;
line_directive
: LINE_DIRECTIVE integral_literal;
local_directive
: LOCAL_DIRECTIVE REGISTER (COMMA (null_literal | string_literal) COLON (VOID_TYPE | nonvoid_type_descriptor)
(COMMA string_literal)? )?;
end_local_directive
: END_LOCAL_DIRECTIVE REGISTER;
restart_local_directive
: RESTART_LOCAL_DIRECTIVE REGISTER;
prologue_directive
: PROLOGUE_DIRECTIVE;
epilogue_directive
: EPILOGUE_DIRECTIVE;
source_directive
: SOURCE_DIRECTIVE string_literal?;
instruction_format12x
: INSTRUCTION_FORMAT12x
| INSTRUCTION_FORMAT12x_OR_ID;
instruction_format22s
: INSTRUCTION_FORMAT22s
| INSTRUCTION_FORMAT22s_OR_ID;
instruction_format31i
: INSTRUCTION_FORMAT31i
| INSTRUCTION_FORMAT31i_OR_ID;
instruction
: insn_format10t
| insn_format10x
| insn_format10x_odex
| insn_format11n
| insn_format11x
| insn_format12x
| insn_format20bc
| insn_format20t
| insn_format21c_field
| insn_format21c_field_odex
| insn_format21c_string
| insn_format21c_type
| insn_format21ih
| insn_format21lh
| insn_format21s
| insn_format21t
| insn_format22b
| insn_format22c_field
| insn_format22c_field_odex
| insn_format22c_type
| insn_format22cs_field
| insn_format22s
| insn_format22t
| insn_format22x
| insn_format23x
| insn_format30t
| insn_format31c
| insn_format31i
| insn_format31t
| insn_format32x
| insn_format35c_method
| insn_format35c_type
| insn_format35c_method_odex
| insn_format35mi_method
| insn_format35ms_method
| insn_format3rc_method
| insn_format3rc_method_odex
| insn_format3rc_type
| insn_format3rmi_method
| insn_format3rms_method
| insn_format51l
| insn_array_data_directive
| insn_packed_switch_directive
| insn_sparse_switch_directive;
insn_format10t
: //e.g. goto endloop:
//e.g. goto +3
INSTRUCTION_FORMAT10t label_ref;
insn_format10x
: //e.g. return-void
INSTRUCTION_FORMAT10x;
insn_format10x_odex
: //e.g. return-void-barrier
INSTRUCTION_FORMAT10x_ODEX;
insn_format11n
: //e.g. const/4 v0, 5
INSTRUCTION_FORMAT11n REGISTER COMMA integral_literal;
insn_format11x
: //e.g. move-result-object v1
INSTRUCTION_FORMAT11x REGISTER;
insn_format12x
: //e.g. move v1 v2
instruction_format12x REGISTER COMMA REGISTER;
insn_format20bc
: //e.g. throw-verification-error generic-error, Lsome/class;
INSTRUCTION_FORMAT20bc VERIFICATION_ERROR_TYPE COMMA verification_error_reference;
insn_format20t
: //e.g. goto/16 endloop:
INSTRUCTION_FORMAT20t label_ref;
insn_format21c_field
: //e.g. sget-object v0, java/lang/System/out LJava/io/PrintStream;
INSTRUCTION_FORMAT21c_FIELD REGISTER COMMA fully_qualified_field;
insn_format21c_field_odex
: //e.g. sget-object-volatile v0, java/lang/System/out LJava/io/PrintStream;
INSTRUCTION_FORMAT21c_FIELD_ODEX REGISTER COMMA fully_qualified_field;
insn_format21c_string
: //e.g. const-string v1, "Hello World!"
INSTRUCTION_FORMAT21c_STRING REGISTER COMMA string_literal;
insn_format21c_type
: //e.g. const-class v2, Lorg/jf/HelloWorld2/HelloWorld2;
INSTRUCTION_FORMAT21c_TYPE REGISTER COMMA nonvoid_type_descriptor;
insn_format21ih
: //e.g. const/high16 v1, 1234
INSTRUCTION_FORMAT21ih REGISTER COMMA fixed_32bit_literal;
insn_format21lh
: //e.g. const-wide/high16 v1, 1234
INSTRUCTION_FORMAT21lh REGISTER COMMA fixed_32bit_literal;
insn_format21s
: //e.g. const/16 v1, 1234
INSTRUCTION_FORMAT21s REGISTER COMMA integral_literal;
insn_format21t
: //e.g. if-eqz v0, endloop:
INSTRUCTION_FORMAT21t REGISTER COMMA label_ref;
insn_format22b
: //e.g. add-int v0, v1, 123
INSTRUCTION_FORMAT22b REGISTER COMMA REGISTER COMMA integral_literal;
insn_format22c_field
: //e.g. iput-object v1, v0 org/jf/HelloWorld2/HelloWorld2.helloWorld Ljava/lang/String;
INSTRUCTION_FORMAT22c_FIELD REGISTER COMMA REGISTER COMMA fully_qualified_field;
insn_format22c_field_odex
: //e.g. iput-object-volatile v1, v0 org/jf/HelloWorld2/HelloWorld2.helloWorld Ljava/lang/String;
INSTRUCTION_FORMAT22c_FIELD_ODEX REGISTER COMMA REGISTER COMMA fully_qualified_field;
insn_format22c_type
: //e.g. instance-of v0, v1, Ljava/lang/String;
INSTRUCTION_FORMAT22c_TYPE REGISTER COMMA REGISTER COMMA nonvoid_type_descriptor;
insn_format22cs_field
: //e.g. iget-quick v0, v1, field@0xc
INSTRUCTION_FORMAT22cs_FIELD REGISTER COMMA REGISTER COMMA FIELD_OFFSET;
insn_format22s
: //e.g. add-int/lit16 v0, v1, 12345
instruction_format22s REGISTER COMMA REGISTER COMMA integral_literal;
insn_format22t
: //e.g. if-eq v0, v1, endloop:
INSTRUCTION_FORMAT22t REGISTER COMMA REGISTER COMMA label_ref;
insn_format22x
: //e.g. move/from16 v1, v1234
INSTRUCTION_FORMAT22x REGISTER COMMA REGISTER;
insn_format23x
: //e.g. add-int v1, v2, v3
INSTRUCTION_FORMAT23x REGISTER COMMA REGISTER COMMA REGISTER;
insn_format30t
: //e.g. goto/32 endloop:
INSTRUCTION_FORMAT30t label_ref;
insn_format31c
: //e.g. const-string/jumbo v1 "Hello World!"
INSTRUCTION_FORMAT31c REGISTER COMMA string_literal;
insn_format31i
: //e.g. const v0, 123456
instruction_format31i REGISTER COMMA fixed_32bit_literal;
insn_format31t
: //e.g. fill-array-data v0, ArrayData:
INSTRUCTION_FORMAT31t REGISTER COMMA label_ref;
insn_format32x
: //e.g. move/16 v4567, v1234
INSTRUCTION_FORMAT32x REGISTER COMMA REGISTER;
insn_format35c_method
: //e.g. invoke-virtual {v0,v1} java/io/PrintStream/print(Ljava/lang/Stream;)V
INSTRUCTION_FORMAT35c_METHOD OPEN_BRACE register_list CLOSE_BRACE COMMA fully_qualified_method;
insn_format35c_type
: //e.g. filled-new-array {v0,v1}, I
INSTRUCTION_FORMAT35c_TYPE OPEN_BRACE register_list CLOSE_BRACE COMMA nonvoid_type_descriptor;
insn_format35c_method_odex
: //e.g. invoke-direct {p0}, Ljava/lang/Object;-><init>()V
INSTRUCTION_FORMAT35c_METHOD_ODEX OPEN_BRACE register_list CLOSE_BRACE COMMA fully_qualified_method;
insn_format35mi_method
: //e.g. execute-inline {v0, v1}, inline@0x4
INSTRUCTION_FORMAT35mi_METHOD OPEN_BRACE register_list CLOSE_BRACE COMMA INLINE_INDEX;
insn_format35ms_method
: //e.g. invoke-virtual-quick {v0, v1}, vtable@0x4
INSTRUCTION_FORMAT35ms_METHOD OPEN_BRACE register_list CLOSE_BRACE COMMA VTABLE_INDEX;
insn_format3rc_method
: //e.g. invoke-virtual/range {v25..v26}, java/lang/StringBuilder/append(Ljava/lang/String;)Ljava/lang/StringBuilder;
INSTRUCTION_FORMAT3rc_METHOD OPEN_BRACE register_range CLOSE_BRACE COMMA fully_qualified_method;
insn_format3rc_method_odex
: //e.g. invoke-object-init/range {p0}, Ljava/lang/Object;-><init>()V
INSTRUCTION_FORMAT3rc_METHOD_ODEX OPEN_BRACE register_list CLOSE_BRACE COMMA fully_qualified_method;
insn_format3rc_type
: //e.g. filled-new-array/range {v0..v6}, I
INSTRUCTION_FORMAT3rc_TYPE OPEN_BRACE register_range CLOSE_BRACE COMMA nonvoid_type_descriptor;
insn_format3rmi_method
: //e.g. execute-inline/range {v0 .. v10}, inline@0x14
INSTRUCTION_FORMAT3rmi_METHOD OPEN_BRACE register_range CLOSE_BRACE COMMA INLINE_INDEX;
insn_format3rms_method
: //e.g. invoke-virtual-quick/range {v0 .. v10}, vtable@0x14
INSTRUCTION_FORMAT3rms_METHOD OPEN_BRACE register_range CLOSE_BRACE COMMA VTABLE_INDEX;
insn_format51l
: //e.g. const-wide v0, 5000000000L
INSTRUCTION_FORMAT51l REGISTER COMMA fixed_literal;
insn_array_data_directive
: ARRAY_DATA_DIRECTIVE
integer_literal
fixed_literal* END_ARRAY_DATA_DIRECTIVE;
insn_packed_switch_directive
: PACKED_SWITCH_DIRECTIVE
fixed_32bit_literal
label_ref*
END_PACKED_SWITCH_DIRECTIVE;
insn_sparse_switch_directive
: SPARSE_SWITCH_DIRECTIVE
(fixed_32bit_literal ARROW label_ref)*
END_SPARSE_SWITCH_DIRECTIVE;