2016-12-14 31 views
0

我已经实现了一种语言的语法,该语言最好被描述为没有预处理器的C++的脚本化版本。我试图让范围工作。 (语法大约是500行,这样可以让你了解包含多少C++语法和多少内容,包括枚举类,类,全局和类成员函数,以及一些时髦的东西)如何在C++语言中对合格名称进行范围划分

我觉得有点愚蠢,问这样一个广泛的问题,可能有一个简单的答案,但我觉得在这一点上,我已经烧了足够多的时间在XText文档,这本书,网页搜索,相关博客,以及看看最好问的XText代码。

我想弄清范围。一些我已经工作的关键件:

  1. 它提供了合适的限定名,以便C类的对象成员变量x是C.x.理论上讲,一旦我有了一个类型系统(就像XText书中的那个)一样工作,这对我来说可能会确定一个对象的类型,然后用它来导入该类的范围。在我可以使用ref = [ecore :: EObject | GenericDataTypeRule]的地方,我有GenericDataTypeRule:name = ID;我知道如何使用ref = [ecore :: EObject | GenericDataTypeRule]在语法中可能有一个词法分析规则有多个相应的数据类型的地方。

所以,问题如下:

如何(有效!)让我MyCppLikeDSLScopeProvider允许以下类型的引用:

class MyClass { 
    void memberFunction(); 
    Integer j; 
    ... 
} 

Integer MyClass::memberFunction() { 
    return j; 
} 

有些事情我已经尝试过:

  • I已经尝试使用Scopes.scopeFor(context.getAllContentsOfType(ClassDecl),并且如果该类在同一个文件中定义,那么工作正常,但不知何故我不知道如何让这个工作可扩展地工作,如果该类在另一个资源。例如,如果一切都在同一文件中,和我正在寻找的东西,可以是一个类,变量,函数或枚举,我可以做到这一点:不包括在

    def scope_SymbolicValue_ref(EObject context, EReference eRef) { 
        var Iterable<EObject> crossRefClassDeclTargets = context.getAllContentsOfType(ClassDecl).map[it as EObject] 
        var Iterable<EObject> crossRefDataDefTargets = context.getAllContentsOfType(DataDef).map[it as EObject] 
        var Iterable<EObject> crossRefFxnTargets = context.getAllContentsOfType(FunctionSpec).map[it as EObject] 
        var Iterable<EObject> crossRefEnumTargets = context.getAllContentsOfType(SimpleEnum).map[it as EObject] 
    
        var List<EObject> allCrossRefTargets = new ArrayList() 
        allCrossRefTargets.addAll(crossRefClassDeclTargets) 
        allCrossRefTargets.addAll(crossRefDataDefTargets) 
        allCrossRefTargets.addAll(crossRefEnumTargets) 
        allCrossRefTargets.addAll(crossRefFxnTargets) 
        return Scopes.scopeFor(allCrossRefTargets) 
    } 
    
  • 类继承这个例子,但我设法让这个工作遵循书中的例子和自定义的多重继承,尽管它并没有真正做出适当的DFS或BFS,它更像是一个“愚蠢但终止的搜索”:在每一步,查看每个顶点的边,并在该步的结尾处查看顶点数是否等于您开始使用的顶点数;所以也许我应该通过使用非愚蠢的图搜索来加快速度。
  • 我曾尝试使用context.resourceSet并遍历所有类的资源和过滤,但我的代码库大约300个文件中大约有300k行,而且速度太慢。
  • 我试过编写一个实现了IScope的自定义类。 Scopes.ScopeFor将EObject的列表转换为EObjectDescription的列表,但如果我有两个EObjectDescription的列表(例如,我可以从两个实现了IScope的不同类中获得),我想合并?当然,必须有一个微不足道的方法来结合两个示波器,而我只是因为没有找到它而死脑筋。
  • 我已经开始考虑只写自己的对象缓存,这会将我移动到一个完全自定义的类,它从头开始实现IScope,但显然XText有很多从AbstractScopeProvider继承的类,而我只需要找出我需要使用哪一个。

谢谢!我很乐意写更多的细节,但我想这是微不足道的。

+0

你可以给你一个提示你实际上想要的范围吗? –

+0

对于您不需要任何范围界定的课程。你需要它的方法调用 –

+0

和ref = [ecore :: EObject | GenericDataTypeRule]的东西是没有意义的。请解释 –

回答

0

如果您需要能够引用任何全局可见的类/方法/等。从当前或其他模型中,这由全局范围提供者完成,该提供者访问Xtext索引。

在这种情况下,你需要像

MethodImpl: 
    containingClass=[ClassDeclaration] '::' method=[Method] ; 

规则在,你必须定义它创建为containingClass所有方法书的“方法”属性,例如范围方法范围提供:

def scope_MethodImpl_method(MethodImpl methodImpl, EReference ref) { 
    Scopes::scopeFor(methodImpl.containingClass.members.filter(Method)) 
} 

棘手的部分是containingClass的范围: C++没有任何类似于导入机制的东西。您只能在同一文件中或在直接或间接的d头文件中为您之前定义的类提供方法实现。因此,如果你的子集C++允许#include,你不知何故必须模拟这种行为(这可能涉及创建自定义IDefaultResourceDescriptionStrategy或类似的东西,但这不是问题的一部分)。

在任何情况下,使用缓存可能最有意义,因为您应该使用IResourceScopeCache来缓存来自直接或间接包含文件的所有类。 忽略循环包括,它可能看起来像这样:

@Inject 
IResourceScopeCache cache 

def Set<ClassDeclaration> getImportedClasses(Module module) { 
    cache.get("INCLUDED_CLASSES", module.eResource) [ 
     (module.classDeclarations + module.includes.map[module.importedClasses].flatten).toSet 
    ] 
} 
相关问题