• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * [The "BSD licence"]
3 * Copyright (c) 2010 Ben Gruver
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote products
15 *    derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29parser grammar smaliParser;
30
31options {
32	tokenVocab=smaliLexer;
33	output=AST;
34	ASTLabelType=CommonTree;
35}
36
37tokens {
38	//I_* tokens are imaginary tokens used as parent AST nodes
39	I_CLASS_DEF;
40	I_SUPER;
41	I_IMPLEMENTS;
42	I_SOURCE;
43	I_ACCESS_LIST;
44	I_METHODS;
45	I_FIELDS;
46	I_FIELD;
47	I_FIELD_TYPE;
48	I_FIELD_INITIAL_VALUE;
49	I_METHOD;
50	I_METHOD_PROTOTYPE;
51	I_METHOD_RETURN_TYPE;
52	I_REGISTERS;
53	I_LOCALS;
54	I_LABELS;
55	I_LABEL;
56	I_ANNOTATIONS;
57	I_ANNOTATION;
58	I_ANNOTATION_ELEMENT;
59	I_SUBANNOTATION;
60	I_ENCODED_FIELD;
61	I_ENCODED_METHOD;
62	I_ENCODED_ENUM;
63	I_ENCODED_ARRAY;
64	I_ARRAY_ELEMENT_SIZE;
65	I_ARRAY_ELEMENTS;
66	I_PACKED_SWITCH_START_KEY;
67	I_PACKED_SWITCH_TARGET_COUNT;
68	I_PACKED_SWITCH_TARGETS;
69	I_PACKED_SWITCH_DECLARATION;
70	I_PACKED_SWITCH_DECLARATIONS;
71	I_SPARSE_SWITCH_KEYS;
72	I_SPARSE_SWITCH_TARGET_COUNT;
73	I_SPARSE_SWITCH_TARGETS;
74	I_SPARSE_SWITCH_DECLARATION;
75	I_SPARSE_SWITCH_DECLARATIONS;
76	I_ADDRESS;
77	I_CATCH;
78	I_CATCHALL;
79	I_CATCHES;
80	I_PARAMETER;
81	I_PARAMETERS;
82	I_PARAMETER_NOT_SPECIFIED;
83	I_ORDERED_DEBUG_DIRECTIVES;
84	I_LINE;
85	I_LOCAL;
86	I_END_LOCAL;
87	I_RESTART_LOCAL;
88	I_PROLOGUE;
89	I_EPILOGUE;
90	I_STATEMENTS;
91	I_STATEMENT_FORMAT10t;
92	I_STATEMENT_FORMAT10x;
93	I_STATEMENT_FORMAT11n;
94	I_STATEMENT_FORMAT11x;
95	I_STATEMENT_FORMAT12x;
96	I_STATEMENT_FORMAT20bc;
97	I_STATEMENT_FORMAT20t;
98	I_STATEMENT_FORMAT21c_TYPE;
99	I_STATEMENT_FORMAT21c_FIELD;
100	I_STATEMENT_FORMAT21c_STRING;
101	I_STATEMENT_FORMAT21h;
102	I_STATEMENT_FORMAT21s;
103	I_STATEMENT_FORMAT21t;
104	I_STATEMENT_FORMAT22b;
105	I_STATEMENT_FORMAT22c_FIELD;
106	I_STATEMENT_FORMAT22c_TYPE;
107	I_STATEMENT_FORMAT22s;
108	I_STATEMENT_FORMAT22t;
109	I_STATEMENT_FORMAT22x;
110	I_STATEMENT_FORMAT23x;
111	I_STATEMENT_FORMAT30t;
112	I_STATEMENT_FORMAT31c;
113	I_STATEMENT_FORMAT31i;
114	I_STATEMENT_FORMAT31t;
115	I_STATEMENT_FORMAT32x;
116	I_STATEMENT_FORMAT35c_METHOD;
117	I_STATEMENT_FORMAT35c_TYPE;
118	I_STATEMENT_FORMAT3rc_METHOD;
119	I_STATEMENT_FORMAT3rc_TYPE;
120	I_STATEMENT_FORMAT51l;
121	I_STATEMENT_ARRAY_DATA;
122	I_STATEMENT_PACKED_SWITCH;
123	I_STATEMENT_SPARSE_SWITCH;
124	I_REGISTER_RANGE;
125	I_REGISTER_LIST;
126
127	LABEL;
128	INTEGER_LITERAL;
129	INVALID_TOKEN;
130}
131
132@header {
133package org.jf.smali;
134
135import org.jf.dexlib.Code.Format.*;
136}
137
138
139@members {
140	private boolean verboseErrors = false;
141	private boolean allowOdex = false;
142
143	public void setVerboseErrors(boolean verboseErrors) {
144		this.verboseErrors = verboseErrors;
145	}
146
147	public void setAllowOdex(boolean allowOdex) {
148	    this.allowOdex = allowOdex;
149	}
150
151	public String getErrorMessage(RecognitionException e,
152		String[] tokenNames) {
153
154		if (verboseErrors) {
155			List stack = getRuleInvocationStack(e, this.getClass().getName());
156			String msg = null;
157
158			if (e instanceof NoViableAltException) {
159				NoViableAltException nvae = (NoViableAltException)e;
160				msg = " no viable alt; token="+getTokenErrorDisplay(e.token)+
161				" (decision="+nvae.decisionNumber+
162				" state "+nvae.stateNumber+")"+
163				" decision=<<"+nvae.grammarDecisionDescription+">>";
164			} else {
165				msg = super.getErrorMessage(e, tokenNames);
166			}
167
168			return stack + " " + msg;
169		} else {
170			return super.getErrorMessage(e, tokenNames);
171		}
172	}
173
174	public String getTokenErrorDisplay(Token t) {
175		if (!verboseErrors) {
176			String s = t.getText();
177			if ( s==null ) {
178				if ( t.getType()==Token.EOF ) {
179					s = "<EOF>";
180				}
181				else {
182					s = "<"+tokenNames[t.getType()]+">";
183				}
184			}
185			s = s.replaceAll("\n","\\\\n");
186			s = s.replaceAll("\r","\\\\r");
187			s = s.replaceAll("\t","\\\\t");
188			return "'"+s+"'";
189		}
190
191		CommonToken ct = (CommonToken)t;
192
193		String channelStr = "";
194		if (t.getChannel()>0) {
195			channelStr=",channel="+t.getChannel();
196		}
197		String txt = t.getText();
198		if ( txt!=null ) {
199			txt = txt.replaceAll("\n","\\\\n");
200			txt = txt.replaceAll("\r","\\\\r");
201			txt = txt.replaceAll("\t","\\\\t");
202		}
203		else {
204			txt = "<no text>";
205		}
206		return "[@"+t.getTokenIndex()+","+ct.getStartIndex()+":"+ct.getStopIndex()+"='"+txt+"',<"+tokenNames[t.getType()]+">"+channelStr+","+t.getLine()+":"+t.getCharPositionInLine()+"]";
207	}
208
209	public String getErrorHeader(RecognitionException e) {
210		return getSourceName()+"["+ e.line+","+e.charPositionInLine+"]";
211	}
212
213	private CommonTree buildTree(int type, String text, List<CommonTree> children) {
214		CommonTree root = new CommonTree(new CommonToken(type, text));
215		for (CommonTree child: children) {
216			root.addChild(child);
217		}
218		return root;
219	}
220
221	private CommonToken getParamListSubToken(CommonToken baseToken, String str, int typeStartIndex) {
222		CommonToken token = new CommonToken(baseToken);
223		token.setStartIndex(baseToken.getStartIndex() + typeStartIndex);
224
225		switch (str.charAt(typeStartIndex)) {
226			case 'Z':
227			case 'B':
228			case 'S':
229			case 'C':
230			case 'I':
231			case 'J':
232			case 'F':
233			case 'D':
234			{
235				token.setType(PRIMITIVE_TYPE);
236				token.setText(str.substring(typeStartIndex, typeStartIndex+1));
237				token.setStopIndex(baseToken.getStartIndex() + typeStartIndex);
238				break;
239			}
240			case 'L':
241			{
242				int i = typeStartIndex;
243				while (str.charAt(++i) != ';');
244
245				token.setType(CLASS_DESCRIPTOR);
246				token.setText(str.substring(typeStartIndex, i + 1));
247				token.setStopIndex(baseToken.getStartIndex() + i);
248				break;
249			}
250			case '[':
251			{
252				int i = typeStartIndex;
253    				while (str.charAt(++i) == '[');
254
255    				if (str.charAt(i++) == 'L') {
256    				    while (str.charAt(i++) != ';');
257				}
258
259    				token.setType(ARRAY_DESCRIPTOR);
260    				token.setText(str.substring(typeStartIndex, i));
261    				token.setStopIndex(baseToken.getStartIndex() + i - 1);
262    				break;
263			}
264			default:
265				throw new RuntimeException(String.format("Invalid character '\%c' in param list \"\%s\" at position \%d", str.charAt(typeStartIndex), str, typeStartIndex));
266		}
267
268		return token;
269	}
270
271	private CommonTree parseParamList(CommonToken paramListToken) {
272		String paramList = paramListToken.getText();
273		CommonTree root = new CommonTree();
274
275		int startIndex = paramListToken.getStartIndex();
276
277		int i=0;
278		while (i<paramList.length()) {
279			CommonToken token = getParamListSubToken(paramListToken, paramList, i);
280			root.addChild(new CommonTree(token));
281			i += token.getText().length();
282		}
283
284		if (root.getChildCount() == 0) {
285			return null;
286		}
287		return root;
288	}
289
290	private void throwOdexedInstructionException(IntStream input, String odexedInstruction)
291			throws OdexedInstructionException {
292		/*this has to be done in a separate method, otherwise java will complain about the
293		auto-generated code in the rule after the throw not being reachable*/
294		throw new OdexedInstructionException(input, odexedInstruction);
295	}
296}
297
298
299smali_file
300	scope
301	{
302		boolean hasClassSpec;
303		boolean hasSuperSpec;
304		boolean hasSourceSpec;
305		List<CommonTree> classAnnotations;
306	}
307	@init
308	{	$smali_file::hasClassSpec = $smali_file::hasSuperSpec = $smali_file::hasSourceSpec = false;
309		$smali_file::classAnnotations = new ArrayList<CommonTree>();
310	}
311	:
312	(	{!$smali_file::hasClassSpec}?=> class_spec {$smali_file::hasClassSpec = true;}
313	|	{!$smali_file::hasSuperSpec}?=> super_spec {$smali_file::hasSuperSpec = true;}
314	|	implements_spec
315	|	{!$smali_file::hasSourceSpec}?=> source_spec {$smali_file::hasSourceSpec = true;}
316	|	method
317	|	field
318	|	annotation {$smali_file::classAnnotations.add($annotation.tree);}
319	)+
320	EOF
321	{
322		if (!$smali_file::hasClassSpec) {
323			throw new SemanticException(input, "The file must contain a .class directive");
324		}
325
326		if (!$smali_file::hasSuperSpec) {
327			if (!$class_spec.className.equals("Ljava/lang/Object;")) {
328				throw new SemanticException(input, "The file must contain a .super directive");
329			}
330		}
331	}
332	->	^(I_CLASS_DEF
333			class_spec
334			super_spec?
335			implements_spec*
336			source_spec?
337			^(I_METHODS method*) ^(I_FIELDS field*) {buildTree(I_ANNOTATIONS, "I_ANNOTATIONS", $smali_file::classAnnotations)});
338
339class_spec returns[String className]
340	:	CLASS_DIRECTIVE access_list CLASS_DESCRIPTOR {$className = $CLASS_DESCRIPTOR.text;} -> CLASS_DESCRIPTOR access_list;
341
342super_spec
343	:	SUPER_DIRECTIVE CLASS_DESCRIPTOR -> ^(I_SUPER[$start, "I_SUPER"] CLASS_DESCRIPTOR);
344
345implements_spec
346	:	IMPLEMENTS_DIRECTIVE CLASS_DESCRIPTOR -> ^(I_IMPLEMENTS[$start, "I_IMPLEMENTS"] CLASS_DESCRIPTOR);
347
348source_spec
349	:	SOURCE_DIRECTIVE STRING_LITERAL -> ^(I_SOURCE[$start, "I_SOURCE"] STRING_LITERAL);
350
351access_list
352	:	ACCESS_SPEC* -> ^(I_ACCESS_LIST[$start,"I_ACCESS_LIST"] ACCESS_SPEC*);
353
354
355/*When there are annotations immediately after a field definition, we don't know whether they are field annotations
356or class annotations until we determine if there is an .end field directive. In either case, we still "consume" and parse
357the annotations. If it turns out that they are field annotations, we include them in the I_FIELD AST. Otherwise, we
358add them to the $smali_file::classAnnotations list*/
359field
360	@init {List<CommonTree> annotations = new ArrayList<CommonTree>();}
361	:	FIELD_DIRECTIVE access_list simple_name COLON nonvoid_type_descriptor (EQUAL literal)?
362		(	({input.LA(1) == ANNOTATION_DIRECTIVE}? annotation {annotations.add($annotation.tree);})*
363			(	END_FIELD_DIRECTIVE
364				-> ^(I_FIELD[$start, "I_FIELD"] simple_name access_list ^(I_FIELD_TYPE nonvoid_type_descriptor) ^(I_FIELD_INITIAL_VALUE literal)? ^(I_ANNOTATIONS annotation*))
365			|	/*epsilon*/ {$smali_file::classAnnotations.addAll(annotations);}
366				-> ^(I_FIELD[$start, "I_FIELD"] simple_name access_list ^(I_FIELD_TYPE nonvoid_type_descriptor) ^(I_FIELD_INITIAL_VALUE literal)? ^(I_ANNOTATIONS))
367			)
368		);
369
370method
371	scope {int currentAddress;}
372	:	{$method::currentAddress = 0;}
373		METHOD_DIRECTIVE access_list method_name method_prototype statements_and_directives
374		END_METHOD_DIRECTIVE
375		-> ^(I_METHOD[$start, "I_METHOD"] method_name method_prototype access_list statements_and_directives);
376
377statements_and_directives
378	scope
379	{
380		boolean hasRegistersDirective;
381		List<CommonTree> packedSwitchDeclarations;
382		List<CommonTree> sparseSwitchDeclarations;
383		List<CommonTree> methodAnnotations;
384	}
385	:	{
386			$method::currentAddress = 0;
387			$statements_and_directives::hasRegistersDirective = false;
388			$statements_and_directives::packedSwitchDeclarations = new ArrayList<CommonTree>();
389			$statements_and_directives::sparseSwitchDeclarations = new ArrayList<CommonTree>();
390			$statements_and_directives::methodAnnotations = new ArrayList<CommonTree>();
391		}
392		(	instruction {$method::currentAddress += $instruction.size/2;}
393		|	registers_directive
394		|	label
395		|	catch_directive
396		|	catchall_directive
397		|	parameter_directive
398		|	ordered_debug_directive
399		|	annotation  {$statements_and_directives::methodAnnotations.add($annotation.tree);}
400		)*
401		->	registers_directive?
402			^(I_LABELS label*)
403			{buildTree(I_PACKED_SWITCH_DECLARATIONS, "I_PACKED_SWITCH_DECLARATIONS", $statements_and_directives::packedSwitchDeclarations)}
404			{buildTree(I_SPARSE_SWITCH_DECLARATIONS, "I_SPARSE_SWITCH_DECLARATIONS", $statements_and_directives::sparseSwitchDeclarations)}
405			^(I_STATEMENTS instruction*)
406			^(I_CATCHES catch_directive* catchall_directive*)
407			^(I_PARAMETERS parameter_directive*)
408			^(I_ORDERED_DEBUG_DIRECTIVES ordered_debug_directive*)
409			{buildTree(I_ANNOTATIONS, "I_ANNOTATIONS", $statements_and_directives::methodAnnotations)};
410
411registers_directive
412	:	(
413			directive=REGISTERS_DIRECTIVE regCount=integral_literal -> ^(I_REGISTERS[$REGISTERS_DIRECTIVE, "I_REGISTERS"] $regCount)
414		|	directive=LOCALS_DIRECTIVE regCount2=integral_literal -> ^(I_LOCALS[$LOCALS_DIRECTIVE, "I_LOCALS"] $regCount2)
415		)
416		{
417			if ($statements_and_directives::hasRegistersDirective) {
418				throw new SemanticException(input, $directive, "There can only be a single .registers or .locals directive in a method");
419			}
420			$statements_and_directives::hasRegistersDirective=true;
421		};
422
423/*identifiers are much more general than most languages. Any of the below can either be
424the indicated type OR an identifier, depending on the context*/
425simple_name
426	:	SIMPLE_NAME
427	|	ACCESS_SPEC -> SIMPLE_NAME[$ACCESS_SPEC]
428	|	VERIFICATION_ERROR_TYPE -> SIMPLE_NAME[$VERIFICATION_ERROR_TYPE]
429	|	POSITIVE_INTEGER_LITERAL -> SIMPLE_NAME[$POSITIVE_INTEGER_LITERAL]
430	|	NEGATIVE_INTEGER_LITERAL -> SIMPLE_NAME[$NEGATIVE_INTEGER_LITERAL]
431	|	INTEGER_LITERAL -> SIMPLE_NAME[$INTEGER_LITERAL]
432	|	FLOAT_LITERAL_OR_ID -> SIMPLE_NAME[$FLOAT_LITERAL_OR_ID]
433	|	DOUBLE_LITERAL_OR_ID -> SIMPLE_NAME[$DOUBLE_LITERAL_OR_ID]
434	|	BOOL_LITERAL -> SIMPLE_NAME[$BOOL_LITERAL]
435	|	NULL_LITERAL -> SIMPLE_NAME[$NULL_LITERAL]
436	|	REGISTER -> SIMPLE_NAME[$REGISTER]
437	|	PARAM_LIST_OR_ID -> SIMPLE_NAME[$PARAM_LIST_OR_ID]
438	|	PRIMITIVE_TYPE -> SIMPLE_NAME[$PRIMITIVE_TYPE]
439	|	VOID_TYPE -> SIMPLE_NAME[$VOID_TYPE]
440	|	ANNOTATION_VISIBILITY -> SIMPLE_NAME[$ANNOTATION_VISIBILITY]
441	|	INSTRUCTION_FORMAT10t -> SIMPLE_NAME[$INSTRUCTION_FORMAT10t]
442	|	INSTRUCTION_FORMAT10x -> SIMPLE_NAME[$INSTRUCTION_FORMAT10x]
443	|	INSTRUCTION_FORMAT11x -> SIMPLE_NAME[$INSTRUCTION_FORMAT11x]
444	|	INSTRUCTION_FORMAT12x_OR_ID -> SIMPLE_NAME[$INSTRUCTION_FORMAT12x_OR_ID]
445	|	INSTRUCTION_FORMAT21c_FIELD -> SIMPLE_NAME[$INSTRUCTION_FORMAT21c_FIELD]
446	|	INSTRUCTION_FORMAT21c_FIELD_ODEX -> SIMPLE_NAME[$INSTRUCTION_FORMAT21c_FIELD_ODEX]
447	|	INSTRUCTION_FORMAT21c_STRING -> SIMPLE_NAME[$INSTRUCTION_FORMAT21c_STRING]
448	|	INSTRUCTION_FORMAT21c_TYPE -> SIMPLE_NAME[$INSTRUCTION_FORMAT21c_TYPE]
449	|	INSTRUCTION_FORMAT21t -> SIMPLE_NAME[$INSTRUCTION_FORMAT21t]
450	|	INSTRUCTION_FORMAT22c_FIELD -> SIMPLE_NAME[$INSTRUCTION_FORMAT22c_FIELD]
451	|	INSTRUCTION_FORMAT22c_FIELD_ODEX -> SIMPLE_NAME[$INSTRUCTION_FORMAT22c_FIELD_ODEX]
452	|	INSTRUCTION_FORMAT22c_TYPE -> SIMPLE_NAME[$INSTRUCTION_FORMAT22c_TYPE]
453	|	INSTRUCTION_FORMAT22cs_FIELD -> SIMPLE_NAME[$INSTRUCTION_FORMAT22cs_FIELD]
454	|	INSTRUCTION_FORMAT22s_OR_ID -> SIMPLE_NAME[$INSTRUCTION_FORMAT22s_OR_ID]
455	|	INSTRUCTION_FORMAT22t -> SIMPLE_NAME[$INSTRUCTION_FORMAT22t]
456	|	INSTRUCTION_FORMAT23x -> SIMPLE_NAME[$INSTRUCTION_FORMAT23x]
457	|	INSTRUCTION_FORMAT31i_OR_ID -> SIMPLE_NAME[$INSTRUCTION_FORMAT31i_OR_ID]
458	|	INSTRUCTION_FORMAT31t -> SIMPLE_NAME[$INSTRUCTION_FORMAT31t]
459	|	INSTRUCTION_FORMAT35c_METHOD -> SIMPLE_NAME[$INSTRUCTION_FORMAT35c_METHOD]
460	|	INSTRUCTION_FORMAT35c_TYPE -> SIMPLE_NAME[$INSTRUCTION_FORMAT35c_TYPE]
461	|	INSTRUCTION_FORMAT35s_METHOD -> SIMPLE_NAME[$INSTRUCTION_FORMAT35s_METHOD]
462	|	INSTRUCTION_FORMAT35ms_METHOD -> SIMPLE_NAME[$INSTRUCTION_FORMAT35ms_METHOD]
463	|	INSTRUCTION_FORMAT51l -> SIMPLE_NAME[$INSTRUCTION_FORMAT51l];
464
465method_name
466	:	simple_name
467	|	METHOD_NAME -> SIMPLE_NAME[$METHOD_NAME];
468
469method_prototype
470	:	OPEN_PAREN param_list CLOSE_PAREN type_descriptor
471		-> ^(I_METHOD_PROTOTYPE[$start, "I_METHOD_PROTOTYPE"] ^(I_METHOD_RETURN_TYPE type_descriptor) param_list?);
472
473param_list
474	:	PARAM_LIST -> { parseParamList((CommonToken)$PARAM_LIST) }
475	|	PARAM_LIST_OR_ID -> { parseParamList((CommonToken)$PARAM_LIST_OR_ID) }
476	|	nonvoid_type_descriptor*;
477
478type_descriptor
479	:	VOID_TYPE
480	|	PRIMITIVE_TYPE
481	|	CLASS_DESCRIPTOR
482	|	ARRAY_DESCRIPTOR;
483
484nonvoid_type_descriptor
485	:	PRIMITIVE_TYPE
486	|	CLASS_DESCRIPTOR
487	|	ARRAY_DESCRIPTOR;
488
489reference_type_descriptor
490	:	CLASS_DESCRIPTOR
491	|	ARRAY_DESCRIPTOR;
492
493integer_literal
494	:	POSITIVE_INTEGER_LITERAL -> INTEGER_LITERAL[$POSITIVE_INTEGER_LITERAL]
495	|	NEGATIVE_INTEGER_LITERAL -> INTEGER_LITERAL[$NEGATIVE_INTEGER_LITERAL]
496	|	INTEGER_LITERAL;
497
498float_literal
499	:	FLOAT_LITERAL_OR_ID -> FLOAT_LITERAL[$FLOAT_LITERAL_OR_ID]
500	|	FLOAT_LITERAL;
501
502double_literal
503	:	DOUBLE_LITERAL_OR_ID -> DOUBLE_LITERAL[$DOUBLE_LITERAL_OR_ID]
504	|	DOUBLE_LITERAL;
505
506literal
507	:	LONG_LITERAL
508	|	integer_literal
509	|	SHORT_LITERAL
510	|	BYTE_LITERAL
511	|	float_literal
512	|	double_literal
513	|	CHAR_LITERAL
514	|	STRING_LITERAL
515	|	BOOL_LITERAL
516	|	NULL_LITERAL
517	|	array_literal
518	|	subannotation
519	|	type_field_method_literal
520	|	enum_literal;
521
522integral_literal
523	:	LONG_LITERAL
524	|	integer_literal
525	|	SHORT_LITERAL
526	|	CHAR_LITERAL
527	|	BYTE_LITERAL;
528
529fixed_32bit_literal
530	:	LONG_LITERAL
531	|	integer_literal
532	|	SHORT_LITERAL
533	|	BYTE_LITERAL
534	|	float_literal
535	|	CHAR_LITERAL
536	|	BOOL_LITERAL;
537
538fixed_literal returns[int size]
539	:	integer_literal {$size = 4;}
540	|	LONG_LITERAL {$size = 8;}
541	|	SHORT_LITERAL {$size = 2;}
542	|	BYTE_LITERAL {$size = 1;}
543	|	float_literal {$size = 4;}
544	|	double_literal {$size = 8;}
545	|	CHAR_LITERAL {$size = 2;}
546	|	BOOL_LITERAL {$size = 1;};
547
548array_literal
549	:	OPEN_BRACE (literal (COMMA literal)* | ) CLOSE_BRACE
550		-> ^(I_ENCODED_ARRAY[$start, "I_ENCODED_ARRAY"] literal*);
551
552annotation_element
553	:	simple_name EQUAL literal
554		-> ^(I_ANNOTATION_ELEMENT[$start, "I_ANNOTATION_ELEMENT"] simple_name literal);
555
556annotation
557	:	ANNOTATION_DIRECTIVE ANNOTATION_VISIBILITY CLASS_DESCRIPTOR
558		annotation_element* END_ANNOTATION_DIRECTIVE
559		-> ^(I_ANNOTATION[$start, "I_ANNOTATION"] ANNOTATION_VISIBILITY ^(I_SUBANNOTATION[$start, "I_SUBANNOTATION"] CLASS_DESCRIPTOR annotation_element*));
560
561subannotation
562	:	SUBANNOTATION_DIRECTIVE CLASS_DESCRIPTOR annotation_element* END_SUBANNOTATION_DIRECTIVE
563		-> ^(I_SUBANNOTATION[$start, "I_SUBANNOTATION"] CLASS_DESCRIPTOR annotation_element*);
564
565enum_literal
566	:	ENUM_DIRECTIVE reference_type_descriptor ARROW simple_name COLON reference_type_descriptor
567	->	^(I_ENCODED_ENUM reference_type_descriptor simple_name reference_type_descriptor);
568
569type_field_method_literal
570	:	reference_type_descriptor
571		(	ARROW
572			(	simple_name COLON nonvoid_type_descriptor -> ^(I_ENCODED_FIELD reference_type_descriptor simple_name nonvoid_type_descriptor)
573			|	method_name method_prototype -> ^(I_ENCODED_METHOD reference_type_descriptor method_name method_prototype)
574			)
575		|	-> reference_type_descriptor
576		)
577	|	PRIMITIVE_TYPE
578	|	VOID_TYPE;
579
580fully_qualified_method
581	:	reference_type_descriptor ARROW method_name method_prototype
582	->	reference_type_descriptor method_name method_prototype;
583
584fully_qualified_field
585	:	reference_type_descriptor ARROW simple_name COLON nonvoid_type_descriptor
586	->	reference_type_descriptor simple_name nonvoid_type_descriptor;
587
588label
589	:	COLON simple_name -> ^(I_LABEL[$COLON, "I_LABEL"] simple_name I_ADDRESS[$start, Integer.toString($method::currentAddress)]);
590
591label_ref_or_offset
592	:	COLON simple_name -> simple_name
593	|	OFFSET
594	|	NEGATIVE_INTEGER_LITERAL -> OFFSET[$NEGATIVE_INTEGER_LITERAL];
595
596register_list
597	:	REGISTER (COMMA REGISTER)* -> ^(I_REGISTER_LIST[$start, "I_REGISTER_LIST"] REGISTER*)
598	|	->^(I_REGISTER_LIST[$start, "I_REGISTER_LIST"]);
599
600register_range
601	:	REGISTER (DOTDOT REGISTER)? -> ^(I_REGISTER_RANGE[$start, "I_REGISTER_RANGE"] REGISTER REGISTER?);
602
603verification_error_reference
604	:	CLASS_DESCRIPTOR | fully_qualified_field | fully_qualified_method;
605
606catch_directive
607	:	CATCH_DIRECTIVE nonvoid_type_descriptor OPEN_BRACE from=label_ref_or_offset DOTDOT to=label_ref_or_offset CLOSE_BRACE using=label_ref_or_offset
608		-> ^(I_CATCH[$start, "I_CATCH"] I_ADDRESS[$start, Integer.toString($method::currentAddress)] nonvoid_type_descriptor $from $to $using);
609
610catchall_directive
611	:	CATCHALL_DIRECTIVE OPEN_BRACE from=label_ref_or_offset DOTDOT to=label_ref_or_offset CLOSE_BRACE using=label_ref_or_offset
612		-> ^(I_CATCHALL[$start, "I_CATCHALL"] I_ADDRESS[$start, Integer.toString($method::currentAddress)] $from $to $using);
613
614/*When there are annotations immediately after a parameter definition, we don't know whether they are parameter annotations
615or method annotations until we determine if there is an .end parameter directive. In either case, we still "consume" and parse
616the annotations. If it turns out that they are parameter annotations, we include them in the I_PARAMETER AST. Otherwise, we
617add them to the $statements_and_directives::methodAnnotations list*/
618parameter_directive
619	@init {List<CommonTree> annotations = new ArrayList<CommonTree>();}
620	:	PARAMETER_DIRECTIVE
621		STRING_LITERAL?
622		({input.LA(1) == ANNOTATION_DIRECTIVE}? annotation {annotations.add($annotation.tree);})*
623
624		(	END_PARAMETER_DIRECTIVE
625			-> ^(I_PARAMETER[$start, "I_PARAMETER"] STRING_LITERAL? ^(I_ANNOTATIONS annotation*))
626		|	/*epsilon*/ {$statements_and_directives::methodAnnotations.addAll(annotations);}
627			-> ^(I_PARAMETER[$start, "I_PARAMETER"] STRING_LITERAL? ^(I_ANNOTATIONS))
628		);
629
630ordered_debug_directive
631	:	line_directive
632	|	local_directive
633	|	end_local_directive
634	|	restart_local_directive
635	|	prologue_directive
636	|	epilogue_directive
637	|	source_directive;
638
639line_directive
640	:	LINE_DIRECTIVE integral_literal
641		-> ^(I_LINE integral_literal I_ADDRESS[$start, Integer.toString($method::currentAddress)]);
642
643local_directive
644	:	LOCAL_DIRECTIVE	REGISTER COMMA simple_name COLON nonvoid_type_descriptor (COMMA STRING_LITERAL)?
645		-> ^(I_LOCAL[$start, "I_LOCAL"] REGISTER simple_name nonvoid_type_descriptor STRING_LITERAL? I_ADDRESS[$start, Integer.toString($method::currentAddress)]);
646
647end_local_directive
648	:	END_LOCAL_DIRECTIVE REGISTER
649		-> ^(I_END_LOCAL[$start, "I_END_LOCAL"] REGISTER I_ADDRESS[$start, Integer.toString($method::currentAddress)]);
650
651restart_local_directive
652	:	RESTART_LOCAL_DIRECTIVE REGISTER
653		-> ^(I_RESTART_LOCAL[$start, "I_RESTART_LOCAL"] REGISTER I_ADDRESS[$start, Integer.toString($method::currentAddress)]);
654
655prologue_directive
656	:	PROLOGUE_DIRECTIVE
657		-> ^(I_PROLOGUE[$start, "I_PROLOGUE"] I_ADDRESS[$start, Integer.toString($method::currentAddress)]);
658
659epilogue_directive
660	:	EPILOGUE_DIRECTIVE
661		-> ^(I_EPILOGUE[$start, "I_EPILOGUE"] I_ADDRESS[$start, Integer.toString($method::currentAddress)]);
662
663source_directive
664	:	SOURCE_DIRECTIVE STRING_LITERAL
665		-> ^(I_SOURCE[$start, "I_SOURCE"] STRING_LITERAL I_ADDRESS[$start, Integer.toString($method::currentAddress)]);
666
667instruction_format12x
668	:	INSTRUCTION_FORMAT12x
669	|	INSTRUCTION_FORMAT12x_OR_ID -> INSTRUCTION_FORMAT12x[$INSTRUCTION_FORMAT12x_OR_ID];
670
671instruction_format22s
672	:	INSTRUCTION_FORMAT22s
673	|	INSTRUCTION_FORMAT22s_OR_ID -> INSTRUCTION_FORMAT22s[$INSTRUCTION_FORMAT22s_OR_ID];
674
675instruction_format31i
676	:	INSTRUCTION_FORMAT31i
677	|	INSTRUCTION_FORMAT31i_OR_ID -> INSTRUCTION_FORMAT31i[$INSTRUCTION_FORMAT31i_OR_ID];
678
679instruction returns [int size]
680	@init {boolean needsNop = false; int targetCount = 0;}
681	:	//e.g. goto endloop:
682		//e.g. goto +3
683		INSTRUCTION_FORMAT10t label_ref_or_offset {$size = Format.Format10t.size;}
684		-> ^(I_STATEMENT_FORMAT10t[$start, "I_STATEMENT_FORMAT10t"] INSTRUCTION_FORMAT10t label_ref_or_offset)
685	|	//e.g. return
686		INSTRUCTION_FORMAT10x {$size = Format.Format10x.size;}
687		-> ^(I_STATEMENT_FORMAT10x[$start, "I_STATEMENT_FORMAT10x"] INSTRUCTION_FORMAT10x)
688	|	//e.g. const/4 v0, 5
689		INSTRUCTION_FORMAT11n REGISTER COMMA integral_literal {$size = Format.Format11n.size;}
690		-> ^(I_STATEMENT_FORMAT11n[$start, "I_STATEMENT_FORMAT11n"] INSTRUCTION_FORMAT11n REGISTER integral_literal)
691	|	//e.g. move-result-object v1
692		INSTRUCTION_FORMAT11x REGISTER {$size = Format.Format11x.size;}
693		-> ^(I_STATEMENT_FORMAT11x[$start, "I_STATEMENT_FORMAT11x"] INSTRUCTION_FORMAT11x REGISTER)
694	|	//e.g. move v1 v2
695		instruction_format12x REGISTER COMMA REGISTER {$size = Format.Format12x.size;}
696		-> ^(I_STATEMENT_FORMAT12x[$start, "I_STATEMENT_FORMAT12x"] instruction_format12x REGISTER REGISTER)
697	|	//e.g. throw-verification-error generic-error, Lsome/class;
698		INSTRUCTION_FORMAT20bc VERIFICATION_ERROR_TYPE COMMA verification_error_reference {$size += Format.Format20bc.size;}
699		{
700			if (!allowOdex) {
701				throwOdexedInstructionException(input, $INSTRUCTION_FORMAT20bc.text);
702			}
703		}
704		-> ^(I_STATEMENT_FORMAT20bc INSTRUCTION_FORMAT20bc VERIFICATION_ERROR_TYPE verification_error_reference)
705	|	//e.g. goto/16 endloop:
706		INSTRUCTION_FORMAT20t label_ref_or_offset {$size = Format.Format20t.size;}
707		-> ^(I_STATEMENT_FORMAT20t[$start, "I_STATEMENT_FORMAT20t"] INSTRUCTION_FORMAT20t label_ref_or_offset)
708	|	//e.g. sget-object v0 java/lang/System/out LJava/io/PrintStream;
709		INSTRUCTION_FORMAT21c_FIELD REGISTER COMMA fully_qualified_field {$size = Format.Format21c.size;}
710		-> ^(I_STATEMENT_FORMAT21c_FIELD[$start, "I_STATEMENT_FORMAT21c_FIELD"] INSTRUCTION_FORMAT21c_FIELD REGISTER fully_qualified_field)
711	|	//e.g. sget-object-volatile v0 java/lang/System/out LJava/io/PrintStream;
712		INSTRUCTION_FORMAT21c_FIELD_ODEX REGISTER COMMA fully_qualified_field {$size = Format.Format21c.size;}
713		{
714			if (!allowOdex) {
715				throwOdexedInstructionException(input, $INSTRUCTION_FORMAT21c_FIELD_ODEX.text);
716			}
717		}
718		-> ^(I_STATEMENT_FORMAT21c_FIELD[$start, "I_STATEMENT_FORMAT21c_FIELD"] INSTRUCTION_FORMAT21c_FIELD_ODEX REGISTER fully_qualified_field)
719	|	//e.g. const-string v1 "Hello World!"
720		INSTRUCTION_FORMAT21c_STRING REGISTER COMMA STRING_LITERAL {$size = Format.Format21c.size;}
721		-> ^(I_STATEMENT_FORMAT21c_STRING[$start, "I_STATEMENT_FORMAT21c_STRING"] INSTRUCTION_FORMAT21c_STRING REGISTER STRING_LITERAL)
722	|	//e.g. const-class v2 Lorg/jf/HelloWorld2/HelloWorld2;
723		INSTRUCTION_FORMAT21c_TYPE REGISTER COMMA reference_type_descriptor {$size = Format.Format21c.size;}
724		-> ^(I_STATEMENT_FORMAT21c_TYPE[$start, "I_STATEMENT_FORMAT21c"] INSTRUCTION_FORMAT21c_TYPE REGISTER reference_type_descriptor)
725	|	//e.g. const/high16 v1, 1234
726		INSTRUCTION_FORMAT21h REGISTER COMMA integral_literal {$size = Format.Format21h.size;}
727		-> ^(I_STATEMENT_FORMAT21h[$start, "I_STATEMENT_FORMAT21h"] INSTRUCTION_FORMAT21h REGISTER integral_literal)
728	|	//e.g. const/16 v1, 1234
729		INSTRUCTION_FORMAT21s REGISTER COMMA integral_literal {$size = Format.Format21s.size;}
730		-> ^(I_STATEMENT_FORMAT21s[$start, "I_STATEMENT_FORMAT21s"] INSTRUCTION_FORMAT21s REGISTER integral_literal)
731	|	//e.g. if-eqz v0, endloop:
732		INSTRUCTION_FORMAT21t REGISTER COMMA (label_ref_or_offset) {$size = Format.Format21t.size;}
733		-> ^(I_STATEMENT_FORMAT21t[$start, "I_STATEMENT_FORMAT21t"] INSTRUCTION_FORMAT21t REGISTER label_ref_or_offset)
734	|	//e.g. add-int v0, v1, 123
735		INSTRUCTION_FORMAT22b REGISTER COMMA REGISTER COMMA integral_literal {$size = Format.Format22b.size;}
736		-> ^(I_STATEMENT_FORMAT22b[$start, "I_STATEMENT_FORMAT22b"] INSTRUCTION_FORMAT22b REGISTER REGISTER integral_literal)
737	|	//e.g. iput-object v1, v0 org/jf/HelloWorld2/HelloWorld2.helloWorld Ljava/lang/String;
738		INSTRUCTION_FORMAT22c_FIELD REGISTER COMMA REGISTER COMMA fully_qualified_field {$size = Format.Format22c.size;}
739		-> ^(I_STATEMENT_FORMAT22c_FIELD[$start, "I_STATEMENT_FORMAT22c_FIELD"] INSTRUCTION_FORMAT22c_FIELD REGISTER REGISTER fully_qualified_field)
740	|	//e.g. iput-object-volatile v1, v0 org/jf/HelloWorld2/HelloWorld2.helloWorld Ljava/lang/String;
741		INSTRUCTION_FORMAT22c_FIELD_ODEX REGISTER COMMA REGISTER COMMA fully_qualified_field {$size = Format.Format22c.size;}
742		{
743			if (!allowOdex) {
744				throwOdexedInstructionException(input, $INSTRUCTION_FORMAT22c_FIELD_ODEX.text);
745			}
746		}
747		-> ^(I_STATEMENT_FORMAT22c_FIELD[$start, "I_STATEMENT_FORMAT22c_FIELD"] INSTRUCTION_FORMAT22c_FIELD_ODEX REGISTER REGISTER fully_qualified_field)
748	|	//e.g. instance-of v0, v1, Ljava/lang/String;
749		INSTRUCTION_FORMAT22c_TYPE REGISTER COMMA REGISTER COMMA nonvoid_type_descriptor {$size = Format.Format22c.size;}
750		-> ^(I_STATEMENT_FORMAT22c_TYPE[$start, "I_STATEMENT_FORMAT22c_TYPE"] INSTRUCTION_FORMAT22c_TYPE REGISTER REGISTER nonvoid_type_descriptor)
751	|	//e.g. iget-quick v0, v1, field@0xc
752		INSTRUCTION_FORMAT22cs_FIELD REGISTER COMMA REGISTER COMMA FIELD_OFFSET
753		{
754			throwOdexedInstructionException(input, $INSTRUCTION_FORMAT22cs_FIELD.text);
755		}
756	|	//e.g. add-int/lit16 v0, v1, 12345
757		instruction_format22s REGISTER COMMA REGISTER COMMA integral_literal {$size = Format.Format22s.size;}
758		-> ^(I_STATEMENT_FORMAT22s[$start, "I_STATEMENT_FORMAT22s"] instruction_format22s REGISTER REGISTER integral_literal)
759	|	//e.g. if-eq v0, v1, endloop:
760		INSTRUCTION_FORMAT22t REGISTER COMMA REGISTER COMMA label_ref_or_offset {$size = Format.Format22t.size;}
761		-> ^(I_STATEMENT_FORMAT22t[$start, "I_STATEMENT_FFORMAT22t"] INSTRUCTION_FORMAT22t REGISTER REGISTER label_ref_or_offset)
762	|	//e.g. move/from16 v1, v1234
763		INSTRUCTION_FORMAT22x REGISTER COMMA REGISTER {$size = Format.Format22x.size;}
764		-> ^(I_STATEMENT_FORMAT22x[$start, "I_STATEMENT_FORMAT22x"] INSTRUCTION_FORMAT22x REGISTER REGISTER)
765	|	//e.g. add-int v1, v2, v3
766		INSTRUCTION_FORMAT23x REGISTER COMMA REGISTER COMMA REGISTER {$size = Format.Format23x.size;}
767		-> ^(I_STATEMENT_FORMAT23x[$start, "I_STATEMENT_FORMAT23x"] INSTRUCTION_FORMAT23x REGISTER REGISTER REGISTER)
768	|	//e.g. goto/32 endloop:
769		INSTRUCTION_FORMAT30t label_ref_or_offset {$size = Format.Format30t.size;}
770		-> ^(I_STATEMENT_FORMAT30t[$start, "I_STATEMENT_FORMAT30t"] INSTRUCTION_FORMAT30t label_ref_or_offset)
771	|	//e.g. const-string/jumbo v1 "Hello World!"
772		INSTRUCTION_FORMAT31c REGISTER COMMA STRING_LITERAL {$size = Format.Format31c.size;}
773		->^(I_STATEMENT_FORMAT31c[$start, "I_STATEMENT_FORMAT31c"] INSTRUCTION_FORMAT31c REGISTER STRING_LITERAL)
774	|	//e.g. const v0, 123456
775		instruction_format31i REGISTER COMMA fixed_32bit_literal {$size = Format.Format31i.size;}
776		-> ^(I_STATEMENT_FORMAT31i[$start, "I_STATEMENT_FORMAT31i"] instruction_format31i REGISTER fixed_32bit_literal)
777	|	//e.g. fill-array-data v0, ArrayData:
778		INSTRUCTION_FORMAT31t REGISTER COMMA label_ref_or_offset {$size = Format.Format31t.size;}
779		{
780			if ($INSTRUCTION_FORMAT31t.text.equals("packed-switch")) {
781				CommonTree root = new CommonTree(new CommonToken(I_PACKED_SWITCH_DECLARATION, "I_PACKED_SWITCH_DECLARATION"));
782				CommonTree address = new CommonTree(new CommonToken(I_ADDRESS, Integer.toString($method::currentAddress)));
783				root.addChild(address);
784				root.addChild($label_ref_or_offset.tree.dupNode());
785				$statements_and_directives::packedSwitchDeclarations.add(root);
786			} else if ($INSTRUCTION_FORMAT31t.text.equals("sparse-switch")) {
787				CommonTree root = new CommonTree(new CommonToken(I_SPARSE_SWITCH_DECLARATION, "I_SPARSE_SWITCH_DECLARATION"));
788				CommonTree address = new CommonTree(new CommonToken(I_ADDRESS, Integer.toString($method::currentAddress)));
789				root.addChild(address);
790				root.addChild($label_ref_or_offset.tree.dupNode());
791				$statements_and_directives::sparseSwitchDeclarations.add(root);
792			}
793		}
794		-> ^(I_STATEMENT_FORMAT31t[$start, "I_STATEMENT_FORMAT31t"] INSTRUCTION_FORMAT31t REGISTER label_ref_or_offset)
795	|	//e.g. move/16 v4567, v1234
796		INSTRUCTION_FORMAT32x REGISTER COMMA REGISTER {$size = Format.Format32x.size;}
797		-> ^(I_STATEMENT_FORMAT32x[$start, "I_STATEMENT_FORMAT32x"] INSTRUCTION_FORMAT32x REGISTER REGISTER)
798	|	//e.g. invoke-virtual {v0,v1} java/io/PrintStream/print(Ljava/lang/Stream;)V
799		INSTRUCTION_FORMAT35c_METHOD OPEN_BRACE register_list CLOSE_BRACE COMMA fully_qualified_method {$size = Format.Format35c.size;}
800		-> ^(I_STATEMENT_FORMAT35c_METHOD[$start, "I_STATEMENT_FORMAT35c_METHOD"] INSTRUCTION_FORMAT35c_METHOD register_list fully_qualified_method)
801	|	//e.g. filled-new-array {v0,v1}, I
802		INSTRUCTION_FORMAT35c_TYPE OPEN_BRACE register_list CLOSE_BRACE COMMA nonvoid_type_descriptor {$size = Format.Format35c.size;}
803		-> ^(I_STATEMENT_FORMAT35c_TYPE[$start, "I_STATEMENT_FORMAT35c_TYPE"] INSTRUCTION_FORMAT35c_TYPE register_list nonvoid_type_descriptor)
804	|	//e.g. invoke-direct {p0}, Ljava/lang/Object;-><init>()V
805		INSTRUCTION_FORMAT35s_METHOD OPEN_BRACE register_list CLOSE_BRACE COMMA fully_qualified_method
806		{
807			throwOdexedInstructionException(input, $INSTRUCTION_FORMAT35s_METHOD.text);
808		}
809	|	//e.g. invoke-virtual-range {v0, v1}, vtable@0x4
810		INSTRUCTION_FORMAT35ms_METHOD OPEN_BRACE register_list CLOSE_BRACE COMMA VTABLE_OFFSET
811		{
812			throwOdexedInstructionException(input, $INSTRUCTION_FORMAT35ms_METHOD.text);
813		}
814	|	//e.g. invoke-virtual/range {v25..v26}, java/lang/StringBuilder/append(Ljava/lang/String;)Ljava/lang/StringBuilder;
815		INSTRUCTION_FORMAT3rc_METHOD OPEN_BRACE register_range CLOSE_BRACE COMMA fully_qualified_method {$size = Format.Format3rc.size;}
816		-> ^(I_STATEMENT_FORMAT3rc_METHOD[$start, "I_STATEMENT_FORMAT3rc_METHOD"] INSTRUCTION_FORMAT3rc_METHOD register_range fully_qualified_method)
817	|	//e.g. filled-new-array/range {v0..v6}, I
818		INSTRUCTION_FORMAT3rc_TYPE OPEN_BRACE register_range CLOSE_BRACE COMMA nonvoid_type_descriptor {$size = Format.Format3rc.size;}
819		-> ^(I_STATEMENT_FORMAT3rc_TYPE[$start, "I_STATEMENT_FORMAT3rc_TYPE"] INSTRUCTION_FORMAT3rc_TYPE register_range nonvoid_type_descriptor)
820	|	//e.g. invoke-virtual-quick/range {v0 .. v10}, vtable@0x14
821		INSTRUCTION_FORMAT3rms_METHOD OPEN_BRACE register_range CLOSE_BRACE COMMA VTABLE_OFFSET
822		{
823			throwOdexedInstructionException(input, $INSTRUCTION_FORMAT3rms_METHOD.text);
824		}
825	|	//e.g. const-wide v0, 5000000000L
826		INSTRUCTION_FORMAT51l REGISTER COMMA fixed_literal {$size = Format.Format51l.size;}
827		-> ^(I_STATEMENT_FORMAT51l[$start, "I_STATEMENT_FORMAT51l"] INSTRUCTION_FORMAT51l REGISTER fixed_literal)
828	|
829		ARRAY_DATA_DIRECTIVE
830		{
831			if (($method::currentAddress \% 2) != 0) {
832				needsNop = true;
833				$size = 2;
834			} else {
835				$size = 0;
836			}
837		}
838
839		integral_literal (fixed_literal {$size+=$fixed_literal.size;})* END_ARRAY_DATA_DIRECTIVE
840		{$size = (($size + 1)/2)*2 + 8;}
841
842		/*add a nop statement before this if needed to force the correct alignment*/
843		->	{needsNop}?	^(I_STATEMENT_FORMAT10x[$start,  "I_STATEMENT_FORMAT10x"] INSTRUCTION_FORMAT10x[$start, "nop"])
844					^(I_STATEMENT_ARRAY_DATA ^(I_ARRAY_ELEMENT_SIZE integral_literal) ^(I_ARRAY_ELEMENTS fixed_literal*))
845
846		->	^(I_STATEMENT_ARRAY_DATA[$start, "I_STATEMENT_ARRAY_DATA"] ^(I_ARRAY_ELEMENT_SIZE integral_literal)
847				^(I_ARRAY_ELEMENTS fixed_literal*))
848	|
849		PACKED_SWITCH_DIRECTIVE
850		{
851			targetCount = 0;
852			if (($method::currentAddress \% 2) != 0) {
853				needsNop = true;
854				$size = 2;
855			} else {
856				$size = 0;
857			}
858		}
859
860		fixed_32bit_literal
861
862		(switch_target += label_ref_or_offset {$size+=4; targetCount++;})*
863
864		END_PACKED_SWITCH_DIRECTIVE {$size = $size + 8;}
865
866		/*add a nop statement before this if needed to force the correct alignment*/
867		->	{needsNop}?	^(I_STATEMENT_FORMAT10x[$start,  "I_STATEMENT_FORMAT10x"] INSTRUCTION_FORMAT10x[$start, "nop"])
868					^(I_STATEMENT_PACKED_SWITCH[$start, "I_STATEMENT_PACKED_SWITCH"]
869						^(I_PACKED_SWITCH_START_KEY[$start, "I_PACKED_SWITCH_START_KEY"] fixed_32bit_literal)
870						^(I_PACKED_SWITCH_TARGETS[$start, "I_PACKED_SWITCH_TARGETS"] I_PACKED_SWITCH_TARGET_COUNT[$start, Integer.toString(targetCount)] $switch_target*)
871					)
872
873		->	^(I_STATEMENT_PACKED_SWITCH[$start, "I_STATEMENT_PACKED_SWITCH"]
874				^(I_PACKED_SWITCH_START_KEY[$start, "I_PACKED_SWITCH_START_KEY"] fixed_32bit_literal)
875				^(I_PACKED_SWITCH_TARGETS[$start, "I_PACKED_SWITCH_TARGETS"] I_PACKED_SWITCH_TARGET_COUNT[$start, Integer.toString(targetCount)] $switch_target*)
876			)
877
878	|
879		SPARSE_SWITCH_DIRECTIVE
880		{
881			targetCount = 0;
882			if (($method::currentAddress \% 2) != 0) {
883				needsNop = true;
884				$size = 2;
885			} else {
886				$size = 0;
887			}
888		}
889
890		(fixed_32bit_literal ARROW switch_target += label_ref_or_offset {$size += 8; targetCount++;})*
891
892		END_SPARSE_SWITCH_DIRECTIVE {$size = $size + 4;}
893
894		/*add a nop statement before this if needed to force the correct alignment*/
895		->	{needsNop}?	^(I_STATEMENT_FORMAT10x[$start,  "I_STATEMENT_FORMAT10x"] INSTRUCTION_FORMAT10x[$start, "nop"])
896					^(I_STATEMENT_SPARSE_SWITCH[$start, "I_STATEMENT_SPARSE_SWITCH"]
897						I_SPARSE_SWITCH_TARGET_COUNT[$start, Integer.toString(targetCount)]
898						^(I_SPARSE_SWITCH_KEYS[$start, "I_SPARSE_SWITCH_KEYS"] fixed_32bit_literal*)
899						^(I_SPARSE_SWITCH_TARGETS $switch_target*))
900		->	^(I_STATEMENT_SPARSE_SWITCH[$start, "I_STATEMENT_SPARSE_SWITCH"]
901				I_SPARSE_SWITCH_TARGET_COUNT[$start, Integer.toString(targetCount)]
902				^(I_SPARSE_SWITCH_KEYS[$start, "I_SPARSE_SWITCH_KEYS"] fixed_32bit_literal*)
903				^(I_SPARSE_SWITCH_TARGETS $switch_target*));