Я экспериментирую с синтаксическим анализатором combinators, и я часто сталкиваюсь с тем, что походит на бесконечные рекурсии. Вот первый, с которым я столкнулся:
import util.parsing.combinator.Parsers
import util.parsing.input.CharSequenceReader
class CombinatorParserTest extends Parsers {
type Elem = Char
def notComma = elem("not comma", _ != ',')
def notEndLine = elem("not end line", x => x != '\r' && x != '\n')
def text = rep(notComma | notEndLine)
}
object CombinatorParserTest {
def main(args:Array[String]): Unit = {
val p = new CombinatorParserTest()
val r = p.text(new CharSequenceReader(","))
// does not get here
println(r)
}
}
Как я могу распечатать то, что продолжается? И почему это не заканчивается?
Регистрация попыток синтаксического анализа notComma
и notEndLine
показывает, что это конец файла (отображается как CTRL-Z в вывод журнала (...) ("mesg")), который повторно анализируется. Вот как я модифицировал ваш синтаксический анализатор для этой цели:
def text = rep(log(notComma)("notComma") | log(notEndLine)("notEndLine"))
Я не совсем уверен, что происходит (я пробовал много вариантов вашей грамматики), но я думаю, что это примерно так: EOF на самом деле не является символом, искусственно введенным в входной поток, а скорее своего рода постоянное условие в конце входа. Таким образом, этот никогда не использованный псевдосимвол EOF многократно анализируется как «либо не запятая, либо не конец строки».
Хорошо, я думаю, что разобрался. CharSequenceReader возвращает '\ 032' в качестве маркера конца ввода. Итак, если я изменю свой ввод таким образом, он будет работать:
import util.parsing.combinator.Parsers
import util.parsing.input.CharSequenceReader
class CombinatorParserTest extends Parsers {
type Elem = Char
import CharSequenceReader.EofCh
def notComma = elem("not comma", x => x != ',' && x!=EofCh)
def notEndLine = elem("not end line", x => x != '\r' && x != '\n' && x!=EofCh)
//def text = rep(notComma | notEndLine)
def text = rep(log(notComma)("notComma") | log(notEndLine)("notEndLine"))
}
object CombinatorParserTest {
def main(args:Array[String]): Unit = {
val p = new CombinatorParserTest()
val r = p.text(new CharSequenceReader(","))
println(r)
}
}
См. Исходный код для CharSequenceReader
здесь . Если бы скаладок упомянул об этом, это сэкономило бы мне много времени.