diff --git a/core/org.eclipse.cdt.core/.classpath b/core/org.eclipse.cdt.core/.classpath index 1c9f189c9d3..70f839cf53b 100644 --- a/core/org.eclipse.cdt.core/.classpath +++ b/core/org.eclipse.cdt.core/.classpath @@ -5,6 +5,8 @@ + + diff --git a/core/org.eclipse.cdt.core/dom/org/eclipse/cdt/core/dom/IScope.java b/core/org.eclipse.cdt.core/dom/org/eclipse/cdt/core/dom/IScope.java new file mode 100644 index 00000000000..98d6587b8bd --- /dev/null +++ b/core/org.eclipse.cdt.core/dom/org/eclipse/cdt/core/dom/IScope.java @@ -0,0 +1,15 @@ +package org.eclipse.cdt.core.dom; + +import java.util.List; + +import org.eclipse.cdt.internal.core.dom.Declaration; + +/** + * A scope contains a set of declarations that are defined in that scope. + */ +public interface IScope { + + public void addDeclaration(Declaration declaration); + public List getDeclarations(); + +} diff --git a/core/org.eclipse.cdt.core/dom/org/eclipse/cdt/internal/core/dom/BaseSpecifier.java b/core/org.eclipse.cdt.core/dom/org/eclipse/cdt/internal/core/dom/BaseSpecifier.java new file mode 100644 index 00000000000..3e14f8a1aaa --- /dev/null +++ b/core/org.eclipse.cdt.core/dom/org/eclipse/cdt/internal/core/dom/BaseSpecifier.java @@ -0,0 +1,44 @@ +package org.eclipse.cdt.internal.core.dom; + +/** + * @author dschaefe + * + * To change this generated comment edit the template variable "typecomment": + * Window>Preferences>Java>Templates. + * To enable and disable the creation of type comments go to + * Window>Preferences>Java>Code Generation. + */ +public class BaseSpecifier { + + public BaseSpecifier(ClassSpecifier classSpecifier) { + this.classSpecifier = classSpecifier; + classSpecifier.addBaseSpecifier(this); + + switch (classSpecifier.getClassKey()) { + case ClassSpecifier.t_class: + access = t_private; + break; + case ClassSpecifier.t_struct: + access = t_public; + break; + } + } + + private ClassSpecifier classSpecifier; + public ClassSpecifier getClassSpecifier() { return classSpecifier; } + + private boolean isVirtual = false; + public void setVirtual(boolean isVirtual) { this.isVirtual = isVirtual; } + public boolean isVirtual() { return isVirtual; } + + public static final int t_private = 0; + public static final int t_protected = 1; + public static final int t_public = 2; + private int access; + public void setAccess(int access) { this.access = access; } + public int getAccess() { return access; } + + private String name; + public void setName(String name) { this.name = name; } + public String getName() { return name; } +} diff --git a/core/org.eclipse.cdt.core/dom/org/eclipse/cdt/internal/core/dom/ClassSpecifier.java b/core/org.eclipse.cdt.core/dom/org/eclipse/cdt/internal/core/dom/ClassSpecifier.java new file mode 100644 index 00000000000..025955c9a2b --- /dev/null +++ b/core/org.eclipse.cdt.core/dom/org/eclipse/cdt/internal/core/dom/ClassSpecifier.java @@ -0,0 +1,42 @@ +package org.eclipse.cdt.internal.core.dom; + +import java.util.LinkedList; +import java.util.List; + +import org.eclipse.cdt.core.dom.IScope; +import org.eclipse.cdt.internal.core.parser.util.Name; + +public class ClassSpecifier extends TypeSpecifier implements IScope { + + public static final int t_class = 0; + public static final int t_struct = 1; + public static final int t_union = 2; + + private final int classKey; + public int getClassKey() { return classKey; } + + public ClassSpecifier(int classKey, SimpleDeclaration declaration) { + super(declaration); + this.classKey = classKey; + } + + private Name name; + public void setName(Name n) { name = n; } + public Name getName() { return name; } + + private List baseSpecifiers = new LinkedList(); + public void addBaseSpecifier(BaseSpecifier baseSpecifier) { + baseSpecifiers.add(baseSpecifier); + } + public List getBaseSpecifiers() { return baseSpecifiers; } + + private List declarations = new LinkedList(); + + public void addDeclaration(Declaration declaration) { + declarations.add(declaration); + } + + public List getDeclarations() { + return declarations; + } +} diff --git a/core/org.eclipse.cdt.core/dom/org/eclipse/cdt/internal/core/dom/DOMBuilder.java b/core/org.eclipse.cdt.core/dom/org/eclipse/cdt/internal/core/dom/DOMBuilder.java new file mode 100644 index 00000000000..85eb6631861 --- /dev/null +++ b/core/org.eclipse.cdt.core/dom/org/eclipse/cdt/internal/core/dom/DOMBuilder.java @@ -0,0 +1,266 @@ +package org.eclipse.cdt.internal.core.dom; + + +import org.eclipse.cdt.core.dom.IScope; +import org.eclipse.cdt.internal.core.parser.IParserCallback; +import org.eclipse.cdt.internal.core.parser.Token; +import org.eclipse.cdt.internal.core.parser.util.*; +import org.eclipse.cdt.internal.core.parser.util.Name; + +/** + * This is the parser callback that creates objects in the DOM. + */ +public class DOMBuilder implements IParserCallback +{ + + private TranslationUnit translationUnit; + + public TranslationUnit getTranslationUnit() { + return translationUnit; + } + + /** + * @see org.eclipse.cdt.internal.core.newparser.IParserCallback#argumentsBegin() + */ + public Object argumentsBegin( Object declarator ) { + Declarator decl = ((Declarator)declarator); + ParameterDeclarationClause clause = new ParameterDeclarationClause( decl ); + return clause; + } + + /** + * @see org.eclipse.cdt.internal.core.newparser.IParserCallback#argumentsEnd() + */ + public void argumentsEnd(Object parameterDeclarationClause) { + } + + /** + * @see org.eclipse.cdt.internal.core.newparser.IParserCallback#classBegin(java.lang.String, org.eclipse.cdt.internal.core.newparser.Token) + */ + public Object classSpecifierBegin(Object container, Token classKey) { + SimpleDeclaration decl = (SimpleDeclaration)container; + + int kind = ClassSpecifier.t_struct; + + switch (classKey.getType()) { + case Token.t_class: + kind = ClassSpecifier.t_class; + break; + case Token.t_struct: + kind = ClassSpecifier.t_struct; + break; + case Token.t_union: + kind = ClassSpecifier.t_union; + break; + } + + ClassSpecifier classSpecifier = new ClassSpecifier(kind, decl); + decl.setTypeSpecifier(classSpecifier); + return classSpecifier; + } + + /** + * @see org.eclipse.cdt.internal.core.newparser.IParserCallback#classSpecifierName() + */ + public void classSpecifierName(Object classSpecifier) { + ((ClassSpecifier)classSpecifier).setName(currName); + } + + /** + * @see org.eclipse.cdt.internal.core.newparser.IParserCallback#classEnd() + */ + public void classSpecifierEnd(Object classSpecifier) { + } + + /** + * @see org.eclipse.cdt.internal.core.newparser.IParserCallback#declaratorBegin() + */ + public Object declaratorBegin(Object container) { + DeclarationSpecifier.Container decl = (DeclarationSpecifier.Container )container; + Declarator declarator = new Declarator(decl); + decl.addDeclarator(declarator); + return declarator; + } + + /** + * @see org.eclipse.cdt.internal.core.newparser.IParserCallback#declaratorEnd() + */ + public void declaratorEnd(Object declarator) { + } + + /** + * @see org.eclipse.cdt.internal.core.newparser.IParserCallback#declaratorId(org.eclipse.cdt.internal.core.newparser.Token) + */ + public void declaratorId(Object declarator) { + ((Declarator)declarator).setName(currName); + } + + /** + * @see org.eclipse.cdt.internal.core.newparser.IParserCallback#declSpecifier(org.eclipse.cdt.internal.core.newparser.Token) + */ + public void simpleDeclSpecifier(Object Container, Token specifier) { + DeclarationSpecifier.Container decl = (DeclarationSpecifier.Container)Container; + DeclarationSpecifier declSpec = decl.getDeclSpecifier(); + if( declSpec == null ) + { + declSpec = new DeclarationSpecifier(); + decl.setDeclSpecifier( declSpec ); + } + + declSpec.setType( specifier ); + } + + /** + * @see org.eclipse.cdt.internal.core.newparser.IParserCallback#expressionOperator(org.eclipse.cdt.internal.core.newparser.Token) + */ + public void expressionOperator(Token operator) throws Exception { + } + + /** + * @see org.eclipse.cdt.internal.core.newparser.IParserCallback#expressionTerminal(org.eclipse.cdt.internal.core.newparser.Token) + */ + public void expressionTerminal(Token terminal) throws Exception { + } + + /** + * @see org.eclipse.cdt.internal.core.newparser.IParserCallback#functionBodyBegin() + */ + public void functionBodyBegin() { + } + + /** + * @see org.eclipse.cdt.internal.core.newparser.IParserCallback#functionBodyEnd() + */ + public void functionBodyEnd() { + } + + /** + * @see org.eclipse.cdt.internal.core.newparser.IParserCallback#inclusionBegin(java.lang.String) + */ + public void inclusionBegin(String includeFile, int offset) { + } + + /** + * @see org.eclipse.cdt.internal.core.newparser.IParserCallback#inclusionEnd() + */ + public void inclusionEnd() { + } + + /** + * @see org.eclipse.cdt.internal.core.newparser.IParserCallback#macro(java.lang.String) + */ + public void macro(String macroName, int offset) { + } + + /** + * @see org.eclipse.cdt.internal.core.newparser.IParserCallback#simpleDeclarationBegin(org.eclipse.cdt.internal.core.newparser.Token) + */ + public Object simpleDeclarationBegin(Object container) { + SimpleDeclaration decl = new SimpleDeclaration(); + ((IScope)container).addDeclaration(decl); + return decl; + } + + /** + * @see org.eclipse.cdt.internal.core.newparser.IParserCallback#simpleDeclarationEnd(org.eclipse.cdt.internal.core.newparser.Token) + */ + public void simpleDeclarationEnd(Object declaration) { + } + + /** + * @see org.eclipse.cdt.internal.core.newparser.IParserCallback#translationUnitBegin() + */ + public Object translationUnitBegin() { + translationUnit = new TranslationUnit(); + return translationUnit; + } + + /** + * @see org.eclipse.cdt.internal.core.newparser.IParserCallback#translationUnitEnd() + */ + public void translationUnitEnd(Object unit) { + } + + private Name currName; + + /** + * @see org.eclipse.cdt.internal.core.newparser.IParserCallback#nameBegin(org.eclipse.cdt.internal.core.newparser.Token) + */ + public void nameBegin(Token firstToken) { + currName = new Name(firstToken); + } + + /** + * @see org.eclipse.cdt.internal.core.newparser.IParserCallback#nameEnd(org.eclipse.cdt.internal.core.newparser.Token) + */ + public void nameEnd(Token lastToken) { + currName.setEnd(lastToken); + } + + public Object baseSpecifierBegin( Object classSpecifier ) + { + ClassSpecifier cs =(ClassSpecifier)classSpecifier; + BaseSpecifier baseSpec = new BaseSpecifier( cs ); + return baseSpec; + } + + public void baseSpecifierEnd( Object baseSpecifier ) + { + + } + + public void baseSpecifierVirtual( Object baseSpecifier, boolean virtual ) + { + BaseSpecifier bs = (BaseSpecifier)baseSpecifier; + bs.setVirtual( virtual ); + } + + public void baseSpecifierVisibility( Object baseSpecifier, Token visibility ) + { + int access = BaseSpecifier.t_public; + switch( visibility.type ) + { + case Token.t_public: + access = BaseSpecifier.t_public; + break; + case Token.t_protected: + access = BaseSpecifier.t_protected; + break; + case Token.t_private: + access = BaseSpecifier.t_private; + break; + default: + break; + } + + ((BaseSpecifier)baseSpecifier).setAccess(access); + } + + + public void baseSpecifierName( Object baseSpecifier ) + { + ((BaseSpecifier)baseSpecifier).setName(currName.toString()); + } + + public Object parameterDeclarationBegin( Object container ) + { + ParameterDeclarationClause clause = (ParameterDeclarationClause)container; + ParameterDeclaration pd = new ParameterDeclaration(); + clause.addDeclaration( pd ); + return pd; + } + + public void parameterDeclarationEnd( Object declaration ){ + } + /** + * @see org.eclipse.cdt.internal.core.newparser.IParserCallback#declaratorAbort(java.lang.Object, java.lang.Object) + */ + public void declaratorAbort(Object container, Object declarator) { + DeclarationSpecifier.Container decl = (DeclarationSpecifier.Container )container; + Declarator toBeRemoved = (Declarator)declarator; + decl.removeDeclarator( toBeRemoved ); + currName = null; + toBeRemoved = null; + } + +} \ No newline at end of file diff --git a/core/org.eclipse.cdt.core/dom/org/eclipse/cdt/internal/core/dom/Declaration.java b/core/org.eclipse.cdt.core/dom/org/eclipse/cdt/internal/core/dom/Declaration.java new file mode 100644 index 00000000000..9b726db0e1c --- /dev/null +++ b/core/org.eclipse.cdt.core/dom/org/eclipse/cdt/internal/core/dom/Declaration.java @@ -0,0 +1,7 @@ +package org.eclipse.cdt.internal.core.dom; + +/** + */ +public class Declaration { + +} diff --git a/core/org.eclipse.cdt.core/dom/org/eclipse/cdt/internal/core/dom/Declarator.java b/core/org.eclipse.cdt.core/dom/org/eclipse/cdt/internal/core/dom/Declarator.java new file mode 100644 index 00000000000..ab94281ebcf --- /dev/null +++ b/core/org.eclipse.cdt.core/dom/org/eclipse/cdt/internal/core/dom/Declarator.java @@ -0,0 +1,64 @@ +package org.eclipse.cdt.internal.core.dom; + +import org.eclipse.cdt.internal.core.parser.util.*; +import org.eclipse.cdt.internal.core.parser.util.Name; + + +public class Declarator { + + public Declarator(DeclarationSpecifier.Container declaration) { + this.declaration = declaration; + } + + private DeclarationSpecifier.Container declaration; + + /** + * Returns the declaration. + * @return SimpleDeclaration + */ + public DeclarationSpecifier.Container getDeclaration() { + return declaration; + } + + /** + * Sets the declaration. + * @param declaration The declaration to set + */ + public void setDeclaration(SimpleDeclaration declaration) { + this.declaration = declaration; + } + + private Name name; + + /** + * Returns the name. + * @return Name + */ + public Name getName() { + return name; + } + + /** + * Sets the name. + * @param name The name to set + */ + public void setName(Name name) { + this.name = name; + } + + ParameterDeclarationClause parms = null; + + public void addParms( ParameterDeclarationClause parms ) + { + this.parms = parms; + } + + /** + * Returns the parms. + * @return ParameterDeclarationClause + */ + public ParameterDeclarationClause getParms() { + return parms; + } + +} diff --git a/core/org.eclipse.cdt.core/dom/org/eclipse/cdt/internal/core/dom/MemberDeclaration.java b/core/org.eclipse.cdt.core/dom/org/eclipse/cdt/internal/core/dom/MemberDeclaration.java new file mode 100644 index 00000000000..aa932d03688 --- /dev/null +++ b/core/org.eclipse.cdt.core/dom/org/eclipse/cdt/internal/core/dom/MemberDeclaration.java @@ -0,0 +1,26 @@ +package org.eclipse.cdt.internal.core.dom; + +/** + * @author dschaefe + * + * To change this generated comment edit the template variable "typecomment": + * Window>Preferences>Java>Templates. + * To enable and disable the creation of type comments go to + * Window>Preferences>Java>Code Generation. + */ +public class MemberDeclaration { + public static final int t_private = 0; + public static final int t_protected = 1; + public static final int t_public = 2; + + public MemberDeclaration(int access, Declaration declaration) { + this.access = access; + this.declaration = declaration; + } + + private int access; + public int getAccess() { return access; } + + private Declaration declaration; + public Declaration getDeclaration() { return declaration; } +} diff --git a/core/org.eclipse.cdt.core/dom/org/eclipse/cdt/internal/core/dom/ParameterDeclaration.java b/core/org.eclipse.cdt.core/dom/org/eclipse/cdt/internal/core/dom/ParameterDeclaration.java new file mode 100644 index 00000000000..cfe7caab72b --- /dev/null +++ b/core/org.eclipse.cdt.core/dom/org/eclipse/cdt/internal/core/dom/ParameterDeclaration.java @@ -0,0 +1,52 @@ +package org.eclipse.cdt.internal.core.dom; + +import java.util.LinkedList; +import java.util.List; + +import org.eclipse.cdt.internal.core.parser.util.*; + +/** + * @author jcamelon + * + * To change this generated comment edit the template variable "typecomment": + * Window>Preferences>Java>Templates. + * To enable and disable the creation of type comments go to + * Window>Preferences>Java>Code Generation. + */ +public class ParameterDeclaration extends Declaration implements DeclarationSpecifier.Container { + + DeclarationSpecifier declSpec = null; + + /** + * @see org.eclipse.cdt.internal.core.dom.DeclarationSpecifier.CElementWrapper#getDeclSpecifier() + */ + public DeclarationSpecifier getDeclSpecifier() { + if( declSpec == null ) + declSpec = new DeclarationSpecifier(); + + return declSpec; + } + + /** + * @see org.eclipse.cdt.internal.core.dom.DeclarationSpecifier.CElementWrapper#setDeclSpecifier(org.eclipse.cdt.internal.core.dom.DeclarationSpecifier) + */ + public void setDeclSpecifier(DeclarationSpecifier in) { + declSpec = in; + } + private List declarators = new LinkedList(); + + public void addDeclarator(Object declarator) { + declarators.add(declarator); + } + + public List getDeclarators() { + return declarators; + } + + /** + * @see org.eclipse.cdt.internal.core.newparser.util.DeclarationSpecifier.Container#removeDeclarator(java.lang.Object) + */ + public void removeDeclarator(Object declarator) { + declarators.remove( declarator ); + } +} diff --git a/core/org.eclipse.cdt.core/dom/org/eclipse/cdt/internal/core/dom/ParameterDeclarationClause.java b/core/org.eclipse.cdt.core/dom/org/eclipse/cdt/internal/core/dom/ParameterDeclarationClause.java new file mode 100644 index 00000000000..a5caa43ac73 --- /dev/null +++ b/core/org.eclipse.cdt.core/dom/org/eclipse/cdt/internal/core/dom/ParameterDeclarationClause.java @@ -0,0 +1,40 @@ +package org.eclipse.cdt.internal.core.dom; + +import java.util.LinkedList; +import java.util.List; + +import org.eclipse.cdt.core.dom.IScope; + +/** + * @author jcamelon + * + * To change this generated comment edit the template variable "typecomment": + * Window>Preferences>Java>Templates. + * To enable and disable the creation of type comments go to + * Window>Preferences>Java>Code Generation. + */ +public class ParameterDeclarationClause implements IScope { + + /** + * @see org.eclipse.cdt.core.dom.IScope#addDeclaration(org.eclipse.cdt.internal.core.dom.Declaration) + */ + public void addDeclaration( Declaration declaration) { + declarations.add( declaration ); + } + + /** + * @see org.eclipse.cdt.core.dom.IScope#getDeclarations() + */ + public List getDeclarations() { + return declarations; + } + + private List declarations = new LinkedList(); + private Declarator owner; + + ParameterDeclarationClause( Declarator owner ) + { + this.owner = owner; + this.owner.addParms( this ); + } +} diff --git a/core/org.eclipse.cdt.core/dom/org/eclipse/cdt/internal/core/dom/SimpleDeclaration.java b/core/org.eclipse.cdt.core/dom/org/eclipse/cdt/internal/core/dom/SimpleDeclaration.java new file mode 100644 index 00000000000..2f7e39aaf4e --- /dev/null +++ b/core/org.eclipse.cdt.core/dom/org/eclipse/cdt/internal/core/dom/SimpleDeclaration.java @@ -0,0 +1,63 @@ +package org.eclipse.cdt.internal.core.dom; + +import java.util.LinkedList; +import java.util.List; + +import org.eclipse.cdt.internal.core.parser.util.*; + +public class SimpleDeclaration extends Declaration implements DeclarationSpecifier.Container{ + + private DeclarationSpecifier declSpec = null; + + public DeclarationSpecifier getDeclSpecifier() + { + if( declSpec == null ) + declSpec = new DeclarationSpecifier(); + return declSpec; + } + + public void setDeclSpecifier( DeclarationSpecifier in ) + { + declSpec = in; + } + + /** + * This is valid when the type is t_type. It points to a + * classSpecifier, etc. + */ + private TypeSpecifier typeSpecifier; + + /** + * Returns the typeSpecifier. + * @return TypeSpecifier + */ + public TypeSpecifier getTypeSpecifier() { + return typeSpecifier; + } + + /** + * Sets the typeSpecifier. + * @param typeSpecifier The typeSpecifier to set + */ + public void setTypeSpecifier(TypeSpecifier typeSpecifier) { + getDeclSpecifier().setType(DeclarationSpecifier.t_type); + this.typeSpecifier = typeSpecifier; + } + + private List declarators = new LinkedList(); + + public void addDeclarator(Object declarator) { + declarators.add(declarator); + } + + public List getDeclarators() { + return declarators; + } + + /** + * @see org.eclipse.cdt.internal.core.newparser.util.DeclarationSpecifier.Container#removeDeclarator(java.lang.Object) + */ + public void removeDeclarator(Object declarator) { + declarators.remove( declarator ); + } +} diff --git a/core/org.eclipse.cdt.core/dom/org/eclipse/cdt/internal/core/dom/TranslationUnit.java b/core/org.eclipse.cdt.core/dom/org/eclipse/cdt/internal/core/dom/TranslationUnit.java new file mode 100644 index 00000000000..95454b73e57 --- /dev/null +++ b/core/org.eclipse.cdt.core/dom/org/eclipse/cdt/internal/core/dom/TranslationUnit.java @@ -0,0 +1,21 @@ +package org.eclipse.cdt.internal.core.dom; + +import java.util.LinkedList; +import java.util.List; + +import org.eclipse.cdt.core.dom.IScope; + +/** + */ +public class TranslationUnit implements IScope { + + private List declarations = new LinkedList(); + + public void addDeclaration(Declaration declaration) { + declarations.add(declaration); + } + + public List getDeclarations() { + return declarations; + } +} diff --git a/core/org.eclipse.cdt.core/dom/org/eclipse/cdt/internal/core/dom/TypeSpecifier.java b/core/org.eclipse.cdt.core/dom/org/eclipse/cdt/internal/core/dom/TypeSpecifier.java new file mode 100644 index 00000000000..899ce4a394e --- /dev/null +++ b/core/org.eclipse.cdt.core/dom/org/eclipse/cdt/internal/core/dom/TypeSpecifier.java @@ -0,0 +1,30 @@ +package org.eclipse.cdt.internal.core.dom; + +public class TypeSpecifier { + + public TypeSpecifier(SimpleDeclaration declaration) { + this.declaration = declaration; + } + + /** + * Owner declaration. + */ + private SimpleDeclaration declaration; + + /** + * Returns the declaration. + * @return SimpleDeclaration + */ + public SimpleDeclaration getDeclaration() { + return declaration; + } + + /** + * Sets the declaration. + * @param declaration The declaration to set + */ + public void setDeclaration(SimpleDeclaration declaration) { + this.declaration = declaration; + } + +} diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/CElement.java b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/CElement.java index 58d70fe0056..5efd24e05c1 100644 --- a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/CElement.java +++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/CElement.java @@ -194,7 +194,7 @@ public abstract class CElement extends PlatformObject implements ICElement { } if (fType != other.fType) return false; - if (fName.equals(other.fName)) { + if (other.fName != null && fName.equals(other.fName)) { if (fParent != null && fParent.equals(other.fParent)) { return true; } diff --git a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/TranslationUnitInfo.java b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/TranslationUnitInfo.java index bfd10e15238..1400aede4ec 100644 --- a/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/TranslationUnitInfo.java +++ b/core/org.eclipse.cdt.core/model/org/eclipse/cdt/internal/core/model/TranslationUnitInfo.java @@ -8,15 +8,15 @@ package org.eclipse.cdt.internal.core.model; import java.io.IOException; import java.io.InputStream; -import org.eclipse.core.resources.IResource; -import org.eclipse.core.resources.IFile; -import org.eclipse.core.runtime.IPath; -import org.eclipse.core.runtime.CoreException; - -import org.eclipse.cdt.internal.parser.CStructurizer; - -import org.eclipse.cdt.core.model.ISourceRange; +import org.eclipse.cdt.core.CCorePlugin; import org.eclipse.cdt.core.model.ICElement; +import org.eclipse.cdt.core.model.ISourceRange; +import org.eclipse.cdt.internal.core.parser.Parser; +import org.eclipse.cdt.internal.parser.CStructurizer; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; class TranslationUnitInfo extends CFileInfo { @@ -55,10 +55,18 @@ class TranslationUnitInfo extends CFileInfo { protected void parse(InputStream in) { try { removeChildren(); - ModelBuilder modelBuilder= new ModelBuilder((TranslationUnit)getElement()); - CStructurizer.getCStructurizer().parse(modelBuilder, in); - } catch (IOException e) { - //e.printStackTrace(); + if (CCorePlugin.getDefault().useNewParser()) { + // new parser + NewModelBuilder modelBuilder = new NewModelBuilder((TranslationUnit)getElement()); + Parser parser = new Parser(in, modelBuilder, true); + parser.parse(); + } else { + // cdt 1.0 parser + ModelBuilder modelBuilder= new ModelBuilder((TranslationUnit)getElement()); + CStructurizer.getCStructurizer().parse(modelBuilder, in); + } + } catch (Exception e) { + System.out.println(e); } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/model/Declarator.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/model/Declarator.java new file mode 100644 index 00000000000..95698cc37a0 --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/model/Declarator.java @@ -0,0 +1,52 @@ +package org.eclipse.cdt.internal.core.model; + +import java.util.List; + +import org.eclipse.cdt.internal.core.parser.util.Name; + +/** + * @author jcamelon + * + * To change this generated comment edit the template variable "typecomment": + * Window>Preferences>Java>Templates. + * To enable and disable the creation of type comments go to + * Window>Preferences>Java>Code Generation. + */ +public class Declarator { + + private Name name; + + /** + * Returns the name. + * @return Name + */ + public Name getName() { + return name; + } + + /** + * Sets the name. + * @param name The name to set + */ + public void setName(Name name) { + this.name = name; + } + + private List parameterDeclarationClause = null; + + /** + * Returns the parameterDeclarationClause. + * @return List + */ + public List getParameterDeclarationClause() { + return parameterDeclarationClause; + } + + /** + * Sets the parameterDeclarationClause. + * @param parameterDeclarationClause The parameterDeclarationClause to set + */ + public void setParameterDeclarationClause(List parameterDeclarationClause) { + this.parameterDeclarationClause = parameterDeclarationClause; + } +} diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/model/ICElementWrapper.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/model/ICElementWrapper.java new file mode 100644 index 00000000000..5f3db2b35d1 --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/model/ICElementWrapper.java @@ -0,0 +1,15 @@ +package org.eclipse.cdt.internal.core.model; + +/** + * @author jcamelon + * + * To change this generated comment edit the template variable "typecomment": + * Window>Preferences>Java>Templates. + * To enable and disable the creation of type comments go to + * Window>Preferences>Java>Code Generation. + */ +public interface ICElementWrapper { + + public CElement getElement(); + public void setElement (CElement item); +} diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/model/NewModelBuilder.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/model/NewModelBuilder.java new file mode 100644 index 00000000000..e5ea3d488ff --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/model/NewModelBuilder.java @@ -0,0 +1,306 @@ +/******************************************************************************* + * Copyright (c) 2001 Rational Software Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * Rational Software - initial implementation + ******************************************************************************/ +package org.eclipse.cdt.internal.core.model; + +import java.util.LinkedList; +import java.util.List; + +import org.eclipse.cdt.core.model.ICElement; +import org.eclipse.cdt.internal.core.parser.IParserCallback; +import org.eclipse.cdt.internal.core.parser.Token; +import org.eclipse.cdt.internal.core.parser.util.DeclSpecifier; +import org.eclipse.cdt.internal.core.parser.util.DeclarationSpecifier; +import org.eclipse.cdt.internal.core.parser.util.Name; + +public class NewModelBuilder implements IParserCallback { + + private TranslationUnitWrapper translationUnit = new TranslationUnitWrapper(); + + + public NewModelBuilder(TranslationUnit tu) { + translationUnit.setElement( tu ); + } + + /** + * @see org.eclipse.cdt.internal.core.newparser.IParserCallback#beginTranslationUnit() + */ + public Object translationUnitBegin() { + return translationUnit; + } + + + private Token classKey; + /** + * @see org.eclipse.cdt.core.newparser.IParserCallback#beginClass(String, String) + */ + public Object classSpecifierBegin(Object container, Token classKey) { + + SimpleDeclarationWrapper c = (SimpleDeclarationWrapper)container; + + int kind; + switch (classKey.getType()) { + case Token.t_class: + kind = ICElement.C_CLASS; + break; + case Token.t_struct: + kind = ICElement.C_STRUCT; + break; + default: + kind = ICElement.C_UNION; + } + this.classKey = classKey; + + Structure elem = new Structure( c.getParent(), kind, null ); + c.getParent().addChild(elem); + return new SimpleDeclarationWrapper( elem ); + } + + /** + * @see org.eclipse.cdt.internal.core.newparser.IParserCallback#classSpecifierName() + */ + public void classSpecifierName(Object classSpecifier) { + + SimpleDeclarationWrapper container = (SimpleDeclarationWrapper)classSpecifier; + String name = currName.toString(); + Structure elem = ((Structure)container.getElement()); + elem.setElementName( name ); + elem.setIdPos(currName.getEndOffset(), name.length()); + elem.setPos(currName.getEndOffset(), name.length()); + } + + /** + * @see org.eclipse.cdt.core.newparser.IParserCallback#endClass() + */ + public void classSpecifierEnd(Object classSpecifier) { + } + + /** + * @see org.eclipse.cdt.core.newparser.IParserCallback#beginDeclarator() + */ + public Object declaratorBegin(Object container) { + DeclarationSpecifier.Container declSpec = (DeclarationSpecifier.Container)container; + List declarators = declSpec.getDeclarators(); + Declarator declarator =new Declarator(); + declarators.add( declarator ); + return declarator; + } + + + private int startIdPos; + private int idLength; + + private CElement elem; + + /** + * @see org.eclipse.cdt.core.newparser.IParserCallback#endDeclarator() + */ + public void declaratorEnd( Object declarator) { + } + + /** + * @see org.eclipse.cdt.internal.core.newparser.IParserCallback#beginFunctionBody() + */ + public void functionBodyBegin() { + } + + /** + * @see org.eclipse.cdt.core.newparser.IParserCallback#macro(String) + */ + public void macro(String macroName, int offset) { + Macro elem = new Macro((TranslationUnit)translationUnit.getElement(), macroName); + elem.setIdPos(offset, macroName.length()); + elem.setPos(offset, macroName.length()); + + ((TranslationUnit)translationUnit.getElement()).addChild(elem); + + } + + private int startPos; + + /** + * @see +org.eclipse.cdt.internal.core.newparser.IParserCallback#beginSimpleDeclaration(Token) + */ + public Object simpleDeclarationBegin(Object container) { + ICElementWrapper wrapper = (ICElementWrapper)container; + Object parent = wrapper.getElement(); + SimpleDeclarationWrapper result = new SimpleDeclarationWrapper(); + if( wrapper instanceof SimpleDeclarationWrapper ) + result.setParent( (CElement)wrapper.getElement() ); + else if ( wrapper instanceof TranslationUnitWrapper ) + result.setParent( (TranslationUnit)wrapper.getElement()); + return result; + } + + + + /** + * @see org.eclipse.cdt.internal.core.newparser.IParserCallback#beginInclusion(String) + */ + public void inclusionBegin(String includeFile, int offset) { + Include elem = new Include(((TranslationUnit)translationUnit.getElement()), includeFile); + ((TranslationUnit)translationUnit.getElement()).addChild(elem); + elem.setIdPos(offset, includeFile.length()); + elem.setPos(offset, includeFile.length()); + + } + + /** + * @see org.eclipse.cdt.internal.core.newparser.IParserCallback#endInclusion() + */ + public void inclusionEnd() { + } + + private Name currName; + + /** + * @see org.eclipse.cdt.internal.core.newparser.IParserCallback#nameBegin(org.eclipse.cdt.internal.core.newparser.Token) + */ + public void nameBegin(Token firstToken) { + currName = new Name(firstToken); + } + + /** + * @see org.eclipse.cdt.internal.core.newparser.IParserCallback#nameEnd(org.eclipse.cdt.internal.core.newparser.Token) + */ + public void nameEnd(Token lastToken) { + currName.setEnd(lastToken); + } + + + /** + * @see org.eclipse.cdt.internal.core.newparser.IParserCallback#simpleDeclarationEnd(java.lang.Object) + */ + public void simpleDeclarationEnd(Object declaration) { + SimpleDeclarationWrapper wrapper = (SimpleDeclarationWrapper)declaration; + wrapper.createElements(); + } + + /** + * @see org.eclipse.cdt.internal.core.newparser.IParserCallback#simpleDeclSpecifier(java.lang.Object, org.eclipse.cdt.internal.core.newparser.Token) + */ + public void simpleDeclSpecifier(Object declSpec, Token specifier) { + DeclSpecifier declSpecifier = (DeclSpecifier)declSpec; + declSpecifier.setType( specifier ); + } + + /** + * @see org.eclipse.cdt.internal.core.newparser.IParserCallback#declaratorId(java.lang.Object) + */ + public void declaratorId(Object declarator) { + Declarator decl = (Declarator)declarator; + decl.setName( currName ); + } + + + /** + * @see org.eclipse.cdt.internal.core.newparser.IParserCallback#argumentsBegin(java.lang.Object) + */ + public Object argumentsBegin(Object declarator) { + Declarator decl = (Declarator)declarator; + List parameterDeclarationClause = new LinkedList(); + decl.setParameterDeclarationClause( parameterDeclarationClause ); + return parameterDeclarationClause; + + } + + /** + * @see org.eclipse.cdt.internal.core.newparser.IParserCallback#baseSpecifierBegin(java.lang.Object) + */ + public Object baseSpecifierBegin(Object containingClassSpec) { + return null; + } + + /** + * @see org.eclipse.cdt.internal.core.newparser.IParserCallback#baseSpecifierEnd(java.lang.Object) + */ + public void baseSpecifierEnd(Object baseSpecifier) { + } + + /** + * @see org.eclipse.cdt.internal.core.newparser.IParserCallback#baseSpecifierName(java.lang.Object) + */ + public void baseSpecifierName(Object baseSpecifier) { + } + + /** + * @see org.eclipse.cdt.internal.core.newparser.IParserCallback#baseSpecifierVirtual(java.lang.Object, boolean) + */ + public void baseSpecifierVirtual(Object baseSpecifier, boolean virtual) { + } + + /** + * @see org.eclipse.cdt.internal.core.newparser.IParserCallback#baseSpecifierVisibility(java.lang.Object, org.eclipse.cdt.internal.core.newparser.Token) + */ + public void baseSpecifierVisibility( + Object baseSpecifier, + Token visibility) { + } + + /** + * @see org.eclipse.cdt.internal.core.newparser.IParserCallback#expressionOperator(org.eclipse.cdt.internal.core.newparser.Token) + */ + public void expressionOperator(Token operator) throws Exception { + } + + /** + * @see org.eclipse.cdt.internal.core.newparser.IParserCallback#expressionTerminal(org.eclipse.cdt.internal.core.newparser.Token) + */ + public void expressionTerminal(Token terminal) throws Exception { + } + + /** + * @see org.eclipse.cdt.internal.core.newparser.IParserCallback#functionBodyEnd() + */ + public void functionBodyEnd() { + } + + /** + * @see org.eclipse.cdt.internal.core.newparser.IParserCallback#parameterDeclarationBegin(java.lang.Object, org.eclipse.cdt.internal.core.newparser.Token) + */ + public Object parameterDeclarationBegin( + Object container ) { + List parameterDeclarationClause = (List)container; + Parameter p = new Parameter(); + parameterDeclarationClause.add( p ); + return p; + + } + + /** + * @see org.eclipse.cdt.internal.core.newparser.IParserCallback#parameterDeclarationEnd(java.lang.Object) + */ + public void parameterDeclarationEnd(Object declaration) { + } + + /** + * @see org.eclipse.cdt.internal.core.newparser.IParserCallback#translationUnitEnd(java.lang.Object) + */ + public void translationUnitEnd(Object unit) { + } + /** + * @see org.eclipse.cdt.internal.core.newparser.IParserCallback#argumentsEnd() + */ + public void argumentsEnd(Object parameterDeclarationClause) { + } + + /** + * @see org.eclipse.cdt.internal.core.newparser.IParserCallback#declaratorAbort(java.lang.Object, java.lang.Object) + */ + public void declaratorAbort(Object container, Object declarator) { + DeclarationSpecifier.Container declSpec = (DeclarationSpecifier.Container)container; + Declarator toBeRemoved =(Declarator)declarator; + declSpec.removeDeclarator( toBeRemoved ); + toBeRemoved = null; + currName = null; + } + +} diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/model/Parameter.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/model/Parameter.java new file mode 100644 index 00000000000..56370297289 --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/model/Parameter.java @@ -0,0 +1,53 @@ +package org.eclipse.cdt.internal.core.model; + +import java.util.LinkedList; +import java.util.List; + +import org.eclipse.cdt.internal.core.parser.util.DeclSpecifier; +import org.eclipse.cdt.internal.core.parser.util.DeclarationSpecifier; + +/** + * @author jcamelon + * + * To change this generated comment edit the template variable "typecomment": + * Window>Preferences>Java>Templates. + * To enable and disable the creation of type comments go to + * Window>Preferences>Java>Code Generation. + */ +public class Parameter extends DeclSpecifier implements DeclarationSpecifier.Container +{ + DeclarationSpecifier declSpec = null; + + /** + * @see org.eclipse.cdt.internal.core.dom.DeclarationSpecifier.CElementWrapper#getDeclSpecifier() + */ + public DeclarationSpecifier getDeclSpecifier() { + if( declSpec == null ) + declSpec = new DeclarationSpecifier(); + + return declSpec; + } + + /** + * @see org.eclipse.cdt.internal.core.dom.DeclarationSpecifier.CElementWrapper#setDeclSpecifier(org.eclipse.cdt.internal.core.dom.DeclarationSpecifier) + */ + public void setDeclSpecifier(DeclarationSpecifier in) { + declSpec = in; + } + private List declarators = new LinkedList(); + + public void addDeclarator(Object declarator) { + declarators.add(declarator); + } + + public List getDeclarators() { + return declarators; + } + + /** + * @see org.eclipse.cdt.internal.core.newparser.util.DeclarationSpecifier.Container#removeDeclarator(java.lang.Object) + */ + public void removeDeclarator(Object declarator) { + declarators.remove( declarator ); + } +} diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/model/SimpleDeclarationWrapper.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/model/SimpleDeclarationWrapper.java new file mode 100644 index 00000000000..1e6bf4e9521 --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/model/SimpleDeclarationWrapper.java @@ -0,0 +1,163 @@ +package org.eclipse.cdt.internal.core.model; + +import java.util.LinkedList; +import java.util.List; + +import org.eclipse.cdt.core.model.IStructure; +import org.eclipse.cdt.core.model.ITranslationUnit; +import org.eclipse.cdt.internal.core.parser.util.DeclSpecifier; +import org.eclipse.cdt.internal.core.parser.util.DeclarationSpecifier; + +/** + * @author jcamelon + * + * To change this generated comment edit the template variable "typecomment": + * Window>Preferences>Java>Templates. + * To enable and disable the creation of type comments go to + * Window>Preferences>Java>Code Generation. + */ +public class SimpleDeclarationWrapper extends DeclSpecifier implements DeclarationSpecifier.Container, ICElementWrapper { + + private CElement element = null; + private CElement parent = null; + + public SimpleDeclarationWrapper( CElement item ) + { + this.element = item; + } + + public SimpleDeclarationWrapper() + { + } + + /** + * Returns the item. + * @return CElement + */ + public CElement getElement() { + return element; + } + + /** + * Sets the item. + * @param item The item to set + */ + public void setElement (CElement item) { + this.element = (CElement)item; + } + + /** + * Returns the parent. + * @return CElement + */ + public CElement getParent() { + return parent; + } + + /** + * Sets the parent. + * @param parent The parent to set + */ + public void setParent(CElement parent) { + this.parent = parent; + } + + public void createElements() + { + // creates the appropriate C Elements + List declaratorList = getDeclarators(); + Declarator [] declarators = (Declarator []) declaratorList.toArray( new Declarator[ declaratorList.size() ] ); + CElement parentElement = getParent(); + + for( int i = 0; i < declarators.length; ++i ) + { + Declarator currentDeclarator = declarators[i]; + CElement declaration = null; + + // instantiate the right element + List clause =currentDeclarator.getParameterDeclarationClause(); + if( clause == null ) + { + // this is an attribute or a varaible + if( parentElement instanceof IStructure ) + { + declaration = new Field( parentElement, currentDeclarator.getName().toString() ); + } + else if( parentElement instanceof ITranslationUnit ) + { + declaration = new Variable( parentElement, currentDeclarator.getName().toString() ); + } + } + else + { + // this is a function or a method + if( parentElement instanceof IStructure ) + { + declaration = new Method( parentElement, currentDeclarator.getName().toString() ); + + } + else if( parentElement instanceof ITranslationUnit ) + { + declaration = new FunctionDeclaration( parentElement, currentDeclarator.getName().toString() ); + } + + Parameter [] parameters = (Parameter []) clause.toArray( new Parameter[ clause.size() ]); + + for( int j = 0; j< parameters.length; ++j ) + { + Parameter parm = parameters[j]; + + } + + } + + // hook up the offsets + declaration.setIdPos( +currentDeclarator.getName().getEndOffset(),currentDeclarator.getName().toString().length()); + declaration.setPos( currentDeclarator.getName().getEndOffset(), currentDeclarator.getName().toString().length() ); + + // add to parent + parentElement.addChild( declaration ); + } + + } + + List declarators = new LinkedList(); + + public void addDeclarator( Object in ) + { + declarators.add( in ); + } + + public List getDeclarators() + { + return declarators; + } + + DeclarationSpecifier declSpec = null; + + /** + * @see org.eclipse.cdt.internal.core.dom.DeclarationSpecifier.CElementWrapper#getDeclSpecifier() + */ + public DeclarationSpecifier getDeclSpecifier() { + if( declSpec == null ) + declSpec = new DeclarationSpecifier(); + + return declSpec; + } + + /** + * @see org.eclipse.cdt.internal.core.dom.DeclarationSpecifier.CElementWrapper#setDeclSpecifier(org.eclipse.cdt.internal.core.dom.DeclarationSpecifier) + */ + public void setDeclSpecifier(DeclarationSpecifier in) { + declSpec = in; + } + + /** + * @see org.eclipse.cdt.internal.core.newparser.util.DeclarationSpecifier.Container#removeDeclarator(java.lang.Object) + */ + public void removeDeclarator(Object declarator) { + declarators.remove( declarator ); + } + +} diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/model/TranslationUnitWrapper.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/model/TranslationUnitWrapper.java new file mode 100644 index 00000000000..7284d695401 --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/model/TranslationUnitWrapper.java @@ -0,0 +1,32 @@ +package org.eclipse.cdt.internal.core.model; + +/** + * @author jcamelon + * + * To change this generated comment edit the template variable "typecomment": + * Window>Preferences>Java>Templates. + * To enable and disable the creation of type comments go to + * Window>Preferences>Java>Code Generation. + */ +public class TranslationUnitWrapper implements ICElementWrapper { + + TranslationUnit unit = null; + + /** + * @see org.eclipse.cdt.internal.core.model.IWrapper#getElement() + */ + public CElement getElement() { + return unit; + } + /** + * @see org.eclipse.cdt.internal.core.model.IWrapper#setElement(java.lang.Object) + */ + public void setElement(CElement item) { + unit = (TranslationUnit)item; + } + + public TranslationUnitWrapper( ) + { + } + +} diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/BranchTracker.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/BranchTracker.java new file mode 100644 index 00000000000..4aab6428b9b --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/BranchTracker.java @@ -0,0 +1,180 @@ +package org.eclipse.cdt.internal.core.parser; + +import java.util.EmptyStackException; +import java.util.Stack; + +/** + * @author jcamelon + * + * To change this generated comment edit the template variable +"typecomment": + * Window>Preferences>Java>Templates. + * To enable and disable the creation of type comments go to + * Window>Preferences>Java>Code Generation. + */ +public class BranchTracker { + + private static final int IGNORE_SENTINEL = -1; + + /** + * Default constructor. + * + * @see java.lang.Object#Object() + */ + public BranchTracker() + { + } + + private Stack branches = new Stack(); + + private int ignore = IGNORE_SENTINEL; + private static final Boolean FALSE = new Boolean( false ); + private static final Boolean TRUE = new Boolean( true ); + + /** + * Method poundif. + * + * This method is called whenever one encounters a #if, #ifndef + * or #ifdef preprocessor directive. + * + * @param taken - boolean indicates whether or not the condition + * evaluates to true or false + * @return boolean - are we set to continue scanning or not? + */ + public boolean poundif( boolean taken ) + { + if( ignore == IGNORE_SENTINEL ) + { + // we are entering an if + // push the taken value onto the stack + branches.push( new Boolean( taken ) ); + + if( taken == false ) + { + ignore = branches.size(); + } + + return taken; + } + else + { + branches.push( FALSE ); + return false; + } + } + + public boolean poundelif( boolean taken ) throws ScannerException + { + if( ignore != IGNORE_SENTINEL && ignore < branches.size() ) + { + branches.pop(); + branches.push( FALSE ); + return false; + } + + // so at this point we are either + // --> ignore == IGNORE_SENTINEL + // --> ignore >= branches.size() + // check the branch queue to see whether or not the branch has already been taken + Boolean branchAlreadyTaken; + try + { + branchAlreadyTaken = (Boolean) branches.peek(); + } + catch( EmptyStackException ese ) + { + throw new ScannerException( "#elif without a #if "); + } + + if( ignore == IGNORE_SENTINEL ) + { + if( ! branchAlreadyTaken.booleanValue() ) + { + branches.pop(); + branches.push( new Boolean( taken ) ); + if( ! taken ) + ignore = branches.size(); + + return taken; + } + + // otherwise this section is to be ignored as well + ignore = branches.size(); + return false; + } + + // if we have gotten this far then ignore == branches.size() + if( ! branchAlreadyTaken.booleanValue() ) + { + branches.pop(); + branches.push( new Boolean( taken ) ); + if( taken ) + ignore = IGNORE_SENTINEL; + + return taken; + } + ignore = branches.size(); + return false; + } + + public boolean poundelse() throws ScannerException + { + if( ignore != IGNORE_SENTINEL && ignore < branches.size() ) + { + branches.pop(); + branches.push( FALSE ); + return false; + } + + Boolean branchAlreadyTaken; + try + { + branchAlreadyTaken = (Boolean) branches.peek(); + } + catch( EmptyStackException ese ) + { + throw new ScannerException( "#else without a #if "); + } + + if( ignore == IGNORE_SENTINEL ) + { + if( branchAlreadyTaken.booleanValue() ) + { + ignore = branches.size(); + return false; + } + + branches.pop(); + branches.push( TRUE ); + return true; + + } + + // now ignore >= branches.size() + if( branchAlreadyTaken.booleanValue() ) + { + ignore = branches.size(); + return false; + } + + branches.pop(); + branches.push( TRUE ); + ignore = IGNORE_SENTINEL; + return true; + + } + + // taken only on an #endif + public boolean poundendif( ) + { + if( ignore == branches.size() ) + ignore = IGNORE_SENTINEL; + branches.pop(); + return ( ignore == IGNORE_SENTINEL ); + } + + public int getDepth() + { + return branches.size(); + } +} diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/Declaration.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/Declaration.java new file mode 100644 index 00000000000..8ad426e9437 --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/Declaration.java @@ -0,0 +1,220 @@ +package org.eclipse.cdt.internal.core.parser; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.Set; + +/** + * @author aniefer + * + * To change this generated comment edit the template variable "typecomment": + * Window>Preferences>Java>Templates. + * To enable and disable the creation of type comments go to + * Window>Preferences>Java>Code Generation. + */ +public class Declaration { + + /** + * Constructor for Declaration. + */ + public Declaration() { + super(); + } + + public Declaration( String name ){ + _name = name; + } + + public Declaration( String name, Object obj ){ + _name = name; + _object = obj; + } + + //Type information, only what we need for now... + public static final int typeMask = 0x0001f; + public static final int isStatic = 0x00020; + + // Types + public static final int t_type = 0; // Type Specifier + public static final int t_class = 1; + public static final int t_struct = 2; + public static final int t_union = 3; + public static final int t_enum = 4; + + public void setStatic( boolean b ) { setBit( b, isStatic ); } + public boolean isStatic() { return checkBit( isStatic ); } + + public void setType(int t) throws ParserSymbolTableException { + if( t > typeMask ) + throw new ParserSymbolTableException( ParserSymbolTableException.r_BadTypeInfo ); + _typeInfo = _typeInfo & ~typeMask | t; + } + public int getType(){ + return _typeInfo & typeMask; + } + public boolean isType( int t ){ + return ( t == -1 || getType() == t ); + } + + public Declaration getTypeDeclaration() { return _typeDeclaration; } + public void setTypeDeclaration( Declaration type ){ + try { setType( t_type ); } + catch (ParserSymbolTableException e) { /*will never happen*/ } + + _typeDeclaration = type; + } + + public String getName() { return _name; } + public void setName(String name) { _name = name; } + + public Object getObject() { return _object; } + public void setObject( Object obj ) { _object = obj; } + + public Declaration getContainingScope() { return _containingScope; } + protected void setContainingScope( Declaration scope ) { _containingScope = scope; } + + public void addParent( Declaration parent ){ + addParent( parent, false ); + } + public void addParent( Declaration parent, boolean virtual ){ + _parentScopes.add( new ParentWrapper( parent, virtual ) ); + } + + protected void addDeclaration( Declaration obj ){ + obj.setContainingScope( this ); + _containedDeclarations.put( obj.getName(), obj ); + } + + public Map getContainedDeclarations(){ + return _containedDeclarations; + } + + /** + * Lookup the given name in this context. + * @param type: for elaborated lookups, only return declarations of this + * type + * @param name: Name of the object to lookup + * @return Declaration + * @throws ParserSymbolTableException + * @see ParserSymbolTable#Lookup + */ + protected Declaration Lookup( int type, String name ) throws ParserSymbolTableException{ + + if( type != -1 && type < t_class && type > t_union ) + throw new ParserSymbolTableException( ParserSymbolTableException.r_BadTypeInfo ); + + Declaration decl = null; + + //if this name define in this scope? + decl = (Declaration) _containedDeclarations.get( name ); + + //if yes, it hides any others, we are done. + if( decl != null && decl.isType( type ) ){ + return decl; + } + + //if no, we next check any parents we have + decl = LookupInParents( type, name, new HashSet() ); + + //if still not found, check our containing scope. + if( decl == null && _containingScope != null ) + decl = _containingScope.Lookup( type, name ); + + return decl; + } + + private Declaration LookupInParents( int type, String name, Set virtualsVisited ) throws ParserSymbolTableException{ + + Declaration decl = null, temp = null; + + Iterator iterator = _parentScopes.iterator(); + + ParentWrapper wrapper = null; + try{ + wrapper = (ParentWrapper) iterator.next(); + } + catch ( NoSuchElementException e ){ + wrapper = null; + } + + while( wrapper != null ) + { + if( !wrapper.isVirtual || !virtualsVisited.contains( wrapper.parent ) ){ + if( wrapper.isVirtual ) + virtualsVisited.add( wrapper.parent ); + + //is this name define in this scope? + temp = (Declaration) wrapper.parent._containedDeclarations.get( name ); + if( temp == null || !temp.isType( type ) ) + temp = wrapper.parent.LookupInParents( type, name, virtualsVisited ); + } + + if( temp != null && temp.isType( type ) ){ + if( decl == null ) + decl = temp; + else if ( temp != null ) + { + //it is not ambiguous if temp & decl are the same thing and it is static + //or an enum + if( decl == temp && ( temp.isStatic() || temp.getType() == t_enum) ) + temp = null; + else + throw( new ParserSymbolTableException( ParserSymbolTableException.r_AmbiguousName ) ); + + } + } + else + temp = null; + + try{ + wrapper = (ParentWrapper) iterator.next(); + } + catch (NoSuchElementException e){ + wrapper = null; + } + } + + return decl; + } + + + // Convenience methods + private void setBit(boolean b, int mask) { + if (b) _typeInfo = _typeInfo | mask; + else _typeInfo = _typeInfo & ~mask; + } + + private boolean checkBit(int mask) { + return (_typeInfo & mask) != 0; + } + + + //Other scopes to check if the name is not in currRegion + //we might want another Vector to deal with namespaces & using... + private Declaration _containingScope = null; + private Declaration _type = null; + private Declaration _typeDeclaration = null; + private int _typeInfo = 0; + private Object _object = null; + private List _parentScopes = new LinkedList(); + private Map _containedDeclarations = new HashMap(); + private String _name; + + + private class ParentWrapper{ + public ParentWrapper( Declaration p, boolean v ){ + parent = p; + isVirtual = v; + } + + public boolean isVirtual = false; + public Declaration parent = null; + } + + +} diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/ExpressionEvaluator.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/ExpressionEvaluator.java new file mode 100644 index 00000000000..bfb67a30d0e --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/ExpressionEvaluator.java @@ -0,0 +1,111 @@ +/******************************************************************************* + * Copyright (c) 2001 Rational Software Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * Rational Software - initial implementation + ******************************************************************************/ +package org.eclipse.cdt.internal.core.parser; + +import java.util.Stack; + +public class ExpressionEvaluator extends NullParserCallback { + + public class ExpressionException extends Exception { + public ExpressionException(String msg) { + super(msg); + } + } + + private Stack stack = new Stack(); + + private int popInt() { + return ((Integer)stack.pop()).intValue(); + } + + /** + * @see org.eclipse.cdt.core.newparser.IParserCallback#expressionOperator(Token) + */ + public void expressionOperator(Token operator) throws Exception { + + int second = popInt(); + int first; + switch (operator.getType()) { + + case Token.tPLUS: + first = popInt(); + stack.push(new Integer(first + second)); + break; + case Token.tMINUS: + first = popInt(); + stack.push(new Integer(first - second)); + break; + case Token.tSTAR: + first = popInt(); + stack.push(new Integer(first * second)); + break; + case Token.tDIV: + first = popInt(); + stack.push(new Integer(first / second)); + break; + case Token.tLT: + first = popInt(); + stack.push(new Integer(first < second ? 1 : 0)); + break; + case Token.tLTEQUAL: + first = popInt(); + stack.push(new Integer(first <= second ? 1 : 0)); + break; + case Token.tGT: + first = popInt(); + stack.push(new Integer(first > second ? 1 : 0)); + break; + case Token.tGTEQUAL: + first = popInt(); + stack.push(new Integer(first >= second ? 1 : 0)); + break; + case Token.tEQUAL: + first = popInt(); + stack.push(new Integer(first == second ? 1 : 0)); + break; + case Token.tNOTEQUAL: + first = popInt(); + stack.push(new Integer(first != second ? 1 : 0)); + break; + case Token.tAND: + first = popInt(); + stack.push( new Integer( ( ( first != 0 ) && ( second != 0 ) ) ? 1 : 0 ) ); + break; + case Token.tOR: + first = popInt(); + stack.push( new Integer( ( ( first != 0 ) || ( second != 0 ) ) ? 1 : 0 ) ); + break; + case Token.tNOT: + stack.push( new Integer( ( second == 0 ) ? 1 : 0 ) ); + break; + default: + throw new ExpressionException("Unhandled operator: " + operator ); + } + } + + /** + * @see org.eclipse.cdt.core.newparser.IParserCallback#expressionTerminal(Token) + */ + public void expressionTerminal(Token terminal) throws Exception { + switch (terminal.getType()) { + case Token.tINTEGER: + stack.push(new Integer(terminal.getImage())); + break; + default: + throw new ExpressionException("Unhandled terminal: " + terminal.getImage()); + } + } + + public Object getResult() { + return stack.peek(); + } + +} diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/IMacroDescriptor.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/IMacroDescriptor.java new file mode 100644 index 00000000000..9c9fba8e3dc --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/IMacroDescriptor.java @@ -0,0 +1,18 @@ +package org.eclipse.cdt.internal.core.parser; +import java.util.List; +/** + * @author jcamelon + * + * To change this generated comment edit the template variable +"typecomment": + * Window>Preferences>Java>Templates. + * To enable and disable the creation of type comments go to + * Window>Preferences>Java>Code Generation. + */ +public interface IMacroDescriptor { + void initialize(String name, List identifiers, List tokens, String sig); + List getParameters(); + List getTokenizedExpansion(); + String getName(); + String getSignature(); +} \ No newline at end of file diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/IParserCallback.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/IParserCallback.java new file mode 100644 index 00000000000..f8d7fe7dc7a --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/IParserCallback.java @@ -0,0 +1,57 @@ +/******************************************************************************* + * Copyright (c) 2001 Rational Software Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * Rational Software - initial implementation + ******************************************************************************/ +package org.eclipse.cdt.internal.core.parser; + +public interface IParserCallback { + + public Object translationUnitBegin(); + public void translationUnitEnd(Object unit); + + public void inclusionBegin(String includeFile, int offset); + public void inclusionEnd(); + public void macro(String macroName, int offset); + + public Object simpleDeclarationBegin(Object Container); + public void simpleDeclarationEnd(Object declaration); + + public Object parameterDeclarationBegin( Object Container ); + public void parameterDeclarationEnd( Object declaration ); + + public void simpleDeclSpecifier(Object Container, Token specifier); + + public void nameBegin(Token firstToken); + public void nameEnd(Token lastToken); + + public Object declaratorBegin(Object container); + public void declaratorId(Object declarator); + public void declaratorAbort( Object container, Object declarator ); + public void declaratorEnd(Object declarator); + + public Object argumentsBegin( Object declarator ); + public void argumentsEnd(Object parameterDeclarationClause); + + + public void functionBodyBegin(); + public void functionBodyEnd(); + + public Object classSpecifierBegin(Object container, Token classKey); + public void classSpecifierName(Object classSpecifier); + public void classSpecifierEnd(Object classSpecifier); + + public Object baseSpecifierBegin( Object containingClassSpec ); + public void baseSpecifierName( Object baseSpecifier ); + public void baseSpecifierVisibility( Object baseSpecifier, Token visibility ); + public void baseSpecifierVirtual( Object baseSpecifier, boolean virtual ); + public void baseSpecifierEnd( Object baseSpecifier ); + + public void expressionOperator(Token operator) throws Exception; + public void expressionTerminal(Token terminal) throws Exception; +} diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/IScanner.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/IScanner.java new file mode 100644 index 00000000000..63ef33190a4 --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/IScanner.java @@ -0,0 +1,31 @@ +package org.eclipse.cdt.internal.core.parser; + +import java.io.Reader; +import java.util.List; + +/** + * @author jcamelon + * + * To change this generated comment edit the template variable +"typecomment": + * Window>Preferences>Java>Templates. + * To enable and disable the creation of type comments go to + * Window>Preferences>Java>Code Generation. + */ +public interface IScanner { + + public IScanner initialize( Reader sourceToBeRead, String fileName ); + + public void addDefinition(String key, IMacroDescriptor macroToBeAdded ); + public void addDefinition(String key, String value); + public Object getDefinition(String key); + + public Object[] getIncludePaths(); + public void addIncludePath(String includePath); + public void overwriteIncludePath( List newIncludePaths ); + + public Token nextToken() throws ScannerException; + + public void setQuickScan(boolean qs); + public void setCallback(IParserCallback c); +} diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/IScannerContext.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/IScannerContext.java new file mode 100644 index 00000000000..b96f3f2aa2d --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/IScannerContext.java @@ -0,0 +1,21 @@ +package org.eclipse.cdt.internal.core.parser; +import java.io.Reader; +import java.io.IOException; +/** + * @author jcamelon + * + * To change this generated comment edit the template variable +"typecomment": + * Window>Preferences>Java>Templates. + * To enable and disable the creation of type comments go to + * Window>Preferences>Java>Code Generation. + */ +public interface IScannerContext { + IScannerContext initialize(Reader r, String f, int u); + int read() throws IOException; + String getFilename(); + int getOffset(); + Reader getReader(); + int getUndo(); + void setUndo(int undo); +} \ No newline at end of file diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/MacroDescriptor.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/MacroDescriptor.java new file mode 100644 index 00000000000..13874ca22ea --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/MacroDescriptor.java @@ -0,0 +1,107 @@ +/******************************************************************************* + * Copyright (c) 2001 Rational Software Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * Rational Software - initial implementation + ******************************************************************************/ +package org.eclipse.cdt.internal.core.parser; + +import java.util.Iterator; +import java.util.List; + +public class MacroDescriptor implements IMacroDescriptor { + + public MacroDescriptor() + { + } + + /** + * Method initialize. + * @param name The name or label that the Macro can be identified by. + * @param identifiers An ordered list of parameters in the macro + * definition. + * @param tokens An ordered list of tokens that describe the + * RHS expansion in the macro definition. + * @param sig The complete signature of the macro, as a string. + */ + public void initialize( String name, List identifiers, List tokens, String sig ) + { + this.name = name; + identifierParameters = identifiers; + tokenizedExpansion = tokens; + signature = sig; + } + + private String name; + private List identifierParameters; + private List tokenizedExpansion; + private String signature; + /** + * Returns the identifiers. + * @return List + */ + public final List getParameters() { + return identifierParameters; + } + + /** + * Returns the tokens. + * @return List + */ + public final List getTokenizedExpansion() { + return tokenizedExpansion; + } + + /** + * Returns the name. + * @return String + */ + public final String getName() + { + return name; + } + + /** + * @see java.lang.Object#toString() + */ + public String toString() + { + StringBuffer buffer = new StringBuffer( 128 ); + int count = getParameters().size(); + + buffer.append( "MacroDescriptor with name=" + getName() + "\n" ); + buffer.append( "Number of parameters = " + count + "\n" ); + Iterator iter = getParameters().iterator(); + int current = 0; + while( iter.hasNext() ) + { + buffer.append( "Parameter #" + current++ + " with name=" + (String) iter.next() + "\n" ); + } + + count = getTokenizedExpansion().size(); + iter = getTokenizedExpansion().iterator(); + + buffer.append( "Number of tokens = " + count + "\n" ); + current = 0; + while( iter.hasNext() ) + { + buffer.append( "Token #" + current++ + " is " + ((Token)iter.next()).toString() + "\n" ); + } + + return buffer.toString(); + } + + /** + * Returns the signature. + * @return String + */ + public final String getSignature() + { + return signature; + } + +} diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/Main.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/Main.java new file mode 100644 index 00000000000..85636acb0e5 --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/Main.java @@ -0,0 +1,82 @@ +/******************************************************************************* + * Copyright (c) 2001 Rational Software Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * Rational Software - initial implementation + ******************************************************************************/ +package org.eclipse.cdt.internal.core.parser; + +import java.io.FileReader; +import java.io.Reader; + +public class Main { + + public static void main(String[] args) { + + String fileName = null; + + // Find the file + for (int i = 0; i < args.length; ++i) { + if (!args[i].startsWith("-")) + fileName = args[i]; + } + + if (fileName == null) { + System.out.println("Error: no files."); + return; + } + + Reader reader; + try { + reader = new FileReader(fileName); + } catch (Exception e) { + System.err.println(e); + return; + } + + Scanner scanner = new Scanner(); + scanner.initialize( reader, fileName ); + + // Now pass on the preprocessing options + for (int i = 0; i < args.length; ++i) { + if (args[i].startsWith("-I")) { + String dir = args[i].substring(2); + scanner.addIncludePath(dir); + } else if (args[i].startsWith("-D")) { + int pos = args[i].indexOf('='); + String name; + String value = ""; + if (pos < 0) { + name = args[i].substring(2); + } else { + name = args[i].substring(2, pos); + value = args[i].substring(pos + 1); + } + scanner.addDefinition(name, value); + } + } + + Parser parser = null; + try { + parser = new Parser(scanner); + } catch (Exception e) { + System.out.println(e); + return; + } + + long startTime = System.currentTimeMillis(); + try { + parser.parse(); + } catch (Exception e) { + System.err.println(e); + } + + long time = System.currentTimeMillis() - startTime; + + System.out.println("done " + scanner.getCount() + " tokens in " + time + "ms."); + } +} diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/NullParserCallback.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/NullParserCallback.java new file mode 100644 index 00000000000..2560d7466d1 --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/NullParserCallback.java @@ -0,0 +1,175 @@ +package org.eclipse.cdt.internal.core.parser; + +public class NullParserCallback implements IParserCallback { + /** + * @see org.eclipse.cdt.internal.core.newparser.IParserCallback#beginArguments() + */ + public Object argumentsBegin( Object container ) { + return null; + } + + /** + * @see org.eclipse.cdt.internal.core.newparser.IParserCallback#beginClass(String, Token) + */ + public Object classSpecifierBegin(Object container, Token classKey) { + return null; + } + + /** + * @see org.eclipse.cdt.internal.core.newparser.IParserCallback#beginDeclarator() + */ + public Object declaratorBegin(Object container) { + return null; + } + + /** + * @see org.eclipse.cdt.internal.core.newparser.IParserCallback#beginFunctionBody() + */ + public void functionBodyBegin() { + } + + /** + * @see org.eclipse.cdt.internal.core.newparser.IParserCallback#beginInclusion(String) + */ + public void inclusionBegin(String includeFile, int offset) { + } + + /** + * @see org.eclipse.cdt.internal.core.newparser.IParserCallback#beginSimpleDeclaration(Token) + */ + public Object simpleDeclarationBegin(Object Container) { + return null; + } + + /** + * @see org.eclipse.cdt.internal.core.newparser.IParserCallback#beginTranslationUnit() + */ + public Object translationUnitBegin() { + return null; + } + + /** + * @see org.eclipse.cdt.internal.core.newparser.IParserCallback#declaratorId(Token) + */ + public void declaratorId(Object declarator) { + } + + /** + * @see org.eclipse.cdt.internal.core.newparser.IParserCallback#declSpecifier(Token) + */ + public void simpleDeclSpecifier(Object Container, Token specifier) { + } + + /** + * @see org.eclipse.cdt.internal.core.newparser.IParserCallback#endArguments() + */ + public void argumentsEnd(Object parameterDeclarationClause) { + } + + /** + * @see org.eclipse.cdt.internal.core.newparser.IParserCallback#endClass() + */ + public void classSpecifierEnd(Object classSpecifier) { + } + + /** + * @see org.eclipse.cdt.internal.core.newparser.IParserCallback#endDeclarator() + */ + public void declaratorEnd(Object declarator) { + } + + /** + * @see org.eclipse.cdt.internal.core.newparser.IParserCallback#endFunctionBody() + */ + public void functionBodyEnd() { + } + + /** + * @see org.eclipse.cdt.internal.core.newparser.IParserCallback#endInclusion() + */ + public void inclusionEnd() { + } + + /** + * @see org.eclipse.cdt.internal.core.newparser.IParserCallback#endSimpleDeclaration(Token) + */ + public void simpleDeclarationEnd(Object declaration) { + } + + /** + * @see org.eclipse.cdt.internal.core.newparser.IParserCallback#endTranslationUnit() + */ + public void translationUnitEnd(Object unit) { + } + + /** + * @see org.eclipse.cdt.internal.core.newparser.IParserCallback#expressionOperator(Token) + */ + public void expressionOperator(Token operator) throws Exception { + } + + /** + * @see org.eclipse.cdt.internal.core.newparser.IParserCallback#expressionTerminal(Token) + */ + public void expressionTerminal(Token terminal) throws Exception { + } + + /** + * @see org.eclipse.cdt.internal.core.newparser.IParserCallback#macro(String) + */ + public void macro(String macroName, int offset) { + } + + /** + * @see org.eclipse.cdt.internal.core.newparser.IParserCallback#nameBegin(org.eclipse.cdt.internal.core.newparser.Token) + */ + public void nameBegin(Token firstToken) { + } + + /** + * @see org.eclipse.cdt.internal.core.newparser.IParserCallback#nameEnd(org.eclipse.cdt.internal.core.newparser.Token) + */ + public void nameEnd(Token lastToken) { + } + + /** + * @see org.eclipse.cdt.internal.core.newparser.IParserCallback#classSpecifierName() + */ + public void classSpecifierName(Object classSpecifier) { + } + + public Object baseSpecifierBegin( Object classSpecifier ) + { + return null; + } + + public void baseSpecifierEnd( Object x ) + { + } + + public void baseSpecifierName( Object baseSpecifier ) + { + } + + public void baseSpecifierVisibility( Object baseSpecifier, Token visibility ) + { + } + + public void baseSpecifierVirtual( Object baseSpecifier, boolean virtual ) + { + } + + public Object parameterDeclarationBegin( Object container ) + { + return null; + } + + public void parameterDeclarationEnd( Object declaration ){ + } + /** + * @see org.eclipse.cdt.internal.core.newparser.IParserCallback#declaratorAbort(java.lang.Object, java.lang.Object) + */ + public void declaratorAbort(Object container, Object declarator) { + } + +} diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/Parser.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/Parser.java new file mode 100644 index 00000000000..d44b0c02d46 --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/Parser.java @@ -0,0 +1,1286 @@ +package org.eclipse.cdt.internal.core.parser; + +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.StringReader; +import java.util.HashMap; +import java.util.Map; + +/** + * This is an attempt at a copyright clean parser. The grammar is based + * on the ISO C++ standard + */ +public class Parser { + + private IParserCallback callback; + private boolean quickParse = false; + private boolean parsePassed = true; + + // TO DO: convert to a real symbol table + private Map currRegion = new HashMap(); + + public Parser(IScanner s, IParserCallback c, boolean quick) throws Exception { + callback = c; + scanner = s; + quickParse = quick; + scanner.setQuickScan(quick); + scanner.setCallback(c); + //fetchToken(); + } + + public Parser(IScanner s, IParserCallback c) throws Exception { + this(s, c, false); + } + + public Parser( IScanner s) throws Exception { + this(s, new NullParserCallback(), false); + } + + public Parser(String code) throws Exception { + this(new Scanner().initialize( new StringReader( code ), null +)); + } + + public Parser(String code, IParserCallback c) throws Exception { + this(new Scanner().initialize( new StringReader( code ), null +), c, false); + } + + public Parser(InputStream stream, IParserCallback c, boolean quick) throws Exception { + this(new Scanner().initialize( new InputStreamReader(stream), null ), +c, quick); + } + + private static int parseCount = 0; + + public boolean parse() throws Exception { + long startTime = System.currentTimeMillis(); + translationUnit(); + System.out.println("Parse " + (++parseCount) + ": " + + ( System.currentTimeMillis() - startTime ) + "ms" + + ( parsePassed ? "" : " - parse failure" )); + + return parsePassed; + } + + /** + * translationUnit + * : (declaration)* + * + */ + public void translationUnit() throws Exception { + Object translationUnit = callback.translationUnitBegin(); + Token lastBacktrack = null; + while (LT(1) != Token.tEOF) { + try { + declaration( translationUnit ); + } catch (Backtrack b) { + // Mark as failure and try to reach a recovery point + parsePassed = false; + + if (lastBacktrack != null && lastBacktrack == LA(1)) { + // we haven't progressed from the last backtrack + // try and find tne next definition + for (int t = LT(1); t != Token.tEOF; t = LT(1)) { + consume(); + // TO DO: we should really check for matching braces too + if (t == Token.tSEMI) + break; + } + } else { + // start again from here + lastBacktrack = LA(1); + } + } + } + callback.translationUnitEnd(translationUnit); + } + + /** + * declaration + * : {"asm"} asmDefinition + * | {"namespace"} namespaceDefinition + * | {"using"} usingDeclaration + * | {"export"|"template"} templateDeclaration + * | {"extern"} linkageSpecification + * | simpleDeclaration + * + * Notes: + * - folded in blockDeclaration + * - merged alternatives that required same LA + * - functionDefinition into simpleDeclaration + * - namespaceAliasDefinition into namespaceDefinition + * - usingDirective into usingDeclaration + * - explicitInstantiation and explicitSpecialization into + * templateDeclaration + */ + public void declaration( Object container ) throws Exception { + switch (LT(1)) { + case Token.t_asm: + // asmDefinition( ); + consume(); + return; + case Token.t_namespace: + // namespaceDefinition(); + consume(); + return; + case Token.t_using: + // usingDeclaration(); + consume(); + return; + case Token.t_export: + case Token.t_template: + // templateDeclaration(); + consume(); + return; + case Token.t_extern: + if (LT(2) == Token.tSTRING) + { + // linkageSpecification(); + consume(); + return; + } + + // else drop through + default: + simpleDeclaration( container ); + } + } + + + + /** + * simpleDeclaration + * : (declSpecifier)* (initDeclarator ("," initDeclarator)*)? + * (";" | {"{"} functionBody) + * + * Notes: + * - append functionDefinition stuff to end of this rule + * + * To do: + * - work in ctorInitializer and functionTryBlock + */ + public void simpleDeclaration( Object container ) throws Exception { + Object simpleDecl = callback.simpleDeclarationBegin( container); + declSpecifierSeq(simpleDecl); + + if (LT(1) != Token.tSEMI) + try { + initDeclarator(simpleDecl); + + while (LT(1) == Token.tCOMMA) { + consume(); + + try { + initDeclarator(simpleDecl); + } catch (Backtrack b) { + throw b; + } + } + } catch (Backtrack b) { + // allowed to be empty + } + + switch (LT(1)) { + case Token.tSEMI: + consume(); + break; + case Token.tLBRACE: + callback.functionBodyBegin(); + if (quickParse) { + // speed up the parser by skiping the body + // simply look for matching brace and return + consume(); + int depth = 1; + while (depth > 0) { + switch (consume().getType()) { + case Token.tRBRACE: + --depth; + break; + case Token.tLBRACE: + ++depth; + break; + case Token.tEOF: + // Oops, no match + throw backtrack; + } + } + } else { + functionBody(); + } + callback.functionBodyEnd(); + break; + default: + break; + } + + callback.simpleDeclarationEnd(simpleDecl); + } + + + public void parameterDeclaration( Object containerObject ) throws Exception + { + Object parameterDecl = callback.parameterDeclarationBegin( containerObject ); + declSpecifierSeq( parameterDecl ); + + if (LT(1) != Token.tSEMI) + try { + initDeclarator(parameterDecl); + + } catch (Backtrack b) { + // allowed to be empty + } + + callback.parameterDeclarationEnd( parameterDecl ); + + } + + /** + * declSpecifier + * : "auto" | "register" | "static" | "extern" | "mutable" + * | "inline" | "virtual" | "explicit" + * | "char" | "wchar_t" | "bool" | "short" | "int" | "long" + * | "signed" | "unsigned" | "float" | "double" | "void" + * | "const" | "volatile" + * | "friend" | "typedef" + * | ("typename")? name + * | {"class"|"struct"|"union"} classSpecifier + * | {"enum"} enumSpecifier + * + * Notes: + * - folded in storageClassSpecifier, typeSpecifier, functionSpecifier + * - folded elaboratedTypeSpecifier into classSpecifier and enumSpecifier + * - find template names in name + */ + public void declSpecifierSeq( Object decl ) throws Exception { + boolean encounteredTypename = false; + boolean encounteredRawType = false; + declSpecifiers: + for (;;) { + switch (LT(1)) { + case Token.t_auto: + case Token.t_register: + case Token.t_static: + case Token.t_extern: + case Token.t_mutable: + case Token.t_inline: + case Token.t_virtual: + case Token.t_explicit: + case Token.t_typedef: + case Token.t_friend: + case Token.t_const: + case Token.t_volatile: + case Token.t_char: + case Token.t_wchar_t: + case Token.t_bool: + case Token.t_short: + case Token.t_int: + case Token.t_long: + case Token.t_signed: + case Token.t_unsigned: + case Token.t_float: + case Token.t_double: + case Token.t_void: + encounteredRawType = true; + callback.simpleDeclSpecifier(decl, consume()); + break; + case Token.t_typename: + consume(); + name(); + break; + case Token.tCOLONCOLON: + consume(); + // handle nested later: + case Token.tIDENTIFIER: + if( ! encounteredRawType ) + { + // handle nested later: + if( ! encounteredTypename ) + { + callback.simpleDeclSpecifier(decl,consume()); + encounteredTypename = true; + break; + } + else + return; + } + else + return; + + case Token.t_class: + case Token.t_struct: + case Token.t_union: + classSpecifier(decl); + return; + case Token.t_enum: + // enumSpecifier(); + break; + default: + break declSpecifiers; + } + } + } + + /** + * name + * : ("::")? name2 ("::" name2)* + * + * name2 + * : IDENTIFER + * + * To Do: + * - Handle template ids + * - Handle unqualifiedId + */ + public boolean name() throws Exception { + Token last = null; + + callback.nameBegin(LA(1)); + + if (LT(1) == Token.tCOLONCOLON) + last = consume(); + + last = consume(Token.tIDENTIFIER); + + while (LT(1) == Token.tCOLONCOLON) { + last = consume(); + + last = consume(Token.tIDENTIFIER); + } + + callback.nameEnd(last); + + return true; + } + + /** + * cvQualifier + * : "const" | "volatile" + */ + public Object cvQualifier() throws Exception { + switch (LT(1)) { + case Token.t_const: + case Token.t_volatile: + consume(); + return null; + default: + throw backtrack; + } + } + + /** + * initDeclarator + * : declarator ("=" initializerClause | "(" expressionList ")")? + * + * To Do: + * - handle initializers + */ + public void initDeclarator( Object owner ) throws Exception { + declarator( owner ); + } + + /** + * declarator + * : (ptrOperator)* directDeclarator + * + * directDeclarator + * : declaratorId + * | directDeclarator "(" parameterDeclarationClause ")" (cvQualifier)* + * (exceptionSpecification)* + * | directDeclarator "[" (constantExpression)? "]" + * | "(" declarator")" + * + * declaratorId + * : name + */ + public void declarator( Object container ) throws Exception { + + boolean aborted; + do + { + aborted = false; + Object declarator = callback.declaratorBegin( container ); + + for (;;) { + try { + ptrOperator(); + } catch (Backtrack b) { + break; + } + } + + if (LT(1) == Token.tLPAREN) { + consume(); + declarator(declarator); + consume(Token.tRPAREN); + return; + } + + name(); + callback.declaratorId(declarator); + + for (;;) { + switch (LT(1)) { + case Token.tLPAREN: + // parameterDeclarationClause + Object clause = callback.argumentsBegin(declarator); + consume(); + parameterDeclarationLoop: + for (;;) { + switch (LT(1)) { + case Token.tRPAREN: + consume(); + break parameterDeclarationLoop; + case Token.tELIPSE: + consume(); + break; + case Token.tCOMMA: + consume(); + break; + default: + parameterDeclaration( clause ); + } + } + callback.argumentsEnd(clause); + break; + case Token.tLBRACKET: + consume(); + // constantExpression(); + consume(Token.tRBRACKET); + continue; + } + break; + } + + if( LA(1).getType() == Token.tIDENTIFIER ) + { + callback.declaratorAbort( container, declarator ); + declarator = null; + aborted = true; + } + else + callback.declaratorEnd(declarator); + } while( aborted ); + } + + /** + * ptrOperator + * : "*" (cvQualifier)* + * | "&" + * | name "*" (cvQualifier)* + */ + public Object ptrOperator() throws Exception { + int t = LT(1); + + if (t == Token.tAMPER) { + consume(); + return null; + } + + Token mark = mark(); + if (t == Token.tIDENTIFIER || t == Token.tCOLONCOLON) + name(); + + if (t == Token.tSTAR) { + consume(); + + for (;;) { + try { + cvQualifier(); + } catch (Backtrack b) { + break; + } + } + + return null; + } + + backup(mark); + throw backtrack; + } + + /** + * classSpecifier + * : classKey name (baseClause)? "{" (memberSpecification)* "}" + */ + public void classSpecifier( Object owner ) throws Exception { + Token classKey = null; + + // class key + switch (LT(1)) { + case Token.t_class: + case Token.t_struct: + case Token.t_union: + classKey = consume(); + break; + default: + throw backtrack; + } + + Object classSpec = callback.classSpecifierBegin( owner, classKey); + + // class name + if (LT(1) == Token.tIDENTIFIER) { + name(); + callback.classSpecifierName(classSpec); + } + + //currRegion.put(name.getImage(), classKey); + + // base clause + if (LT(1) == Token.tCOLON) { + consume(); + baseSpecifier( classSpec ); + } + + // If we don't get a "{", assume elaborated type + if (LT(1) == Token.tLBRACE) { + consume(); + + memberDeclarationLoop: + while (LT(1) != Token.tRBRACE) { + switch (LT(1)) { + case Token.t_public: + consume(); + consume(Token.tCOLON); + break; + case Token.t_protected: + consume(); + consume(Token.tCOLON); + break; + case Token.t_private: + consume(); + consume(Token.tCOLON); + break; + case Token.tRBRACE: + consume(Token.tRBRACE); + break memberDeclarationLoop; + default: + declaration(classSpec); + } + } + // consume the } + consume(); + } + + callback.classSpecifierEnd(classSpec); + } + + public void baseSpecifier( Object classSpecOwner ) throws Exception { + + Object baseSpecifier = callback.baseSpecifierBegin( classSpecOwner ); + + baseSpecifierLoop: + for (;;) { + switch (LT(1)) { + case Token.t_virtual: + callback.baseSpecifierVirtual( baseSpecifier, true ); + consume(); + break; + case Token.t_public: + case Token.t_protected: + case Token.t_private: + callback.baseSpecifierVisibility( baseSpecifier, currToken ); + consume(); + break; + case Token.tCOLONCOLON: + case Token.tIDENTIFIER: + name(); + callback.baseSpecifierName( baseSpecifier ); + break; + case Token.tCOMMA: + callback.baseSpecifierEnd( baseSpecifier ); + baseSpecifier = callback.baseSpecifierBegin( classSpecOwner ); + consume(); + continue baseSpecifierLoop; + default: + break baseSpecifierLoop; + } + } + callback.baseSpecifierEnd( baseSpecifier ); + } + + public void functionBody() throws Exception { + compoundStatement(); + } + + // Statements + public void statement() throws Exception { + switch (LT(1)) { + case Token.t_case: + consume(); + constantExpression(); + consume(Token.tCOLON); + statement(); + return; + case Token.t_default: + consume(); + consume(Token.tCOLON); + statement(); + return; + case Token.tLBRACE: + compoundStatement(); + return; + case Token.t_if: + consume(); + consume(Token.tLPAREN); + condition(); + consume(Token.tRPAREN); + statement(); + if (LT(1) == Token.t_else) { + consume(); + statement(); + } + return; + case Token.t_switch: + consume(); + consume(Token.tLPAREN); + condition(); + consume(Token.tRPAREN); + statement(); + return; + case Token.t_while: + consume(); + consume(Token.tLPAREN); + condition(); + consume(Token.tRPAREN); + statement(); + return; + case Token.t_do: + consume(); + statement(); + consume(Token.t_while); + consume(Token.tLPAREN); + condition(); + consume(Token.tRPAREN); + return; + case Token.t_for: + consume(); + consume(Token.tLPAREN); + forInitStatement(); + if (LT(1) != Token.tSEMI) + condition(); + consume(Token.tSEMI); + if (LT(1) != Token.tRPAREN) + expression(); + consume(Token.tRPAREN); + statement(); + return; + case Token.t_break: + consume(); + consume(Token.tSEMI); + return; + case Token.t_continue: + consume(); + consume(Token.tSEMI); + return; + case Token.t_return: + consume(); + if (LT(1) != Token.tSEMI) + expression(); + consume(Token.tSEMI); + return; + case Token.t_goto: + consume(); + consume(Token.tIDENTIFIER); + consume(Token.tSEMI); + return; + case Token.t_try: + consume(); + compoundStatement(); + while (LT(1) == Token.t_catch) { + consume(); + consume(Token.tLPAREN); + declaration(null); // was exceptionDeclaration + consume(Token.tRPAREN); + compoundStatement(); + } + return; + case Token.tSEMI: + consume(); + return; + default: + // can be many things: + // label + if (LT(1) == Token.tIDENTIFIER && LT(2) == Token.tCOLON) { + consume(); + consume(); + statement(); + return; + } + + // expressionStatement + // Note: the function style cast ambiguity is handled in expression + // Since it only happens when we are in a statement + try { + expression(); + consume(Token.tSEMI); + return; + } catch (Backtrack b) { + } + + // declarationStatement + declaration(null); + } + } + + public void condition() throws Exception { + // TO DO + } + + public void forInitStatement() throws Exception { + // TO DO + } + + public void compoundStatement() throws Exception { + consume(Token.tLBRACE); + while (LT(1) != Token.tRBRACE) + statement(); + consume(); + } + + // Expressions + public void constantExpression() throws Exception { + conditionalExpression(); + } + + public void expression() throws Exception { + assignmentExpression(); + + while (LT(1) == Token.tCOMMA) { + Token t = consume(); + assignmentExpression(); + callback.expressionOperator(t); + } + } + + public void assignmentExpression() throws Exception { + if (LT(1) == Token.t_throw) { + throwExpression(); + return; + } + + // if the condition not taken, try assignment operators + if (!conditionalExpression()) { + switch (LT(1)) { + case Token.tASSIGN: + case Token.tSTARASSIGN: + case Token.tDIVASSIGN: + case Token.tMODASSIGN: + case Token.tPLUSASSIGN: + case Token.tMINUSASSIGN: + case Token.tSHIFTRASSIGN: + case Token.tSHIFTLASSIGN: + case Token.tAMPERASSIGN: + case Token.tXORASSIGN: + case Token.tBITORASSIGN: + Token t = consume(); + conditionalExpression(); + callback.expressionOperator(t); + break; + } + } + } + + public void throwExpression() throws Exception { + consume(Token.t_throw); + + try { + expression(); + } catch (Backtrack b) { + } + } + + public boolean conditionalExpression() throws Exception { + logicalOrExpression(); + + if (LT(1) == Token.tQUESTION) { + consume(); + expression(); + consume(Token.tCOLON); + assignmentExpression(); + return true; + } else + return false; + } + + public void logicalOrExpression() throws Exception { + logicalAndExpression(); + + while (LT(1) == Token.tOR) { + Token t = consume(); + logicalAndExpression(); + callback.expressionOperator(t); + } + } + + public void logicalAndExpression() throws Exception { + inclusiveOrExpression(); + + while (LT(1) == Token.tAND) { + Token t = consume(); + inclusiveOrExpression(); + callback.expressionOperator(t); + } + } + + public void inclusiveOrExpression() throws Exception { + exclusiveOrExpression(); + + while (LT(1) == Token.tBITOR) { + Token t = consume(); + exclusiveOrExpression(); + callback.expressionOperator(t); + } + } + + public void exclusiveOrExpression() throws Exception { + andExpression(); + + while (LT(1) == Token.tXOR) { + Token t = consume(); + andExpression(); + callback.expressionOperator(t); + } + } + + public void andExpression() throws Exception { + equalityExpression(); + + while (LT(1) == Token.tAMPER) { + Token t = consume(); + equalityExpression(); + callback.expressionOperator(t); + } + } + + public void equalityExpression() throws Exception { + relationalExpression(); + + for (;;) { + switch (LT(1)) { + case Token.tEQUAL: + case Token.tNOTEQUAL: + Token t = consume(); + relationalExpression(); + callback.expressionOperator(t); + break; + default: + return; + } + } + } + + public void relationalExpression() throws Exception { + shiftExpression(); + + for (;;) { + switch (LT(1)) { + case Token.tGT: + // For template args, the GT means end of args + //if (templateArgs) + // return; + case Token.tLT: + case Token.tLTEQUAL: + case Token.tGTEQUAL: + Token t = consume(); + shiftExpression(); + callback.expressionOperator(t); + break; + default: + return; + } + } + } + + public void shiftExpression() throws Exception { + additiveExpression(); + + for (;;) { + switch (LT(1)) { + case Token.tSHIFTL: + case Token.tSHIFTR: + Token t = consume(); + additiveExpression(); + callback.expressionOperator(t); + break; + default: + return; + } + } + } + + public void additiveExpression() throws Exception { + multiplicativeExpression(); + + for (;;) { + switch (LT(1)) { + case Token.tPLUS: + case Token.tMINUS: + Token t = consume(); + multiplicativeExpression(); + callback.expressionOperator(t); + break; + default: + return; + } + } + } + + public void multiplicativeExpression() throws Exception { + pmExpression(); + + for (;;) { + switch (LT(1)) { + case Token.tSTAR: + case Token.tDIV: + case Token.tMOD: + Token t = consume(); + pmExpression(); + callback.expressionOperator(t); + break; + default: + return; + } + } + } + + public void pmExpression() throws Exception { + castExpression(); + + for (;;) { + switch (LT(1)) { + case Token.tDOTSTAR: + case Token.tARROWSTAR: + Token t = consume(); + castExpression(); + callback.expressionOperator(t); + break; + default: + return; + } + } + } + + /** + * castExpression + * : unaryExpression + * | "(" typeId ")" castExpression + */ + public void castExpression() throws Exception { + // TO DO: we need proper symbol checkint to ensure type name + if (false && LT(1) == Token.tLPAREN) { + Token mark = mark(); + consume(); + + // If this isn't a type name, then we shouldn't be here + try { + typeId(); + consume(Token.tRPAREN); + castExpression(); + return; + } catch (Backtrack b) { + backup(mark); + } + } + + unaryExpression(); + } + + public void typeId() throws Exception { + try { + name(); + return; + } catch (Backtrack b) { + } + } + + public void deleteExpression() throws Exception { + if (LT(1) == Token.tCOLONCOLON) { + // global scope + consume(); + } + + consume(Token.t_delete); + + if (LT(1) == Token.tLBRACKET) { + // array delete + consume(); + consume(Token.tRBRACKET); + } + + castExpression(); + } + + public void newExpression() throws Exception { + if (LT(1) == Token.tCOLONCOLON) { + // global scope + consume(); + } + + consume (Token.t_new); + + // TO DO: finish this horrible mess... + } + + public void unaryExpression() throws Exception { + switch (LT(1)) { + case Token.tSTAR: + case Token.tAMPER: + case Token.tPLUS: + case Token.tMINUS: + case Token.tNOT: + case Token.tCOMPL: + case Token.tINCR: + case Token.tDECR: + Token t = consume(); + castExpression(); + callback.expressionOperator(t); + return; + case Token.t_sizeof: + if (LT(1) == Token.tLPAREN) { + consume(); + typeId(); + consume(Token.tRPAREN); + } else { + unaryExpression(); + } + return; + case Token.t_new: + newExpression(); + return; + case Token.t_delete: + deleteExpression(); + return; + case Token.tCOLONCOLON: + switch (LT(2)) { + case Token.t_new: + newExpression(); + return; + case Token.t_delete: + deleteExpression(); + return; + default: + postfixExpression(); + return; + } + default: + postfixExpression(); + return; + } + } + + public void postfixExpression() throws Exception { + switch (LT(1)) { + case Token.t_typename: + consume(); + // TO DO: this + break; + case Token.t_dynamic_cast: + case Token.t_static_cast: + case Token.t_reinterpret_cast: + case Token.t_const_cast: + consume(); + consume(Token.tLT); + typeId(); + consume(Token.tGT); + consume(Token.tLPAREN); + expression(); + consume(Token.tRPAREN); + break; + case Token.t_typeid: + consume(); + consume(Token.tLPAREN); + try { + typeId(); + } catch (Backtrack b) { + expression(); + } + consume(Token.tRPAREN); + break; + default: + // TO DO: try simpleTypeSpecifier "(" expressionList ")" + primaryExpression(); + } + + for (;;) { + switch (LT(1)) { + case Token.tLBRACKET: + // array access + consume(); + expression(); + consume(Token.tRBRACKET); + break; + case Token.tLPAREN: + // function call + consume(); + // Note: since expressionList and expression are the same... + expression(); + consume(Token.tRPAREN); + break; + case Token.tINCR: + case Token.tDECR: + // post incr/decr + consume(); + break; + case Token.tDOT: + case Token.tARROW: + // member access + consume(); + // TO DO: handle this + //varName(); + break; + default: + return; + } + } + } + + public void primaryExpression() throws Exception { + switch (LT(1)) { + // TO DO: we need more literals... + case Token.tINTEGER: + callback.expressionTerminal(consume()); + return; + case Token.tSTRING: + callback.expressionTerminal(consume()); + return; + case Token.t_this: + consume(); + return; + case Token.tLPAREN: + consume(); + expression(); + consume(Token.tRPAREN); + return; + default: + // TO DO: idExpression which yeilds a variable + //idExpression(); + return; + } + } + + public void varName() throws Exception { + if (LT(1) == Token.tCOLONCOLON) + consume(); + + for (;;) { + switch (LT(1)) { + case Token.tIDENTIFIER: + consume(); + //if (isTemplateArgs()) { + // rTemplateArgs(); + //} + + if (LT(1) == Token.tCOLONCOLON) { + switch (LT(2)) { + case Token.tIDENTIFIER: + case Token.tCOMPL: + case Token.t_operator: + consume(); + break; + default: + return; + } + } else + return; + break; + case Token.tCOMPL: + consume(); + consume(Token.tIDENTIFIER); + return; + case Token.t_operator: + consume(); + //rOperatorName(); + return; + default: + throw backtrack; + } + } + } + + // Backtracking + private static class Backtrack extends Exception { + } + + private static Backtrack backtrack = new Backtrack(); + + // Token management + private IScanner scanner; + private Token currToken; + + private Token fetchToken() { + try { + return scanner.nextToken(); + } catch (Exception e) { + return null; + } + } + + protected Token LA(int i) { + if (i < 1) + // can't go backwards + return null; + + if (currToken == null) + currToken = fetchToken(); + + Token retToken = currToken; + + for (; i > 1; --i) { + if (retToken.getNext() == null) + fetchToken(); + retToken = retToken.getNext(); + } + + return retToken; + } + + protected int LT(int i) { + return LA(i).type; + } + + protected Token consume() { + if (currToken.getNext() == null) + fetchToken(); + Token retToken = currToken; + currToken = currToken.getNext(); + return retToken; + } + + protected Token consume(int type) throws Exception { + if (LT(1) == type) + return consume(); + else + throw backtrack; + } + + protected Token mark() { + return currToken; + } + + protected void backup(Token mark) { + currToken = mark; + } + + // Utility routines that require a knowledge of the grammar + public static String generateName(Token startToken) throws Exception { + Token currToken = startToken.getNext(); + + if (currToken == null || currToken.getType() != Token.tCOLONCOLON) + return startToken.getImage(); + + StringBuffer buff = new StringBuffer(startToken.getImage()); + while (currToken != null && currToken.getType() == Token.tCOLONCOLON) { + currToken = currToken.getNext(); + if (currToken == null || currToken.getType() != Token.tIDENTIFIER) + // Not good + throw new ParserException(startToken); + buff.append("::"); + buff.append(currToken.getImage()); + currToken = currToken.getNext(); + } + + return buff.toString(); + } +} diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/ParserException.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/ParserException.java new file mode 100644 index 00000000000..90246f0a00d --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/ParserException.java @@ -0,0 +1,22 @@ +/******************************************************************************* + * Copyright (c) 2001 Rational Software Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * Rational Software - initial implementation + ******************************************************************************/ +package org.eclipse.cdt.internal.core.parser; + +public class ParserException extends Exception { + + public ParserException(Token t) { + } + + public ParserException( String msg ) + { + super( msg ); + } +} diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/ParserSymbolTable.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/ParserSymbolTable.java new file mode 100644 index 00000000000..3f4f5ab35f7 --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/ParserSymbolTable.java @@ -0,0 +1,55 @@ +package org.eclipse.cdt.internal.core.parser; + +import java.util.Stack; +/** + * @author aniefer + * + * To change this generated comment edit the template variable "typecomment": + * Window>Preferences>Java>Templates. + * To enable and disable the creation of type comments go to + * Window>Preferences>Java>Code Generation. + */ +public class ParserSymbolTable { + + /** + * Constructor for ParserSymbolTable. + */ + public ParserSymbolTable() { + super(); + _compilationUnit = new Declaration(); + push( _compilationUnit ); + } + + public void push( Declaration obj ){ + if( _contextStack.empty() == false ) + obj.setContainingScope( (Declaration) _contextStack.peek() ); + _contextStack.push( obj ); + } + + public Declaration pop(){ + return (Declaration) _contextStack.pop(); + } + + public Declaration peek(){ + return (Declaration) _contextStack.peek(); + } + + public Declaration Lookup( String name ) throws ParserSymbolTableException { + return ( (Declaration) _contextStack.peek() ).Lookup( -1, name ); + } + + public Declaration ElaboratedLookup( int type, String name ) throws ParserSymbolTableException{ + return ( (Declaration) _contextStack.peek() ).Lookup( type, name ); + } + + public void addDeclaration( Declaration obj ){ + ((Declaration) _contextStack.peek() ).addDeclaration( obj ); + } + + public Declaration getCompilationUnit(){ + return _compilationUnit; + } + + private Stack _contextStack = new Stack(); + private Declaration _compilationUnit; +} diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/ParserSymbolTableException.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/ParserSymbolTableException.java new file mode 100644 index 00000000000..b031325bced --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/ParserSymbolTableException.java @@ -0,0 +1,33 @@ +package org.eclipse.cdt.internal.core.parser; + +/** + * @author aniefer + * + * To change this generated comment edit the template variable "typecomment": + * Window>Preferences>Java>Templates. + * To enable and disable the creation of type comments go to + * Window>Preferences>Java>Code Generation. + */ +public class ParserSymbolTableException extends Exception { + + /** + * Constructor for ParserSymbolTableException. + */ + public ParserSymbolTableException() { + super(); + } + + /** + * Constructor for ParserSymbolTableException. + * @param int r: reason + */ + public ParserSymbolTableException( int r ) { + reason = r; + } + + public static final int r_Unspecified = -1; + public static final int r_AmbiguousName = 0; + public static final int r_BadTypeInfo = 1; + + public int reason = -1; +} \ No newline at end of file diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/Scanner.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/Scanner.java new file mode 100644 index 00000000000..ee57683c4ed --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/Scanner.java @@ -0,0 +1,1433 @@ +/******************************************************************************* + * Copyright (c) 2001 Rational Software Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * Rational Software - initial implementation + ******************************************************************************/ +package org.eclipse.cdt.internal.core.parser; + +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.IOException; +import java.io.Reader; +import java.io.StringReader; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.List; +import java.util.Stack; +import java.util.StringTokenizer; +import java.util.Vector; + +/** + * @author jcamelon + * + * To change this generated comment edit the template variable "typecomment": + * Window>Preferences>Java>Templates. + * To enable and disable the creation of type comments go to + * Window>Preferences>Java>Code Generation. + */ + +public class Scanner implements IScanner { + + public IScanner initialize(Reader reader, String filename) { + init(reader, filename); + return this; + } + + protected void init(Reader reader, String filename) { + // this is a hack to get around a sudden EOF experience + contextStack.push( + new ScannerContext().initialize( + new StringReader("\n"), + START, + NOCHAR)); + if (filename == null) + currentContext = + new ScannerContext().initialize(reader, TEXT, NOCHAR); + else + currentContext = + new ScannerContext().initialize(reader, filename, NOCHAR); + } + + public Scanner() { + } + + protected Scanner(Reader reader, String filename, Hashtable defns) { + initialize(reader, filename); + definitions = defns; + } + + protected void updateContext(Reader reader, String filename) { +// if (callback != null) +// callback.inclusionBegin(filename); // not quite right ... fix me!!! + + contextStack.push(currentContext); + currentContext = + new ScannerContext().initialize(reader, filename, NOCHAR); + } + + protected boolean rollbackContext() { + try { + currentContext.getReader().close(); + } catch (IOException ie) { + System.out.println("Error closing reader"); + } + + if (contextStack.isEmpty()) { + currentContext = null; + return false; + } + + //if (callback != null) + // callback.inclusionEnd(); + + currentContext = (ScannerContext) contextStack.pop(); + return true; + } + + public void addIncludePath(String includePath) { + includePaths.add(includePath); + } + + public void overwriteIncludePath(List newIncludePaths) { + includePaths = null; + includePaths = new ArrayList(); + includePaths.addAll(newIncludePaths); + } + + public void addDefinition(String key, IMacroDescriptor macro) { + definitions.put(key, macro); + } + + public void addDefinition(String key, String value) { + definitions.put(key, value); + } + + public final Object getDefinition(String key) { + return definitions.get(key); + } + + public final Object[] getIncludePaths() { + return includePaths.toArray(); + } + + protected void skipOverWhitespace() { + int c = getChar(); + while ((c != NOCHAR) && ((c == ' ') || (c == '\t'))) + c = getChar(); + if (c != NOCHAR) + ungetChar(c); + + } + + protected String getRestOfPreprocessorLine() throws ScannerException { + StringBuffer buffer = new StringBuffer(); + skipOverWhitespace(); + int c = getChar(); + + while (true) { + while ((c != '\n') + && (c != '\r') + && (c != '\\') + && (c != '/') + && (c != NOCHAR)) { + buffer.append((char) c); + c = getChar(); + } + if (c == '/') { + // we need to peek ahead at the next character to see if + // this is a comment or not + int next = getChar(); + if (next == '/') { + // single line comment + skipOverTextUntilNewline(); + break; + } else if (next == '*') { + // multiline comment + if (skipOverMultilineComment()) + break; + else + c = getChar(); + continue; + } else { + // we are not in a comment + buffer.append((char) c); + c = next; + continue; + } + } else { + if (c != '\\') { + ungetChar(c); + } else { + c = getChar(); + } + break; + } + } + + return buffer.toString(); + } + + protected void skipOverTextUntilNewline() { + for (;;) { + switch (getChar()) { + case NOCHAR : + case '\n' : + return; + case '\\' : + getChar(); + } + } + } + + private void setCurrentToken(Token t) { + if (currentToken != null) + currentToken.setNext(t); + currentToken = t; + } + + protected Token newToken(int t, String i, IScannerContext c) { + setCurrentToken(new Token(t, i, c)); + return currentToken; + } + + protected Token newToken(int t, String i) { + setCurrentToken(new Token(t, i)); + return currentToken; + } + + protected String getNextIdentifier() { + StringBuffer buffer = new StringBuffer(); + skipOverWhitespace(); + int c = getChar(); + + if (((c >= 'a') && (c <= 'z')) + || ((c >= 'A') && (c <= 'Z')) | (c == '_')) { + buffer.append((char) c); + + c = getChar(); + while (((c >= 'a') && (c <= 'z')) + || ((c >= 'A') && (c <= 'Z')) + || ((c >= '0') && (c <= '9')) + || (c == '_')) { + buffer.append((char) c); + c = getChar(); + } + } + ungetChar(c); + + return buffer.toString(); + } + + protected void handleInclusion(String fileName) throws ScannerException { + // Skip over inclusions in quickScan mode + if (quickScan) + return; + + // iterate through the include paths + Iterator iter = includePaths.iterator(); + + while (iter.hasNext()) { + String path = (String) iter.next(); + + java.io.File pathFile = new java.io.File(path); + if (pathFile.isDirectory()) { + String newPath = pathFile + "\\" + fileName; + + java.io.File includeFile = new java.io.File(newPath); + + if (includeFile.exists() && includeFile.isFile()) { + try { + FileReader inclusionReader = + new FileReader(includeFile); + //System.out.println( "Parsing inclusion file " + newPath ); + updateContext(inclusionReader, newPath); + return; + } catch (FileNotFoundException fnf) { + // do nothing + } + } + } + } + if (throwExceptionOnInclusionNotFound) + throw new ScannerException("Cannot find inclusion " + fileName); + } + + // constants + public static final int NOCHAR = -1; + + private static final String TEXT = ""; + private static final String START = ""; + private static final String EXPRESSION = ""; + private static final String BAD_PP = + "Invalid preprocessor directive encountered at offset "; + private static final String DEFINED = "defined"; + private static final String POUND_DEFINE = "#define "; + + private IScannerContext currentContext; + private Stack contextStack = new Stack(); + + private List includePaths = new ArrayList(); + private Hashtable definitions = new Hashtable(); + private int count = 0; + private static HashMap keywords = new HashMap(); + private static HashMap ppDirectives = new HashMap(); + + private Token currentToken = null; + + private boolean passOnToClient = true; + private BranchTracker branches = new BranchTracker(); + + // these are scanner configuration aspects that we perhaps want to tweak + // eventually, these should be configurable by the client, but for now + // we can just leave it internal + private boolean throwExceptionPPError = true; + private boolean throwExceptionOnRedefinition = false; + private boolean throwExceptionOnBadPPDirective = true; + private boolean throwExceptionOnInclusionNotFound = true; + private boolean throwExceptionOnBadMacroExpansion = true; + private boolean throwExceptionOnUnboundedString = true; + private boolean throwExceptionOnEOFWithinMultilineComment = true; + private boolean throwExceptionOnEOFWithoutBalancedEndifs = true; + private boolean providedDefinedMacro = true; + + private boolean quickScan = false; + public void setQuickScan(boolean qs) { + quickScan = qs; + } + + private IParserCallback callback; + public void setCallback(IParserCallback c) { + callback = c; + } + + private int getChar() { + int c = NOCHAR; + + boolean done; + do { + done = true; + + if (currentContext.getUndo() != NOCHAR) { + c = currentContext.getUndo(); + currentContext.setUndo(NOCHAR); + } else { + try { + c = currentContext.read(); + if (c == NOCHAR) { + if (rollbackContext() == false) { + c = NOCHAR; + break; + } else { + done = false; + } + } + } catch (IOException e) { + if (rollbackContext() == false) { + c = NOCHAR; + } else { + done = false; + } + } + } + } while (!done); + + if (c == '\\') { + c = getChar(); + if (c == '\r') { + c = getChar(); + if (c == '\n') + c = getChar(); + } else if (c == '\n') + c = getChar(); + } + + return c; + } + + private void ungetChar(int c) { + // Should really check whether there already is a char there + // If so, we should be using a buffer, instead of a single char + currentContext.setUndo(c); + } + + public Token nextToken() throws ScannerException { + + count++; + + int c = getChar(); + + while (c != NOCHAR) { + if ( ! passOnToClient ) { + while (c != '#') { + c = getChar(); + } + } + + if ((c == ' ') || (c == '\r') || (c == '\t') || (c == '\n')) { + c = getChar(); + continue; + } else if ( + ((c >= 'a') && (c <= 'z')) + || ((c >= 'A') && (c <= 'Z')) | (c == '_')) { + // String buffer is slow, we need a better way such as memory mapped files + StringBuffer buff = new StringBuffer(); + buff.append((char) c); + + c = getChar(); + while (((c >= 'a') && (c <= 'z')) + || ((c >= 'A') && (c <= 'Z')) + || ((c >= '0') && (c <= '9')) + || (c == '_')) { + buff.append((char) c); + c = getChar(); + } + + ungetChar(c); + + String ident = buff.toString(); + + if (providedDefinedMacro) { + if (ident.equals(DEFINED)) { + return newToken(Token.tINTEGER, handleDefinedMacro()); + } + } + + Object mapping = definitions.get(ident); + + if (mapping != null) { + expandDefinition(ident, mapping); + c = getChar(); + continue; + } + + Object tokenTypeObject = keywords.get(ident); + int tokenType = Token.tIDENTIFIER; + if (tokenTypeObject != null) + tokenType = ((Integer) tokenTypeObject).intValue(); + + return newToken(tokenType, ident, currentContext); + } else if (c == '"') { + // string + StringBuffer buff = new StringBuffer(); + c = getChar(); + + while (c != '"' && c != '\n') { + buff.append((char) c); + c = getChar(); + } + + if (c != '\n') { + return newToken( + Token.tSTRING, + buff.toString(), + currentContext); + } else { + if (throwExceptionOnUnboundedString) + throw new ScannerException( + "Unbounded string found at offset " + + currentContext.getOffset()); + } + + } else if ((c >= '0') && (c <= '9')) { + StringBuffer buff = new StringBuffer(); + buff.append((char) c); + + c = getChar(); + boolean hex = false; + if (c == 'x') { + hex = true; + c = getChar(); + } + + while ((c >= '0' && c <= '9') + || (hex + && ((c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')))) { + buff.append((char) c); + c = getChar(); + } + + ungetChar(c); + return newToken( + Token.tINTEGER, + buff.toString(), + currentContext); + } else if (c == '#') { + // lets prepare for a preprocessor statement + StringBuffer buff = new StringBuffer(); + buff.append((char) c); + + // we are allowed arbitrary whitespace after the '#' and before the rest of the text + skipOverWhitespace(); + + c = getChar(); + while (((c >= 'a') && (c <= 'z')) + || ((c >= 'A') && (c <= 'Z')) | (c == '_')) { + buff.append((char) c); + c = getChar(); + } + ungetChar(c); + + String token = buff.toString(); + + Object directive = ppDirectives.get(token); + if (directive == null) { + if (throwExceptionOnBadPPDirective) + throw new ScannerException( + BAD_PP + currentContext.getOffset()); + + } else { + int type = ((Integer) directive).intValue(); + switch (type) { + case PreprocessorDirectives.DEFINE : + if ( ! passOnToClient ) { + skipOverTextUntilNewline(); + c = getChar(); + continue; + } + + poundDefine(); + + c = getChar(); + continue; + + case PreprocessorDirectives.INCLUDE : + if (! passOnToClient ) { + skipOverTextUntilNewline(); + c = getChar(); + continue; + } + + poundInclude(); + + c = getChar(); + continue; + case PreprocessorDirectives.UNDEFINE : + if (! passOnToClient) { + skipOverTextUntilNewline(); + c = getChar(); + continue; + } + skipOverWhitespace(); + // definition + String toBeUndefined = getNextIdentifier(); + // TODO -- Should we throw an exception if we + // do not have this in our table? + definitions.remove(toBeUndefined); + skipOverTextUntilNewline(); + c = getChar(); + continue; + case PreprocessorDirectives.IF : + // get the rest of the line + String expression = getRestOfPreprocessorLine(); + + boolean expressionEvalResult = + evaluateExpression(expression); + + passOnToClient = branches.poundif( expressionEvalResult ); + c = getChar(); + continue; + + case PreprocessorDirectives.IFDEF : + skipOverWhitespace(); + String definition = getNextIdentifier(); + Object mapping = definitions.get(definition); + + if (mapping == null) { + // not defined + passOnToClient = branches.poundif( false ); + skipOverTextUntilNewline(); + } else { + passOnToClient = branches.poundif( true ); + // continue along, act like nothing is wrong :-) + c = getChar(); + } + continue; + case PreprocessorDirectives.ENDIF : + // TODO - make sure there is nothing after endif + + passOnToClient = branches.poundendif(); + c = getChar(); + continue; + + case PreprocessorDirectives.IFNDEF : + skipOverWhitespace(); + String def = getNextIdentifier(); + Object map = definitions.get(def); + + if (map != null) { + // not defined + skipOverTextUntilNewline(); + passOnToClient = branches.poundif( false ); + } else { + passOnToClient = branches.poundif( true ); + // continue along, act like nothing is wrong :-) + c = getChar(); + } + continue; + + case PreprocessorDirectives.ELSE : + passOnToClient = branches.poundelse(); + + skipOverTextUntilNewline(); + c = getChar(); + continue; + + case PreprocessorDirectives.ELIF : + + String elsifExpression = getRestOfPreprocessorLine(); + + if (elsifExpression.equals("")) + if (throwExceptionOnBadPPDirective) + throw new ScannerException("Malformed #elsif clause"); + + boolean elsifResult = + evaluateExpression(elsifExpression); + + passOnToClient = branches.poundelif( elsifResult ); + c = getChar(); + continue; + + case PreprocessorDirectives.LINE : + //TO DO + skipOverTextUntilNewline(); + c = getChar(); + continue; + case PreprocessorDirectives.ERROR : + if (! passOnToClient) { + skipOverTextUntilNewline(); + c = getChar(); + continue; + } + + String error = getRestOfPreprocessorLine(); + + if (throwExceptionPPError) { + throw new ScannerException("#error " + error); + } + c = getChar(); + continue; + case PreprocessorDirectives.PRAGMA : + //TO DO + skipOverTextUntilNewline(); + c = getChar(); + continue; + case PreprocessorDirectives.BLANK : + String remainderOfLine = + getRestOfPreprocessorLine().trim(); + if (!remainderOfLine.equals("")) { + if (throwExceptionOnBadPPDirective) + throw new ScannerException( + BAD_PP + currentContext.getOffset()); + } + + c = getChar(); + continue; + default : + if (throwExceptionOnBadPPDirective) + throw new ScannerException( + BAD_PP + currentContext.getOffset()); + + } + } + } else { + switch (c) { + case ':' : + c = getChar(); + switch (c) { + case ':' : + return newToken( + Token.tCOLONCOLON, + "::", + currentContext); + default : + ungetChar(c); + return newToken( + Token.tCOLON, + ":", + currentContext); + } + case ';' : + return newToken(Token.tSEMI, ";", currentContext); + case ',' : + return newToken(Token.tCOMMA, ",", currentContext); + case '?' : + return newToken(Token.tQUESTION, "?", currentContext); + case '(' : + return newToken(Token.tLPAREN, "(", currentContext); + case ')' : + return newToken(Token.tRPAREN, ")", currentContext); + case '[' : + return newToken(Token.tLBRACKET, "[", currentContext); + case ']' : + return newToken(Token.tRBRACKET, "]", currentContext); + case '{' : + return newToken(Token.tLBRACE, "{", currentContext); + case '}' : + return newToken(Token.tRBRACE, "}", currentContext); + case '+' : + c = getChar(); + switch (c) { + case '=' : + return newToken( + Token.tPLUSASSIGN, + "+=", + currentContext); + case '+' : + return newToken( + Token.tINCR, + "++", + currentContext); + default : + ungetChar(c); + return newToken( + Token.tPLUS, + "+", + currentContext); + } + case '-' : + c = getChar(); + switch (c) { + case '=' : + return newToken( + Token.tMINUSASSIGN, + "-=", + currentContext); + case '-' : + return newToken( + Token.tDECR, + "--", + currentContext); + case '>' : + c = getChar(); + switch (c) { + case '*' : + return newToken( + Token.tARROWSTAR, + "->*", + currentContext); + default : + ungetChar(c); + return newToken( + Token.tARROW, + "->", + currentContext); + } + default : + ungetChar(c); + return newToken( + Token.tMINUS, + "-", + currentContext); + } + case '*' : + c = getChar(); + switch (c) { + case '=' : + return newToken( + Token.tSTARASSIGN, + "*=", + currentContext); + default : + ungetChar(c); + return newToken( + Token.tSTAR, + "*", + currentContext); + } + case '%' : + c = getChar(); + switch (c) { + case '=' : + return newToken( + Token.tMODASSIGN, + "%=", + currentContext); + default : + ungetChar(c); + return newToken( + Token.tMOD, + "%", + currentContext); + } + case '^' : + c = getChar(); + switch (c) { + case '=' : + return newToken( + Token.tXORASSIGN, + "^=", + currentContext); + default : + ungetChar(c); + return newToken( + Token.tXOR, + "^", + currentContext); + } + case '&' : + c = getChar(); + switch (c) { + case '=' : + return newToken( + Token.tAMPERASSIGN, + "&=", + currentContext); + case '&' : + return newToken( + Token.tAND, + "&&", + currentContext); + default : + ungetChar(c); + return newToken( + Token.tAMPER, + "&", + currentContext); + } + case '|' : + c = getChar(); + switch (c) { + case '=' : + return newToken( + Token.tBITORASSIGN, + "|=", + currentContext); + case '|' : + return newToken( + Token.tOR, + "||", + currentContext); + default : + ungetChar(c); + return newToken( + Token.tBITOR, + "|", + currentContext); + } + case '~' : + return newToken(Token.tCOMPL, "~", currentContext); + case '!' : + c = getChar(); + switch (c) { + case '=' : + return newToken( + Token.tNOTEQUAL, + "!=", + currentContext); + default : + ungetChar(c); + return newToken( + Token.tNOT, + "!", + currentContext); + } + case '=' : + c = getChar(); + switch (c) { + case '=' : + return newToken( + Token.tEQUAL, + "==", + currentContext); + default : + ungetChar(c); + return newToken( + Token.tASSIGN, + "=", + currentContext); + } + case '<' : + c = getChar(); + switch (c) { + case '<' : + c = getChar(); + switch (c) { + case '=' : + return newToken( + Token.tSHIFTLASSIGN, + "<<=", + currentContext); + default : + ungetChar(c); + return newToken( + Token.tSHIFTL, + "<<", + currentContext); + } + case '=' : + return newToken( + Token.tLTEQUAL, + "<=", + currentContext); + default : + ungetChar(c); + return newToken(Token.tLT, "<", currentContext); + } + case '>' : + c = getChar(); + switch (c) { + case '>' : + c = getChar(); + switch (c) { + case '=' : + return newToken( + Token.tSHIFTRASSIGN, + ">>=", + currentContext); + default : + ungetChar(c); + return newToken( + Token.tSHIFTR, + ">>", + currentContext); + } + case '=' : + return newToken( + Token.tGTEQUAL, + ">=", + currentContext); + default : + ungetChar(c); + return newToken(Token.tGT, ">", currentContext); + } + case '.' : + c = getChar(); + switch (c) { + case '.' : + c = getChar(); + switch (c) { + case '.' : + return newToken( + Token.tELIPSE, + "...", + currentContext); + default : + break; + } + break; + case '*' : + return newToken( + Token.tDOTSTAR, + ".*", + currentContext); + default : + ungetChar(c); + return newToken( + Token.tDOT, + ".", + currentContext); + } + break; + case '/' : + c = getChar(); + switch (c) { + case '/' : + c = getChar(); + while (c != '\n' && c != NOCHAR) + c = getChar(); + continue; + case '*' : + skipOverMultilineComment(); + c = getChar(); + continue; + case '=' : + return newToken( + Token.tDIVASSIGN, + "/=", + currentContext); + default : + ungetChar(c); + return newToken( + Token.tDIV, + "/", + currentContext); + } + default : + break; + } + + return newToken( + Token.tEOF, + "Bad Char: " + (char) c, + currentContext); + } + } + + if (throwExceptionOnEOFWithoutBalancedEndifs && (getDepth() != 0)) + throw new ScannerException("End of file encountered without terminating #endif"); + + // we're done + if (currentToken != null) + currentToken.setNext(Token.EOF); + return Token.EOF; + } + + static { + keywords.put("and", new Integer(Token.t_and)); + keywords.put("and_eq", new Integer(Token.t_and_eq)); + keywords.put("asm", new Integer(Token.t_asm)); + keywords.put("auto", new Integer(Token.t_auto)); + keywords.put("bitand", new Integer(Token.t_bitand)); + keywords.put("bitor", new Integer(Token.t_bitor)); + keywords.put("bool", new Integer(Token.t_bool)); + keywords.put("break", new Integer(Token.t_break)); + keywords.put("case", new Integer(Token.t_case)); + keywords.put("catch", new Integer(Token.t_catch)); + keywords.put("char", new Integer(Token.t_char)); + keywords.put("class", new Integer(Token.t_class)); + keywords.put("compl", new Integer(Token.t_compl)); + keywords.put("const", new Integer(Token.t_const)); + keywords.put("const_cast", new Integer(Token.t_const_cast)); + keywords.put("continue", new Integer(Token.t_continue)); + keywords.put("default", new Integer(Token.t_default)); + keywords.put("delete", new Integer(Token.t_delete)); + keywords.put("do", new Integer(Token.t_do)); + keywords.put("double", new Integer(Token.t_double)); + keywords.put("dynamic_cast", new Integer(Token.t_dynamic_cast)); + keywords.put("else", new Integer(Token.t_else)); + keywords.put("enum", new Integer(Token.t_enum)); + keywords.put("explicit", new Integer(Token.t_explicit)); + keywords.put("export", new Integer(Token.t_export)); + keywords.put("extern", new Integer(Token.t_extern)); + keywords.put("false", new Integer(Token.t_false)); + keywords.put("float", new Integer(Token.t_float)); + keywords.put("for", new Integer(Token.t_for)); + keywords.put("friend", new Integer(Token.t_friend)); + keywords.put("goto", new Integer(Token.t_goto)); + keywords.put("if", new Integer(Token.t_if)); + keywords.put("inline", new Integer(Token.t_inline)); + keywords.put("int", new Integer(Token.t_int)); + keywords.put("long", new Integer(Token.t_long)); + keywords.put("mutable", new Integer(Token.t_mutable)); + keywords.put("namespace", new Integer(Token.t_namespace)); + keywords.put("new", new Integer(Token.t_new)); + keywords.put("not", new Integer(Token.t_not)); + keywords.put("not_eq", new Integer(Token.t_not_eq)); + keywords.put("operator", new Integer(Token.t_operator)); + keywords.put("or", new Integer(Token.t_or)); + keywords.put("or_eq", new Integer(Token.t_or_eq)); + keywords.put("private", new Integer(Token.t_private)); + keywords.put("protected", new Integer(Token.t_protected)); + keywords.put("public", new Integer(Token.t_public)); + keywords.put("register", new Integer(Token.t_register)); + keywords.put("reinterpret_cast", new Integer(Token.t_reinterpret_cast)); + keywords.put("return", new Integer(Token.t_return)); + keywords.put("short", new Integer(Token.t_short)); + keywords.put("signed", new Integer(Token.t_signed)); + keywords.put("sizeof", new Integer(Token.t_sizeof)); + keywords.put("static", new Integer(Token.t_static)); + keywords.put("static_cast", new Integer(Token.t_static_cast)); + keywords.put("struct", new Integer(Token.t_struct)); + keywords.put("switch", new Integer(Token.t_switch)); + keywords.put("template", new Integer(Token.t_template)); + keywords.put("this", new Integer(Token.t_this)); + keywords.put("throw", new Integer(Token.t_throw)); + keywords.put("true", new Integer(Token.t_true)); + keywords.put("try", new Integer(Token.t_try)); + keywords.put("typedef", new Integer(Token.t_typedef)); + keywords.put("typeid", new Integer(Token.t_typeid)); + keywords.put("typename", new Integer(Token.t_typename)); + keywords.put("union", new Integer(Token.t_union)); + keywords.put("unsigned", new Integer(Token.t_unsigned)); + keywords.put("using", new Integer(Token.t_using)); + keywords.put("virtual", new Integer(Token.t_virtual)); + keywords.put("void", new Integer(Token.t_void)); + keywords.put("volatile", new Integer(Token.t_volatile)); + keywords.put("wchar_t", new Integer(Token.t_wchar_t)); + keywords.put("while", new Integer(Token.t_while)); + keywords.put("xor", new Integer(Token.t_xor)); + keywords.put("xor_eq", new Integer(Token.t_xor_eq)); + + ppDirectives.put("#define", new Integer(PreprocessorDirectives.DEFINE)); + ppDirectives.put( + "#undef", + new Integer(PreprocessorDirectives.UNDEFINE)); + ppDirectives.put("#if", new Integer(PreprocessorDirectives.IF)); + ppDirectives.put("#ifdef", new Integer(PreprocessorDirectives.IFDEF)); + ppDirectives.put("#ifndef", new Integer(PreprocessorDirectives.IFNDEF)); + ppDirectives.put("#else", new Integer(PreprocessorDirectives.ELSE)); + ppDirectives.put("#endif", new Integer(PreprocessorDirectives.ENDIF)); + ppDirectives.put( + "#include", + new Integer(PreprocessorDirectives.INCLUDE)); + ppDirectives.put("#line", new Integer(PreprocessorDirectives.LINE)); + ppDirectives.put("#error", new Integer(PreprocessorDirectives.ERROR)); + ppDirectives.put("#pragma", new Integer(PreprocessorDirectives.PRAGMA)); + ppDirectives.put("#elif", new Integer(PreprocessorDirectives.ELIF)); + ppDirectives.put("#", new Integer(PreprocessorDirectives.BLANK)); + + } + + static public class PreprocessorDirectives { + static public final int DEFINE = 0; + static public final int UNDEFINE = 1; + static public final int IF = 2; + static public final int IFDEF = 3; + static public final int IFNDEF = 4; + static public final int ELSE = 5; + static public final int ENDIF = 6; + static public final int INCLUDE = 7; + static public final int LINE = 8; + static public final int ERROR = 9; + static public final int PRAGMA = 10; + static public final int BLANK = 11; + static public final int ELIF = 12; + } + + public final int getCount() { + return count; + } + + public final int getDepth() { + return branches.getDepth(); + } + + protected boolean evaluateExpression(String expression) + throws ScannerException { + Object expressionEvalResult = null; + try { + ExpressionEvaluator evaluator = new ExpressionEvaluator(); + Scanner trial = + new Scanner( + new StringReader(expression), + EXPRESSION, + definitions); + Parser parser = new Parser(trial, evaluator); + parser.expression(); + expressionEvalResult = evaluator.getResult(); + } catch (Exception e) { + System.out.println("Exception from Parser : " + e.toString()); + } + + if (expressionEvalResult == null) + throw new ScannerException( + "Expression " + + expression + + " evaluates to an undefined value"); + + if (expressionEvalResult.getClass() == java.lang.Integer.class) { + int i = ((Integer) expressionEvalResult).intValue(); + if (i == 0) { + return false; + } + return true; + } else if ( + expressionEvalResult.getClass() == java.lang.Boolean.class) { + return ((Boolean) expressionEvalResult).booleanValue(); + } else { + throw new ScannerException( + "Unexpected expression type - we do not expect " + + expressionEvalResult.getClass().getName()); + } + } + + protected boolean skipOverMultilineComment() throws ScannerException { + int state = 0; + boolean encounteredNewline = false; + // simple state machine to handle multi-line comments + // state 0 == no end of comment in site + // state 1 == encountered *, expecting / + // state 2 == we are no longer in a comment + + int c = getChar(); + while (state != 2 && c != NOCHAR) { + if (c == '\n') + encounteredNewline = true; + + switch (state) { + case 0 : + if (c == '*') + state = 1; + break; + case 1 : + if (c == '/') + state = 2; + else if (c != '*') + state = 0; + break; + } + c = getChar(); + } + + if (c == NOCHAR) { + if (throwExceptionOnEOFWithinMultilineComment) + throw new ScannerException("Encountered EOF while in multiline comment"); + } + + ungetChar(c); + + return encounteredNewline; + } + + protected void poundInclude() throws ScannerException { + skipOverWhitespace(); + int c = getChar(); + int offset; + + StringBuffer fileName = new StringBuffer(); + if (c == '<') { + c = getChar(); + while ((c != '>')) { + fileName.append((char) c); + c = getChar(); + } + } + else if (c == '"') { + c = getChar(); + while ((c != '"')) { + fileName.append((char) c); + c = getChar(); + } + + // TO DO: Make sure the directory of the current file is in the + // inclusion paths. + } + + String f = fileName.toString(); + + if( quickScan ) + { + if( callback != null ) + { + offset = currentContext.getOffset() - f.length() - 1; // -1 for the end quote + + callback.inclusionBegin( f, offset ); + callback.inclusionEnd(); + } + } + else + handleInclusion(f.trim()); + } + + protected void poundDefine() throws ScannerException { + skipOverWhitespace(); + // definition + String key = getNextIdentifier(); + int offset = currentContext.getOffset() - key.length(); + if( currentContext.getUndo() != Scanner.NOCHAR ) + offset -= 1; + + if (throwExceptionOnRedefinition) { + String checkForRedefinition = (String) definitions.get(key); + if (checkForRedefinition != null) { + throw new ScannerException( + "Preprocessor symbol " + + key + + " has already been defined to " + + checkForRedefinition + + " cannot redefined."); + } + } + + // get the next character + // the C++ standard says that macros must not put + // whitespace between the end of the definition + // identifier and the opening parenthesis + int c = getChar(); + if (c == '(') { + StringBuffer buffer = new StringBuffer(); + c = getChar(); + while (c != ')') { + buffer.append((char) c); + c = getChar(); + } + + String parameters = buffer.toString(); + + // replace StringTokenizer later -- not performant + StringTokenizer tokenizer = new StringTokenizer(parameters, ","); + ArrayList parameterIdentifiers = + new ArrayList(tokenizer.countTokens()); + while (tokenizer.hasMoreTokens()) { + parameterIdentifiers.add(tokenizer.nextToken().trim()); + } + + skipOverWhitespace(); + + ArrayList macroReplacementTokens = new ArrayList(); + String replacementString = getRestOfPreprocessorLine(); + Scanner helperScanner = new Scanner(); + helperScanner.initialize( + new StringReader(replacementString), + null); + Token t = helperScanner.nextToken(); + + while (t.type != Token.tEOF) { + macroReplacementTokens.add(t); + t = helperScanner.nextToken(); + } + + IMacroDescriptor descriptor = new MacroDescriptor(); + descriptor.initialize( + key, + parameterIdentifiers, + macroReplacementTokens, + key + "(" + parameters + ")"); + addDefinition(key, descriptor); + + } else if ((c == ' ') || (c == '\t') || (c == '\n') || (c == '\r')) { + // this is a simple definition + skipOverWhitespace(); + + // get what we are to map the name to and add it to the definitions list + String value = getRestOfPreprocessorLine(); + addDefinition(key, value); + } else if (c == '/') { + // this could be a comment + c = getChar(); + if (c == '/') // one line comment + { + skipOverTextUntilNewline(); + addDefinition(key, ""); + } else if (c == '*') // multi-line comment + { + if (skipOverMultilineComment()) { + // we have gone over a newline + // therefore, this symbol was defined to an empty string + addDefinition(key, ""); + } else { + String value = getRestOfPreprocessorLine(); + addDefinition(key, value); + } + } else { + // this is not a comment + // it is a bad statement + if (throwExceptionOnBadPPDirective) + throw new ScannerException( + BAD_PP + currentContext.getOffset()); + } + } else { + System.out.println("Unexpected character " + ((char) c)); + if (throwExceptionOnBadPPDirective) + throw new ScannerException(BAD_PP + currentContext.getOffset()); + } + + // call the callback accordingly + if( callback != null ) + callback.macro( key, offset ); + } + + protected void expandDefinition(String symbol, Object expansion) + throws ScannerException { + if (expansion.getClass() == String.class) { + String replacementValue = (String) expansion; + updateContext( + new StringReader(replacementValue), + POUND_DEFINE + symbol); + } else if (expansion.getClass() == MacroDescriptor.class) { + IMacroDescriptor macro = (IMacroDescriptor) expansion; + skipOverWhitespace(); + int c = getChar(); + + if (c == '(') { + StringBuffer buffer = new StringBuffer(); + int bracketCount = 1; + c = getChar(); + + while (true) { + if (c == '(') + ++bracketCount; + else if (c == ')') + --bracketCount; + + if (bracketCount == 0) + break; + buffer.append((char) c); + c = getChar(); + } + String betweenTheBrackets = buffer.toString(); + StringTokenizer tokenizer = + new StringTokenizer(betweenTheBrackets, ","); + Vector parameterValues = new Vector(tokenizer.countTokens()); + while (tokenizer.hasMoreTokens()) { + parameterValues.add(tokenizer.nextToken().trim()); + } + + // create a string that represents what needs to be tokenized + buffer = new StringBuffer(); + List tokens = macro.getTokenizedExpansion(); + List parameterNames = macro.getParameters(); + + if (parameterNames.size() != parameterValues.size()) { + if (throwExceptionOnBadMacroExpansion) + throw new ScannerException( + "Improper use of macro " + symbol); + } + + int numberOfTokens = tokens.size(); + + for (int i = 0; i < numberOfTokens; ++i) { + Token t = (Token) tokens.get(i); + if (t.type == Token.tIDENTIFIER) { + String identifierName = t.image; + + // is this identifier in the parameterNames + // list? + + int index = parameterNames.indexOf(t.image); + if (index == -1 ) { + // not found + // just add image to buffer + buffer.append(t.image); + } else { + buffer.append( + (String) parameterValues.elementAt(index)); + } + } else { + buffer.append(t.image); + } + } + updateContext( + new StringReader(buffer.toString()), + POUND_DEFINE + macro.getSignature()); + } else { + if (throwExceptionOnBadMacroExpansion) + throw new ScannerException( + "Improper use of macro " + symbol); + + } + + } else { + System.out.println( + "Unexpected class stored in definitions table. " + + expansion.getClass().getName()); + } + + } + + protected String handleDefinedMacro() throws ScannerException { + skipOverWhitespace(); + + int c = getChar(); + + if (c != '(') { + if (throwExceptionOnBadMacroExpansion) + throw new ScannerException("Improper use of macro defined()"); + } + + StringBuffer buffer = new StringBuffer(); + c = getChar(); + while ((c != NOCHAR) && (c != ')')) { + buffer.append((char) c); + c = getChar(); + } + if (c == NOCHAR) { + if (throwExceptionOnBadMacroExpansion) + throw new ScannerException("Improper use of macro defined()"); + } + + String definitionIdentifier = buffer.toString().trim(); + + if (definitions.get(definitionIdentifier) != null) + return "1"; + + return "0"; + } +} diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/ScannerContext.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/ScannerContext.java new file mode 100644 index 00000000000..e7df6008604 --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/ScannerContext.java @@ -0,0 +1,83 @@ +/******************************************************************************* + * Copyright (c) 2001 Rational Software Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * Rational Software - initial implementation + ******************************************************************************/ +package org.eclipse.cdt.internal.core.parser; + +import java.io.IOException; +import java.io.Reader; + +public class ScannerContext implements IScannerContext +{ + private Reader reader; + private String filename; + private int offset; + private int undo; + + public ScannerContext(){} + public IScannerContext initialize(Reader r, String f, int u ) + { + reader = r; + filename = f; + offset = 0; + undo = u; + return this; + } + + public int read() throws IOException { + ++offset; + return reader.read(); + } + + /** + * Returns the filename. + * @return String + */ + public final String getFilename() + { + return filename; + } + + /** + * Returns the offset. + * @return int + */ + public final int getOffset() + { + return offset; + } + + /** + * Returns the reader. + * @return Reader + */ + public final Reader getReader() + { + return reader; + } + + /** + * Returns the undo. + * @return int + */ + public final int getUndo() + { + return undo; + } + + /** + * Sets the undo. + * @param undo The undo to set + */ + public void setUndo(int undo) + { + this.undo= undo; + } + +} diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/ScannerException.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/ScannerException.java new file mode 100644 index 00000000000..8f299523ef7 --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/ScannerException.java @@ -0,0 +1,30 @@ +/******************************************************************************* + * Copyright (c) 2001 Rational Software Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * Rational Software - initial implementation + ******************************************************************************/ +package org.eclipse.cdt.internal.core.parser; + +public class ScannerException extends Exception { + + /** + * Constructor for ScannerException. + */ + public ScannerException() { + super(); + } + + /** + * Constructor for ScannerException. + * @param s + */ + public ScannerException(String s) { + super(s); + } + +} diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/Token.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/Token.java new file mode 100644 index 00000000000..5a7dd39da8c --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/Token.java @@ -0,0 +1,184 @@ +/******************************************************************************* + * Copyright (c) 2001 Rational Software Corp. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v0.5 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v05.html + * + * Contributors: + * Rational Software - initial implementation + ******************************************************************************/ +package org.eclipse.cdt.internal.core.parser; + +public class Token { + + public Token(int t, String i, IScannerContext context ) { + type = t; + image = i; + filename = context.getFilename(); + offset = context.getOffset() - image.length(); + + if( context.getUndo() != Scanner.NOCHAR ) + offset -= 1; + } + + public Token(int t, String i) { + type = t; + image = i; + } + + public static Token EOF = new Token(Token.tEOF, ""); + + public String toString() + { + return "Token type=" + type + " image =" + image + " offset=" + offset; + } + + public int type; + public int getType() { return type; } + + public String image; + public String getImage() { return image; } + + public String filename; + public int offset; + public int getOffset() { return offset; } + public int getLength() { return image.length(); } + + private Token next; + public Token getNext() { return next; } + public void setNext(Token t) { next = t; } + + // Token types + static public final int tEOF = 0; + static public final int tIDENTIFIER = 1; + static public final int tINTEGER = 2; + static public final int tCOLONCOLON = 3; + static public final int tCOLON = 4; + static public final int tSEMI = 5; + static public final int tCOMMA = 6; + static public final int tQUESTION = 7; + static public final int tLPAREN = 8; + static public final int tRPAREN = 9; + static public final int tLBRACKET = 10; + static public final int tRBRACKET = 11; + static public final int tLBRACE = 12; + static public final int tRBRACE = 13; + static public final int tPLUSASSIGN = 14; + static public final int tINCR = 15; + static public final int tPLUS = 16; + static public final int tMINUSASSIGN = 17; + static public final int tDECR = 18; + static public final int tARROWSTAR = 19; + static public final int tARROW = 20; + static public final int tMINUS = 21; + static public final int tSTARASSIGN = 22; + static public final int tSTAR = 23; + static public final int tMODASSIGN = 24; + static public final int tMOD = 25; + static public final int tXORASSIGN = 26; + static public final int tXOR = 27; + static public final int tAMPERASSIGN = 28; + static public final int tAND = 29; + static public final int tAMPER = 30; + static public final int tBITORASSIGN = 31; + static public final int tOR = 32; + static public final int tBITOR = 33; + static public final int tCOMPL = 34; + static public final int tNOTEQUAL = 35; + static public final int tNOT = 36; + static public final int tEQUAL = 37; + static public final int tASSIGN = 38; + static public final int tSHIFLASSIGN = 39; + static public final int tSHIFTL = 40; + static public final int tLTEQUAL = 41; + static public final int tLT = 42; + static public final int tSHIFTRASSIGN = 43; + static public final int tSHIFTR = 44; + static public final int tGTEQUAL = 45; + static public final int tGT = 46; + static public final int tSHIFTLASSIGN = 47; + static public final int tELIPSE = 48; + static public final int tDOTSTAR = 49; + static public final int tDOT = 50; + static public final int tDIVASSIGN = 51; + static public final int tDIV = 52; + static public final int tCLASSNAME = 53; + static public final int t_and = 54; + static public final int t_and_eq = 55; + static public final int t_asm = 56; + static public final int t_auto = 57; + static public final int t_bitand = 58; + static public final int t_bitor = 59; + static public final int t_bool = 60; + static public final int t_break = 61; + static public final int t_case = 62; + static public final int t_catch = 63; + static public final int t_char = 64; + static public final int t_class = 65; + static public final int t_compl = 66; + static public final int t_const = 67; + static public final int t_const_cast = 69; + static public final int t_continue = 70; + static public final int t_default = 71; + static public final int t_delete = 72; + static public final int t_do = 73; + static public final int t_double = 74; + static public final int t_dynamic_cast = 75; + static public final int t_else = 76; + static public final int t_enum = 77; + static public final int t_explicit = 78; + static public final int t_export = 79; + static public final int t_extern = 80; + static public final int t_false = 81; + static public final int t_float = 82; + static public final int t_for = 83; + static public final int t_friend = 84; + static public final int t_goto = 85; + static public final int t_if = 86; + static public final int t_inline = 87; + static public final int t_int = 88; + static public final int t_long = 89; + static public final int t_mutable = 90; + static public final int t_namespace = 91; + static public final int t_new = 92; + static public final int t_not = 93; + static public final int t_not_eq = 94; + static public final int t_operator = 95; + static public final int t_or = 96; + static public final int t_or_eq = 97; + static public final int t_private = 98; + static public final int t_protected = 99; + static public final int t_public = 100; + static public final int t_register = 101; + static public final int t_reinterpret_cast = 102; + static public final int t_return = 103; + static public final int t_short = 104; + static public final int t_sizeof = 105; + static public final int t_static = 106; + static public final int t_static_cast = 107; + static public final int t_signed = 108; + static public final int t_struct = 109; + static public final int t_switch = 110; + static public final int t_template = 111; + static public final int t_this = 112; + static public final int t_throw = 113; + static public final int t_true = 114; + static public final int t_try = 115; + static public final int t_typedef = 116; + static public final int t_typeid = 117; + static public final int t_typename = 118; + static public final int t_union = 119; + static public final int t_unsigned = 120; + static public final int t_using = 121; + static public final int t_virtual = 122; + static public final int t_void = 123; + static public final int t_volatile = 124; + static public final int t_wchar_t = 125; + static public final int t_while = 126; + static public final int t_xor = 127; + static public final int t_xor_eq = 128; + static public final int tSTRING = 129; + + static public final int tLAST = tSTRING; +} diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/util/DeclSpecifier.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/util/DeclSpecifier.java new file mode 100644 index 00000000000..6ed3b42b04d --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/util/DeclSpecifier.java @@ -0,0 +1,191 @@ +package org.eclipse.cdt.internal.core.parser.util; + +import org.eclipse.cdt.internal.core.parser.Token; + +/** + * @author jcamelon + * + * To change this generated comment edit the template variable "typecomment": + * Window>Preferences>Java>Templates. + * To enable and disable the creation of type comments go to + * Window>Preferences>Java>Code Generation. + */ +public class DeclSpecifier { + + // DeclSpecifier layed out as bit array + // leftmost 5 bits are type + public static final int typeMask = 0x001f; + public static final int isAuto = 0x0020; + public static final int isRegister = 0x0040; + public static final int isStatic = 0x0080; + public static final int isExtern = 0x0100; + public static final int isMutable = 0x0200; + public static final int isInline = 0x0400; + public static final int isVirtual = 0x0800; + public static final int isExplicit = 0x1000; + public static final int isTypedef = 0x2000; + public static final int isFriend = 0x4000; + public static final int isConst = 0x8000; + public static final int isVolatile = 0x10000; + public static final int isUnsigned = 0x20000; + public static final int isShort = 0x40000; + public static final int isLong = 0x80000; + + private int declSpecifierSeq = 0; + public int getDeclSpecifierSeq() { return declSpecifierSeq; } + + // Convenience methods + private void setBit(boolean b, int mask) { + if (b) + declSpecifierSeq = declSpecifierSeq | mask; + else + declSpecifierSeq = declSpecifierSeq & ~mask; + } + + private boolean checkBit(int mask) { + return (declSpecifierSeq & mask) == 1; + } + + public void setAuto(boolean b) { setBit(b, isAuto); } + public boolean isAuto() { return checkBit(isAuto); } + + public void setRegister(boolean b) { setBit(b, isRegister); } + public boolean isRegister() { return checkBit(isRegister); } + + public void setStatic(boolean b) { setBit(b, isStatic); } + public boolean isStatic() { return checkBit(isStatic); } + + public void setExtern(boolean b) { setBit(b, isExtern); } + public boolean isExtern() { return checkBit(isExtern); } + + public void setMutable(boolean b) { setBit(b, isMutable); } + public boolean isMutable() { return checkBit(isMutable); } + + public void setInline(boolean b) { setBit(b, isInline); } + public boolean isInline() { return checkBit(isInline); } + + public void setVirtual(boolean b) { setBit(b, isVirtual); } + public boolean isVirtual() { return checkBit(isVirtual); } + + public void setExplicit(boolean b) { setBit(b, isExplicit); } + public boolean isExplicit() { return checkBit(isExplicit); } + + public void setTypedef(boolean b) { setBit(b, isTypedef); } + public boolean isTypedef() { return checkBit(isTypedef); } + + public void setFriend(boolean b) { setBit(b, isFriend); } + public boolean isFriend() { return checkBit(isFriend); } + + public void setConst(boolean b) { setBit(b, isConst); } + public boolean isConst() { return checkBit(isConst); } + + public void setVolatile(boolean b) { setBit(b, isVolatile); } + public boolean isVolatile() { return checkBit(isVolatile); } + + public void setUnsigned(boolean b) { setBit(b, isUnsigned); } + public boolean isUnsigned() { return checkBit(isUnsigned); } + + public void setShort(boolean b) { setBit(b, isShort); } + public boolean isShort() { return checkBit(isShort); } + + public void setLong(boolean b) { setBit(b, isLong); } + public boolean isLong() { return checkBit(isLong); } + + // Simple Types + public static final int t_type = 0; // Type Specifier + public static final int t_char = 1; + public static final int t_wchar_t = 2; + public static final int t_bool = 3; + public static final int t_int = 4; + public static final int t_float = 5; + public static final int t_double = 6; + public static final int t_void = 7; + + public void setType( Token token ) + { + switch (token.getType()) { + case Token.t_auto: + setAuto(true); + break; + case Token.t_register: + setRegister(true); + break; + case Token.t_static: + setStatic(true); + break; + case Token.t_extern: + setExtern(true); + break; + case Token.t_mutable: + setMutable(true); + break; + case Token.t_inline: + setInline(true); + break; + case Token.t_virtual: + setVirtual(true); + break; + case Token.t_explicit: + setExplicit(true); + break; + case Token.t_typedef: + setTypedef(true); + break; + case Token.t_friend: + setFriend(true); + break; + case Token.t_const: + setConst(true); + break; + case Token.t_volatile: + setVolatile(true); + break; + case Token.t_char: + setType(DeclarationSpecifier.t_char); + break; + case Token.t_wchar_t: + setType(DeclarationSpecifier.t_wchar_t); + break; + case Token.t_bool: + setType(DeclarationSpecifier.t_bool); + break; + case Token.t_short: + setShort(true); + break; + case Token.t_int: + setType(DeclarationSpecifier.t_int); + break; + case Token.t_long: + setLong(true); + break; + case Token.t_signed: + setUnsigned(false); + break; + case Token.t_unsigned: + setUnsigned(true); + break; + case Token.t_float: + setType(DeclarationSpecifier.t_float); + break; + case Token.t_double: + setType(DeclarationSpecifier.t_double); + break; + case Token.t_void: + setType(DeclarationSpecifier.t_void); + break; + case Token.tIDENTIFIER: + setType(DeclarationSpecifier.t_type); + break; + } + + } + + public void setType(int t) { + declSpecifierSeq = declSpecifierSeq & ~typeMask | t; + } + + public int getType() { + return declSpecifierSeq & typeMask; + } + +} diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/util/DeclarationSpecifier.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/util/DeclarationSpecifier.java new file mode 100644 index 00000000000..9413877ab9a --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/util/DeclarationSpecifier.java @@ -0,0 +1,26 @@ +package org.eclipse.cdt.internal.core.parser.util; + +import java.util.List; + +/** + * @author jcamelon + * + * To change this generated comment edit the template variable "typecomment": + * Window>Preferences>Java>Templates. + * To enable and disable the creation of type comments go to + * Window>Preferences>Java>Code Generation. + */ +public class DeclarationSpecifier extends DeclSpecifier { + + public interface Container { + + public DeclarationSpecifier getDeclSpecifier(); + + public void setDeclSpecifier( DeclarationSpecifier in ); + + public void addDeclarator(Object declarator); + public void removeDeclarator( Object declarator ); + public List getDeclarators(); + + }; +} diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/util/Name.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/util/Name.java new file mode 100644 index 00000000000..deb94337417 --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/parser/util/Name.java @@ -0,0 +1,46 @@ +package org.eclipse.cdt.internal.core.parser.util; + +import org.eclipse.cdt.internal.core.parser.Token; + + +/** + * @author dschaefe + * + * To change this generated comment edit the template variable "typecomment": + * Window>Preferences>Java>Templates. + * To enable and disable the creation of type comments go to + * Window>Preferences>Java>Code Generation. + */ +public class Name { + + private Token nameStart, nameEnd; + + public Name(Token nameStart) { + this.nameStart = nameStart; + } + + public void setEnd(Token nameEnd) { + this.nameEnd = nameEnd; + } + + public int getStartOffset() + { + return nameStart.offset; + } + + public int getEndOffset() + { + return nameEnd.offset; + } + + public String toString() { + String name = nameStart.getImage(); + + for (Token t = nameStart; nameStart != nameEnd;) { + t = nameStart.getNext(); + name += t.getImage(); + } + + return name; + } +} diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/CCorePlugin.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/CCorePlugin.java index a07e80c0ff5..f1276b4fdee 100644 --- a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/CCorePlugin.java +++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/CCorePlugin.java @@ -443,4 +443,17 @@ public class CCorePlugin extends Plugin { } return null; } -} + + // Preference to turn on/off the new parser + + private boolean useNewParser = false; + + public void setUseNewParser(boolean useNewParser) { + this.useNewParser = useNewParser; + } + + public boolean useNewParser() { + return useNewParser; + } + +} \ No newline at end of file diff --git a/core/org.eclipse.cdt.ui.tests/.classpath b/core/org.eclipse.cdt.ui.tests/.classpath index a067b89762f..a7f81b4612e 100644 --- a/core/org.eclipse.cdt.ui.tests/.classpath +++ b/core/org.eclipse.cdt.ui.tests/.classpath @@ -4,6 +4,7 @@ + diff --git a/core/org.eclipse.cdt.ui.tests/parser/org/eclipse/cdt/core/parser/tests/BranchTrackerTest.java b/core/org.eclipse.cdt.ui.tests/parser/org/eclipse/cdt/core/parser/tests/BranchTrackerTest.java new file mode 100644 index 00000000000..96250bb0401 --- /dev/null +++ b/core/org.eclipse.cdt.ui.tests/parser/org/eclipse/cdt/core/parser/tests/BranchTrackerTest.java @@ -0,0 +1,200 @@ +package org.eclipse.cdt.core.parser.tests; + +import junit.framework.TestCase; + +import org.eclipse.cdt.internal.core.parser.BranchTracker; +import org.eclipse.cdt.internal.core.parser.ScannerException; + +/** + * @author jcamelon + * + * To change this generated comment edit the template variable "typecomment": + * Window>Preferences>Java>Templates. + * To enable and disable the creation of type comments go to + * Window>Preferences>Java>Code Generation. + */ +public class BranchTrackerTest extends TestCase { + + public BranchTrackerTest( String ignoreMe ) + { + super( ignoreMe ); + } + + public static void assertFalse( boolean input ) + { + assertTrue( input == false ); + } + + public void testIgnore() + { + + BranchTracker bt = new BranchTracker(); + try + { + /* + * #if 0 + * # if 1 + * # elif 1 + * # else + * # endif + * #else + * #endif + */ + + assertFalse( bt.poundif( false ) ); + assertFalse( bt.poundif( true ) ); + assertFalse( bt.poundelif( true ) ); + assertFalse( bt.poundelse() ); + assertFalse( bt.poundendif() ); + assertTrue( bt.poundelse() ); + assertTrue( bt.poundendif() ); + + /* + * #if 0 + * # if 1 + * # elif 1 + * # else + * # endif + * #else + * # if 0 + * # elif 1 + * # elif 0 + * # elif 1 + * # else + * # endif + * #endif + */ + + bt = new BranchTracker(); + assertFalse( bt.poundif( false ) ); + assertFalse( bt.poundif( true )); + assertFalse( bt.poundelif( true ) ); + assertFalse( bt.poundelse() ); + assertFalse( bt.poundendif() ); + assertTrue( bt.poundelse() ); + assertFalse( bt.poundif( false ) ); + assertTrue( bt.poundelif( true ) ); + assertFalse( bt.poundelif( false ) ); + assertFalse( bt.poundelif( true ) ); + assertFalse( bt.poundelse() ); + assertTrue( bt.poundendif() ); + assertTrue( bt.poundendif() ); + assertEquals( 0, bt.getDepth() ); + + /* + * #if 0 + * # if 1 + * # elif 0 + * # elif 1 + * # else + * # endif + * #elif 0 + * # if 0 + * # elif 0 + * # elif 1 + * # else + * # endif + * #elif 1 + * # if 0 + * # elif 0 + * # elif 0 + * # else + * # endif + * #else + * # if 1 + * # elif 0 + * # elif 1 + * # else + * # endif + * #endif + */ + + assertFalse(bt.poundif(false)); + assertFalse(bt.poundif(true)); + assertFalse(bt.poundelif(false)); + assertFalse(bt.poundelif(true)); + assertFalse(bt.poundelse()); + assertFalse( bt.poundendif() ); + assertFalse(bt.poundelif(false)); + assertFalse(bt.poundif(false)); + assertFalse(bt.poundelif(false)); + assertFalse(bt.poundelif(true)); + assertFalse(bt.poundelse()); + assertFalse( bt.poundendif()); + assertTrue(bt.poundelif(true)); + assertFalse(bt.poundif(false)); + assertFalse(bt.poundelif(false)); + assertFalse(bt.poundelif(false)); + assertTrue(bt.poundelse()); + assertTrue( bt.poundendif() ); + assertFalse(bt.poundelse()); + assertFalse(bt.poundif(true)); + assertFalse(bt.poundelif(false)); + assertFalse(bt.poundelif(true)); + assertFalse(bt.poundelse()); + assertFalse( bt.poundendif() ); + assertTrue( bt.poundendif() ); + assertEquals(0, bt.getDepth()); + } catch (ScannerException se) { + fail("Unexpected Scanner exception thrown"); + } + } + + public void testSimpleBranches() + { + try + { + /* + * code sequence is + * #if 1 + * #else + * #endif + */ + BranchTracker bt = new BranchTracker(); + assertTrue( bt.poundif( true ) ); + assertFalse( bt.poundelse() ); + assertTrue( bt.poundendif() ); + + /* + * code sequence is + * #if 1 + * # if 0 + * # elif 0 + * # else + * # endif + * #else + * #endif + */ + bt = new BranchTracker(); + assertTrue( bt.poundif( true )); + assertFalse( bt.poundif( false )); + assertFalse( bt.poundelif( false )); + assertTrue( bt.poundelse()); + assertTrue( bt.poundendif() ); + assertFalse( bt.poundelse() ); + assertTrue( bt.poundendif() ); + + /* + * #if 1 + * #elsif 1 + * #elsif 0 + * #else + * #endif + */ + + bt = new BranchTracker(); + assertTrue( bt.poundif( true ) ); + assertFalse( bt.poundelif( true )); + assertFalse( bt.poundelif( false )); + assertFalse( bt.poundelse()); + assertTrue( bt.poundendif() ); + + + } + catch( ScannerException se ) + { + fail( "Exception" ); + } + } + +} diff --git a/core/org.eclipse.cdt.ui.tests/parser/org/eclipse/cdt/core/parser/tests/DOMTests.java b/core/org.eclipse.cdt.ui.tests/parser/org/eclipse/cdt/core/parser/tests/DOMTests.java new file mode 100644 index 00000000000..d7356efebc8 --- /dev/null +++ b/core/org.eclipse.cdt.ui.tests/parser/org/eclipse/cdt/core/parser/tests/DOMTests.java @@ -0,0 +1,309 @@ +package org.eclipse.cdt.core.parser.tests; + +import java.io.IOException; +import java.io.StringWriter; +import java.io.Writer; +import java.util.List; + +import junit.framework.TestCase; + +import org.eclipse.cdt.internal.core.dom.BaseSpecifier; +import org.eclipse.cdt.internal.core.dom.ClassSpecifier; +import org.eclipse.cdt.internal.core.dom.DOMBuilder; +import org.eclipse.cdt.internal.core.dom.Declarator; +import org.eclipse.cdt.internal.core.dom.ParameterDeclaration; +import org.eclipse.cdt.internal.core.dom.ParameterDeclarationClause; +import org.eclipse.cdt.internal.core.dom.SimpleDeclaration; +import org.eclipse.cdt.internal.core.dom.TranslationUnit; +import org.eclipse.cdt.internal.core.parser.Parser; +import org.eclipse.cdt.internal.core.parser.ParserException; +import org.eclipse.cdt.internal.core.parser.util.DeclarationSpecifier; +import org.eclipse.cdt.internal.core.parser.util.Name; + +/** + * Tests the construction of DOMs for snippets of code + */ +public class DOMTests extends TestCase { + + public TranslationUnit parse(String code) throws Exception { + DOMBuilder domBuilder = new DOMBuilder(); + Parser parser = new Parser(code, domBuilder); + if( ! parser.parse() ) throw new ParserException( "Parse failure" ); + + return domBuilder.getTranslationUnit(); + } + + /** + * Test code: int x; + * Purpose: to test the simple decaration in it's simplest form. + */ + public void testIntGlobal() throws Exception { + // Parse and get the translation Unit + TranslationUnit translationUnit = parse("int x;"); + + // Get the simple declaration + List declarations = translationUnit.getDeclarations(); + assertEquals(1, declarations.size()); + SimpleDeclaration declaration = (SimpleDeclaration)declarations.get(0); + + // Make sure it is only an int + assertEquals(DeclarationSpecifier.t_int, declaration.getDeclSpecifier().getDeclSpecifierSeq()); + + // Get the declarator and check its name + List declarators = declaration.getDeclarators(); + assertEquals(1, declarators.size()); + Declarator declarator = (Declarator)declarators.get(0); + Name name = declarator.getName(); + assertEquals("x", name.toString()); + } + + /** + * Test code: class A { } a; + * Purpose: tests the use of a classSpecifier in + */ + public void testEmptyClass() throws Exception { + // Parse and get the translation unit + Writer code = new StringWriter(); + code.write("class A { } a;"); + TranslationUnit translationUnit = parse(code.toString()); + + // Get the simple declaration + List declarations = translationUnit.getDeclarations(); + assertEquals(1, declarations.size()); + SimpleDeclaration declaration = (SimpleDeclaration)declarations.get(0); + + // Make sure it is a type specifier + assertEquals(0, declaration.getDeclSpecifier().getDeclSpecifierSeq()); + + // Get the class specifier and check its name + ClassSpecifier classSpecifier = (ClassSpecifier)declaration.getTypeSpecifier(); + Name className = classSpecifier.getName(); + assertEquals("A", className.toString()); + + // Get the declarator and check it's name + List declarators = declaration.getDeclarators(); + assertEquals(1, declarators.size()); + Declarator declarator = (Declarator)declarators.get(0); + Name name = declarator.getName(); + assertEquals("a", name.toString()); + } + + /** + * Test code: class A { public: int x; }; + * Purpose: tests a declaration in a class scope. + */ + public void testSimpleClassMember() throws Exception { + // Parse and get the translaton unit + Writer code = new StringWriter(); + code.write("class A { public: int x; };"); + TranslationUnit translationUnit = parse(code.toString()); + + // Get the declaration + List declarations = translationUnit.getDeclarations(); + assertEquals(1, declarations.size()); + SimpleDeclaration declaration = (SimpleDeclaration)declarations.get(0); + + // Make sure there is no declarator + assertEquals(0, declaration.getDeclarators().size()); + + // Make sure it's a type specifier + assertEquals(0, declaration.getDeclSpecifier().getDeclSpecifierSeq()); + + // Get the class specifier and check its name + ClassSpecifier classSpecifier = (ClassSpecifier)declaration.getTypeSpecifier(); + Name className = classSpecifier.getName(); + assertEquals("A", className.toString()); + + // Get the member declaration + declarations = classSpecifier.getDeclarations(); + assertEquals(1, declarations.size()); + declaration = (SimpleDeclaration)declarations.get(0); + + // Make sure it's an int + assertEquals(DeclarationSpecifier.t_int, declaration.getDeclSpecifier().getDeclSpecifierSeq()); + + // Get the declarator and check it's name + List declarators = declaration.getDeclarators(); + assertEquals(1, declarators.size()); + Declarator declarator = (Declarator)declarators.get(0); + Name name = declarator.getName(); + assertEquals("x", name.toString()); + } + /** + * Test code: class A : public B, private C, virtual protected D { public: int x, y; float a,b,c; } + * Purpose: tests a declaration in a class scope. + */ + public void testSimpleClassMembers() throws Exception { + // Parse and get the translaton unit + Writer code = new StringWriter(); + code.write("class A : public B, private C, virtual protected D { public: int x, y; float a,b,c; };"); + TranslationUnit translationUnit = parse(code.toString()); + + // Get the declaration + List declarations = translationUnit.getDeclarations(); + assertEquals(1, declarations.size()); + SimpleDeclaration declaration = (SimpleDeclaration)declarations.get(0); + + // Make sure there is no declarator + assertEquals(0, declaration.getDeclarators().size()); + + // Make sure it's a type specifier + assertEquals(0, declaration.getDeclSpecifier().getDeclSpecifierSeq()); + + // Get the class specifier and check its name + ClassSpecifier classSpecifier = (ClassSpecifier)declaration.getTypeSpecifier(); + Name className = classSpecifier.getName(); + assertEquals("A", className.toString()); + + List baseClasses = classSpecifier.getBaseSpecifiers(); + assertEquals( 3, baseClasses.size() ); + BaseSpecifier bs = (BaseSpecifier)baseClasses.get( 0 ); + assertEquals( bs.getAccess(), BaseSpecifier.t_public ); + assertEquals( bs.isVirtual(), false ); + assertEquals( bs.getName(), "B" ); + + bs = (BaseSpecifier)baseClasses.get( 1 ); + assertEquals( bs.getAccess(), BaseSpecifier.t_private ); + assertEquals( bs.isVirtual(), false ); + assertEquals( bs.getName(), "C" ); + + bs = (BaseSpecifier)baseClasses.get( 2 ); + assertEquals( bs.getAccess(), BaseSpecifier.t_protected ); + assertEquals( bs.isVirtual(), true ); + assertEquals( bs.getName(), "D" ); + + + // Get the member declaration + declarations = classSpecifier.getDeclarations(); + assertEquals(2, declarations.size()); + declaration = (SimpleDeclaration)declarations.get(0); + + // Make sure it's an int + assertEquals(DeclarationSpecifier.t_int, declaration.getDeclSpecifier().getDeclSpecifierSeq()); + + // Get the declarator and check it's name + List declarators = declaration.getDeclarators(); + assertEquals(2, declarators.size()); + Declarator declarator = (Declarator)declarators.get(0); + Name name = declarator.getName(); + assertEquals("x", name.toString()); + declarator = (Declarator)declarators.get(1); + name = declarator.getName(); + assertEquals("y", name.toString()); + + declaration = (SimpleDeclaration)declarations.get(1); + // Make sure it's an float + assertEquals(DeclarationSpecifier.t_float, declaration.getDeclSpecifier().getDeclSpecifierSeq()); + declarators = declaration.getDeclarators(); + assertEquals( 3, declarators.size() ); + name = ((Declarator)declarators.get(0)).getName(); + assertEquals( "a", name.toString() ); + name = ((Declarator)declarators.get(1)).getName(); + assertEquals( "b", name.toString() ); + name = ((Declarator)declarators.get(2)).getName(); + assertEquals( "c", name.toString() ); + + } + + + /** + * Test code: int myFunction( void ); + */ + public void testSimpleFunctionDeclaration() throws Exception + { + // Parse and get the translaton unit + Writer code = new StringWriter(); + code.write("void myFunction( void );"); + TranslationUnit translationUnit = parse(code.toString()); + + // Get the declaration + List declarations = translationUnit.getDeclarations(); + assertEquals(1, declarations.size()); + SimpleDeclaration simpleDeclaration = (SimpleDeclaration)declarations.get(0); + assertEquals( simpleDeclaration.getDeclSpecifier().getType(), DeclarationSpecifier.t_void ); + List declarators = simpleDeclaration.getDeclarators(); + assertEquals( 1, declarators.size() ); + Declarator functionDeclarator = (Declarator)declarators.get( 0 ); + assertEquals( functionDeclarator.getName().toString(), "myFunction" ); + ParameterDeclarationClause pdc = functionDeclarator.getParms(); + assertNotNull( pdc ); + List parameterDecls = pdc.getDeclarations(); + assertEquals( 1, parameterDecls.size() ); + ParameterDeclaration parm1 = (ParameterDeclaration)parameterDecls.get( 0 ); + assertEquals( DeclarationSpecifier.t_void, parm1.getDeclSpecifier().getType() ); + List parm1Decls = parm1.getDeclarators(); + assertEquals( 1, parm1Decls.size() ); + Declarator parm1Declarator = (Declarator) parm1Decls.get(0); + assertNull( parm1Declarator.getName() ); + } + + /** + * Test code: "class A { int floor( double input ), someInt; };" + */ + public void testMultipleDeclarators() throws Exception + { + // Parse and get the translaton unit + Writer code = new StringWriter(); + code.write("class A { int floor( double input ), someInt; };"); + TranslationUnit translationUnit = parse(code.toString()); + + List tudeclarations = translationUnit.getDeclarations(); + assertEquals( 1, tudeclarations.size() ); + SimpleDeclaration classDecl = (SimpleDeclaration)tudeclarations.get(0); + assertEquals( 0, classDecl.getDeclarators().size() ); + ClassSpecifier classSpec = (ClassSpecifier)classDecl.getTypeSpecifier(); + + List classDeclarations = classSpec.getDeclarations(); + assertEquals( classDeclarations.size(), 1 ); + SimpleDeclaration simpleDeclaration = (SimpleDeclaration)classDeclarations.get(0); + assertEquals( simpleDeclaration.getDeclSpecifier().getType(), DeclarationSpecifier.t_int ); + List simpleDeclarators = simpleDeclaration.getDeclarators(); + assertEquals( simpleDeclarators.size(), 2 ); + Declarator methodDeclarator = (Declarator)simpleDeclarators.get(0); + assertEquals( methodDeclarator.getName().toString(), "floor" ); + ParameterDeclarationClause pdc = methodDeclarator.getParms(); + assertNotNull( pdc ); + List parameterDeclarations = pdc.getDeclarations(); + assertEquals( 1, parameterDeclarations.size() ); + ParameterDeclaration parm1Declaration = (ParameterDeclaration)parameterDeclarations.get(0); + assertEquals( DeclarationSpecifier.t_double, parm1Declaration.getDeclSpecifier().getType() ); + List parm1Declarators = parm1Declaration.getDeclarators(); + assertEquals( parm1Declarators.size(), 1 ); + Declarator parm1Declarator = (Declarator)parm1Declarators.get(0); + assertEquals( parm1Declarator.getName().toString(), "input" ); + Declarator integerDeclarator = (Declarator)simpleDeclarators.get(1); + assertEquals( integerDeclarator.getName().toString(), "someInt" ); + assertNull( integerDeclarator.getParms() ); + } + +// public void testErrors() +// { +// validateWeEncounterAnError( "void myFunc( int hey, flo );"); +// } + + public void validateWeEncounterAnError( String codeText ) + { + try + { + // Parse and get the translaton unit + Writer code = new StringWriter(); + code.write(codeText); + try + { + TranslationUnit translationUnit = parse(code.toString()); + fail( "We should not reach this line. Failure."); + } catch( ParserException pe ) + { + } + catch( Exception e ) + { + fail( "Unknown exception " + e.getMessage() ); + } + }catch( IOException io ) + { + fail( "IOException thrown"); + } + + } +} + diff --git a/core/org.eclipse.cdt.ui.tests/parser/org/eclipse/cdt/core/parser/tests/ExprEvalTest.java b/core/org.eclipse.cdt.ui.tests/parser/org/eclipse/cdt/core/parser/tests/ExprEvalTest.java new file mode 100644 index 00000000000..fd330147e7e --- /dev/null +++ b/core/org.eclipse.cdt.ui.tests/parser/org/eclipse/cdt/core/parser/tests/ExprEvalTest.java @@ -0,0 +1,41 @@ +package org.eclipse.cdt.core.parser.tests; + +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestSuite; + +import org.eclipse.cdt.internal.core.parser.ExpressionEvaluator; +import org.eclipse.cdt.internal.core.parser.Parser; + +public class ExprEvalTest extends TestCase { + + public static Test suite() { + return new TestSuite(ExprEvalTest.class); + } + + public ExprEvalTest(String name) { + super(name); + } + + public void runTest(String code, int expectedValue) throws Exception { + ExpressionEvaluator evaluator = new ExpressionEvaluator(); + Parser parser = new Parser(code, evaluator); + parser.expression(); + assertEquals(expectedValue, ((Integer)evaluator.getResult()).intValue()); + } + + public void testInteger() throws Exception { + runTest("5", 5); + } + + public void testRelational() throws Exception { + runTest("1 < 2", 1); + runTest("2 < 1", 0); + runTest("2 == 1 + 1", 1); + runTest("2 != 1 + 1", 0); + } + + public void testBracketed() throws Exception { + runTest("2 * (3 + 4)", 14); + } +} diff --git a/core/org.eclipse.cdt.ui.tests/parser/org/eclipse/cdt/core/parser/tests/ParserSymbolTableTest.java b/core/org.eclipse.cdt.ui.tests/parser/org/eclipse/cdt/core/parser/tests/ParserSymbolTableTest.java new file mode 100644 index 00000000000..a2cb060dfef --- /dev/null +++ b/core/org.eclipse.cdt.ui.tests/parser/org/eclipse/cdt/core/parser/tests/ParserSymbolTableTest.java @@ -0,0 +1,500 @@ +package org.eclipse.cdt.core.parser.tests; + +import junit.framework.TestCase; + +import java.util.Iterator; +import java.util.Map; +import org.eclipse.cdt.internal.core.parser.Declaration; +import org.eclipse.cdt.internal.core.parser.ParserSymbolTable; +import org.eclipse.cdt.internal.core.parser.ParserSymbolTableException; + +/** + * @author aniefer + * + * To change this generated comment edit the template variable "typecomment": + * Window>Preferences>Java>Templates. + * To enable and disable the creation of type comments go to + * Window>Preferences>Java>Code Generation. + */ +public class ParserSymbolTableTest extends TestCase { + + public ParserSymbolTable table = null; + public ParserSymbolTable newTable(){ + table = new ParserSymbolTable(); + return table; + } + + /** + * testSimpleAdd. + * Add a declaration to the table and confirm it is there. + * + * @throws Exception + */ + public void testSimpleAdd() throws Exception{ + newTable(); //create the symbol table + + Declaration decl = new Declaration( "x" ); + + table.addDeclaration( decl ); + + Declaration compUnit = table.getCompilationUnit(); + assertEquals( compUnit, table.peek() ); + + Map declarations = compUnit.getContainedDeclarations(); + assertEquals( 1, declarations.size() ); + + Iterator iter = declarations.values().iterator(); + Declaration contained = (Declaration) iter.next(); + + assertEquals( false, iter.hasNext() ); + assertEquals( decl, contained ); + assertEquals( contained.getName(), "x" ); + } + + /** + * testSimpleLookup + * Add a declaration to the table, then look it up. + * @throws Exception + */ + public void testSimpleLookup() throws Exception{ + newTable(); //new symbol table + + Declaration decl = new Declaration( "x" ); + + table.addDeclaration( decl ); + + Declaration look = table.Lookup( "x" ); + + assertEquals( decl, look ); + } + + public void testLookupNonExistant() throws Exception{ + newTable(); + + Declaration look = table.Lookup( "boo" ); + assertEquals( look, null ); + } + + /** + * testSimplePushPop + * test pushing and popping + * @throws Exception + */ + public void testSimplePushPop() throws Exception{ + newTable(); + + Declaration pushing = new Declaration( "class" ); + assertEquals( pushing.getContainingScope(), null ); + + table.push( pushing ); + assertEquals( pushing, table.peek() ); + assertEquals( pushing.getContainingScope(), table.getCompilationUnit() ); + + Declaration popped = table.pop(); + assertEquals( pushing, popped ); + assertEquals( table.peek(), table.getCompilationUnit() ); + } + + public void testSimpleSetGetObject() throws Exception{ + newTable(); + + Declaration decl = new Declaration( "x" ); + Object obj = new Object(); + + decl.setObject( obj ); + + table.addDeclaration( decl ); + + Declaration look = table.Lookup( "x" ); + + assertEquals( look.getObject(), obj ); + } + + /** + * testHide + * test that a declaration in a scope hides declarations in containing + * scopes + * @throws Exception + */ + public void testHide() throws Exception{ + newTable(); + + Declaration firstX = new Declaration( "x" ); + table.addDeclaration( firstX ); + + Declaration firstClass = new Declaration( "class" ); + table.addDeclaration( firstClass ); + table.push( firstClass ); + + Declaration look = table.Lookup( "x" ); + assertEquals( look, firstX ); + + Declaration secondX = new Declaration( "x" ); + table.addDeclaration( secondX ); + + look = table.Lookup( "x" ); + assertEquals( look, secondX ); + + table.pop(); + + look = table.Lookup( "x" ); + assertEquals( look, firstX ); + } + + /** + * testContainingScopeLookup + * test lookup of something declared in the containing scope + * @throws Exception + */ + public void testContainingScopeLookup() throws Exception{ + newTable(); + + Declaration x = new Declaration("x"); + Declaration cls = new Declaration("class"); + + table.addDeclaration( x ); + table.addDeclaration( cls ); + table.push( cls ); + + Declaration look = table.Lookup( "x" ); + + assertEquals( x, look ); + } + + /** + * testParentLookup + * test lookup of a variable declaration in the parent + * + * @throws Exception + */ + public void testParentLookup() throws Exception{ + newTable(); + + Declaration class1 = new Declaration( "class" ); + Declaration parent = new Declaration( "parent" ); + Declaration decl = new Declaration( "x" ); + + table.addDeclaration( parent ); + table.push( parent ); + table.addDeclaration( decl ); + table.pop(); + + class1.addParent( parent ); + table.addDeclaration( class1 ); + table.push( class1 ); + + Declaration look = table.Lookup( "x" ); + assertEquals( look, decl ); + + table.pop(); + assertEquals( table.peek(), table.getCompilationUnit() ); + } + + /** + * testAmbiguousParentLookup + * calls testParentLookup + * + * tests that if a variable is declared in two parents that the lookup + * returns an ambiguous result. + * + * @throws Exception + */ + public void testAmbiguousParentLookup() throws Exception{ + testParentLookup(); + + Declaration parent2 = new Declaration( "parent2" ); + + table.addDeclaration( parent2 ); + + Declaration class1 = table.Lookup( "class" ); + class1.addParent( parent2 ); + + Declaration decl = new Declaration("x"); + table.push( parent2 ); + table.addDeclaration( decl ); + table.pop(); + + table.push( class1 ); + try{ + table.Lookup( "x" ); + assertTrue( false ); + } + catch ( ParserSymbolTableException e ){ + assertTrue( true ); + } + + } + + /** + * testVirtualParentLookup + * + * @throws Exception + * tests lookup of name in virtual baseclass C + * + * C + * / \ + * A B + * \ / + * class + */ + public void testVirtualParentLookup() throws Exception{ + newTable(); + + Declaration decl = new Declaration("class"); + Declaration c = new Declaration("C"); + + Declaration a = new Declaration("A"); + a.addParent( c, true ); + + Declaration b = new Declaration("B"); + b.addParent( c, true ); + + decl.addParent( a ); + decl.addParent( b ); + + table.addDeclaration( c ); + table.push( c ); + Declaration x = new Declaration( "x" ); + table.addDeclaration( x ); + table.pop(); + + table.addDeclaration( decl ); + table.addDeclaration( a ); + table.addDeclaration( b ); + + table.push(decl); + + Declaration look = table.Lookup( "x" ); + + assertEquals( look, x ); + + table.pop(); + + assertEquals( table.peek(), table.getCompilationUnit() ); + } + + /** + * testAmbiguousVirtualParentLookup + * @throws Exception + * + * tests lookup of name in base class C in the following hierarchy + * C C + * / \ | + * A B D + * \ / / + * class + */ + public void testAmbiguousVirtualParentLookup() throws Exception{ + testVirtualParentLookup(); + + Declaration cls = table.Lookup("class"); + Declaration c = table.Lookup("C"); + Declaration d = new Declaration("D"); + + d.addParent( c ); + + cls.addParent( d ); + + table.push( cls ); + + try{ + table.Lookup( "x" ); + assertTrue( false ); + } + catch( ParserSymbolTableException e){ + assertTrue( true ); + } + } + + /** + * testStaticEnumParentLookup + * + * @throws Exception + * + * D D + * | | + * B C + * \ / + * A + * + * Things defined in D are not ambiguous if they are static or an enum + */ + public void testStaticEnumParentLookup() throws Exception{ + newTable(); + + Declaration a = new Declaration( "a" ); + Declaration b = new Declaration( "b" ); + Declaration c = new Declaration( "c" ); + Declaration d = new Declaration( "d" ); + + table.addDeclaration( a ); + table.addDeclaration( b ); + table.addDeclaration( c ); + table.addDeclaration( d ); + + Declaration enum = new Declaration("enum"); + enum.setType( Declaration.t_enum ); + + Declaration stat = new Declaration("static"); + stat.setStatic(true); + + Declaration x = new Declaration("x"); + + table.push(d); + table.addDeclaration( enum ); + table.addDeclaration( stat ); + table.addDeclaration( x ); + table.pop(); + + a.addParent( b ); + a.addParent( c ); + b.addParent( d ); + c.addParent( d ); + + table.push( a ); + try{ + table.Lookup( "enum" ); + assertTrue( true ); + } + catch ( ParserSymbolTableException e){ + assertTrue( false ); + } + + try{ + table.Lookup( "static" ); + assertTrue( true ); + } + catch ( ParserSymbolTableException e){ + assertTrue( false ); + } + + try{ + table.Lookup( "x" ); + assertTrue( false ); + } + catch ( ParserSymbolTableException e){ + assertTrue( true ); + } + } + + /** + * testElaboratedLookup + * @throws Exception + * test lookup of hidden names using elaborated type spec + */ + public void testElaboratedLookup() throws Exception{ + newTable(); + + Declaration cls = new Declaration( "class" ); + cls.setType( Declaration.t_class ); + + Declaration struct = new Declaration("struct"); + struct.setType( Declaration.t_struct ); + + Declaration union = new Declaration("union"); + union.setType( Declaration.t_union ); + + Declaration hideCls = new Declaration( "class" ); + Declaration hideStruct = new Declaration("struct"); + Declaration hideUnion = new Declaration("union"); + + Declaration a = new Declaration("a"); + Declaration b = new Declaration("b"); + + table.push(a); + table.addDeclaration(hideCls); + table.addDeclaration(hideStruct); + table.addDeclaration(hideUnion); + + a.addParent( b ); + + table.push(b); + table.addDeclaration(cls); + table.addDeclaration(struct); + table.addDeclaration(union); + table.pop(); + + Declaration look = table.ElaboratedLookup( Declaration.t_class, "class" ); + assertEquals( look, cls ); + look = table.ElaboratedLookup( Declaration.t_struct, "struct" ); + assertEquals( look, struct ); + look = table.ElaboratedLookup( Declaration.t_union, "union" ); + assertEquals( look, union ); + } + + /** + * testDeclarationType + * @throws Exception + * test the use of Declaration type in the scenario + * A a; + * a.member <=...>; + * where A was previously declared + */ + public void testDeclarationType() throws Exception{ + newTable(); + //pre-condition + Declaration A = new Declaration("A"); + table.addDeclaration(A); + + Declaration member = new Declaration("member"); + table.push(A); + table.addDeclaration(member); + table.pop(); + + //at time of "A a;" + Declaration look = table.Lookup("A"); + assertEquals( look, A ); + Declaration a = new Declaration("a"); + a.setTypeDeclaration( look ); + table.addDeclaration( a ); + + //later "a.member" + look = table.Lookup("a"); + assertEquals( look, a ); + Declaration type = look.getTypeDeclaration(); + assertEquals( type, A ); + table.push(type); + look = table.Lookup("member"); + assertEquals( look, member ); + } + + /** + * testFunctions + * @throws Exception + * Functions are stored by signature. Where the signature can really be of + * any for you like, as long as it can't possibly be a regular name (ie + * including the parenthese is good...) + * So lookup of function names proceeds inthe same manner as normal names, + * this test doesn't really test anything new + */ + + public void testFunctions() throws Exception{ + newTable(); + + Declaration cls = new Declaration( "class"); + Declaration f1 = new Declaration("foo()"); + Declaration f2 = new Declaration("foo(int)"); + Declaration f3 = new Declaration("foo(int,char)"); + + table.addDeclaration(cls); + table.push(cls); + + table.addDeclaration( f1 ); + table.addDeclaration( f2 ); + table.addDeclaration( f3 ); + + //return type can be specified by setting the TypeDeclaration + Declaration returnType = new Declaration("return"); + f1.setTypeDeclaration( returnType ); + f2.setTypeDeclaration( returnType ); + f3.setTypeDeclaration( returnType ); + + assertEquals( table.Lookup("foo()"), f1 ); + assertEquals( table.Lookup("foo(int)"), f2 ); + assertEquals( table.Lookup("foo(int,char)"), f3 ); + + //notice that, with the current implementation, you can't do a lookup + //on just the function name without the rest of the signature + assertEquals( table.Lookup("foo"), null ); + } +} \ No newline at end of file diff --git a/core/org.eclipse.cdt.ui.tests/parser/org/eclipse/cdt/core/parser/tests/ScannerTestCase.java b/core/org.eclipse.cdt.ui.tests/parser/org/eclipse/cdt/core/parser/tests/ScannerTestCase.java new file mode 100644 index 00000000000..af88698b8ae --- /dev/null +++ b/core/org.eclipse.cdt.ui.tests/parser/org/eclipse/cdt/core/parser/tests/ScannerTestCase.java @@ -0,0 +1,990 @@ +package org.eclipse.cdt.core.parser.tests; + +import java.io.StringReader; +import java.util.List; + +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestSuite; + +import org.eclipse.cdt.internal.core.parser.IMacroDescriptor; +import org.eclipse.cdt.internal.core.parser.Scanner; +import org.eclipse.cdt.internal.core.parser.ScannerException; +import org.eclipse.cdt.internal.core.parser.Token; + +/** + * @author jcamelon + * + * To change this generated comment edit the template variable "typecomment": + * Window>Preferences>Java>Templates. + * To enable and disable the creation of type comments go to + * Window>Preferences>Java>Code Generation. + */ +public class ScannerTestCase extends TestCase +{ + public class TableRow + { + private int[] values; + private int length; + + public TableRow(int[] v) + { + length= v.length; + values= new int[length]; + System.arraycopy(v, 0, values, 0, length); + } + + public String toString() + { + StringBuffer s= new StringBuffer(); + for (int i= 0; i < length; ++i) + { + s.append("var").append(i).append("=").append(values[i]).append(" "); + } + return s.toString(); + } + + public String symbolName(int index) + { + return "DEFINITION" + index; + } + + public int symbolValue(int index) + { + return new Long(Math.round(Math.pow(index, index))).intValue(); + } + + public String generateCode() + { + if (length < 2) + { + return "Array must have at least 2 elements"; + } + int numberOfElsifs= length - 1; + StringBuffer buffer= new StringBuffer(); + buffer.append("#if ").append(values[0]).append("\n#\tdefine "); + buffer.append(symbolName(0)).append(" ").append(symbolValue(0)); + for (int i= 0; i < numberOfElsifs; ++i) + buffer + .append("\n#elif ") + .append(values[1 + i]) + .append("\n#\tdefine ") + .append(symbolName(i + 1)) + .append(" ") + .append(symbolValue(i + 1)); + buffer + .append("\n#else \n#\tdefine ") + .append(symbolName(length)) + .append(" ") + .append(symbolValue(length)) + .append("\n#endif"); + return buffer.toString(); + } + + public int selectWinner() + { + for (int i= 0; i < values.length; ++i) + { + if (values[i] != 0) + { + return i; + } + } + return length; + } + /** + * Returns the length. + * @return int + */ + public int getLength() + { + return length; + } + + } + + public class TruthTable + { + private int numberOfVariables; + private int numberOfRows; + public TableRow[] rows; + + public TruthTable(int n) + { + numberOfVariables= n; + numberOfRows= new Long(Math.round(Math.pow(2, n))).intValue(); + + rows= new TableRow[numberOfRows]; + for (int i= 0; i < numberOfRows; ++i) + { + String Z= Integer.toBinaryString(i); + + int[] input= new int[numberOfVariables]; + for (int j= 0; j < numberOfVariables; ++j) + { + int padding= numberOfVariables - Z.length(); + int k= 0; + for (; k < padding; ++k) + { + input[k]= 0; + } + for (int l= 0; l < Z.length(); ++l) + { + char c= Z.charAt(l); + int value= Character.digit(c, 10); + input[k++]= value; + } + } + rows[i]= new TableRow(input); + } + } + /** + * Returns the numberOfRows. + * @return int + */ + public int getNumberOfRows() + { + return numberOfRows; + } + + } + + public final static String EXCEPTION_THROWN= "Exception thrown "; + public final static String EXPECTED_FAILURE= + "This statement should not be reached " + + "as we sent in bad preprocessor input to the scanner"; + public final static boolean verbose= false; + public final static boolean doConcatenation= false; + public final static boolean doIncludeStdio= false; + public final static boolean doIncludeWindowsH= false; + public final static boolean doIncludeWinUserH= false; + + public final static int SIZEOF_TRUTHTABLE = 10; + + public void initializeScanner(String input) + { + scanner= new Scanner(); + scanner.initialize( new StringReader(input),"TEXT"); + } + + public static Test suite() + { + return new TestSuite(ScannerTestCase.class); + } + + public int fullyTokenize() throws Exception + { + try + { + Token t= scanner.nextToken(); + while ((t != null) && (t.type != Token.tEOF)) + { + if (verbose) + System.out.println("Token t = " + t); + + if ((t.type < Token.tEOF) || (t.type > Token.tLAST)) + System.out.println("Unknown type for token " + t); + t= scanner.nextToken(); + } + } + catch (ScannerException se) + { + throw se; + } + return scanner.getCount(); + } + + Scanner scanner; + + /** + * Constructor for ScannerTestCase. + * @param name + */ + public ScannerTestCase(String name) + { + super(name); + } + + public void testPreprocessorDefines() + { + try + { + initializeScanner("#define SIMPLE_NUMERIC 5\nint x = SIMPLE_NUMERIC"); + validateToken(Token.t_int); + validateDefinition("SIMPLE_NUMERIC", "5"); + validateIdentifier("x"); + validateToken(Token.tASSIGN); + validateInteger("5"); + validateEOF(); + + initializeScanner("#define SIMPLE_STRING \"This is a simple string.\"\n\nconst char * myVariable = SIMPLE_STRING;"); + validateToken(Token.t_const); + validateDefinition("SIMPLE_STRING", "\"This is a simple string.\""); + validateToken(Token.t_char); + validateToken(Token.tSTAR); + validateIdentifier("myVariable"); + validateToken(Token.tASSIGN); + validateString("This is a simple string."); + validateToken(Token.tSEMI); + validateEOF(); + + initializeScanner("#define FOOL 5 \n int tryAFOOL = FOOL + FOOL;"); + + validateToken(Token.t_int); + validateIdentifier("tryAFOOL"); + validateToken(Token.tASSIGN); + validateInteger("5"); + validateToken(Token.tPLUS); + validateInteger("5"); + validateToken(Token.tSEMI); + validateEOF(); + + initializeScanner("#define FOOL 5 \n int FOOLer = FOOL;"); + + validateToken(Token.t_int); + validateIdentifier("FOOLer"); + validateToken(Token.tASSIGN); + validateInteger("5"); + validateToken(Token.tSEMI); + validateToken(Token.tEOF); + + // the case we were failing against in ctype.h + // this is a definition, not a macro! + initializeScanner("#define _ALPHA (0x0100|_UPPER|_LOWER)"); + validateEOF(); + validateDefinition("_ALPHA", "(0x0100|_UPPER|_LOWER)"); + + // test for comments after the macro + initializeScanner("#define NO_COMMENT// ignore me"); + validateEOF(); + validateDefinition("NO_COMMENT", ""); + + initializeScanner("#define NO_COMMENT/* ignore me*/"); + validateEOF(); + validateDefinition("NO_COMMENT", ""); + + initializeScanner("#define ANSWER 42 // i think"); + validateEOF(); + validateDefinition("ANSWER", "42"); + + initializeScanner("#define ANSWER 42 /* i think */"); + validateEOF(); + validateDefinition("ANSWER", "42"); + + initializeScanner("#define MULTILINE 3 /* comment \n that goes more than one line */"); + validateEOF(); + validateDefinition("MULTILINE", "3"); + + initializeScanner("#define MULTICOMMENT X /* comment1 */ + Y /* comment 2 */"); + validateEOF(); + validateDefinition("MULTICOMMENT", "X + Y"); + + for (int i= 0; i < 7; ++i) + { + switch (i) + { + case 0 : + initializeScanner("#define SIMPLE_STRING This is a simple string.\n"); + break; + case 1 : + initializeScanner("# define SIMPLE_NUMERIC 5\n"); + break; + case 2 : + initializeScanner("# define SIMPLE_NUMERIC 5\n"); + break; + case 3 : + initializeScanner("#define SIMPLE_STRING \"This is a simple string.\"\n"); + break; + case 4 : + initializeScanner("#define SIMPLE_STRING This is a simple string.\n"); + break; + case 5 : + initializeScanner("#define FLAKE\n\nFLAKE"); + break; + case 6 : + initializeScanner("#define SIMPLE_STRING This is a simple string.\\\n Continue please."); + break; + } + validateEOF(); + + switch (i) + { + case 0 : + validateDefinition( + "SIMPLE_STRING", + "This is a simple string."); + break; + case 1 : + validateDefinition("SIMPLE_NUMERIC", "5"); + break; + case 2 : + validateDefinition("SIMPLE_NUMERIC", "5"); + break; + case 3 : + validateDefinition( + "SIMPLE_STRING", + "\"This is a simple string.\""); + break; + case 4 : + validateDefinition( + "SIMPLE_STRING", + "This is a simple string."); + break; + case 5 : + validateDefinition("FLAKE", ""); + break; + case 6 : + validateDefinition( + "SIMPLE_STRING", + "This is a simple string. Continue please."); + } + } + } + catch (Exception e) + { + fail(EXCEPTION_THROWN + e.toString()); + } + } + + public void prepareForWindowsRH() + { + scanner.addIncludePath( + "C:\\Program Files\\Microsoft Visual Studio .NET\\Vc7\\PlatformSDK\\include"); + scanner.addDefinition("_WIN32_WINNT", "0x0300"); + scanner.addDefinition("WINVER", "0x0400"); + scanner.addDefinition("_WIN32_WINDOWS", "0x0300"); + scanner.addDefinition("_MSC_VER", "1200"); + } + + public void prepareForWindowsH() + { + scanner.addIncludePath( + "C:\\Program Files\\Microsoft Visual Studio .NET\\Vc7\\PlatformSDK\\include"); + scanner.addIncludePath( + "C:\\Program Files\\Microsoft Visual Studio .NET\\Vc7\\include"); + scanner.addDefinition("_MSC_VER", "1200"); + scanner.addDefinition("__cplusplus", "1"); + scanner.addDefinition("__STDC__", "1"); + scanner.addDefinition("_WIN32", ""); + scanner.addDefinition( "__midl", "1000" ); + } + + public void prepareForStdio() + { + scanner.addIncludePath( + "C:\\Program Files\\Microsoft Visual Studio .NET\\Vc7\\include"); + scanner.addDefinition("_MSC_VER", "1100"); + scanner.addDefinition("__STDC__", "1"); + scanner.addDefinition("_INTEGRAL_MAX_BITS", "64"); + scanner.addDefinition("_WIN32", ""); + } + + public void testConcatenation() + { + if (doConcatenation) + { + try + { + initializeScanner("#define F1 3\n#define F2 F1##F1\nint x=F2;"); + validateToken(Token.t_int); + validateDefinition("F1", "3"); + validateDefinition("F2", "F1##F1"); + validateIdentifier("x"); + validateToken(Token.tASSIGN); + validateInteger("33"); + validateToken(Token.tSEMI); + validateEOF(); + + initializeScanner("#define PREFIX RT_\n#define RUN PREFIX##Run"); + validateEOF(); + validateDefinition( "PREFIX", "RT_" ); + validateDefinition( "RUN", "RT_Run" ); + } + catch (Exception e) + { + fail(EXCEPTION_THROWN + e.toString()); + } + } + } + + public void testSimpleIfdef() + { + try + { + + initializeScanner("#define SYMBOL 5\n#ifdef SYMBOL\nint counter(SYMBOL);\n#endif"); + + validateToken(Token.t_int); + validateIdentifier("counter"); + validateToken(Token.tLPAREN); + validateInteger("5"); + validateToken(Token.tRPAREN); + validateToken(Token.tSEMI); + validateEOF(); + + initializeScanner("#define SYMBOL 5\n#ifndef SYMBOL\nint counter(SYMBOL);\n#endif"); + validateToken(Token.tEOF); + + initializeScanner("#ifndef DEFINED\n#define DEFINED 100\n#endif\nint count = DEFINED;"); + validateToken(Token.t_int); + validateDefinition("DEFINED", "100"); + + validateIdentifier("count"); + validateToken(Token.tASSIGN); + validateInteger("100"); + validateToken(Token.tSEMI); + validateEOF(); + + initializeScanner("#ifndef DEFINED\n#define DEFINED 100\n#endif\nint count = DEFINED;"); + scanner.addDefinition("DEFINED", "101"); + + validateDefinition("DEFINED", "101"); + validateToken(Token.t_int); + validateIdentifier("count"); + validateToken(Token.tASSIGN); + validateInteger("101"); + validateToken(Token.tSEMI); + validateEOF(); + + } + catch (Exception e) + { + fail(EXCEPTION_THROWN + e.toString()); + } + } + + public void testSlightlyComplexIfdefStructure() + { + try + { + initializeScanner("#ifndef BASE\n#define BASE 10\n#endif\n#ifndef BASE\n#error BASE is defined\n#endif"); + validateEOF(); + validateBalance(); + } + catch (Exception e) + { + fail(EXCEPTION_THROWN + e.toString()); + } + + try + { + initializeScanner("#ifndef ONE\n#define ONE 1\n#ifdef TWO\n#define THREE ONE + TWO\n#endif\n#endif\nint three(THREE);"); + + validateToken(Token.t_int); + validateDefinition("ONE", "1"); + validateAsUndefined("TWO"); + validateAsUndefined("THREE"); + validateIdentifier("three"); + validateToken(Token.tLPAREN); + validateIdentifier("THREE"); + validateToken(Token.tRPAREN); + validateToken(Token.tSEMI); + validateEOF(); + validateBalance(); + + initializeScanner("#ifndef ONE\n#define ONE 1\n#ifdef TWO\n#define THREE ONE + TWO\n#endif\n#endif\nint three(THREE);"); + scanner.addDefinition("TWO", "2"); + validateToken(Token.t_int); + validateDefinition("ONE", "1"); + validateDefinition("TWO", "2"); + validateDefinition("THREE", "ONE + TWO"); + + validateIdentifier("three"); + validateToken(Token.tLPAREN); + validateInteger("1"); + validateToken(Token.tPLUS); + validateInteger("2"); + validateToken(Token.tRPAREN); + validateToken(Token.tSEMI); + validateEOF(); + validateBalance(); + + initializeScanner("#ifndef FOO\n#define FOO 4\n#else\n#undef FOO\n#define FOO 6\n#endif"); + validateToken(Token.tEOF); + validateBalance(); + validateDefinition("FOO", "4"); + + initializeScanner("#ifndef FOO\n#define FOO 4\n#else\n#undef FOO\n#define FOO 6\n#endif"); + scanner.addDefinition("FOO", "2"); + validateEOF(); + validateBalance(); + validateDefinition("FOO", "6"); + + initializeScanner("#ifndef ONE\n# define ONE 1\n# ifndef TWO\n# define TWO ONE + ONE \n# else\n# undef TWO\n# define TWO 2 \n# endif\n#else\n# ifndef TWO\n# define TWO ONE + ONE \n# else\n# undef TWO\n# define TWO 2 \n# endif\n#endif\n"); + validateEOF(); + validateBalance(); + validateDefinition("ONE", "1"); + validateDefinition("TWO", "ONE + ONE"); + + initializeScanner("#ifndef ONE\n# define ONE 1\n# ifndef TWO\n# define TWO ONE + ONE \n# else\n# undef TWO\n# define TWO 2 \n# endif\n#else\n# ifndef TWO\n# define TWO ONE + ONE \n# else\n# undef TWO\n# define TWO 2 \n# endif\n#endif\n"); + scanner.addDefinition("ONE", "one"); + validateEOF(); + validateBalance(); + validateDefinition("ONE", "one"); + validateDefinition("TWO", "ONE + ONE"); + + initializeScanner("#ifndef ONE\n# define ONE 1\n# ifndef TWO\n# define TWO ONE + ONE \n# else\n# undef TWO\n# define TWO 2 \n# endif\n#else\n# ifndef TWO\n# define TWO ONE + ONE \n# else\n# undef TWO\n# define TWO 2 \n# endif\n#endif\n"); + scanner.addDefinition("ONE", "one"); + scanner.addDefinition("TWO", "two"); + validateEOF(); + validateBalance(); + + validateDefinition("ONE", "one"); + validateDefinition("TWO", "2"); + + initializeScanner("#ifndef ONE\n# define ONE 1\n# ifndef TWO\n# define TWO ONE + ONE \n# else\n# undef TWO\n# define TWO 2 \n# endif\n#else\n# ifndef TWO\n# define TWO ONE + ONE \n# else\n# undef TWO\n# define TWO 2 \n# endif\n#endif\n"); + scanner.addDefinition("TWO", "two"); + validateEOF(); + validateBalance(); + + validateDefinition("ONE", "1"); + validateDefinition("TWO", "2"); + + } + catch (Exception e) + { + fail(EXCEPTION_THROWN + e.toString()); + } + } + + public void testIfs() + { + try + { + initializeScanner("#if 0\n#error NEVER\n#endif\n"); + validateEOF(); + validateBalance(); + + initializeScanner("#define X 5\n#define Y 7\n#if (X < Y)\n#define Z X + Y\n#endif"); + validateEOF(); + validateBalance(); + validateDefinition("X", "5"); + validateDefinition("Y", "7"); + validateDefinition("Z", "X + Y"); + + initializeScanner("#if T < 20\n#define Z T + 1\n#endif"); + scanner.addDefinition("X", "5"); + scanner.addDefinition("Y", "7"); + scanner.addDefinition("T", "X + Y"); + validateEOF(); + validateBalance(); + validateDefinition("X", "5"); + validateDefinition("Y", "7"); + validateDefinition("T", "X + Y"); + validateDefinition("Z", "T + 1"); + + } + catch (Exception e) + { + fail(EXCEPTION_THROWN + e.toString()); + } + + try + { + initializeScanner("#if ( 10 / 5 ) != 2\n#error 10/5 seems to not equal 2 anymore\n#endif\n"); + validateEOF(); + validateBalance(); + } + catch (Exception e) + { + fail(EXCEPTION_THROWN + e.toString()); + } + + try + { + initializeScanner("#ifndef FIVE \n#define FIVE 5\n#endif \n#ifndef TEN\n#define TEN 2 * FIVE\n#endif\n#if TEN != 10\n#define MISTAKE 1\n#error Five does not equal 10\n#endif\n"); + scanner.addDefinition("FIVE", "55"); + validateEOF(); + fail(EXPECTED_FAILURE); + } + catch (ScannerException se) + { + validateBalance(1); + validateDefinition("FIVE", "55"); + validateDefinition("TEN", "2 * FIVE"); + validateDefinition("MISTAKE", "1"); + } + catch (Exception e) + { + fail(EXCEPTION_THROWN + e.toString()); + } + + try + { + initializeScanner("#if ((( FOUR / TWO ) * THREE )< FIVE )\n#error 6 is not less than 5 \n#endif\n#if ( ( FIVE * ONE ) != (( (FOUR) + ONE ) * ONE ) )\n#error 5 should equal 5\n#endif \n"); + + scanner.addDefinition("ONE", "1"); + scanner.addDefinition("TWO", "(ONE + ONE)"); + scanner.addDefinition("THREE", "(TWO + ONE)"); + scanner.addDefinition("FOUR", "(TWO * TWO)"); + scanner.addDefinition("FIVE", "(THREE + TWO)"); + + validateEOF(); + validateBalance(); + validateDefinition("ONE", "1"); + validateDefinition("TWO", "(ONE + ONE)"); + validateDefinition("THREE", "(TWO + ONE)"); + validateDefinition("FOUR", "(TWO * TWO)"); + validateDefinition("FIVE", "(THREE + TWO)"); + + TruthTable table= new TruthTable(SIZEOF_TRUTHTABLE); + int numberOfRows= table.getNumberOfRows(); + TableRow[] rows= table.rows; + + for (int i= 0; i < numberOfRows; ++i) + { + TableRow row= rows[i]; + String code= row.generateCode(); + if (verbose) + System.out.println("\n\nRow " + i + " has code\n" + code); + initializeScanner(code); + validateEOF(); + validateBalance(); + validateAllDefinitions(row); + } + } + catch (Exception e) + { + fail(EXCEPTION_THROWN + e.toString()); + } + + try + { + initializeScanner("#if ! 0\n#error Correct!\n#endif"); + Token t= scanner.nextToken(); + fail(EXPECTED_FAILURE); + } + catch (ScannerException se) + { + validateBalance(1); + assertTrue(se.getMessage().equals("#error Correct!")); + } + catch (Exception e) + { + fail(EXCEPTION_THROWN + e.toString()); + } + } + + public void testPreprocessorMacros() + { + try + { + initializeScanner("#define GO(x) x+1\nint y(5);\ny = GO(y);"); + validateToken(Token.t_int); + validateIdentifier("y"); + validateToken(Token.tLPAREN); + validateInteger("5"); + validateToken(Token.tRPAREN); + validateToken(Token.tSEMI); + + IMacroDescriptor descriptor= + (IMacroDescriptor) scanner.getDefinition("GO"); + List parms= descriptor.getParameters(); + assertNotNull(parms); + assertTrue(parms.size() == 1); + String parm1= (String) parms.get(0); + assertTrue(parm1.equals("x")); + List expansion= descriptor.getTokenizedExpansion(); + assertNotNull(parms); + assertTrue(expansion.size() == 3); + assertTrue(((Token) expansion.get(0)).type == Token.tIDENTIFIER); + assertTrue(((Token) expansion.get(0)).image.equals("x")); + assertTrue(((Token) expansion.get(1)).type == Token.tPLUS); + assertTrue(((Token) expansion.get(2)).type == Token.tINTEGER); + assertTrue(((Token) expansion.get(2)).image.equals("1")); + + validateIdentifier("y"); + validateToken(Token.tASSIGN); + validateIdentifier("y"); + validateToken(Token.tPLUS); + validateInteger("1"); + validateToken(Token.tSEMI); + validateEOF(); + validateBalance(); + + initializeScanner( + "#define ONE 1\n" + + "#define SUM(a,b,c,d,e,f,g) ( a + b + c + d + e + f + g )\n" + + "int daSum = SUM(ONE,3,5,7,9,11,13);"); + validateToken(Token.t_int); + validateIdentifier("daSum"); + validateToken(Token.tASSIGN); + validateToken(Token.tLPAREN); + validateInteger("1"); + validateToken(Token.tPLUS); + validateInteger("3"); + validateToken(Token.tPLUS); + validateInteger("5"); + validateToken(Token.tPLUS); + validateInteger("7"); + validateToken(Token.tPLUS); + validateInteger("9"); + validateToken(Token.tPLUS); + validateInteger("11"); + validateToken(Token.tPLUS); + validateInteger("13"); + validateToken(Token.tRPAREN); + validateToken(Token.tSEMI); + validateEOF(); + + IMacroDescriptor macro= (IMacroDescriptor) scanner.getDefinition("SUM"); + List params= macro.getParameters(); + assertNotNull(params); + assertTrue(params.size() == 7); + + List tokens= macro.getTokenizedExpansion(); + assertNotNull(tokens); + assertTrue(tokens.size() == 15); + + initializeScanner("#define LOG( format, var1) printf( format, var1 )\nLOG( \"My name is %s\", \"Bogdan\" );\n"); + validateIdentifier("printf"); + validateToken(Token.tLPAREN); + validateString("My name is %s"); + validateToken(Token.tCOMMA); + validateString("Bogdan"); + validateToken(Token.tRPAREN); + validateToken(Token.tSEMI); + validateEOF(); + + initializeScanner("#define INCR( x ) ++x\nint y(2);\nINCR(y);"); + validateToken(Token.t_int); + validateIdentifier("y"); + validateToken(Token.tLPAREN); + validateInteger("2"); + validateToken(Token.tRPAREN); + validateToken(Token.tSEMI); + validateToken(Token.tINCR); + validateIdentifier("y"); + validateToken(Token.tSEMI); + validateEOF(); + + initializeScanner("#define CHECK_AND_SET( x, y, z ) if( x ) { \\\n y = z; \\\n }\n\nCHECK_AND_SET( 1, balance, 5000 );\nCHECK_AND_SET( confused(), you, dumb );"); + validateToken(Token.t_if); + validateToken(Token.tLPAREN); + validateInteger("1"); + validateToken(Token.tRPAREN); + validateToken(Token.tLBRACE); + validateIdentifier("balance"); + validateToken(Token.tASSIGN); + validateInteger("5000"); + validateToken(Token.tSEMI); + validateToken(Token.tRBRACE); + validateToken(Token.tSEMI); + + validateToken(Token.t_if); + validateToken(Token.tLPAREN); + validateIdentifier("confused"); + validateToken(Token.tLPAREN); + validateToken(Token.tRPAREN); + validateToken(Token.tRPAREN); + validateToken(Token.tLBRACE); + validateIdentifier("you"); + validateToken(Token.tASSIGN); + validateIdentifier("dumb"); + validateToken(Token.tSEMI); + validateToken(Token.tRBRACE); + validateToken(Token.tSEMI); + validateEOF(); + + initializeScanner("#define ON 7\n#if defined(ON)\nint itsOn = ON;\n#endif"); + validateToken(Token.t_int); + validateBalance(1); + validateIdentifier("itsOn"); + validateToken(Token.tASSIGN); + validateInteger("7"); + validateToken(Token.tSEMI); + validateEOF(); + validateBalance(); + + initializeScanner("#if defined( NOTHING ) \nint x = NOTHING;\n#endif"); + validateEOF(); + validateBalance(); + + } + catch (Exception e) + { + fail(EXCEPTION_THROWN + e.toString()); + } + } + + public void testInclusions() + { + try + { + if (doIncludeStdio) + { + initializeScanner("#include "); + prepareForStdio(); + int count= fullyTokenize(); + if (verbose) + System.out.println( + "For stdio.h, Scanner produced " + count + " tokens"); + validateBalance(); + + initializeScanner("#include \\\n<\\\nstdio.h \\\n>"); + prepareForStdio(); + count= fullyTokenize(); + if (verbose) + System.out.println( + "For stdio.h, Scanner produced " + count + " tokens"); + } + + if (doIncludeWindowsH) + { + initializeScanner("#include "); + prepareForWindowsH(); + int count= fullyTokenize(); + if (verbose) + System.out.println( + "For Windows.h, Scanner produced " + + scanner.getCount() + + " tokens"); + validateBalance(); + } + + if (doIncludeWinUserH) + { + initializeScanner("#include "); + prepareForWindowsRH(); + validateEOF(); + validateBalance(); + if (verbose) + System.out.println( + "For WinUser.rh, Scanner produced " + + scanner.getCount() + + " tokens"); + } + } + catch (Exception e) + { + fail(EXCEPTION_THROWN + e.toString()); + } + + } + + public void testOtherPreprocessorCommands() + { + try + { + initializeScanner("#\n#\t\n#define MAX_SIZE 1024\n#\n# "); + validateEOF(); + validateDefinition("MAX_SIZE", "1024"); + } + catch (Exception e) + { + fail(EXCEPTION_THROWN + e.toString()); + } + + for (int i= 0; i < 4; ++i) + { + switch (i) + { + case 0 : + initializeScanner("# ape"); + break; + case 1 : + initializeScanner("# #"); + break; + case 2 : + initializeScanner("# 32"); + break; + case 3 : + initializeScanner("# defines"); + break; + } + + try + { + validateEOF(); + fail(EXPECTED_FAILURE); + } + catch (ScannerException se) + { + validateBalance(); + } + catch (Exception e) + { + fail(EXCEPTION_THROWN + e.toString()); + } + } + + } + + public void validateIdentifier(String expectedImage) throws ScannerException + { + Token t= scanner.nextToken(); + assertTrue(t.type == Token.tIDENTIFIER); + assertTrue(t.image.equals(expectedImage)); + } + + public void validateInteger(String expectedImage) throws ScannerException + { + Token t= scanner.nextToken(); + assertTrue(t.type == Token.tINTEGER); + assertTrue(t.image.equals(expectedImage)); + } + + public void validateString(String expectedImage) throws ScannerException + { + Token t= scanner.nextToken(); + assertTrue(t.type == Token.tSTRING); + assertTrue(t.image.equals(expectedImage)); + } + + public void validateToken(int tokenType) throws ScannerException + { + Token t= scanner.nextToken(); + assertTrue(t.type == tokenType); + } + + public void validateBalance(int expected) + { + assertTrue(scanner.getDepth() == expected); + } + + public void validateBalance() + { + assertTrue(scanner.getDepth() == 0); + } + + public void validateEOF() throws ScannerException + { + validateToken(Token.tEOF); + } + + public void validateDefinition(String name, String value) + { + String definition= null; + definition= (String) scanner.getDefinition(name); + assertNotNull(definition); + assertTrue(definition.trim().equals(value)); + } + + public void validateDefinition(String name, int value) + { + String definition= null; + definition= (String) scanner.getDefinition(name); + this.assertNotNull(definition); + int intValue= (Integer.valueOf((String) definition)).intValue(); + assertEquals(value, intValue); + } + + public void validateAsUndefined(String name) + { + assertNull(scanner.getDefinition(name)); + } + + public void validateAllDefinitions(TableRow row) + { + int winner= row.selectWinner(); + int rowLength= row.getLength(); + for (int i= 0; i <= rowLength; ++i) + { + if (i == winner) + validateDefinition(row.symbolName(i), row.symbolValue(i)); + else + validateAsUndefined(row.symbolName(i)); + } + } + +} diff --git a/core/org.eclipse.cdt.ui.tests/parser/org/eclipse/cdt/core/parser/tests/XMLDumper.java b/core/org.eclipse.cdt.ui.tests/parser/org/eclipse/cdt/core/parser/tests/XMLDumper.java new file mode 100644 index 00000000000..0221d0d25c0 --- /dev/null +++ b/core/org.eclipse.cdt.ui.tests/parser/org/eclipse/cdt/core/parser/tests/XMLDumper.java @@ -0,0 +1,138 @@ +package org.eclipse.cdt.core.parser.tests; + +import java.io.IOException; +import java.io.StringWriter; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.HashMap; + +import org.apache.xerces.dom.DocumentImpl; +import org.apache.xml.serialize.OutputFormat; +import org.apache.xml.serialize.XMLSerializer; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +/** + * This class implements a utility that will walk through an object + * and it's children and create an XML file for it. + */ +public class XMLDumper { + + public static class Test { + private String msg = "hi"; + + public String getMsg() { + return msg; + } + + public Test self = this; + } + + public static void main(String [] args) { + Test test = new Test(); + XMLDumper dumper = new XMLDumper(test); + Document document = dumper.getDocument(); + + OutputFormat format = new OutputFormat( document ); //Serialize DOM + StringWriter stringOut = new StringWriter(); //Writer will be a String + XMLSerializer serial = new XMLSerializer( stringOut, format ); + + try { + serial.asDOMSerializer(); // As a DOM Serializer + serial.serialize( document.getDocumentElement() ); + System.out.println( "STRXML = " + stringOut.toString() ); //Spit out DOM as a String + } catch (IOException e) { + System.out.println(e); + } + + } + + private int id = 0; + private HashMap map = new HashMap(); + private Document document = new DocumentImpl(); + + public Document getDocument() { + return document; + } + + public XMLDumper(Object obj) { + document.appendChild(createObject(obj)); + } + + private Element createObject(Object obj) { + Class cls = obj.getClass(); + String clsName = cls.getName(); + clsName = clsName.replace('$', '.'); + + Element element = document.createElement(clsName); + map.put(obj, new Integer(id)); + element.setAttribute("id",String.valueOf(id++)); + + Field [] fields = cls.getDeclaredFields(); + for (int i = 0; i < fields.length; ++i) { + Field field = fields[i]; + int modifiers = field.getModifiers(); + + // Skip over static fields + if (Modifier.isStatic(modifiers)) + continue; + + // Skip fields that start with an underscore + if (field.getName().charAt(0) == '_') + continue; + + Object value = null; + + String fieldName = field.getName(); + if (Modifier.isPublic(modifiers)) { + try { + value = field.get(obj); + } catch (Exception e) { + value = e; + } + } else { + String methodName = "get" + + fieldName.substring(0, 1).toUpperCase() + + fieldName.substring(1); + + Method method = null; + try { + method = cls.getMethod(methodName, null); + } catch (NoSuchMethodException e) { + continue; + } + + try { + value = method.invoke(obj, null); + } catch (Exception e) { + value = e; + } + } + + Element fieldElement = document.createElement(fieldName); + element.appendChild(fieldElement); + + if (value == null) + return element; + + Class type = field.getType(); + if (String.class.isAssignableFrom(type)) + fieldElement.appendChild(document.createTextNode((String)value)); + else if (Integer.class.isAssignableFrom(type)) + fieldElement.appendChild(document.createTextNode(((Integer)value).toString())); + else if (Exception.class.isAssignableFrom(type)) + fieldElement.appendChild(document.createTextNode(value.toString())); + else { + Object v = map.get(value); + if (v != null) + fieldElement.setAttribute("refid", v.toString()); + else + fieldElement.appendChild(createObject(value)); + } + + } + + return element; + } +} diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/CPluginResources.properties b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/CPluginResources.properties index 47639c3c49b..7d6acf1a78d 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/CPluginResources.properties +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/CPluginResources.properties @@ -16,6 +16,7 @@ CBasePreferencePage.autoOpenConsole.label=Open C-Build view when building CBasePreferencePage.consoleOnTop.label=Bring C-Build view to top when building (if present) CBasePreferencePage.linkToEditor.label=Link view selection to active editor CBasePreferencePage.CUChildren.label=Show file members in Project View +CBasePreferencePage.useNewParser.label=Use New Parser for Code Model CBasePreferencePage.editorFont.label=C Editor font: CBasePreferencePage.consoleFont.label=C-Build view font: diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/CPluginPreferencePage.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/CPluginPreferencePage.java index f92edb71d9c..6c52e83cc72 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/CPluginPreferencePage.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/preferences/CPluginPreferencePage.java @@ -5,6 +5,7 @@ package org.eclipse.cdt.internal.ui.preferences; * All Rights Reserved. */ +import org.eclipse.cdt.core.CCorePlugin; import org.eclipse.cdt.internal.ui.ICHelpContextIds; import org.eclipse.cdt.ui.CUIPlugin; import org.eclipse.jface.preference.BooleanFieldEditor; @@ -20,11 +21,13 @@ import org.eclipse.ui.help.WorkbenchHelp; */ public class CPluginPreferencePage extends FieldEditorPreferencePage implements IWorkbenchPreferencePage { - private static final String PREF_LINK_TO_EDITOR= "linkToEditor"; + private static final String PREF_LINK_TO_EDITOR= "linkToEditor"; //$NON-NLS-1$ public static final String PREF_SHOW_CU_CHILDREN= "CUChildren"; //$NON-NLS-1$ + private static final String PREF_USE_NEW_PARSER= "useNewParser"; //$NON-NLS-1$ private static final String LINK_TO_EDITOR_LABEL= "CBasePreferencePage.linkToEditor.label"; private static final String SHOW_CU_CHILDREN_LABEL= "CBasePreferencePage.CUChildren.label"; + private static final String USE_NEW_PARSER_LABEL= "CBasePreferencePage.useNewParser.label"; public CPluginPreferencePage() { super(GRID); @@ -51,6 +54,8 @@ public class CPluginPreferencePage extends FieldEditorPreferencePage implements BooleanFieldEditor showCUChildrenEditor= new BooleanFieldEditor(PREF_SHOW_CU_CHILDREN, CUIPlugin.getResourceString(SHOW_CU_CHILDREN_LABEL), parent); addField(showCUChildrenEditor); + BooleanFieldEditor useNewParserEditor= new BooleanFieldEditor(PREF_USE_NEW_PARSER, CUIPlugin.getResourceString(USE_NEW_PARSER_LABEL), parent); + addField(useNewParserEditor); } @@ -62,6 +67,10 @@ public class CPluginPreferencePage extends FieldEditorPreferencePage implements return CUIPlugin.getDefault().getPreferenceStore().getBoolean(PREF_SHOW_CU_CHILDREN); } + public static boolean useNewParser() { + return CUIPlugin.getDefault().getPreferenceStore().getBoolean(PREF_USE_NEW_PARSER); + } + /** * @see IWorkbenchPreferencePage#init */ @@ -74,6 +83,18 @@ public class CPluginPreferencePage extends FieldEditorPreferencePage implements public static void initDefaults(IPreferenceStore prefs) { prefs.setDefault(PREF_LINK_TO_EDITOR, true); prefs.setDefault(PREF_SHOW_CU_CHILDREN, true); - } + prefs.setDefault(PREF_USE_NEW_PARSER, false); + } + /* (non-Javadoc) + * @see org.eclipse.jface.preference.IPreferencePage#performOk() + */ + public boolean performOk() { + if (!super.performOk()) + return false; + + CCorePlugin.getDefault().setUseNewParser(useNewParser()); + return true; + } + } diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/CUIPlugin.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/CUIPlugin.java index 7f917f69263..80741f2fe2f 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/CUIPlugin.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/CUIPlugin.java @@ -9,6 +9,7 @@ import java.text.MessageFormat; import java.util.MissingResourceException; import java.util.ResourceBundle; +import org.eclipse.cdt.core.CCorePlugin; import org.eclipse.cdt.core.model.CoreModel; import org.eclipse.cdt.core.model.ICElement; import org.eclipse.cdt.internal.ui.BuildConsoleManager; @@ -217,6 +218,10 @@ public class CUIPlugin extends AbstractUIPlugin { CPluginImages.initialize(); } }); + + // TODO - temporary kludge (maybe) to make sure the core preferences + // are kept in sync with the stored preferences + CCorePlugin.getDefault().setUseNewParser(CPluginPreferencePage.useNewParser()); } /**