javascript - 从 JavaScript 中的自定义语法创建 AST

标签 javascript parsing abstract-syntax-tree

我正在构建一个小型框架,它可以读取我定制的 HTML 语法并将其转换为 HTML 代码。然而,我一直坚持对我的代码进行标记并创建 AST。我知道该算法需要递归方法,但我不知道如何正确执行。

这是我在 app.txt 文件中的自定义代码:

View {
    Heading {
        
    }

    Text {

    }
}

这是迄今为止我的递归解析器:

function parse(source) {
    let tag = "";
    let children = [];

    for (let i = 0; i < source.length; i++) {
        const char = source[i];

        if (char === "{") {
            const child = parse(source.substring(i + 1, source.length));
            children.push(child);
        } else if (char === "}") {
            return {
                tag: tag,
                children: children
            };
        } else {
            tag += char;
        }
    }

    return;
}

解析预计会产生类似这样的结果(并且应该能够达到任何深度):

{
    tag: "View",
    children: [
        {
            tag: "Heading",
            children: []
        },
        {
            tag: "Text",
            children: []
        }
    ]
}

我做错了什么?我将不胜感激任何帮助。

最佳答案

让我们或多或少正式地写下你的语法:

tag := name '{' children '}'
name := letter | letter name
children := tag | tag children
letter := [a-z]

然后,我们为语法中的每条规则编写一个解析函数。我们需要两个辅助函数:getsym(它从输入中返回第一个有意义的(非空白)符号)和 nextsym(它删除该符号)。

工作示例:

function parse(text) {
    let chars = [...text]

    function getsym() {
        while (chars.length > 0 && /\s/.test(chars[0]))
            chars.shift()
        return chars[0] || ''
    }

    function nextsym() {
        return chars.shift()
    }

    return tag()

    //

    function tag() {
        let n = name()

        if (getsym() !== '{')
            throw new SyntaxError()
        nextsym()

        let c = children(text)

        if (getsym() !== '}')
            throw new SyntaxError()
        nextsym()

        return {name: n, children: c}
    }

    function name() {
        let t = letter()
        if (t)
            return t + name()
        return ''
    }

    function letter() {
        if (/[a-z]/i.test(getsym()))
            return nextsym()
    }

    function children() {
        if (getsym() === '}')
            return []
        let t = tag()
        return [t, ...children()]
    }

}

///

text = ` View {
    Heading {
        Content {
            One {}
            Two {}
            Three {}
        }
    }
    Text {
        More {}
    }
}
`

console.log(parse(text))

话虽如此,如果您计划使用更复杂的语法,更实用的选择是使用像 peg.js 这样的解析器生成器。

关于javascript - 从 JavaScript 中的自定义语法创建 AST,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67958137/

相关文章:

javascript - 是什么阻止了 Ryan Dahl(Node 的创建者)在 Ruby 而不是 Javascript 中创建与 Node 相同的概念

javascript window.print() 无法打印完整的网格

java - 使用第一行文本值java获取第二行xml

使用 ANTLR 解析非结构化文本

rust - Rc 中用于 AST 操作的沮丧特征

c# - C# 中的 System.Linq.Expressions 是干什么用的?

javascript - 逻辑运算符两侧的 if 语句中的多个条件

javascript - 弹出窗口最大化按钮

java - Log4j2手动解析?

java - 表达式树和访问者模式的实现