2016-05-10 47 views
0

我想了解將語義操作「附加」到解析器的準確含義,更準確地說,我想了解語義操作何時以及持續了多長時間解析器。以助推精神將語義操作附加到解析器

對於這一點,我稍微修改以下述方式升壓精神庫的employee.cpp例如:

1°/增加了一個函數print()其輸出僅跟蹤時它被稱爲:

void print(const struct employee & e) { std::cout << e.surname << "\n"} 

2°/在類employee_parser的構造的端部,我結合的print()功能到start解析器:

employee_parser() : employee_parser::base_type(start) 
    { 
     using qi::int_; 
     using qi::lit; 
     using qi::double_; 
     using qi::lexeme; 
     using ascii::char_; 

     quoted_string %= lexeme['"' >> +(char_ - '"') >> '"']; 

     start %= 
      lit("employee") 
      >> '{' 
      >> int_ >> ',' 
      >> quoted_string >> ',' 
      >> quoted_string >> ',' 
      >> double_ 
      >> '}' 
      ; 
     start[&print]; 
    } 

儘管我接到start解析器的語義動作print,如文檔中所述,但我始終不會調用print()函數。它接近語義動作需要附加在解析器的右端側定義,解析器出現在相同的定義。任何人都可以詳細解釋一下嗎?

回答

2

在精神,解析器是一個函數對象,並且在大多數情況下,這是爲了重載運營商允許你做出新的解析器,如>>等,返回不同函數對象,而比修改原文。

如果您曾經使用過java並且遇到過java的不可變字符串,那麼您可以將它看成是這樣的。

當你有像

rule1 = lit("employee"); 
rule2 = (rule1 >> lit(",") >> rule1) [ &print ]; 

表達所發生的事情是,一個新解析器對象產生並分配給變量規則2,並且解析器對象貼有語義動作。

實際上,表達式中的每個運算符都有一個新的臨時解析器對象。解析器構造時,開銷只有一次,它在解析時並不重要。

當你有

start[&print]; 

這就像生產被立即丟棄臨時值。它對start變量中的值沒有副作用。這就是打印從未被調用的原因。

如果它不這樣工作,那麼製作語法可能會複雜得多。

當你在靈氣中定義一個語法時,通常定義基本上是在語法對象的構造函數中完成的。首先給出規則的原型,指定它們的類型,船長等,然後逐個構造規則。在初始化之前,您必須確保您在另一個規則的定義中不使用規則。但是在初始化之後,它的大部分內容不會改變到所涉及的語法。 (儘管你可以修改諸如調試信息之類的東西。)

如果所有規則在初始化後都可能會發生變化,那麼他們都必須更新關於更改的其他規則,這會變得更加複雜。

您可能會想到,通過使規則存儲對彼此的引用而不是值來避免這種情況。但這意味着指針和動態分配afaik,並會更慢。根據我的理解,精神上的一點是它是表達式模板 - 所有這些「指針取消引用」都應該在編譯時解決。

+1

注意:我不是精神內部的專家,這正是我從閱讀文檔中學到並使用它的原因。如果有人能夠給我一個比我更深入的解釋,或者可以解決我的回答中的一些緊張情緒,我很樂意閱讀它。 –

+0

對我來說這很清楚 – Heyji

相關問題