在运行时组合 Scala 解析器组合器
Composing scala parser combinators at runtime
我在这里看到了其他几个相关的 SO 帖子,建议使用特征继承是解决这个问题的唯一方法,但我在这里看不到如何使用它。
我正在编写一个汇编器,它有一个允许您更改处理器模型的指令,从而影响可解析的操作码集。我有两个解析器 类,一个处理所有指令关键字,一个处理指令。 (对于不同的处理器型号,会有更多)。当 'cpu' 指令被解析时,它会选择合适的指令解析器。这是一个非常简化的插图:
import scala.util.parsing.combinator.JavaTokenParsers
class ComposingParser {
sealed abstract class Statement {
}
case class Dinst(value: String) extends Statement
case class Keyword(value: String) extends Statement
class InstructionParser extends JavaTokenParsers {
def directOpcode: Parser[Statement] = j | ldlp | pfix
private def j: Parser[Dinst] = """(?i)J""".r ^^ ( x => Dinst(x.toUpperCase) )
private def ldlp: Parser[Dinst] = """(?i)LDLP""".r ^^ ( x => Dinst(x.toUpperCase) )
private def pfix: Parser[Dinst] = """(?i)PFIX""".r ^^ ( x => Dinst(x.toUpperCase) )
}
class KeywordParser extends JavaTokenParsers {
def program: Parser[Statement] = keys | instruction // the main, top-level parser
def keys: Parser[Keyword] = start | end
private def start: Parser[Keyword] = """(?i)START""".r ^^ ( x => Keyword(x.toUpperCase) )
private def end: Parser[Keyword] = """(?i)END""".r ^^ ( x => Keyword(x.toUpperCase) )
private def instruction: Parser[Statement] = {
val ip = new InstructionParser // will be dynamically instantiating different parsers for different instruction sets so can't use traits
ip.directOpcode
// Error:(46, 16) type mismatch;
// found : ip.Parser[ComposingParser.this.Statement]
// required: KeywordParser.this.Parser[ComposingParser.this.Statement]
// ip.directOpcode
}
// I can't use traits as in
// I can't see how to apply the solution from
// Is it possible to convert an 'ip.Parser[Statement]' into a 'KeywordParser.this.Parser[Statement]' ?
}
}
directOpcode 和 instruction 都是 returnParser[Statement],为什么我不能这样组合它们?自类型注释可以帮助解决这个问题吗?提前感谢您提供的任何帮助...(或显示引用的其他 SO 帖子中发布的解决方案如何提供帮助的插图)。
从问题来看,您 "cannot use traits" 的原因并不明显。至少您的具体示例确实可以很好地处理特征:
// uses `$ivy`-imports, either run with Ammonite, or remove the import and
// compile using SBT.
import $ivy.`org.scala-lang.modules:scala-parser-combinators_2.12:1.1.1`
import scala.util.parsing.combinator.JavaTokenParsers
class ComposingParser {
sealed abstract class Statement {
}
case class Dinst(value: String) extends Statement
case class Keyword(value: String) extends Statement
trait InstructionParser extends JavaTokenParsers {
def directOpcode: Parser[Statement] = j | ldlp | pfix
private def j: Parser[Dinst] = """(?i)J""".r ^^ ( x => Dinst(x.toUpperCase) )
private def ldlp: Parser[Dinst] = """(?i)LDLP""".r ^^ ( x => Dinst(x.toUpperCase) )
private def pfix: Parser[Dinst] = """(?i)PFIX""".r ^^ ( x => Dinst(x.toUpperCase) )
}
trait InstructionParser2 extends JavaTokenParsers {
def directOpcode2: Parser[Statement] = j | ldlp | pfix
private def j: Parser[Dinst] = """(?i)J""".r ^^ ( x => Dinst(x.toUpperCase) )
private def ldlp: Parser[Dinst] = """(?i)LDLP""".r ^^ ( x => Dinst(x.toUpperCase) )
private def pfix: Parser[Dinst] = """(?i)PFIX""".r ^^ ( x => Dinst(x.toUpperCase) )
}
class KeywordParser extends JavaTokenParsers
with InstructionParser
with InstructionParser2 {
def program: Parser[Statement] = keys | instruction // the main, top-level parser
def keys: Parser[Keyword] = start | end
private def start: Parser[Keyword] = """(?i)START""".r ^^ ( x => Keyword(x.toUpperCase) )
private def end: Parser[Keyword] = """(?i)END""".r ^^ ( x => Keyword(x.toUpperCase) )
private def instruction: Parser[Statement] = {
if (math.random < 0.5) directOpcode else directOpcode2
}
}
}
我在这里看到了其他几个相关的 SO 帖子,建议使用特征继承是解决这个问题的唯一方法,但我在这里看不到如何使用它。
我正在编写一个汇编器,它有一个允许您更改处理器模型的指令,从而影响可解析的操作码集。我有两个解析器 类,一个处理所有指令关键字,一个处理指令。 (对于不同的处理器型号,会有更多)。当 'cpu' 指令被解析时,它会选择合适的指令解析器。这是一个非常简化的插图:
import scala.util.parsing.combinator.JavaTokenParsers
class ComposingParser {
sealed abstract class Statement {
}
case class Dinst(value: String) extends Statement
case class Keyword(value: String) extends Statement
class InstructionParser extends JavaTokenParsers {
def directOpcode: Parser[Statement] = j | ldlp | pfix
private def j: Parser[Dinst] = """(?i)J""".r ^^ ( x => Dinst(x.toUpperCase) )
private def ldlp: Parser[Dinst] = """(?i)LDLP""".r ^^ ( x => Dinst(x.toUpperCase) )
private def pfix: Parser[Dinst] = """(?i)PFIX""".r ^^ ( x => Dinst(x.toUpperCase) )
}
class KeywordParser extends JavaTokenParsers {
def program: Parser[Statement] = keys | instruction // the main, top-level parser
def keys: Parser[Keyword] = start | end
private def start: Parser[Keyword] = """(?i)START""".r ^^ ( x => Keyword(x.toUpperCase) )
private def end: Parser[Keyword] = """(?i)END""".r ^^ ( x => Keyword(x.toUpperCase) )
private def instruction: Parser[Statement] = {
val ip = new InstructionParser // will be dynamically instantiating different parsers for different instruction sets so can't use traits
ip.directOpcode
// Error:(46, 16) type mismatch;
// found : ip.Parser[ComposingParser.this.Statement]
// required: KeywordParser.this.Parser[ComposingParser.this.Statement]
// ip.directOpcode
}
// I can't use traits as in
// I can't see how to apply the solution from
// Is it possible to convert an 'ip.Parser[Statement]' into a 'KeywordParser.this.Parser[Statement]' ?
}
}
directOpcode 和 instruction 都是 returnParser[Statement],为什么我不能这样组合它们?自类型注释可以帮助解决这个问题吗?提前感谢您提供的任何帮助...(或显示引用的其他 SO 帖子中发布的解决方案如何提供帮助的插图)。
从问题来看,您 "cannot use traits" 的原因并不明显。至少您的具体示例确实可以很好地处理特征:
// uses `$ivy`-imports, either run with Ammonite, or remove the import and
// compile using SBT.
import $ivy.`org.scala-lang.modules:scala-parser-combinators_2.12:1.1.1`
import scala.util.parsing.combinator.JavaTokenParsers
class ComposingParser {
sealed abstract class Statement {
}
case class Dinst(value: String) extends Statement
case class Keyword(value: String) extends Statement
trait InstructionParser extends JavaTokenParsers {
def directOpcode: Parser[Statement] = j | ldlp | pfix
private def j: Parser[Dinst] = """(?i)J""".r ^^ ( x => Dinst(x.toUpperCase) )
private def ldlp: Parser[Dinst] = """(?i)LDLP""".r ^^ ( x => Dinst(x.toUpperCase) )
private def pfix: Parser[Dinst] = """(?i)PFIX""".r ^^ ( x => Dinst(x.toUpperCase) )
}
trait InstructionParser2 extends JavaTokenParsers {
def directOpcode2: Parser[Statement] = j | ldlp | pfix
private def j: Parser[Dinst] = """(?i)J""".r ^^ ( x => Dinst(x.toUpperCase) )
private def ldlp: Parser[Dinst] = """(?i)LDLP""".r ^^ ( x => Dinst(x.toUpperCase) )
private def pfix: Parser[Dinst] = """(?i)PFIX""".r ^^ ( x => Dinst(x.toUpperCase) )
}
class KeywordParser extends JavaTokenParsers
with InstructionParser
with InstructionParser2 {
def program: Parser[Statement] = keys | instruction // the main, top-level parser
def keys: Parser[Keyword] = start | end
private def start: Parser[Keyword] = """(?i)START""".r ^^ ( x => Keyword(x.toUpperCase) )
private def end: Parser[Keyword] = """(?i)END""".r ^^ ( x => Keyword(x.toUpperCase) )
private def instruction: Parser[Statement] = {
if (math.random < 0.5) directOpcode else directOpcode2
}
}
}