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