我的问题基本上与PEG for Python style indentation相同,但我想就this answer提出更多指示。
答案成功生成一个字符串数组,每行输入行之间有'INDENT'和'DEDENT'。似乎他几乎用PEG.js来标记,但没有真正的解析发生。
那么我怎样才能扩展他的例子来做一些实际的解析呢?
举个例子,我该如何改变这个语法:
start = obj
obj = id:id children:(indent obj* outdent)?
{
var o = {};
o[id] = children[1];
return (children[1] ? o : id);
}
id = [a-z]
indent = '{'
outdent = '}'
使用缩进而不是大括号来描述块,并仍然得到相同的输出?
(使用http://pegjs.majda.cz/online使用以下输入测试该语法:a{bcd{zyx{}}}
)
答案 0 :(得分:18)
分析器:
// 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"
]
}
]
}
它无法解析空对象(最后x
),但应该很容易解决。这里的技巧是SAMEDENT
规则,当缩进级别没有改变时它会成功。 INDENT
和DEDENT
更改当前缩进级别而不更改文本pos = offset
中的位置。
答案 1 :(得分:0)
这里是@Jakub Kulhan的语法的修复程序,该语法可在PEG.js v 0.10.0中使用。最后一行需要更改为= &{ indent = indentStack.pop(); return true;}
,因为PEG.js现在不再允许语法中的独立动作({...}
)。现在,该行是谓词(&{...}
),它总是成功(return true;
)。
我还删除了pos = offset;
,因为它给出了错误offset is not defined
。雅库布(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;}
从v 0.11.0开始,PEG.js还支持Value Plucking operator,@
,这将使编写该语法更加简单,但由于目前不在在线解析器中,因此我将避免将其添加到此示例中。
答案 2 :(得分:0)
此示例使用冒号(:
)来分隔对象和简单字母。这样,它也可以以对象结尾,但是需要冒号。像问题中的示例一样,它不会处理可忽略的空格(例如在冒号之前)。它基于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: