コメントの削除
Posted feedbacks - Haskell
α置換の時に使ったパーサーがコメントを読み落としてしまうことを利用しました。もっと単純に文字列のパースでもできるはずですが、既存のソースに手を加えればできるということで…
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | module Main where
import Language.Haskell.Syntax
import Language.Haskell.Parser
import Language.Haskell.Pretty
import Data.Generics
pp :: ParseResult HsModule -> String
pp (ParseOk hsm) = prettyPrint hsm
pp _ = "parse failed"
main :: IO ()
main
= do mod <- getContents
putStr $ pp $ parseModule mod
|
おもいっきりベタな実装してみました。もしかすると抜けている部分があるかもしれません…。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | decomment :: String -> String
decomment s = decommentNormal s
where
decommentNormal [] = []
decommentNormal ('\'':'"':'\'':cs) = '\'':'"':'\'':(decommentNormal cs)
decommentNormal ('\'':'\\':'"':'\'':cs) = '\'':'\\':'"':'\'':(decommentNormal cs)
decommentNormal ('"':cs) = '"':(decommentQuote cs)
decommentNormal ('-':'-':cs) = decommentCommentLine cs
decommentNormal ('{':'-':cs) = decommentCommentBlock 0 cs
decommentNormal (c:cs) = c:(decommentNormal cs)
decommentQuote ('"':cs) = '"':(decommentNormal cs)
decommentQuote ('\\':'"':cs) = '\\':'"':(decommentQuote cs)
decommentQuote (c:cs) = c:(decommentQuote cs)
decommentCommentLine ('\n':cs) = '\n':(decommentNormal cs)
decommentCommentLine (_:cs) = decommentCommentLine cs
decommentCommentBlock 0 ('-':'}':cs) = '\n':(decommentNormal cs)
decommentCommentBlock n ('-':'}':cs) = decommentCommentBlock (n-1) cs
decommentCommentBlock n ('{':'-':cs) = decommentCommentBlock (n+1) cs
decommentCommentBlock n (c:cs) = decommentCommentBlock n cs
main = getContents >>= putStrLn.decomment
|
ちょっと長いけど,Haskell, C, C++ 対応のつもり,
CommentStyleクラスとQuoteStyleクラスを使って,いろいろな言語に対応できるように工夫してみた.
- commentLeadings メソッドは一行コメントの開始マーク(複数可)文字列を返すメソッド
- commentOpenings メソッドはブロックコメントの開始マーク(複数可)文字列を返すメソッド
- commentClosing メソッドは与えられたブロックコメントの開始マークに対応する修了マークを返すメソッド
- commentNestable はブロックコメントがネスト可能かどうかを返すメソッド
など.
- 文字列リテラル
- ブロックコメントのネスト
に対応する.厳密にやるには,その言語のパーザを読んで結果の構文木データを,プリティプリンタ(自作することになる)に食わせるのかな.めんどうだけど...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 | {-# LANGUAGE EmptyDataDecls #-}
module Main (main) where
import Control.Arrow
import Data.Char
import Data.List
import Data.Maybe
import System.Environment
main :: IO ()
main = interact . genDecomment . listToMaybe . map (map toLower) =<< getArgs
genDecomment :: Maybe String -> String -> String
genDecomment (Just "c") = decomment cstyle
genDecomment (Just "c++") = decomment cppstyle
genDecomment _ = decomment hstyle
class CommentStyle c where
commentLeadings :: c -> [String]
commentOpenings :: c -> [String]
commentClosing :: c -> String -> String
commentNestable :: c -> Bool
class QuoteStyle q where
quoteOpenings :: q -> [Char]
quoteClosing :: q -> Char -> Char
quoteEscape :: q -> Char
splitWithPrefix :: Eq a => [a] -> [a] -> Maybe ([a],[a])
splitWithPrefix [] xs = Just ([],xs)
splitWithPrefix (p:ps) xxs@(x:xs)
| p == x = splitWithPrefix ps xs >>= return . ((x:) *** id)
| otherwise = Nothing
splitQuoted :: Eq a => a -> a -> [a] -> ([a], [a])
splitQuoted esc qm [] = ([],[])
splitQuoted esc qm (c:cs)
| c == qm = ([],cs)
| c == esc = case cs of
[] -> ([c],[])
c':cs' -> ((c:).(c':) *** id) $ splitQuoted esc qm cs'
| otherwise = ((c:) *** id) $ splitQuoted esc qm cs
decomment :: (CommentStyle s, QuoteStyle s) => s -> String -> String
decomment s "" = ""
decomment s ccs@(c:cs) = case mapMaybe (flip splitWithPrefix ccs) $ commentLeadings s of
(_,xs):_ -> decomment s $ snd $ break ('\n'==) xs
[] -> case mapMaybe (flip splitWithPrefix ccs) $ commentOpenings s of
(p,xs):_ -> decommentC s [p] xs
[] -> if elem c (quoteOpenings s) then c:decommentQ s c cs
else c:decomment s cs
decommentC :: (CommentStyle s, QuoteStyle s) => s -> [String] -> String -> String
decommentC s [] xs = ' ':decomment s xs
decommentC s pps@(p:ps) xxs@(x:xs)
| commentNestable s = case splitWithPrefix (commentClosing s p) xxs of
Just (_,ys) -> decommentC s ps ys
Nothing -> case mapMaybe (flip splitWithPrefix xxs) $ commentOpenings s of
[] -> decommentC s pps xs
(p',yys):_ -> decommentC s (p':pps) yys
| otherwise = case mapMaybe (splitWithPrefix (commentClosing s p)) $ tails xs of
(_,ys):_ -> ' ':decomment s ys
[] -> ""
decommentQ :: (CommentStyle s, QuoteStyle s) => s -> Char -> String -> String
decommentQ s c xs = case splitQuoted (quoteEscape s) (quoteClosing s c) xs of
(ys,zs) -> ys ++ '"':decomment s zs
data Haskell
hstyle :: Haskell
hstyle = undefined
instance CommentStyle Haskell where
commentLeadings = const ["--"]
commentOpenings = const ["{-"]
commentClosing = const (\ "{-" -> "-}")
commentNestable = const True
instance QuoteStyle Haskell where
quoteOpenings = const ['"']
quoteClosing = const (\ '"' -> '"')
quoteEscape = const '\\'
data C
cstyle :: C
cstyle = undefined
instance CommentStyle C where
commentLeadings = const []
commentOpenings = const ["/*"]
commentClosing = const (\ "/*" -> "*/")
commentNestable = const False
instance QuoteStyle C where
quoteOpenings = const ['"']
quoteClosing = const (\ '"' -> '"')
quoteEscape = const '\\'
data CPlusPlus
cppstyle :: CPlusPlus
cppstyle = undefined
instance Show CPlusPlus where
show = const "C++"
instance CommentStyle CPlusPlus where
commentLeadings = const ["//"]
commentOpenings = const ["/*"]
commentClosing = const (\ "/*" -> "*/")
commentNestable = const False
instance QuoteStyle CPlusPlus where
quoteOpenings = const ['"']
quoteClosing = const (\ '"' -> '"')
quoteEscape = const '\\'
|
ここまでParsecなし、と
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | module Main where
import Text.ParserCombinators.Parsec
decommentParser :: CharParser st String
decommentParser = try (eof >> return "") <|> do
c <- anyChar
case c of
'{' -> anyChar >>= f skips1 c
'-' -> anyChar >>= f (manyTill (noneOf "\n") (char '\n')) c
_ -> decommentParser >>= return . ((:) c)
where skips1 = do
c <- anyChar
case c of
'-' -> anyChar >>= \x -> if x == '}' then return "" else skips1
_ -> skips1
f g c x = if x == '-' then g >> decommentParser
else decommentParser >>= \xs -> return $ c:x:xs
decomment content = parse decommentParser "decomment" content
main = do
content <- readFile "test.hs"
case decomment content of
Left e -> print e
Right s -> mapM_ putStrLn $ lines s
|



nobsun
#6534()
Rating-1/5=-0.20
[ reply ]