本文介绍了如何将解析器与不同类型的 Elem 结合使用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试创建一个结合了 Regex 解析器和我拥有的自定义解析器的解析器.我看过 Scala:如何组合来自不同的解析器组合器对象,但该问题和答案涉及具有相同类型的 Elem 的解析器.

I'm trying to create a parser that combines Regex parsers and a custom parser I have. I've looked at Scala: How to combine parser combinators from different objects, but that question and answers deal with parsers that have the same type of Elem.

假设我有几个 RegexParsers,还有一个用于查找字符串的解析器:

Say I have a few RegexParsers, and also a parser that does a lookup for a String:

trait NumbersParsers extends RegexParsers {
  def number = """\d+""".r
}

trait LookupParsers extends Parsers {
  type Elem = String
  def word = elem("word", (potential:String) => dictionary.exists(_.equals(x))
}

如果我天真地结合这些解析器

If I combine these parsers naively

object MyParser extends NumbersParsers with RegexParsers {
  def quantitive = number ~ word
}

由于Elem 的不同类型,我显然会遇到类型错误.如何组合这些解析器?

I obviously get type errors because of the different types of Elem. How do I combine these parsers?

推荐答案

我觉得回答这个问题有点责任,因为我问并回答了 Scala:如何组合来自不同对象的解析器组合器.

I feel somewhat responsible for answering this one since I asked and answered Scala: How to combine parser combinators from different objects.

快速回答是,您不能组合不同类型的 Elem.解决此问题的另一种优雅方法是使用 ^? 来增加具有额外过滤功能的正则表达式解析器.

The quick answer would be, you can't combine different types of Elem. A different and elegant way to solve this problem uses ^? to augment a regex parser with extra filtering.

阅读编程中的 Combinator Parsing 可能会有所帮助斯卡拉:

It might be helpful to read up on Combinator Parsing in Programming in Scala:

有时,解析器读取令牌流而不是原始字符序列.然后使用单独的词法分析器将原始字符流转换为标记流.解析器输入的类型定义如下:

type Input = Reader[Elem]   

Reader 类来自 scala.util.parsing.input 包.它类似于 Stream,但也会跟踪它读取的所有元素的位置.Elem 类型表示单个输入元素.它是 Parsers trait 的抽象类型成员:

The class Reader comes from the package scala.util.parsing.input. It is similar to a Stream, but also keeps track of the positions of all the elements it reads. The type Elem represents individual input elements. It is an abstract type member of the Parsers trait:

type Elem

这意味着解析器的子类和子特征需要将 Elem 类实例化为正在解析的输入元素的类型.例如,RegexParsersJavaTokenParsersElem 固定为等于 Char.

This means that subclasses and subtraits of Parsers need to instantiate class Elem to the type of input elements that are being parsed. For instance, RegexParsers and JavaTokenParsers fix Elem to be equal to Char.

所以 Elem 被词法分析器使用,它负责将你的输入流分成解析器想要处理的最小可能的标记.既然要处理正则表达式,你的Elem就是Char.

So Elem is used by the lexical analyzer, which is responsible for chopping up your input stream into the smallest possible tokens that the parser wants to deal with. Since you want to deal with regular expression, your Elem is Char.

不过别担心.仅仅因为你的 lexer 给了你 Char 并不意味着你的 parser 也被它们困住了.RegexParsers 为您提供的是从正则表达式到 Parser[String] 的隐式转换器.您可以使用 ^^ 运算符(完全映射输入)和 ^? 运算符(部分映射输入)进一步转换它们.

But don't worry. Just because your lexer gives you Chars that doesn't mean your parser is stuck with them too. What RegexParsers gives you is an implicit converter from a regex to Parser[String]. You can further convert them using ^^ operator (fully maps input) and ^? operator (partially maps input).

让我们将它们合并到您的解析器中:

Let's incorporate them into your parsers:

import scala.util.parsing.combinator._

scala> val dictionary = Map("Foo" -> "x")
dictionary: scala.collection.immutable.Map[String,String] = Map(Foo -> x)

scala> trait NumbersParsers extends RegexParsers {
     |   def number: Parser[Int] = """\d+""".r ^^ { _.toInt }
     | }
defined trait NumbersParsers

scala> trait LookupParsers extends RegexParsers {
     |   def token: Parser[String] = """\w+""".r
     |   def word =
     |     token ^? ({
     |       case x if dictionary.contains(x) => x
     |     }, {
     |       case s => s + " is not found in the dictionary!"
     |     })
     | }
defined trait LookupParsers

scala> object MyParser extends NumbersParsers with LookupParsers {
     |   def quantitive = number ~ word
     |   
     |   def main(args: Array[String]) {
     |     println(parseAll(quantitive, args(0) ))
     |   }
     | }
defined module MyParser

scala> MyParser.main(Array("1 Foo"))
[1.6] parsed: (1~Foo)

scala> MyParser.main(Array("Foo"))
[1.1] failure: string matching regex `\d+' expected but `F' found

Foo
^

scala> MyParser.main(Array("2 Bar"))
[1.6] failure: Bar is not found in the dictionary!

2 Bar
     ^

这篇关于如何将解析器与不同类型的 Elem 结合使用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-22 09:05