2015-07-06 58 views
2

我正在使用Camlp4來解析量化關鍵字和變量之間用逗號分隔的一串量詞。一個例子是象下面這樣:使用Camlp4來解析一串通用和存在量詞

exists x,y,z, forall a,b, exists h,k 

這裏,existsforall是關鍵字,x,y,z,a,b,h,k是標識符。相應的令牌爲EXISTS,FORALLIDENTIFIER of string

我的數據結構:

type quantifier = 
    | Exists of string 
    | Forall of string 

爲了解析量詞上面的字符串,我的規則是:

id: [[ 
    `IDENTIFIER s-> s 
]]; 

one_kind_quantifiers: [[ 
    `EXISTS; il=LIST1 id SEP `COMMA -> List.map (fun v -> Exists v) il 
|`FORALL; il=LIST1 id SEP `COMMA -> List.map (fun v -> Forall v) il 
]]; 

quantifiers: [[ 
    t=LIST0 one_kind_quantifiers SEP `COMMA -> List.flatten t 
]]; 

然而,我的解析器總是拋出一個錯誤:

Stream.Error("[id] expected after COMMA (in [one_kind_quantifiers])"). 

你知道如何解決這個問題嗎?如何使LIST1`COMMA是關鍵字後檢測到元素時停止拋出錯誤?

非常感謝!

(有關詳細信息,如果我使用空格分開由同一量化關鍵字的影響變量,如exists x y z, forall a b, exists h k。而在one_kind_quantifiers規則刪除SEP `COMMA,那麼解析器可以完全解析這個新的字符串)。

===========================

更新的解決方案:

與伊戈爾建議(@ ygrek),我可以通過不使用LIST1編寫預期的解析器,而是手動編寫規則來解析字符串列表。

id_list: [[ 
    `IDENTIFIER s -> [s] 
|t=`id_list; `COMMA; `IDENTIFIER s -> [email protected][s] 
]]; 

one_kind_quantifiers: [[ 
    `EXISTS; il=id_list -> List.map (fun v -> Exists v) il 
|`FORALL; il=id_list -> List.map (fun v -> Forall v) il 
]]; 

quantifiers: [[ 
    t=LIST0 one_kind_quantifiers SEP `COMMA -> List.flatten t 
]]; 

注意,規則解析字符串列表是:

id_list: [[ 
    `IDENTIFIER s -> [s] 
| t=`id_list; `COMMA; `IDENTIFIER s -> [email protected][s] 
]]; 

但不是:

id_list: [[ 
    `IDENTIFIER s -> [s] 
| `IDENTIFIER s; `COMMA; t=`id_list -> [s]@t 
]]; 

id_list規則的第二種方法拋出相同的錯誤時使用LIST1。 (所以我猜這可能是LIST1的實現方式......)

回答

2

camlp4是遞歸下降解析器和IIRC它只會回溯到每個規則的第一個標記,一旦第一個標記匹配它將繼續到規則的結束。在這種情況下,對於LIST1,它可以在逗號上匹配,因此它會下降,但第二個標記不符合預期,並且回溯時間太晚。我想展開LIST1,並且將內聯插入到您的語法中將解決此問題,但可能會相當難看。

+0

謝謝伊戈爾的建議!你是對的!通過展開LIST1,我可以按預期編寫解析器。我在主線程中更新瞭解決方案。 –