1/*
2 * [The "BSD licence"]
3 * Copyright (c) 2010 Ben Gruver
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote products
15 *    derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29parser grammar smalideaParser;
30
31options {
32  tokenVocab=smaliParser;
33}
34
35@header {
36package org.jf.smalidea;
37
38import com.intellij.lang.PsiBuilder;
39import com.intellij.lang.PsiBuilder.Marker;
40import com.intellij.psi.tree.IElementType;
41import org.jf.smalidea.psi.SmaliElementTypes;
42
43import javax.annotation.Nonnull;
44import javax.annotation.Nullable;
45}
46
47
48@members {
49    private PsiBuilder psiBuilder;
50
51    public void setPsiBuilder(PsiBuilder psiBuilder) {
52        this.psiBuilder = psiBuilder;
53    }
54
55    public Marker mark() {
56        return psiBuilder.mark();
57    }
58
59    protected void syncToFollows(boolean acceptEof) {
60        BitSet follow = computeErrorRecoverySet();
61        int mark = input.mark();
62        Marker marker = null;
63        try {
64            int token = input.LA(1);
65            while (!follow.member(token)) {
66                if (token == Token.EOF) {
67                    if (acceptEof) {
68                        break;
69                    }
70                    input.rewind(mark);
71                    mark = -1;
72                    marker = null;
73                    return;
74                }
75                if (marker == null) {
76                    marker = mark();
77                }
78                input.consume();
79                token = input.LA(1);
80            }
81        } finally {
82            if  (mark != -1) {
83                input.release(mark);
84            }
85            if (marker != null) {
86                marker.error("Unexpected tokens");
87            }
88        }
89    }
90
91    @Override
92    public void recover(IntStream input, RecognitionException re) {
93        BitSet followSet = computeErrorRecoverySet();
94        beginResync();
95        consumeUntil(input, followSet);
96        endResync();
97    }
98
99    @Override
100    protected Object recoverFromMismatchedToken(IntStream input, int ttype, BitSet follow)
101            throws RecognitionException
102    {
103        RecognitionException e = null;
104        // if next token is what we are looking for then "delete" this token
105        if ( mismatchIsUnwantedToken(input, ttype) ) {
106            e = new UnwantedTokenException(ttype, input);
107            beginResync();
108            Marker mark = mark();
109            input.consume(); // simply delete extra token
110            mark.error(getErrorMessage(e, tokenNames));
111            endResync();
112            reportError(null, e, true);  // report after consuming so AW sees the token in the exception
113            // we want to return the token we're actually matching
114            Object matchedSymbol = getCurrentInputSymbol(input);
115            input.consume(); // move past ttype token as if all were ok
116            return matchedSymbol;
117        }
118        // can't recover with single token deletion, try insertion
119        if ( mismatchIsMissingToken(input, follow) ) {
120            Object inserted = getMissingSymbol(input, e, ttype, follow);
121            Marker mark = mark();
122            e = new MissingTokenException(ttype, input, inserted);
123            mark.error(getErrorMessage(e, tokenNames));
124            reportError(null, e, true);  // report after inserting so AW sees the token in the exception
125            return inserted;
126        }
127
128        // even that didn't work; must throw the exception
129        e = new MismatchedTokenException(ttype, input);
130        throw e;
131    }
132
133    @Override
134    public void reportError(RecognitionException e) {
135        reportError(mark(), e, false);
136    }
137
138    public void reportError(@Nullable Marker marker, RecognitionException e, boolean alreadyReported) {
139        // if we've already reported an error and have not matched a token
140        // yet successfully, don't report any errors.
141        if ( state.errorRecovery ) {
142            if (marker != null) {
143                marker.drop();
144            }
145            return;
146        }
147        state.syntaxErrors++; // don't count spurious
148        state.errorRecovery = true;
149
150        if (marker != null) {
151            if (!alreadyReported) {
152                displayRecognitionError(marker, this.getTokenNames(), e);
153            } else {
154                marker.drop();
155            }
156        }
157    }
158
159    public void finishToken(Marker marker, IElementType elementType) {
160        if (state.errorRecovery) {
161            marker.drop();
162        } else {
163            marker.done(elementType);
164        }
165    }
166
167    @Override
168    public void displayRecognitionError(String[] tokenNames, RecognitionException e) {
169        displayRecognitionError(mark(), tokenNames, e);
170    }
171
172    public void displayRecognitionError(@Nonnull Marker marker, String[] tokenNames, RecognitionException e) {
173        marker.error(getErrorMessage(e, tokenNames));
174    }
175}
176
177sync[boolean toEof]
178  @init { syncToFollows($toEof); }
179  : /*epsilon*/;
180
181smali_file
182  @init {
183    mark().done(SmaliElementTypes.EXTENDS_LIST);
184    mark().done(SmaliElementTypes.IMPLEMENTS_LIST);
185  }
186  :
187  (
188    ( class_spec
189    | super_spec
190    | implements_spec
191    | source_spec
192    | method
193    | field
194    | annotation
195    )
196    sync[true]
197  )+
198  EOF;
199
200class_spec
201  @init { Marker marker = mark(); }
202  : CLASS_DIRECTIVE class_access_list class_descriptor
203  { marker.done(SmaliElementTypes.CLASS_STATEMENT); };
204  catch [RecognitionException re] {
205    recover(input, re);
206    reportError(marker, re, false);
207  }
208
209super_spec
210  @init { Marker marker = mark(); }
211  : SUPER_DIRECTIVE class_descriptor
212  { marker.done(SmaliElementTypes.SUPER_STATEMENT); };
213  catch [RecognitionException re] {
214    recover(input, re);
215    reportError(marker, re, false);
216  }
217
218implements_spec
219  @init { Marker marker = mark(); }
220  : IMPLEMENTS_DIRECTIVE class_descriptor
221  { marker.done(SmaliElementTypes.IMPLEMENTS_STATEMENT); };
222  catch [RecognitionException re] {
223    recover(input, re);
224    reportError(marker, re, false);
225  }
226
227source_spec
228  @init { Marker marker = mark(); }
229  : SOURCE_DIRECTIVE string_literal
230  { marker.done(SmaliElementTypes.SOURCE_STATEMENT); };
231  catch [RecognitionException re] {
232    recover(input, re);
233    reportError(marker, re, false);
234  }
235
236// class_access_list should be separate from access_list, because
237// it exists in a slightly different context, and can consume
238// ACCESS_SPECs greedily, without having to look ahead.
239class_access_list
240  @init { Marker marker = mark(); }
241  : ACCESS_SPEC*
242  { marker.done(SmaliElementTypes.MODIFIER_LIST); };
243  catch [RecognitionException re] {
244    recover(input, re);
245    reportError(marker, re, false);
246  }
247
248access_list
249  @init { Marker marker = mark(); }
250  : ACCESS_SPEC*
251  { marker.done(SmaliElementTypes.MODIFIER_LIST); };
252  catch [RecognitionException re] {
253    recover(input, re);
254    reportError(marker, re, false);
255  }
256
257/*When there are annotations immediately after a field definition, we don't know whether they are field annotations
258or class annotations until we determine if there is an .end field directive. In either case, we still "consume" and parse
259the annotations. If it turns out that they are field annotations, we include them in the I_FIELD AST. Otherwise, we
260add them to the $smali_file::classAnnotations list*/
261field
262  @init {
263    Marker marker = mark();
264    Marker annotationsMarker = null;
265    boolean gotEndField = false;
266  }
267  : FIELD_DIRECTIVE
268    access_list
269    member_name colon nonvoid_type_descriptor
270    field_initializer?
271    (
272       (ANNOTATION_DIRECTIVE)=> (
273         { annotationsMarker = mark(); }
274         ((ANNOTATION_DIRECTIVE)=> annotation)+
275       )
276    )?
277    ( end_field_directive { gotEndField = true; } )?
278  {
279    if (annotationsMarker != null) {
280      if (gotEndField) {
281        annotationsMarker.drop();
282        marker.done(SmaliElementTypes.FIELD);
283      } else {
284        marker.doneBefore(SmaliElementTypes.FIELD, annotationsMarker);
285        annotationsMarker.drop();
286      }
287    } else {
288      marker.done(SmaliElementTypes.FIELD);
289    }
290  };
291  catch [RecognitionException re] {
292    if (annotationsMarker != null) {
293        annotationsMarker.drop();
294    }
295    recover(input, re);
296    reportError(marker, re, false);
297  }
298
299end_field_directive
300  : END_FIELD_DIRECTIVE;
301
302field_initializer
303  @init { Marker marker = mark(); }
304  : EQUAL literal
305  { marker.done(SmaliElementTypes.FIELD_INITIALIZER); };
306  catch [RecognitionException re] {
307    recover(input, re);
308    reportError(marker, re, false);
309  }
310
311method
312  @init {
313    Marker marker = mark();
314    mark().done(SmaliElementTypes.THROWS_LIST);
315  }
316  : METHOD_DIRECTIVE access_list member_name method_prototype statements_and_directives
317    end_method_directive
318  { marker.done(SmaliElementTypes.METHOD); };
319  catch [RecognitionException re] {
320    recover(input, re);
321    reportError(marker, re, false);
322  }
323
324end_method_directive
325  : END_METHOD_DIRECTIVE;
326catch [RecognitionException re] {
327    Marker errorMarker = mark();
328    recover(input, re);
329    reportError(errorMarker, re, false);
330  }
331
332statements_and_directives
333  : (
334      ( ordered_method_item
335      | registers_directive
336      | catch_directive
337      | catchall_directive
338      | parameter_directive
339      | annotation
340      )
341      sync[false]
342    )*;
343
344/* Method items whose order/location is important */
345ordered_method_item
346  : label
347  | instruction
348  | debug_directive;
349
350registers_directive
351  @init { Marker marker = mark(); }
352  : (
353      REGISTERS_DIRECTIVE integral_literal
354    | LOCALS_DIRECTIVE integral_literal
355    )
356  { marker.done(SmaliElementTypes.REGISTERS_STATEMENT); };
357  catch [RecognitionException re] {
358    recover(input, re);
359    reportError(marker, re, false);
360  }
361
362param_list_or_id
363  : PARAM_LIST_OR_ID_PRIMITIVE_TYPE+;
364
365/*identifiers are much more general than most languages. Any of the below can either be
366the indicated type OR an identifier, depending on the context*/
367simple_name
368  : SIMPLE_NAME
369  | ACCESS_SPEC
370  | VERIFICATION_ERROR_TYPE
371  | POSITIVE_INTEGER_LITERAL
372  | NEGATIVE_INTEGER_LITERAL
373  | FLOAT_LITERAL_OR_ID
374  | DOUBLE_LITERAL_OR_ID
375  | BOOL_LITERAL
376  | NULL_LITERAL
377  | register
378  | param_list_or_id
379  | PRIMITIVE_TYPE
380  | VOID_TYPE
381  | ANNOTATION_VISIBILITY
382  | INSTRUCTION_FORMAT10t
383  | INSTRUCTION_FORMAT10x
384  | INSTRUCTION_FORMAT10x_ODEX
385  | INSTRUCTION_FORMAT11x
386  | INSTRUCTION_FORMAT12x_OR_ID
387  | INSTRUCTION_FORMAT21c_FIELD
388  | INSTRUCTION_FORMAT21c_FIELD_ODEX
389  | INSTRUCTION_FORMAT21c_STRING
390  | INSTRUCTION_FORMAT21c_TYPE
391  | INSTRUCTION_FORMAT21t
392  | INSTRUCTION_FORMAT22c_FIELD
393  | INSTRUCTION_FORMAT22c_FIELD_ODEX
394  | INSTRUCTION_FORMAT22c_TYPE
395  | INSTRUCTION_FORMAT22cs_FIELD
396  | INSTRUCTION_FORMAT22s_OR_ID
397  | INSTRUCTION_FORMAT22t
398  | INSTRUCTION_FORMAT23x
399  | INSTRUCTION_FORMAT31i_OR_ID
400  | INSTRUCTION_FORMAT31t
401  | INSTRUCTION_FORMAT35c_METHOD
402  | INSTRUCTION_FORMAT35c_METHOD_ODEX
403  | INSTRUCTION_FORMAT35c_TYPE
404  | INSTRUCTION_FORMAT35mi_METHOD
405  | INSTRUCTION_FORMAT35ms_METHOD
406  | INSTRUCTION_FORMAT51l;
407
408member_name
409  @init { Marker marker = mark(); }
410  : member_name_inner
411  { marker.done(SmaliElementTypes.MEMBER_NAME); };
412
413member_name_inner
414  : (simple_name
415    | MEMBER_NAME);
416  catch [RecognitionException re] {
417    Marker errorMarker = mark();
418    recover(input, re);
419    reportError(errorMarker, re, false);
420  }
421
422method_prototype
423  @init { Marker marker = mark(); }
424  : open_paren param_list close_paren type_descriptor
425    { marker.done(SmaliElementTypes.METHOD_PROTOTYPE); };
426  catch [RecognitionException re] {
427    recover(input, re);
428    reportError(marker, re, false);
429  }
430
431open_paren
432  : OPEN_PAREN;
433  catch [RecognitionException re] {
434    Marker errorMarker = mark();
435    recover(input, re);
436    reportError(errorMarker, re, false);
437  }
438
439close_paren
440  : CLOSE_PAREN;
441  catch [RecognitionException re] {
442    Marker errorMarker = mark();
443    recover(input, re);
444    reportError(errorMarker, re, false);
445  }
446
447open_brace
448  : OPEN_BRACE;
449  catch [RecognitionException re] {
450    Marker errorMarker = mark();
451    recover(input, re);
452    reportError(errorMarker, re, false);
453  }
454
455close_brace
456  : CLOSE_BRACE;
457  catch [RecognitionException re] {
458    Marker errorMarker = mark();
459    recover(input, re);
460    reportError(errorMarker, re, false);
461  }
462
463comma
464  : COMMA;
465  catch [RecognitionException re] {
466    Marker errorMarker = mark();
467    recover(input, re);
468    reportError(errorMarker, re, false);
469  }
470
471colon
472  : COLON;
473  catch [RecognitionException re] {
474    Marker errorMarker = mark();
475    recover(input, re);
476    reportError(errorMarker, re, false);
477  }
478
479dotdot
480  : DOTDOT;
481  catch [RecognitionException re] {
482    Marker errorMarker = mark();
483    recover(input, re);
484    reportError(errorMarker, re, false);
485  }
486
487param_list_inner
488  : param+;
489  catch [RecognitionException re] {
490    Marker errorMarker = mark();
491    recover(input, re);
492    reportError(errorMarker, re, false);
493  }
494
495param_list
496  @init { Marker marker = mark(); }
497  : param_list_inner?
498    { marker.done(SmaliElementTypes.METHOD_PARAM_LIST); };
499
500param
501  @init {
502    Marker marker = mark();
503    mark().done(SmaliElementTypes.MODIFIER_LIST);
504  }
505  : nonvoid_type_descriptor
506  { marker.done(SmaliElementTypes.METHOD_PARAMETER); };
507  catch [RecognitionException re] {
508    recover(input, re);
509    reportError(marker, re, false);
510  }
511
512method_prototype_reference
513  : open_paren param_list_reference close_paren type_descriptor;
514
515param_list_reference
516  @init {
517    Marker marker = mark();
518  }
519  : nonvoid_type_descriptor*
520  { marker.done(SmaliElementTypes.METHOD_REFERENCE_PARAM_LIST); };
521  catch [RecognitionException re] {
522    recover(input, re);
523    reportError(marker, re, false);
524  }
525
526primitive_type
527  @init { Marker marker = mark(); }
528  : (PRIMITIVE_TYPE | PARAM_LIST_OR_ID_PRIMITIVE_TYPE)
529  { finishToken(marker, SmaliElementTypes.PRIMITIVE_TYPE); };
530  catch [RecognitionException re] {
531    recover(input, re);
532    reportError(marker, re, false);
533  }
534
535class_descriptor
536  @init { Marker marker = mark(); }
537  : CLASS_DESCRIPTOR
538  { finishToken(marker, SmaliElementTypes.CLASS_TYPE); };
539  catch [RecognitionException re] {
540    recover(input, re);
541    reportError(marker, re, false);
542  }
543
544array_descriptor
545  @init { Marker marker = mark(); }
546  : ARRAY_TYPE_PREFIX (primitive_type | class_descriptor)
547  { finishToken(marker, SmaliElementTypes.ARRAY_TYPE); };
548  catch [RecognitionException re] {
549    recover(input, re);
550    reportError(marker, re, false);
551  }
552
553void_type
554  @init { Marker marker = mark(); }
555  : VOID_TYPE
556  { finishToken(marker, SmaliElementTypes.VOID_TYPE); };
557  catch [RecognitionException re] {
558    recover(input, re);
559    reportError(marker, re, false);
560  }
561
562type_descriptor
563  : void_type
564  | primitive_type
565  | class_descriptor
566  | array_descriptor;
567  catch [RecognitionException re] {
568    Marker marker = mark();
569    recover(input, re);
570    reportError(marker, re, false);
571  }
572
573nonvoid_type_descriptor
574  : primitive_type
575  | class_descriptor
576  | array_descriptor;
577  catch [RecognitionException re] {
578    Marker marker = mark();
579    recover(input, re);
580    reportError(marker, re, false);
581  }
582
583reference_type_descriptor
584  : class_descriptor
585  | array_descriptor;
586  catch [RecognitionException re] {
587    Marker marker = mark();
588    recover(input, re);
589    reportError(marker, re, false);
590  }
591
592null_literal
593  @init { Marker marker = mark(); }
594  : NULL_LITERAL
595  { finishToken(marker, SmaliElementTypes.LITERAL); };
596  catch [RecognitionException re] {
597    recover(input, re);
598    reportError(marker, re, false);
599  }
600
601bool_literal
602  @init { Marker marker = mark(); }
603  : BOOL_LITERAL
604  { finishToken(marker, SmaliElementTypes.LITERAL); };
605  catch [RecognitionException re] {
606    recover(input, re);
607    reportError(marker, re, false);
608  }
609
610byte_literal
611  @init { Marker marker = mark(); }
612  : BYTE_LITERAL
613  { finishToken(marker, SmaliElementTypes.LITERAL); };
614  catch [RecognitionException re] {
615    recover(input, re);
616    reportError(marker, re, false);
617  }
618
619char_literal
620  @init { Marker marker = mark(); }
621  : CHAR_LITERAL
622  { finishToken(marker, SmaliElementTypes.LITERAL); };
623  catch [RecognitionException re] {
624    recover(input, re);
625    reportError(marker, re, false);
626  }
627
628short_literal
629  @init { Marker marker = mark(); }
630  : SHORT_LITERAL
631  { finishToken(marker, SmaliElementTypes.LITERAL); };
632  catch [RecognitionException re] {
633    recover(input, re);
634    reportError(marker, re, false);
635  }
636
637integer_literal
638  @init { Marker marker = mark(); }
639  : ( POSITIVE_INTEGER_LITERAL
640    | NEGATIVE_INTEGER_LITERAL)
641  { finishToken(marker, SmaliElementTypes.LITERAL); };
642  catch [RecognitionException re] {
643    recover(input, re);
644    reportError(marker, re, false);
645  }
646
647long_literal
648  @init { Marker marker = mark(); }
649  : LONG_LITERAL
650  { finishToken(marker, SmaliElementTypes.LITERAL); };
651  catch [RecognitionException re] {
652    recover(input, re);
653    reportError(marker, re, false);
654  }
655
656float_literal
657  @init { Marker marker = mark(); }
658  : ( FLOAT_LITERAL_OR_ID
659    | FLOAT_LITERAL )
660  { finishToken(marker, SmaliElementTypes.LITERAL); };
661  catch [RecognitionException re] {
662    recover(input, re);
663    reportError(marker, re, false);
664  }
665
666double_literal
667  @init { Marker marker = mark(); }
668  : ( DOUBLE_LITERAL_OR_ID
669    | DOUBLE_LITERAL)
670  { finishToken(marker, SmaliElementTypes.LITERAL); };
671  catch [RecognitionException re] {
672    recover(input, re);
673    reportError(marker, re, false);
674  }
675
676string_literal
677  @init { Marker marker = mark(); }
678  : STRING_LITERAL
679  { finishToken(marker, SmaliElementTypes.LITERAL); };
680  catch [RecognitionException re] {
681    recover(input, re);
682    reportError(marker, re, false);
683  }
684
685array_literal
686  @init { Marker marker = mark(); }
687  : open_brace (literal (comma literal)* | ) close_brace
688  { marker.done(SmaliElementTypes.LITERAL); };
689  catch [RecognitionException re] {
690    recover(input, re);
691    reportError(marker, re, false);
692  }
693
694enum_literal
695  @init { Marker marker = mark(); }
696  : ENUM_DIRECTIVE fully_qualified_field
697  { marker.done(SmaliElementTypes.LITERAL); };
698  catch [RecognitionException re] {
699    recover(input, re);
700    reportError(marker, re, false);
701  }
702
703type_field_method_literal
704  @init { Marker marker = mark(); }
705  : ( type_descriptor
706    | fully_qualified_field
707    | fully_qualified_method)
708  { marker.done(SmaliElementTypes.LITERAL); };
709  catch [RecognitionException re] {
710    recover(input, re);
711    reportError(marker, re, false);
712  }
713
714subannotation
715  @init {
716    Marker marker = mark();
717    Marker paramListMarker = null;
718  }
719  : SUBANNOTATION_DIRECTIVE class_descriptor
720    { paramListMarker = mark(); }
721    annotation_element*
722    { paramListMarker.done(SmaliElementTypes.ANNOTATION_PARAMETER_LIST); }
723    end_subannotation_directive
724    { marker.done(SmaliElementTypes.ANNOTATION); };
725  catch [RecognitionException re] {
726    recover(input, re);
727    reportError(marker, re, false);
728  }
729
730end_subannotation_directive
731  : END_SUBANNOTATION_DIRECTIVE;
732  catch [RecognitionException re] {
733    Marker errorMarker = mark();
734    recover(input, re);
735    reportError(errorMarker, re, false);
736  }
737
738literal
739  : long_literal
740  | integer_literal
741  | short_literal
742  | byte_literal
743  | float_literal
744  | double_literal
745  | char_literal
746  | string_literal
747  | bool_literal
748  | null_literal
749  | array_literal
750  | subannotation
751  | type_field_method_literal
752  | enum_literal;
753  catch [RecognitionException re] {
754    Marker errorMarker = mark();
755    recover(input, re);
756    reportError(errorMarker, re, false);
757  }
758
759string_or_null_literal
760  : string_literal
761  | null_literal;
762  catch [RecognitionException re] {
763    Marker errorMarker = mark();
764    recover(input, re);
765    reportError(errorMarker, re, false);
766  }
767
768integral_literal
769  : long_literal
770  | integer_literal
771  | short_literal
772  | char_literal
773  | byte_literal;
774  catch [RecognitionException re] {
775    Marker errorMarker = mark();
776    recover(input, re);
777    reportError(errorMarker, re, false);
778  }
779
780fixed_32bit_literal
781  : long_literal
782  | integer_literal
783      | short_literal
784  | byte_literal
785  | float_literal
786  | char_literal
787  | bool_literal;
788  catch [RecognitionException re] {
789    Marker errorMarker = mark();
790    recover(input, re);
791    reportError(errorMarker, re, false);
792  }
793
794fixed_literal
795  : integer_literal
796  | long_literal
797  | short_literal
798  | byte_literal
799  | float_literal
800  | double_literal
801  | char_literal
802  | bool_literal;
803  catch [RecognitionException re] {
804    Marker errorMarker = mark();
805    recover(input, re);
806    reportError(errorMarker, re, false);
807  }
808
809annotation_element
810  @init {
811    Marker marker = mark();
812    Marker nameMarker = null;
813  }
814  : { nameMarker = mark(); } simple_name { nameMarker.done(SmaliElementTypes.ANNOTATION_ELEMENT_NAME); }
815    equal literal
816  { marker.done(SmaliElementTypes.ANNOTATION_ELEMENT); };
817  catch [RecognitionException re] {
818    recover(input, re);
819    reportError(marker, re, false);
820  }
821
822equal
823  : EQUAL;
824  catch [RecognitionException re] {
825    Marker errorMarker = mark();
826    recover(input, re);
827    reportError(errorMarker, re, false);
828  }
829
830annotation
831  @init {
832    Marker marker = mark();
833    Marker paramListMarker = null;
834  }
835  : ANNOTATION_DIRECTIVE annotation_visibility class_descriptor
836    { paramListMarker = mark(); }
837    annotation_element*
838    { paramListMarker.done(SmaliElementTypes.ANNOTATION_PARAMETER_LIST); }
839    end_annotation_directive
840  { marker.done(SmaliElementTypes.ANNOTATION); };
841
842annotation_visibility
843  : ANNOTATION_VISIBILITY;
844  catch [RecognitionException re] {
845    Marker errorMarker = mark();
846    recover(input, re);
847    reportError(errorMarker, re, false);
848  }
849
850end_annotation_directive
851  : END_ANNOTATION_DIRECTIVE;
852  catch [RecognitionException re] {
853    Marker errorMarker = mark();
854    recover(input, re);
855    reportError(errorMarker, re, false);
856  }
857
858arrow
859  : ARROW;
860  catch [RecognitionException re] {
861    Marker errorMarker = mark();
862    recover(input, re);
863    reportError(errorMarker, re, false);
864  }
865
866fully_qualified_method
867  @init { Marker marker = mark(); }
868  : reference_type_descriptor arrow member_name method_prototype_reference
869  { marker.done(SmaliElementTypes.METHOD_REFERENCE); };
870  catch [RecognitionException re] {
871    recover(input, re);
872    reportError(marker, re, false);
873  }
874
875fully_qualified_field
876  @init { Marker marker = mark(); }
877  : reference_type_descriptor arrow member_name colon nonvoid_type_descriptor
878  { marker.done(SmaliElementTypes.FIELD_REFERENCE); };
879  catch [RecognitionException re] {
880    recover(input, re);
881    reportError(marker, re, false);
882  }
883
884label
885  @init { Marker marker = mark(); }
886  : colon simple_name
887  { marker.done(SmaliElementTypes.LABEL); };
888  catch [RecognitionException re] {
889    recover(input, re);
890    reportError(marker, re, false);
891  }
892
893label_ref
894  @init { Marker marker = mark(); }
895  : colon simple_name
896  { marker.done(SmaliElementTypes.LABEL_REFERENCE); };
897  catch [RecognitionException re] {
898    recover(input, re);
899    reportError(marker, re, false);
900  }
901
902register_list
903  : open_brace (register (comma register)*)? close_brace;
904
905register_range
906  : open_brace (register (dotdot register)?)? close_brace;
907
908verification_error_reference
909  : class_descriptor | fully_qualified_field | fully_qualified_method;
910
911catch_directive
912  @init { Marker marker = mark(); }
913  : CATCH_DIRECTIVE nonvoid_type_descriptor open_brace label_ref dotdot label_ref close_brace label_ref
914  { marker.done(SmaliElementTypes.CATCH_STATEMENT); };
915  catch [RecognitionException re] {
916    recover(input, re);
917    reportError(marker, re, false);
918  }
919
920catchall_directive
921  @init { Marker marker = mark(); }
922  : CATCHALL_DIRECTIVE open_brace label_ref dotdot label_ref close_brace label_ref
923  { marker.done(SmaliElementTypes.CATCH_ALL_STATEMENT); };
924  catch [RecognitionException re] {
925    recover(input, re);
926    reportError(marker, re, false);
927  }
928
929/*When there are annotations immediately after a parameter definition, we don't know whether they are parameter annotations
930or method annotations until we determine if there is an .end parameter directive. In either case, we still "consume" and parse
931the annotations. If it turns out that they are parameter annotations, we include them in the I_PARAMETER AST. Otherwise, we
932add them to the $statements_and_directives::methodAnnotations list*/
933parameter_directive
934  @init {
935    Marker marker = mark();
936    Marker annotationsMarker = null;
937    boolean gotEndParam = false;
938  }
939  : PARAMETER_DIRECTIVE register
940    (comma local_name)?
941    { annotationsMarker = mark(); } parameter_annotations
942    ( end_parameter_directive { gotEndParam = true; } )?
943  {
944    if (gotEndParam) {
945      annotationsMarker.drop();
946      marker.done(SmaliElementTypes.PARAMETER_STATEMENT);
947    } else {
948      marker.doneBefore(SmaliElementTypes.PARAMETER_STATEMENT, annotationsMarker);
949      annotationsMarker.drop();
950    }
951  };
952  catch [RecognitionException re] {
953    if (annotationsMarker != null) {
954        annotationsMarker.drop();
955    }
956    recover(input, re);
957    reportError(marker, re, false);
958  }
959
960parameter_annotations
961  : ((ANNOTATION_DIRECTIVE)=> annotation)*;
962  catch [RecognitionException re] {
963    Marker errorMarker = mark();
964    recover(input, re);
965    reportError(errorMarker, re, false);
966  }
967
968end_parameter_directive
969  : END_PARAMETER_DIRECTIVE;
970
971local_name
972  @init {
973    Marker localNameMarker = mark();
974    Marker stringMarker = mark();
975  }
976  : STRING_LITERAL
977  {
978    finishToken(stringMarker, SmaliElementTypes.LITERAL);
979    finishToken(localNameMarker, SmaliElementTypes.LOCAL_NAME);
980  };
981  catch [RecognitionException re] {
982      stringMarker.drop();
983      recover(input, re);
984      reportError(localNameMarker, re, false);
985  }
986
987register
988  @init { Marker marker = mark(); }
989  : REGISTER
990  { finishToken(marker, SmaliElementTypes.REGISTER_REFERENCE); };
991  catch [RecognitionException re] {
992    recover(input, re);
993    reportError(marker, re, false);
994  }
995
996debug_directive
997  : line_directive
998  | local_directive
999  | end_local_directive
1000  | restart_local_directive
1001  | prologue_directive
1002  | epilogue_directive
1003  | source_directive;
1004
1005line_directive
1006  @init { Marker marker = mark(); }
1007  : LINE_DIRECTIVE integral_literal
1008  { marker.done(SmaliElementTypes.LINE_DEBUG_STATEMENT); };
1009  catch [RecognitionException re] {
1010    recover(input, re);
1011    reportError(marker, re, false);
1012  }
1013
1014local_directive
1015  @init { Marker marker = mark(); }
1016  : LOCAL_DIRECTIVE register (comma string_or_null_literal colon type_descriptor
1017                              (comma string_literal)? )?
1018  { marker.done(SmaliElementTypes.LOCAL_DEBUG_STATEMENT); };
1019  catch [RecognitionException re] {
1020    recover(input, re);
1021    reportError(marker, re, false);
1022  }
1023
1024end_local_directive
1025  @init { Marker marker = mark(); }
1026  : END_LOCAL_DIRECTIVE register
1027  { marker.done(SmaliElementTypes.END_LOCAL_DEBUG_STATEMENT); };
1028  catch [RecognitionException re] {
1029    recover(input, re);
1030    reportError(marker, re, false);
1031  }
1032
1033restart_local_directive
1034  @init { Marker marker = mark(); }
1035  : RESTART_LOCAL_DIRECTIVE register
1036  { marker.done(SmaliElementTypes.RESTART_LOCAL_DEBUG_STATEMENT); };
1037  catch [RecognitionException re] {
1038    recover(input, re);
1039    reportError(marker, re, false);
1040  }
1041
1042prologue_directive
1043  @init { Marker marker = mark(); }
1044  : PROLOGUE_DIRECTIVE
1045  { marker.done(SmaliElementTypes.PROLOGUE_DEBUG_STATEMENT); };
1046  catch [RecognitionException re] {
1047    recover(input, re);
1048    reportError(marker, re, false);
1049  }
1050
1051epilogue_directive
1052  @init { Marker marker = mark(); }
1053  : EPILOGUE_DIRECTIVE
1054  { marker.done(SmaliElementTypes.EPILOGUE_DEBUG_STATEMENT); };
1055  catch [RecognitionException re] {
1056    recover(input, re);
1057    reportError(marker, re, false);
1058  }
1059
1060source_directive
1061  @init { Marker marker = mark(); }
1062  : SOURCE_DIRECTIVE string_literal?
1063  { marker.done(SmaliElementTypes.SOURCE_DEBUG_STATEMENT); };
1064  catch [RecognitionException re] {
1065    recover(input, re);
1066    reportError(marker, re, false);
1067  }
1068
1069instruction_format12x
1070  : INSTRUCTION_FORMAT12x
1071  | INSTRUCTION_FORMAT12x_OR_ID;
1072
1073instruction_format22s
1074  : INSTRUCTION_FORMAT22s
1075  | INSTRUCTION_FORMAT22s_OR_ID;
1076
1077instruction_format31i
1078  : INSTRUCTION_FORMAT31i
1079  | INSTRUCTION_FORMAT31i_OR_ID;
1080
1081instruction
1082  @init { Marker marker = mark(); }
1083  : ( insn_format10t
1084    | insn_format10x
1085    | insn_format10x_odex
1086    | insn_format11n
1087    | insn_format11x
1088    | insn_format12x
1089    | insn_format20bc
1090    | insn_format20t
1091    | insn_format21c_field
1092    | insn_format21c_field_odex
1093    | insn_format21c_string
1094      | insn_format21c_type
1095      | insn_format21ih
1096      | insn_format21lh
1097      | insn_format21s
1098      | insn_format21t
1099      | insn_format22b
1100      | insn_format22c_field
1101      | insn_format22c_field_odex
1102      | insn_format22c_type
1103      | insn_format22cs_field
1104      | insn_format22s
1105      | insn_format22t
1106      | insn_format22x
1107      | insn_format23x
1108      | insn_format30t
1109      | insn_format31c
1110      | insn_format31i
1111      | insn_format31t
1112      | insn_format32x
1113      | insn_format35c_method
1114      | insn_format35c_type
1115      | insn_format35c_method_odex
1116      | insn_format35mi_method
1117      | insn_format35ms_method
1118      | insn_format3rc_method
1119      | insn_format3rc_method_odex
1120      | insn_format3rc_type
1121      | insn_format3rmi_method
1122      | insn_format3rms_method
1123      | insn_format51l
1124      | insn_array_data_directive
1125      | insn_packed_switch_directive
1126      | insn_sparse_switch_directive )
1127  { marker.done(SmaliElementTypes.INSTRUCTION); };
1128  catch [RecognitionException re] {
1129    recover(input, re);
1130    reportError(marker, re, false);
1131  }
1132
1133insn_format10t
1134  : //e.g. goto endloop:
1135    //e.g. goto +3
1136    INSTRUCTION_FORMAT10t label_ref;
1137
1138insn_format10x
1139  : //e.g. return-void
1140    INSTRUCTION_FORMAT10x;
1141
1142insn_format10x_odex
1143  : //e.g. return-void-barrier
1144    INSTRUCTION_FORMAT10x_ODEX;
1145
1146insn_format11n
1147  : //e.g. const/4 v0, 5
1148    INSTRUCTION_FORMAT11n register comma integral_literal;
1149
1150insn_format11x
1151  : //e.g. move-result-object v1
1152    INSTRUCTION_FORMAT11x register;
1153
1154insn_format12x
1155  : //e.g. move v1 v2
1156    instruction_format12x register comma register;
1157
1158insn_format20bc
1159  : //e.g. throw-verification-error generic-error, Lsome/class;
1160    INSTRUCTION_FORMAT20bc VERIFICATION_ERROR_TYPE comma verification_error_reference;
1161
1162insn_format20t
1163  : //e.g. goto/16 endloop:
1164    INSTRUCTION_FORMAT20t label_ref;
1165
1166insn_format21c_field
1167  : //e.g. sget-object v0, java/lang/System/out LJava/io/PrintStream;
1168    INSTRUCTION_FORMAT21c_FIELD register comma fully_qualified_field;
1169
1170insn_format21c_field_odex
1171  : //e.g. sget-object-volatile v0, java/lang/System/out LJava/io/PrintStream;
1172    INSTRUCTION_FORMAT21c_FIELD_ODEX register comma fully_qualified_field;
1173
1174insn_format21c_string
1175  : //e.g. const-string v1, "Hello World!"
1176    INSTRUCTION_FORMAT21c_STRING register comma string_literal;
1177
1178insn_format21c_type
1179  : //e.g. const-class v2, Lorg/jf/HelloWorld2/HelloWorld2;
1180    INSTRUCTION_FORMAT21c_TYPE register comma nonvoid_type_descriptor;
1181
1182insn_format21ih
1183  : //e.g. const/high16 v1, 1234
1184    INSTRUCTION_FORMAT21ih register comma fixed_32bit_literal;
1185
1186insn_format21lh
1187  : //e.g. const-wide/high16 v1, 1234
1188    INSTRUCTION_FORMAT21lh register comma fixed_32bit_literal;
1189
1190insn_format21s
1191  : //e.g. const/16 v1, 1234
1192    INSTRUCTION_FORMAT21s register comma integral_literal;
1193
1194insn_format21t
1195  : //e.g. if-eqz v0, endloop:
1196    INSTRUCTION_FORMAT21t register comma label_ref;
1197
1198insn_format22b
1199  : //e.g. add-int v0, v1, 123
1200    INSTRUCTION_FORMAT22b register comma register comma integral_literal;
1201
1202insn_format22c_field
1203  : //e.g. iput-object v1, v0 org/jf/HelloWorld2/HelloWorld2.helloWorld Ljava/lang/String;
1204    INSTRUCTION_FORMAT22c_FIELD register comma register comma fully_qualified_field;
1205
1206insn_format22c_field_odex
1207  : //e.g. iput-object-volatile v1, v0 org/jf/HelloWorld2/HelloWorld2.helloWorld Ljava/lang/String;
1208    INSTRUCTION_FORMAT22c_FIELD_ODEX register comma register comma fully_qualified_field;
1209
1210insn_format22c_type
1211  : //e.g. instance-of v0, v1, Ljava/lang/String;
1212    INSTRUCTION_FORMAT22c_TYPE register comma register comma nonvoid_type_descriptor;
1213
1214insn_format22cs_field
1215  : //e.g. iget-quick v0, v1, field@0xc
1216    INSTRUCTION_FORMAT22cs_FIELD register comma register comma FIELD_OFFSET;
1217
1218insn_format22s
1219  : //e.g. add-int/lit16 v0, v1, 12345
1220    instruction_format22s register comma register comma integral_literal;
1221
1222insn_format22t
1223  : //e.g. if-eq v0, v1, endloop:
1224    INSTRUCTION_FORMAT22t register comma register comma label_ref;
1225
1226insn_format22x
1227  : //e.g. move/from16 v1, v1234
1228    INSTRUCTION_FORMAT22x register comma register;
1229
1230insn_format23x
1231  : //e.g. add-int v1, v2, v3
1232    INSTRUCTION_FORMAT23x register comma register comma register;
1233
1234insn_format30t
1235  : //e.g. goto/32 endloop:
1236    INSTRUCTION_FORMAT30t label_ref;
1237
1238insn_format31c
1239  : //e.g. const-string/jumbo v1 "Hello World!"
1240    INSTRUCTION_FORMAT31c register comma string_literal;
1241
1242insn_format31i
1243  : //e.g. const v0, 123456
1244    instruction_format31i register comma fixed_32bit_literal;
1245
1246insn_format31t
1247  : //e.g. fill-array-data v0, ArrayData:
1248    INSTRUCTION_FORMAT31t register comma label_ref;
1249
1250insn_format32x
1251  : //e.g. move/16 v4567, v1234
1252    INSTRUCTION_FORMAT32x register comma register;
1253
1254insn_format35c_method
1255  : //e.g. invoke-virtual {v0,v1} java/io/PrintStream/print(Ljava/lang/Stream;)V
1256    INSTRUCTION_FORMAT35c_METHOD register_list comma fully_qualified_method;
1257
1258insn_format35c_type
1259  : //e.g. filled-new-array {v0,v1}, I
1260    INSTRUCTION_FORMAT35c_TYPE register_list comma nonvoid_type_descriptor;
1261
1262insn_format35c_method_odex
1263  : //e.g. invoke-direct {p0}, Ljava/lang/Object;-><init>()V
1264    INSTRUCTION_FORMAT35c_METHOD_ODEX register_list comma fully_qualified_method;
1265
1266insn_format35mi_method
1267  : //e.g. execute-inline {v0, v1}, inline@0x4
1268    INSTRUCTION_FORMAT35mi_METHOD register_list comma INLINE_INDEX;
1269
1270insn_format35ms_method
1271  : //e.g. invoke-virtual-quick {v0, v1}, vtable@0x4
1272    INSTRUCTION_FORMAT35ms_METHOD register_list comma VTABLE_INDEX;
1273
1274insn_format3rc_method
1275  : //e.g. invoke-virtual/range {v25..v26}, java/lang/StringBuilder/append(Ljava/lang/String;)Ljava/lang/StringBuilder;
1276    INSTRUCTION_FORMAT3rc_METHOD register_range comma fully_qualified_method;
1277
1278insn_format3rc_method_odex
1279  : //e.g. invoke-object-init/range {p0}, Ljava/lang/Object;-><init>()V
1280    INSTRUCTION_FORMAT3rc_METHOD_ODEX register_list comma fully_qualified_method;
1281
1282insn_format3rc_type
1283  : //e.g. filled-new-array/range {v0..v6}, I
1284    INSTRUCTION_FORMAT3rc_TYPE register_range comma nonvoid_type_descriptor;
1285
1286insn_format3rmi_method
1287  : //e.g. execute-inline/range {v0 .. v10}, inline@0x14
1288    INSTRUCTION_FORMAT3rmi_METHOD register_range comma INLINE_INDEX;
1289
1290insn_format3rms_method
1291  : //e.g. invoke-virtual-quick/range {v0 .. v10}, vtable@0x14
1292    INSTRUCTION_FORMAT3rms_METHOD register_range comma VTABLE_INDEX;
1293
1294insn_format51l
1295  : //e.g. const-wide v0, 5000000000L
1296    INSTRUCTION_FORMAT51l register comma fixed_literal;
1297
1298insn_array_data_directive
1299  : ARRAY_DATA_DIRECTIVE
1300    integer_literal
1301    array_data_element* end_array_data_directive;
1302
1303end_array_data_directive
1304  : END_ARRAY_DATA_DIRECTIVE;
1305  catch [RecognitionException re] {
1306    Marker errorMarker = mark();
1307    recover(input, re);
1308    reportError(errorMarker, re, false);
1309  }
1310
1311array_data_element
1312  @init { Marker marker = mark(); }
1313  : fixed_literal
1314  { marker.done(SmaliElementTypes.ARRAY_DATA_ELEMENT); };
1315  catch [RecognitionException re] {
1316    recover(input, re);
1317    reportError(marker, re, false);
1318  }
1319
1320insn_packed_switch_directive
1321  : PACKED_SWITCH_DIRECTIVE
1322    fixed_32bit_literal
1323    packed_switch_element*
1324    end_packed_switch_directive;
1325
1326end_packed_switch_directive
1327  : END_PACKED_SWITCH_DIRECTIVE;
1328  catch [RecognitionException re] {
1329    Marker errorMarker = mark();
1330    recover(input, re);
1331    reportError(errorMarker, re, false);
1332  }
1333
1334packed_switch_element
1335  @init { Marker marker = mark(); }
1336  : label_ref
1337  { marker.done(SmaliElementTypes.PACKED_SWITCH_ELEMENT); };
1338  catch [RecognitionException re] {
1339    recover(input, re);
1340    reportError(marker, re, false);
1341  }
1342
1343insn_sparse_switch_directive
1344  : SPARSE_SWITCH_DIRECTIVE
1345    sparse_switch_element*
1346    end_sparse_switch_directive;
1347
1348end_sparse_switch_directive
1349  : END_SPARSE_SWITCH_DIRECTIVE;
1350  catch [RecognitionException re] {
1351    Marker errorMarker = mark();
1352    recover(input, re);
1353    reportError(errorMarker, re, false);
1354  }
1355
1356sparse_switch_element
1357  @init { Marker marker = mark(); }
1358  : fixed_32bit_literal arrow label_ref
1359  { marker.done(SmaliElementTypes.SPARSE_SWITCH_ELEMENT); };
1360  catch [RecognitionException re] {
1361    recover(input, re);
1362    reportError(marker, re, false);
1363  }
1364