是否有一種方便的方式使用Scala的解析器組合器來解析縮進顯着的語言? (例如Python)的使用Scala解析器組合器解析基於縮進的語言
6
A
回答
5
假設我們有一個非常簡單的語言,其中這是一個有效的程序
block
inside
the
block
,我們希望與塊內每行一個String
解析成List[String]
這一點。
我們首先定義一個方法,該方法採用最小縮進級別並返回具有該縮進級別的行的解析器。
def line(minIndent:Int):Parser[String] =
repN(minIndent + 1,"\\s".r) ~ ".*".r ^^ {case s ~ r => s.mkString + r}
然後,我們通過在行之間用合適的分隔符重複行解析器來定義具有最小縮進級別的塊。
def lines(minIndent:Int):Parser[List[String]] =
rep1sep(line(minIndent), "[\n\r]|(\n\r)".r)
現在,我們可以定義一個解析器爲我們這樣的小語:
val block:Parser[List[String]] =
(("\\s*".r <~ "block\\n".r) ^^ { _.size }) >> lines
它首先確定當前縮進級別,然後傳遞,作爲最小的線解析器。讓我們測試一下:
val s =
"""block
inside
the
block
outside
the
block"""
println(block(new CharSequenceReader(s)))
而我們得到
[4.10] parsed: List( inside, the, block)
對於這一切來編譯,你需要這些進口
import scala.util.parsing.combinator.RegexParsers
import scala.util.parsing.input.CharSequenceReader
而且你需要把一切都變成一個擴展的對象RegexParsers
像這樣
object MyParsers extends RegexParsers {
override def skipWhitespace = false
....
1
從我所知,不,Scala解析器組合器不支持這種開箱即用的東西。您當然可以通過以有意義的方式解析空白區域來做到這一點,但由於您需要某種形式的狀態機來跟蹤縮進堆棧,因此您會遇到一些問題。
我會推薦做一個預處理步驟。這裏是一個小預處理這增加標記來分隔縮進塊:
object Preprocessor {
val BlockStartToken = "{"
val BlockEndToken = "}"
val TabSize = 4 //how many spaces does a tab take
def preProcess(text: String): String = {
val lines = text.split('\n').toList.filterNot(_.forall(isWhiteChar))
val processedLines = BlockStartToken :: insertTokens(lines, List(0))
processedLines.mkString("\n")
}
def insertTokens(lines: List[String], stack: List[Int]): List[String] = lines match {
case List() => List.fill(stack.length) { BlockEndToken } //closing all opened blocks
case line :: rest => {
(computeIndentation(line), stack) match {
case (indentation, top :: stackRest) if indentation > top => {
BlockStartToken :: line :: insertTokens(rest, indentation :: stack)
}
case (indentation, top :: stackRest) if indentation == top =>
line :: insertTokens(rest, stack)
case (indentation, top :: stackRest) if indentation < top => {
BlockEndToken :: insertTokens(lines, stackRest)
}
case _ => throw new IllegalStateException("Invalid algorithm")
}
}
}
private def computeIndentation(line: String): Int = {
val whiteSpace = line takeWhile isWhiteChar
(whiteSpace map {
case ' ' => 1
case '\t' => TabSize
}).sum
}
private def isWhiteChar(ch: Char) = ch == ' ' || ch == '\t'
}
執行此文給:
val text =
"""
|line1
|line2
| line3
| line4
| line5
| line6
| line7
| line8
| line9
|line10
| line11
| line12
| line13
""".stripMargin
println(Preprocessor.preProcess(text))
...以下結果
{
line1
line2
{
line3
line4
line5
{
line6
line7
}
}
{
line8
line9
}
line10
{
line11
line12
line13
}
}
而且後記你可以使用combinator庫以更簡單的方式進行解析。
希望這會有幫助
相關問題
- 1. 使用Scala解析器組合器解析句子
- 2. 使用parsimmon庫解析基於縮進的語言
- 3. 有使用Scala組合子解析器
- 4. 如何進一步改善基於Scala語法分析器 - 組合器的解析器中的錯誤消息?
- 5. scala解析器組合器stackoverflow遞歸
- 6. Scala解析器組合器:有效地解析C-Style註釋
- 7. 使用Scala/SBT解析器組合器重複依賴解析器
- 8. scala的解析器組合器可以解析二進制文件嗎?
- 9. Scala的解析器組合:提取型
- 10. Scala的解析器組合減少/ foldLeft
- 11. EBNF Scala的解析器組合
- 12. 的Symfony建於語言解析器
- 13. 編寫混合語言解析器
- 14. DOT語言解析器
- 15. Scala:使用Scala的組合器解析多個文件
- 16. 解析器組合器 - 簡單語法
- 17. 在Scala語法分析器組合器中沒有排序解析器
- 18. 斯卡拉句子解析使用解析器組合器
- 19. 在Haskell中使用解析器組合器庫編寫的分析解析器
- 20. 語法,Scala解析組合器和無序集合
- 21. F#解析器組合器
- 22. Scala的解析器組合基於計算器,也可以採取dataRecord
- 23. Scala的:自定義語法/解析器組合
- 24. 組合的解析器/解析器生成器
- 25. 是否有用於構建合金語言解析器的外部解析器生成器工具
- 26. 多語言解析器生成器
- 27. 語義定向解析器組合
- 28. Scala的解析器組合,二義性文法與剖析林
- 29. 通用標記語言解析器
- 30. scala解析器。日誌解析器實用程序的輸出
使用'override val skipWhitespace = false' – senia