- made the .registers directive optional. it defaults to .registers 0 if not present

- added logic to avoid creating an empty code_item (i.e. for abstract methods)
- changed the field and parameter syntax so that there is a colon instead of a whitespace between the field/local name and the following type
- changed the member name syntax, so that the initial class is specified with the preceeding 'L' and folling ';', and changed the seperator between the class name and the member name to '->' instead of just another '/'
- added the ability to specify members and fields as constants for static fields or annotations (note: dalvik doesn't seem to like embedded field references)
- fixed the short and byte literals in the parser (they were mistakenly using the _EMIT token)
- fixed an issue with char literals where the value was always a single quote
- renamed the CLASS_OR_ARRAY_TYPE_DESCRIPTOR token and related rules to REFERENCE_TYPE_DESCRIPTOR
- renamed the FIELD_TYPE_DESCRIPTOR token and related rules to NONVOID_TYPE_DESCRIPTOR

git-svn-id: https://smali.googlecode.com/svn/trunk@64 55b6fa8a-2a1e-11de-a435-ffa8d773f76a
This commit is contained in:
JesusFreke@JesusFreke.com 2009-06-03 04:58:54 +00:00
parent 5cf0028e73
commit 4250768620
3 changed files with 184 additions and 139 deletions

View File

@ -122,31 +122,31 @@ import java.util.ArrayDeque;
} }
public Token nextToken() { public Token nextToken() {
while (true) { while (true) {
if (tokens.size() > 0) { if (tokens.size() > 0) {
Token token = tokens.poll(); Token token = tokens.poll();
if (token == Token.SKIP_TOKEN) { if (token == Token.SKIP_TOKEN) {
continue; continue;
} }
System.out.println(token.toString()); System.out.println(token.toString());
return token; return token;
} }
state.channel = Token.DEFAULT_CHANNEL; state.channel = Token.DEFAULT_CHANNEL;
state.tokenStartCharIndex = input.index(); state.tokenStartCharIndex = input.index();
state.tokenStartCharPositionInLine = input.getCharPositionInLine(); state.tokenStartCharPositionInLine = input.getCharPositionInLine();
state.tokenStartLine = input.getLine(); state.tokenStartLine = input.getLine();
state.text = null; state.text = null;
if ( input.LA(1)==CharStream.EOF ) { if ( input.LA(1)==CharStream.EOF ) {
return Token.EOF_TOKEN; return Token.EOF_TOKEN;
} }
try { try {
mTokens(); mTokens();
if (tokens.size() == 0) { if (tokens.size() == 0) {
emit(); emit();
} }
} }
catch (NoViableAltException nva) { catch (NoViableAltException nva) {
reportError(nva); reportError(nva);
@ -177,11 +177,6 @@ import java.util.ArrayDeque;
token.setChannel(channel); token.setChannel(channel);
tokens.add(token); tokens.add(token);
} }
public void reportError(RecognitionException e)
{
throw new RuntimeException(e);
}
} }
@ -212,8 +207,8 @@ FIELD_PHRASE
WS WS
(FIELD_ACCESS_SPEC_EMIT WS)+ (FIELD_ACCESS_SPEC_EMIT WS)+
MEMBER_NAME_EMIT MEMBER_NAME_EMIT
WS COLON_EMIT
FIELD_TYPE_DESCRIPTOR_EMITCHILD NONVOID_TYPE_DESCRIPTOR_EMITCHILD
WS? WS?
(EQUAL_EMIT WS? LITERAL_EMITCHILD)?; (EQUAL_EMIT WS? LITERAL_EMITCHILD)?;
@ -267,9 +262,7 @@ INSTRUCTION_FORMAT21c_FIELD_PHRASE
WS WS
REGISTER_EMIT REGISTER_EMIT
WS? COMMA_EMIT WS? WS? COMMA_EMIT WS?
FULLY_QUALIFIED_MEMBER_NAME_EMITCHILDREN FULLY_QUALIFIED_FIELD_EMITCHILDREN;
WS
FIELD_TYPE_DESCRIPTOR_EMITCHILD;
INSTRUCTION_FORMAT21c_STRING_PHRASE INSTRUCTION_FORMAT21c_STRING_PHRASE
: INSTRUCTION_FORMAT21c_STRING_EMIT : INSTRUCTION_FORMAT21c_STRING_EMIT
@ -283,7 +276,7 @@ INSTRUCTION_FORMAT21c_TYPE_PHRASE
WS WS
REGISTER_EMIT REGISTER_EMIT
WS? COMMA_EMIT WS? WS? COMMA_EMIT WS?
CLASS_OR_ARRAY_TYPE_DESCRIPTOR_EMITCHILD; REFERENCE_TYPE_DESCRIPTOR_EMITCHILD;
INSTRUCTION_FORMAT21h_PHRASE INSTRUCTION_FORMAT21h_PHRASE
: INSTRUCTION_FORMAT21h_EMIT : INSTRUCTION_FORMAT21h_EMIT
@ -322,9 +315,7 @@ INSTRUCTION_FORMAT22c_FIELD_PHRASE
WS? COMMA_EMIT WS? WS? COMMA_EMIT WS?
REGISTER_EMIT REGISTER_EMIT
WS? COMMA_EMIT WS? WS? COMMA_EMIT WS?
FULLY_QUALIFIED_MEMBER_NAME_EMITCHILDREN FULLY_QUALIFIED_FIELD_EMITCHILDREN;
WS
FIELD_TYPE_DESCRIPTOR_EMITCHILD;
INSTRUCTION_FORMAT22c_TYPE_PHRASE INSTRUCTION_FORMAT22c_TYPE_PHRASE
: INSTRUCTION_FORMAT22c_TYPE_EMIT : INSTRUCTION_FORMAT22c_TYPE_EMIT
@ -333,7 +324,7 @@ INSTRUCTION_FORMAT22c_TYPE_PHRASE
WS? COMMA_EMIT WS? WS? COMMA_EMIT WS?
REGISTER_EMIT REGISTER_EMIT
WS? COMMA_EMIT WS? WS? COMMA_EMIT WS?
FIELD_TYPE_DESCRIPTOR_EMITCHILD; NONVOID_TYPE_DESCRIPTOR_EMITCHILD;
INSTRUCTION_FORMAT22s_PHRASE INSTRUCTION_FORMAT22s_PHRASE
: INSTRUCTION_FORMAT22s_EMIT : INSTRUCTION_FORMAT22s_EMIT
@ -407,16 +398,14 @@ INSTRUCTION_FORMAT35c_METHOD_PHRASE
WS WS
REGISTER_LIST_EMITCHILDREN REGISTER_LIST_EMITCHILDREN
WS? COMMA_EMIT WS? WS? COMMA_EMIT WS?
FULLY_QUALIFIED_MEMBER_NAME_EMITCHILDREN FULLY_QUALIFIED_METHOD_EMITCHILDREN;
METHOD_PROTOTYPE_EMITCHILDREN;
INSTRUCTION_FORMAT3rc_METHOD_PHRASE INSTRUCTION_FORMAT3rc_METHOD_PHRASE
: INSTRUCTION_FORMAT3rc_METHOD_EMIT : INSTRUCTION_FORMAT3rc_METHOD_EMIT
WS WS
REGISTER_RANGE_EMITCHILDREN REGISTER_RANGE_EMITCHILDREN
WS? COMMA_EMIT WS? WS? COMMA_EMIT WS?
FULLY_QUALIFIED_MEMBER_NAME_EMITCHILDREN FULLY_QUALIFIED_METHOD_EMITCHILDREN;
METHOD_PROTOTYPE_EMITCHILDREN;
INSTRUCTION_FORMAT51l_PHRASE INSTRUCTION_FORMAT51l_PHRASE
: INSTRUCTION_FORMAT51l_EMIT : INSTRUCTION_FORMAT51l_EMIT
@ -459,7 +448,7 @@ REGISTERS_PHRASE
CATCH_PHRASE CATCH_PHRASE
: CATCH_DIRECTIVE_EMIT : CATCH_DIRECTIVE_EMIT
WS WS
FIELD_TYPE_DESCRIPTOR_EMITCHILD NONVOID_TYPE_DESCRIPTOR_EMITCHILD
WS? '{' WS? WS? '{' WS?
(LABEL_EMIT | OFFSET_EMIT) (LABEL_EMIT | OFFSET_EMIT)
WS '..' WS WS '..' WS
@ -485,8 +474,8 @@ LOCAL_PHRASE
REGISTER_EMIT REGISTER_EMIT
WS? COMMA_EMIT WS? WS? COMMA_EMIT WS?
SIMPLE_NAME_EMIT SIMPLE_NAME_EMIT
WS COLON_EMIT
FIELD_TYPE_DESCRIPTOR_EMITCHILD NONVOID_TYPE_DESCRIPTOR_EMITCHILD
WS? WS?
( COMMA_EMIT WS? STRING_LITERAL_EMIT)?; ( COMMA_EMIT WS? STRING_LITERAL_EMIT)?;
@ -673,29 +662,35 @@ fragment REGISTER_RANGE_EMITCHILDREN
fragment METHOD_PROTOTYPE_EMITCHILDREN fragment METHOD_PROTOTYPE_EMITCHILDREN
: OPEN_PAREN_EMIT : OPEN_PAREN_EMIT
(FIELD_TYPE_DESCRIPTOR_EMITCHILD+)? (NONVOID_TYPE_DESCRIPTOR_EMITCHILD+)?
CLOSE_PAREN_EMIT CLOSE_PAREN_EMIT
TYPE_DESCRIPTOR_EMITCHILD; TYPE_DESCRIPTOR_EMITCHILD;
fragment FULLY_QUALIFIED_MEMBER_NAME_EMITCHILDREN fragment FULLY_QUALIFIED_FIELD_EMITCHILDREN
@init {int startPos;} : REFERENCE_TYPE_DESCRIPTOR_EMITCHILD
: {startPos = getCharIndex();} (SIMPLE_NAME '/')* token=SIMPLE_NAME {((CommonToken)$token).setStartIndex(startPos); emit($token, CLASS_NAME);} ARROW_EMIT
'/' MEMBER_NAME_EMIT
MEMBER_NAME_EMIT; COLON_EMIT
NONVOID_TYPE_DESCRIPTOR_EMITCHILD;
fragment FULLY_QUALIFIED_METHOD_EMITCHILDREN
: REFERENCE_TYPE_DESCRIPTOR_EMITCHILD
ARROW_EMIT
MEMBER_NAME_EMIT
METHOD_PROTOTYPE_EMITCHILDREN;
fragment TYPE_DESCRIPTOR_EMITCHILD fragment TYPE_DESCRIPTOR_EMITCHILD
: PRIMITIVE_TYPE_EMIT : PRIMITIVE_TYPE_EMIT
| VOID_TYPE_EMIT | VOID_TYPE_EMIT
| CLASS_DESCRIPTOR_EMIT | CLASS_DESCRIPTOR_EMIT
| ARRAY_DESCRIPTOR_EMIT; | ARRAY_DESCRIPTOR_EMIT;
fragment NONVOID_TYPE_DESCRIPTOR_EMITCHILD
fragment FIELD_TYPE_DESCRIPTOR_EMITCHILD
: PRIMITIVE_TYPE_EMIT : PRIMITIVE_TYPE_EMIT
| CLASS_DESCRIPTOR_EMIT | CLASS_DESCRIPTOR_EMIT
| ARRAY_DESCRIPTOR_EMIT; | ARRAY_DESCRIPTOR_EMIT;
fragment CLASS_OR_ARRAY_TYPE_DESCRIPTOR_EMITCHILD fragment REFERENCE_TYPE_DESCRIPTOR_EMITCHILD
: CLASS_DESCRIPTOR_EMIT : CLASS_DESCRIPTOR_EMIT
| ARRAY_DESCRIPTOR_EMIT; | ARRAY_DESCRIPTOR_EMIT;
@ -724,10 +719,7 @@ fragment CLASS_DESCRIPTOR_EMIT
: CLASS_DESCRIPTOR {emit($CLASS_DESCRIPTOR, CLASS_DESCRIPTOR);}; : CLASS_DESCRIPTOR {emit($CLASS_DESCRIPTOR, CLASS_DESCRIPTOR);};
fragment CLASS_DESCRIPTOR fragment CLASS_DESCRIPTOR
: 'L' CLASS_NAME ';'; : 'L' (SIMPLE_NAME '/')* SIMPLE_NAME ';';
fragment CLASS_NAME
: (SIMPLE_NAME '/')* SIMPLE_NAME;
fragment ARRAY_DESCRIPTOR_EMIT fragment ARRAY_DESCRIPTOR_EMIT
@ -848,9 +840,9 @@ fragment LITERAL_EMITCHILD
| DOUBLE_LITERAL_EMIT | DOUBLE_LITERAL_EMIT
| CHAR_LITERAL_EMIT | CHAR_LITERAL_EMIT
| BOOL_LITERAL_EMIT | BOOL_LITERAL_EMIT
| TYPE_DESCRIPTOR_EMITCHILD
| ARRAY_LITERAL_EMITCHILDREN | ARRAY_LITERAL_EMITCHILDREN
| SUBANNOTATION_EMITCHILDREN; | SUBANNOTATION_EMITCHILDREN
| TYPE_FIELD_METHOD_LITERAL_EMITCHILDREN;
fragment SUBANNOTATION_EMITCHILDREN fragment SUBANNOTATION_EMITCHILDREN
: SUBANNOTATION_START_EMIT : SUBANNOTATION_START_EMIT
@ -894,7 +886,17 @@ fragment ANNOTATION_ELEMENT_EMITCHILDREN
EQUAL_EMIT EQUAL_EMIT
WS? WS?
LITERAL_EMITCHILD; LITERAL_EMITCHILD;
fragment TYPE_FIELD_METHOD_LITERAL_EMITCHILDREN
: REFERENCE_TYPE_DESCRIPTOR_EMITCHILD
( ARROW_EMIT
MEMBER_NAME_EMIT
( METHOD_PROTOTYPE_EMITCHILDREN
| COLON_EMIT NONVOID_TYPE_DESCRIPTOR_EMITCHILD))?
//TODO: allow void and primitive type here?
| PRIMITIVE_TYPE_EMIT
| VOID_TYPE_EMIT;
fragment ARRAY_LITERAL_EMITCHILDREN fragment ARRAY_LITERAL_EMITCHILDREN
: ARRAY_START_EMIT : ARRAY_START_EMIT
WS? WS?
@ -1414,3 +1416,13 @@ fragment COMMA_EMIT
: COMMA {emit($COMMA, COMMA, Token.HIDDEN_CHANNEL);}; : COMMA {emit($COMMA, COMMA, Token.HIDDEN_CHANNEL);};
fragment COMMA fragment COMMA
: ','; : ',';
fragment COLON_EMIT
: COLON {emit($COLON, COLON, Token.HIDDEN_CHANNEL);};
fragment COLON
: ':';
fragment ARROW_EMIT
: ARROW {emit($ARROW, ARROW);};
fragment ARROW
: '->';

View File

@ -56,6 +56,8 @@ tokens {
I_ANNOTATION; I_ANNOTATION;
I_ANNOTATION_ELEMENT; I_ANNOTATION_ELEMENT;
I_SUBANNOTATION; I_SUBANNOTATION;
I_ENCODED_FIELD;
I_ENCODED_METHOD;
I_ENCODED_ARRAY; I_ENCODED_ARRAY;
I_ARRAY_ELEMENT_SIZE; I_ARRAY_ELEMENT_SIZE;
I_ARRAY_ELEMENTS; I_ARRAY_ELEMENTS;
@ -113,9 +115,6 @@ tokens {
I_STATEMENT_SPARSE_SWITCH; I_STATEMENT_SPARSE_SWITCH;
I_REGISTER_RANGE; I_REGISTER_RANGE;
I_REGISTER_LIST; I_REGISTER_LIST;
CLASS_NAME;
MEMBER_NAME;
} }
@header { @header {
@ -200,11 +199,11 @@ access_list
: ACCESS_SPEC+ -> ^(I_ACCESS_LIST[$start,"I_ACCESS_LIST"] ACCESS_SPEC+); : ACCESS_SPEC+ -> ^(I_ACCESS_LIST[$start,"I_ACCESS_LIST"] ACCESS_SPEC+);
field : FIELD_DIRECTIVE access_list MEMBER_NAME field_type_descriptor literal? field : FIELD_DIRECTIVE access_list MEMBER_NAME nonvoid_type_descriptor literal?
( (annotation+ END_FIELD_DIRECTIVE)=> annotation+ END_FIELD_DIRECTIVE ( (annotation+ END_FIELD_DIRECTIVE)=> annotation+ END_FIELD_DIRECTIVE
| END_FIELD_DIRECTIVE? | END_FIELD_DIRECTIVE?
) )
-> ^(I_FIELD[$start, "I_FIELD"] MEMBER_NAME access_list ^(I_FIELD_TYPE field_type_descriptor) ^(I_FIELD_INITIAL_VALUE literal)? ^(I_ANNOTATIONS annotation*)); -> ^(I_FIELD[$start, "I_FIELD"] MEMBER_NAME access_list ^(I_FIELD_TYPE nonvoid_type_descriptor) ^(I_FIELD_INITIAL_VALUE literal)? ^(I_ANNOTATIONS annotation*));
method method
scope {int currentAddress;} scope {int currentAddress;}
@ -215,15 +214,17 @@ method
-> ^(I_METHOD[$start, "I_METHOD"] MEMBER_NAME method_prototype access_list statements_and_directives); -> ^(I_METHOD[$start, "I_METHOD"] MEMBER_NAME method_prototype access_list statements_and_directives);
method_prototype method_prototype
: OPEN_PAREN field_type_descriptor* CLOSE_PAREN type_descriptor : OPEN_PAREN nonvoid_type_descriptor* CLOSE_PAREN type_descriptor
-> ^(I_METHOD_PROTOTYPE[$start, "I_METHOD_PROTOTYPE"] ^(I_METHOD_RETURN_TYPE type_descriptor) field_type_descriptor*); -> ^(I_METHOD_PROTOTYPE[$start, "I_METHOD_PROTOTYPE"] ^(I_METHOD_RETURN_TYPE type_descriptor) nonvoid_type_descriptor*);
fully_qualified_method fully_qualified_method
: CLASS_NAME MEMBER_NAME method_prototype; : reference_type_descriptor ARROW MEMBER_NAME method_prototype
-> reference_type_descriptor MEMBER_NAME method_prototype;
fully_qualified_field fully_qualified_field
: CLASS_NAME MEMBER_NAME field_type_descriptor; : reference_type_descriptor ARROW MEMBER_NAME nonvoid_type_descriptor
-> reference_type_descriptor MEMBER_NAME nonvoid_type_descriptor;
statements_and_directives statements_and_directives
scope {boolean hasRegistersDirective;} scope {boolean hasRegistersDirective;}
@ -239,13 +240,7 @@ statements_and_directives
| ordered_debug_directive | ordered_debug_directive
| annotation | annotation
)* )*
{ -> ^(I_REGISTERS registers_directive?)
if (!$statements_and_directives::hasRegistersDirective) {
//TODO: throw correct exception type here
throw new RuntimeException("This method has no register directive");
}
}
-> registers_directive
^(I_LABELS label*) ^(I_LABELS label*)
^(I_STATEMENTS instruction*) ^(I_STATEMENTS instruction*)
^(I_CATCHES catch_directive*) ^(I_CATCHES catch_directive*)
@ -255,11 +250,11 @@ statements_and_directives
registers_directive registers_directive
: REGISTERS_DIRECTIVE integral_literal : REGISTERS_DIRECTIVE integral_literal
-> ^(I_REGISTERS[$start, "I_REGISTERS"] integral_literal); -> integral_literal;
catch_directive catch_directive
: CATCH_DIRECTIVE field_type_descriptor from=offset_or_label to=offset_or_label using=offset_or_label : CATCH_DIRECTIVE nonvoid_type_descriptor from=offset_or_label to=offset_or_label using=offset_or_label
-> ^(I_CATCH[$start, "I_CATCH"] I_ADDRESS[$start, Integer.toString($method::currentAddress)] field_type_descriptor $from $to $using) -> ^(I_CATCH[$start, "I_CATCH"] I_ADDRESS[$start, Integer.toString($method::currentAddress)] nonvoid_type_descriptor $from $to $using)
; ;
@ -290,8 +285,8 @@ line_directive
-> ^(I_LINE integral_literal I_ADDRESS[$start, Integer.toString($method::currentAddress)]); -> ^(I_LINE integral_literal I_ADDRESS[$start, Integer.toString($method::currentAddress)]);
local_directive local_directive
: LOCAL_DIRECTIVE REGISTER SIMPLE_NAME field_type_descriptor STRING_LITERAL? : LOCAL_DIRECTIVE REGISTER SIMPLE_NAME nonvoid_type_descriptor STRING_LITERAL?
-> ^(I_LOCAL[$start, "I_LOCAL"] REGISTER SIMPLE_NAME field_type_descriptor STRING_LITERAL? I_ADDRESS[$start, Integer.toString($method::currentAddress)]); -> ^(I_LOCAL[$start, "I_LOCAL"] REGISTER SIMPLE_NAME nonvoid_type_descriptor STRING_LITERAL? I_ADDRESS[$start, Integer.toString($method::currentAddress)]);
end_local_directive end_local_directive
: END_LOCAL_DIRECTIVE REGISTER : END_LOCAL_DIRECTIVE REGISTER
@ -344,8 +339,8 @@ instruction returns [int size]
INSTRUCTION_FORMAT21c_STRING REGISTER STRING_LITERAL {$size = Format21c.Format.getByteCount();} INSTRUCTION_FORMAT21c_STRING REGISTER STRING_LITERAL {$size = Format21c.Format.getByteCount();}
-> ^(I_STATEMENT_FORMAT21c_STRING[$start, "I_STATEMENT_FORMAT21c_STRING"] INSTRUCTION_FORMAT21c_STRING REGISTER STRING_LITERAL) -> ^(I_STATEMENT_FORMAT21c_STRING[$start, "I_STATEMENT_FORMAT21c_STRING"] INSTRUCTION_FORMAT21c_STRING REGISTER STRING_LITERAL)
| //e.g. const-class v2 org/JesusFreke/HelloWorld2/HelloWorld2 | //e.g. const-class v2 org/JesusFreke/HelloWorld2/HelloWorld2
INSTRUCTION_FORMAT21c_TYPE REGISTER class_or_array_type_descriptor {$size = Format21c.Format.getByteCount();} INSTRUCTION_FORMAT21c_TYPE REGISTER reference_type_descriptor {$size = Format21c.Format.getByteCount();}
-> ^(I_STATEMENT_FORMAT21c_TYPE[$start, "I_STATEMENT_FORMAT21c"] INSTRUCTION_FORMAT21c_TYPE REGISTER class_or_array_type_descriptor) -> ^(I_STATEMENT_FORMAT21c_TYPE[$start, "I_STATEMENT_FORMAT21c"] INSTRUCTION_FORMAT21c_TYPE REGISTER reference_type_descriptor)
| //e.g. const/high16 v1, 1234 | //e.g. const/high16 v1, 1234
INSTRUCTION_FORMAT21h REGISTER integral_literal {$size = Format21h.Format.getByteCount();} INSTRUCTION_FORMAT21h REGISTER integral_literal {$size = Format21h.Format.getByteCount();}
-> ^(I_STATEMENT_FORMAT21h[$start, "I_STATEMENT_FORMAT21h"] INSTRUCTION_FORMAT21h REGISTER integral_literal) -> ^(I_STATEMENT_FORMAT21h[$start, "I_STATEMENT_FORMAT21h"] INSTRUCTION_FORMAT21h REGISTER integral_literal)
@ -362,8 +357,8 @@ instruction returns [int size]
INSTRUCTION_FORMAT22c_FIELD REGISTER REGISTER fully_qualified_field {$size = Format22c.Format.getByteCount();} INSTRUCTION_FORMAT22c_FIELD REGISTER REGISTER fully_qualified_field {$size = Format22c.Format.getByteCount();}
-> ^(I_STATEMENT_FORMAT22c_FIELD[$start, "I_STATEMENT_FORMAT22c_FIELD"] INSTRUCTION_FORMAT22c_FIELD REGISTER REGISTER fully_qualified_field) -> ^(I_STATEMENT_FORMAT22c_FIELD[$start, "I_STATEMENT_FORMAT22c_FIELD"] INSTRUCTION_FORMAT22c_FIELD REGISTER REGISTER fully_qualified_field)
| //e.g. instance-of v0, v1, Ljava/lang/String; | //e.g. instance-of v0, v1, Ljava/lang/String;
INSTRUCTION_FORMAT22c_TYPE REGISTER REGISTER field_type_descriptor {$size = Format22c.Format.getByteCount();} INSTRUCTION_FORMAT22c_TYPE REGISTER REGISTER nonvoid_type_descriptor {$size = Format22c.Format.getByteCount();}
-> ^(I_STATEMENT_FORMAT22c_TYPE[$start, "I_STATEMENT_FORMAT22c_TYPE"] INSTRUCTION_FORMAT22c_TYPE REGISTER REGISTER field_type_descriptor) -> ^(I_STATEMENT_FORMAT22c_TYPE[$start, "I_STATEMENT_FORMAT22c_TYPE"] INSTRUCTION_FORMAT22c_TYPE REGISTER REGISTER nonvoid_type_descriptor)
| //e.g. add-int/lit16 v0, v1, 12345 | //e.g. add-int/lit16 v0, v1, 12345
INSTRUCTION_FORMAT22s REGISTER REGISTER integral_literal {$size = Format22s.Format.getByteCount();} INSTRUCTION_FORMAT22s REGISTER REGISTER integral_literal {$size = Format22s.Format.getByteCount();}
-> ^(I_STATEMENT_FORMAT22s[$start, "I_STATEMENT_FORMAT22s"] INSTRUCTION_FORMAT22s REGISTER REGISTER integral_literal) -> ^(I_STATEMENT_FORMAT22s[$start, "I_STATEMENT_FORMAT22s"] INSTRUCTION_FORMAT22s REGISTER REGISTER integral_literal)
@ -496,13 +491,13 @@ register_range
: REGISTER REGISTER? -> ^(I_REGISTER_RANGE[$start, "I_REGISTER_RANGE"] REGISTER REGISTER?); : REGISTER REGISTER? -> ^(I_REGISTER_RANGE[$start, "I_REGISTER_RANGE"] REGISTER REGISTER?);
field_type_descriptor nonvoid_type_descriptor
: PRIMITIVE_TYPE : PRIMITIVE_TYPE
| CLASS_DESCRIPTOR | CLASS_DESCRIPTOR
| ARRAY_DESCRIPTOR | ARRAY_DESCRIPTOR
; ;
class_or_array_type_descriptor reference_type_descriptor
: CLASS_DESCRIPTOR : CLASS_DESCRIPTOR
| ARRAY_DESCRIPTOR; | ARRAY_DESCRIPTOR;
@ -541,16 +536,16 @@ fixed_literal returns[int size]
literal literal
: INTEGER_LITERAL : INTEGER_LITERAL
| LONG_LITERAL | LONG_LITERAL
| SHORT_LITERAL_EMIT | SHORT_LITERAL
| BYTE_LITERAL_EMIT | BYTE_LITERAL
| FLOAT_LITERAL | FLOAT_LITERAL
| DOUBLE_LITERAL | DOUBLE_LITERAL
| CHAR_LITERAL | CHAR_LITERAL
| STRING_LITERAL | STRING_LITERAL
| BOOL_LITERAL | BOOL_LITERAL
| type_descriptor
| array_literal | array_literal
| subannotation; | subannotation
| type_field_method;
array_literal array_literal
: ARRAY_START literal* ARRAY_END : ARRAY_START literal* ARRAY_END
@ -568,3 +563,14 @@ annotation_element
subannotation subannotation
: SUBANNOTATION_START CLASS_DESCRIPTOR annotation_element* SUBANNOTATION_END : SUBANNOTATION_START CLASS_DESCRIPTOR annotation_element* SUBANNOTATION_END
-> ^(I_SUBANNOTATION[$start, "I_SUBANNOTATION"] CLASS_DESCRIPTOR annotation_element*); -> ^(I_SUBANNOTATION[$start, "I_SUBANNOTATION"] CLASS_DESCRIPTOR annotation_element*);
type_field_method
: reference_type_descriptor
( ARROW MEMBER_NAME
( nonvoid_type_descriptor -> ^(I_ENCODED_FIELD reference_type_descriptor MEMBER_NAME nonvoid_type_descriptor)
| method_prototype -> ^(I_ENCODED_METHOD reference_type_descriptor MEMBER_NAME method_prototype)
)
| -> reference_type_descriptor
)
| PRIMITIVE_TYPE
| VOID_TYPE;

View File

@ -197,11 +197,11 @@ methods returns[List<AnnotationDirectoryItem.MethodAnnotation> methodAnnotationS
})*); })*);
field returns[ClassDataItem.EncodedField encodedField, EncodedValue encodedValue, AnnotationDirectoryItem.FieldAnnotation fieldAnnotationSet] field returns[ClassDataItem.EncodedField encodedField, EncodedValue encodedValue, AnnotationDirectoryItem.FieldAnnotation fieldAnnotationSet]
:^(I_FIELD MEMBER_NAME access_list ^(I_FIELD_TYPE field_type_descriptor) field_initial_value annotations?) :^(I_FIELD MEMBER_NAME access_list ^(I_FIELD_TYPE nonvoid_type_descriptor) field_initial_value annotations?)
{ {
TypeIdItem classType = classDefItem.getClassType(); TypeIdItem classType = classDefItem.getClassType();
StringIdItem memberName = new StringIdItem(dexFile, $MEMBER_NAME.text); StringIdItem memberName = new StringIdItem(dexFile, $MEMBER_NAME.text);
TypeIdItem fieldType = $field_type_descriptor.type; TypeIdItem fieldType = $nonvoid_type_descriptor.type;
FieldIdItem fieldIdItem = new FieldIdItem(dexFile, classType, memberName, fieldType); FieldIdItem fieldIdItem = new FieldIdItem(dexFile, classType, memberName, fieldType);
$encodedField = new ClassDataItem.EncodedField(dexFile, fieldIdItem, $access_list.value); $encodedField = new ClassDataItem.EncodedField(dexFile, fieldIdItem, $access_list.value);
@ -239,7 +239,9 @@ literal returns[EncodedValue encodedValue]
| bool_literal { $encodedValue = new EncodedValue(dexFile, new BoolEncodedValueSubField($bool_literal.value)); } | bool_literal { $encodedValue = new EncodedValue(dexFile, new BoolEncodedValueSubField($bool_literal.value)); }
| type_descriptor { $encodedValue = new EncodedValue(dexFile, new EncodedIndexedItemReference(dexFile, $type_descriptor.type)); } | type_descriptor { $encodedValue = new EncodedValue(dexFile, new EncodedIndexedItemReference(dexFile, $type_descriptor.type)); }
| array_literal { $encodedValue = new EncodedValue(dexFile, new ArrayEncodedValueSubField(dexFile, $array_literal.values)); } | array_literal { $encodedValue = new EncodedValue(dexFile, new ArrayEncodedValueSubField(dexFile, $array_literal.values)); }
| subannotation { $encodedValue = new EncodedValue(dexFile, $subannotation.value); }; | subannotation { $encodedValue = new EncodedValue(dexFile, $subannotation.value); }
| field_literal { $encodedValue = new EncodedValue(dexFile, $field_literal.value); }
| method_literal { $encodedValue = new EncodedValue(dexFile, $method_literal.value); };
//everything but string //everything but string
@ -355,46 +357,59 @@ method returns[ ClassDataItem.EncodedMethod encodedMethod,
parameters parameters
ordered_debug_directives ordered_debug_directives
annotations annotations
) )
{ {
MethodIdItem methodIdItem = $method_name_and_prototype.methodIdItem; MethodIdItem methodIdItem = $method_name_and_prototype.methodIdItem;
int registers = $registers_directive.registers;
int access = $access_list.value; int access = $access_list.value;
boolean isStatic = (access & AccessFlags.STATIC) != 0; boolean isStatic = (access & AccessFlags.STATIC) != 0;
int registers = $registers_directive.registers;
ArrayList<Instruction> instructions = $statements.instructions; ArrayList<Instruction> instructions = $statements.instructions;
int minRegisters = methodIdItem.getParameterRegisterCount((access & AccessFlags.STATIC) != 0);
if (registers < minRegisters) {
//TODO: throw the correct exception type
throw new RuntimeException( "This method requires at least " +
Integer.toString(minRegisters) +
" registers, for the method parameters");
}
Pair<List<CodeItem.TryItem>, List<CodeItem.EncodedCatchHandler>> temp = $method::tryList.encodeTries(dexFile); Pair<List<CodeItem.TryItem>, List<CodeItem.EncodedCatchHandler>> temp = $method::tryList.encodeTries(dexFile);
List<CodeItem.TryItem> tries = temp.first; List<CodeItem.TryItem> tries = temp.first;
List<CodeItem.EncodedCatchHandler> handlers = temp.second; List<CodeItem.EncodedCatchHandler> handlers = temp.second;
DebugInfoItem debugInfoItem = $method::debugInfo.encodeDebugInfo(dexFile);
int methodParameterCount = methodIdItem.getParameterCount(); CodeItem codeItem;
if ($method::debugInfo.getParameterNameCount() > methodParameterCount) {
//TODO: throw the correct exception type
throw new RuntimeException( "Too many parameter names specified. This method only has " +
Integer.toString(methodParameterCount) +
" parameters.");
}
DebugInfoItem debugInfoItem = $method::debugInfo.encodeDebugInfo(dexFile); if (registers == 0 &&
instructions.size() == 0 &&
$method::labels.size()== 0 &&
(tries == null || tries.size() == 0) &&
(handlers == null || handlers.size() == 0) &&
debugInfoItem == null) {
codeItem = null;
} else {
int minRegisters = methodIdItem.getParameterRegisterCount((access & AccessFlags.STATIC) != 0);
CodeItem codeItem = new CodeItem(dexFile, if (registers < minRegisters) {
//TODO: throw the correct exception type
throw new RuntimeException( "This method requires at least " +
Integer.toString(minRegisters) +
" registers, for the method parameters");
}
int methodParameterCount = methodIdItem.getParameterCount();
if ($method::debugInfo.getParameterNameCount() > methodParameterCount) {
//TODO: throw the correct exception type
throw new RuntimeException( "Too many parameter names specified. This method only has " +
Integer.toString(methodParameterCount) +
" parameters.");
}
codeItem = new CodeItem(dexFile,
registers, registers,
methodIdItem.getParameterRegisterCount(isStatic), methodIdItem.getParameterRegisterCount(isStatic),
instructions, instructions,
debugInfoItem, debugInfoItem,
tries, tries,
handlers); handlers);
}
$encodedMethod = new ClassDataItem.EncodedMethod(dexFile, methodIdItem, access, codeItem); $encodedMethod = new ClassDataItem.EncodedMethod(dexFile, methodIdItem, access, codeItem);
@ -433,33 +448,34 @@ field_type_list returns[ArrayList<TypeIdItem> types]
$types = new ArrayList<TypeIdItem>(); $types = new ArrayList<TypeIdItem>();
} }
: ( : (
field_type_descriptor nonvoid_type_descriptor
{ {
$types.add($field_type_descriptor.type); $types.add($nonvoid_type_descriptor.type);
} }
)*; )*;
fully_qualified_method returns[MethodIdItem methodIdItem] fully_qualified_method returns[MethodIdItem methodIdItem]
: CLASS_NAME MEMBER_NAME method_prototype : reference_type_descriptor MEMBER_NAME method_prototype
{ {
TypeIdItem classType = new TypeIdItem(dexFile, "L" + $CLASS_NAME.text + ";"); TypeIdItem classType = $reference_type_descriptor.type;
StringIdItem methodName = new StringIdItem(dexFile, $MEMBER_NAME.text); StringIdItem methodName = new StringIdItem(dexFile, $MEMBER_NAME.text);
ProtoIdItem prototype = $method_prototype.protoIdItem; ProtoIdItem prototype = $method_prototype.protoIdItem;
$methodIdItem = new MethodIdItem(dexFile, classType, methodName, prototype); $methodIdItem = new MethodIdItem(dexFile, classType, methodName, prototype);
}; };
fully_qualified_field returns[FieldIdItem fieldIdItem] fully_qualified_field returns[FieldIdItem fieldIdItem]
: CLASS_NAME MEMBER_NAME field_type_descriptor : reference_type_descriptor MEMBER_NAME nonvoid_type_descriptor
{ {
TypeIdItem classType = new TypeIdItem(dexFile, "L" + $CLASS_NAME.text + ";"); TypeIdItem classType = $reference_type_descriptor.type;
StringIdItem fieldName = new StringIdItem(dexFile, $MEMBER_NAME.text); StringIdItem fieldName = new StringIdItem(dexFile, $MEMBER_NAME.text);
TypeIdItem fieldType = $field_type_descriptor.type; TypeIdItem fieldType = $nonvoid_type_descriptor.type;
$fieldIdItem = new FieldIdItem(dexFile, classType, fieldName, fieldType); $fieldIdItem = new FieldIdItem(dexFile, classType, fieldName, fieldType);
}; };
registers_directive returns[int registers] registers_directive returns[int registers]
: ^(I_REGISTERS short_integral_literal) {$registers = $short_integral_literal.value;}; : {$registers = 0;}
^(I_REGISTERS (short_integral_literal {$registers = $short_integral_literal.value;} )? );
labels labels
: ^(I_LABELS label_def*); : ^(I_LABELS label_def*);
@ -480,9 +496,9 @@ label_def
catches : ^(I_CATCHES catch_directive*); catches : ^(I_CATCHES catch_directive*);
catch_directive catch_directive
: ^(I_CATCH address field_type_descriptor from=offset_or_label_absolute[$address.address] to=offset_or_label_absolute[$address.address] using=offset_or_label_absolute[$address.address]) : ^(I_CATCH address nonvoid_type_descriptor from=offset_or_label_absolute[$address.address] to=offset_or_label_absolute[$address.address] using=offset_or_label_absolute[$address.address])
{ {
TypeIdItem type = $field_type_descriptor.type; TypeIdItem type = $nonvoid_type_descriptor.type;
int startAddress = $from.address; int startAddress = $from.address;
int endAddress = $to.address; int endAddress = $to.address;
int handlerAddress = $using.address; int handlerAddress = $using.address;
@ -547,14 +563,14 @@ line
}; };
local local
: ^(I_LOCAL REGISTER SIMPLE_NAME field_type_descriptor string_literal? address) : ^(I_LOCAL REGISTER SIMPLE_NAME nonvoid_type_descriptor string_literal? address)
{ {
int registerNumber = parseRegister_short($REGISTER.text); int registerNumber = parseRegister_short($REGISTER.text);
if ($string_literal.value != null) { if ($string_literal.value != null) {
$method::debugInfo.addLocalExtended($address.address, registerNumber, $SIMPLE_NAME.text, $field_type_descriptor.type.getTypeDescriptor(), $string_literal.value); $method::debugInfo.addLocalExtended($address.address, registerNumber, $SIMPLE_NAME.text, $nonvoid_type_descriptor.type.getTypeDescriptor(), $string_literal.value);
} else { } else {
$method::debugInfo.addLocal($address.address, registerNumber, $SIMPLE_NAME.text, $field_type_descriptor.type.getTypeDescriptor()); $method::debugInfo.addLocal($address.address, registerNumber, $SIMPLE_NAME.text, $nonvoid_type_descriptor.type.getTypeDescriptor());
} }
}; };
@ -725,12 +741,12 @@ instruction returns[Instruction instruction]
$instruction = Format21c.Format.make(dexFile, opcode.value, regA, stringIdItem); $instruction = Format21c.Format.make(dexFile, opcode.value, regA, stringIdItem);
} }
| //e.g. const-class v2 org/JesusFreke/HelloWorld2/HelloWorld2 | //e.g. const-class v2 org/JesusFreke/HelloWorld2/HelloWorld2
^(I_STATEMENT_FORMAT21c_TYPE INSTRUCTION_FORMAT21c_TYPE REGISTER class_or_array_type_descriptor) ^(I_STATEMENT_FORMAT21c_TYPE INSTRUCTION_FORMAT21c_TYPE REGISTER reference_type_descriptor)
{ {
Opcode opcode = Opcode.getOpcodeByName($INSTRUCTION_FORMAT21c_TYPE.text); Opcode opcode = Opcode.getOpcodeByName($INSTRUCTION_FORMAT21c_TYPE.text);
short regA = parseRegister_byte($REGISTER.text); short regA = parseRegister_byte($REGISTER.text);
TypeIdItem typeIdItem = $class_or_array_type_descriptor.type; TypeIdItem typeIdItem = $reference_type_descriptor.type;
$instruction = Format21c.Format.make(dexFile, opcode.value, regA, typeIdItem); $instruction = Format21c.Format.make(dexFile, opcode.value, regA, typeIdItem);
} }
@ -793,13 +809,13 @@ instruction returns[Instruction instruction]
$instruction = Format22c.Format.make(dexFile, opcode.value, regA, regB, fieldIdItem); $instruction = Format22c.Format.make(dexFile, opcode.value, regA, regB, fieldIdItem);
} }
| //e.g. instance-of v0, v1, Ljava/lang/String; | //e.g. instance-of v0, v1, Ljava/lang/String;
^(I_STATEMENT_FORMAT22c_TYPE INSTRUCTION_FORMAT22c_TYPE registerA=REGISTER registerB=REGISTER field_type_descriptor) ^(I_STATEMENT_FORMAT22c_TYPE INSTRUCTION_FORMAT22c_TYPE registerA=REGISTER registerB=REGISTER nonvoid_type_descriptor)
{ {
Opcode opcode = Opcode.getOpcodeByName($INSTRUCTION_FORMAT22c_TYPE.text); Opcode opcode = Opcode.getOpcodeByName($INSTRUCTION_FORMAT22c_TYPE.text);
byte regA = parseRegister_nibble($registerA.text); byte regA = parseRegister_nibble($registerA.text);
byte regB = parseRegister_nibble($registerB.text); byte regB = parseRegister_nibble($registerB.text);
TypeIdItem typeIdItem = $field_type_descriptor.type; TypeIdItem typeIdItem = $nonvoid_type_descriptor.type;
$instruction = Format22c.Format.make(dexFile, opcode.value, regA, regB, typeIdItem); $instruction = Format22c.Format.make(dexFile, opcode.value, regA, regB, typeIdItem);
} }
@ -1002,7 +1018,7 @@ register_range returns[int startRegister, int endRegister]
} }
; ;
field_type_descriptor returns [TypeIdItem type] nonvoid_type_descriptor returns [TypeIdItem type]
: (PRIMITIVE_TYPE : (PRIMITIVE_TYPE
| CLASS_DESCRIPTOR | CLASS_DESCRIPTOR
| ARRAY_DESCRIPTOR) | ARRAY_DESCRIPTOR)
@ -1010,7 +1026,7 @@ field_type_descriptor returns [TypeIdItem type]
$type = new TypeIdItem(dexFile, $start.getText()); $type = new TypeIdItem(dexFile, $start.getText());
}; };
class_or_array_type_descriptor returns [TypeIdItem type] reference_type_descriptor returns [TypeIdItem type]
: (CLASS_DESCRIPTOR : (CLASS_DESCRIPTOR
| ARRAY_DESCRIPTOR) | ARRAY_DESCRIPTOR)
{ {
@ -1025,7 +1041,7 @@ class_type_descriptor returns [TypeIdItem type]
type_descriptor returns [TypeIdItem type] type_descriptor returns [TypeIdItem type]
: VOID_TYPE {$type = new TypeIdItem(dexFile, "V");} : VOID_TYPE {$type = new TypeIdItem(dexFile, "V");}
| field_type_descriptor {$type = $field_type_descriptor.type;} | nonvoid_type_descriptor {$type = $nonvoid_type_descriptor.type;}
; ;
short_integral_literal returns[short value] short_integral_literal returns[short value]
@ -1072,7 +1088,7 @@ double_literal returns[double value]
: DOUBLE_LITERAL { $value = Double.parseDouble($DOUBLE_LITERAL.text); }; : DOUBLE_LITERAL { $value = Double.parseDouble($DOUBLE_LITERAL.text); };
char_literal returns[char value] char_literal returns[char value]
: CHAR_LITERAL { $value = $CHAR_LITERAL.text.charAt(0); }; : CHAR_LITERAL { $value = $CHAR_LITERAL.text.charAt(1); };
string_literal returns[String value] string_literal returns[String value]
: STRING_LITERAL : STRING_LITERAL
@ -1120,4 +1136,15 @@ subannotation returns[AnnotationEncodedValueSubField value]
{ {
$value = new AnnotationEncodedValueSubField(dexFile, $class_type_descriptor.type, elements); $value = new AnnotationEncodedValueSubField(dexFile, $class_type_descriptor.type, elements);
}; };
field_literal returns[EncodedIndexedItemReference<FieldIdItem> value]
: ^(I_ENCODED_FIELD fully_qualified_field)
{
$value = new EncodedIndexedItemReference<FieldIdItem>(dexFile, $fully_qualified_field.fieldIdItem);
};
method_literal returns[EncodedIndexedItemReference<MethodIdItem> value]
: ^(I_ENCODED_METHOD fully_qualified_method)
{
$value = new EncodedIndexedItemReference<MethodIdItem>(dexFile, $fully_qualified_method.methodIdItem);
};