diff --git a/smali/src/main/antlr3/org/jf/smali/smaliParser.g b/smali/src/main/antlr3/org/jf/smali/smaliParser.g index b6146e84..e3f9f2a4 100644 --- a/smali/src/main/antlr3/org/jf/smali/smaliParser.g +++ b/smali/src/main/antlr3/org/jf/smali/smaliParser.g @@ -50,6 +50,7 @@ tokens { I_METHOD_PROTOTYPE; I_METHOD_RETURN_TYPE; I_REGISTERS; + I_LOCALS; I_LABELS; I_LABEL; I_ANNOTATIONS; @@ -316,7 +317,7 @@ statements_and_directives $statements_and_directives::methodAnnotations = new ArrayList(); } ( instruction {$method::currentAddress += $instruction.size/2;} - | {!$statements_and_directives::hasRegistersDirective}?=> registers_directive {$statements_and_directives::hasRegistersDirective = true;} + | registers_directive | label | catch_directive | catchall_directive @@ -324,7 +325,7 @@ statements_and_directives | ordered_debug_directive | annotation {$statements_and_directives::methodAnnotations.add($annotation.tree);} )* - -> ^(I_REGISTERS registers_directive?) + -> registers_directive? ^(I_LABELS label*) {buildTree(I_PACKED_SWITCH_DECLARATIONS, "I_PACKED_SWITCH_DECLARATIONS", $statements_and_directives::packedSwitchDeclarations)} {buildTree(I_SPARSE_SWITCH_DECLARATIONS, "I_SPARSE_SWITCH_DECLARATIONS", $statements_and_directives::sparseSwitchDeclarations)} @@ -335,8 +336,16 @@ statements_and_directives {buildTree(I_ANNOTATIONS, "I_ANNOTATIONS", $statements_and_directives::methodAnnotations)}; registers_directive - : (REGISTERS_DIRECTIVE | LOCALS_DIRECTIVE) integral_literal - -> REGISTERS_DIRECTIVE? LOCALS_DIRECTIVE? integral_literal; + : ( + REGISTERS_DIRECTIVE regCount=integral_literal -> ^(I_REGISTERS[$REGISTERS_DIRECTIVE, "I_REGISTERS"] $regCount) + | LOCALS_DIRECTIVE regCount2=integral_literal -> ^(I_LOCALS[$LOCALS_DIRECTIVE, "I_LOCALS"] $regCount2) + ) + { + if ($statements_and_directives::hasRegistersDirective) { + throw new SemanticException(input, $registers_directive.tree, "There can only be a single .registers or .locals directive in a method"); + } + $statements_and_directives::hasRegistersDirective=true; + }; /*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*/ diff --git a/smali/src/main/antlr3/org/jf/smali/smaliTreeWalker.g b/smali/src/main/antlr3/org/jf/smali/smaliTreeWalker.g index debb0c61..40633206 100644 --- a/smali/src/main/antlr3/org/jf/smali/smaliTreeWalker.g +++ b/smali/src/main/antlr3/org/jf/smali/smaliTreeWalker.g @@ -487,14 +487,7 @@ method returns[ ClassDataItem.EncodedMethod encodedMethod, methodParameterRegisters++; } } - registers_directive - { - if ($registers_directive.isLocalsDirective) { - totalMethodRegisters = $registers_directive.registers + methodParameterRegisters; - } else { - totalMethodRegisters = $registers_directive.registers; - } - } + registers_directive? labels packed_switch_declarations sparse_switch_declarations @@ -524,6 +517,12 @@ method returns[ ClassDataItem.EncodedMethod encodedMethod, codeItem = null; } else { + if ($registers_directive.isLocalsDirective) { + totalMethodRegisters = $registers_directive.registers + methodParameterRegisters; + } else { + totalMethodRegisters = $registers_directive.registers; + } + if (totalMethodRegisters < methodParameterRegisters) { throw new SemanticException(input, "This method requires at least " + Integer.toString(methodParameterRegisters) + @@ -614,12 +613,11 @@ fully_qualified_field returns[FieldIdItem fieldIdItem] registers_directive returns[boolean isLocalsDirective, int registers] : {$registers = 0;} - ^(I_REGISTERS - ( ( REGISTERS_DIRECTIVE {$isLocalsDirective = false;} - | LOCALS_DIRECTIVE {$isLocalsDirective = true;} - ) - short_integral_literal {$registers = $short_integral_literal.value;} - )?); + ^( ( I_REGISTERS {$isLocalsDirective = false;} + | I_LOCALS {$isLocalsDirective = true;} + ) + short_integral_literal {$registers = $short_integral_literal.value;} + ); labels : ^(I_LABELS label_def*);