从 JavaScript 中的自定义语法创建 AST
Creating AST from custom syntax in JavaScript
我正在构建一个小型框架,它可以读取我自定义的 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
,returns 来自输入的第一个有意义的(非空白)符号,以及 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.
这样的解析器生成器
我正在构建一个小型框架,它可以读取我自定义的 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
,returns 来自输入的第一个有意义的(非空白)符号,以及 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.
这样的解析器生成器