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_METHOD_OR_METHOD_HANDLE_TYPE
404  | INSTRUCTION_FORMAT35c_TYPE
405  | INSTRUCTION_FORMAT35mi_METHOD
406  | INSTRUCTION_FORMAT35ms_METHOD
407  | INSTRUCTION_FORMAT51l;
408
409member_name
410  @init { Marker marker = mark(); }
411  : member_name_inner
412  { marker.done(SmaliElementTypes.MEMBER_NAME); };
413
414member_name_inner
415  : (simple_name
416    | MEMBER_NAME);
417  catch [RecognitionException re] {
418    Marker errorMarker = mark();
419    recover(input, re);
420    reportError(errorMarker, re, false);
421  }
422
423method_prototype
424  @init { Marker marker = mark(); }
425  : open_paren param_list close_paren type_descriptor
426    { marker.done(SmaliElementTypes.METHOD_PROTOTYPE); };
427  catch [RecognitionException re] {
428    recover(input, re);
429    reportError(marker, re, false);
430  }
431
432open_paren
433  : OPEN_PAREN;
434  catch [RecognitionException re] {
435    Marker errorMarker = mark();
436    recover(input, re);
437    reportError(errorMarker, re, false);
438  }
439
440close_paren
441  : CLOSE_PAREN;
442  catch [RecognitionException re] {
443    Marker errorMarker = mark();
444    recover(input, re);
445    reportError(errorMarker, re, false);
446  }
447
448open_brace
449  : OPEN_BRACE;
450  catch [RecognitionException re] {
451    Marker errorMarker = mark();
452    recover(input, re);
453    reportError(errorMarker, re, false);
454  }
455
456close_brace
457  : CLOSE_BRACE;
458  catch [RecognitionException re] {
459    Marker errorMarker = mark();
460    recover(input, re);
461    reportError(errorMarker, re, false);
462  }
463
464comma
465  : COMMA;
466  catch [RecognitionException re] {
467    Marker errorMarker = mark();
468    recover(input, re);
469    reportError(errorMarker, re, false);
470  }
471
472colon
473  : COLON;
474  catch [RecognitionException re] {
475    Marker errorMarker = mark();
476    recover(input, re);
477    reportError(errorMarker, re, false);
478  }
479
480dotdot
481  : DOTDOT;
482  catch [RecognitionException re] {
483    Marker errorMarker = mark();
484    recover(input, re);
485    reportError(errorMarker, re, false);
486  }
487
488param_list_inner
489  : param+;
490  catch [RecognitionException re] {
491    Marker errorMarker = mark();
492    recover(input, re);
493    reportError(errorMarker, re, false);
494  }
495
496param_list
497  @init { Marker marker = mark(); }
498  : param_list_inner?
499    { marker.done(SmaliElementTypes.METHOD_PARAM_LIST); };
500
501param
502  @init {
503    Marker marker = mark();
504    mark().done(SmaliElementTypes.MODIFIER_LIST);
505  }
506  : nonvoid_type_descriptor
507  { marker.done(SmaliElementTypes.METHOD_PARAMETER); };
508  catch [RecognitionException re] {
509    recover(input, re);
510    reportError(marker, re, false);
511  }
512
513method_prototype_reference
514  : open_paren param_list_reference close_paren type_descriptor;
515
516param_list_reference
517  @init {
518    Marker marker = mark();
519  }
520  : nonvoid_type_descriptor*
521  { marker.done(SmaliElementTypes.METHOD_REFERENCE_PARAM_LIST); };
522  catch [RecognitionException re] {
523    recover(input, re);
524    reportError(marker, re, false);
525  }
526
527primitive_type
528  @init { Marker marker = mark(); }
529  : (PRIMITIVE_TYPE | PARAM_LIST_OR_ID_PRIMITIVE_TYPE)
530  { finishToken(marker, SmaliElementTypes.PRIMITIVE_TYPE); };
531  catch [RecognitionException re] {
532    recover(input, re);
533    reportError(marker, re, false);
534  }
535
536class_descriptor
537  @init { Marker marker = mark(); }
538  : CLASS_DESCRIPTOR
539  { finishToken(marker, SmaliElementTypes.CLASS_TYPE); };
540  catch [RecognitionException re] {
541    recover(input, re);
542    reportError(marker, re, false);
543  }
544
545array_descriptor
546  @init { Marker marker = mark(); }
547  : ARRAY_TYPE_PREFIX (primitive_type | class_descriptor)
548  { finishToken(marker, SmaliElementTypes.ARRAY_TYPE); };
549  catch [RecognitionException re] {
550    recover(input, re);
551    reportError(marker, re, false);
552  }
553
554void_type
555  @init { Marker marker = mark(); }
556  : VOID_TYPE
557  { finishToken(marker, SmaliElementTypes.VOID_TYPE); };
558  catch [RecognitionException re] {
559    recover(input, re);
560    reportError(marker, re, false);
561  }
562
563type_descriptor
564  : void_type
565  | primitive_type
566  | class_descriptor
567  | array_descriptor;
568  catch [RecognitionException re] {
569    Marker marker = mark();
570    recover(input, re);
571    reportError(marker, re, false);
572  }
573
574nonvoid_type_descriptor
575  : primitive_type
576  | class_descriptor
577  | array_descriptor;
578  catch [RecognitionException re] {
579    Marker marker = mark();
580    recover(input, re);
581    reportError(marker, re, false);
582  }
583
584reference_type_descriptor
585  : class_descriptor
586  | array_descriptor;
587  catch [RecognitionException re] {
588    Marker marker = mark();
589    recover(input, re);
590    reportError(marker, re, false);
591  }
592
593null_literal
594  @init { Marker marker = mark(); }
595  : NULL_LITERAL
596  { finishToken(marker, SmaliElementTypes.LITERAL); };
597  catch [RecognitionException re] {
598    recover(input, re);
599    reportError(marker, re, false);
600  }
601
602bool_literal
603  @init { Marker marker = mark(); }
604  : BOOL_LITERAL
605  { finishToken(marker, SmaliElementTypes.LITERAL); };
606  catch [RecognitionException re] {
607    recover(input, re);
608    reportError(marker, re, false);
609  }
610
611byte_literal
612  @init { Marker marker = mark(); }
613  : BYTE_LITERAL
614  { finishToken(marker, SmaliElementTypes.LITERAL); };
615  catch [RecognitionException re] {
616    recover(input, re);
617    reportError(marker, re, false);
618  }
619
620char_literal
621  @init { Marker marker = mark(); }
622  : CHAR_LITERAL
623  { finishToken(marker, SmaliElementTypes.LITERAL); };
624  catch [RecognitionException re] {
625    recover(input, re);
626    reportError(marker, re, false);
627  }
628
629short_literal
630  @init { Marker marker = mark(); }
631  : SHORT_LITERAL
632  { finishToken(marker, SmaliElementTypes.LITERAL); };
633  catch [RecognitionException re] {
634    recover(input, re);
635    reportError(marker, re, false);
636  }
637
638integer_literal
639  @init { Marker marker = mark(); }
640  : ( POSITIVE_INTEGER_LITERAL
641    | NEGATIVE_INTEGER_LITERAL)
642  { finishToken(marker, SmaliElementTypes.LITERAL); };
643  catch [RecognitionException re] {
644    recover(input, re);
645    reportError(marker, re, false);
646  }
647
648long_literal
649  @init { Marker marker = mark(); }
650  : LONG_LITERAL
651  { finishToken(marker, SmaliElementTypes.LITERAL); };
652  catch [RecognitionException re] {
653    recover(input, re);
654    reportError(marker, re, false);
655  }
656
657float_literal
658  @init { Marker marker = mark(); }
659  : ( FLOAT_LITERAL_OR_ID
660    | FLOAT_LITERAL )
661  { finishToken(marker, SmaliElementTypes.LITERAL); };
662  catch [RecognitionException re] {
663    recover(input, re);
664    reportError(marker, re, false);
665  }
666
667double_literal
668  @init { Marker marker = mark(); }
669  : ( DOUBLE_LITERAL_OR_ID
670    | DOUBLE_LITERAL)
671  { finishToken(marker, SmaliElementTypes.LITERAL); };
672  catch [RecognitionException re] {
673    recover(input, re);
674    reportError(marker, re, false);
675  }
676
677string_literal
678  @init { Marker marker = mark(); }
679  : STRING_LITERAL
680  { finishToken(marker, SmaliElementTypes.LITERAL); };
681  catch [RecognitionException re] {
682    recover(input, re);
683    reportError(marker, re, false);
684  }
685
686array_literal
687  @init { Marker marker = mark(); }
688  : open_brace (literal (comma literal)* | ) close_brace
689  { marker.done(SmaliElementTypes.LITERAL); };
690  catch [RecognitionException re] {
691    recover(input, re);
692    reportError(marker, re, false);
693  }
694
695enum_literal
696  @init { Marker marker = mark(); }
697  : ENUM_DIRECTIVE fully_qualified_field
698  { marker.done(SmaliElementTypes.LITERAL); };
699  catch [RecognitionException re] {
700    recover(input, re);
701    reportError(marker, re, false);
702  }
703
704type_field_method_literal
705  @init { Marker marker = mark(); }
706  : ( type_descriptor
707    | fully_qualified_field
708    | fully_qualified_method)
709  { marker.done(SmaliElementTypes.LITERAL); };
710  catch [RecognitionException re] {
711    recover(input, re);
712    reportError(marker, re, false);
713  }
714
715subannotation
716  @init {
717    Marker marker = mark();
718    Marker paramListMarker = null;
719  }
720  : SUBANNOTATION_DIRECTIVE class_descriptor
721    { paramListMarker = mark(); }
722    annotation_element*
723    { paramListMarker.done(SmaliElementTypes.ANNOTATION_PARAMETER_LIST); }
724    end_subannotation_directive
725    { marker.done(SmaliElementTypes.ANNOTATION); };
726  catch [RecognitionException re] {
727    recover(input, re);
728    reportError(marker, re, false);
729  }
730
731end_subannotation_directive
732  : END_SUBANNOTATION_DIRECTIVE;
733  catch [RecognitionException re] {
734    Marker errorMarker = mark();
735    recover(input, re);
736    reportError(errorMarker, re, false);
737  }
738
739literal
740  : long_literal
741  | integer_literal
742  | short_literal
743  | byte_literal
744  | float_literal
745  | double_literal
746  | char_literal
747  | string_literal
748  | bool_literal
749  | null_literal
750  | array_literal
751  | subannotation
752  | type_field_method_literal
753  | enum_literal;
754  catch [RecognitionException re] {
755    Marker errorMarker = mark();
756    recover(input, re);
757    reportError(errorMarker, re, false);
758  }
759
760string_or_null_literal
761  : string_literal
762  | null_literal;
763  catch [RecognitionException re] {
764    Marker errorMarker = mark();
765    recover(input, re);
766    reportError(errorMarker, re, false);
767  }
768
769integral_literal
770  : long_literal
771  | integer_literal
772  | short_literal
773  | char_literal
774  | byte_literal;
775  catch [RecognitionException re] {
776    Marker errorMarker = mark();
777    recover(input, re);
778    reportError(errorMarker, re, false);
779  }
780
781fixed_32bit_literal
782  : long_literal
783  | integer_literal
784      | short_literal
785  | byte_literal
786  | float_literal
787  | char_literal
788  | bool_literal;
789  catch [RecognitionException re] {
790    Marker errorMarker = mark();
791    recover(input, re);
792    reportError(errorMarker, re, false);
793  }
794
795fixed_literal
796  : integer_literal
797  | long_literal
798  | short_literal
799  | byte_literal
800  | float_literal
801  | double_literal
802  | char_literal
803  | bool_literal;
804  catch [RecognitionException re] {
805    Marker errorMarker = mark();
806    recover(input, re);
807    reportError(errorMarker, re, false);
808  }
809
810annotation_element
811  @init {
812    Marker marker = mark();
813    Marker nameMarker = null;
814  }
815  : { nameMarker = mark(); } simple_name { nameMarker.done(SmaliElementTypes.ANNOTATION_ELEMENT_NAME); }
816    equal literal
817  { marker.done(SmaliElementTypes.ANNOTATION_ELEMENT); };
818  catch [RecognitionException re] {
819    recover(input, re);
820    reportError(marker, re, false);
821  }
822
823equal
824  : EQUAL;
825  catch [RecognitionException re] {
826    Marker errorMarker = mark();
827    recover(input, re);
828    reportError(errorMarker, re, false);
829  }
830
831annotation
832  @init {
833    Marker marker = mark();
834    Marker paramListMarker = null;
835  }
836  : ANNOTATION_DIRECTIVE annotation_visibility class_descriptor
837    { paramListMarker = mark(); }
838    annotation_element*
839    { paramListMarker.done(SmaliElementTypes.ANNOTATION_PARAMETER_LIST); }
840    end_annotation_directive
841  { marker.done(SmaliElementTypes.ANNOTATION); };
842
843annotation_visibility
844  : ANNOTATION_VISIBILITY;
845  catch [RecognitionException re] {
846    Marker errorMarker = mark();
847    recover(input, re);
848    reportError(errorMarker, re, false);
849  }
850
851end_annotation_directive
852  : END_ANNOTATION_DIRECTIVE;
853  catch [RecognitionException re] {
854    Marker errorMarker = mark();
855    recover(input, re);
856    reportError(errorMarker, re, false);
857  }
858
859arrow
860  : ARROW;
861  catch [RecognitionException re] {
862    Marker errorMarker = mark();
863    recover(input, re);
864    reportError(errorMarker, re, false);
865  }
866
867fully_qualified_method
868  @init { Marker marker = mark(); }
869  : reference_type_descriptor arrow member_name method_prototype_reference
870  { marker.done(SmaliElementTypes.METHOD_REFERENCE); };
871  catch [RecognitionException re] {
872    recover(input, re);
873    reportError(marker, re, false);
874  }
875
876fully_qualified_field
877  @init { Marker marker = mark(); }
878  : reference_type_descriptor arrow member_name colon nonvoid_type_descriptor
879  { marker.done(SmaliElementTypes.FIELD_REFERENCE); };
880  catch [RecognitionException re] {
881    recover(input, re);
882    reportError(marker, re, false);
883  }
884
885label
886  @init { Marker marker = mark(); }
887  : colon simple_name
888  { marker.done(SmaliElementTypes.LABEL); };
889  catch [RecognitionException re] {
890    recover(input, re);
891    reportError(marker, re, false);
892  }
893
894label_ref
895  @init { Marker marker = mark(); }
896  : colon simple_name
897  { marker.done(SmaliElementTypes.LABEL_REFERENCE); };
898  catch [RecognitionException re] {
899    recover(input, re);
900    reportError(marker, re, false);
901  }
902
903register_list
904  : open_brace (register (comma register)*)? close_brace;
905
906register_range
907  : open_brace (register (dotdot register)?)? close_brace;
908
909verification_error_reference
910  : class_descriptor | fully_qualified_field | fully_qualified_method;
911
912catch_directive
913  @init { Marker marker = mark(); }
914  : CATCH_DIRECTIVE nonvoid_type_descriptor open_brace label_ref dotdot label_ref close_brace label_ref
915  { marker.done(SmaliElementTypes.CATCH_STATEMENT); };
916  catch [RecognitionException re] {
917    recover(input, re);
918    reportError(marker, re, false);
919  }
920
921catchall_directive
922  @init { Marker marker = mark(); }
923  : CATCHALL_DIRECTIVE open_brace label_ref dotdot label_ref close_brace label_ref
924  { marker.done(SmaliElementTypes.CATCH_ALL_STATEMENT); };
925  catch [RecognitionException re] {
926    recover(input, re);
927    reportError(marker, re, false);
928  }
929
930/*When there are annotations immediately after a parameter definition, we don't know whether they are parameter annotations
931or method annotations until we determine if there is an .end parameter directive. In either case, we still "consume" and parse
932the annotations. If it turns out that they are parameter annotations, we include them in the I_PARAMETER AST. Otherwise, we
933add them to the $statements_and_directives::methodAnnotations list*/
934parameter_directive
935  @init {
936    Marker marker = mark();
937    Marker annotationsMarker = null;
938    boolean gotEndParam = false;
939  }
940  : PARAMETER_DIRECTIVE register
941    (comma local_name)?
942    { annotationsMarker = mark(); } parameter_annotations
943    ( end_parameter_directive { gotEndParam = true; } )?
944  {
945    if (gotEndParam) {
946      annotationsMarker.drop();
947      marker.done(SmaliElementTypes.PARAMETER_STATEMENT);
948    } else {
949      marker.doneBefore(SmaliElementTypes.PARAMETER_STATEMENT, annotationsMarker);
950      annotationsMarker.drop();
951    }
952  };
953  catch [RecognitionException re] {
954    if (annotationsMarker != null) {
955        annotationsMarker.drop();
956    }
957    recover(input, re);
958    reportError(marker, re, false);
959  }
960
961parameter_annotations
962  : ((ANNOTATION_DIRECTIVE)=> annotation)*;
963  catch [RecognitionException re] {
964    Marker errorMarker = mark();
965    recover(input, re);
966    reportError(errorMarker, re, false);
967  }
968
969end_parameter_directive
970  : END_PARAMETER_DIRECTIVE;
971
972local_name
973  @init {
974    Marker localNameMarker = mark();
975    Marker stringMarker = mark();
976  }
977  : STRING_LITERAL
978  {
979    finishToken(stringMarker, SmaliElementTypes.LITERAL);
980    finishToken(localNameMarker, SmaliElementTypes.LOCAL_NAME);
981  };
982  catch [RecognitionException re] {
983      stringMarker.drop();
984      recover(input, re);
985      reportError(localNameMarker, re, false);
986  }
987
988register
989  @init { Marker marker = mark(); }
990  : REGISTER
991  { finishToken(marker, SmaliElementTypes.REGISTER_REFERENCE); };
992  catch [RecognitionException re] {
993    recover(input, re);
994    reportError(marker, re, false);
995  }
996
997debug_directive
998  : line_directive
999  | local_directive
1000  | end_local_directive
1001  | restart_local_directive
1002  | prologue_directive
1003  | epilogue_directive
1004  | source_directive;
1005
1006line_directive
1007  @init { Marker marker = mark(); }
1008  : LINE_DIRECTIVE integral_literal
1009  { marker.done(SmaliElementTypes.LINE_DEBUG_STATEMENT); };
1010  catch [RecognitionException re] {
1011    recover(input, re);
1012    reportError(marker, re, false);
1013  }
1014
1015local_directive
1016  @init { Marker marker = mark(); }
1017  : LOCAL_DIRECTIVE register (comma string_or_null_literal colon type_descriptor
1018                              (comma string_literal)? )?
1019  { marker.done(SmaliElementTypes.LOCAL_DEBUG_STATEMENT); };
1020  catch [RecognitionException re] {
1021    recover(input, re);
1022    reportError(marker, re, false);
1023  }
1024
1025end_local_directive
1026  @init { Marker marker = mark(); }
1027  : END_LOCAL_DIRECTIVE register
1028  { marker.done(SmaliElementTypes.END_LOCAL_DEBUG_STATEMENT); };
1029  catch [RecognitionException re] {
1030    recover(input, re);
1031    reportError(marker, re, false);
1032  }
1033
1034restart_local_directive
1035  @init { Marker marker = mark(); }
1036  : RESTART_LOCAL_DIRECTIVE register
1037  { marker.done(SmaliElementTypes.RESTART_LOCAL_DEBUG_STATEMENT); };
1038  catch [RecognitionException re] {
1039    recover(input, re);
1040    reportError(marker, re, false);
1041  }
1042
1043prologue_directive
1044  @init { Marker marker = mark(); }
1045  : PROLOGUE_DIRECTIVE
1046  { marker.done(SmaliElementTypes.PROLOGUE_DEBUG_STATEMENT); };
1047  catch [RecognitionException re] {
1048    recover(input, re);
1049    reportError(marker, re, false);
1050  }
1051
1052epilogue_directive
1053  @init { Marker marker = mark(); }
1054  : EPILOGUE_DIRECTIVE
1055  { marker.done(SmaliElementTypes.EPILOGUE_DEBUG_STATEMENT); };
1056  catch [RecognitionException re] {
1057    recover(input, re);
1058    reportError(marker, re, false);
1059  }
1060
1061source_directive
1062  @init { Marker marker = mark(); }
1063  : SOURCE_DIRECTIVE string_literal?
1064  { marker.done(SmaliElementTypes.SOURCE_DEBUG_STATEMENT); };
1065  catch [RecognitionException re] {
1066    recover(input, re);
1067    reportError(marker, re, false);
1068  }
1069
1070instruction_format12x
1071  : INSTRUCTION_FORMAT12x
1072  | INSTRUCTION_FORMAT12x_OR_ID;
1073
1074instruction_format22s
1075  : INSTRUCTION_FORMAT22s
1076  | INSTRUCTION_FORMAT22s_OR_ID;
1077
1078instruction_format31i
1079  : INSTRUCTION_FORMAT31i
1080  | INSTRUCTION_FORMAT31i_OR_ID;
1081
1082instruction
1083  @init { Marker marker = mark(); }
1084  : ( insn_format10t
1085    | insn_format10x
1086    | insn_format10x_odex
1087    | insn_format11n
1088    | insn_format11x
1089    | insn_format12x
1090    | insn_format20bc
1091    | insn_format20t
1092    | insn_format21c_field
1093    | insn_format21c_field_odex
1094    | insn_format21c_string
1095      | insn_format21c_type
1096      | insn_format21ih
1097      | insn_format21lh
1098      | insn_format21s
1099      | insn_format21t
1100      | insn_format22b
1101      | insn_format22c_field
1102      | insn_format22c_field_odex
1103      | insn_format22c_type
1104      | insn_format22cs_field
1105      | insn_format22s
1106      | insn_format22t
1107      | insn_format22x
1108      | insn_format23x
1109      | insn_format30t
1110      | insn_format31c
1111      | insn_format31i
1112      | insn_format31t
1113      | insn_format32x
1114      | insn_format35c_method
1115      | insn_format35c_type
1116      | insn_format35c_method_odex
1117      | insn_format35mi_method
1118      | insn_format35ms_method
1119      | insn_format3rc_method
1120      | insn_format3rc_method_odex
1121      | insn_format3rc_type
1122      | insn_format3rmi_method
1123      | insn_format3rms_method
1124      | insn_format51l
1125      | insn_array_data_directive
1126      | insn_packed_switch_directive
1127      | insn_sparse_switch_directive )
1128  { marker.done(SmaliElementTypes.INSTRUCTION); };
1129  catch [RecognitionException re] {
1130    recover(input, re);
1131    reportError(marker, re, false);
1132  }
1133
1134insn_format10t
1135  : //e.g. goto endloop:
1136    //e.g. goto +3
1137    INSTRUCTION_FORMAT10t label_ref;
1138
1139insn_format10x
1140  : //e.g. return-void
1141    INSTRUCTION_FORMAT10x;
1142
1143insn_format10x_odex
1144  : //e.g. return-void-barrier
1145    INSTRUCTION_FORMAT10x_ODEX;
1146
1147insn_format11n
1148  : //e.g. const/4 v0, 5
1149    INSTRUCTION_FORMAT11n register comma integral_literal;
1150
1151insn_format11x
1152  : //e.g. move-result-object v1
1153    INSTRUCTION_FORMAT11x register;
1154
1155insn_format12x
1156  : //e.g. move v1 v2
1157    instruction_format12x register comma register;
1158
1159insn_format20bc
1160  : //e.g. throw-verification-error generic-error, Lsome/class;
1161    INSTRUCTION_FORMAT20bc VERIFICATION_ERROR_TYPE comma verification_error_reference;
1162
1163insn_format20t
1164  : //e.g. goto/16 endloop:
1165    INSTRUCTION_FORMAT20t label_ref;
1166
1167insn_format21c_field
1168  : //e.g. sget-object v0, java/lang/System/out LJava/io/PrintStream;
1169    INSTRUCTION_FORMAT21c_FIELD register comma fully_qualified_field;
1170
1171insn_format21c_field_odex
1172  : //e.g. sget-object-volatile v0, java/lang/System/out LJava/io/PrintStream;
1173    INSTRUCTION_FORMAT21c_FIELD_ODEX register comma fully_qualified_field;
1174
1175insn_format21c_string
1176  : //e.g. const-string v1, "Hello World!"
1177    INSTRUCTION_FORMAT21c_STRING register comma string_literal;
1178
1179insn_format21c_type
1180  : //e.g. const-class v2, Lorg/jf/HelloWorld2/HelloWorld2;
1181    INSTRUCTION_FORMAT21c_TYPE register comma nonvoid_type_descriptor;
1182
1183insn_format21ih
1184  : //e.g. const/high16 v1, 1234
1185    INSTRUCTION_FORMAT21ih register comma fixed_32bit_literal;
1186
1187insn_format21lh
1188  : //e.g. const-wide/high16 v1, 1234
1189    INSTRUCTION_FORMAT21lh register comma fixed_32bit_literal;
1190
1191insn_format21s
1192  : //e.g. const/16 v1, 1234
1193    INSTRUCTION_FORMAT21s register comma integral_literal;
1194
1195insn_format21t
1196  : //e.g. if-eqz v0, endloop:
1197    INSTRUCTION_FORMAT21t register comma label_ref;
1198
1199insn_format22b
1200  : //e.g. add-int v0, v1, 123
1201    INSTRUCTION_FORMAT22b register comma register comma integral_literal;
1202
1203insn_format22c_field
1204  : //e.g. iput-object v1, v0 org/jf/HelloWorld2/HelloWorld2.helloWorld Ljava/lang/String;
1205    INSTRUCTION_FORMAT22c_FIELD register comma register comma fully_qualified_field;
1206
1207insn_format22c_field_odex
1208  : //e.g. iput-object-volatile v1, v0 org/jf/HelloWorld2/HelloWorld2.helloWorld Ljava/lang/String;
1209    INSTRUCTION_FORMAT22c_FIELD_ODEX register comma register comma fully_qualified_field;
1210
1211insn_format22c_type
1212  : //e.g. instance-of v0, v1, Ljava/lang/String;
1213    INSTRUCTION_FORMAT22c_TYPE register comma register comma nonvoid_type_descriptor;
1214
1215insn_format22cs_field
1216  : //e.g. iget-quick v0, v1, field@0xc
1217    INSTRUCTION_FORMAT22cs_FIELD register comma register comma FIELD_OFFSET;
1218
1219insn_format22s
1220  : //e.g. add-int/lit16 v0, v1, 12345
1221    instruction_format22s register comma register comma integral_literal;
1222
1223insn_format22t
1224  : //e.g. if-eq v0, v1, endloop:
1225    INSTRUCTION_FORMAT22t register comma register comma label_ref;
1226
1227insn_format22x
1228  : //e.g. move/from16 v1, v1234
1229    INSTRUCTION_FORMAT22x register comma register;
1230
1231insn_format23x
1232  : //e.g. add-int v1, v2, v3
1233    INSTRUCTION_FORMAT23x register comma register comma register;
1234
1235insn_format30t
1236  : //e.g. goto/32 endloop:
1237    INSTRUCTION_FORMAT30t label_ref;
1238
1239insn_format31c
1240  : //e.g. const-string/jumbo v1 "Hello World!"
1241    INSTRUCTION_FORMAT31c register comma string_literal;
1242
1243insn_format31i
1244  : //e.g. const v0, 123456
1245    instruction_format31i register comma fixed_32bit_literal;
1246
1247insn_format31t
1248  : //e.g. fill-array-data v0, ArrayData:
1249    INSTRUCTION_FORMAT31t register comma label_ref;
1250
1251insn_format32x
1252  : //e.g. move/16 v4567, v1234
1253    INSTRUCTION_FORMAT32x register comma register;
1254
1255insn_format35c_method
1256  : //e.g. invoke-virtual {v0,v1} java/io/PrintStream/print(Ljava/lang/Stream;)V
1257    (INSTRUCTION_FORMAT35c_METHOD | INSTRUCTION_FORMAT35c_METHOD_OR_METHOD_HANDLE_TYPE) register_list comma fully_qualified_method;
1258
1259insn_format35c_type
1260  : //e.g. filled-new-array {v0,v1}, I
1261    INSTRUCTION_FORMAT35c_TYPE register_list comma nonvoid_type_descriptor;
1262
1263insn_format35c_method_odex
1264  : //e.g. invoke-direct {p0}, Ljava/lang/Object;-><init>()V
1265    INSTRUCTION_FORMAT35c_METHOD_ODEX register_list comma fully_qualified_method;
1266
1267insn_format35mi_method
1268  : //e.g. execute-inline {v0, v1}, inline@0x4
1269    INSTRUCTION_FORMAT35mi_METHOD register_list comma INLINE_INDEX;
1270
1271insn_format35ms_method
1272  : //e.g. invoke-virtual-quick {v0, v1}, vtable@0x4
1273    INSTRUCTION_FORMAT35ms_METHOD register_list comma VTABLE_INDEX;
1274
1275insn_format3rc_method
1276  : //e.g. invoke-virtual/range {v25..v26}, java/lang/StringBuilder/append(Ljava/lang/String;)Ljava/lang/StringBuilder;
1277    INSTRUCTION_FORMAT3rc_METHOD register_range comma fully_qualified_method;
1278
1279insn_format3rc_method_odex
1280  : //e.g. invoke-object-init/range {p0}, Ljava/lang/Object;-><init>()V
1281    INSTRUCTION_FORMAT3rc_METHOD_ODEX register_list comma fully_qualified_method;
1282
1283insn_format3rc_type
1284  : //e.g. filled-new-array/range {v0..v6}, I
1285    INSTRUCTION_FORMAT3rc_TYPE register_range comma nonvoid_type_descriptor;
1286
1287insn_format3rmi_method
1288  : //e.g. execute-inline/range {v0 .. v10}, inline@0x14
1289    INSTRUCTION_FORMAT3rmi_METHOD register_range comma INLINE_INDEX;
1290
1291insn_format3rms_method
1292  : //e.g. invoke-virtual-quick/range {v0 .. v10}, vtable@0x14
1293    INSTRUCTION_FORMAT3rms_METHOD register_range comma VTABLE_INDEX;
1294
1295insn_format51l
1296  : //e.g. const-wide v0, 5000000000L
1297    INSTRUCTION_FORMAT51l register comma fixed_literal;
1298
1299insn_array_data_directive
1300  : ARRAY_DATA_DIRECTIVE
1301    integer_literal
1302    array_data_element* end_array_data_directive;
1303
1304end_array_data_directive
1305  : END_ARRAY_DATA_DIRECTIVE;
1306  catch [RecognitionException re] {
1307    Marker errorMarker = mark();
1308    recover(input, re);
1309    reportError(errorMarker, re, false);
1310  }
1311
1312array_data_element
1313  @init { Marker marker = mark(); }
1314  : fixed_literal
1315  { marker.done(SmaliElementTypes.ARRAY_DATA_ELEMENT); };
1316  catch [RecognitionException re] {
1317    recover(input, re);
1318    reportError(marker, re, false);
1319  }
1320
1321insn_packed_switch_directive
1322  : PACKED_SWITCH_DIRECTIVE
1323    fixed_32bit_literal
1324    packed_switch_element*
1325    end_packed_switch_directive;
1326
1327end_packed_switch_directive
1328  : END_PACKED_SWITCH_DIRECTIVE;
1329  catch [RecognitionException re] {
1330    Marker errorMarker = mark();
1331    recover(input, re);
1332    reportError(errorMarker, re, false);
1333  }
1334
1335packed_switch_element
1336  @init { Marker marker = mark(); }
1337  : label_ref
1338  { marker.done(SmaliElementTypes.PACKED_SWITCH_ELEMENT); };
1339  catch [RecognitionException re] {
1340    recover(input, re);
1341    reportError(marker, re, false);
1342  }
1343
1344insn_sparse_switch_directive
1345  : SPARSE_SWITCH_DIRECTIVE
1346    sparse_switch_element*
1347    end_sparse_switch_directive;
1348
1349end_sparse_switch_directive
1350  : END_SPARSE_SWITCH_DIRECTIVE;
1351  catch [RecognitionException re] {
1352    Marker errorMarker = mark();
1353    recover(input, re);
1354    reportError(errorMarker, re, false);
1355  }
1356
1357sparse_switch_element
1358  @init { Marker marker = mark(); }
1359  : fixed_32bit_literal arrow label_ref
1360  { marker.done(SmaliElementTypes.SPARSE_SWITCH_ELEMENT); };
1361  catch [RecognitionException re] {
1362    recover(input, re);
1363    reportError(marker, re, false);
1364  }
1365