Parsing 构造Scala解析器组合器代码的正确方法是什么?

Parsing 构造Scala解析器组合器代码的正确方法是什么?,parsing,scala,coding-style,formatting,Parsing,Scala,Coding Style,Formatting,因为Scala解析器库要求您对解析器进行子类化,这最终会给您留下一个特定的解析器实现,所以您似乎无法真正将其划分为多个类或对象,除非它们位于最初对解析器进行子类化的类的范围内。处理这个问题的正确方法是什么,这样我就不必一行有50个惰性VAL?您可以将不同的组件拆分为扩展同一父解析器类型的traits,然后将它们混合在一起创建最终的解析器。显然,一些解析器组合器将依赖于其他解析器组合器,但至少可以通过这种方式分解出基本的解析器(例如终端解析器)。您可能不想将其拆分为太多不同的类/特征,否则,如果代

因为Scala解析器库要求您对解析器进行子类化,这最终会给您留下一个特定的解析器实现,所以您似乎无法真正将其划分为多个类或对象,除非它们位于最初对解析器进行子类化的类的范围内。处理这个问题的正确方法是什么,这样我就不必一行有50个惰性VAL?

您可以将不同的组件拆分为扩展同一父
解析器类型的
trait
s,然后将它们混合在一起创建最终的解析器。显然,一些解析器组合器将依赖于其他解析器组合器,但至少可以通过这种方式分解出基本的解析器(例如终端解析器)。您可能不想将其拆分为太多不同的类/特征,否则,如果代码拆分为太多不同的文件,则可能很难分析解析器正在执行的操作。

就我个人而言,我认为这样做的方法是将所有代码都保存在一个类中,或者,如果有意义的话,创建一个继承层次结构来扩展概念,就像
JavaTokenParsers
扩展
RegexParsers
扩展
Parsers
一样。此外,通过从语法中分离词汇,使用标记化解析器也有一定的帮助

除此之外,把它放在一个地方:拆分语法会让理解成为噩梦。其余的所有类——AST类以及对它们进行操作的代码,都不需要保存在解析器中


现在,如果这真的不符合你的测试,你可以将它们分成特征,并使用自我类型在特征之间创建必要的依赖关系。你只需要给它们创建一个继承自所有trait的大类(或对象)。

这似乎是个好主意,但是当它们在继承解析器的类之外时,它们怎么能从父解析器继承呢?我有一组这样组织的解析器。有一个核心解析器扩展了
RegexParsers
,它包含了一系列解析器,用于语法中最基本的终端和非终端。所有其他特征都扩展了这一特征,因为它们是在这些终端和非终端的基础上构建的。我的最后一个解析器类扩展了核心解析器,并混合了一些其他解析器特性,形成了一个完整的解析器。@nnythm您看到了什么问题?trait可以从类继承。@DanielC.Sobral我认为当X扩展解析器时,X.Parser是私有的[X],但我只是尝试了一下,我错了。我想我现在明白了。你说的标记化解析器是什么意思?这是否意味着解析器对每种令牌类型都有单独的规则?@DaoWen我指的是不读取字符串,而是读取令牌的解析器。代币是由lexer生成的,lexer负责这些低级细节。这就是传统编译器的工作原理:lex+yacc。请参阅标准库中的json解析器以获取示例。@DanielC.Sobral,我尝试实现了这一点,但在创建单一继承层次结构时遇到了问题,因为类型解析不同,父.parser和子.parser被视为不同的类型。你怎么能用自我类型来解决这个问题?@nnythm你可能不相信这一点,但我甚至想不出是什么给你带来了问题。请给出示例和错误消息。@DanielC.Sobral你是对的,我只是在摆弄它,唯一给我带来问题的是我错误地使用了多重构造函数模式,我忘记了将我的对象移动到与它所构造的类相同的特性中。