smaliParser.g revision a81c962f008def897a9294c4eea6e5bf5a1d79ae
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  output=AST;
33  ASTLabelType=CommonTree;
34}
35
36tokens {
37  //Lexer tokens
38  ACCESS_SPEC;
39  ANNOTATION_DIRECTIVE;
40  ANNOTATION_VISIBILITY;
41  ARRAY_DATA_DIRECTIVE;
42  ARRAY_DESCRIPTOR;
43  ARROW;
44  BASE_ARRAY_DESCRIPTOR;
45  BASE_CHAR_LITERAL;
46  BASE_CLASS_DESCRIPTOR;
47  BASE_FLOAT;
48  BASE_FLOAT_OR_ID;
49  BASE_INTEGER;
50  BASE_PRIMITIVE_TYPE;
51  BASE_SIMPLE_NAME;
52  BASE_STRING_LITERAL;
53  BASE_TYPE;
54  BINARY_EXPONENT;
55  BOOL_LITERAL;
56  BYTE_LITERAL;
57  CATCH_DIRECTIVE;
58  CATCHALL_DIRECTIVE;
59  CHAR_LITERAL;
60  CLASS_DESCRIPTOR;
61  CLASS_DIRECTIVE;
62  CLOSE_BRACE;
63  CLOSE_PAREN;
64  COLON;
65  COMMA;
66  DECIMAL_EXPONENT;
67  DOTDOT;
68  DOUBLE_LITERAL;
69  DOUBLE_LITERAL_OR_ID;
70  END_ANNOTATION_DIRECTIVE;
71  END_ARRAY_DATA_DIRECTIVE;
72  END_FIELD_DIRECTIVE;
73  END_LOCAL_DIRECTIVE;
74  END_METHOD_DIRECTIVE;
75  END_PACKED_SWITCH_DIRECTIVE;
76  END_PARAMETER_DIRECTIVE;
77  END_SPARSE_SWITCH_DIRECTIVE;
78  END_SUBANNOTATION_DIRECTIVE;
79  ENUM_DIRECTIVE;
80  EPILOGUE_DIRECTIVE;
81  EQUAL;
82  ESCAPE_SEQUENCE;
83  FIELD_DIRECTIVE;
84  FIELD_OFFSET;
85  FLOAT_LITERAL;
86  FLOAT_LITERAL_OR_ID;
87  HEX_DIGIT;
88  HEX_DIGITS;
89  HEX_PREFIX;
90  IMPLEMENTS_DIRECTIVE;
91  INLINE_INDEX;
92  INSTRUCTION_FORMAT10t;
93  INSTRUCTION_FORMAT10x;
94  INSTRUCTION_FORMAT10x_ODEX;
95  INSTRUCTION_FORMAT11n;
96  INSTRUCTION_FORMAT11x;
97  INSTRUCTION_FORMAT12x;
98  INSTRUCTION_FORMAT12x_OR_ID;
99  INSTRUCTION_FORMAT20bc;
100  INSTRUCTION_FORMAT20t;
101  INSTRUCTION_FORMAT21c_FIELD;
102  INSTRUCTION_FORMAT21c_FIELD_ODEX;
103  INSTRUCTION_FORMAT21c_STRING;
104  INSTRUCTION_FORMAT21c_TYPE;
105  INSTRUCTION_FORMAT21ih;
106  INSTRUCTION_FORMAT21lh;
107  INSTRUCTION_FORMAT21s;
108  INSTRUCTION_FORMAT21t;
109  INSTRUCTION_FORMAT22b;
110  INSTRUCTION_FORMAT22c_FIELD;
111  INSTRUCTION_FORMAT22c_FIELD_ODEX;
112  INSTRUCTION_FORMAT22c_TYPE;
113  INSTRUCTION_FORMAT22cs_FIELD;
114  INSTRUCTION_FORMAT22s;
115  INSTRUCTION_FORMAT22s_OR_ID;
116  INSTRUCTION_FORMAT22t;
117  INSTRUCTION_FORMAT22x;
118  INSTRUCTION_FORMAT23x;
119  INSTRUCTION_FORMAT30t;
120  INSTRUCTION_FORMAT31c;
121  INSTRUCTION_FORMAT31i;
122  INSTRUCTION_FORMAT31i_OR_ID;
123  INSTRUCTION_FORMAT31t;
124  INSTRUCTION_FORMAT32x;
125  INSTRUCTION_FORMAT35c_METHOD;
126  INSTRUCTION_FORMAT35c_METHOD_ODEX;
127  INSTRUCTION_FORMAT35c_TYPE;
128  INSTRUCTION_FORMAT35mi_METHOD;
129  INSTRUCTION_FORMAT35ms_METHOD;
130  INSTRUCTION_FORMAT3rc_METHOD;
131  INSTRUCTION_FORMAT3rc_METHOD_ODEX;
132  INSTRUCTION_FORMAT3rc_TYPE;
133  INSTRUCTION_FORMAT3rmi_METHOD;
134  INSTRUCTION_FORMAT3rms_METHOD;
135  INSTRUCTION_FORMAT51l;
136  INVALID_TOKEN;
137  LINE_COMMENT;
138  LINE_DIRECTIVE;
139  LOCAL_DIRECTIVE;
140  LOCALS_DIRECTIVE;
141  LONG_LITERAL;
142  METHOD_DIRECTIVE;
143  METHOD_NAME;
144  NEGATIVE_INTEGER_LITERAL;
145  NULL_LITERAL;
146  OPEN_BRACE;
147  OPEN_PAREN;
148  PACKED_SWITCH_DIRECTIVE;
149  PARAM_LIST;
150  PARAM_LIST_OR_ID;
151  PARAMETER_DIRECTIVE;
152  POSITIVE_INTEGER_LITERAL;
153  PRIMITIVE_TYPE;
154  PROLOGUE_DIRECTIVE;
155  REGISTER;
156  REGISTERS_DIRECTIVE;
157  RESTART_LOCAL_DIRECTIVE;
158  SHORT_LITERAL;
159  SIMPLE_NAME;
160  SOURCE_DIRECTIVE;
161  SPARSE_SWITCH_DIRECTIVE;
162  STRING_LITERAL;
163  SUBANNOTATION_DIRECTIVE;
164  SUPER_DIRECTIVE;
165  VERIFICATION_ERROR_TYPE;
166  VOID_TYPE;
167  VTABLE_INDEX;
168  WHITE_SPACE;
169
170  //A couple of generated types that we remap other tokens to, to simplify the generated AST
171  LABEL;
172  INTEGER_LITERAL;
173
174  //I_* tokens are imaginary tokens used as parent AST nodes
175  I_CLASS_DEF;
176  I_SUPER;
177  I_IMPLEMENTS;
178  I_SOURCE;
179  I_ACCESS_LIST;
180  I_METHODS;
181  I_FIELDS;
182  I_FIELD;
183  I_FIELD_TYPE;
184  I_FIELD_INITIAL_VALUE;
185  I_METHOD;
186  I_METHOD_PROTOTYPE;
187  I_METHOD_RETURN_TYPE;
188  I_REGISTERS;
189  I_LOCALS;
190  I_LABELS;
191  I_LABEL;
192  I_ANNOTATIONS;
193  I_ANNOTATION;
194  I_ANNOTATION_ELEMENT;
195  I_SUBANNOTATION;
196  I_ENCODED_FIELD;
197  I_ENCODED_METHOD;
198  I_ENCODED_ENUM;
199  I_ENCODED_ARRAY;
200  I_ARRAY_ELEMENT_SIZE;
201  I_ARRAY_ELEMENTS;
202  I_PACKED_SWITCH_START_KEY;
203  I_PACKED_SWITCH_ELEMENTS;
204  I_PACKED_SWITCH_DECLARATION;
205  I_PACKED_SWITCH_DECLARATIONS;
206  I_SPARSE_SWITCH_ELEMENTS;
207  I_SPARSE_SWITCH_DECLARATION;
208  I_SPARSE_SWITCH_DECLARATIONS;
209  I_ADDRESS;
210  I_CATCH;
211  I_CATCHALL;
212  I_CATCHES;
213  I_PARAMETER;
214  I_PARAMETERS;
215  I_PARAMETER_NOT_SPECIFIED;
216  I_ORDERED_DEBUG_DIRECTIVES;
217  I_LINE;
218  I_LOCAL;
219  I_END_LOCAL;
220  I_RESTART_LOCAL;
221  I_PROLOGUE;
222  I_EPILOGUE;
223  I_STATEMENTS;
224  I_STATEMENT_FORMAT10t;
225  I_STATEMENT_FORMAT10x;
226  I_STATEMENT_FORMAT11n;
227  I_STATEMENT_FORMAT11x;
228  I_STATEMENT_FORMAT12x;
229  I_STATEMENT_FORMAT20bc;
230  I_STATEMENT_FORMAT20t;
231  I_STATEMENT_FORMAT21c_TYPE;
232  I_STATEMENT_FORMAT21c_FIELD;
233  I_STATEMENT_FORMAT21c_STRING;
234  I_STATEMENT_FORMAT21ih;
235  I_STATEMENT_FORMAT21lh;
236  I_STATEMENT_FORMAT21s;
237  I_STATEMENT_FORMAT21t;
238  I_STATEMENT_FORMAT22b;
239  I_STATEMENT_FORMAT22c_FIELD;
240  I_STATEMENT_FORMAT22c_TYPE;
241  I_STATEMENT_FORMAT22s;
242  I_STATEMENT_FORMAT22t;
243  I_STATEMENT_FORMAT22x;
244  I_STATEMENT_FORMAT23x;
245  I_STATEMENT_FORMAT30t;
246  I_STATEMENT_FORMAT31c;
247  I_STATEMENT_FORMAT31i;
248  I_STATEMENT_FORMAT31t;
249  I_STATEMENT_FORMAT32x;
250  I_STATEMENT_FORMAT35c_METHOD;
251  I_STATEMENT_FORMAT35c_TYPE;
252  I_STATEMENT_FORMAT3rc_METHOD;
253  I_STATEMENT_FORMAT3rc_TYPE;
254  I_STATEMENT_FORMAT51l;
255  I_STATEMENT_ARRAY_DATA;
256  I_STATEMENT_PACKED_SWITCH;
257  I_STATEMENT_SPARSE_SWITCH;
258  I_REGISTER_RANGE;
259  I_REGISTER_LIST;
260}
261
262@header {
263package org.jf.smali;
264
265import org.jf.dexlib2.Format;
266import org.jf.dexlib2.Opcode;
267import org.jf.dexlib2.Opcodes;
268}
269
270
271@members {
272  public static final int ERROR_CHANNEL = 100;
273
274  private boolean verboseErrors = false;
275  private boolean allowOdex = false;
276  private int apiLevel = 15;
277  private Opcodes opcodes = new Opcodes(apiLevel);
278
279  public void setVerboseErrors(boolean verboseErrors) {
280    this.verboseErrors = verboseErrors;
281  }
282
283  public void setAllowOdex(boolean allowOdex) {
284      this.allowOdex = allowOdex;
285  }
286
287  public void setApiLevel(int apiLevel) {
288      this.opcodes = new Opcodes(apiLevel);
289      this.apiLevel = apiLevel;
290  }
291
292  public String getErrorMessage(RecognitionException e,
293    String[] tokenNames) {
294
295    if (verboseErrors) {
296      List stack = getRuleInvocationStack(e, this.getClass().getName());
297      String msg = null;
298
299      if (e instanceof NoViableAltException) {
300        NoViableAltException nvae = (NoViableAltException)e;
301        msg = " no viable alt; token="+getTokenErrorDisplay(e.token)+
302        " (decision="+nvae.decisionNumber+
303        " state "+nvae.stateNumber+")"+
304        " decision=<<"+nvae.grammarDecisionDescription+">>";
305      } else {
306        msg = super.getErrorMessage(e, tokenNames);
307      }
308
309      return stack + " " + msg;
310    } else {
311      return super.getErrorMessage(e, tokenNames);
312    }
313  }
314
315  public String getTokenErrorDisplay(Token t) {
316    if (!verboseErrors) {
317      String s = t.getText();
318      if ( s==null ) {
319        if ( t.getType()==Token.EOF ) {
320          s = "<EOF>";
321        }
322        else {
323          s = "<"+tokenNames[t.getType()]+">";
324        }
325      }
326      s = s.replaceAll("\n","\\\\n");
327      s = s.replaceAll("\r","\\\\r");
328      s = s.replaceAll("\t","\\\\t");
329      return "'"+s+"'";
330    }
331
332    CommonToken ct = (CommonToken)t;
333
334    String channelStr = "";
335    if (t.getChannel()>0) {
336      channelStr=",channel="+t.getChannel();
337    }
338    String txt = t.getText();
339    if ( txt!=null ) {
340      txt = txt.replaceAll("\n","\\\\n");
341      txt = txt.replaceAll("\r","\\\\r");
342      txt = txt.replaceAll("\t","\\\\t");
343    }
344    else {
345      txt = "<no text>";
346    }
347    return "[@"+t.getTokenIndex()+","+ct.getStartIndex()+":"+ct.getStopIndex()+"='"+txt+"',<"+tokenNames[t.getType()]+">"+channelStr+","+t.getLine()+":"+t.getCharPositionInLine()+"]";
348  }
349
350  public String getErrorHeader(RecognitionException e) {
351    return getSourceName()+"["+ e.line+","+e.charPositionInLine+"]";
352  }
353
354  private CommonTree buildTree(int type, String text, List<CommonTree> children) {
355    CommonTree root = new CommonTree(new CommonToken(type, text));
356    for (CommonTree child: children) {
357      root.addChild(child);
358    }
359    return root;
360  }
361
362  private CommonToken getParamListSubToken(CommonToken baseToken, String str, int typeStartIndex) {
363    CommonToken token = new CommonToken(baseToken);
364    token.setStartIndex(baseToken.getStartIndex() + typeStartIndex);
365
366    switch (str.charAt(typeStartIndex)) {
367      case 'Z':
368      case 'B':
369      case 'S':
370      case 'C':
371      case 'I':
372      case 'J':
373      case 'F':
374      case 'D':
375      {
376        token.setType(PRIMITIVE_TYPE);
377        token.setText(str.substring(typeStartIndex, typeStartIndex+1));
378        token.setStopIndex(baseToken.getStartIndex() + typeStartIndex);
379        break;
380      }
381      case 'L':
382      {
383        int i = typeStartIndex;
384        while (str.charAt(++i) != ';');
385
386        token.setType(CLASS_DESCRIPTOR);
387        token.setText(str.substring(typeStartIndex, i + 1));
388        token.setStopIndex(baseToken.getStartIndex() + i);
389        break;
390      }
391      case '[':
392      {
393        int i = typeStartIndex;
394            while (str.charAt(++i) == '[');
395
396            if (str.charAt(i++) == 'L') {
397                while (str.charAt(i++) != ';');
398        }
399
400            token.setType(ARRAY_DESCRIPTOR);
401            token.setText(str.substring(typeStartIndex, i));
402            token.setStopIndex(baseToken.getStartIndex() + i - 1);
403            break;
404      }
405      default:
406        throw new RuntimeException(String.format("Invalid character '\%c' in param list \"\%s\" at position \%d", str.charAt(typeStartIndex), str, typeStartIndex));
407    }
408
409    return token;
410  }
411
412  private CommonTree parseParamList(CommonToken paramListToken) {
413    String paramList = paramListToken.getText();
414    CommonTree root = new CommonTree();
415
416    int startIndex = paramListToken.getStartIndex();
417
418    int i=0;
419    while (i<paramList.length()) {
420      CommonToken token = getParamListSubToken(paramListToken, paramList, i);
421      root.addChild(new CommonTree(token));
422      i += token.getText().length();
423    }
424
425    if (root.getChildCount() == 0) {
426      return null;
427    }
428    return root;
429  }
430
431  private void throwOdexedInstructionException(IntStream input, String odexedInstruction)
432      throws OdexedInstructionException {
433    /*this has to be done in a separate method, otherwise java will complain about the
434    auto-generated code in the rule after the throw not being reachable*/
435    throw new OdexedInstructionException(input, odexedInstruction);
436  }
437}
438
439
440smali_file
441  scope
442  {
443    boolean hasClassSpec;
444    boolean hasSuperSpec;
445    boolean hasSourceSpec;
446    List<CommonTree> classAnnotations;
447  }
448  @init
449  { $smali_file::hasClassSpec = $smali_file::hasSuperSpec = $smali_file::hasSourceSpec = false;
450    $smali_file::classAnnotations = new ArrayList<CommonTree>();
451  }
452  :
453  ( {!$smali_file::hasClassSpec}?=> class_spec {$smali_file::hasClassSpec = true;}
454  | {!$smali_file::hasSuperSpec}?=> super_spec {$smali_file::hasSuperSpec = true;}
455  | implements_spec
456  | {!$smali_file::hasSourceSpec}?=> source_spec {$smali_file::hasSourceSpec = true;}
457  | method
458  | field
459  | annotation {$smali_file::classAnnotations.add($annotation.tree);}
460  )+
461  EOF
462  {
463    if (!$smali_file::hasClassSpec) {
464      throw new SemanticException(input, "The file must contain a .class directive");
465    }
466
467    if (!$smali_file::hasSuperSpec) {
468      if (!$class_spec.className.equals("Ljava/lang/Object;")) {
469        throw new SemanticException(input, "The file must contain a .super directive");
470      }
471    }
472  }
473  -> ^(I_CLASS_DEF
474       class_spec
475       super_spec?
476       implements_spec*
477       source_spec?
478       ^(I_METHODS method*) ^(I_FIELDS field*) {buildTree(I_ANNOTATIONS, "I_ANNOTATIONS", $smali_file::classAnnotations)});
479
480class_spec returns[String className]
481  : CLASS_DIRECTIVE access_list CLASS_DESCRIPTOR {$className = $CLASS_DESCRIPTOR.text;} -> CLASS_DESCRIPTOR access_list;
482
483super_spec
484  : SUPER_DIRECTIVE CLASS_DESCRIPTOR -> ^(I_SUPER[$start, "I_SUPER"] CLASS_DESCRIPTOR);
485
486implements_spec
487  : IMPLEMENTS_DIRECTIVE CLASS_DESCRIPTOR -> ^(I_IMPLEMENTS[$start, "I_IMPLEMENTS"] CLASS_DESCRIPTOR);
488
489source_spec
490  : SOURCE_DIRECTIVE STRING_LITERAL -> ^(I_SOURCE[$start, "I_SOURCE"] STRING_LITERAL);
491
492access_list
493  : ACCESS_SPEC* -> ^(I_ACCESS_LIST[$start,"I_ACCESS_LIST"] ACCESS_SPEC*);
494
495
496/*When there are annotations immediately after a field definition, we don't know whether they are field annotations
497or class annotations until we determine if there is an .end field directive. In either case, we still "consume" and parse
498the annotations. If it turns out that they are field annotations, we include them in the I_FIELD AST. Otherwise, we
499add them to the $smali_file::classAnnotations list*/
500field
501  @init {List<CommonTree> annotations = new ArrayList<CommonTree>();}
502  : FIELD_DIRECTIVE access_list simple_name COLON nonvoid_type_descriptor (EQUAL literal)?
503    ( ({input.LA(1) == ANNOTATION_DIRECTIVE}? annotation {annotations.add($annotation.tree);})*
504      ( END_FIELD_DIRECTIVE
505        -> ^(I_FIELD[$start, "I_FIELD"] simple_name access_list ^(I_FIELD_TYPE nonvoid_type_descriptor) ^(I_FIELD_INITIAL_VALUE literal)? ^(I_ANNOTATIONS annotation*))
506      | /*epsilon*/ {$smali_file::classAnnotations.addAll(annotations);}
507        -> ^(I_FIELD[$start, "I_FIELD"] simple_name access_list ^(I_FIELD_TYPE nonvoid_type_descriptor) ^(I_FIELD_INITIAL_VALUE literal)? ^(I_ANNOTATIONS))
508      )
509    );
510
511method
512  scope {int currentAddress;}
513  : {$method::currentAddress = 0;}
514    METHOD_DIRECTIVE access_list method_name method_prototype statements_and_directives
515    END_METHOD_DIRECTIVE
516    -> ^(I_METHOD[$start, "I_METHOD"] method_name method_prototype access_list statements_and_directives);
517
518statements_and_directives
519  scope
520  {
521    boolean hasRegistersDirective;
522    List<CommonTree> packedSwitchDeclarations;
523    List<CommonTree> sparseSwitchDeclarations;
524    List<CommonTree> methodAnnotations;
525  }
526  : {
527      $method::currentAddress = 0;
528      $statements_and_directives::hasRegistersDirective = false;
529      $statements_and_directives::packedSwitchDeclarations = new ArrayList<CommonTree>();
530      $statements_and_directives::sparseSwitchDeclarations = new ArrayList<CommonTree>();
531      $statements_and_directives::methodAnnotations = new ArrayList<CommonTree>();
532    }
533    ( instruction {$method::currentAddress += $instruction.size/2;}
534    | registers_directive
535    | label
536    | catch_directive
537    | catchall_directive
538    | parameter_directive
539    | ordered_debug_directive
540    | annotation  {$statements_and_directives::methodAnnotations.add($annotation.tree);}
541    )*
542    -> registers_directive?
543       ^(I_LABELS label*)
544       {buildTree(I_PACKED_SWITCH_DECLARATIONS, "I_PACKED_SWITCH_DECLARATIONS", $statements_and_directives::packedSwitchDeclarations)}
545       {buildTree(I_SPARSE_SWITCH_DECLARATIONS, "I_SPARSE_SWITCH_DECLARATIONS", $statements_and_directives::sparseSwitchDeclarations)}
546       ^(I_STATEMENTS instruction*)
547       ^(I_CATCHES catch_directive* catchall_directive*)
548       ^(I_PARAMETERS parameter_directive*)
549       ^(I_ORDERED_DEBUG_DIRECTIVES ordered_debug_directive*)
550       {buildTree(I_ANNOTATIONS, "I_ANNOTATIONS", $statements_and_directives::methodAnnotations)};
551
552registers_directive
553  : (
554      directive=REGISTERS_DIRECTIVE regCount=integral_literal -> ^(I_REGISTERS[$REGISTERS_DIRECTIVE, "I_REGISTERS"] $regCount)
555    | directive=LOCALS_DIRECTIVE regCount2=integral_literal -> ^(I_LOCALS[$LOCALS_DIRECTIVE, "I_LOCALS"] $regCount2)
556    )
557    {
558      if ($statements_and_directives::hasRegistersDirective) {
559        throw new SemanticException(input, $directive, "There can only be a single .registers or .locals directive in a method");
560      }
561      $statements_and_directives::hasRegistersDirective=true;
562    };
563
564/*identifiers are much more general than most languages. Any of the below can either be
565the indicated type OR an identifier, depending on the context*/
566simple_name
567  : SIMPLE_NAME
568  | ACCESS_SPEC -> SIMPLE_NAME[$ACCESS_SPEC]
569  | VERIFICATION_ERROR_TYPE -> SIMPLE_NAME[$VERIFICATION_ERROR_TYPE]
570  | POSITIVE_INTEGER_LITERAL -> SIMPLE_NAME[$POSITIVE_INTEGER_LITERAL]
571  | NEGATIVE_INTEGER_LITERAL -> SIMPLE_NAME[$NEGATIVE_INTEGER_LITERAL]
572  | FLOAT_LITERAL_OR_ID -> SIMPLE_NAME[$FLOAT_LITERAL_OR_ID]
573  | DOUBLE_LITERAL_OR_ID -> SIMPLE_NAME[$DOUBLE_LITERAL_OR_ID]
574  | BOOL_LITERAL -> SIMPLE_NAME[$BOOL_LITERAL]
575  | NULL_LITERAL -> SIMPLE_NAME[$NULL_LITERAL]
576  | REGISTER -> SIMPLE_NAME[$REGISTER]
577  | PARAM_LIST_OR_ID -> SIMPLE_NAME[$PARAM_LIST_OR_ID]
578  | PRIMITIVE_TYPE -> SIMPLE_NAME[$PRIMITIVE_TYPE]
579  | VOID_TYPE -> SIMPLE_NAME[$VOID_TYPE]
580  | ANNOTATION_VISIBILITY -> SIMPLE_NAME[$ANNOTATION_VISIBILITY]
581  | INSTRUCTION_FORMAT10t -> SIMPLE_NAME[$INSTRUCTION_FORMAT10t]
582  | INSTRUCTION_FORMAT10x -> SIMPLE_NAME[$INSTRUCTION_FORMAT10x]
583  | INSTRUCTION_FORMAT10x_ODEX -> SIMPLE_NAME[$INSTRUCTION_FORMAT10x_ODEX]
584  | INSTRUCTION_FORMAT11x -> SIMPLE_NAME[$INSTRUCTION_FORMAT11x]
585  | INSTRUCTION_FORMAT12x_OR_ID -> SIMPLE_NAME[$INSTRUCTION_FORMAT12x_OR_ID]
586  | INSTRUCTION_FORMAT21c_FIELD -> SIMPLE_NAME[$INSTRUCTION_FORMAT21c_FIELD]
587  | INSTRUCTION_FORMAT21c_FIELD_ODEX -> SIMPLE_NAME[$INSTRUCTION_FORMAT21c_FIELD_ODEX]
588  | INSTRUCTION_FORMAT21c_STRING -> SIMPLE_NAME[$INSTRUCTION_FORMAT21c_STRING]
589  | INSTRUCTION_FORMAT21c_TYPE -> SIMPLE_NAME[$INSTRUCTION_FORMAT21c_TYPE]
590  | INSTRUCTION_FORMAT21t -> SIMPLE_NAME[$INSTRUCTION_FORMAT21t]
591  | INSTRUCTION_FORMAT22c_FIELD -> SIMPLE_NAME[$INSTRUCTION_FORMAT22c_FIELD]
592  | INSTRUCTION_FORMAT22c_FIELD_ODEX -> SIMPLE_NAME[$INSTRUCTION_FORMAT22c_FIELD_ODEX]
593  | INSTRUCTION_FORMAT22c_TYPE -> SIMPLE_NAME[$INSTRUCTION_FORMAT22c_TYPE]
594  | INSTRUCTION_FORMAT22cs_FIELD -> SIMPLE_NAME[$INSTRUCTION_FORMAT22cs_FIELD]
595  | INSTRUCTION_FORMAT22s_OR_ID -> SIMPLE_NAME[$INSTRUCTION_FORMAT22s_OR_ID]
596  | INSTRUCTION_FORMAT22t -> SIMPLE_NAME[$INSTRUCTION_FORMAT22t]
597  | INSTRUCTION_FORMAT23x -> SIMPLE_NAME[$INSTRUCTION_FORMAT23x]
598  | INSTRUCTION_FORMAT31i_OR_ID -> SIMPLE_NAME[$INSTRUCTION_FORMAT31i_OR_ID]
599  | INSTRUCTION_FORMAT31t -> SIMPLE_NAME[$INSTRUCTION_FORMAT31t]
600  | INSTRUCTION_FORMAT35c_METHOD -> SIMPLE_NAME[$INSTRUCTION_FORMAT35c_METHOD]
601  | INSTRUCTION_FORMAT35c_METHOD_ODEX -> SIMPLE_NAME[$INSTRUCTION_FORMAT35c_METHOD_ODEX]
602  | INSTRUCTION_FORMAT35c_TYPE -> SIMPLE_NAME[$INSTRUCTION_FORMAT35c_TYPE]
603  | INSTRUCTION_FORMAT35mi_METHOD -> SIMPLE_NAME[$INSTRUCTION_FORMAT35mi_METHOD]
604  | INSTRUCTION_FORMAT35ms_METHOD -> SIMPLE_NAME[$INSTRUCTION_FORMAT35ms_METHOD]
605  | INSTRUCTION_FORMAT51l -> SIMPLE_NAME[$INSTRUCTION_FORMAT51l];
606
607method_name
608  : simple_name
609  | METHOD_NAME -> SIMPLE_NAME[$METHOD_NAME];
610
611method_prototype
612  : OPEN_PAREN param_list CLOSE_PAREN type_descriptor
613    -> ^(I_METHOD_PROTOTYPE[$start, "I_METHOD_PROTOTYPE"] ^(I_METHOD_RETURN_TYPE type_descriptor) param_list?);
614
615param_list
616  : PARAM_LIST -> { parseParamList((CommonToken)$PARAM_LIST) }
617  | PARAM_LIST_OR_ID -> { parseParamList((CommonToken)$PARAM_LIST_OR_ID) }
618  | nonvoid_type_descriptor*;
619
620type_descriptor
621  : VOID_TYPE
622  | PRIMITIVE_TYPE
623  | CLASS_DESCRIPTOR
624  | ARRAY_DESCRIPTOR;
625
626nonvoid_type_descriptor
627  : PRIMITIVE_TYPE
628  | CLASS_DESCRIPTOR
629  | ARRAY_DESCRIPTOR;
630
631reference_type_descriptor
632  : CLASS_DESCRIPTOR
633  | ARRAY_DESCRIPTOR;
634
635integer_literal
636  : POSITIVE_INTEGER_LITERAL -> INTEGER_LITERAL[$POSITIVE_INTEGER_LITERAL]
637  | NEGATIVE_INTEGER_LITERAL -> INTEGER_LITERAL[$NEGATIVE_INTEGER_LITERAL];
638
639float_literal
640  : FLOAT_LITERAL_OR_ID -> FLOAT_LITERAL[$FLOAT_LITERAL_OR_ID]
641  | FLOAT_LITERAL;
642
643double_literal
644  : DOUBLE_LITERAL_OR_ID -> DOUBLE_LITERAL[$DOUBLE_LITERAL_OR_ID]
645  | DOUBLE_LITERAL;
646
647literal
648  : LONG_LITERAL
649  | integer_literal
650  | SHORT_LITERAL
651  | BYTE_LITERAL
652  | float_literal
653  | double_literal
654  | CHAR_LITERAL
655  | STRING_LITERAL
656  | BOOL_LITERAL
657  | NULL_LITERAL
658  | array_literal
659  | subannotation
660  | type_field_method_literal
661  | enum_literal;
662
663parsed_integer_literal returns[int value]
664  : integer_literal { $value = LiteralTools.parseInt($integer_literal.text); };
665
666integral_literal
667  : LONG_LITERAL
668  | integer_literal
669  | SHORT_LITERAL
670  | CHAR_LITERAL
671  | BYTE_LITERAL;
672
673fixed_32bit_literal
674  : LONG_LITERAL
675  | integer_literal
676  | SHORT_LITERAL
677  | BYTE_LITERAL
678  | float_literal
679  | CHAR_LITERAL
680  | BOOL_LITERAL;
681
682fixed_literal returns[int size]
683  : integer_literal {$size = 4;}
684  | LONG_LITERAL {$size = 8;}
685  | SHORT_LITERAL {$size = 2;}
686  | BYTE_LITERAL {$size = 1;}
687  | float_literal {$size = 4;}
688  | double_literal {$size = 8;}
689  | CHAR_LITERAL {$size = 2;}
690  | BOOL_LITERAL {$size = 1;};
691
692array_literal
693  : OPEN_BRACE (literal (COMMA literal)* | ) CLOSE_BRACE
694    -> ^(I_ENCODED_ARRAY[$start, "I_ENCODED_ARRAY"] literal*);
695
696annotation_element
697  : simple_name EQUAL literal
698    -> ^(I_ANNOTATION_ELEMENT[$start, "I_ANNOTATION_ELEMENT"] simple_name literal);
699
700annotation
701  : ANNOTATION_DIRECTIVE ANNOTATION_VISIBILITY CLASS_DESCRIPTOR
702    annotation_element* END_ANNOTATION_DIRECTIVE
703    -> ^(I_ANNOTATION[$start, "I_ANNOTATION"] ANNOTATION_VISIBILITY ^(I_SUBANNOTATION[$start, "I_SUBANNOTATION"] CLASS_DESCRIPTOR annotation_element*));
704
705subannotation
706  : SUBANNOTATION_DIRECTIVE CLASS_DESCRIPTOR annotation_element* END_SUBANNOTATION_DIRECTIVE
707    -> ^(I_SUBANNOTATION[$start, "I_SUBANNOTATION"] CLASS_DESCRIPTOR annotation_element*);
708
709enum_literal
710  : ENUM_DIRECTIVE reference_type_descriptor ARROW simple_name COLON reference_type_descriptor
711  -> ^(I_ENCODED_ENUM reference_type_descriptor simple_name reference_type_descriptor);
712
713type_field_method_literal
714  : reference_type_descriptor
715    ( ARROW
716      ( simple_name COLON nonvoid_type_descriptor -> ^(I_ENCODED_FIELD reference_type_descriptor simple_name nonvoid_type_descriptor)
717      | method_name method_prototype -> ^(I_ENCODED_METHOD reference_type_descriptor method_name method_prototype)
718      )
719    | -> reference_type_descriptor
720    )
721  | PRIMITIVE_TYPE
722  | VOID_TYPE;
723
724fully_qualified_method
725  : reference_type_descriptor ARROW method_name method_prototype
726  -> reference_type_descriptor method_name method_prototype;
727
728fully_qualified_field
729  : reference_type_descriptor ARROW simple_name COLON nonvoid_type_descriptor
730  -> reference_type_descriptor simple_name nonvoid_type_descriptor;
731
732label
733  : COLON simple_name -> ^(I_LABEL[$COLON, "I_LABEL"] simple_name I_ADDRESS[$start, Integer.toString($method::currentAddress)]);
734
735label_ref
736  : COLON simple_name -> simple_name;
737
738register_list
739  : REGISTER (COMMA REGISTER)* -> ^(I_REGISTER_LIST[$start, "I_REGISTER_LIST"] REGISTER*)
740  | ->^(I_REGISTER_LIST[$start, "I_REGISTER_LIST"]);
741
742register_range
743  : (startreg=REGISTER (DOTDOT endreg=REGISTER)?)? -> ^(I_REGISTER_RANGE[$start, "I_REGISTER_RANGE"] $startreg? $endreg?);
744
745verification_error_reference
746  : CLASS_DESCRIPTOR | fully_qualified_field | fully_qualified_method;
747
748catch_directive
749  : CATCH_DIRECTIVE nonvoid_type_descriptor OPEN_BRACE from=label_ref DOTDOT to=label_ref CLOSE_BRACE using=label_ref
750    -> ^(I_CATCH[$start, "I_CATCH"] I_ADDRESS[$start, Integer.toString($method::currentAddress)] nonvoid_type_descriptor $from $to $using);
751
752catchall_directive
753  : CATCHALL_DIRECTIVE OPEN_BRACE from=label_ref DOTDOT to=label_ref CLOSE_BRACE using=label_ref
754    -> ^(I_CATCHALL[$start, "I_CATCHALL"] I_ADDRESS[$start, Integer.toString($method::currentAddress)] $from $to $using);
755
756/*When there are annotations immediately after a parameter definition, we don't know whether they are parameter annotations
757or method annotations until we determine if there is an .end parameter directive. In either case, we still "consume" and parse
758the annotations. If it turns out that they are parameter annotations, we include them in the I_PARAMETER AST. Otherwise, we
759add them to the $statements_and_directives::methodAnnotations list*/
760parameter_directive
761  @init {List<CommonTree> annotations = new ArrayList<CommonTree>();}
762  : PARAMETER_DIRECTIVE REGISTER (COMMA STRING_LITERAL)?
763    ({input.LA(1) == ANNOTATION_DIRECTIVE}? annotation {annotations.add($annotation.tree);})*
764
765    ( END_PARAMETER_DIRECTIVE
766      -> ^(I_PARAMETER[$start, "I_PARAMETER"] REGISTER STRING_LITERAL? ^(I_ANNOTATIONS annotation*))
767    | /*epsilon*/ {$statements_and_directives::methodAnnotations.addAll(annotations);}
768      -> ^(I_PARAMETER[$start, "I_PARAMETER"] REGISTER STRING_LITERAL? ^(I_ANNOTATIONS))
769    );
770
771ordered_debug_directive
772  : line_directive
773  | local_directive
774  | end_local_directive
775  | restart_local_directive
776  | prologue_directive
777  | epilogue_directive
778  | source_directive;
779
780line_directive
781  : LINE_DIRECTIVE integral_literal
782    -> ^(I_LINE[$start, "I_LINE"] integral_literal I_ADDRESS[$start, Integer.toString($method::currentAddress)]);
783
784local_directive
785  : LOCAL_DIRECTIVE REGISTER (COMMA (NULL_LITERAL | name=STRING_LITERAL) COLON (VOID_TYPE | nonvoid_type_descriptor)
786                              (COMMA signature=STRING_LITERAL)? )?
787    -> ^(I_LOCAL[$start, "I_LOCAL"] REGISTER NULL_LITERAL? $name? nonvoid_type_descriptor? $signature?
788         I_ADDRESS[$start, Integer.toString($method::currentAddress)]);
789
790end_local_directive
791  : END_LOCAL_DIRECTIVE REGISTER
792    -> ^(I_END_LOCAL[$start, "I_END_LOCAL"] REGISTER I_ADDRESS[$start, Integer.toString($method::currentAddress)]);
793
794restart_local_directive
795  : RESTART_LOCAL_DIRECTIVE REGISTER
796    -> ^(I_RESTART_LOCAL[$start, "I_RESTART_LOCAL"] REGISTER I_ADDRESS[$start, Integer.toString($method::currentAddress)]);
797
798prologue_directive
799  : PROLOGUE_DIRECTIVE
800    -> ^(I_PROLOGUE[$start, "I_PROLOGUE"] I_ADDRESS[$start, Integer.toString($method::currentAddress)]);
801
802epilogue_directive
803  : EPILOGUE_DIRECTIVE
804    -> ^(I_EPILOGUE[$start, "I_EPILOGUE"] I_ADDRESS[$start, Integer.toString($method::currentAddress)]);
805
806source_directive
807  : SOURCE_DIRECTIVE STRING_LITERAL?
808    -> ^(I_SOURCE[$start, "I_SOURCE"] STRING_LITERAL? I_ADDRESS[$start, Integer.toString($method::currentAddress)]);
809
810instruction_format12x
811  : INSTRUCTION_FORMAT12x
812  | INSTRUCTION_FORMAT12x_OR_ID -> INSTRUCTION_FORMAT12x[$INSTRUCTION_FORMAT12x_OR_ID];
813
814instruction_format22s
815  : INSTRUCTION_FORMAT22s
816  | INSTRUCTION_FORMAT22s_OR_ID -> INSTRUCTION_FORMAT22s[$INSTRUCTION_FORMAT22s_OR_ID];
817
818instruction_format31i
819  : INSTRUCTION_FORMAT31i
820  | INSTRUCTION_FORMAT31i_OR_ID -> INSTRUCTION_FORMAT31i[$INSTRUCTION_FORMAT31i_OR_ID];
821
822
823
824instruction returns [int size]
825  : insn_format10t { $size = $insn_format10t.size; }
826  | insn_format10x { $size = $insn_format10x.size; }
827  | insn_format10x_odex { $size = $insn_format10x_odex.size; }
828  | insn_format11n { $size = $insn_format11n.size; }
829  | insn_format11x { $size = $insn_format11x.size; }
830  | insn_format12x { $size = $insn_format12x.size; }
831  | insn_format20bc { $size = $insn_format20bc.size; }
832  | insn_format20t { $size = $insn_format20t.size; }
833  | insn_format21c_field { $size = $insn_format21c_field.size; }
834  | insn_format21c_field_odex { $size = $insn_format21c_field_odex.size; }
835  | insn_format21c_string { $size = $insn_format21c_string.size; }
836  | insn_format21c_type { $size = $insn_format21c_type.size; }
837  | insn_format21ih { $size = $insn_format21ih.size; }
838  | insn_format21lh { $size = $insn_format21lh.size; }
839  | insn_format21s { $size = $insn_format21s.size; }
840  | insn_format21t { $size = $insn_format21t.size; }
841  | insn_format22b { $size = $insn_format22b.size; }
842  | insn_format22c_field { $size = $insn_format22c_field.size; }
843  | insn_format22c_field_odex { $size = $insn_format22c_field_odex.size; }
844  | insn_format22c_type { $size = $insn_format22c_type.size; }
845  | insn_format22cs_field { $size = $insn_format22cs_field.size; }
846  | insn_format22s { $size = $insn_format22s.size; }
847  | insn_format22t { $size = $insn_format22t.size; }
848  | insn_format22x { $size = $insn_format22x.size; }
849  | insn_format23x { $size = $insn_format23x.size; }
850  | insn_format30t { $size = $insn_format30t.size; }
851  | insn_format31c { $size = $insn_format31c.size; }
852  | insn_format31i { $size = $insn_format31i.size; }
853  | insn_format31t { $size = $insn_format31t.size; }
854  | insn_format32x { $size = $insn_format32x.size; }
855  | insn_format35c_method { $size = $insn_format35c_method.size; }
856  | insn_format35c_type { $size = $insn_format35c_type.size; }
857  | insn_format35c_method_odex { $size = $insn_format35c_method_odex.size; }
858  | insn_format35mi_method { $size = $insn_format35mi_method.size; }
859  | insn_format35ms_method { $size = $insn_format35ms_method.size; }
860  | insn_format3rc_method { $size = $insn_format3rc_method.size; }
861  | insn_format3rc_method_odex { $size = $insn_format3rc_method_odex.size; }
862  | insn_format3rc_type { $size = $insn_format3rc_type.size; }
863  | insn_format3rmi_method { $size = $insn_format3rmi_method.size; }
864  | insn_format3rms_method { $size = $insn_format3rms_method.size; }
865  | insn_format51l { $size = $insn_format51l.size; }
866  | insn_array_data_directive { $size = $insn_array_data_directive.size; }
867  | insn_packed_switch_directive { $size = $insn_packed_switch_directive.size; }
868  | insn_sparse_switch_directive { $size = $insn_sparse_switch_directive.size; };
869
870insn_format10t returns [int size]
871  : //e.g. goto endloop:
872    //e.g. goto +3
873    INSTRUCTION_FORMAT10t label_ref {$size = Format.Format10t.size;}
874    -> ^(I_STATEMENT_FORMAT10t[$start, "I_STATEMENT_FORMAT10t"] INSTRUCTION_FORMAT10t label_ref);
875
876insn_format10x returns [int size]
877  : //e.g. return-void
878    INSTRUCTION_FORMAT10x {$size = Format.Format10x.size;}
879    -> ^(I_STATEMENT_FORMAT10x[$start, "I_STATEMENT_FORMAT10x"] INSTRUCTION_FORMAT10x);
880
881insn_format10x_odex returns [int size]
882  : //e.g. return-void-barrier
883    INSTRUCTION_FORMAT10x_ODEX {$size = Format.Format10x.size;}
884    {
885      throwOdexedInstructionException(input, $INSTRUCTION_FORMAT10x_ODEX.text);
886    };
887
888insn_format11n returns [int size]
889  : //e.g. const/4 v0, 5
890    INSTRUCTION_FORMAT11n REGISTER COMMA integral_literal {$size = Format.Format11n.size;}
891    -> ^(I_STATEMENT_FORMAT11n[$start, "I_STATEMENT_FORMAT11n"] INSTRUCTION_FORMAT11n REGISTER integral_literal);
892
893insn_format11x returns [int size]
894  : //e.g. move-result-object v1
895    INSTRUCTION_FORMAT11x REGISTER {$size = Format.Format11x.size;}
896    -> ^(I_STATEMENT_FORMAT11x[$start, "I_STATEMENT_FORMAT11x"] INSTRUCTION_FORMAT11x REGISTER);
897
898insn_format12x returns [int size]
899  : //e.g. move v1 v2
900    instruction_format12x REGISTER COMMA REGISTER {$size = Format.Format12x.size;}
901    -> ^(I_STATEMENT_FORMAT12x[$start, "I_STATEMENT_FORMAT12x"] instruction_format12x REGISTER REGISTER);
902
903insn_format20bc returns [int size]
904  : //e.g. throw-verification-error generic-error, Lsome/class;
905    INSTRUCTION_FORMAT20bc VERIFICATION_ERROR_TYPE COMMA verification_error_reference {$size += Format.Format20bc.size;}
906    {
907      if (!allowOdex || opcodes.getOpcodeByName($INSTRUCTION_FORMAT20bc.text) == null || apiLevel >= 14) {
908        throwOdexedInstructionException(input, $INSTRUCTION_FORMAT20bc.text);
909      }
910    }
911    -> ^(I_STATEMENT_FORMAT20bc INSTRUCTION_FORMAT20bc VERIFICATION_ERROR_TYPE verification_error_reference);
912
913insn_format20t returns [int size]
914  : //e.g. goto/16 endloop:
915    INSTRUCTION_FORMAT20t label_ref {$size = Format.Format20t.size;}
916    -> ^(I_STATEMENT_FORMAT20t[$start, "I_STATEMENT_FORMAT20t"] INSTRUCTION_FORMAT20t label_ref);
917
918insn_format21c_field returns [int size]
919  : //e.g. sget-object v0, java/lang/System/out LJava/io/PrintStream;
920    INSTRUCTION_FORMAT21c_FIELD REGISTER COMMA fully_qualified_field {$size = Format.Format21c.size;}
921    -> ^(I_STATEMENT_FORMAT21c_FIELD[$start, "I_STATEMENT_FORMAT21c_FIELD"] INSTRUCTION_FORMAT21c_FIELD REGISTER fully_qualified_field);
922
923insn_format21c_field_odex returns [int size]
924  : //e.g. sget-object-volatile v0, java/lang/System/out LJava/io/PrintStream;
925    INSTRUCTION_FORMAT21c_FIELD_ODEX REGISTER COMMA fully_qualified_field {$size = Format.Format21c.size;}
926    {
927      if (!allowOdex || opcodes.getOpcodeByName($INSTRUCTION_FORMAT21c_FIELD_ODEX.text) == null || apiLevel >= 14) {
928        throwOdexedInstructionException(input, $INSTRUCTION_FORMAT21c_FIELD_ODEX.text);
929      }
930    }
931    -> ^(I_STATEMENT_FORMAT21c_FIELD[$start, "I_STATEMENT_FORMAT21c_FIELD"] INSTRUCTION_FORMAT21c_FIELD_ODEX REGISTER fully_qualified_field);
932
933insn_format21c_string returns [int size]
934  : //e.g. const-string v1, "Hello World!"
935    INSTRUCTION_FORMAT21c_STRING REGISTER COMMA STRING_LITERAL {$size = Format.Format21c.size;}
936    -> ^(I_STATEMENT_FORMAT21c_STRING[$start, "I_STATEMENT_FORMAT21c_STRING"] INSTRUCTION_FORMAT21c_STRING REGISTER STRING_LITERAL);
937
938insn_format21c_type returns [int size]
939  : //e.g. const-class v2, Lorg/jf/HelloWorld2/HelloWorld2;
940    INSTRUCTION_FORMAT21c_TYPE REGISTER COMMA reference_type_descriptor {$size = Format.Format21c.size;}
941    -> ^(I_STATEMENT_FORMAT21c_TYPE[$start, "I_STATEMENT_FORMAT21c"] INSTRUCTION_FORMAT21c_TYPE REGISTER reference_type_descriptor);
942
943insn_format21ih returns [int size]
944  : //e.g. const/high16 v1, 1234
945    INSTRUCTION_FORMAT21ih REGISTER COMMA fixed_32bit_literal {$size = Format.Format21ih.size;}
946    -> ^(I_STATEMENT_FORMAT21ih[$start, "I_STATEMENT_FORMAT21ih"] INSTRUCTION_FORMAT21ih REGISTER fixed_32bit_literal);
947
948insn_format21lh returns [int size]
949  : //e.g. const-wide/high16 v1, 1234
950    INSTRUCTION_FORMAT21lh REGISTER COMMA fixed_32bit_literal {$size = Format.Format21lh.size;}
951    -> ^(I_STATEMENT_FORMAT21lh[$start, "I_STATEMENT_FORMAT21lh"] INSTRUCTION_FORMAT21lh REGISTER fixed_32bit_literal);
952
953insn_format21s returns [int size]
954  : //e.g. const/16 v1, 1234
955    INSTRUCTION_FORMAT21s REGISTER COMMA integral_literal {$size = Format.Format21s.size;}
956    -> ^(I_STATEMENT_FORMAT21s[$start, "I_STATEMENT_FORMAT21s"] INSTRUCTION_FORMAT21s REGISTER integral_literal);
957
958insn_format21t returns [int size]
959  : //e.g. if-eqz v0, endloop:
960    INSTRUCTION_FORMAT21t REGISTER COMMA (label_ref) {$size = Format.Format21t.size;}
961    -> ^(I_STATEMENT_FORMAT21t[$start, "I_STATEMENT_FORMAT21t"] INSTRUCTION_FORMAT21t REGISTER label_ref);
962
963insn_format22b returns [int size]
964  : //e.g. add-int v0, v1, 123
965    INSTRUCTION_FORMAT22b REGISTER COMMA REGISTER COMMA integral_literal {$size = Format.Format22b.size;}
966    -> ^(I_STATEMENT_FORMAT22b[$start, "I_STATEMENT_FORMAT22b"] INSTRUCTION_FORMAT22b REGISTER REGISTER integral_literal);
967
968insn_format22c_field returns [int size]
969  : //e.g. iput-object v1, v0 org/jf/HelloWorld2/HelloWorld2.helloWorld Ljava/lang/String;
970    INSTRUCTION_FORMAT22c_FIELD REGISTER COMMA REGISTER COMMA fully_qualified_field {$size = Format.Format22c.size;}
971    -> ^(I_STATEMENT_FORMAT22c_FIELD[$start, "I_STATEMENT_FORMAT22c_FIELD"] INSTRUCTION_FORMAT22c_FIELD REGISTER REGISTER fully_qualified_field);
972
973insn_format22c_field_odex returns [int size]
974  : //e.g. iput-object-volatile v1, v0 org/jf/HelloWorld2/HelloWorld2.helloWorld Ljava/lang/String;
975    INSTRUCTION_FORMAT22c_FIELD_ODEX REGISTER COMMA REGISTER COMMA fully_qualified_field {$size = Format.Format22c.size;}
976    {
977      if (!allowOdex || opcodes.getOpcodeByName($INSTRUCTION_FORMAT22c_FIELD_ODEX.text) == null || apiLevel >= 14) {
978        throwOdexedInstructionException(input, $INSTRUCTION_FORMAT22c_FIELD_ODEX.text);
979      }
980    }
981    -> ^(I_STATEMENT_FORMAT22c_FIELD[$start, "I_STATEMENT_FORMAT22c_FIELD"] INSTRUCTION_FORMAT22c_FIELD_ODEX REGISTER REGISTER fully_qualified_field);
982
983insn_format22c_type returns [int size]
984  : //e.g. instance-of v0, v1, Ljava/lang/String;
985    INSTRUCTION_FORMAT22c_TYPE REGISTER COMMA REGISTER COMMA nonvoid_type_descriptor {$size = Format.Format22c.size;}
986    -> ^(I_STATEMENT_FORMAT22c_TYPE[$start, "I_STATEMENT_FORMAT22c_TYPE"] INSTRUCTION_FORMAT22c_TYPE REGISTER REGISTER nonvoid_type_descriptor);
987
988insn_format22cs_field returns [int size]
989  : //e.g. iget-quick v0, v1, field@0xc
990    INSTRUCTION_FORMAT22cs_FIELD REGISTER COMMA REGISTER COMMA FIELD_OFFSET
991    {
992      throwOdexedInstructionException(input, $INSTRUCTION_FORMAT22cs_FIELD.text);
993    };
994
995insn_format22s returns [int size]
996  : //e.g. add-int/lit16 v0, v1, 12345
997    instruction_format22s REGISTER COMMA REGISTER COMMA integral_literal {$size = Format.Format22s.size;}
998    -> ^(I_STATEMENT_FORMAT22s[$start, "I_STATEMENT_FORMAT22s"] instruction_format22s REGISTER REGISTER integral_literal);
999
1000insn_format22t returns [int size]
1001  : //e.g. if-eq v0, v1, endloop:
1002    INSTRUCTION_FORMAT22t REGISTER COMMA REGISTER COMMA label_ref {$size = Format.Format22t.size;}
1003    -> ^(I_STATEMENT_FORMAT22t[$start, "I_STATEMENT_FFORMAT22t"] INSTRUCTION_FORMAT22t REGISTER REGISTER label_ref);
1004
1005insn_format22x returns [int size]
1006  : //e.g. move/from16 v1, v1234
1007    INSTRUCTION_FORMAT22x REGISTER COMMA REGISTER {$size = Format.Format22x.size;}
1008    -> ^(I_STATEMENT_FORMAT22x[$start, "I_STATEMENT_FORMAT22x"] INSTRUCTION_FORMAT22x REGISTER REGISTER);
1009
1010insn_format23x returns [int size]
1011  : //e.g. add-int v1, v2, v3
1012    INSTRUCTION_FORMAT23x REGISTER COMMA REGISTER COMMA REGISTER {$size = Format.Format23x.size;}
1013    -> ^(I_STATEMENT_FORMAT23x[$start, "I_STATEMENT_FORMAT23x"] INSTRUCTION_FORMAT23x REGISTER REGISTER REGISTER);
1014
1015insn_format30t returns [int size]
1016  : //e.g. goto/32 endloop:
1017    INSTRUCTION_FORMAT30t label_ref {$size = Format.Format30t.size;}
1018    -> ^(I_STATEMENT_FORMAT30t[$start, "I_STATEMENT_FORMAT30t"] INSTRUCTION_FORMAT30t label_ref);
1019
1020insn_format31c returns [int size]
1021  : //e.g. const-string/jumbo v1 "Hello World!"
1022    INSTRUCTION_FORMAT31c REGISTER COMMA STRING_LITERAL {$size = Format.Format31c.size;}
1023    ->^(I_STATEMENT_FORMAT31c[$start, "I_STATEMENT_FORMAT31c"] INSTRUCTION_FORMAT31c REGISTER STRING_LITERAL);
1024
1025insn_format31i returns [int size]
1026  : //e.g. const v0, 123456
1027    instruction_format31i REGISTER COMMA fixed_32bit_literal {$size = Format.Format31i.size;}
1028    -> ^(I_STATEMENT_FORMAT31i[$start, "I_STATEMENT_FORMAT31i"] instruction_format31i REGISTER fixed_32bit_literal);
1029
1030insn_format31t returns [int size]
1031  : //e.g. fill-array-data v0, ArrayData:
1032    INSTRUCTION_FORMAT31t REGISTER COMMA label_ref {$size = Format.Format31t.size;}
1033    {
1034      if ($INSTRUCTION_FORMAT31t.text.equals("packed-switch")) {
1035        CommonTree root = new CommonTree(new CommonToken(I_PACKED_SWITCH_DECLARATION, "I_PACKED_SWITCH_DECLARATION"));
1036        CommonTree address = new CommonTree(new CommonToken(I_ADDRESS, Integer.toString($method::currentAddress)));
1037        root.addChild(address);
1038        root.addChild($label_ref.tree.dupNode());
1039        $statements_and_directives::packedSwitchDeclarations.add(root);
1040      } else if ($INSTRUCTION_FORMAT31t.text.equals("sparse-switch")) {
1041        CommonTree root = new CommonTree(new CommonToken(I_SPARSE_SWITCH_DECLARATION, "I_SPARSE_SWITCH_DECLARATION"));
1042        CommonTree address = new CommonTree(new CommonToken(I_ADDRESS, Integer.toString($method::currentAddress)));
1043        root.addChild(address);
1044        root.addChild($label_ref.tree.dupNode());
1045        $statements_and_directives::sparseSwitchDeclarations.add(root);
1046      }
1047    }
1048    -> ^(I_STATEMENT_FORMAT31t[$start, "I_STATEMENT_FORMAT31t"] INSTRUCTION_FORMAT31t REGISTER label_ref);
1049
1050insn_format32x returns [int size]
1051  : //e.g. move/16 v4567, v1234
1052    INSTRUCTION_FORMAT32x REGISTER COMMA REGISTER {$size = Format.Format32x.size;}
1053    -> ^(I_STATEMENT_FORMAT32x[$start, "I_STATEMENT_FORMAT32x"] INSTRUCTION_FORMAT32x REGISTER REGISTER);
1054
1055insn_format35c_method returns [int size]
1056  : //e.g. invoke-virtual {v0,v1} java/io/PrintStream/print(Ljava/lang/Stream;)V
1057    INSTRUCTION_FORMAT35c_METHOD OPEN_BRACE register_list CLOSE_BRACE COMMA fully_qualified_method {$size = Format.Format35c.size;}
1058    -> ^(I_STATEMENT_FORMAT35c_METHOD[$start, "I_STATEMENT_FORMAT35c_METHOD"] INSTRUCTION_FORMAT35c_METHOD register_list fully_qualified_method);
1059
1060insn_format35c_type returns [int size]
1061  : //e.g. filled-new-array {v0,v1}, I
1062    INSTRUCTION_FORMAT35c_TYPE OPEN_BRACE register_list CLOSE_BRACE COMMA nonvoid_type_descriptor {$size = Format.Format35c.size;}
1063    -> ^(I_STATEMENT_FORMAT35c_TYPE[$start, "I_STATEMENT_FORMAT35c_TYPE"] INSTRUCTION_FORMAT35c_TYPE register_list nonvoid_type_descriptor);
1064
1065insn_format35c_method_odex returns [int size]
1066  : //e.g. invoke-direct {p0}, Ljava/lang/Object;-><init>()V
1067    INSTRUCTION_FORMAT35c_METHOD_ODEX OPEN_BRACE register_list CLOSE_BRACE COMMA fully_qualified_method
1068    {
1069      throwOdexedInstructionException(input, $INSTRUCTION_FORMAT35c_METHOD_ODEX.text);
1070    };
1071
1072insn_format35mi_method returns [int size]
1073  : //e.g. execute-inline {v0, v1}, inline@0x4
1074    INSTRUCTION_FORMAT35mi_METHOD OPEN_BRACE register_list CLOSE_BRACE COMMA INLINE_INDEX
1075    {
1076      throwOdexedInstructionException(input, $INSTRUCTION_FORMAT35mi_METHOD.text);
1077    };
1078
1079insn_format35ms_method returns [int size]
1080  : //e.g. invoke-virtual-quick {v0, v1}, vtable@0x4
1081    INSTRUCTION_FORMAT35ms_METHOD OPEN_BRACE register_list CLOSE_BRACE COMMA VTABLE_INDEX
1082    {
1083      throwOdexedInstructionException(input, $INSTRUCTION_FORMAT35ms_METHOD.text);
1084    };
1085
1086insn_format3rc_method returns [int size]
1087  : //e.g. invoke-virtual/range {v25..v26}, java/lang/StringBuilder/append(Ljava/lang/String;)Ljava/lang/StringBuilder;
1088    INSTRUCTION_FORMAT3rc_METHOD OPEN_BRACE register_range CLOSE_BRACE COMMA fully_qualified_method {$size = Format.Format3rc.size;}
1089    -> ^(I_STATEMENT_FORMAT3rc_METHOD[$start, "I_STATEMENT_FORMAT3rc_METHOD"] INSTRUCTION_FORMAT3rc_METHOD register_range fully_qualified_method);
1090
1091insn_format3rc_method_odex returns [int size]
1092  : //e.g. invoke-object-init/range {p0}, Ljava/lang/Object;-><init>()V
1093    INSTRUCTION_FORMAT3rc_METHOD_ODEX OPEN_BRACE register_list CLOSE_BRACE COMMA fully_qualified_method
1094    {
1095      throwOdexedInstructionException(input, $INSTRUCTION_FORMAT3rc_METHOD_ODEX.text);
1096    };
1097
1098insn_format3rc_type returns [int size]
1099  : //e.g. filled-new-array/range {v0..v6}, I
1100    INSTRUCTION_FORMAT3rc_TYPE OPEN_BRACE register_range CLOSE_BRACE COMMA nonvoid_type_descriptor {$size = Format.Format3rc.size;}
1101    -> ^(I_STATEMENT_FORMAT3rc_TYPE[$start, "I_STATEMENT_FORMAT3rc_TYPE"] INSTRUCTION_FORMAT3rc_TYPE register_range nonvoid_type_descriptor);
1102
1103insn_format3rmi_method returns [int size]
1104  : //e.g. execute-inline/range {v0 .. v10}, inline@0x14
1105    INSTRUCTION_FORMAT3rmi_METHOD OPEN_BRACE register_range CLOSE_BRACE COMMA INLINE_INDEX
1106    {
1107      throwOdexedInstructionException(input, $INSTRUCTION_FORMAT3rmi_METHOD.text);
1108    };
1109
1110insn_format3rms_method returns [int size]
1111  : //e.g. invoke-virtual-quick/range {v0 .. v10}, vtable@0x14
1112    INSTRUCTION_FORMAT3rms_METHOD OPEN_BRACE register_range CLOSE_BRACE COMMA VTABLE_INDEX
1113    {
1114      throwOdexedInstructionException(input, $INSTRUCTION_FORMAT3rms_METHOD.text);
1115    };
1116
1117insn_format51l returns [int size]
1118  : //e.g. const-wide v0, 5000000000L
1119    INSTRUCTION_FORMAT51l REGISTER COMMA fixed_literal {$size = Format.Format51l.size;}
1120    -> ^(I_STATEMENT_FORMAT51l[$start, "I_STATEMENT_FORMAT51l"] INSTRUCTION_FORMAT51l REGISTER fixed_literal);
1121
1122insn_array_data_directive returns [int size]
1123  : ARRAY_DATA_DIRECTIVE
1124    parsed_integer_literal
1125    {
1126        int elementWidth = $parsed_integer_literal.value;
1127        if (elementWidth != 4 && elementWidth != 8 && elementWidth != 1 && elementWidth != 2) {
1128            throw new SemanticException(input, $start, "Invalid element width: \%d. Must be 1, 2, 4 or 8", elementWidth);
1129        }
1130    }
1131
1132    (fixed_literal {$size+=elementWidth;})* END_ARRAY_DATA_DIRECTIVE
1133    {$size = (($size + 1) & ~1) + 8;}
1134
1135    -> ^(I_STATEMENT_ARRAY_DATA[$start, "I_STATEMENT_ARRAY_DATA"] ^(I_ARRAY_ELEMENT_SIZE parsed_integer_literal)
1136       ^(I_ARRAY_ELEMENTS fixed_literal*));
1137
1138insn_packed_switch_directive returns [int size]
1139    :   PACKED_SWITCH_DIRECTIVE
1140    fixed_32bit_literal
1141
1142    (switch_target += label_ref {$size+=4;})*
1143
1144    END_PACKED_SWITCH_DIRECTIVE {$size = $size + 8;}
1145
1146    -> ^(I_STATEMENT_PACKED_SWITCH[$start, "I_STATEMENT_PACKED_SWITCH"]
1147         ^(I_PACKED_SWITCH_START_KEY[$start, "I_PACKED_SWITCH_START_KEY"] fixed_32bit_literal)
1148         ^(I_PACKED_SWITCH_ELEMENTS[$start, "I_PACKED_SWITCH_ELEMENTS"]
1149          $switch_target*)
1150       );
1151
1152insn_sparse_switch_directive returns [int size]
1153  :   SPARSE_SWITCH_DIRECTIVE
1154    (fixed_32bit_literal ARROW switch_target += label_ref {$size += 8;})*
1155
1156    END_SPARSE_SWITCH_DIRECTIVE {$size = $size + 4;}
1157
1158    -> ^(I_STATEMENT_SPARSE_SWITCH[$start, "I_STATEMENT_SPARSE_SWITCH"]
1159       ^(I_SPARSE_SWITCH_ELEMENTS[$start, "I_SPARSE_SWITCH_ELEMENTS"] (fixed_32bit_literal $switch_target)*));