から最新のコンパイラ実装であるのTiger言語用のパーサを作成しようとしています。再帰型の1つに固執しています。sum-type inifinite再帰における左回帰文法の解析
私は次の文法では、次のタイプ
data LValue =
Id Atom
| RecordAccess LValue Atom
| ArraySubscript LValue Expression
あります
lvalue -> id
-> lvalue.id
-> lvalue[exp]
id -> atom
exp -> (the big, overarching, everything-is-an-expression type)
をそして私はParsecのとそれを解析しようとしているが、私は無限再帰ループで立ち往生しています。ここに私の現在のベースのパーサーです:
lvalueParser :: Parsec String() LValue
lvalueParser =
try (Id <$> (atomParser <* (notFollowedBy (char '.'))))
<|> try recordAccessParser
where recordAccessParser = (uncurry RecordAccess) <$> do {
record <- lvalueParser;
char '.';
atom <- atomParser;
return (record, atom)
}
(注:私はまだArrayAccess
部分を処理するために何かを実装しようとしていない)
明らかに、無限loopinessがlvalueParser
に戻ったときにrecordAccessParser
電話をたまたま。
私はthusly recordAccessParser
を変更することができます。
recordAccessParser = (uncurry RecordAccess) <$> do {
record <- atomParser;
char '.';
atom <- atomParser;
return (Id record, atom)
}
、それが終了します。しかし、それは深い単一レベルよりも多くのレコードアクセス解析を行いません。
Parsec.parse lvalueParser "" "record_1.field_1.field_2"
#=> RecordAccess (Id record_1) (Id field_1)
をそして私は、私はchainl1
に見えたが、連鎖パーサのタイプはa -> a -> a
で、doesnのこと
#=> RecordAccess (RecordAccess (Id record_1) (Id field_1)) (Id field_2)
を期待します文法を反映するLValue
の種類に一致しません。私はまたmany
を見た;しかし、私は各用語の定数プレフィックスを持っていません - 左の再帰用語は、私が結果の型の一部に解析しようとしているものです。
私はParsec/Parsingの具体的な概念が不足していて、正しい方向を指していると思っています。言語の中には、これと同じ構文を持つパーサーを作成する他のタイプもあります。
:最初に別の文法を使用して構文解析し、目的の文法を反映するように構文解析ツリーを修正します。 – rici