我目前正在尝试实现多个不同的语法,这些语法共享一些概念。
让我们说他们看起来像这样 - 这与我的实际语法无关:
语法pathBase;
extension
: 'txt' #txtExt
| 'tar' #tarExt
| 'gz' #gzExt
| extension '.' extension #compositeExt
;
并说有一些特定于os的路径语法。 一个用于Windows:
grammar win;
import base;
path: DRIVE ('\' NAME)+ ('.' extension)?;
还有一个用于linux:
grammar linux;
import base;
path: ('/' NAME)+ ('.' extension)?;
现在我有两个不同的语法,它们有两个不同的解析器(WinParser和LinuxParser),它们与extension
具有完全独立的上下文。由于我想避免重复代码,我现在创建一个PathBaseBaseVisitor
,它对这个基本语法中定义的所有规则作出反应:
visitTxtExt
,visitTarExt
,visitGzExt
,visitCompositeExt
他们都只接受PathBaseParser.*Context
个对象。
这意味着当我为win
和linux
实施我的访问者时,其仅提供WinParser.*Context
和LinuxParser.*Context
(不是PathBaseParser
中的上下文的子类),我似乎无法通过在给定的ExtensionContext上调用PathBaseBaseVisitor
来实现我刚刚实现的visit()
。
有人知道如何解决这个问题吗?
我似乎唯一想到的就是在上下文中调用getText()
并用PathBaseParser
重新解析它,但这对我来说似乎很脏。
答案 0 :(得分:1)
要处理多种语法变体,正如您似乎要尝试的那样,您的目标应该是构造一个语法,该语法导入定义变体的规则子集。也就是说,在您的示例中,“base”应该是您的主要语法,导入的语法应该包含“path”规则。没有其他实用的方法可以避免遇到的继承问题。
可以肯定的是,如果变体的差异很大或者可能变得很大(例如Python 2 - > Python 3),维护相互依赖的语法的努力将很快超过感知的好处。相反,如果很小,您可以使用谓词来处理差异
path : { os().isWindows() }? DRIVE ('\' NAME)+ ('.' extension)?
| { os().isLinux() }? DRIVE ('/' NAME)+ ('.' extension)?
| ...
;