首页 > parboiled2,Scala 2.10 + 基於宏的PEG解析器生成器,下載parboiled2的源碼_GitHub

parboiled2,Scala 2.10 + 基於宏的PEG解析器生成器,下載parboiled2的源碼_GitHub

互联网 2021-04-20 06:27:20

parboiled2 - Scala 2.11 + 基於宏的PEG解析器生成器

這裡文檔的內容

簡介特性安裝工具示例快速入門如何解析解析器的輸入內容規則DSL規則規則類型和值堆棧基本字元匹配規則組合器和修飾符解析器操作失敗附加輔助對象錯誤報告錯誤錯誤 Collection 進程錯誤。格式分析錯誤調整錯誤報告錯誤atomic 標記quiet 標記命名規則手動錯誤報告失敗限制錯誤運行從分析錯誤中恢復先進技術。元規則常見錯誤忽略訂單選擇選項。使用句法謂詞時,不終止。未選中的可變狀態處理空白字元。解析整個輸入過程。語法調試工具對分析器的訪問結果的訪問結果:替代 DeliverySchemes運行示例替代組件parboiled2 vs-parboiled-1.xparboiled2 vs Scala 解析器parboiled2 vs 正規表達式路線圖。支持插件引用片尾許可協議簡介

parboiled2 是一個 Scala 2.11 + 庫,支持輕量級和 easy-to-use,但功能強大,快速,優雅地解析任意輸入文本。 它為解析表達式語法( ) 實現了基於宏的解析器生成器,它在編譯時運行,並將語法規則定義轉換為相應的JVM位元組碼。

stub是上下文無關語法的替代 alternative ( 成形) 用於正式指定語法,它們為 正規表達式 提供了良好的替代,並在構建解析器的過程中有一些優勢,通過構造解析器。

是 parboiled 1.x的後繼者,它提供類似的功能( 對於 Scala 以及 Java ),但實際上並不需要生成解析器a。 更確切地說,parboiled 1.x 根據輸入解釋規則樹結構( 它也是通過內部DSL創建的),這會導致解析性能下降。 有關如何使用 parboiled-1.x 和 parboiled2的詳細信息,請參見 parboiled2-vs-parboiled-1.x。 你可能還對讀取 parboiled2-vs Scala 解析器和 parboiled2-vs 正規表達式 感興趣。

特性簡潔。靈活和類型安全的DSL,用於表示解析邏輯充分表達解析表達式語法,以有效處理大多數真實世界的解析需求出色的分析錯誤報告解析性能與手寫解析器的性能比較易於學習和使用( 只需要一個解析階段( 不需要lexer代碼) ),更小的API輕量足夠作為 正規表達式的替換( 也嚴格強大於 voiceover )安裝

基於web的parboiled2的構件位於 Maven 中心,並且可以像這樣綁定到你的sbt中的Scala 項目中:

libraryDependencies +="org.parboiled"%%"parboiled"%"2.1.4"

最新發布的版本為 2.1.4。 它可以用於 Scala 2.11,Scala 2.12以及 Scala.js 0.6.

parboiled2 只有一個依賴項,它將可以傳遞到你的類路徑中: 無形狀的。

注意:如果項目也使用 "io.spray" %%"spray-routing",你將需要更改 "io.spray" %%"spray-routing-shapeless2" 為了使項目繼續生成,因為"常規"Spray 構建使用了無形 1. x.

在你的類路徑上,你可以使用這個單一導入將所需的所有內容放到作用域中:

importorg.parboiled2._

可能有更新的快照生成可用於位於位於以下位置的sonatype快照庫: https://oss.sonatype.org/content/repositories/snapshots/

你可以在這裡找到最新的: https://oss.sonatype.org/content/repositories/snapshots/org/parboiled/parboiled_2.11/ ( Scala 2.11 ) 和 https://oss.sonatype.org/content/repositories/snapshots/org/parboiled/parboiled_2.12/( Scala 2.12 )

示例

這就是一個簡單的parboiled2 解析器看起來像:

importorg.parboiled2._classCalculator(valinput:ParserInput) extendsParser { defInputLine= rule { Expression~EOI } defExpression:Rule1[Int] = rule { Term~ zeroOrMore( '+'~Term~> ((_: Int) + _) |'-'~Term~> ((_: Int) - _)) } defTerm= rule { Factor~ zeroOrMore( '*'~Factor~> ((_: Int) * _) |'/'~Factor~> ((_: Int) / _)) } defFactor= rule { Number|Parens } defParens= rule { '('~Expression~')' } defNumber= rule { capture(Digits) ~> (_.toInt) } defDigits= rule { oneOrMore(CharPredicate.Digit) }}newCalculator("1+1").InputLine.run() // evaluates to `scala.util.Success(2)`

