我正尝试在Haskell中将“操脑筋”解释器作为练习/娱乐项目来编写,但遇到了一个小问题。

Brainfuck的“ while循环”结构只是一系列放在方括号内的命令。我正在尝试以将运算符存储在[数据构造函数内部的循环内的方式来构建语法树。

这是命令和语法“ tree”的数据声明现在的样子:

data Operator = Plus
                | Minus
                | RShift
                | LShift
                | Dot
                | Comma
                | SBracket [Operator]
                | EBracket
                deriving (Show, Eq)


type STree = [Operator]


我想做的是采用String命令,例如"+><[.>]"并将其解析为如下所示的STree

[Plus, RShift, LShift, SBracket [Dot, RShift], EBracket]


到目前为止,我只能从String中获取一维列表,因为我不确定如何检查列表的开头是否为SBracket以便在其中添加新的运算符运算符列表,而不是主列表的开头。

这是我用来解析的函数:

matchChar :: Char -> Maybe Operator
matchChar c = case c of
                '+' -> Just Plus
                '-' -> Just Minus
                '>' -> Just RShift
                '<' -> Just LShift
                '.' -> Just Dot
                ',' -> Just Comma
                '[' -> Just (SBracket [])
                ']' -> Just EBracket
                _   -> Nothing

getChars :: [Char] -> STree
getChars str = foldr toOp [] str
    where
            toOp x acc = case matchChar x of
                            Just a -> a:acc
                            Nothing -> acc


我想做的是检查head acc是否为SBracket实例,如果是,则不要将新的Operator放在列表的前面,而是将其放在SBracketOperator之前清单。

我已经尝试过模式匹配(toOp x ((SBracket list):xs) = ...)以及试图显式检查列表的头(if head acc == SBracket ...),但是这些东西都不能正常工作。

任何帮助将是巨大的!

最佳答案

首先,我将SBracket [Operator]重新定义为Bracket STree并摆脱EBracket。然后,我将更改您的解析器以同时跟踪“当前STree”和父级列表。每次遇到括号时,您都将当前树推送到父列表中并创建新树。然后,当遇到尾括号时,您将当前树取下,用Bracket构造函数将其包裹起来,弹出第一个父树,将括号添加到末尾并成为当前树。



这是一个完全未经测试的版本(此组件上没有ghc),该版本可能会或可能不会起作用:

data Operator = Plus
                | Minus
                | RShift
                | LShift
                | Dot
                | Comma
                | Bracket [Operator]
                deriving (Show, Eq)

parse :: [Char] -> Either String [Operator]
parse str = parse' str [] []
  where parse' :: [Char] -> [Operator] -> [[Operator]] -> Either String [Operator]
        parse' [] context [] = Right (reverse context)
        parse' [] context _ = Left "unclosed []"
        parse' (']':cs) _ [] = Left "unexpected ]"
        parse' (c:cs) ctx stack
            | c == '+' = parse' cs (Plus:ctx) stack
            | c == '-' = parse' cs (Minus:ctx) stack
            | c == '>' = parse' cs (RShift:ctx) stack
            | c == '<' = parse' cs (LShift:ctx) stack
            | c == '.' = parse' cs (Dot:ctx) stack
            | c == ',' = parse' cs (Comma:ctx) stack
            | c == '[' = parse' cs [] (ctx:stack)
            | c == ']' = parse' cs (Bracket (reverse ctx):s) tack
            | otherwise = parse' cs ctx stack
          where (s:tack) = stack

关于haskell - 如何检查Haskell中的数据类型?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/11463512/

10-10 05:20