- Added support for .implements directive, to declare interfaces that a class implements

- Added support for the class level .source directive, to set the source file string for the class
- Changed the parser so that the top level directives (.class, .super, .implements, etc.) can appear anywhere in the file in any order, instead of requiring them to be at the front of the file in a specific order
- Added some better error reporting to the parser, and changed the lexer to immediately exit on an error


git-svn-id: https://smali.googlecode.com/svn/trunk@41 55b6fa8a-2a1e-11de-a435-ffa8d773f76a
This commit is contained in:
JesusFreke@JesusFreke.com 2009-05-17 21:24:50 +00:00
parent 05700838d7
commit 73d29aa52f
5 changed files with 143 additions and 25 deletions

View File

@ -178,23 +178,13 @@ import java.util.ArrayDeque;
tokens.add(token);
}
/*protected void mismatch(IntStream input, int ttype, BitSet follow) throws RecognitionException
{
throw new MismatchedTokenException(ttype, input);
public void reportError(RecognitionException e)
{
throw new RuntimeException(e);
}
}
public Object recoverFromMismatchedSet(IntStream input, RecognitionException e, BitSet follow) throws RecognitionException
{
throw e;
}*/
}
/*@rulecatch {
catch (RecognitionException e) {
throw e;
}
}*/
CLASS_PHRASE
: CLASS_DIRECTIVE_EMIT
@ -207,6 +197,16 @@ SUPER_PHRASE
WS
CLASS_DESCRIPTOR_EMIT;
IMPLEMENTS_PHRASE
: IMPLEMENTS_DIRECTIVE_EMIT
WS
CLASS_DESCRIPTOR_EMIT;
SOURCE_PHRASE
: SOURCE_DIRECTIVE_EMIT
WS
STRING_LITERAL_EMIT;
FIELD_PHRASE
: FIELD_DIRECTIVE_EMIT
WS
@ -461,7 +461,7 @@ CATCH_PHRASE
(LABEL_EMIT | OFFSET_EMIT)
WS 'to' WS
(LABEL_EMIT | OFFSET_EMIT)
WS 'using'
WS 'using' WS
(LABEL_EMIT | OFFSET_EMIT);
@ -485,6 +485,16 @@ fragment SUPER_DIRECTIVE_EMIT
: SUPER_DIRECTIVE {emit($SUPER_DIRECTIVE, SUPER_DIRECTIVE);};
fragment SUPER_DIRECTIVE
: '.super';
fragment IMPLEMENTS_DIRECTIVE_EMIT
: IMPLEMENTS_DIRECTIVE {emit($IMPLEMENTS_DIRECTIVE, IMPLEMENTS_DIRECTIVE);};
fragment IMPLEMENTS_DIRECTIVE
: '.implements';
fragment SOURCE_DIRECTIVE_EMIT
: SOURCE_DIRECTIVE {emit($SOURCE_DIRECTIVE, SOURCE_DIRECTIVE);};
fragment SOURCE_DIRECTIVE
: '.source';
fragment FIELD_DIRECTIVE_EMIT
: FIELD_DIRECTIVE {emit($FIELD_DIRECTIVE, FIELD_DIRECTIVE);};
@ -505,7 +515,7 @@ fragment REGISTERS_DIRECTIVE_EMIT
: REGISTERS_DIRECTIVE {emit($REGISTERS_DIRECTIVE, REGISTERS_DIRECTIVE);};
fragment REGISTERS_DIRECTIVE
: '.registers';
fragment ARRAY_DATA_DIRECTIVE_EMIT
: ARRAY_DATA_DIRECTIVE {emit($ARRAY_DATA_DIRECTIVE, ARRAY_DATA_DIRECTIVE);};
fragment ARRAY_DATA_DIRECTIVE

View File

@ -38,6 +38,8 @@ tokens {
//I_* tokens are imaginary tokens used as parent AST nodes
I_CLASS_DEF;
I_SUPER;
I_IMPLEMENTS;
I_SOURCE;
I_ACCESS_LIST;
I_METHODS;
I_FIELDS;
@ -108,21 +110,81 @@ import org.JesusFreke.dexlib.code.Format.*;
}
smali_file: header methods_and_fields -> ^(I_CLASS_DEF header methods_and_fields);
@members {
public String getErrorMessage(RecognitionException e,
String[] tokenNames)
{
List stack = getRuleInvocationStack(e, this.getClass().getName());
String msg = null;
if ( e instanceof NoViableAltException ) {
NoViableAltException nvae = (NoViableAltException)e;
msg = " no viable alt; token="+e.token+
" (decision="+nvae.decisionNumber+
" state "+nvae.stateNumber+")"+
" decision=<<"+nvae.grammarDecisionDescription+">>";
}
else {
msg = super.getErrorMessage(e, tokenNames);
}
return stack+" "+msg;
}
public String getTokenErrorDisplay(Token t) {
return t.toString();
}
}
header : class_spec super_spec;
smali_file
scope
{
boolean hasClassSpec;
boolean hasSuperSpec;
}
:
{
$smali_file::hasClassSpec = false;
$smali_file::hasSuperSpec = false;
}
( {!$smali_file::hasClassSpec}?=> class_spec {$smali_file::hasClassSpec = true;}
| {!$smali_file::hasSuperSpec}?=> super_spec {$smali_file::hasSuperSpec = true;}
| implements_spec
| source_spec
| method
| field)*
{
if (!$smali_file::hasClassSpec) {
//TODO: throw correct exception type
throw new RuntimeException("The file must contain a .class directive");
}
if (!$smali_file::hasSuperSpec) {
//TODO: throw correct exception type
throw new RuntimeException("The file must contain a .super directive");
}
}
-> ^(I_CLASS_DEF
class_spec
super_spec
implements_spec*
source_spec
^(I_METHODS method*) ^(I_FIELDS field*));
class_spec
: CLASS_DIRECTIVE access_list CLASS_DESCRIPTOR -> CLASS_DESCRIPTOR access_list;
super_spec
: SUPER_DIRECTIVE CLASS_DESCRIPTOR -> ^(I_SUPER[$start, "I_SUPER"] CLASS_DESCRIPTOR);
implements_spec
: IMPLEMENTS_DIRECTIVE CLASS_DESCRIPTOR -> ^(I_IMPLEMENTS[$start, "I_IMPLEMENTS"] CLASS_DESCRIPTOR);
source_spec
: SOURCE_DIRECTIVE STRING_LITERAL -> ^(I_SOURCE[$start, "I_SOURCE"] STRING_LITERAL);
access_list
: ACCESS_SPEC+ -> ^(I_ACCESS_LIST[$start,"I_ACCESS_LIST"] ACCESS_SPEC+);
methods_and_fields
: (method | field)* -> ^(I_METHODS method*) ^(I_FIELDS field*);
field : FIELD_DIRECTIVE access_list MEMBER_NAME field_type_descriptor literal?
-> ^(I_FIELD[$start, "I_FIELD"] MEMBER_NAME access_list ^(I_FIELD_TYPE field_type_descriptor) ^(I_FIELD_INITIAL_VALUE literal)?);

