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
29tree grammar smaliTreeWalker;
30
31options {
32  tokenVocab=smaliParser;
33  ASTLabelType=CommonTree;
34}
35
36@header {
37package org.jf.smali;
38
39import com.google.common.collect.ImmutableSet;
40import com.google.common.collect.Iterables;
41import com.google.common.collect.Lists;
42import com.google.common.collect.Maps;
43import org.antlr.runtime.BitSet;
44import org.antlr.runtime.*;
45import org.antlr.runtime.tree.CommonTree;
46import org.antlr.runtime.tree.TreeNodeStream;
47import org.antlr.runtime.tree.TreeParser;
48import org.antlr.runtime.tree.TreeRuleReturnScope;
49import org.jf.dexlib2.*;
50import org.jf.dexlib2.builder.Label;
51import org.jf.dexlib2.builder.MethodImplementationBuilder;
52import org.jf.dexlib2.builder.SwitchLabelElement;
53import org.jf.dexlib2.builder.instruction.*;
54import org.jf.dexlib2.iface.Annotation;
55import org.jf.dexlib2.iface.AnnotationElement;
56import org.jf.dexlib2.iface.ClassDef;
57import org.jf.dexlib2.iface.MethodImplementation;
58import org.jf.dexlib2.iface.reference.FieldReference;
59import org.jf.dexlib2.iface.reference.MethodReference;
60import org.jf.dexlib2.iface.value.EncodedValue;
61import org.jf.dexlib2.immutable.ImmutableAnnotation;
62import org.jf.dexlib2.immutable.ImmutableAnnotationElement;
63import org.jf.dexlib2.immutable.reference.ImmutableFieldReference;
64import org.jf.dexlib2.immutable.reference.ImmutableMethodReference;
65import org.jf.dexlib2.immutable.reference.ImmutableReference;
66import org.jf.dexlib2.immutable.reference.ImmutableTypeReference;
67import org.jf.dexlib2.immutable.value.*;
68import org.jf.dexlib2.util.MethodUtil;
69import org.jf.dexlib2.writer.InstructionFactory;
70import org.jf.dexlib2.writer.builder.*;
71import org.jf.util.LinearSearch;
72
73import java.util.*;
74}
75
76@members {
77  public String classType;
78  private boolean verboseErrors = false;
79  private int apiLevel = 15;
80  private Opcodes opcodes = Opcodes.forApi(apiLevel);
81  private DexBuilder dexBuilder;
82
83  public void setDexBuilder(DexBuilder dexBuilder) {
84      this.dexBuilder = dexBuilder;
85  }
86
87  public void setApiLevel(int apiLevel, boolean experimental) {
88      this.opcodes = new Opcodes(apiLevel, experimental);
89      this.apiLevel = apiLevel;
90  }
91
92  public void setVerboseErrors(boolean verboseErrors) {
93    this.verboseErrors = verboseErrors;
94  }
95
96  private byte parseRegister_nibble(String register)
97      throws SemanticException {
98    int totalMethodRegisters = method_stack.peek().totalMethodRegisters;
99    int methodParameterRegisters = method_stack.peek().methodParameterRegisters;
100
101    //register should be in the format "v12"
102    int val = Byte.parseByte(register.substring(1));
103    if (register.charAt(0) == 'p') {
104      val = totalMethodRegisters - methodParameterRegisters + val;
105    }
106    if (val >= 2<<4) {
107      throw new SemanticException(input, "The maximum allowed register in this context is list of registers is v15");
108    }
109    //the parser wouldn't have accepted a negative register, i.e. v-1, so we don't have to check for val<0;
110    return (byte)val;
111  }
112
113  //return a short, because java's byte is signed
114  private short parseRegister_byte(String register)
115      throws SemanticException {
116    int totalMethodRegisters = method_stack.peek().totalMethodRegisters;
117    int methodParameterRegisters = method_stack.peek().methodParameterRegisters;
118    //register should be in the format "v123"
119    int val = Short.parseShort(register.substring(1));
120    if (register.charAt(0) == 'p') {
121      val = totalMethodRegisters - methodParameterRegisters + val;
122    }
123    if (val >= 2<<8) {
124      throw new SemanticException(input, "The maximum allowed register in this context is v255");
125    }
126    return (short)val;
127  }
128
129  //return an int because java's short is signed
130  private int parseRegister_short(String register)
131      throws SemanticException {
132    int totalMethodRegisters = method_stack.peek().totalMethodRegisters;
133    int methodParameterRegisters = method_stack.peek().methodParameterRegisters;
134    //register should be in the format "v12345"
135    int val = Integer.parseInt(register.substring(1));
136    if (register.charAt(0) == 'p') {
137      val = totalMethodRegisters - methodParameterRegisters + val;
138    }
139    if (val >= 2<<16) {
140      throw new SemanticException(input, "The maximum allowed register in this context is v65535");
141    }
142    //the parser wouldn't accept a negative register, i.e. v-1, so we don't have to check for val<0;
143    return val;
144  }
145
146  public String getErrorMessage(RecognitionException e, String[] tokenNames) {
147    if ( e instanceof SemanticException ) {
148      return e.getMessage();
149    } else {
150      return super.getErrorMessage(e, tokenNames);
151    }
152  }
153
154  public String getErrorHeader(RecognitionException e) {
155    return getSourceName()+"["+ e.line+","+e.charPositionInLine+"]";
156  }
157}
158
159smali_file returns[ClassDef classDef]
160  : ^(I_CLASS_DEF header methods fields annotations)
161  {
162    $classDef = dexBuilder.internClassDef($header.classType, $header.accessFlags, $header.superType,
163            $header.implementsList, $header.sourceSpec, $annotations.annotations, $fields.fields, $methods.methods);
164  };
165  catch [Exception ex] {
166    if (verboseErrors) {
167      ex.printStackTrace(System.err);
168    }
169    reportError(new SemanticException(input, ex));
170  }
171
172
173header returns[String classType, int accessFlags, String superType, List<String> implementsList, String sourceSpec]
174: class_spec super_spec? implements_list source_spec
175  {
176    classType = $class_spec.type;
177    $classType = classType;
178    $accessFlags = $class_spec.accessFlags;
179    $superType = $super_spec.type;
180    $implementsList = $implements_list.implementsList;
181    $sourceSpec = $source_spec.source;
182  };
183
184
185class_spec returns[String type, int accessFlags]
186  : CLASS_DESCRIPTOR access_list
187  {
188    $type = $CLASS_DESCRIPTOR.text;
189    $accessFlags = $access_list.value;
190  };
191
192super_spec returns[String type]
193  : ^(I_SUPER CLASS_DESCRIPTOR)
194  {
195    $type = $CLASS_DESCRIPTOR.text;
196  };
197
198
199implements_spec returns[String type]
200  : ^(I_IMPLEMENTS CLASS_DESCRIPTOR)
201  {
202    $type = $CLASS_DESCRIPTOR.text;
203  };
204
205implements_list returns[List<String> implementsList]
206@init { List<String> typeList; }
207  : {typeList = Lists.newArrayList();}
208    (implements_spec {typeList.add($implements_spec.type);} )*
209  {
210    if (typeList.size() > 0) {
211      $implementsList = typeList;
212    } else {
213      $implementsList = null;
214    }
215  };
216
217source_spec returns[String source]
218  : {$source = null;}
219    ^(I_SOURCE string_literal {$source = $string_literal.value;})
220  | /*epsilon*/;
221
222access_list returns [int value]
223  @init
224  {
225    $value = 0;
226  }
227  : ^(I_ACCESS_LIST
228      (
229        ACCESS_SPEC
230        {
231          $value |= AccessFlags.getAccessFlag($ACCESS_SPEC.getText()).getValue();
232        }
233      )*);
234
235
236fields returns[List<BuilderField> fields]
237  @init {$fields = Lists.newArrayList();}
238  : ^(I_FIELDS
239      (field
240      {
241        $fields.add($field.field);
242      })*);
243
244methods returns[List<BuilderMethod> methods]
245  @init {$methods = Lists.newArrayList();}
246  : ^(I_METHODS
247      (method
248      {
249        $methods.add($method.ret);
250      })*);
251
252field returns [BuilderField field]
253  :^(I_FIELD SIMPLE_NAME access_list ^(I_FIELD_TYPE nonvoid_type_descriptor) field_initial_value annotations?)
254  {
255    int accessFlags = $access_list.value;
256
257
258    if (!AccessFlags.STATIC.isSet(accessFlags) && $field_initial_value.encodedValue != null) {
259        throw new SemanticException(input, "Initial field values can only be specified for static fields.");
260    }
261
262    $field = dexBuilder.internField(classType, $SIMPLE_NAME.text, $nonvoid_type_descriptor.type, $access_list.value,
263            $field_initial_value.encodedValue, $annotations.annotations);
264  };
265
266
267field_initial_value returns[EncodedValue encodedValue]
268  : ^(I_FIELD_INITIAL_VALUE literal) {$encodedValue = $literal.encodedValue;}
269  | /*epsilon*/;
270
271literal returns[EncodedValue encodedValue]
272  : integer_literal { $encodedValue = new ImmutableIntEncodedValue($integer_literal.value); }
273  | long_literal { $encodedValue = new ImmutableLongEncodedValue($long_literal.value); }
274  | short_literal { $encodedValue = new ImmutableShortEncodedValue($short_literal.value); }
275  | byte_literal { $encodedValue = new ImmutableByteEncodedValue($byte_literal.value); }
276  | float_literal { $encodedValue = new ImmutableFloatEncodedValue($float_literal.value); }
277  | double_literal { $encodedValue = new ImmutableDoubleEncodedValue($double_literal.value); }
278  | char_literal { $encodedValue = new ImmutableCharEncodedValue($char_literal.value); }
279  | string_literal { $encodedValue = new ImmutableStringEncodedValue($string_literal.value); }
280  | bool_literal { $encodedValue = ImmutableBooleanEncodedValue.forBoolean($bool_literal.value); }
281  | NULL_LITERAL { $encodedValue = ImmutableNullEncodedValue.INSTANCE; }
282  | type_descriptor { $encodedValue = new ImmutableTypeEncodedValue($type_descriptor.type); }
283  | array_literal { $encodedValue = new ImmutableArrayEncodedValue($array_literal.elements); }
284  | subannotation { $encodedValue = new ImmutableAnnotationEncodedValue($subannotation.annotationType, $subannotation.elements); }
285  | field_literal { $encodedValue = new ImmutableFieldEncodedValue($field_literal.value); }
286  | method_literal { $encodedValue = new ImmutableMethodEncodedValue($method_literal.value); }
287  | enum_literal { $encodedValue = new ImmutableEnumEncodedValue($enum_literal.value); };
288
289//everything but string
290fixed_64bit_literal_number returns[Number value]
291  : integer_literal { $value = $integer_literal.value; }
292  | long_literal { $value = $long_literal.value; }
293  | short_literal { $value = $short_literal.value; }
294  | byte_literal { $value = $byte_literal.value; }
295  | float_literal { $value = Float.floatToRawIntBits($float_literal.value); }
296  | double_literal { $value = Double.doubleToRawLongBits($double_literal.value); }
297  | char_literal { $value = (int)$char_literal.value; }
298  | bool_literal { $value = $bool_literal.value?1:0; };
299
300fixed_64bit_literal returns[long value]
301  : integer_literal { $value = $integer_literal.value; }
302  | long_literal { $value = $long_literal.value; }
303  | short_literal { $value = $short_literal.value; }
304  | byte_literal { $value = $byte_literal.value; }
305  | float_literal { $value = Float.floatToRawIntBits($float_literal.value); }
306  | double_literal { $value = Double.doubleToRawLongBits($double_literal.value); }
307  | char_literal { $value = $char_literal.value; }
308  | bool_literal { $value = $bool_literal.value?1:0; };
309
310//everything but string and double
311//long is allowed, but it must fit into an int
312fixed_32bit_literal returns[int value]
313  : integer_literal { $value = $integer_literal.value; }
314  | long_literal { LiteralTools.checkInt($long_literal.value); $value = (int)$long_literal.value; }
315  | short_literal { $value = $short_literal.value; }
316  | byte_literal { $value = $byte_literal.value; }
317  | float_literal { $value = Float.floatToRawIntBits($float_literal.value); }
318  | char_literal { $value = $char_literal.value; }
319  | bool_literal { $value = $bool_literal.value?1:0; };
320
321array_elements returns[List<Number> elements]
322  : {$elements = Lists.newArrayList();}
323    ^(I_ARRAY_ELEMENTS
324      (fixed_64bit_literal_number
325      {
326        $elements.add($fixed_64bit_literal_number.value);
327      })*);
328
329packed_switch_elements returns[List<Label> elements]
330  @init {$elements = Lists.newArrayList();}
331  :
332    ^(I_PACKED_SWITCH_ELEMENTS
333      (label_ref { $elements.add($label_ref.label); })*
334    );
335
336sparse_switch_elements returns[List<SwitchLabelElement> elements]
337  @init {$elements = Lists.newArrayList();}
338  :
339    ^(I_SPARSE_SWITCH_ELEMENTS
340       (fixed_32bit_literal label_ref
341       {
342         $elements.add(new SwitchLabelElement($fixed_32bit_literal.value, $label_ref.label));
343       })*
344    );
345
346method returns[BuilderMethod ret]
347  scope
348  {
349    boolean isStatic;
350    int totalMethodRegisters;
351    int methodParameterRegisters;
352    MethodImplementationBuilder methodBuilder;
353  }
354  @init
355  {
356    $method::totalMethodRegisters = 0;
357    $method::methodParameterRegisters = 0;
358    int accessFlags = 0;
359    $method::isStatic = false;
360  }
361  :
362    ^(I_METHOD
363      method_name_and_prototype
364      access_list
365      {
366        accessFlags = $access_list.value;
367        $method::isStatic = AccessFlags.STATIC.isSet(accessFlags);
368        $method::methodParameterRegisters =
369                MethodUtil.getParameterRegisterCount($method_name_and_prototype.parameters, $method::isStatic);
370      }
371      (
372        (registers_directive
373        {
374          if ($registers_directive.isLocalsDirective) {
375            $method::totalMethodRegisters = $registers_directive.registers + $method::methodParameterRegisters;
376          } else {
377            $method::totalMethodRegisters = $registers_directive.registers;
378          }
379
380          $method::methodBuilder = new MethodImplementationBuilder($method::totalMethodRegisters);
381
382        })
383        |
384        /* epsilon */
385        {
386          $method::methodBuilder = new MethodImplementationBuilder(0);
387        }
388      )
389      ordered_method_items
390      catches
391      parameters[$method_name_and_prototype.parameters]
392      annotations
393    )
394  {
395    MethodImplementation methodImplementation = null;
396    List<BuilderTryBlock> tryBlocks = $catches.tryBlocks;
397
398    boolean isAbstract = false;
399    boolean isNative = false;
400
401    if ((accessFlags & AccessFlags.ABSTRACT.getValue()) != 0) {
402      isAbstract = true;
403    } else if ((accessFlags & AccessFlags.NATIVE.getValue()) != 0) {
404      isNative = true;
405    }
406
407    methodImplementation = $method::methodBuilder.getMethodImplementation();
408
409    if (Iterables.isEmpty(methodImplementation.getInstructions())) {
410      if (!isAbstract && !isNative) {
411        throw new SemanticException(input, $I_METHOD, "A non-abstract/non-native method must have at least 1 instruction");
412      }
413
414      String methodType;
415      if (isAbstract) {
416        methodType = "an abstract";
417      } else {
418        methodType = "a native";
419      }
420
421      if ($registers_directive.start != null) {
422        if ($registers_directive.isLocalsDirective) {
423          throw new SemanticException(input, $registers_directive.start, "A .locals directive is not valid in \%s method", methodType);
424        } else {
425          throw new SemanticException(input, $registers_directive.start, "A .registers directive is not valid in \%s method", methodType);
426        }
427      }
428
429      if (methodImplementation.getTryBlocks().size() > 0) {
430        throw new SemanticException(input, $I_METHOD, "try/catch blocks cannot be present in \%s method", methodType);
431      }
432
433      if (!Iterables.isEmpty(methodImplementation.getDebugItems())) {
434        throw new SemanticException(input, $I_METHOD, "debug directives cannot be present in \%s method", methodType);
435      }
436
437      methodImplementation = null;
438    } else {
439      if (isAbstract) {
440        throw new SemanticException(input, $I_METHOD, "An abstract method cannot have any instructions");
441      }
442      if (isNative) {
443        throw new SemanticException(input, $I_METHOD, "A native method cannot have any instructions");
444      }
445
446      if ($registers_directive.start == null) {
447        throw new SemanticException(input, $I_METHOD, "A .registers or .locals directive must be present for a non-abstract/non-final method");
448      }
449
450      if ($method::totalMethodRegisters < $method::methodParameterRegisters) {
451        throw new SemanticException(input, $registers_directive.start, "This method requires at least " +
452                Integer.toString($method::methodParameterRegisters) +
453                " registers, for the method parameters");
454      }
455    }
456
457    $ret = dexBuilder.internMethod(
458            classType,
459            $method_name_and_prototype.name,
460            $method_name_and_prototype.parameters,
461            $method_name_and_prototype.returnType,
462            accessFlags,
463            $annotations.annotations,
464            methodImplementation);
465  };
466
467method_prototype returns[List<String> parameters, String returnType]
468  : ^(I_METHOD_PROTOTYPE ^(I_METHOD_RETURN_TYPE type_descriptor) method_type_list)
469  {
470    $returnType = $type_descriptor.type;
471    $parameters = $method_type_list.types;
472  };
473
474method_name_and_prototype returns[String name, List<SmaliMethodParameter> parameters, String returnType]
475  : SIMPLE_NAME method_prototype
476  {
477    $name = $SIMPLE_NAME.text;
478    $parameters = Lists.newArrayList();
479
480    int paramRegister = 0;
481    for (String type: $method_prototype.parameters) {
482        $parameters.add(new SmaliMethodParameter(paramRegister++, type));
483        char c = type.charAt(0);
484        if (c == 'D' || c == 'J') {
485            paramRegister++;
486        }
487    }
488    $returnType = $method_prototype.returnType;
489  };
490
491method_type_list returns[List<String> types]
492  @init
493  {
494    $types = Lists.newArrayList();
495  }
496  : (
497      nonvoid_type_descriptor
498      {
499        $types.add($nonvoid_type_descriptor.type);
500      }
501    )*;
502
503
504method_reference returns[ImmutableMethodReference methodReference]
505  : reference_type_descriptor? SIMPLE_NAME method_prototype
506  {
507    String type;
508    if ($reference_type_descriptor.type == null) {
509        type = classType;
510    } else {
511        type = $reference_type_descriptor.type;
512    }
513    $methodReference = new ImmutableMethodReference(type, $SIMPLE_NAME.text,
514             $method_prototype.parameters, $method_prototype.returnType);
515  };
516
517field_reference returns[ImmutableFieldReference fieldReference]
518  : reference_type_descriptor? SIMPLE_NAME nonvoid_type_descriptor
519  {
520    String type;
521    if ($reference_type_descriptor.type == null) {
522        type = classType;
523    } else {
524        type = $reference_type_descriptor.type;
525    }
526    $fieldReference = new ImmutableFieldReference(type, $SIMPLE_NAME.text,
527            $nonvoid_type_descriptor.type);
528  };
529
530registers_directive returns[boolean isLocalsDirective, int registers]
531  : {$registers = 0;}
532    ^(( I_REGISTERS {$isLocalsDirective = false;}
533      | I_LOCALS {$isLocalsDirective = true;}
534      )
535      short_integral_literal {$registers = $short_integral_literal.value & 0xFFFF;}
536     );
537
538label_def
539  : ^(I_LABEL SIMPLE_NAME)
540  {
541    $method::methodBuilder.addLabel($SIMPLE_NAME.text);
542  };
543
544catches returns[List<BuilderTryBlock> tryBlocks]
545  @init {tryBlocks = Lists.newArrayList();}
546  : ^(I_CATCHES catch_directive* catchall_directive*);
547
548catch_directive
549  : ^(I_CATCH nonvoid_type_descriptor from=label_ref to=label_ref using=label_ref)
550  {
551    $method::methodBuilder.addCatch(dexBuilder.internTypeReference($nonvoid_type_descriptor.type),
552        $from.label, $to.label, $using.label);
553  };
554
555catchall_directive
556  : ^(I_CATCHALL from=label_ref to=label_ref using=label_ref)
557  {
558    $method::methodBuilder.addCatch($from.label, $to.label, $using.label);
559  };
560
561parameters[List<SmaliMethodParameter> parameters]
562  : ^(I_PARAMETERS (parameter[parameters])*);
563
564parameter[List<SmaliMethodParameter> parameters]
565  : ^(I_PARAMETER REGISTER string_literal? annotations)
566    {
567        final int registerNumber = parseRegister_short($REGISTER.text);
568        int totalMethodRegisters = $method::totalMethodRegisters;
569        int methodParameterRegisters = $method::methodParameterRegisters;
570
571        if (registerNumber >= totalMethodRegisters) {
572            throw new SemanticException(input, $I_PARAMETER, "Register \%s is larger than the maximum register v\%d " +
573                    "for this method", $REGISTER.text, totalMethodRegisters-1);
574        }
575        final int indexGuess = registerNumber - (totalMethodRegisters - methodParameterRegisters) - ($method::isStatic?0:1);
576
577        if (indexGuess < 0) {
578            throw new SemanticException(input, $I_PARAMETER, "Register \%s is not a parameter register.",
579                    $REGISTER.text);
580        }
581
582        int parameterIndex = LinearSearch.linearSearch(parameters, SmaliMethodParameter.COMPARATOR,
583            new WithRegister() { public int getRegister() { return indexGuess; } },
584                indexGuess);
585
586        if (parameterIndex < 0) {
587            throw new SemanticException(input, $I_PARAMETER, "Register \%s is the second half of a wide parameter.",
588                                $REGISTER.text);
589        }
590
591        SmaliMethodParameter methodParameter = parameters.get(parameterIndex);
592        methodParameter.name = $string_literal.value;
593        if ($annotations.annotations != null && $annotations.annotations.size() > 0) {
594            methodParameter.annotations = $annotations.annotations;
595        }
596    };
597
598debug_directive
599  : line
600  | local
601  | end_local
602  | restart_local
603  | prologue
604  | epilogue
605  | source;
606
607line
608  : ^(I_LINE integral_literal)
609    {
610        $method::methodBuilder.addLineNumber($integral_literal.value);
611    };
612
613local
614  : ^(I_LOCAL REGISTER ((NULL_LITERAL | name=string_literal) nonvoid_type_descriptor? signature=string_literal?)?)
615    {
616      int registerNumber = parseRegister_short($REGISTER.text);
617      $method::methodBuilder.addStartLocal(registerNumber,
618              dexBuilder.internNullableStringReference($name.value),
619              dexBuilder.internNullableTypeReference($nonvoid_type_descriptor.type),
620              dexBuilder.internNullableStringReference($signature.value));
621    };
622
623end_local
624  : ^(I_END_LOCAL REGISTER)
625    {
626      int registerNumber = parseRegister_short($REGISTER.text);
627      $method::methodBuilder.addEndLocal(registerNumber);
628    };
629
630restart_local
631  : ^(I_RESTART_LOCAL REGISTER)
632    {
633      int registerNumber = parseRegister_short($REGISTER.text);
634      $method::methodBuilder.addRestartLocal(registerNumber);
635    };
636
637prologue
638  : I_PROLOGUE
639    {
640      $method::methodBuilder.addPrologue();
641    };
642
643epilogue
644  : I_EPILOGUE
645    {
646      $method::methodBuilder.addEpilogue();
647    };
648
649source
650  : ^(I_SOURCE string_literal?)
651    {
652      $method::methodBuilder.addSetSourceFile(dexBuilder.internNullableStringReference($string_literal.value));
653    };
654
655ordered_method_items
656  : ^(I_ORDERED_METHOD_ITEMS (label_def | instruction | debug_directive)*);
657
658label_ref returns[Label label]
659  : SIMPLE_NAME { $label = $method::methodBuilder.getLabel($SIMPLE_NAME.text); };
660
661register_list returns[byte[\] registers, byte registerCount]
662  @init
663  {
664    $registers = new byte[5];
665    $registerCount = 0;
666  }
667  : ^(I_REGISTER_LIST
668      (REGISTER
669      {
670        if ($registerCount == 5) {
671          throw new SemanticException(input, $I_REGISTER_LIST, "A list of registers can only have a maximum of 5 " +
672                  "registers. Use the <op>/range alternate opcode instead.");
673        }
674        $registers[$registerCount++] = parseRegister_nibble($REGISTER.text);
675      })*);
676
677register_list4 returns[byte[\] registers, byte registerCount]
678  @init
679  {
680    $registers = new byte[4];
681    $registerCount = 0;
682  }
683  : ^(I_REGISTER_LIST
684      (REGISTER
685      {
686        if ($registerCount == 4) {
687          throw new SemanticException(input, $I_REGISTER_LIST, "A list4 of registers can only have a maximum of 4 " +
688                  "registers. Use the <op>/range alternate opcode instead.");
689        }
690        $registers[$registerCount++] = parseRegister_nibble($REGISTER.text);
691      })*);
692
693register_range returns[int startRegister, int endRegister]
694  : ^(I_REGISTER_RANGE (startReg=REGISTER endReg=REGISTER?)?)
695    {
696        if ($startReg == null) {
697            $startRegister = 0;
698            $endRegister = -1;
699        } else {
700                $startRegister  = parseRegister_short($startReg.text);
701                if ($endReg == null) {
702                    $endRegister = $startRegister;
703                } else {
704                    $endRegister = parseRegister_short($endReg.text);
705                }
706
707                int registerCount = $endRegister-$startRegister+1;
708                if (registerCount < 1) {
709                    throw new SemanticException(input, $I_REGISTER_RANGE, "A register range must have the lower register listed first");
710                }
711            }
712    };
713
714verification_error_reference returns[ImmutableReference reference]
715  : CLASS_DESCRIPTOR
716  {
717    $reference = new ImmutableTypeReference($CLASS_DESCRIPTOR.text);
718  }
719  | field_reference
720  {
721    $reference = $field_reference.fieldReference;
722  }
723  | method_reference
724  {
725    $reference = $method_reference.methodReference;
726  };
727
728verification_error_type returns[int verificationError]
729  : VERIFICATION_ERROR_TYPE
730  {
731    $verificationError = VerificationError.getVerificationError($VERIFICATION_ERROR_TYPE.text);
732  };
733
734instruction
735  : insn_format10t
736  | insn_format10x
737  | insn_format11n
738  | insn_format11x
739  | insn_format12x
740  | insn_format20bc
741  | insn_format20t
742  | insn_format21c_field
743  | insn_format21c_string
744  | insn_format21c_type
745  | insn_format21c_lambda
746  | insn_format21c_method
747  | insn_format21ih
748  | insn_format21lh
749  | insn_format21s
750  | insn_format21t
751  | insn_format22b
752  | insn_format22c_field
753  | insn_format22c_type
754  | insn_format22c_string
755  | insn_format22s
756  | insn_format22t
757  | insn_format22x
758  | insn_format23x
759  | insn_format25x
760  | insn_format30t
761  | insn_format31c
762  | insn_format31i
763  | insn_format31t
764  | insn_format32x
765  | insn_format35c_method
766  | insn_format35c_type
767  | insn_format3rc_method
768  | insn_format3rc_type
769  | insn_format51l_type
770  | insn_array_data_directive
771  | insn_packed_switch_directive
772  | insn_sparse_switch_directive;
773  catch [Exception ex] {
774    reportError(new SemanticException(input, $start, ex.getMessage()));
775    recover(input, null);
776  }
777
778insn_format10t
779  : //e.g. goto endloop:
780    ^(I_STATEMENT_FORMAT10t INSTRUCTION_FORMAT10t label_ref)
781    {
782      Opcode opcode = opcodes.getOpcodeByName($INSTRUCTION_FORMAT10t.text);
783      $method::methodBuilder.addInstruction(new BuilderInstruction10t(opcode, $label_ref.label));
784    };
785
786insn_format10x
787  : //e.g. return
788    ^(I_STATEMENT_FORMAT10x INSTRUCTION_FORMAT10x)
789    {
790      Opcode opcode = opcodes.getOpcodeByName($INSTRUCTION_FORMAT10x.text);
791      $method::methodBuilder.addInstruction(new BuilderInstruction10x(opcode));
792    };
793
794insn_format11n
795  : //e.g. const/4 v0, 5
796    ^(I_STATEMENT_FORMAT11n INSTRUCTION_FORMAT11n REGISTER short_integral_literal)
797    {
798      Opcode opcode = opcodes.getOpcodeByName($INSTRUCTION_FORMAT11n.text);
799      byte regA = parseRegister_nibble($REGISTER.text);
800
801      short litB = $short_integral_literal.value;
802      LiteralTools.checkNibble(litB);
803
804      $method::methodBuilder.addInstruction(new BuilderInstruction11n(opcode, regA, litB));
805    };
806
807insn_format11x
808  : //e.g. move-result-object v1
809    ^(I_STATEMENT_FORMAT11x INSTRUCTION_FORMAT11x REGISTER)
810    {
811      Opcode opcode = opcodes.getOpcodeByName($INSTRUCTION_FORMAT11x.text);
812      short regA = parseRegister_byte($REGISTER.text);
813
814      $method::methodBuilder.addInstruction(new BuilderInstruction11x(opcode, regA));
815    };
816
817insn_format12x
818  : //e.g. move v1 v2
819    ^(I_STATEMENT_FORMAT12x INSTRUCTION_FORMAT12x registerA=REGISTER registerB=REGISTER)
820    {
821      Opcode opcode = opcodes.getOpcodeByName($INSTRUCTION_FORMAT12x.text);
822      byte regA = parseRegister_nibble($registerA.text);
823      byte regB = parseRegister_nibble($registerB.text);
824
825      $method::methodBuilder.addInstruction(new BuilderInstruction12x(opcode, regA, regB));
826    };
827
828insn_format20bc
829  : //e.g. throw-verification-error generic-error, Lsome/class;
830    ^(I_STATEMENT_FORMAT20bc INSTRUCTION_FORMAT20bc verification_error_type verification_error_reference)
831    {
832      Opcode opcode = opcodes.getOpcodeByName($INSTRUCTION_FORMAT20bc.text);
833
834      int verificationError = $verification_error_type.verificationError;
835      ImmutableReference referencedItem = $verification_error_reference.reference;
836
837      $method::methodBuilder.addInstruction(new BuilderInstruction20bc(opcode, verificationError,
838              dexBuilder.internReference(referencedItem)));
839    };
840
841insn_format20t
842  : //e.g. goto/16 endloop:
843    ^(I_STATEMENT_FORMAT20t INSTRUCTION_FORMAT20t label_ref)
844    {
845      Opcode opcode = opcodes.getOpcodeByName($INSTRUCTION_FORMAT20t.text);
846      $method::methodBuilder.addInstruction(new BuilderInstruction20t(opcode, $label_ref.label));
847    };
848
849insn_format21c_field
850  : //e.g. sget_object v0, java/lang/System/out LJava/io/PrintStream;
851    ^(I_STATEMENT_FORMAT21c_FIELD inst=(INSTRUCTION_FORMAT21c_FIELD | INSTRUCTION_FORMAT21c_FIELD_ODEX) REGISTER field_reference)
852    {
853      Opcode opcode = opcodes.getOpcodeByName($inst.text);
854      short regA = parseRegister_byte($REGISTER.text);
855
856      ImmutableFieldReference fieldReference = $field_reference.fieldReference;
857
858      $method::methodBuilder.addInstruction(new BuilderInstruction21c(opcode, regA,
859              dexBuilder.internFieldReference(fieldReference)));
860    };
861
862insn_format21c_string
863  : //e.g. const-string v1, "Hello World!"
864    ^(I_STATEMENT_FORMAT21c_STRING INSTRUCTION_FORMAT21c_STRING REGISTER string_literal)
865    {
866      Opcode opcode = opcodes.getOpcodeByName($INSTRUCTION_FORMAT21c_STRING.text);
867      short regA = parseRegister_byte($REGISTER.text);
868
869      $method::methodBuilder.addInstruction(new BuilderInstruction21c(opcode, regA,
870              dexBuilder.internStringReference($string_literal.value)));
871    };
872
873insn_format21c_type
874  : //e.g. const-class v2, org/jf/HelloWorld2/HelloWorld2
875    ^(I_STATEMENT_FORMAT21c_TYPE INSTRUCTION_FORMAT21c_TYPE REGISTER nonvoid_type_descriptor)
876    {
877      Opcode opcode = opcodes.getOpcodeByName($INSTRUCTION_FORMAT21c_TYPE.text);
878      short regA = parseRegister_byte($REGISTER.text);
879
880      $method::methodBuilder.addInstruction(new BuilderInstruction21c(opcode, regA,
881              dexBuilder.internTypeReference($nonvoid_type_descriptor.type)));
882    };
883
884insn_format21c_lambda
885  : //e.g. capture-variable v1, "foobar"
886    ^(I_STATEMENT_FORMAT21c_LAMBDA INSTRUCTION_FORMAT21c_LAMBDA REGISTER string_literal)
887    {
888      Opcode opcode = opcodes.getOpcodeByName($INSTRUCTION_FORMAT21c_LAMBDA.text);
889      short regA = parseRegister_byte($REGISTER.text);
890
891      $method::methodBuilder.addInstruction(new BuilderInstruction21c(opcode, regA,
892              dexBuilder.internStringReference($string_literal.value)));
893    };
894
895insn_format21c_method
896  : //e.g. create-lambda v1, java/io/PrintStream/print(Ljava/lang/Stream;)V
897    ^(I_STATEMENT_FORMAT21c_METHOD INSTRUCTION_FORMAT21c_METHOD REGISTER method_reference)
898    {
899      Opcode opcode = opcodes.getOpcodeByName($INSTRUCTION_FORMAT21c_METHOD.text);
900      short regA = parseRegister_byte($REGISTER.text);
901
902      ImmutableMethodReference methodReference = $method_reference.methodReference;
903
904      $method::methodBuilder.addInstruction(new BuilderInstruction21c(opcode, regA,
905              dexBuilder.internMethodReference(methodReference)));
906    };
907
908insn_format21ih
909  : //e.g. const/high16 v1, 1234
910    ^(I_STATEMENT_FORMAT21ih INSTRUCTION_FORMAT21ih REGISTER fixed_32bit_literal)
911    {
912      Opcode opcode = opcodes.getOpcodeByName($INSTRUCTION_FORMAT21ih.text);
913      short regA = parseRegister_byte($REGISTER.text);
914
915      int litB = $fixed_32bit_literal.value;
916
917      $method::methodBuilder.addInstruction(new BuilderInstruction21ih(opcode, regA, litB));
918    };
919
920insn_format21lh
921  : //e.g. const-wide/high16 v1, 1234
922    ^(I_STATEMENT_FORMAT21lh INSTRUCTION_FORMAT21lh REGISTER fixed_64bit_literal)
923    {
924      Opcode opcode = opcodes.getOpcodeByName($INSTRUCTION_FORMAT21lh.text);
925      short regA = parseRegister_byte($REGISTER.text);
926
927      long litB = $fixed_64bit_literal.value;
928
929      $method::methodBuilder.addInstruction(new BuilderInstruction21lh(opcode, regA, litB));
930    };
931
932insn_format21s
933  : //e.g. const/16 v1, 1234
934    ^(I_STATEMENT_FORMAT21s INSTRUCTION_FORMAT21s REGISTER short_integral_literal)
935    {
936      Opcode opcode = opcodes.getOpcodeByName($INSTRUCTION_FORMAT21s.text);
937      short regA = parseRegister_byte($REGISTER.text);
938
939      short litB = $short_integral_literal.value;
940
941      $method::methodBuilder.addInstruction(new BuilderInstruction21s(opcode, regA, litB));
942    };
943
944insn_format21t
945  : //e.g. if-eqz v0, endloop:
946    ^(I_STATEMENT_FORMAT21t INSTRUCTION_FORMAT21t REGISTER label_ref)
947    {
948      Opcode opcode = opcodes.getOpcodeByName($INSTRUCTION_FORMAT21t.text);
949      short regA = parseRegister_byte($REGISTER.text);
950
951      $method::methodBuilder.addInstruction(new BuilderInstruction21t(opcode, regA, $label_ref.label));
952    };
953
954insn_format22b
955  : //e.g. add-int v0, v1, 123
956    ^(I_STATEMENT_FORMAT22b INSTRUCTION_FORMAT22b registerA=REGISTER registerB=REGISTER short_integral_literal)
957    {
958      Opcode opcode = opcodes.getOpcodeByName($INSTRUCTION_FORMAT22b.text);
959      short regA = parseRegister_byte($registerA.text);
960      short regB = parseRegister_byte($registerB.text);
961
962      short litC = $short_integral_literal.value;
963      LiteralTools.checkByte(litC);
964
965      $method::methodBuilder.addInstruction(new BuilderInstruction22b(opcode, regA, regB, litC));
966    };
967
968insn_format22c_field
969  : //e.g. iput-object v1, v0, org/jf/HelloWorld2/HelloWorld2.helloWorld Ljava/lang/String;
970    ^(I_STATEMENT_FORMAT22c_FIELD inst=(INSTRUCTION_FORMAT22c_FIELD | INSTRUCTION_FORMAT22c_FIELD_ODEX) registerA=REGISTER registerB=REGISTER field_reference)
971    {
972      Opcode opcode = opcodes.getOpcodeByName($inst.text);
973      byte regA = parseRegister_nibble($registerA.text);
974      byte regB = parseRegister_nibble($registerB.text);
975
976      ImmutableFieldReference fieldReference = $field_reference.fieldReference;
977
978      $method::methodBuilder.addInstruction(new BuilderInstruction22c(opcode, regA, regB,
979              dexBuilder.internFieldReference(fieldReference)));
980    };
981
982insn_format22c_type
983  : //e.g. instance-of v0, v1, Ljava/lang/String;
984    ^(I_STATEMENT_FORMAT22c_TYPE INSTRUCTION_FORMAT22c_TYPE registerA=REGISTER registerB=REGISTER nonvoid_type_descriptor)
985    {
986      Opcode opcode = opcodes.getOpcodeByName($INSTRUCTION_FORMAT22c_TYPE.text);
987      byte regA = parseRegister_nibble($registerA.text);
988      byte regB = parseRegister_nibble($registerB.text);
989
990      $method::methodBuilder.addInstruction(new BuilderInstruction22c(opcode, regA, regB,
991              dexBuilder.internTypeReference($nonvoid_type_descriptor.type)));
992    };
993
994insn_format22c_string
995  : //e.g. liberate-variable v0, v1, "baz"
996    ^(I_STATEMENT_FORMAT22c_STRING INSTRUCTION_FORMAT22c_STRING registerA=REGISTER registerB=REGISTER string_literal)
997    {
998      Opcode opcode = opcodes.getOpcodeByName($INSTRUCTION_FORMAT22c_STRING.text);
999      byte regA = parseRegister_nibble($registerA.text);
1000      byte regB = parseRegister_nibble($registerB.text);
1001
1002      $method::methodBuilder.addInstruction(new BuilderInstruction22c(opcode, regA, regB,
1003              dexBuilder.internStringReference($string_literal.value)));
1004    };
1005
1006insn_format22s
1007  : //e.g. add-int/lit16 v0, v1, 12345
1008    ^(I_STATEMENT_FORMAT22s INSTRUCTION_FORMAT22s registerA=REGISTER registerB=REGISTER short_integral_literal)
1009    {
1010      Opcode opcode = opcodes.getOpcodeByName($INSTRUCTION_FORMAT22s.text);
1011      byte regA = parseRegister_nibble($registerA.text);
1012      byte regB = parseRegister_nibble($registerB.text);
1013
1014      short litC = $short_integral_literal.value;
1015
1016      $method::methodBuilder.addInstruction(new BuilderInstruction22s(opcode, regA, regB, litC));
1017    };
1018
1019insn_format22t
1020  : //e.g. if-eq v0, v1, endloop:
1021    ^(I_STATEMENT_FORMAT22t INSTRUCTION_FORMAT22t registerA=REGISTER registerB=REGISTER label_ref)
1022    {
1023      Opcode opcode = opcodes.getOpcodeByName($INSTRUCTION_FORMAT22t.text);
1024      byte regA = parseRegister_nibble($registerA.text);
1025      byte regB = parseRegister_nibble($registerB.text);
1026
1027      $method::methodBuilder.addInstruction(new BuilderInstruction22t(opcode, regA, regB, $label_ref.label));
1028    };
1029
1030insn_format22x
1031  : //e.g. move/from16 v1, v1234
1032    ^(I_STATEMENT_FORMAT22x INSTRUCTION_FORMAT22x registerA=REGISTER registerB=REGISTER)
1033    {
1034      Opcode opcode = opcodes.getOpcodeByName($INSTRUCTION_FORMAT22x.text);
1035      short regA = parseRegister_byte($registerA.text);
1036      int regB = parseRegister_short($registerB.text);
1037
1038      $method::methodBuilder.addInstruction(new BuilderInstruction22x(opcode, regA, regB));
1039    };
1040
1041insn_format23x
1042  : //e.g. add-int v1, v2, v3
1043    ^(I_STATEMENT_FORMAT23x INSTRUCTION_FORMAT23x registerA=REGISTER registerB=REGISTER registerC=REGISTER)
1044    {
1045      Opcode opcode = opcodes.getOpcodeByName($INSTRUCTION_FORMAT23x.text);
1046      short regA = parseRegister_byte($registerA.text);
1047      short regB = parseRegister_byte($registerB.text);
1048      short regC = parseRegister_byte($registerC.text);
1049
1050      $method::methodBuilder.addInstruction(new BuilderInstruction23x(opcode, regA, regB, regC));
1051    };
1052
1053insn_format25x
1054  : //e.g. invoke-lambda vClosure, {vD, vE, vF, vG} -- up to 4 parameters + the closure.
1055    ^(I_STATEMENT_FORMAT25x INSTRUCTION_FORMAT25x REGISTER register_list4)
1056    {
1057      Opcode opcode = opcodes.getOpcodeByName($INSTRUCTION_FORMAT25x.text);
1058
1059      byte closureRegister = parseRegister_nibble($REGISTER.text);
1060
1061      //this depends on the fact that register_list4 returns a byte[4]
1062      byte[] registers = $register_list4.registers;
1063      int parameterRegisterCount = $register_list4.registerCount;  // don't count closure register
1064
1065      $method::methodBuilder.addInstruction(new BuilderInstruction25x(opcode,
1066            parameterRegisterCount, closureRegister, registers[0], registers[1],
1067            registers[2], registers[3]));
1068    };
1069
1070insn_format30t
1071  : //e.g. goto/32 endloop:
1072    ^(I_STATEMENT_FORMAT30t INSTRUCTION_FORMAT30t label_ref)
1073    {
1074      Opcode opcode = opcodes.getOpcodeByName($INSTRUCTION_FORMAT30t.text);
1075
1076      $method::methodBuilder.addInstruction(new BuilderInstruction30t(opcode, $label_ref.label));
1077    };
1078
1079insn_format31c
1080  : //e.g. const-string/jumbo v1 "Hello World!"
1081    ^(I_STATEMENT_FORMAT31c INSTRUCTION_FORMAT31c REGISTER string_literal)
1082    {
1083      Opcode opcode = opcodes.getOpcodeByName($INSTRUCTION_FORMAT31c.text);
1084      short regA = parseRegister_byte($REGISTER.text);
1085
1086      $method::methodBuilder.addInstruction(new BuilderInstruction31c(opcode, regA,
1087              dexBuilder.internStringReference($string_literal.value)));
1088    };
1089
1090insn_format31i
1091  : //e.g. const v0, 123456
1092    ^(I_STATEMENT_FORMAT31i INSTRUCTION_FORMAT31i REGISTER fixed_32bit_literal)
1093    {
1094      Opcode opcode = opcodes.getOpcodeByName($INSTRUCTION_FORMAT31i.text);
1095      short regA = parseRegister_byte($REGISTER.text);
1096
1097      int litB = $fixed_32bit_literal.value;
1098
1099      $method::methodBuilder.addInstruction(new BuilderInstruction31i(opcode, regA, litB));
1100    };
1101
1102insn_format31t
1103  : //e.g. fill-array-data v0, ArrayData:
1104    ^(I_STATEMENT_FORMAT31t INSTRUCTION_FORMAT31t REGISTER label_ref)
1105    {
1106      Opcode opcode = opcodes.getOpcodeByName($INSTRUCTION_FORMAT31t.text);
1107
1108      short regA = parseRegister_byte($REGISTER.text);
1109
1110      $method::methodBuilder.addInstruction(new BuilderInstruction31t(opcode, regA, $label_ref.label));
1111    };
1112
1113insn_format32x
1114  : //e.g. move/16 v5678, v1234
1115    ^(I_STATEMENT_FORMAT32x INSTRUCTION_FORMAT32x registerA=REGISTER registerB=REGISTER)
1116    {
1117      Opcode opcode = opcodes.getOpcodeByName($INSTRUCTION_FORMAT32x.text);
1118      int regA = parseRegister_short($registerA.text);
1119      int regB = parseRegister_short($registerB.text);
1120
1121      $method::methodBuilder.addInstruction(new BuilderInstruction32x(opcode, regA, regB));
1122    };
1123
1124insn_format35c_method
1125  : //e.g. invoke-virtual {v0,v1} java/io/PrintStream/print(Ljava/lang/Stream;)V
1126    ^(I_STATEMENT_FORMAT35c_METHOD INSTRUCTION_FORMAT35c_METHOD register_list method_reference)
1127    {
1128      Opcode opcode = opcodes.getOpcodeByName($INSTRUCTION_FORMAT35c_METHOD.text);
1129
1130      //this depends on the fact that register_list returns a byte[5]
1131      byte[] registers = $register_list.registers;
1132      byte registerCount = $register_list.registerCount;
1133
1134      ImmutableMethodReference methodReference = $method_reference.methodReference;
1135
1136      $method::methodBuilder.addInstruction(new BuilderInstruction35c(opcode, registerCount, registers[0], registers[1],
1137              registers[2], registers[3], registers[4], dexBuilder.internMethodReference(methodReference)));
1138    };
1139
1140insn_format35c_type
1141  : //e.g. filled-new-array {v0,v1}, I
1142    ^(I_STATEMENT_FORMAT35c_TYPE INSTRUCTION_FORMAT35c_TYPE register_list nonvoid_type_descriptor)
1143    {
1144      Opcode opcode = opcodes.getOpcodeByName($INSTRUCTION_FORMAT35c_TYPE.text);
1145
1146      //this depends on the fact that register_list returns a byte[5]
1147      byte[] registers = $register_list.registers;
1148      byte registerCount = $register_list.registerCount;
1149
1150      $method::methodBuilder.addInstruction(new BuilderInstruction35c(opcode, registerCount, registers[0], registers[1],
1151              registers[2], registers[3], registers[4], dexBuilder.internTypeReference($nonvoid_type_descriptor.type)));
1152    };
1153
1154insn_format3rc_method
1155  : //e.g. invoke-virtual/range {v25..v26} java/lang/StringBuilder/append(Ljava/lang/String;)Ljava/lang/StringBuilder;
1156    ^(I_STATEMENT_FORMAT3rc_METHOD INSTRUCTION_FORMAT3rc_METHOD register_range method_reference)
1157    {
1158      Opcode opcode = opcodes.getOpcodeByName($INSTRUCTION_FORMAT3rc_METHOD.text);
1159      int startRegister = $register_range.startRegister;
1160      int endRegister = $register_range.endRegister;
1161
1162      int registerCount = endRegister-startRegister+1;
1163
1164      ImmutableMethodReference methodReference = $method_reference.methodReference;
1165
1166      $method::methodBuilder.addInstruction(new BuilderInstruction3rc(opcode, startRegister, registerCount,
1167              dexBuilder.internMethodReference(methodReference)));
1168    };
1169
1170insn_format3rc_type
1171  : //e.g. filled-new-array/range {v0..v6} I
1172    ^(I_STATEMENT_FORMAT3rc_TYPE INSTRUCTION_FORMAT3rc_TYPE register_range nonvoid_type_descriptor)
1173    {
1174      Opcode opcode = opcodes.getOpcodeByName($INSTRUCTION_FORMAT3rc_TYPE.text);
1175      int startRegister = $register_range.startRegister;
1176      int endRegister = $register_range.endRegister;
1177
1178      int registerCount = endRegister-startRegister+1;
1179
1180      $method::methodBuilder.addInstruction(new BuilderInstruction3rc(opcode, startRegister, registerCount,
1181              dexBuilder.internTypeReference($nonvoid_type_descriptor.type)));
1182    };
1183
1184insn_format51l_type
1185  : //e.g. const-wide v0, 5000000000L
1186    ^(I_STATEMENT_FORMAT51l INSTRUCTION_FORMAT51l REGISTER fixed_64bit_literal)
1187    {
1188      Opcode opcode = opcodes.getOpcodeByName($INSTRUCTION_FORMAT51l.text);
1189      short regA = parseRegister_byte($REGISTER.text);
1190
1191      long litB = $fixed_64bit_literal.value;
1192
1193      $method::methodBuilder.addInstruction(new BuilderInstruction51l(opcode, regA, litB));
1194    };
1195
1196insn_array_data_directive
1197  : //e.g. .array-data 4 1000000 .end array-data
1198    ^(I_STATEMENT_ARRAY_DATA ^(I_ARRAY_ELEMENT_SIZE short_integral_literal) array_elements)
1199    {
1200      int elementWidth = $short_integral_literal.value;
1201      List<Number> elements = $array_elements.elements;
1202
1203      $method::methodBuilder.addInstruction(new BuilderArrayPayload(elementWidth, $array_elements.elements));
1204    };
1205
1206insn_packed_switch_directive
1207  :
1208    ^(I_STATEMENT_PACKED_SWITCH ^(I_PACKED_SWITCH_START_KEY fixed_32bit_literal) packed_switch_elements)
1209      {
1210        int startKey = $fixed_32bit_literal.value;
1211        $method::methodBuilder.addInstruction(new BuilderPackedSwitchPayload(startKey,
1212            $packed_switch_elements.elements));
1213      };
1214
1215insn_sparse_switch_directive
1216  :
1217    ^(I_STATEMENT_SPARSE_SWITCH sparse_switch_elements)
1218    {
1219      $method::methodBuilder.addInstruction(new BuilderSparseSwitchPayload($sparse_switch_elements.elements));
1220    };
1221
1222array_descriptor returns [String type]
1223  : ARRAY_TYPE_PREFIX ( PRIMITIVE_TYPE { $type = $ARRAY_TYPE_PREFIX.text + $PRIMITIVE_TYPE.text; }
1224                      | CLASS_DESCRIPTOR { $type = $ARRAY_TYPE_PREFIX.text + $CLASS_DESCRIPTOR.text; });
1225
1226nonvoid_type_descriptor returns [String type]
1227  : (PRIMITIVE_TYPE { $type = $text; }
1228  | CLASS_DESCRIPTOR { $type = $text; }
1229  | array_descriptor { $type = $array_descriptor.type; })
1230  ;
1231
1232reference_type_descriptor returns [String type]
1233  : (CLASS_DESCRIPTOR { $type = $text; }
1234  | array_descriptor { $type = $array_descriptor.type; })
1235  ;
1236
1237type_descriptor returns [String type]
1238  : VOID_TYPE {$type = "V";}
1239  | nonvoid_type_descriptor {$type = $nonvoid_type_descriptor.type;}
1240  ;
1241
1242short_integral_literal returns[short value]
1243  : long_literal
1244    {
1245      LiteralTools.checkShort($long_literal.value);
1246      $value = (short)$long_literal.value;
1247    }
1248  | integer_literal
1249    {
1250      LiteralTools.checkShort($integer_literal.value);
1251      $value = (short)$integer_literal.value;
1252    }
1253  | short_literal {$value = $short_literal.value;}
1254  | char_literal {$value = (short)$char_literal.value;}
1255  | byte_literal {$value = $byte_literal.value;};
1256
1257integral_literal returns[int value]
1258  : long_literal
1259    {
1260      LiteralTools.checkInt($long_literal.value);
1261      $value = (int)$long_literal.value;
1262    }
1263  | integer_literal {$value = $integer_literal.value;}
1264  | short_literal {$value = $short_literal.value;}
1265  | byte_literal {$value = $byte_literal.value;};
1266
1267
1268integer_literal returns[int value]
1269  : INTEGER_LITERAL { $value = LiteralTools.parseInt($INTEGER_LITERAL.text); };
1270
1271long_literal returns[long value]
1272  : LONG_LITERAL { $value = LiteralTools.parseLong($LONG_LITERAL.text); };
1273
1274short_literal returns[short value]
1275  : SHORT_LITERAL { $value = LiteralTools.parseShort($SHORT_LITERAL.text); };
1276
1277byte_literal returns[byte value]
1278  : BYTE_LITERAL { $value = LiteralTools.parseByte($BYTE_LITERAL.text); };
1279
1280float_literal returns[float value]
1281  : FLOAT_LITERAL { $value = LiteralTools.parseFloat($FLOAT_LITERAL.text); };
1282
1283double_literal returns[double value]
1284  : DOUBLE_LITERAL { $value = LiteralTools.parseDouble($DOUBLE_LITERAL.text); };
1285
1286char_literal returns[char value]
1287  : CHAR_LITERAL { $value = $CHAR_LITERAL.text.charAt(1); };
1288
1289string_literal returns[String value]
1290  : STRING_LITERAL
1291    {
1292      $value = $STRING_LITERAL.text;
1293      $value = $value.substring(1,$value.length()-1);
1294    };
1295
1296bool_literal returns[boolean value]
1297  : BOOL_LITERAL { $value = Boolean.parseBoolean($BOOL_LITERAL.text); };
1298
1299array_literal returns[List<EncodedValue> elements]
1300  : {$elements = Lists.newArrayList();}
1301    ^(I_ENCODED_ARRAY (literal {$elements.add($literal.encodedValue);})*);
1302
1303annotations returns[Set<Annotation> annotations]
1304  : {HashMap<String, Annotation> annotationMap = Maps.newHashMap();}
1305    ^(I_ANNOTATIONS (annotation
1306    {
1307        Annotation anno = $annotation.annotation;
1308        Annotation old = annotationMap.put(anno.getType(), anno);
1309        if (old != null) {
1310            throw new SemanticException(input, "Multiple annotations of type \%s", anno.getType());
1311        }
1312    })*)
1313    {
1314      if (annotationMap.size() > 0) {
1315        $annotations = ImmutableSet.copyOf(annotationMap.values());
1316      }
1317    };
1318
1319annotation returns[Annotation annotation]
1320  : ^(I_ANNOTATION ANNOTATION_VISIBILITY subannotation)
1321    {
1322      int visibility = AnnotationVisibility.getVisibility($ANNOTATION_VISIBILITY.text);
1323      $annotation = new ImmutableAnnotation(visibility, $subannotation.annotationType, $subannotation.elements);
1324    };
1325
1326annotation_element returns[AnnotationElement element]
1327  : ^(I_ANNOTATION_ELEMENT SIMPLE_NAME literal)
1328    {
1329      $element = new ImmutableAnnotationElement($SIMPLE_NAME.text, $literal.encodedValue);
1330    };
1331
1332subannotation returns[String annotationType, List<AnnotationElement> elements]
1333  : {ArrayList<AnnotationElement> elements = Lists.newArrayList();}
1334    ^(I_SUBANNOTATION
1335        CLASS_DESCRIPTOR
1336        (annotation_element
1337        {
1338           elements.add($annotation_element.element);
1339        })*
1340     )
1341    {
1342      $annotationType = $CLASS_DESCRIPTOR.text;
1343      $elements = elements;
1344    };
1345
1346field_literal returns[FieldReference value]
1347  : ^(I_ENCODED_FIELD field_reference)
1348    {
1349      $value = $field_reference.fieldReference;
1350    };
1351
1352method_literal returns[MethodReference value]
1353  : ^(I_ENCODED_METHOD method_reference)
1354    {
1355      $value = $method_reference.methodReference;
1356    };
1357
1358enum_literal returns[FieldReference value]
1359  : ^(I_ENCODED_ENUM field_reference)
1360    {
1361      $value = $field_reference.fieldReference;
1362    };
1363