這為簡單整數表達式( 如 1+(2-3*4)/5 ) 實現了解析器,並使用解析器在階段中運行實際計算。 如果你想看到它運行並親自嘗試,請查看運行示例。

快速啟動

parboiled2 解析器是從 org.parboiled2.Parser 派生的類,它定義一個抽象成員:

definput:ParserInput

保存解析運行的輸入。 通常,最好在構造函數( 如上面的示例所示) 中以 val 參數的形式實現。 從這個設計可以看出,你需要為每個解析運行實例創建一個新的解析器實例。

然後定義語法的"產品"( 或者"規則"),大多數情況下是由一個調用 rule 宏的簡單方法組成,它定義了規則的輸入,並定義了什麼動作的行為。

為了根據給定輸入運行解析器,你可以創建一個新實例,並在頂級規則 e.g 上調用 run():

valparser=newMyParser(input)parser.topLevelRule.run() // by default returns a ``scala.util.Try``

有關訪問解析運行結果的選項的詳細信息,請參閱訪問分析器結果的部分。

如何解析解析器的輸入值

因為解析理論的工作原理很容易構建解析器"手工",所以它們很容易理解,因為它們工作起來很容易理解: 遞歸下降。他們只有一個解析階段( 不是兩個,像大多數解析器產生的傳統解析器生成器,像 ANTLR。),不需要任何提前 look,在大多數真實世界場景中都能表現良好。

一個 解析器由許多邏輯組成,在邏輯上形成一個"樹",頂部調用零或者更低的規則,可以調用其它規則等等。 因為規則也可以調用自身或者任何父規則,規則"樹"實際上不是真正的樹,而是可能的循環圖,但大多數情況下,樹結構是有可能的,它有可能認為它是具有潛在循環功能的樹。

針對輸入緩衝區中的當前位置執行規則時,它將它的特定匹配邏輯應用到輸入,這可以成功或者失敗。 在成功案例中解析器將輸入輸入位置( 游標 ) 並潛在地執行下一個規則。 否則,當規則失敗,游標被重置,解析器backtracks在搜索可能成功的另一個解析替代文件時。

例如考慮這個簡單的parboiled2 規則:

deffoo= rule { 'a'~ ('b'~'c'|'b'~'d') }

當與輸入 abd 面對這裡規則時,解析器將按以下步驟輸入輸入:

規則 foo 開始執行,它調用它的第一個子規則 'a'。 游標位於位置 0.規則 'a' 針對輸入位置 0.MATCHES ( 成功) 執行,並將游標提升到 1位。規則 'b' ~ 'c' | 'b' ~ 'd' 開始執行,它調用它的第一個子規則 'b'~'c'。規則 'b'~'c' 開始執行,它調用它的第一個子規則 'b'。規則 'b' 針對輸入位置 1.MATCHES ( 成功) 執行,並將游標提升到 2位。規則 'c' 是針對輸入位置 2和不匹配( 失敗) 執行的。規則 'b' ~ 'c' | 'b' ~ 'd' 注意它的第一個子規則失敗,將游標重置為位置 1,並調用它的2nd 子規則 'b'~'d'。規則 'b'~'d' 開始執行,它調用它的第一個子規則 'b'。規則 'b' 針對輸入位置 1執行,MATCHES 和游標被提前定位到 2.規則 'd' 針對輸入位置 2執行,MATCHES 和游標被提前定位到 3。規則 'b'~'d' 成功完成,因為它的最後一個子規則已經成功。規則 'b' ~ 'c' | 'b' ~ 'd' 成功完成,因為它的一個子規則已經成功。規則 foo 成功完成執行,因為它的最後一個子規則已經成功。 整個輸入"abd"匹配,游標位於位置 3 ( 在最後匹配的字元之後)。規則DSL的規則

在有效地處理 parboiled2 你應該理解它的規則DSL背後的核心概念,主要是"值堆棧"和如何在 Scala 類型系統中編碼值堆棧操作。

規則類型和值堆棧