View File

@ -90,10 +90,10 @@ import org.JesusFreke.dexlib.code.Format.*;
smali_file returns[ClassDefItem classDefItem]
: ^(I_CLASS_DEF header methods fields);
header : class_spec super_spec
header : class_spec super_spec implements_list source_spec
{
classDataItem = new ClassDataItem(dexFile, 0);
classDefItem = new ClassDefItem(dexFile, $class_spec.type, $class_spec.accessFlags, $super_spec.type, classDataItem);
classDefItem = new ClassDefItem(dexFile, $class_spec.type, $class_spec.accessFlags, $super_spec.type, $implements_list.implementsList, $source_spec.source, classDataItem);
};
class_spec returns[TypeIdItem type, int accessFlags]
@ -108,6 +108,27 @@ super_spec returns[TypeIdItem type]
{
$type = $class_type_descriptor.type;
};
implements_spec returns[TypeIdItem type]
: ^(I_IMPLEMENTS class_type_descriptor)
{
$type = $class_type_descriptor.type;
};
implements_list returns[TypeListItem implementsList]
@init { ArrayList<TypeIdItem> typeList; }
: {typeList = new ArrayList<TypeIdItem>();}
(implements_spec {typeList.add($implements_spec.type);} )*
{if (typeList.size() > 0) $implementsList = new TypeListItem(dexFile, typeList);
else $implementsList = null;};
source_spec returns[StringIdItem source]
: {$source = null;}
^(I_SOURCE string_literal {$source = new StringIdItem(dexFile, $string_literal.value);})
| ;
access_list returns [int value]
@init

View File

@ -69,7 +69,7 @@ public class ClassDefItem extends IndexedItem<ClassDefItem> {
};
}
public ClassDefItem(DexFile dexFile, TypeIdItem classType, int accessFlags, TypeIdItem superType, ClassDataItem classDataItem) {
public ClassDefItem(DexFile dexFile, TypeIdItem classType, int accessFlags, TypeIdItem superType, TypeListItem implementsList, StringIdItem source, ClassDataItem classDataItem) {
super(-1);
this.dexFile = dexFile;
@ -78,8 +78,8 @@ public class ClassDefItem extends IndexedItem<ClassDefItem> {
this.classType = new IndexedItemReference<TypeIdItem>(dexFile, classType, new IntegerField()),
this.accessFlags = new IntegerField(accessFlags),
superclassType = new IndexedItemReference<TypeIdItem>(dexFile, superType, new IntegerField()),
classInterfacesList = new OffsettedItemReference<TypeListItem>(dexFile.TypeListsSection, new IntegerField()),
sourceFile = new IndexedItemReference<StringIdItem>(dexFile.StringIdsSection, new IntegerField()),
classInterfacesList = new OffsettedItemReference<TypeListItem>(dexFile, implementsList, new IntegerField()),
sourceFile = new IndexedItemReference<StringIdItem>(dexFile, source, new IntegerField()),
classAnnotations = new OffsettedItemReference<AnnotationDirectoryItem>(dexFile.AnnotationDirectoriesSection, new IntegerField()),
classData = new OffsettedItemReference<ClassDataItem>(dexFile, classDataItem, new IntegerField()),
staticFieldInitialValues = new OffsettedItemReference<EncodedArrayItem>(dexFile.EncodedArraysSection, new IntegerField())

View File

@ -1,6 +1,31 @@
.class public Lorg/JesusFreke/HelloWorld2/HelloWorld2;
.super Landroid/app/Activity;
.source "HelloWorld2.smali"
;two random interfaces with only a single method to implement
.implements Landroid/util/Printer;
.implements Landroid/accounts/AccountMonitorListener;
.method public println(Ljava/lang/String;)V
.registers 1
return-void
.end method
.method public onAccountsUpdated([Ljava/lang/String;)V
.registers 1
return-void
.end method
.field private helloWorld Ljava/lang/String;
.field private static helloWorldStatic Ljava/lang/String;