Составление комбинаторов парсера Скала во время выполнения
Я видел несколько других сообщений 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 https://stackru.com/questions/2650254/scala-how-to-combine-parser-combinators-from-different-objects
// I can't see how to apply the solution from https://stackru.com/questions/40166258/reuse-parser-within-another-parser-with-scala-parser-combinators
// Is it possible to convert an 'ip.Parser[Statement]' into a 'KeywordParser.this.Parser[Statement]' ?
}
}
DirectOpcode и инструкция оба возвращают Parser[Statement], почему я не могу их так скомбинировать? Могут ли здесь помочь аннотации самопечатания? Заранее благодарим за любую помощь, которую вы можете предоставить... (или иллюстрации, показывающие, как могут помочь решения, опубликованные в других цитируемых публикациях SO).
1 ответ
Из вопроса не очевидно, почему вы "не можете использовать черты". По крайней мере, ваш конкретный пример отлично работает с чертами:
// 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
}
}
}