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