2010-08-12 16 views
10

我想在Boost.Spirit中編寫一個shell語言分析器。但是,我不清楚關於rule的語義的一些基本問題。boost :: spirit's rule <>的複製或引用語義?

查看文檔,有和r.copy()rule的成員。 IIUC,這些成員應該分別返回提及規則和規則內容的副本。但是,我沒有明確說明當我在另一個規則的定義中使用規則時會發生什麼。從我的實驗,我發現相互遞歸規則可以定義爲:

rule<Iter> r1, r2; 
r1 = ... >> r2 >> ...; 
r2 = ... >> r1 >> ...; 

這表明該規則採取解析表達式中引用。問題是,當變量超出作用域它有什麼作用,如:

rule<Iter> r1; 
{ 
    rule<Iter> r2; 
    r1 = ... >> r2 >> ...; 
    r2 = ... >> r1 >> ...; 
} 
... // use r1 

在相同的音符,將分配給從包含類型的規則工作的右值(r.copy()將是一個解析表達式規則rule類型的右值也是,是不是)?例如。

rule<Iter> f() { return char_('a') << char_('b'); } 
rule<Iter> r1 = ... << f(); 

有人可以告訴我關於rule的副本,並引用了詳細的語義,並可能糾正這個職位的任何誤解?

回答

13

答案取決於你所指的Spirit版本。


Spirit.Classic(以前的Spirit V1.x)爲規則實現特殊的複製語義。該文件說:

當規則在任何地方 引用的EBNF 表達的右手邊,該規則是由 表達參考舉行。客戶端的責任 確保 引用的規則停留在 範圍內,並且在被引用時不會被銷燬 。

賦值運算符本質上也引用rhs規則而不創建深層副本。這樣做是爲了讓:

rule<> r1, r2; 
r1 = ...; 
r2 = r1; 

但是,這被證明是非常混亂,因爲它防止處理規則的方式「正常」的對象相同。

因爲這個原因,有成員函數rule::copy(),允許明確規則的深層副本(例如將它們存儲在STL容器中)。

同時此:

r2 = r1.copy(); 

是完全錯誤的。 r2將指代從函數copy()返回的(破壞的)r1的臨時副本。


在Spirit.Qi(即Spirit V2.x)中,行爲被部分改變。規則現在在解析器之外處理時按預期行事。您可以將它們通常存儲在容器中(賦值運算符公開預期的行爲)。但要注意,一個解析器內則表達式規則仍然被引用,它仍然允許引用的規則相同的方式召開前:

rule<> r1, r2; 
r1 = ... >> r2 >> ...; 
r2 = ... >> r1 >> ...; 

有時有必要制定一條規則的深層副本,所以有仍然是會員functon copy

更改後的副本語義有另一個副作用。結構,如:

r1 = r2; 

現在正在創建的r2一(深)的副本,這可能不是你所期望的,特別是如果r2將只得到被「分配」到r1後指派其RHS。出於這個原因,有新的成員函數alias這個角落的情況下,允許對參考語義:

r1 = r2.alias(); 

在任何情況下,聖靈的兩個版本中,你將最終懸空引用如果規則中的一部分,從一個解析器引用表達超出了範圍。

順便說一句,既不Spirit版本實現功能rule::ref()

+0

感謝您的回答。我只是有一個後續問題:是否有可能在分析器表達式中使用某種類型的分析器表達式的rvalues(臨時值)以允許像'r1 = r1 |字符串(「abc」)或在函數中生成規則? – jpalecek 2010-08-13 21:09:58

+0

雖然表達式'r1 = r1 |字符串(「abc」)在理論上是可能的,它是一個左遞歸,當Spirit產生遞歸下降解析器時,這將導致無限遞歸。但是表達式'r1 = string(「abc」)| r1'將按預期工作。如果您確定它沒有引用任何超出範圍的其他規則,則可以在函數中生成規則。另外,在Spirit.Classic中,你需要從函數返回r.copy()。 – hkaiser 2010-08-13 23:30:58

+0

'r1 = string(「abc」)| r1'也是左遞歸:)但是我想要做的是讓r1匹配先前匹配的r1和「abc」。順便說一句如何在函數中生成規則?這對我不起作用:http://pastebin.org/482764 – jpalecek 2010-08-14 13:02:32

相關問題