Я пытаюсь разобрать синтаксис типа F #. Я начал писать грамматику [F] Parsec и столкнулся с проблемами, поэтому я упростил грамматику до этого:
type ::= identifier | type -> type
identifier ::= [A-Za-z0-9.`]+
После проблем с FParsec я переключился на Parsec, так как у меня есть полная глава книги, посвященная объяснению . Мой код для этой грамматики
typeP = choice [identP, arrowP]
identP = do
id <- many1 (digit <|> letter <|> char '.' <|> char '`')
-- more complicated code here later
return id
arrowP = do
domain <- typeP
string "->"
range <- typeP
return $ "("++domain++" -> "++range++")"
run = parse (do t <- typeP
eof
return t) "F# type syntax"
Проблема в том, что Parsec по умолчанию не возвращается, поэтому
> run "int"
Right "int"
-- works!
> run "int->int"
Left "F# type syntax"
unexpected "-"
expecting digit, letter, ".", "`" or end of input
-- doesn't work!
Первым делом я попытался изменить тип P:
typeP = choice [arrowP, identP]
Но это просто переполнение стека, потому что грамматика является леворекурсивной - typeP никогда не пытается identP
, потому что она продолжает пытаться arrowP
снова и снова. Затем я попробовал try
в разных местах, например:
typeP = choice [try identP, arrowP]
Но, похоже, ничто из того, что я делаю, не меняет базового поведения (1) переполнения стека или (2) непризнания "->" после идентификатора.
Моя ошибка, вероятно, очевидна для любого, кто успешно написал грамматику Парсека. Кто-нибудь может указать на это?