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 smaliParser; 30 31options { 32 tokenVocab=smaliLexer; 33 output=AST; 34 ASTLabelType=CommonTree; 35} 36 37tokens { 38 //I_* tokens are imaginary tokens used as parent AST nodes 39 I_CLASS_DEF; 40 I_SUPER; 41 I_IMPLEMENTS; 42 I_SOURCE; 43 I_ACCESS_LIST; 44 I_METHODS; 45 I_FIELDS; 46 I_FIELD; 47 I_FIELD_TYPE; 48 I_FIELD_INITIAL_VALUE; 49 I_METHOD; 50 I_METHOD_PROTOTYPE; 51 I_METHOD_RETURN_TYPE; 52 I_REGISTERS; 53 I_LOCALS; 54 I_LABELS; 55 I_LABEL; 56 I_ANNOTATIONS; 57 I_ANNOTATION; 58 I_ANNOTATION_ELEMENT; 59 I_SUBANNOTATION; 60 I_ENCODED_FIELD; 61 I_ENCODED_METHOD; 62 I_ENCODED_ENUM; 63 I_ENCODED_ARRAY; 64 I_ARRAY_ELEMENT_SIZE; 65 I_ARRAY_ELEMENTS; 66 I_PACKED_SWITCH_START_KEY; 67 I_PACKED_SWITCH_TARGET_COUNT; 68 I_PACKED_SWITCH_TARGETS; 69 I_PACKED_SWITCH_DECLARATION; 70 I_PACKED_SWITCH_DECLARATIONS; 71 I_SPARSE_SWITCH_KEYS; 72 I_SPARSE_SWITCH_TARGET_COUNT; 73 I_SPARSE_SWITCH_TARGETS; 74 I_SPARSE_SWITCH_DECLARATION; 75 I_SPARSE_SWITCH_DECLARATIONS; 76 I_ADDRESS; 77 I_CATCH; 78 I_CATCHALL; 79 I_CATCHES; 80 I_PARAMETER; 81 I_PARAMETERS; 82 I_PARAMETER_NOT_SPECIFIED; 83 I_ORDERED_DEBUG_DIRECTIVES; 84 I_LINE; 85 I_LOCAL; 86 I_END_LOCAL; 87 I_RESTART_LOCAL; 88 I_PROLOGUE; 89 I_EPILOGUE; 90 I_STATEMENTS; 91 I_STATEMENT_FORMAT10t; 92 I_STATEMENT_FORMAT10x; 93 I_STATEMENT_FORMAT11n; 94 I_STATEMENT_FORMAT11x; 95 I_STATEMENT_FORMAT12x; 96 I_STATEMENT_FORMAT20bc; 97 I_STATEMENT_FORMAT20t; 98 I_STATEMENT_FORMAT21c_TYPE; 99 I_STATEMENT_FORMAT21c_FIELD; 100 I_STATEMENT_FORMAT21c_STRING; 101 I_STATEMENT_FORMAT21h; 102 I_STATEMENT_FORMAT21s; 103 I_STATEMENT_FORMAT21t; 104 I_STATEMENT_FORMAT22b; 105 I_STATEMENT_FORMAT22c_FIELD; 106 I_STATEMENT_FORMAT22c_TYPE; 107 I_STATEMENT_FORMAT22s; 108 I_STATEMENT_FORMAT22t; 109 I_STATEMENT_FORMAT22x; 110 I_STATEMENT_FORMAT23x; 111 I_STATEMENT_FORMAT30t; 112 I_STATEMENT_FORMAT31c; 113 I_STATEMENT_FORMAT31i; 114 I_STATEMENT_FORMAT31t; 115 I_STATEMENT_FORMAT32x; 116 I_STATEMENT_FORMAT35c_METHOD; 117 I_STATEMENT_FORMAT35c_TYPE; 118 I_STATEMENT_FORMAT3rc_METHOD; 119 I_STATEMENT_FORMAT3rc_TYPE; 120 I_STATEMENT_FORMAT51l; 121 I_STATEMENT_ARRAY_DATA; 122 I_STATEMENT_PACKED_SWITCH; 123 I_STATEMENT_SPARSE_SWITCH; 124 I_REGISTER_RANGE; 125 I_REGISTER_LIST; 126 127 LABEL; 128 INTEGER_LITERAL; 129 INVALID_TOKEN; 130} 131 132@header { 133package org.jf.smali; 134 135import org.jf.dexlib.Code.Format.*; 136} 137 138 139@members { 140 private boolean verboseErrors = false; 141 private boolean allowOdex = false; 142 143 public void setVerboseErrors(boolean verboseErrors) { 144 this.verboseErrors = verboseErrors; 145 } 146 147 public void setAllowOdex(boolean allowOdex) { 148 this.allowOdex = allowOdex; 149 } 150 151 public String getErrorMessage(RecognitionException e, 152 String[] tokenNames) { 153 154 if (verboseErrors) { 155 List stack = getRuleInvocationStack(e, this.getClass().getName()); 156 String msg = null; 157 158 if (e instanceof NoViableAltException) { 159 NoViableAltException nvae = (NoViableAltException)e; 160 msg = " no viable alt; token="+getTokenErrorDisplay(e.token)+ 161 " (decision="+nvae.decisionNumber+ 162 " state "+nvae.stateNumber+")"+ 163 " decision=<<"+nvae.grammarDecisionDescription+">>"; 164 } else { 165 msg = super.getErrorMessage(e, tokenNames); 166 } 167 168 return stack + " " + msg; 169 } else { 170 return super.getErrorMessage(e, tokenNames); 171 } 172 } 173 174 public String getTokenErrorDisplay(Token t) { 175 if (!verboseErrors) { 176 String s = t.getText(); 177 if ( s==null ) { 178 if ( t.getType()==Token.EOF ) { 179 s = "<EOF>"; 180 } 181 else { 182 s = "<"+tokenNames[t.getType()]+">"; 183 } 184 } 185 s = s.replaceAll("\n","\\\\n"); 186 s = s.replaceAll("\r","\\\\r"); 187 s = s.replaceAll("\t","\\\\t"); 188 return "'"+s+"'"; 189 } 190 191 CommonToken ct = (CommonToken)t; 192 193 String channelStr = ""; 194 if (t.getChannel()>0) { 195 channelStr=",channel="+t.getChannel(); 196 } 197 String txt = t.getText(); 198 if ( txt!=null ) { 199 txt = txt.replaceAll("\n","\\\\n"); 200 txt = txt.replaceAll("\r","\\\\r"); 201 txt = txt.replaceAll("\t","\\\\t"); 202 } 203 else { 204 txt = "<no text>"; 205 } 206 return "[@"+t.getTokenIndex()+","+ct.getStartIndex()+":"+ct.getStopIndex()+"='"+txt+"',<"+tokenNames[t.getType()]+">"+channelStr+","+t.getLine()+":"+t.getCharPositionInLine()+"]"; 207 } 208 209 public String getErrorHeader(RecognitionException e) { 210 return getSourceName()+"["+ e.line+","+e.charPositionInLine+"]"; 211 } 212 213 private CommonTree buildTree(int type, String text, List<CommonTree> children) { 214 CommonTree root = new CommonTree(new CommonToken(type, text)); 215 for (CommonTree child: children) { 216 root.addChild(child); 217 } 218 return root; 219 } 220 221 private CommonToken getParamListSubToken(CommonToken baseToken, String str, int typeStartIndex) { 222 CommonToken token = new CommonToken(baseToken); 223 token.setStartIndex(baseToken.getStartIndex() + typeStartIndex); 224 225 switch (str.charAt(typeStartIndex)) { 226 case 'Z': 227 case 'B': 228 case 'S': 229 case 'C': 230 case 'I': 231 case 'J': 232 case 'F': 233 case 'D': 234 { 235 token.setType(PRIMITIVE_TYPE); 236 token.setText(str.substring(typeStartIndex, typeStartIndex+1)); 237 token.setStopIndex(baseToken.getStartIndex() + typeStartIndex); 238 break; 239 } 240 case 'L': 241 { 242 int i = typeStartIndex; 243 while (str.charAt(++i) != ';'); 244 245 token.setType(CLASS_DESCRIPTOR); 246 token.setText(str.substring(typeStartIndex, i + 1)); 247 token.setStopIndex(baseToken.getStartIndex() + i); 248 break; 249 } 250 case '[': 251 { 252 int i = typeStartIndex; 253 while (str.charAt(++i) == '['); 254 255 if (str.charAt(i++) == 'L') { 256 while (str.charAt(i++) != ';'); 257 } 258 259 token.setType(ARRAY_DESCRIPTOR); 260 token.setText(str.substring(typeStartIndex, i)); 261 token.setStopIndex(baseToken.getStartIndex() + i - 1); 262 break; 263 } 264 default: 265 throw new RuntimeException(String.format("Invalid character '\%c' in param list \"\%s\" at position \%d", str.charAt(typeStartIndex), str, typeStartIndex)); 266 } 267 268 return token; 269 } 270 271 private CommonTree parseParamList(CommonToken paramListToken) { 272 String paramList = paramListToken.getText(); 273 CommonTree root = new CommonTree(); 274 275 int startIndex = paramListToken.getStartIndex(); 276 277 int i=0; 278 while (i<paramList.length()) { 279 CommonToken token = getParamListSubToken(paramListToken, paramList, i); 280 root.addChild(new CommonTree(token)); 281 i += token.getText().length(); 282 } 283 284 if (root.getChildCount() == 0) { 285 return null; 286 } 287 return root; 288 } 289 290 private void throwOdexedInstructionException(IntStream input, String odexedInstruction) 291 throws OdexedInstructionException { 292 /*this has to be done in a separate method, otherwise java will complain about the 293 auto-generated code in the rule after the throw not being reachable*/ 294 throw new OdexedInstructionException(input, odexedInstruction); 295 } 296} 297 298 299smali_file 300 scope 301 { 302 boolean hasClassSpec; 303 boolean hasSuperSpec; 304 boolean hasSourceSpec; 305 List<CommonTree> classAnnotations; 306 } 307 @init 308 { $smali_file::hasClassSpec = $smali_file::hasSuperSpec = $smali_file::hasSourceSpec = false; 309 $smali_file::classAnnotations = new ArrayList<CommonTree>(); 310 } 311 : 312 ( {!$smali_file::hasClassSpec}?=> class_spec {$smali_file::hasClassSpec = true;} 313 | {!$smali_file::hasSuperSpec}?=> super_spec {$smali_file::hasSuperSpec = true;} 314 | implements_spec 315 | {!$smali_file::hasSourceSpec}?=> source_spec {$smali_file::hasSourceSpec = true;} 316 | method 317 | field 318 | annotation {$smali_file::classAnnotations.add($annotation.tree);} 319 )+ 320 EOF 321 { 322 if (!$smali_file::hasClassSpec) { 323 throw new SemanticException(input, "The file must contain a .class directive"); 324 } 325 326 if (!$smali_file::hasSuperSpec) { 327 if (!$class_spec.className.equals("Ljava/lang/Object;")) { 328 throw new SemanticException(input, "The file must contain a .super directive"); 329 } 330 } 331 } 332 -> ^(I_CLASS_DEF 333 class_spec 334 super_spec? 335 implements_spec* 336 source_spec? 337 ^(I_METHODS method*) ^(I_FIELDS field*) {buildTree(I_ANNOTATIONS, "I_ANNOTATIONS", $smali_file::classAnnotations)}); 338 339class_spec returns[String className] 340 : CLASS_DIRECTIVE access_list CLASS_DESCRIPTOR {$className = $CLASS_DESCRIPTOR.text;} -> CLASS_DESCRIPTOR access_list; 341 342super_spec 343 : SUPER_DIRECTIVE CLASS_DESCRIPTOR -> ^(I_SUPER[$start, "I_SUPER"] CLASS_DESCRIPTOR); 344 345implements_spec 346 : IMPLEMENTS_DIRECTIVE CLASS_DESCRIPTOR -> ^(I_IMPLEMENTS[$start, "I_IMPLEMENTS"] CLASS_DESCRIPTOR); 347 348source_spec 349 : SOURCE_DIRECTIVE STRING_LITERAL -> ^(I_SOURCE[$start, "I_SOURCE"] STRING_LITERAL); 350 351access_list 352 : ACCESS_SPEC* -> ^(I_ACCESS_LIST[$start,"I_ACCESS_LIST"] ACCESS_SPEC*); 353 354 355/*When there are annotations immediately after a field definition, we don't know whether they are field annotations 356or class annotations until we determine if there is an .end field directive. In either case, we still "consume" and parse 357the annotations. If it turns out that they are field annotations, we include them in the I_FIELD AST. Otherwise, we 358add them to the $smali_file::classAnnotations list*/ 359field 360 @init {List<CommonTree> annotations = new ArrayList<CommonTree>();} 361 : FIELD_DIRECTIVE access_list simple_name COLON nonvoid_type_descriptor (EQUAL literal)? 362 ( ({input.LA(1) == ANNOTATION_DIRECTIVE}? annotation {annotations.add($annotation.tree);})* 363 ( END_FIELD_DIRECTIVE 364 -> ^(I_FIELD[$start, "I_FIELD"] simple_name access_list ^(I_FIELD_TYPE nonvoid_type_descriptor) ^(I_FIELD_INITIAL_VALUE literal)? ^(I_ANNOTATIONS annotation*)) 365 | /*epsilon*/ {$smali_file::classAnnotations.addAll(annotations);} 366 -> ^(I_FIELD[$start, "I_FIELD"] simple_name access_list ^(I_FIELD_TYPE nonvoid_type_descriptor) ^(I_FIELD_INITIAL_VALUE literal)? ^(I_ANNOTATIONS)) 367 ) 368 ); 369 370method 371 scope {int currentAddress;} 372 : {$method::currentAddress = 0;} 373 METHOD_DIRECTIVE access_list method_name method_prototype statements_and_directives 374 END_METHOD_DIRECTIVE 375 -> ^(I_METHOD[$start, "I_METHOD"] method_name method_prototype access_list statements_and_directives); 376 377statements_and_directives 378 scope 379 { 380 boolean hasRegistersDirective; 381 List<CommonTree> packedSwitchDeclarations; 382 List<CommonTree> sparseSwitchDeclarations; 383 List<CommonTree> methodAnnotations; 384 } 385 : { 386 $method::currentAddress = 0; 387 $statements_and_directives::hasRegistersDirective = false; 388 $statements_and_directives::packedSwitchDeclarations = new ArrayList<CommonTree>(); 389 $statements_and_directives::sparseSwitchDeclarations = new ArrayList<CommonTree>(); 390 $statements_and_directives::methodAnnotations = new ArrayList<CommonTree>(); 391 } 392 ( instruction {$method::currentAddress += $instruction.size/2;} 393 | registers_directive 394 | label 395 | catch_directive 396 | catchall_directive 397 | parameter_directive 398 | ordered_debug_directive 399 | annotation {$statements_and_directives::methodAnnotations.add($annotation.tree);} 400 )* 401 -> registers_directive? 402 ^(I_LABELS label*) 403 {buildTree(I_PACKED_SWITCH_DECLARATIONS, "I_PACKED_SWITCH_DECLARATIONS", $statements_and_directives::packedSwitchDeclarations)} 404 {buildTree(I_SPARSE_SWITCH_DECLARATIONS, "I_SPARSE_SWITCH_DECLARATIONS", $statements_and_directives::sparseSwitchDeclarations)} 405 ^(I_STATEMENTS instruction*) 406 ^(I_CATCHES catch_directive* catchall_directive*) 407 ^(I_PARAMETERS parameter_directive*) 408 ^(I_ORDERED_DEBUG_DIRECTIVES ordered_debug_directive*) 409 {buildTree(I_ANNOTATIONS, "I_ANNOTATIONS", $statements_and_directives::methodAnnotations)}; 410 411registers_directive 412 : ( 413 directive=REGISTERS_DIRECTIVE regCount=integral_literal -> ^(I_REGISTERS[$REGISTERS_DIRECTIVE, "I_REGISTERS"] $regCount) 414 | directive=LOCALS_DIRECTIVE regCount2=integral_literal -> ^(I_LOCALS[$LOCALS_DIRECTIVE, "I_LOCALS"] $regCount2) 415 ) 416 { 417 if ($statements_and_directives::hasRegistersDirective) { 418 throw new SemanticException(input, $directive, "There can only be a single .registers or .locals directive in a method"); 419 } 420 $statements_and_directives::hasRegistersDirective=true; 421 }; 422 423/*identifiers are much more general than most languages. Any of the below can either be 424the indicated type OR an identifier, depending on the context*/ 425simple_name 426 : SIMPLE_NAME 427 | ACCESS_SPEC -> SIMPLE_NAME[$ACCESS_SPEC] 428 | VERIFICATION_ERROR_TYPE -> SIMPLE_NAME[$VERIFICATION_ERROR_TYPE] 429 | POSITIVE_INTEGER_LITERAL -> SIMPLE_NAME[$POSITIVE_INTEGER_LITERAL] 430 | NEGATIVE_INTEGER_LITERAL -> SIMPLE_NAME[$NEGATIVE_INTEGER_LITERAL] 431 | INTEGER_LITERAL -> SIMPLE_NAME[$INTEGER_LITERAL] 432 | FLOAT_LITERAL_OR_ID -> SIMPLE_NAME[$FLOAT_LITERAL_OR_ID] 433 | DOUBLE_LITERAL_OR_ID -> SIMPLE_NAME[$DOUBLE_LITERAL_OR_ID] 434 | BOOL_LITERAL -> SIMPLE_NAME[$BOOL_LITERAL] 435 | NULL_LITERAL -> SIMPLE_NAME[$NULL_LITERAL] 436 | REGISTER -> SIMPLE_NAME[$REGISTER] 437 | PARAM_LIST_OR_ID -> SIMPLE_NAME[$PARAM_LIST_OR_ID] 438 | PRIMITIVE_TYPE -> SIMPLE_NAME[$PRIMITIVE_TYPE] 439 | VOID_TYPE -> SIMPLE_NAME[$VOID_TYPE] 440 | ANNOTATION_VISIBILITY -> SIMPLE_NAME[$ANNOTATION_VISIBILITY] 441 | INSTRUCTION_FORMAT10t -> SIMPLE_NAME[$INSTRUCTION_FORMAT10t] 442 | INSTRUCTION_FORMAT10x -> SIMPLE_NAME[$INSTRUCTION_FORMAT10x] 443 | INSTRUCTION_FORMAT11x -> SIMPLE_NAME[$INSTRUCTION_FORMAT11x] 444 | INSTRUCTION_FORMAT12x_OR_ID -> SIMPLE_NAME[$INSTRUCTION_FORMAT12x_OR_ID] 445 | INSTRUCTION_FORMAT21c_FIELD -> SIMPLE_NAME[$INSTRUCTION_FORMAT21c_FIELD] 446 | INSTRUCTION_FORMAT21c_FIELD_ODEX -> SIMPLE_NAME[$INSTRUCTION_FORMAT21c_FIELD_ODEX] 447 | INSTRUCTION_FORMAT21c_STRING -> SIMPLE_NAME[$INSTRUCTION_FORMAT21c_STRING] 448 | INSTRUCTION_FORMAT21c_TYPE -> SIMPLE_NAME[$INSTRUCTION_FORMAT21c_TYPE] 449 | INSTRUCTION_FORMAT21t -> SIMPLE_NAME[$INSTRUCTION_FORMAT21t] 450 | INSTRUCTION_FORMAT22c_FIELD -> SIMPLE_NAME[$INSTRUCTION_FORMAT22c_FIELD] 451 | INSTRUCTION_FORMAT22c_FIELD_ODEX -> SIMPLE_NAME[$INSTRUCTION_FORMAT22c_FIELD_ODEX] 452 | INSTRUCTION_FORMAT22c_TYPE -> SIMPLE_NAME[$INSTRUCTION_FORMAT22c_TYPE] 453 | INSTRUCTION_FORMAT22cs_FIELD -> SIMPLE_NAME[$INSTRUCTION_FORMAT22cs_FIELD] 454 | INSTRUCTION_FORMAT22s_OR_ID -> SIMPLE_NAME[$INSTRUCTION_FORMAT22s_OR_ID] 455 | INSTRUCTION_FORMAT22t -> SIMPLE_NAME[$INSTRUCTION_FORMAT22t] 456 | INSTRUCTION_FORMAT23x -> SIMPLE_NAME[$INSTRUCTION_FORMAT23x] 457 | INSTRUCTION_FORMAT31i_OR_ID -> SIMPLE_NAME[$INSTRUCTION_FORMAT31i_OR_ID] 458 | INSTRUCTION_FORMAT31t -> SIMPLE_NAME[$INSTRUCTION_FORMAT31t] 459 | INSTRUCTION_FORMAT35c_METHOD -> SIMPLE_NAME[$INSTRUCTION_FORMAT35c_METHOD] 460 | INSTRUCTION_FORMAT35c_TYPE -> SIMPLE_NAME[$INSTRUCTION_FORMAT35c_TYPE] 461 | INSTRUCTION_FORMAT35s_METHOD -> SIMPLE_NAME[$INSTRUCTION_FORMAT35s_METHOD] 462 | INSTRUCTION_FORMAT35ms_METHOD -> SIMPLE_NAME[$INSTRUCTION_FORMAT35ms_METHOD] 463 | INSTRUCTION_FORMAT51l -> SIMPLE_NAME[$INSTRUCTION_FORMAT51l]; 464 465method_name 466 : simple_name 467 | METHOD_NAME -> SIMPLE_NAME[$METHOD_NAME]; 468 469method_prototype 470 : OPEN_PAREN param_list CLOSE_PAREN type_descriptor 471 -> ^(I_METHOD_PROTOTYPE[$start, "I_METHOD_PROTOTYPE"] ^(I_METHOD_RETURN_TYPE type_descriptor) param_list?); 472 473param_list 474 : PARAM_LIST -> { parseParamList((CommonToken)$PARAM_LIST) } 475 | PARAM_LIST_OR_ID -> { parseParamList((CommonToken)$PARAM_LIST_OR_ID) } 476 | nonvoid_type_descriptor*; 477 478type_descriptor 479 : VOID_TYPE 480 | PRIMITIVE_TYPE 481 | CLASS_DESCRIPTOR 482 | ARRAY_DESCRIPTOR; 483 484nonvoid_type_descriptor 485 : PRIMITIVE_TYPE 486 | CLASS_DESCRIPTOR 487 | ARRAY_DESCRIPTOR; 488 489reference_type_descriptor 490 : CLASS_DESCRIPTOR 491 | ARRAY_DESCRIPTOR; 492 493integer_literal 494 : POSITIVE_INTEGER_LITERAL -> INTEGER_LITERAL[$POSITIVE_INTEGER_LITERAL] 495 | NEGATIVE_INTEGER_LITERAL -> INTEGER_LITERAL[$NEGATIVE_INTEGER_LITERAL] 496 | INTEGER_LITERAL; 497 498float_literal 499 : FLOAT_LITERAL_OR_ID -> FLOAT_LITERAL[$FLOAT_LITERAL_OR_ID] 500 | FLOAT_LITERAL; 501 502double_literal 503 : DOUBLE_LITERAL_OR_ID -> DOUBLE_LITERAL[$DOUBLE_LITERAL_OR_ID] 504 | DOUBLE_LITERAL; 505 506literal 507 : LONG_LITERAL 508 | integer_literal 509 | SHORT_LITERAL 510 | BYTE_LITERAL 511 | float_literal 512 | double_literal 513 | CHAR_LITERAL 514 | STRING_LITERAL 515 | BOOL_LITERAL 516 | NULL_LITERAL 517 | array_literal 518 | subannotation 519 | type_field_method_literal 520 | enum_literal; 521 522integral_literal 523 : LONG_LITERAL 524 | integer_literal 525 | SHORT_LITERAL 526 | CHAR_LITERAL 527 | BYTE_LITERAL; 528 529fixed_32bit_literal 530 : LONG_LITERAL 531 | integer_literal 532 | SHORT_LITERAL 533 | BYTE_LITERAL 534 | float_literal 535 | CHAR_LITERAL 536 | BOOL_LITERAL; 537 538fixed_literal returns[int size] 539 : integer_literal {$size = 4;} 540 | LONG_LITERAL {$size = 8;} 541 | SHORT_LITERAL {$size = 2;} 542 | BYTE_LITERAL {$size = 1;} 543 | float_literal {$size = 4;} 544 | double_literal {$size = 8;} 545 | CHAR_LITERAL {$size = 2;} 546 | BOOL_LITERAL {$size = 1;}; 547 548array_literal 549 : OPEN_BRACE (literal (COMMA literal)* | ) CLOSE_BRACE 550 -> ^(I_ENCODED_ARRAY[$start, "I_ENCODED_ARRAY"] literal*); 551 552annotation_element 553 : simple_name EQUAL literal 554 -> ^(I_ANNOTATION_ELEMENT[$start, "I_ANNOTATION_ELEMENT"] simple_name literal); 555 556annotation 557 : ANNOTATION_DIRECTIVE ANNOTATION_VISIBILITY CLASS_DESCRIPTOR 558 annotation_element* END_ANNOTATION_DIRECTIVE 559 -> ^(I_ANNOTATION[$start, "I_ANNOTATION"] ANNOTATION_VISIBILITY ^(I_SUBANNOTATION[$start, "I_SUBANNOTATION"] CLASS_DESCRIPTOR annotation_element*)); 560 561subannotation 562 : SUBANNOTATION_DIRECTIVE CLASS_DESCRIPTOR annotation_element* END_SUBANNOTATION_DIRECTIVE 563 -> ^(I_SUBANNOTATION[$start, "I_SUBANNOTATION"] CLASS_DESCRIPTOR annotation_element*); 564 565enum_literal 566 : ENUM_DIRECTIVE reference_type_descriptor ARROW simple_name COLON reference_type_descriptor 567 -> ^(I_ENCODED_ENUM reference_type_descriptor simple_name reference_type_descriptor); 568 569type_field_method_literal 570 : reference_type_descriptor 571 ( ARROW 572 ( simple_name COLON nonvoid_type_descriptor -> ^(I_ENCODED_FIELD reference_type_descriptor simple_name nonvoid_type_descriptor) 573 | method_name method_prototype -> ^(I_ENCODED_METHOD reference_type_descriptor method_name method_prototype) 574 ) 575 | -> reference_type_descriptor 576 ) 577 | PRIMITIVE_TYPE 578 | VOID_TYPE; 579 580fully_qualified_method 581 : reference_type_descriptor ARROW method_name method_prototype 582 -> reference_type_descriptor method_name method_prototype; 583 584fully_qualified_field 585 : reference_type_descriptor ARROW simple_name COLON nonvoid_type_descriptor 586 -> reference_type_descriptor simple_name nonvoid_type_descriptor; 587 588label 589 : COLON simple_name -> ^(I_LABEL[$COLON, "I_LABEL"] simple_name I_ADDRESS[$start, Integer.toString($method::currentAddress)]); 590 591label_ref_or_offset 592 : COLON simple_name -> simple_name 593 | OFFSET 594 | NEGATIVE_INTEGER_LITERAL -> OFFSET[$NEGATIVE_INTEGER_LITERAL]; 595 596register_list 597 : REGISTER (COMMA REGISTER)* -> ^(I_REGISTER_LIST[$start, "I_REGISTER_LIST"] REGISTER*) 598 | ->^(I_REGISTER_LIST[$start, "I_REGISTER_LIST"]); 599 600register_range 601 : REGISTER (DOTDOT REGISTER)? -> ^(I_REGISTER_RANGE[$start, "I_REGISTER_RANGE"] REGISTER REGISTER?); 602 603verification_error_reference 604 : CLASS_DESCRIPTOR | fully_qualified_field | fully_qualified_method; 605 606catch_directive 607 : CATCH_DIRECTIVE nonvoid_type_descriptor OPEN_BRACE from=label_ref_or_offset DOTDOT to=label_ref_or_offset CLOSE_BRACE using=label_ref_or_offset 608 -> ^(I_CATCH[$start, "I_CATCH"] I_ADDRESS[$start, Integer.toString($method::currentAddress)] nonvoid_type_descriptor $from $to $using); 609 610catchall_directive 611 : CATCHALL_DIRECTIVE OPEN_BRACE from=label_ref_or_offset DOTDOT to=label_ref_or_offset CLOSE_BRACE using=label_ref_or_offset 612 -> ^(I_CATCHALL[$start, "I_CATCHALL"] I_ADDRESS[$start, Integer.toString($method::currentAddress)] $from $to $using); 613 614/*When there are annotations immediately after a parameter definition, we don't know whether they are parameter annotations 615or method annotations until we determine if there is an .end parameter directive. In either case, we still "consume" and parse 616the annotations. If it turns out that they are parameter annotations, we include them in the I_PARAMETER AST. Otherwise, we 617add them to the $statements_and_directives::methodAnnotations list*/ 618parameter_directive 619 @init {List<CommonTree> annotations = new ArrayList<CommonTree>();} 620 : PARAMETER_DIRECTIVE 621 STRING_LITERAL? 622 ({input.LA(1) == ANNOTATION_DIRECTIVE}? annotation {annotations.add($annotation.tree);})* 623 624 ( END_PARAMETER_DIRECTIVE 625 -> ^(I_PARAMETER[$start, "I_PARAMETER"] STRING_LITERAL? ^(I_ANNOTATIONS annotation*)) 626 | /*epsilon*/ {$statements_and_directives::methodAnnotations.addAll(annotations);} 627 -> ^(I_PARAMETER[$start, "I_PARAMETER"] STRING_LITERAL? ^(I_ANNOTATIONS)) 628 ); 629 630ordered_debug_directive 631 : line_directive 632 | local_directive 633 | end_local_directive 634 | restart_local_directive 635 | prologue_directive 636 | epilogue_directive 637 | source_directive; 638 639line_directive 640 : LINE_DIRECTIVE integral_literal 641 -> ^(I_LINE integral_literal I_ADDRESS[$start, Integer.toString($method::currentAddress)]); 642 643local_directive 644 : LOCAL_DIRECTIVE REGISTER COMMA simple_name COLON nonvoid_type_descriptor (COMMA STRING_LITERAL)? 645 -> ^(I_LOCAL[$start, "I_LOCAL"] REGISTER simple_name nonvoid_type_descriptor STRING_LITERAL? I_ADDRESS[$start, Integer.toString($method::currentAddress)]); 646 647end_local_directive 648 : END_LOCAL_DIRECTIVE REGISTER 649 -> ^(I_END_LOCAL[$start, "I_END_LOCAL"] REGISTER I_ADDRESS[$start, Integer.toString($method::currentAddress)]); 650 651restart_local_directive 652 : RESTART_LOCAL_DIRECTIVE REGISTER 653 -> ^(I_RESTART_LOCAL[$start, "I_RESTART_LOCAL"] REGISTER I_ADDRESS[$start, Integer.toString($method::currentAddress)]); 654 655prologue_directive 656 : PROLOGUE_DIRECTIVE 657 -> ^(I_PROLOGUE[$start, "I_PROLOGUE"] I_ADDRESS[$start, Integer.toString($method::currentAddress)]); 658 659epilogue_directive 660 : EPILOGUE_DIRECTIVE 661 -> ^(I_EPILOGUE[$start, "I_EPILOGUE"] I_ADDRESS[$start, Integer.toString($method::currentAddress)]); 662 663source_directive 664 : SOURCE_DIRECTIVE STRING_LITERAL 665 -> ^(I_SOURCE[$start, "I_SOURCE"] STRING_LITERAL I_ADDRESS[$start, Integer.toString($method::currentAddress)]); 666 667instruction_format12x 668 : INSTRUCTION_FORMAT12x 669 | INSTRUCTION_FORMAT12x_OR_ID -> INSTRUCTION_FORMAT12x[$INSTRUCTION_FORMAT12x_OR_ID]; 670 671instruction_format22s 672 : INSTRUCTION_FORMAT22s 673 | INSTRUCTION_FORMAT22s_OR_ID -> INSTRUCTION_FORMAT22s[$INSTRUCTION_FORMAT22s_OR_ID]; 674 675instruction_format31i 676 : INSTRUCTION_FORMAT31i 677 | INSTRUCTION_FORMAT31i_OR_ID -> INSTRUCTION_FORMAT31i[$INSTRUCTION_FORMAT31i_OR_ID]; 678 679instruction returns [int size] 680 @init {boolean needsNop = false; int targetCount = 0;} 681 : //e.g. goto endloop: 682 //e.g. goto +3 683 INSTRUCTION_FORMAT10t label_ref_or_offset {$size = Format.Format10t.size;} 684 -> ^(I_STATEMENT_FORMAT10t[$start, "I_STATEMENT_FORMAT10t"] INSTRUCTION_FORMAT10t label_ref_or_offset) 685 | //e.g. return 686 INSTRUCTION_FORMAT10x {$size = Format.Format10x.size;} 687 -> ^(I_STATEMENT_FORMAT10x[$start, "I_STATEMENT_FORMAT10x"] INSTRUCTION_FORMAT10x) 688 | //e.g. const/4 v0, 5 689 INSTRUCTION_FORMAT11n REGISTER COMMA integral_literal {$size = Format.Format11n.size;} 690 -> ^(I_STATEMENT_FORMAT11n[$start, "I_STATEMENT_FORMAT11n"] INSTRUCTION_FORMAT11n REGISTER integral_literal) 691 | //e.g. move-result-object v1 692 INSTRUCTION_FORMAT11x REGISTER {$size = Format.Format11x.size;} 693 -> ^(I_STATEMENT_FORMAT11x[$start, "I_STATEMENT_FORMAT11x"] INSTRUCTION_FORMAT11x REGISTER) 694 | //e.g. move v1 v2 695 instruction_format12x REGISTER COMMA REGISTER {$size = Format.Format12x.size;} 696 -> ^(I_STATEMENT_FORMAT12x[$start, "I_STATEMENT_FORMAT12x"] instruction_format12x REGISTER REGISTER) 697 | //e.g. throw-verification-error generic-error, Lsome/class; 698 INSTRUCTION_FORMAT20bc VERIFICATION_ERROR_TYPE COMMA verification_error_reference {$size += Format.Format20bc.size;} 699 { 700 if (!allowOdex) { 701 throwOdexedInstructionException(input, $INSTRUCTION_FORMAT20bc.text); 702 } 703 } 704 -> ^(I_STATEMENT_FORMAT20bc INSTRUCTION_FORMAT20bc VERIFICATION_ERROR_TYPE verification_error_reference) 705 | //e.g. goto/16 endloop: 706 INSTRUCTION_FORMAT20t label_ref_or_offset {$size = Format.Format20t.size;} 707 -> ^(I_STATEMENT_FORMAT20t[$start, "I_STATEMENT_FORMAT20t"] INSTRUCTION_FORMAT20t label_ref_or_offset) 708 | //e.g. sget-object v0 java/lang/System/out LJava/io/PrintStream; 709 INSTRUCTION_FORMAT21c_FIELD REGISTER COMMA fully_qualified_field {$size = Format.Format21c.size;} 710 -> ^(I_STATEMENT_FORMAT21c_FIELD[$start, "I_STATEMENT_FORMAT21c_FIELD"] INSTRUCTION_FORMAT21c_FIELD REGISTER fully_qualified_field) 711 | //e.g. sget-object-volatile v0 java/lang/System/out LJava/io/PrintStream; 712 INSTRUCTION_FORMAT21c_FIELD_ODEX REGISTER COMMA fully_qualified_field {$size = Format.Format21c.size;} 713 { 714 if (!allowOdex) { 715 throwOdexedInstructionException(input, $INSTRUCTION_FORMAT21c_FIELD_ODEX.text); 716 } 717 } 718 -> ^(I_STATEMENT_FORMAT21c_FIELD[$start, "I_STATEMENT_FORMAT21c_FIELD"] INSTRUCTION_FORMAT21c_FIELD_ODEX REGISTER fully_qualified_field) 719 | //e.g. const-string v1 "Hello World!" 720 INSTRUCTION_FORMAT21c_STRING REGISTER COMMA STRING_LITERAL {$size = Format.Format21c.size;} 721 -> ^(I_STATEMENT_FORMAT21c_STRING[$start, "I_STATEMENT_FORMAT21c_STRING"] INSTRUCTION_FORMAT21c_STRING REGISTER STRING_LITERAL) 722 | //e.g. const-class v2 Lorg/jf/HelloWorld2/HelloWorld2; 723 INSTRUCTION_FORMAT21c_TYPE REGISTER COMMA reference_type_descriptor {$size = Format.Format21c.size;} 724 -> ^(I_STATEMENT_FORMAT21c_TYPE[$start, "I_STATEMENT_FORMAT21c"] INSTRUCTION_FORMAT21c_TYPE REGISTER reference_type_descriptor) 725 | //e.g. const/high16 v1, 1234 726 INSTRUCTION_FORMAT21h REGISTER COMMA integral_literal {$size = Format.Format21h.size;} 727 -> ^(I_STATEMENT_FORMAT21h[$start, "I_STATEMENT_FORMAT21h"] INSTRUCTION_FORMAT21h REGISTER integral_literal) 728 | //e.g. const/16 v1, 1234 729 INSTRUCTION_FORMAT21s REGISTER COMMA integral_literal {$size = Format.Format21s.size;} 730 -> ^(I_STATEMENT_FORMAT21s[$start, "I_STATEMENT_FORMAT21s"] INSTRUCTION_FORMAT21s REGISTER integral_literal) 731 | //e.g. if-eqz v0, endloop: 732 INSTRUCTION_FORMAT21t REGISTER COMMA (label_ref_or_offset) {$size = Format.Format21t.size;} 733 -> ^(I_STATEMENT_FORMAT21t[$start, "I_STATEMENT_FORMAT21t"] INSTRUCTION_FORMAT21t REGISTER label_ref_or_offset) 734 | //e.g. add-int v0, v1, 123 735 INSTRUCTION_FORMAT22b REGISTER COMMA REGISTER COMMA integral_literal {$size = Format.Format22b.size;} 736 -> ^(I_STATEMENT_FORMAT22b[$start, "I_STATEMENT_FORMAT22b"] INSTRUCTION_FORMAT22b REGISTER REGISTER integral_literal) 737 | //e.g. iput-object v1, v0 org/jf/HelloWorld2/HelloWorld2.helloWorld Ljava/lang/String; 738 INSTRUCTION_FORMAT22c_FIELD REGISTER COMMA REGISTER COMMA fully_qualified_field {$size = Format.Format22c.size;} 739 -> ^(I_STATEMENT_FORMAT22c_FIELD[$start, "I_STATEMENT_FORMAT22c_FIELD"] INSTRUCTION_FORMAT22c_FIELD REGISTER REGISTER fully_qualified_field) 740 | //e.g. iput-object-volatile v1, v0 org/jf/HelloWorld2/HelloWorld2.helloWorld Ljava/lang/String; 741 INSTRUCTION_FORMAT22c_FIELD_ODEX REGISTER COMMA REGISTER COMMA fully_qualified_field {$size = Format.Format22c.size;} 742 { 743 if (!allowOdex) { 744 throwOdexedInstructionException(input, $INSTRUCTION_FORMAT22c_FIELD_ODEX.text); 745 } 746 } 747 -> ^(I_STATEMENT_FORMAT22c_FIELD[$start, "I_STATEMENT_FORMAT22c_FIELD"] INSTRUCTION_FORMAT22c_FIELD_ODEX REGISTER REGISTER fully_qualified_field) 748 | //e.g. instance-of v0, v1, Ljava/lang/String; 749 INSTRUCTION_FORMAT22c_TYPE REGISTER COMMA REGISTER COMMA nonvoid_type_descriptor {$size = Format.Format22c.size;} 750 -> ^(I_STATEMENT_FORMAT22c_TYPE[$start, "I_STATEMENT_FORMAT22c_TYPE"] INSTRUCTION_FORMAT22c_TYPE REGISTER REGISTER nonvoid_type_descriptor) 751 | //e.g. iget-quick v0, v1, field@0xc 752 INSTRUCTION_FORMAT22cs_FIELD REGISTER COMMA REGISTER COMMA FIELD_OFFSET 753 { 754 throwOdexedInstructionException(input, $INSTRUCTION_FORMAT22cs_FIELD.text); 755 } 756 | //e.g. add-int/lit16 v0, v1, 12345 757 instruction_format22s REGISTER COMMA REGISTER COMMA integral_literal {$size = Format.Format22s.size;} 758 -> ^(I_STATEMENT_FORMAT22s[$start, "I_STATEMENT_FORMAT22s"] instruction_format22s REGISTER REGISTER integral_literal) 759 | //e.g. if-eq v0, v1, endloop: 760 INSTRUCTION_FORMAT22t REGISTER COMMA REGISTER COMMA label_ref_or_offset {$size = Format.Format22t.size;} 761 -> ^(I_STATEMENT_FORMAT22t[$start, "I_STATEMENT_FFORMAT22t"] INSTRUCTION_FORMAT22t REGISTER REGISTER label_ref_or_offset) 762 | //e.g. move/from16 v1, v1234 763 INSTRUCTION_FORMAT22x REGISTER COMMA REGISTER {$size = Format.Format22x.size;} 764 -> ^(I_STATEMENT_FORMAT22x[$start, "I_STATEMENT_FORMAT22x"] INSTRUCTION_FORMAT22x REGISTER REGISTER) 765 | //e.g. add-int v1, v2, v3 766 INSTRUCTION_FORMAT23x REGISTER COMMA REGISTER COMMA REGISTER {$size = Format.Format23x.size;} 767 -> ^(I_STATEMENT_FORMAT23x[$start, "I_STATEMENT_FORMAT23x"] INSTRUCTION_FORMAT23x REGISTER REGISTER REGISTER) 768 | //e.g. goto/32 endloop: 769 INSTRUCTION_FORMAT30t label_ref_or_offset {$size = Format.Format30t.size;} 770 -> ^(I_STATEMENT_FORMAT30t[$start, "I_STATEMENT_FORMAT30t"] INSTRUCTION_FORMAT30t label_ref_or_offset) 771 | //e.g. const-string/jumbo v1 "Hello World!" 772 INSTRUCTION_FORMAT31c REGISTER COMMA STRING_LITERAL {$size = Format.Format31c.size;} 773 ->^(I_STATEMENT_FORMAT31c[$start, "I_STATEMENT_FORMAT31c"] INSTRUCTION_FORMAT31c REGISTER STRING_LITERAL) 774 | //e.g. const v0, 123456 775 instruction_format31i REGISTER COMMA fixed_32bit_literal {$size = Format.Format31i.size;} 776 -> ^(I_STATEMENT_FORMAT31i[$start, "I_STATEMENT_FORMAT31i"] instruction_format31i REGISTER fixed_32bit_literal) 777 | //e.g. fill-array-data v0, ArrayData: 778 INSTRUCTION_FORMAT31t REGISTER COMMA label_ref_or_offset {$size = Format.Format31t.size;} 779 { 780 if ($INSTRUCTION_FORMAT31t.text.equals("packed-switch")) { 781 CommonTree root = new CommonTree(new CommonToken(I_PACKED_SWITCH_DECLARATION, "I_PACKED_SWITCH_DECLARATION")); 782 CommonTree address = new CommonTree(new CommonToken(I_ADDRESS, Integer.toString($method::currentAddress))); 783 root.addChild(address); 784 root.addChild($label_ref_or_offset.tree.dupNode()); 785 $statements_and_directives::packedSwitchDeclarations.add(root); 786 } else if ($INSTRUCTION_FORMAT31t.text.equals("sparse-switch")) { 787 CommonTree root = new CommonTree(new CommonToken(I_SPARSE_SWITCH_DECLARATION, "I_SPARSE_SWITCH_DECLARATION")); 788 CommonTree address = new CommonTree(new CommonToken(I_ADDRESS, Integer.toString($method::currentAddress))); 789 root.addChild(address); 790 root.addChild($label_ref_or_offset.tree.dupNode()); 791 $statements_and_directives::sparseSwitchDeclarations.add(root); 792 } 793 } 794 -> ^(I_STATEMENT_FORMAT31t[$start, "I_STATEMENT_FORMAT31t"] INSTRUCTION_FORMAT31t REGISTER label_ref_or_offset) 795 | //e.g. move/16 v4567, v1234 796 INSTRUCTION_FORMAT32x REGISTER COMMA REGISTER {$size = Format.Format32x.size;} 797 -> ^(I_STATEMENT_FORMAT32x[$start, "I_STATEMENT_FORMAT32x"] INSTRUCTION_FORMAT32x REGISTER REGISTER) 798 | //e.g. invoke-virtual {v0,v1} java/io/PrintStream/print(Ljava/lang/Stream;)V 799 INSTRUCTION_FORMAT35c_METHOD OPEN_BRACE register_list CLOSE_BRACE COMMA fully_qualified_method {$size = Format.Format35c.size;} 800 -> ^(I_STATEMENT_FORMAT35c_METHOD[$start, "I_STATEMENT_FORMAT35c_METHOD"] INSTRUCTION_FORMAT35c_METHOD register_list fully_qualified_method) 801 | //e.g. filled-new-array {v0,v1}, I 802 INSTRUCTION_FORMAT35c_TYPE OPEN_BRACE register_list CLOSE_BRACE COMMA nonvoid_type_descriptor {$size = Format.Format35c.size;} 803 -> ^(I_STATEMENT_FORMAT35c_TYPE[$start, "I_STATEMENT_FORMAT35c_TYPE"] INSTRUCTION_FORMAT35c_TYPE register_list nonvoid_type_descriptor) 804 | //e.g. invoke-direct {p0}, Ljava/lang/Object;-><init>()V 805 INSTRUCTION_FORMAT35s_METHOD OPEN_BRACE register_list CLOSE_BRACE COMMA fully_qualified_method 806 { 807 throwOdexedInstructionException(input, $INSTRUCTION_FORMAT35s_METHOD.text); 808 } 809 | //e.g. invoke-virtual-range {v0, v1}, vtable@0x4 810 INSTRUCTION_FORMAT35ms_METHOD OPEN_BRACE register_list CLOSE_BRACE COMMA VTABLE_OFFSET 811 { 812 throwOdexedInstructionException(input, $INSTRUCTION_FORMAT35ms_METHOD.text); 813 } 814 | //e.g. invoke-virtual/range {v25..v26}, java/lang/StringBuilder/append(Ljava/lang/String;)Ljava/lang/StringBuilder; 815 INSTRUCTION_FORMAT3rc_METHOD OPEN_BRACE register_range CLOSE_BRACE COMMA fully_qualified_method {$size = Format.Format3rc.size;} 816 -> ^(I_STATEMENT_FORMAT3rc_METHOD[$start, "I_STATEMENT_FORMAT3rc_METHOD"] INSTRUCTION_FORMAT3rc_METHOD register_range fully_qualified_method) 817 | //e.g. filled-new-array/range {v0..v6}, I 818 INSTRUCTION_FORMAT3rc_TYPE OPEN_BRACE register_range CLOSE_BRACE COMMA nonvoid_type_descriptor {$size = Format.Format3rc.size;} 819 -> ^(I_STATEMENT_FORMAT3rc_TYPE[$start, "I_STATEMENT_FORMAT3rc_TYPE"] INSTRUCTION_FORMAT3rc_TYPE register_range nonvoid_type_descriptor) 820 | //e.g. invoke-virtual-quick/range {v0 .. v10}, vtable@0x14 821 INSTRUCTION_FORMAT3rms_METHOD OPEN_BRACE register_range CLOSE_BRACE COMMA VTABLE_OFFSET 822 { 823 throwOdexedInstructionException(input, $INSTRUCTION_FORMAT3rms_METHOD.text); 824 } 825 | //e.g. const-wide v0, 5000000000L 826 INSTRUCTION_FORMAT51l REGISTER COMMA fixed_literal {$size = Format.Format51l.size;} 827 -> ^(I_STATEMENT_FORMAT51l[$start, "I_STATEMENT_FORMAT51l"] INSTRUCTION_FORMAT51l REGISTER fixed_literal) 828 | 829 ARRAY_DATA_DIRECTIVE 830 { 831 if (($method::currentAddress \% 2) != 0) { 832 needsNop = true; 833 $size = 2; 834 } else { 835 $size = 0; 836 } 837 } 838 839 integral_literal (fixed_literal {$size+=$fixed_literal.size;})* END_ARRAY_DATA_DIRECTIVE 840 {$size = (($size + 1)/2)*2 + 8;} 841 842 /*add a nop statement before this if needed to force the correct alignment*/ 843 -> {needsNop}? ^(I_STATEMENT_FORMAT10x[$start, "I_STATEMENT_FORMAT10x"] INSTRUCTION_FORMAT10x[$start, "nop"]) 844 ^(I_STATEMENT_ARRAY_DATA ^(I_ARRAY_ELEMENT_SIZE integral_literal) ^(I_ARRAY_ELEMENTS fixed_literal*)) 845 846 -> ^(I_STATEMENT_ARRAY_DATA[$start, "I_STATEMENT_ARRAY_DATA"] ^(I_ARRAY_ELEMENT_SIZE integral_literal) 847 ^(I_ARRAY_ELEMENTS fixed_literal*)) 848 | 849 PACKED_SWITCH_DIRECTIVE 850 { 851 targetCount = 0; 852 if (($method::currentAddress \% 2) != 0) { 853 needsNop = true; 854 $size = 2; 855 } else { 856 $size = 0; 857 } 858 } 859 860 fixed_32bit_literal 861 862 (switch_target += label_ref_or_offset {$size+=4; targetCount++;})* 863 864 END_PACKED_SWITCH_DIRECTIVE {$size = $size + 8;} 865 866 /*add a nop statement before this if needed to force the correct alignment*/ 867 -> {needsNop}? ^(I_STATEMENT_FORMAT10x[$start, "I_STATEMENT_FORMAT10x"] INSTRUCTION_FORMAT10x[$start, "nop"]) 868 ^(I_STATEMENT_PACKED_SWITCH[$start, "I_STATEMENT_PACKED_SWITCH"] 869 ^(I_PACKED_SWITCH_START_KEY[$start, "I_PACKED_SWITCH_START_KEY"] fixed_32bit_literal) 870 ^(I_PACKED_SWITCH_TARGETS[$start, "I_PACKED_SWITCH_TARGETS"] I_PACKED_SWITCH_TARGET_COUNT[$start, Integer.toString(targetCount)] $switch_target*) 871 ) 872 873 -> ^(I_STATEMENT_PACKED_SWITCH[$start, "I_STATEMENT_PACKED_SWITCH"] 874 ^(I_PACKED_SWITCH_START_KEY[$start, "I_PACKED_SWITCH_START_KEY"] fixed_32bit_literal) 875 ^(I_PACKED_SWITCH_TARGETS[$start, "I_PACKED_SWITCH_TARGETS"] I_PACKED_SWITCH_TARGET_COUNT[$start, Integer.toString(targetCount)] $switch_target*) 876 ) 877 878 | 879 SPARSE_SWITCH_DIRECTIVE 880 { 881 targetCount = 0; 882 if (($method::currentAddress \% 2) != 0) { 883 needsNop = true; 884 $size = 2; 885 } else { 886 $size = 0; 887 } 888 } 889 890 (fixed_32bit_literal ARROW switch_target += label_ref_or_offset {$size += 8; targetCount++;})* 891 892 END_SPARSE_SWITCH_DIRECTIVE {$size = $size + 4;} 893 894 /*add a nop statement before this if needed to force the correct alignment*/ 895 -> {needsNop}? ^(I_STATEMENT_FORMAT10x[$start, "I_STATEMENT_FORMAT10x"] INSTRUCTION_FORMAT10x[$start, "nop"]) 896 ^(I_STATEMENT_SPARSE_SWITCH[$start, "I_STATEMENT_SPARSE_SWITCH"] 897 I_SPARSE_SWITCH_TARGET_COUNT[$start, Integer.toString(targetCount)] 898 ^(I_SPARSE_SWITCH_KEYS[$start, "I_SPARSE_SWITCH_KEYS"] fixed_32bit_literal*) 899 ^(I_SPARSE_SWITCH_TARGETS $switch_target*)) 900 -> ^(I_STATEMENT_SPARSE_SWITCH[$start, "I_STATEMENT_SPARSE_SWITCH"] 901 I_SPARSE_SWITCH_TARGET_COUNT[$start, Integer.toString(targetCount)] 902 ^(I_SPARSE_SWITCH_KEYS[$start, "I_SPARSE_SWITCH_KEYS"] fixed_32bit_literal*) 903 ^(I_SPARSE_SWITCH_TARGETS $switch_target*));