2

Camlp4 を使用して、量化キーワードと変数がコンマで区切られた量指定子の文字列を解析しています。一例を以下に示します。

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

ここで、existsforallはキーワードでx,y,z,a,b,h,kあり、識別子です。対応するトークンはEXISTSFORALLおよびIDENTIFIER 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を削除すると、パーサーはこの新しい文字列を完全に解析できます)。SEP `COMMAone_kind_quantifiers

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

ソリューションの更新:

Igor (@ygrek) からの提案により、LIST1 を使用せずに手動で文字列のリストを解析するルールを作成することで、予想されるパーサーを作成することができました。

id_list: [[
  `IDENTIFIER s -> [s]
 |t=`id_list; `COMMA; `IDENTIFIER s -> t@[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 -> t@[s]
]];

だがしかし:

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

ルールを記述する2 番目の方法ではid_list、 を使用した場合と同じエラーがスローされますLIST1。(だから私は多分それLIST1が実装されている方法だと思います...)

4

1 に答える 1

2

camlp4 は再帰降下パーサーであり、IIRC は各ルールの最初のトークンでのみバックトラックします。最初のトークンが一致すると、ルールの最後まで続行します。この場合、LIST1コンマで一致する可能性があるため、下降しますが、2 番目のトークンは期待どおりではなく、バックトラックするには遅すぎます。LIST1文法を展開してインライン化すると、この問題を回避できると思いますが、おそらくかなり醜いでしょう。

于 2015-07-09T23:36:21.757 に答える