Parsing 什么是适当的数据结构或算法,用于以功能纯方式生成不可变的具体语法树?

Parsing 什么是适当的数据结构或算法,用于以功能纯方式生成不可变的具体语法树?,parsing,language-agnostic,data-structures,functional-programming,state-machine,Parsing,Language Agnostic,Data Structures,Functional Programming,State Machine,给定一个LL(1)语法,什么是一个合适的数据结构或算法,用于以纯功能的方式生成一个不可变的具体语法树?请随意用您喜欢的任何语言编写示例代码 我的想法 symbol : either a token or a node result : success or failure token : a lexical token from source text value -> string : the value of the token type -> integer : the

给定一个LL(1)语法,什么是一个合适的数据结构或算法,用于以纯功能的方式生成一个不可变的具体语法树?请随意用您喜欢的任何语言编写示例代码

我的想法

symbol : either a token or a node result : success or failure token : a lexical token from source text value -> string : the value of the token type -> integer : the named type code of the token next -> token : reads the next token and keeps position of the previous token back -> token : moves back to the previous position and re-reads the token node : a node in the syntax tree type -> integer : the named type code of the node symbols -> linkedList : the symbols found at this node append -> symbol -> node : appends the new symbol to a new copy of the node 请注意

我会悬赏给你最好的答案,所以别着急。与显示代码或包含详细解释的答案相比,仅发布链接的答案的权重更小

最后一个音符

我对这种东西真的很陌生,所以不要害怕叫我傻瓜。

埃里克·利珀特的可能会有帮助。显然,您需要一个不是二进制的树,但它会给您一个大致的想法。

您想要将某些东西解析成一个抽象语法树

在纯函数式编程语言Haskell中,可以使用解析器组合器来表示语法。下面是一个解析微小表达式语言的示例:

编辑使用一元风格匹配格雷厄姆·赫顿的书

    -- import a library of *parser combinators*
import Parsimony
import Parsimony.Char
import Parsimony.Error
(+++) = (<|>)

    -- abstract syntax tree
data Expr = I Int
          | Add Expr Expr
          | Mul Expr Expr
          deriving (Eq,Show)

    -- parse an expression
parseExpr :: String -> Either ParseError Expr
parseExpr = Parsimony.parse pExpr
    where

        -- grammar
    pExpr :: Parser String Expr
    pExpr = do
        a <- pNumber +++ parentheses pExpr  -- first argument
        do
            f <- pOp                        -- operation symbol
            b <- pExpr                      -- second argument
            return (f a b)
         +++ return a                       -- or just the first argument

    parentheses parser = do                 -- parse inside parentheses
        string "("
        x <- parser
        string ")"
        return x

    pNumber = do                            -- parse an integer
        digits <- many1 digit
        return . I . read $ digits

    pOp =                                   -- parse an operation symbol
         do string "+"
            return Add
        +++ 
         do string "*"
            return Mul
要了解有关解析器组合器的更多信息,请参见“真实世界Haskell”或的第8章


许多解析器组合器库可以与不同的令牌类型一起使用,正如您所希望的那样。令牌流通常表示为令牌列表
[Token]

请查看一元解析器组合器方法;我在博客上写过这方面的内容。

自下而上的树有什么问题?@Ira-你告诉我,我对这一切都不熟悉。因为猜测以前的知识很难,你可能想对答案发表评论并要求澄清。@Heinrich-我计划这样做,只是需要一些时间来处理信息。我必须承认,这对我来说很难理解。在我的脑海中,我想象着一个状态机沿着延续传递,但我肯定需要一些时间来理解这一点。这里的关键是,你不再需要实现状态机或其他东西,它已经在解析器组合器库中为你实现了一个its
解析器标记一个
类型。您可以抽象地指定语法,让库知道如何处理它。@Heinrich-理解主题有两种方法(在本例中是语法/解析器/编译器)。第一种方法就是要足够聪明,不费吹灰之力就能理解它(这就是我在决定学习高级计算机科学之前的工作方式)。一旦我发现自己不是那么聪明,我决定我能学会这一点的唯一方法是通过第二种方法。第二种方法是简单的奉献。从那时起,我已经编写了4个ECMAScript解析器,随着我学习新技术,每一个解析器都会越来越好。然而,它们都是必需的。@Heinrich-如果我能从头到尾完成一个功能上纯粹的解析器,我将把它视为我学习经验的顶点。之后,我将开始详细研究我可以使用的工具和库。如果我直接跳进图书馆,我觉得我可能是在欺骗自己。你对学习的杰出贡献最好由一本好书来补充。:-)在你的情况下,我强烈建议你从图书馆或电子设备上获取格雷厄姆·赫顿的书。它介绍了Haskell中的一般树类型,并对解析器组合器及其实现进行了非常清晰的解释。也有基于该书的视频讲座,请访问其网站。我将更改我的代码(我使用了一个额外的“复杂度”),以匹配书中的样式。
    -- import a library of *parser combinators*
import Parsimony
import Parsimony.Char
import Parsimony.Error
(+++) = (<|>)

    -- abstract syntax tree
data Expr = I Int
          | Add Expr Expr
          | Mul Expr Expr
          deriving (Eq,Show)

    -- parse an expression
parseExpr :: String -> Either ParseError Expr
parseExpr = Parsimony.parse pExpr
    where

        -- grammar
    pExpr :: Parser String Expr
    pExpr = do
        a <- pNumber +++ parentheses pExpr  -- first argument
        do
            f <- pOp                        -- operation symbol
            b <- pExpr                      -- second argument
            return (f a b)
         +++ return a                       -- or just the first argument

    parentheses parser = do                 -- parse inside parentheses
        string "("
        x <- parser
        string ")"
        return x

    pNumber = do                            -- parse an integer
        digits <- many1 digit
        return . I . read $ digits

    pOp =                                   -- parse an operation symbol
         do string "+"
            return Add
        +++ 
         do string "*"
            return Mul
*Main> parseExpr "(5*3)+1"
Right (Add (Mul (I 5) (I 3)) (I 1))