我正在嘗試使用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
綠色按預期。 (請注意foo
是primary
,其終端不是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抱怨,因爲expression
和invocationExpression
是相互左遞歸。我如何克服這個問題,還是有不同的方法來解決這個問題?