除了輸入緩衝區和游標之外,解析器還管理另一個重要結構: 這個值堆棧是一個簡單的堆棧構造,它為你的解析器動作的臨時存儲提供了臨時存儲。 在許多情況下,它用於在解析運行期間構造 AST,但是它也可以用於"在階段"計算( 比如在上面的示例中) 或者任何其他用途。

當基於規則的解析器的規則執行它執行以下三種情況的任意組合時:

匹配輸入,換句話說,前進輸入游標在值堆棧上操作,換句話說,彈出值和/或者將值推送到值堆棧執行副作用

匹配輸入是通過調用基本字元匹配規則完成的,該規則只執行輸入並前進,並將游標向前移動。 值堆棧操作( 還有其他潛在的副作用) 由解析器操作執行。

重要的是要理解 parboiled2 ( 例如 ) 中的規則。 解析器類中的規則方法不會直接返回一些自定義值作為方法結果。 相反,它們的所有消費和產生值都是對值堆棧的副作用。 因此,規則與值堆棧交互的方式編碼在規則的類型中。

這是對 parboiled2 規則的一般定義:

classRule[-I (i => i *2)

這導致 Rule1[Int] 將規則 foo的"輸出"乘以 2.

(foo: Rule2[Int, String]) ~> ((i, s) => s + i.toString)

這導致 Rule1[String] 將規則 foo ( 一個 Int 和一個 String )的兩個"輸出"合併成一個單一的String。

(foo: Rule2[Int, String]) ~> (_.toDouble)

這將導致 Rule2[Int, Double]。 可以看到 ~> 函數argument並不總是必須為它應用到的規則的完整輸出提供。 它也可以使用更少或者更多的元素。 它的參數只與值堆棧( 最右邊的參數匹配頂層元素)的頂部相對應。

(foo: Rule1[String]) ~> ((i :Int, s) => s + i.toString)

這導致了 Rule[Int :: HNil, String :: HNil] ,換句話說,a 從堆棧中彈出一個 Int 值並用 String 替換它的規則。 注意,如果可以與基礎規則的"輸出"匹配的參數類型可以推斷,那麼不是直接對應的參數。 在這些情況下,你需要向相應的動作函數 parameter(s) 添加一個顯式類型註釋。

如果操作函數返回 Unit,它不會在堆棧上推送任何內容。 所以這個規則

(foo: Rule1[String]) ~> (println(_))

類型為 Rule0。

此外,動作函數也可以是 Function0,換句話說,函數,不帶任何參數:

(foo: Rule1[String]) ~> (() =>42)

這裡規則具有類型 Rule2[String, Int],且等效于:

(foo: Rule1[String]) ~ push(42)

操作函數還可以通過返回 HList 實例產生多個輸出:

(foo: Rule1[String]) ~> (s => s.toInt ::3.14::HNil)

這裡類型為 Rule2[Int, Double]。

另外一個非常有用的特性是對實例類實例創建的特殊支持:

caseclassPerson(name: String, age: Int)(foo: Rule2[String, Int]) ~>Person

這有 Rule1[Person] 類型。值堆棧的頂部元素被彈出並被類的實例所取代,如果它們是 MATCH 類成員。 這對於構建 AST -like結構非常有用 ! 查看 Calculator2 示例以查看這裡表單的操作。

請注意,有一個怪癖: 出於某些原因,如果你顯式定義了事例類的輔助對象,則這裡符號將停止工作。 你得寫 ~> (Person(_, _)) 了。

還有 finally,還有一個更強大的動作類型: action函數本身可以返回一個規則 ! 如果某個操作返回規則,該規則立即在操作應用程序之後執行,就像它已經用 ~ 運算符連接到底層規則一樣。 因此,你可以這樣做

(foo: Rule1[Int]) ~> (i => test(i %2==0) ~ push(i))

它是一個 Rule1[Int],它只產生整數,並且對所有其他的都失敗。 或者,有些異常但仍完全合法:

capture("x") ~> (str(_))

它是一個與 'x'~'x' 相同的Rule0。

運行( 表達式)

run 是最通用的解析器操作。 它可以有多個形狀,具體取決於它的參數表達式的類型。 如果參數表達式計算為

規則( 例如。具有類型 R
免责声明:非本网注明原创的信息,皆为程序自动获取互联网,目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责;如此页面有侵犯到您的权益,请给站长发送邮件,并提供相关证明(版权证明、身份证正反面、侵权链接),站长将在收到邮件12小时内删除。