4

より簡潔なコード例で最初に投稿されたので、質問を書き直しました。

完全にオプションのセミコロンを持つ言語をほぼ完全にシュガーとして考えてみましょう。

  • ;; foo; bar;;;;有効です
  • foo bar foobar有効です
  • if (+1); fooif (+1) fooはセマンティクスが異なるため、;空白と見なすことはできません

パーサーの例を次に示します。

{-# LANGUAGE OverloadedStrings #-}

import Text.Trifecta
import Text.Trifecta.Delta
import Text.PrettyPrint.ANSI.Leijen (putDoc, (<>), linebreak)
import Control.Monad.Trans.State.Strict
import Control.Applicative

type TestParser a = StateT Int Parser a

data AST a = Foo a | Bar a deriving (Show)

pFoo :: TestParser (AST (Delta, Int))
pFoo = curry Foo <$ string "foo" <*> position <* modify (+1) <*> get

pBar :: TestParser (AST (Delta, Int))
pBar = curry Bar <$ string "bar" <*> position <*> get

pStmt :: TestParser (AST (Delta, Int))
pStmt = semi *> pStmt <|> pFoo <|> pBar <?> "statement"

pTest :: TestParser [AST (Delta, Int)]
pTest = some pStmt

main :: IO ()
main
 = do   let res = parseByteString (evalStateT pTest 0)
                    (Directed "(test)" 0 0 0 0) ";;foo;bar;\nfoo;; foobarbar;;"
        case res of
            Success ast
             -> print ast
            Failure errdoc
             -> putDoc (errdoc <> linebreak)

このようなパーサーで私が抱えている問題は、pStmt. 現時点では、次のエラーが発生します。

(test):2:18: error: unexpected
    EOF, expected: statement
foo;; foobarbar;;<EOF>

これは、ステートメント (in semi *> pStmt) が必要なためですが、積み重ねられたセミコロンが式の最初と最後を砂糖漬けにする可能性があるため、すでに期待する前に本当に期待/解析したいのかどうか確信が持てません。

私が開発したハックの 1 つNopは、AST でコンストラクターとして使用することでしたが、実際にはそうしたくありません。ハックのように感じられ、ドキュメントによってはセミコロンの数が多いため、メモリ使用量が大幅に増加します。

解決策/提案を探しています。


目的の文法の EBNF 形式を試みます。

expr = "foo" | "bar"
expr with sugar = expr | ";"
program = { [white space], expr with sugar, [white space] }
4

1 に答える 1