我正在学习Scala中的Parser Combinators,并且看到了不同的解析方法。我主要看到三种不同类型的解析器,即.gegexpParsers,StandardTokenParsers和JavaTokenParsers。我是解析的新手,并不知道如何选择合适的Parser根据我们的要求。任何人都可以解释这些不同的解析器是如何工作的以及何时使用它们。
答案 0 :(得分:22)
出于不同的目的,有几种不同的解析器特征和基类。
主要特征是scala.util.parsing.combinator.Parsers
。这有大多数主要的组合器,如opt
,rep
,elem
,accept
等。绝对查看这个的文档,因为这是你的大部分内容需要知道。实际的Parser
类在这里被定义为内部类,这也很重要。
另一个重要特征是scala.util.parsing.combinator.lexical.Scanners
。这是解析器读取字符流并生成标记流(也称为词法分析器)的基本特征。为了实现这个特性,你需要实现一个whitespace
解析器,它可以读取空格字符,注释等。你还需要实现一个token
方法,它读取下一个标记。标记可以是您想要的任何内容,但它们必须是Scanners.Token
的子类。 Lexical
扩展Scanners
,StdLexical
扩展Lexical
。前者提供了一些有用的基本操作(如digit
,letter
),而后者实际上定义和修饰了常见的令牌(如数字文字,标识符,字符串,保留字)。您只需要定义delimiters
和reserved
,就可以获得对大多数语言有用的内容。令牌定义位于scala.util.parsing.combinator.token.StdTokens
。
一旦你有了词法分析器,就可以定义一个解析器来读取一个令牌流(由词法分子生成)并生成一个抽象语法树。分离词法分析器和解析器是一个好主意,因为您不需要担心语法中的空格或注释或其他复杂性。如果您使用StdLexical
,则可以考虑使用内置了解析器的scala.util.parsing.combinator.syntax.StdTokenPasers
将令牌转换为值(例如StringLit
转换为String
)。我不确定与StandardTokenParsers
的区别。如果您定义自己的令牌类,那么为简单起见,您应该使用Parsers
。
您明确询问了RegexParsers
和JavaTokenParsers
。 RegexParsers
是一个特征,它使用一个额外的组合符Parsers
扩展regex
,这完全符合您的预期。如果要使用正则表达式匹配标记,请将RegexParsers
混合到词法分析器中。 JavaTokenParsers
提供了一些解析器,它们从Java语法中提取令牌(如标识符,整数)但没有Lexical
或StdLexical
的令牌包。
总而言之,您可能需要两个解析器:一个读取字符并生成标记,另一个使用标记并生成AST。首先使用基于Lexical
或StdLexical
的内容。根据您是否使用Parsers
,使用基于StdTokenParsers
或StdLexical
的内容,具体取决于您是否使用{{1}}。
答案 1 :(得分:6)
RegexpParsers
允许您使用RE值(通常采用"re pattern".r
形式,但同样适用于任何其他Regex实例)。没有预定义的词汇作品(代币)。
JavaTokenParsers
定义了Java令牌的词汇制作:decimalNumber
,floatingPointNumber
,stringLiteral
,wholeNumber
,ident
(标识符)。
StandardTokenParsers
定义词汇制作“......用于简单的类Scala语言。它解析关键字和标识符,数字文字(整数),字符串和分隔符。”其成分实际上是在StdLexical
中定义的。