2016-12-14 71 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 
    ] 
}