| /* |
| * [The "BSD licence"] |
| * Copyright (c) 2010 Ben Gruver |
| * All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * 3. The name of the author may not be used to endorse or promote products |
| * derived from this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
| * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
| * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
| * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
| * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
| * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
| * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| parser grammar smalideaParser; |
| |
| options { |
| tokenVocab=smaliParser; |
| } |
| |
| @header { |
| package org.jf.smalidea; |
| |
| import com.intellij.lang.PsiBuilder; |
| import com.intellij.lang.PsiBuilder.Marker; |
| import com.intellij.psi.tree.IElementType; |
| import org.jf.smalidea.psi.SmaliElementTypes; |
| |
| import javax.annotation.Nonnull; |
| import javax.annotation.Nullable; |
| } |
| |
| |
| @members { |
| private PsiBuilder psiBuilder; |
| |
| public void setPsiBuilder(PsiBuilder psiBuilder) { |
| this.psiBuilder = psiBuilder; |
| } |
| |
| public Marker mark() { |
| return psiBuilder.mark(); |
| } |
| |
| protected void syncToFollows(boolean acceptEof) { |
| BitSet follow = computeErrorRecoverySet(); |
| int mark = input.mark(); |
| Marker marker = null; |
| try { |
| int token = input.LA(1); |
| while (!follow.member(token)) { |
| if (token == Token.EOF) { |
| if (acceptEof) { |
| break; |
| } |
| input.rewind(mark); |
| mark = -1; |
| marker = null; |
| return; |
| } |
| if (marker == null) { |
| marker = mark(); |
| } |
| input.consume(); |
| token = input.LA(1); |
| } |
| } finally { |
| if (mark != -1) { |
| input.release(mark); |
| } |
| if (marker != null) { |
| marker.error("Unexpected tokens"); |
| } |
| } |
| } |
| |
| @Override |
| protected Object recoverFromMismatchedToken(IntStream input, int ttype, BitSet follow) |
| throws RecognitionException |
| { |
| RecognitionException e = null; |
| // if next token is what we are looking for then "delete" this token |
| if ( mismatchIsUnwantedToken(input, ttype) ) { |
| e = new UnwantedTokenException(ttype, input); |
| beginResync(); |
| Marker mark = mark(); |
| input.consume(); // simply delete extra token |
| mark.error(getErrorMessage(e, tokenNames)); |
| endResync(); |
| reportError(null, e, true); // report after consuming so AW sees the token in the exception |
| // we want to return the token we're actually matching |
| Object matchedSymbol = getCurrentInputSymbol(input); |
| input.consume(); // move past ttype token as if all were ok |
| return matchedSymbol; |
| } |
| // can't recover with single token deletion, try insertion |
| if ( mismatchIsMissingToken(input, follow) ) { |
| Object inserted = getMissingSymbol(input, e, ttype, follow); |
| Marker mark = mark(); |
| e = new MissingTokenException(ttype, input, inserted); |
| mark.error(getErrorMessage(e, tokenNames)); |
| reportError(null, e, true); // report after inserting so AW sees the token in the exception |
| return inserted; |
| } |
| |
| // even that didn't work; must throw the exception |
| e = new MismatchedTokenException(ttype, input); |
| throw e; |
| } |
| |
| @Override |
| public void reportError(RecognitionException e) { |
| reportError(mark(), e, false); |
| } |
| |
| public void reportError(@Nullable Marker marker, RecognitionException e, boolean alreadyReported) { |
| // if we've already reported an error and have not matched a token |
| // yet successfully, don't report any errors. |
| if ( state.errorRecovery ) { |
| if (marker != null) { |
| marker.drop(); |
| } |
| return; |
| } |
| state.syntaxErrors++; // don't count spurious |
| state.errorRecovery = true; |
| |
| if (marker != null) { |
| if (!alreadyReported) { |
| displayRecognitionError(marker, this.getTokenNames(), e); |
| } else { |
| marker.drop(); |
| } |
| } |
| } |
| |
| public void finishToken(Marker marker, IElementType elementType) { |
| if (state.errorRecovery) { |
| marker.drop(); |
| } else { |
| marker.done(elementType); |
| } |
| } |
| |
| @Override |
| public void displayRecognitionError(String[] tokenNames, RecognitionException e) { |
| displayRecognitionError(mark(), tokenNames, e); |
| } |
| |
| public void displayRecognitionError(@Nonnull Marker marker, String[] tokenNames, RecognitionException e) { |
| marker.error(getErrorMessage(e, tokenNames)); |
| } |
| } |
| |
| sync[boolean toEof] |
| @init { syncToFollows($toEof); } |
| : /*epsilon*/; |
| |
| smali_file |
| @init { |
| mark().done(SmaliElementTypes.MODIFIER_LIST); |
| mark().done(SmaliElementTypes.EXTENDS_LIST); |
| mark().done(SmaliElementTypes.IMPLEMENTS_LIST); |
| } |
| : |
| ( |
| ( class_spec |
| | super_spec |
| | implements_spec |
| | source_spec |
| | method |
| | field |
| | annotation |
| ) |
| sync[true] |
| )+ |
| EOF; |
| |
| class_spec |
| @init { Marker marker = mark(); } |
| : CLASS_DIRECTIVE access_list class_descriptor |
| { marker.done(SmaliElementTypes.CLASS_STATEMENT); }; |
| catch [RecognitionException re] { |
| recover(input, re); |
| reportError(marker, re, false); |
| } |
| |
| super_spec |
| @init { Marker marker = mark(); } |
| : SUPER_DIRECTIVE class_descriptor |
| { marker.done(SmaliElementTypes.SUPER_STATEMENT); }; |
| catch [RecognitionException re] { |
| recover(input, re); |
| reportError(marker, re, false); |
| } |
| |
| implements_spec |
| @init { Marker marker = mark(); } |
| : IMPLEMENTS_DIRECTIVE class_descriptor |
| { marker.done(SmaliElementTypes.IMPLEMENTS_STATEMENT); }; |
| catch [RecognitionException re] { |
| recover(input, re); |
| reportError(marker, re, false); |
| } |
| |
| source_spec |
| @init { Marker marker = mark(); } |
| : SOURCE_DIRECTIVE string_literal |
| { marker.done(SmaliElementTypes.SOURCE_STATEMENT); }; |
| catch [RecognitionException re] { |
| recover(input, re); |
| reportError(marker, re, false); |
| } |
| |
| access_list |
| @init { Marker marker = mark(); } |
| : ACCESS_SPEC* |
| { marker.done(SmaliElementTypes.ACCESS_LIST); }; |
| catch [RecognitionException re] { |
| recover(input, re); |
| reportError(marker, re, false); |
| } |
| |
| /*When there are annotations immediately after a field definition, we don't know whether they are field annotations |
| or class annotations until we determine if there is an .end field directive. In either case, we still "consume" and parse |
| the annotations. If it turns out that they are field annotations, we include them in the I_FIELD AST. Otherwise, we |
| add them to the $smali_file::classAnnotations list*/ |
| field |
| @init { |
| Marker marker = mark(); |
| mark().done(SmaliElementTypes.MODIFIER_LIST); |
| Marker annotationsMarker = null; |
| boolean classAnnotations = true; |
| } |
| : FIELD_DIRECTIVE |
| access_list |
| member_name COLON nonvoid_type_descriptor |
| field_initializer? |
| ( END_FIELD_DIRECTIVE |
| | (ANNOTATION_DIRECTIVE)=> ( {annotationsMarker = mark();} |
| ((ANNOTATION_DIRECTIVE)=> annotation)+ |
| (END_FIELD_DIRECTIVE {classAnnotations = false;})? |
| ) |
| | /*epsilon*/ |
| ) |
| { |
| if (annotationsMarker != null) { |
| if (classAnnotations) { |
| marker.doneBefore(SmaliElementTypes.FIELD, annotationsMarker); |
| annotationsMarker.drop(); |
| } else { |
| annotationsMarker.drop(); |
| marker.done(SmaliElementTypes.FIELD); |
| } |
| } else { |
| marker.done(SmaliElementTypes.FIELD); |
| } |
| }; |
| catch [RecognitionException re] { |
| annotationsMarker.drop(); |
| recover(input, re); |
| reportError(marker, re, false); |
| } |
| |
| field_initializer |
| @init { Marker marker = mark(); } |
| : EQUAL literal |
| { marker.done(SmaliElementTypes.FIELD_INITIALIZER); }; |
| catch [RecognitionException re] { |
| recover(input, re); |
| reportError(marker, re, false); |
| } |
| |
| method |
| @init { |
| Marker marker = mark(); |
| mark().done(SmaliElementTypes.MODIFIER_LIST); |
| } |
| : METHOD_DIRECTIVE access_list member_name method_prototype statements_and_directives |
| END_METHOD_DIRECTIVE |
| { marker.done(SmaliElementTypes.METHOD); }; |
| catch [RecognitionException re] { |
| recover(input, re); |
| reportError(marker, re, false); |
| } |
| |
| statements_and_directives |
| : ( |
| ( ordered_method_item |
| | registers_directive |
| | catch_directive |
| | catchall_directive |
| | parameter_directive |
| | annotation |
| ) |
| sync[false] |
| )*; |
| |
| /* Method items whose order/location is important */ |
| ordered_method_item |
| : label |
| | instruction |
| | debug_directive; |
| |
| registers_directive |
| @init { Marker marker = mark(); } |
| : ( |
| REGISTERS_DIRECTIVE integral_literal |
| | LOCALS_DIRECTIVE integral_literal |
| ) |
| { marker.done(SmaliElementTypes.REGISTERS_STATEMENT); }; |
| catch [RecognitionException re] { |
| recover(input, re); |
| reportError(marker, re, false); |
| } |
| |
| param_list_or_id |
| : PARAM_LIST_OR_ID_START primitive_type+ PARAM_LIST_OR_ID_END; |
| |
| /*identifiers are much more general than most languages. Any of the below can either be |
| the indicated type OR an identifier, depending on the context*/ |
| simple_name |
| : SIMPLE_NAME |
| | ACCESS_SPEC |
| | VERIFICATION_ERROR_TYPE |
| | POSITIVE_INTEGER_LITERAL |
| | NEGATIVE_INTEGER_LITERAL |
| | FLOAT_LITERAL_OR_ID |
| | DOUBLE_LITERAL_OR_ID |
| | BOOL_LITERAL |
| | NULL_LITERAL |
| | register |
| | param_list_or_id |
| | PRIMITIVE_TYPE |
| | VOID_TYPE |
| | ANNOTATION_VISIBILITY |
| | INSTRUCTION_FORMAT10t |
| | INSTRUCTION_FORMAT10x |
| | INSTRUCTION_FORMAT10x_ODEX |
| | INSTRUCTION_FORMAT11x |
| | INSTRUCTION_FORMAT12x_OR_ID |
| | INSTRUCTION_FORMAT21c_FIELD |
| | INSTRUCTION_FORMAT21c_FIELD_ODEX |
| | INSTRUCTION_FORMAT21c_STRING |
| | INSTRUCTION_FORMAT21c_TYPE |
| | INSTRUCTION_FORMAT21t |
| | INSTRUCTION_FORMAT22c_FIELD |
| | INSTRUCTION_FORMAT22c_FIELD_ODEX |
| | INSTRUCTION_FORMAT22c_TYPE |
| | INSTRUCTION_FORMAT22cs_FIELD |
| | INSTRUCTION_FORMAT22s_OR_ID |
| | INSTRUCTION_FORMAT22t |
| | INSTRUCTION_FORMAT23x |
| | INSTRUCTION_FORMAT31i_OR_ID |
| | INSTRUCTION_FORMAT31t |
| | INSTRUCTION_FORMAT35c_METHOD |
| | INSTRUCTION_FORMAT35c_METHOD_ODEX |
| | INSTRUCTION_FORMAT35c_TYPE |
| | INSTRUCTION_FORMAT35mi_METHOD |
| | INSTRUCTION_FORMAT35ms_METHOD |
| | INSTRUCTION_FORMAT51l; |
| |
| member_name |
| @init { Marker marker = mark(); } |
| : (simple_name |
| | MEMBER_NAME) |
| { finishToken(marker, SmaliElementTypes.MEMBER_NAME); }; |
| catch [RecognitionException re] { |
| recover(input, re); |
| reportError(marker, re, false); |
| } |
| |
| method_prototype |
| @init { Marker marker = mark(); } |
| : OPEN_PAREN param_list CLOSE_PAREN type_descriptor |
| { marker.done(SmaliElementTypes.METHOD_PROTOTYPE); }; |
| catch [RecognitionException re] { |
| recover(input, re); |
| reportError(marker, re, false); |
| } |
| |
| param_list |
| @init { Marker marker = mark(); } |
| : ((PARAM_LIST_START param* PARAM_LIST_END) |
| | (PARAM_LIST_OR_ID_START param* PARAM_LIST_OR_ID_END) |
| | (param*)) |
| { marker.done(SmaliElementTypes.METHOD_PARAM_LIST); }; |
| catch [RecognitionException re] { |
| recover(input, re); |
| reportError(marker, re, false); |
| } |
| |
| param |
| @init { |
| Marker marker = mark(); |
| mark().done(SmaliElementTypes.MODIFIER_LIST); |
| } |
| : nonvoid_type_descriptor |
| { marker.done(SmaliElementTypes.METHOD_PARAMETER); }; |
| catch [RecognitionException re] { |
| recover(input, re); |
| reportError(marker, re, false); |
| } |
| |
| method_prototype_reference |
| : OPEN_PAREN param_list_reference CLOSE_PAREN type_descriptor; |
| |
| param_list_reference |
| @init { |
| Marker marker = mark(); |
| } |
| : ((PARAM_LIST_START nonvoid_type_descriptor* PARAM_LIST_END) |
| | (PARAM_LIST_OR_ID_START nonvoid_type_descriptor* PARAM_LIST_OR_ID_END) |
| | (nonvoid_type_descriptor*)) |
| { marker.done(SmaliElementTypes.METHOD_REFERENCE_PARAM_LIST); }; |
| catch [RecognitionException re] { |
| recover(input, re); |
| reportError(marker, re, false); |
| } |
| |
| primitive_type |
| @init { Marker marker = mark(); } |
| : PRIMITIVE_TYPE |
| { finishToken(marker, SmaliElementTypes.PRIMITIVE_TYPE); }; |
| catch [RecognitionException re] { |
| recover(input, re); |
| reportError(marker, re, false); |
| } |
| |
| class_descriptor |
| @init { Marker marker = mark(); } |
| : CLASS_DESCRIPTOR |
| { finishToken(marker, SmaliElementTypes.CLASS_TYPE); }; |
| catch [RecognitionException re] { |
| recover(input, re); |
| reportError(marker, re, false); |
| } |
| |
| array_descriptor |
| @init { Marker marker = mark(); } |
| : ARRAY_TYPE_PREFIX (primitive_type | class_descriptor) |
| { finishToken(marker, SmaliElementTypes.ARRAY_TYPE); }; |
| catch [RecognitionException re] { |
| recover(input, re); |
| reportError(marker, re, false); |
| } |
| |
| void_type |
| @init { Marker marker = mark(); } |
| : VOID_TYPE |
| { finishToken(marker, SmaliElementTypes.VOID_TYPE); }; |
| catch [RecognitionException re] { |
| recover(input, re); |
| reportError(marker, re, false); |
| } |
| |
| type_descriptor |
| : void_type |
| | primitive_type |
| | class_descriptor |
| | array_descriptor; |
| |
| nonvoid_type_descriptor |
| : primitive_type |
| | class_descriptor |
| | array_descriptor; |
| |
| reference_type_descriptor |
| : class_descriptor |
| | array_descriptor; |
| |
| null_literal |
| @init { Marker marker = mark(); } |
| : NULL_LITERAL |
| { finishToken(marker, SmaliElementTypes.LITERAL); }; |
| catch [RecognitionException re] { |
| recover(input, re); |
| reportError(marker, re, false); |
| } |
| |
| bool_literal |
| @init { Marker marker = mark(); } |
| : BOOL_LITERAL |
| { finishToken(marker, SmaliElementTypes.LITERAL); }; |
| catch [RecognitionException re] { |
| recover(input, re); |
| reportError(marker, re, false); |
| } |
| |
| byte_literal |
| @init { Marker marker = mark(); } |
| : BYTE_LITERAL |
| { finishToken(marker, SmaliElementTypes.LITERAL); }; |
| catch [RecognitionException re] { |
| recover(input, re); |
| reportError(marker, re, false); |
| } |
| |
| char_literal |
| @init { Marker marker = mark(); } |
| : CHAR_LITERAL |
| { finishToken(marker, SmaliElementTypes.LITERAL); }; |
| catch [RecognitionException re] { |
| recover(input, re); |
| reportError(marker, re, false); |
| } |
| |
| short_literal |
| @init { Marker marker = mark(); } |
| : SHORT_LITERAL |
| { finishToken(marker, SmaliElementTypes.LITERAL); }; |
| catch [RecognitionException re] { |
| recover(input, re); |
| reportError(marker, re, false); |
| } |
| |
| integer_literal |
| @init { Marker marker = mark(); } |
| : ( POSITIVE_INTEGER_LITERAL |
| | NEGATIVE_INTEGER_LITERAL) |
| { finishToken(marker, SmaliElementTypes.LITERAL); }; |
| catch [RecognitionException re] { |
| recover(input, re); |
| reportError(marker, re, false); |
| } |
| |
| long_literal |
| @init { Marker marker = mark(); } |
| : LONG_LITERAL |
| { finishToken(marker, SmaliElementTypes.LITERAL); }; |
| catch [RecognitionException re] { |
| recover(input, re); |
| reportError(marker, re, false); |
| } |
| |
| float_literal |
| @init { Marker marker = mark(); } |
| : ( FLOAT_LITERAL_OR_ID |
| | FLOAT_LITERAL ) |
| { finishToken(marker, SmaliElementTypes.LITERAL); }; |
| catch [RecognitionException re] { |
| recover(input, re); |
| reportError(marker, re, false); |
| } |
| |
| double_literal |
| @init { Marker marker = mark(); } |
| : ( DOUBLE_LITERAL_OR_ID |
| | DOUBLE_LITERAL) |
| { finishToken(marker, SmaliElementTypes.LITERAL); }; |
| catch [RecognitionException re] { |
| recover(input, re); |
| reportError(marker, re, false); |
| } |
| |
| string_literal |
| @init { Marker marker = mark(); } |
| : STRING_LITERAL |
| { finishToken(marker, SmaliElementTypes.LITERAL); }; |
| catch [RecognitionException re] { |
| recover(input, re); |
| reportError(marker, re, false); |
| } |
| |
| array_literal |
| @init { Marker marker = mark(); } |
| : OPEN_BRACE (literal (COMMA literal)* | ) CLOSE_BRACE |
| { marker.done(SmaliElementTypes.LITERAL); }; |
| catch [RecognitionException re] { |
| recover(input, re); |
| reportError(marker, re, false); |
| } |
| |
| enum_literal |
| @init { Marker marker = mark(); } |
| : ENUM_DIRECTIVE reference_type_descriptor ARROW simple_name COLON reference_type_descriptor |
| { marker.done(SmaliElementTypes.LITERAL); }; |
| catch [RecognitionException re] { |
| recover(input, re); |
| reportError(marker, re, false); |
| } |
| |
| // TODO: check missing initial token |
| type_field_method_literal |
| @init { Marker marker = mark(); } |
| : ( reference_type_descriptor |
| ( ARROW |
| ( member_name COLON nonvoid_type_descriptor |
| | member_name method_prototype_reference |
| ) |
| | /* epsilon */ |
| ) |
| | primitive_type |
| | void_type) |
| { marker.done(SmaliElementTypes.LITERAL); }; |
| catch [RecognitionException re] { |
| recover(input, re); |
| reportError(marker, re, false); |
| } |
| |
| // TODO: check missing initial token |
| subannotation |
| @init { Marker marker = mark(); } |
| : SUBANNOTATION_DIRECTIVE class_descriptor annotation_element* END_SUBANNOTATION_DIRECTIVE |
| { marker.done(SmaliElementTypes.LITERAL); }; |
| catch [RecognitionException re] { |
| recover(input, re); |
| reportError(marker, re, false); |
| } |
| |
| literal |
| : long_literal |
| | integer_literal |
| | short_literal |
| | byte_literal |
| | float_literal |
| | double_literal |
| | char_literal |
| | string_literal |
| | bool_literal |
| | null_literal |
| | array_literal |
| | subannotation |
| | type_field_method_literal |
| | enum_literal; |
| |
| integral_literal |
| : long_literal |
| | integer_literal |
| | short_literal |
| | char_literal |
| | byte_literal; |
| |
| fixed_32bit_literal |
| : long_literal |
| | integer_literal |
| | short_literal |
| | byte_literal |
| | float_literal |
| | char_literal |
| | bool_literal; |
| |
| fixed_literal |
| : integer_literal |
| | long_literal |
| | short_literal |
| | byte_literal |
| | float_literal |
| | double_literal |
| | char_literal |
| | bool_literal; |
| |
| annotation_element |
| @init { |
| Marker marker = mark(); |
| Marker nameMarker = null; |
| } |
| : { nameMarker = mark(); } simple_name { nameMarker.done(SmaliElementTypes.ANNOTATION_ELEMENT_NAME); } |
| EQUAL literal |
| { marker.done(SmaliElementTypes.ANNOTATION_ELEMENT); }; |
| catch [RecognitionException re] { |
| recover(input, re); |
| reportError(marker, re, false); |
| } |
| |
| annotation |
| @init { |
| Marker marker = mark(); |
| Marker paramListMarker = null; |
| } |
| : ANNOTATION_DIRECTIVE ANNOTATION_VISIBILITY class_descriptor |
| { paramListMarker = mark(); } |
| annotation_element* |
| { paramListMarker.done(SmaliElementTypes.ANNOTATION_PARAMETER_LIST); } |
| END_ANNOTATION_DIRECTIVE |
| { marker.done(SmaliElementTypes.ANNOTATION); }; |
| catch [RecognitionException re] { |
| recover(input, re); |
| reportError(marker, re, false); |
| } |
| |
| // TODO: check missing initial token |
| fully_qualified_method |
| @init { Marker marker = mark(); } |
| : reference_type_descriptor ARROW member_name method_prototype_reference |
| { marker.done(SmaliElementTypes.METHOD_REFERENCE); }; |
| catch [RecognitionException re] { |
| recover(input, re); |
| reportError(marker, re, false); |
| } |
| |
| // TODO: check missing initial token |
| fully_qualified_field |
| @init { Marker marker = mark(); } |
| : reference_type_descriptor ARROW member_name COLON nonvoid_type_descriptor |
| { marker.done(SmaliElementTypes.FIELD_REFERENCE); }; |
| catch [RecognitionException re] { |
| recover(input, re); |
| reportError(marker, re, false); |
| } |
| |
| // TODO: check missing initial token |
| label |
| @init { Marker marker = mark(); } |
| : COLON simple_name |
| { marker.done(SmaliElementTypes.LABEL); }; |
| catch [RecognitionException re] { |
| recover(input, re); |
| reportError(marker, re, false); |
| } |
| |
| // TODO: check missing initial token |
| label_ref |
| @init { Marker marker = mark(); } |
| : COLON simple_name |
| { marker.done(SmaliElementTypes.LABEL_REFERENCE); }; |
| catch [RecognitionException re] { |
| recover(input, re); |
| reportError(marker, re, false); |
| } |
| |
| register_list |
| : register (COMMA register)* |
| | /* epsilon */; |
| |
| register_range |
| : (register (DOTDOT register)?)?; |
| |
| verification_error_reference |
| : class_descriptor | fully_qualified_field | fully_qualified_method; |
| |
| catch_directive |
| @init { Marker marker = mark(); } |
| : CATCH_DIRECTIVE nonvoid_type_descriptor OPEN_BRACE label_ref DOTDOT label_ref CLOSE_BRACE label_ref |
| { marker.done(SmaliElementTypes.CATCH_STATEMENT); }; |
| catch [RecognitionException re] { |
| recover(input, re); |
| reportError(marker, re, false); |
| } |
| |
| catchall_directive |
| @init { Marker marker = mark(); } |
| : CATCHALL_DIRECTIVE OPEN_BRACE label_ref DOTDOT label_ref CLOSE_BRACE label_ref |
| { marker.done(SmaliElementTypes.CATCH_ALL_STATEMENT); }; |
| catch [RecognitionException re] { |
| recover(input, re); |
| reportError(marker, re, false); |
| } |
| |
| /*When there are annotations immediately after a parameter definition, we don't know whether they are parameter annotations |
| or method annotations until we determine if there is an .end parameter directive. In either case, we still "consume" and parse |
| the annotations. If it turns out that they are parameter annotations, we include them in the I_PARAMETER AST. Otherwise, we |
| add them to the $statements_and_directives::methodAnnotations list*/ |
| parameter_directive |
| @init { |
| Marker marker = mark(); |
| Marker preAnnotationMarker = null; |
| Marker nameMarker = null; |
| } |
| : PARAMETER_DIRECTIVE register |
| (COMMA { nameMarker = mark(); } string_literal { nameMarker.done(SmaliElementTypes.LOCAL_NAME); })? |
| { preAnnotationMarker = mark(); } |
| ({input.LA(1) == ANNOTATION_DIRECTIVE}? annotation)* |
| ( END_PARAMETER_DIRECTIVE { |
| preAnnotationMarker.drop(); |
| marker.done(SmaliElementTypes.PARAMETER_STATEMENT); |
| } |
| | /*epsilon*/ { |
| marker.doneBefore(SmaliElementTypes.PARAMETER_STATEMENT, preAnnotationMarker); |
| preAnnotationMarker.drop(); |
| } |
| ); |
| |
| register |
| @init { Marker marker = mark(); } |
| : REGISTER |
| { finishToken(marker, SmaliElementTypes.REGISTER_REFERENCE); }; |
| catch [RecognitionException re] { |
| recover(input, re); |
| reportError(marker, re, false); |
| } |
| |
| debug_directive |
| : line_directive |
| | local_directive |
| | end_local_directive |
| | restart_local_directive |
| | prologue_directive |
| | epilogue_directive |
| | source_directive; |
| |
| line_directive |
| @init { Marker marker = mark(); } |
| : LINE_DIRECTIVE integral_literal |
| { marker.done(SmaliElementTypes.LINE_DEBUG_STATEMENT); }; |
| catch [RecognitionException re] { |
| recover(input, re); |
| reportError(marker, re, false); |
| } |
| |
| local_directive |
| @init { Marker marker = mark(); } |
| : LOCAL_DIRECTIVE register (COMMA (null_literal | string_literal) COLON (void_type | nonvoid_type_descriptor) |
| (COMMA string_literal)? )? |
| { marker.done(SmaliElementTypes.LOCAL_DEBUG_STATEMENT); }; |
| catch [RecognitionException re] { |
| recover(input, re); |
| reportError(marker, re, false); |
| } |
| |
| end_local_directive |
| @init { Marker marker = mark(); } |
| : END_LOCAL_DIRECTIVE register |
| { marker.done(SmaliElementTypes.END_LOCAL_DEBUG_STATEMENT); }; |
| catch [RecognitionException re] { |
| recover(input, re); |
| reportError(marker, re, false); |
| } |
| |
| restart_local_directive |
| @init { Marker marker = mark(); } |
| : RESTART_LOCAL_DIRECTIVE register |
| { marker.done(SmaliElementTypes.RESTART_LOCAL_DEBUG_STATEMENT); }; |
| catch [RecognitionException re] { |
| recover(input, re); |
| reportError(marker, re, false); |
| } |
| |
| prologue_directive |
| @init { Marker marker = mark(); } |
| : PROLOGUE_DIRECTIVE |
| { marker.done(SmaliElementTypes.PROLOGUE_DEBUG_STATEMENT); }; |
| catch [RecognitionException re] { |
| recover(input, re); |
| reportError(marker, re, false); |
| } |
| |
| epilogue_directive |
| @init { Marker marker = mark(); } |
| : EPILOGUE_DIRECTIVE |
| { marker.done(SmaliElementTypes.EPILOGUE_DEBUG_STATEMENT); }; |
| catch [RecognitionException re] { |
| recover(input, re); |
| reportError(marker, re, false); |
| } |
| |
| source_directive |
| @init { Marker marker = mark(); } |
| : SOURCE_DIRECTIVE string_literal? |
| { marker.done(SmaliElementTypes.SOURCE_DEBUG_STATEMENT); }; |
| catch [RecognitionException re] { |
| recover(input, re); |
| reportError(marker, re, false); |
| } |
| |
| instruction_format12x |
| : INSTRUCTION_FORMAT12x |
| | INSTRUCTION_FORMAT12x_OR_ID; |
| |
| instruction_format22s |
| : INSTRUCTION_FORMAT22s |
| | INSTRUCTION_FORMAT22s_OR_ID; |
| |
| instruction_format31i |
| : INSTRUCTION_FORMAT31i |
| | INSTRUCTION_FORMAT31i_OR_ID; |
| |
| instruction |
| @init { Marker marker = mark(); } |
| : ( insn_format10t |
| | insn_format10x |
| | insn_format10x_odex |
| | insn_format11n |
| | insn_format11x |
| | insn_format12x |
| | insn_format20bc |
| | insn_format20t |
| | insn_format21c_field |
| | insn_format21c_field_odex |
| | insn_format21c_string |
| | insn_format21c_type |
| | insn_format21ih |
| | insn_format21lh |
| | insn_format21s |
| | insn_format21t |
| | insn_format22b |
| | insn_format22c_field |
| | insn_format22c_field_odex |
| | insn_format22c_type |
| | insn_format22cs_field |
| | insn_format22s |
| | insn_format22t |
| | insn_format22x |
| | insn_format23x |
| | insn_format30t |
| | insn_format31c |
| | insn_format31i |
| | insn_format31t |
| | insn_format32x |
| | insn_format35c_method |
| | insn_format35c_type |
| | insn_format35c_method_odex |
| | insn_format35mi_method |
| | insn_format35ms_method |
| | insn_format3rc_method |
| | insn_format3rc_method_odex |
| | insn_format3rc_type |
| | insn_format3rmi_method |
| | insn_format3rms_method |
| | insn_format51l |
| | insn_array_data_directive |
| | insn_packed_switch_directive |
| | insn_sparse_switch_directive ) |
| { marker.done(SmaliElementTypes.INSTRUCTION); }; |
| catch [RecognitionException re] { |
| recover(input, re); |
| reportError(marker, re, false); |
| } |
| |
| insn_format10t |
| : //e.g. goto endloop: |
| //e.g. goto +3 |
| INSTRUCTION_FORMAT10t label_ref; |
| |
| insn_format10x |
| : //e.g. return-void |
| INSTRUCTION_FORMAT10x; |
| |
| insn_format10x_odex |
| : //e.g. return-void-barrier |
| INSTRUCTION_FORMAT10x_ODEX; |
| |
| insn_format11n |
| : //e.g. const/4 v0, 5 |
| INSTRUCTION_FORMAT11n register COMMA integral_literal; |
| |
| insn_format11x |
| : //e.g. move-result-object v1 |
| INSTRUCTION_FORMAT11x register; |
| |
| insn_format12x |
| : //e.g. move v1 v2 |
| instruction_format12x register COMMA register; |
| |
| insn_format20bc |
| : //e.g. throw-verification-error generic-error, Lsome/class; |
| INSTRUCTION_FORMAT20bc VERIFICATION_ERROR_TYPE COMMA verification_error_reference; |
| |
| insn_format20t |
| : //e.g. goto/16 endloop: |
| INSTRUCTION_FORMAT20t label_ref; |
| |
| insn_format21c_field |
| : //e.g. sget-object v0, java/lang/System/out LJava/io/PrintStream; |
| INSTRUCTION_FORMAT21c_FIELD register COMMA fully_qualified_field; |
| |
| insn_format21c_field_odex |
| : //e.g. sget-object-volatile v0, java/lang/System/out LJava/io/PrintStream; |
| INSTRUCTION_FORMAT21c_FIELD_ODEX register COMMA fully_qualified_field; |
| |
| insn_format21c_string |
| : //e.g. const-string v1, "Hello World!" |
| INSTRUCTION_FORMAT21c_STRING register COMMA string_literal; |
| |
| insn_format21c_type |
| : //e.g. const-class v2, Lorg/jf/HelloWorld2/HelloWorld2; |
| INSTRUCTION_FORMAT21c_TYPE register COMMA nonvoid_type_descriptor; |
| |
| insn_format21ih |
| : //e.g. const/high16 v1, 1234 |
| INSTRUCTION_FORMAT21ih register COMMA fixed_32bit_literal; |
| |
| insn_format21lh |
| : //e.g. const-wide/high16 v1, 1234 |
| INSTRUCTION_FORMAT21lh register COMMA fixed_32bit_literal; |
| |
| insn_format21s |
| : //e.g. const/16 v1, 1234 |
| INSTRUCTION_FORMAT21s register COMMA integral_literal; |
| |
| insn_format21t |
| : //e.g. if-eqz v0, endloop: |
| INSTRUCTION_FORMAT21t register COMMA label_ref; |
| |
| insn_format22b |
| : //e.g. add-int v0, v1, 123 |
| INSTRUCTION_FORMAT22b register COMMA register COMMA integral_literal; |
| |
| insn_format22c_field |
| : //e.g. iput-object v1, v0 org/jf/HelloWorld2/HelloWorld2.helloWorld Ljava/lang/String; |
| INSTRUCTION_FORMAT22c_FIELD register COMMA register COMMA fully_qualified_field; |
| |
| insn_format22c_field_odex |
| : //e.g. iput-object-volatile v1, v0 org/jf/HelloWorld2/HelloWorld2.helloWorld Ljava/lang/String; |
| INSTRUCTION_FORMAT22c_FIELD_ODEX register COMMA register COMMA fully_qualified_field; |
| |
| insn_format22c_type |
| : //e.g. instance-of v0, v1, Ljava/lang/String; |
| INSTRUCTION_FORMAT22c_TYPE register COMMA register COMMA nonvoid_type_descriptor; |
| |
| insn_format22cs_field |
| : //e.g. iget-quick v0, v1, field@0xc |
| INSTRUCTION_FORMAT22cs_FIELD register COMMA register COMMA FIELD_OFFSET; |
| |
| insn_format22s |
| : //e.g. add-int/lit16 v0, v1, 12345 |
| instruction_format22s register COMMA register COMMA integral_literal; |
| |
| insn_format22t |
| : //e.g. if-eq v0, v1, endloop: |
| INSTRUCTION_FORMAT22t register COMMA register COMMA label_ref; |
| |
| insn_format22x |
| : //e.g. move/from16 v1, v1234 |
| INSTRUCTION_FORMAT22x register COMMA register; |
| |
| insn_format23x |
| : //e.g. add-int v1, v2, v3 |
| INSTRUCTION_FORMAT23x register COMMA register COMMA register; |
| |
| insn_format30t |
| : //e.g. goto/32 endloop: |
| INSTRUCTION_FORMAT30t label_ref; |
| |
| insn_format31c |
| : //e.g. const-string/jumbo v1 "Hello World!" |
| INSTRUCTION_FORMAT31c register COMMA string_literal; |
| |
| insn_format31i |
| : //e.g. const v0, 123456 |
| instruction_format31i register COMMA fixed_32bit_literal; |
| |
| insn_format31t |
| : //e.g. fill-array-data v0, ArrayData: |
| INSTRUCTION_FORMAT31t register COMMA label_ref; |
| |
| insn_format32x |
| : //e.g. move/16 v4567, v1234 |
| INSTRUCTION_FORMAT32x register COMMA register; |
| |
| insn_format35c_method |
| : //e.g. invoke-virtual {v0,v1} java/io/PrintStream/print(Ljava/lang/Stream;)V |
| INSTRUCTION_FORMAT35c_METHOD OPEN_BRACE register_list CLOSE_BRACE COMMA fully_qualified_method; |
| |
| insn_format35c_type |
| : //e.g. filled-new-array {v0,v1}, I |
| INSTRUCTION_FORMAT35c_TYPE OPEN_BRACE register_list CLOSE_BRACE COMMA nonvoid_type_descriptor; |
| |
| insn_format35c_method_odex |
| : //e.g. invoke-direct {p0}, Ljava/lang/Object;-><init>()V |
| INSTRUCTION_FORMAT35c_METHOD_ODEX OPEN_BRACE register_list CLOSE_BRACE COMMA fully_qualified_method; |
| |
| insn_format35mi_method |
| : //e.g. execute-inline {v0, v1}, inline@0x4 |
| INSTRUCTION_FORMAT35mi_METHOD OPEN_BRACE register_list CLOSE_BRACE COMMA INLINE_INDEX; |
| |
| insn_format35ms_method |
| : //e.g. invoke-virtual-quick {v0, v1}, vtable@0x4 |
| INSTRUCTION_FORMAT35ms_METHOD OPEN_BRACE register_list CLOSE_BRACE COMMA VTABLE_INDEX; |
| |
| insn_format3rc_method |
| : //e.g. invoke-virtual/range {v25..v26}, java/lang/StringBuilder/append(Ljava/lang/String;)Ljava/lang/StringBuilder; |
| INSTRUCTION_FORMAT3rc_METHOD OPEN_BRACE register_range CLOSE_BRACE COMMA fully_qualified_method; |
| |
| insn_format3rc_method_odex |
| : //e.g. invoke-object-init/range {p0}, Ljava/lang/Object;-><init>()V |
| INSTRUCTION_FORMAT3rc_METHOD_ODEX OPEN_BRACE register_list CLOSE_BRACE COMMA fully_qualified_method; |
| |
| insn_format3rc_type |
| : //e.g. filled-new-array/range {v0..v6}, I |
| INSTRUCTION_FORMAT3rc_TYPE OPEN_BRACE register_range CLOSE_BRACE COMMA nonvoid_type_descriptor; |
| |
| insn_format3rmi_method |
| : //e.g. execute-inline/range {v0 .. v10}, inline@0x14 |
| INSTRUCTION_FORMAT3rmi_METHOD OPEN_BRACE register_range CLOSE_BRACE COMMA INLINE_INDEX; |
| |
| insn_format3rms_method |
| : //e.g. invoke-virtual-quick/range {v0 .. v10}, vtable@0x14 |
| INSTRUCTION_FORMAT3rms_METHOD OPEN_BRACE register_range CLOSE_BRACE COMMA VTABLE_INDEX; |
| |
| insn_format51l |
| : //e.g. const-wide v0, 5000000000L |
| INSTRUCTION_FORMAT51l register COMMA fixed_literal; |
| |
| insn_array_data_directive |
| : ARRAY_DATA_DIRECTIVE |
| integer_literal |
| array_data_element* END_ARRAY_DATA_DIRECTIVE; |
| |
| array_data_element |
| @init { Marker marker = mark(); } |
| : fixed_literal |
| { marker.done(SmaliElementTypes.ARRAY_DATA_ELEMENT); }; |
| catch [RecognitionException re] { |
| recover(input, re); |
| reportError(marker, re, false); |
| } |
| |
| insn_packed_switch_directive |
| : PACKED_SWITCH_DIRECTIVE |
| fixed_32bit_literal |
| packed_switch_element* |
| END_PACKED_SWITCH_DIRECTIVE; |
| |
| packed_switch_element |
| @init { Marker marker = mark(); } |
| : label_ref |
| { marker.done(SmaliElementTypes.PACKED_SWITCH_ELEMENT); }; |
| catch [RecognitionException re] { |
| recover(input, re); |
| reportError(marker, re, false); |
| } |
| |
| insn_sparse_switch_directive |
| : SPARSE_SWITCH_DIRECTIVE |
| sparse_switch_element* |
| END_SPARSE_SWITCH_DIRECTIVE; |
| |
| sparse_switch_element |
| @init { Marker marker = mark(); } |
| : fixed_32bit_literal ARROW label_ref |
| { marker.done(SmaliElementTypes.SPARSE_SWITCH_ELEMENT); }; |
| catch [RecognitionException re] { |
| recover(input, re); |
| reportError(marker, re, false); |
| } |