Javascript 使用PEG.js解析缩进级别
我有一个基本上与相同的问题,但我想了解更多的方向 答案成功地生成了一个字符串数组,这些字符串是每行输入之间带有“INDENT”和“DEDENT”的字符串。看起来他几乎习惯于使用PEG.js来标记,但是没有真正的解析发生 那么我如何扩展他的示例来进行一些实际的解析呢 例如,如何更改此语法:Javascript 使用PEG.js解析缩进级别,javascript,parsing,syntax,peg,Javascript,Parsing,Syntax,Peg,我有一个基本上与相同的问题,但我想了解更多的方向 答案成功地生成了一个字符串数组,这些字符串是每行输入之间带有“INDENT”和“DEDENT”的字符串。看起来他几乎习惯于使用PEG.js来标记,但是没有真正的解析发生 那么我如何扩展他的示例来进行一些实际的解析呢 例如,如何更改此语法: start = obj obj = id:id children:(indent obj* outdent)? { if (children) { let o =
start = obj
obj = id:id children:(indent obj* outdent)?
{
if (children) {
let o = {}; o[id] = children[1];
return o;
} else {
return id;
}
}
id = [a-z]
indent = '{'
outdent = '}'
使用缩进而不是大括号来描绘块,并且仍然得到相同的输出
(用于使用以下输入测试该语法:a{bcd{zyx{}}
)解析器:
// do not use result cache, nor line and column tracking
{ var indentStack = [], indent = ""; }
start
= INDENT? l:line
{ return l; }
line
= SAMEDENT line:(!EOL c:. { return c; })+ EOL?
children:( INDENT c:line* DEDENT { return c; })?
{ var o = {}; o[line] = children; return children ? o : line.join(""); }
EOL
= "\r\n" / "\n" / "\r"
SAMEDENT
= i:[ \t]* &{ return i.join("") === indent; }
INDENT
= &(i:[ \t]+ &{ return i.length > indent.length; }
{ indentStack.push(indent); indent = i.join(""); pos = offset; })
DEDENT
= { indent = indentStack.pop(); }
输入:
a
b
c
d
z
y
x
输出:
{
"a": [
"b",
"c",
{
"d": [
"z",
"y",
"x"
]
}
]
}
它不能解析空对象(last
x
),但是,它应该很容易解决。这里的技巧是SAMEDENT
规则,当缩进级别没有改变时,它会成功<代码>缩进和DEDENT
更改当前缩进级别而不更改文本中的位置pos=offset
这里是@Jakub Kulhan语法的一个补丁,它在PEG.js v 0.10.0中工作。最后一行需要更改为=&{indent=indentStack.pop();return true;}
,因为PEG.js现在不再允许语法中的独立操作({…}
)。这一行现在是一个谓词(&{…}
),它总是成功(返回true;
)
我还删除了pos=offset代码>因为它给出了错误未定义偏移量
。可能Jakub指的是PEG.js旧版本中可用的一些全局变量。现在,PEG.js提供了location()
函数,该函数返回一个包含偏移量和其他信息的对象
// do not use result cache, nor line and column tracking
{ var indentStack = [], indent = ""; }
start
= INDENT? l:line
{ return l; }
line
= SAMEDENT line:(!EOL c:. { return c; })+ EOL?
children:( INDENT c:line* DEDENT { return c; })?
{ var o = {}; o[line] = children; return children ? o : line.join(""); }
EOL
= "\r\n" / "\n" / "\r"
SAMEDENT
= i:[ \t]* &{ return i.join("") === indent; }
INDENT
= &(i:[ \t]+ &{ return i.length > indent.length; }
{ indentStack.push(indent); indent = i.join(""); })
DEDENT
= &{ indent = indentStack.pop(); return true;}
从V0.11.0peg.js开始,还支持,@
,这将使编写此语法更加简单,但由于它目前不在联机解析器中,我将避免将其添加到此示例中。此示例使用冒号(:
)来分隔对象和简单字母。这样,它也可以以对象结束,但冒号是必需的。与问题中的示例一样,它不考虑可忽略的空格(例如冒号之前)。它基于Jakubs Kulhans的例子:
// do not use result cache, nor line and column tracking
{ var indentStack = [], indent = ""; }
Start = Object
Object = Block / Letterline
Block = Samedent id:Letter ':' childs:(
Newline Indent childs:Object* Dedent {return childs;}
)* {
if (childs) {
var o = {}; o[id] = childs.flat().flat();
return o;
} else {
return id;
}
}
Letterline = Samedent letters:Letter+ Newline? {return letters;}
Letter = [a-z]
Newline = "\r\n" / "\n" / "\r"
Indent = &(
i:[ ]+ &{
return i.length > indent.length;
} {
indentStack.push(indent);
indent = i.join("");
}
)
Samedent = i:[ ]* &{ return i.join("") === indent; }
Dedent = &{ indent = indentStack.pop(); return true; }
语法将为以下输入生成所需的输出:
a:
bc
d:
zy
x:
我真的很感激你。你是怎么想出这个方法的?如果我直接复制/粘贴到它里面,它不会编译。经过一些调整后,还不清楚如何“修复”它。刚刚测试过,代码段编译并生成了预期的输出。不确定您在那里遇到了什么错误。这是如何处理回溯案例的?如果您有一组包含多个子表达式的先行规则,indent.stack会不会因为第一个子表达式中的一系列合法匹配而出错,然后在解析第二个子表达式时会出现混乱?@joeriks:如果仍然有用,我已经决定使用v0.8.0。请给出一个示例,说明您希望输入的外观