{-# LANGUAGE LambdaCase #-} module BNFC.Backend.C.RegToFlex (printRegFlex) where -- modified from pretty-printer generated by the BNF converter import Data.Char (ord, showLitChar) import qualified Data.List as List import BNFC.Abs import BNFC.Backend.Common (flexEps) -- the top-level printing method printRegFlex :: Reg -> String printRegFlex = render . prt 0 -- you may want to change render and parenth render :: [String] -> String render = rend (0::Int) where rend i ss = case ss of "[" :ts -> cons "[" $ rend i ts "(" :ts -> cons "(" $ rend i ts t : "," :ts -> cons t $ space "," $ rend i ts t : ")" :ts -> cons t $ cons ")" $ rend i ts t : "]" :ts -> cons t $ cons "]" $ rend i ts t :ts -> space t $ rend i ts _ -> "" cons s t = s ++ t space t s = if null s then t else t ++ s parenth :: [String] -> [String] parenth ss = ["("] ++ ss ++ [")"] -- the printer class does the job class Print a where prt :: Int -> a -> [String] prPrec :: Int -> Int -> [String] -> [String] prPrec i j = if j prPrec i 2 (concat [prt 2 reg0 , prt 3 reg]) RAlt reg0 reg -> prPrec i 1 (concat [prt 1 reg0 , ["|"] , prt 2 reg]) -- Flex does not support set difference. See link for valid patterns. -- https://westes.github.io/flex/manual/Patterns.html#Patterns -- RMinus reg0 reg -> prPrec i 1 (concat [prt 2 reg0 , ["#"] , prt 2 reg]) RMinus reg0 REps -> prt i reg0 -- REps is identity for set difference RMinus RAny (RChar c) -> [ concat [ "[^", escapeChar c, "]" ] ] RMinus RAny (RAlts str) -> [ concat [ "[^", concatMap escapeChar str, "]" ] ] -- FIXME: unicode inside brackets [...] is not accepted by flex -- FIXME: maybe we could add cases for char - RDigit, RLetter etc. RMinus _ _ -> error "Flex does not support general set difference" RStar reg -> concat [ prt 3 reg , ["*"] ] RPlus reg -> concat [ prt 3 reg , ["+"] ] ROpt reg -> concat [ prt 3 reg , ["?"] ] REps -> [ flexEps ] RChar c -> [ escapeChar c ] -- Unicode characters cannot be inside [...] so we use | instead. RAlts str -> prPrec i 1 $ List.intersperse "|" $ map escapeChar str -- RAlts str -> concat [["["], prt 0 $ concatMap escapeChar str, ["]"]] RSeqs str -> prPrec i 2 $ map escapeChar str RDigit -> [ "{DIGIT}" ] RLetter -> [ "{LETTER}" ] RUpper -> [ "{CAPITAL}" ] RLower -> [ "{SMALL}" ] RAny -> [ "." ] -- | Handle special characters in regular expressions. escapeChar :: Char -> String escapeChar c | c `elem` reserved = '\\':[c] | let x = ord c, x >= 256 = [c] -- keep unicode characters -- "\x" ++ showHex x "" | otherwise = showLitChar c "" where reserved :: String reserved = "$+-*=<>[](){}!?.,;:^~|&%#/\\$_@\""