2017-06-13 38 views
1

我正在嘗試使用this ANTLR grammar爲Java代碼實現語法突出顯示。我的策略是將代碼解析爲具有該語法的樹,然後使用訪問者遍歷樹中的每個終端併爲其相應的文本分配一種顏色。這種顏色通常只是與終端令牌關聯的顏色,但取決於上下文,可以覆蓋覆蓋。例如,從VSCode考慮這個截圖:如何修改此ANTLR語法以使特定匹配模式獲得自己的生產?

默認情況下,標識符染成白色。但是,如果他們被稱爲類/方法,那麼它們就會變成綠色。我想在我的訪問者中作出類似的區分,默認情況下將標識符標記爲白色,但用類別/方法的綠色覆蓋該標識符。

到目前爲止,我已成功實施此類/方法聲明。爲classDeclaration生產規則是這樣的:

classDeclaration 
    : 'class' Identifier typeParameters? 
     ('extends' typeType)? 
     ('implements' typeList)? 
     classBody 
    ; 

這裏,Identifier是終端,而所有其他nonliterals都是非終結點。我的策略是用綠色(1)給每個孩子終端着色可覆蓋的令牌。在最後一個術語中,這是我在代碼庫中發明的,用於解決這個問題。實質上,無論上下文如何,關鍵字應始終具有相同的顏色,因此它們的標記不可覆蓋。標識符的顏色取決於上下文,所以它們有一個默認(白色),但你可以讓它們變成綠色。上述生產中的唯一終端是'class',Identifier,'extends''implements'。第一個和最後兩個是關鍵字,不可覆蓋,所以按照步驟(1)僅將類名稱變爲綠色。

Here是我用來實現上述策略的C#代碼。

不幸的是,當嘗試突出顯示方法調用,例如上面的blah.blah()時,此策略似乎存在問題。 Here是用於expression生產規則:

expression 
    : primary 
    | expression '.' Identifier 
    | expression '.' 'this' 
    | expression '.' 'new' nonWildcardTypeArguments? innerCreator 
    | expression '.' 'super' superSuffix 
    | expression '.' explicitGenericInvocation 
    | expression '[' expression ']' 
    | expression '(' expressionList? ')' 
    | // Lots of other stuff 
    ; 

這意味着foo.bar()解析作爲(('foo') '.' 'bar') '(' ')'。如果,對於所有expression s,我將所有Identifier兒童綠色,然後foo.bar()將有foo白色和bar綠色按預期。 (請注意fooprimary,其終端不是expression的直接子)。但是,foo.bar也有foo white和bar綠色,這與上面的VSCode的行爲不匹配。

我試圖通過創建一個看起來像expression '.' Identifier '(' expressionList? ')'並引用expression的表達式的新生產來解決此問題。

expression 
    : // ... 
    | expression '[' expression ']' 
    | invocationExpression 
    | // ... 
    ; 

invocationExpression 
    : expression '.' Identifier '(' expressionList? ')' 
    | expression '(' expressionList? ')' 
    ; 

然後,我將能夠對invocationExpression在我的訪客運行的程序(1),着色所有子Identifier的綠色,這將使foo.bar()白綠色和白色foo.bar白如預期。然而,ANTLR抱怨,因爲expressioninvocationExpression是相互左遞歸。我如何克服這個問題,還是有不同的方法來解決這個問題?

回答

1

據我所看到的,你只是創建額外的規則才能生成另一個Token,以便你的代碼知道有一個方法正在調用。

爲了做到這一點,您不必創建新的規則。您可以使用標籤來代替。基本上這意味着給每個替代品一個規則一個不同的標籤,以便每個替代品將創建它自己的Token。此外,ANTLR還會爲每個備選方案創建額外的進入和退出方法。
Here你可以在ANTLR GitHub頁面找到這些標籤的描述。

1

你應該在兩個方面分成單獨的步驟,而不是試圖解決它一氣呵成。你首先需要的是一個符號表,它包含關於你的語法實體的信息(比如類名,var名,常量等)。您可以在更改某些內容時解析輸入時創建此項。這完全是孤立的。

當你的編輯希望來標記輸入(使用詞法分析,僅此而已!),那麼你可以查找你的符號表,如果你發現一個標識符是一個已知的實體名稱,並相應地改變顏色。