2021 年更新
这是一个在Peggy.js的在线游乐场中运行的工作示例。Peggy.js 是积极开发中的 PEG.js 的一个分支。PEG.js 已被 David Maida 终止。
该示例显示了如何解析和规则INDENT
,以及如何使用解析位置。检查控制台日志。SAMEDENT
DEDENT
它使用这些语法,其他解析器生成器可能不知道这些语法:
(文件顶部)
{{...}}
(全局初始化程序)–...
在解析器生成时运行。
{...}
(Per-parse initializer) –...
在解析器实例化时运行。
(在文件中)
X = Y {...}
(action) –成功...
时执行Y
。初始化程序中的变量可用。如果...
返回一些东西,它将取代返回的东西Y
。
$X
– 返回用 解析的文本X
,而不是其结果。
... @X ...
(pluck 运算符) – 将 的结果替换为... X ...
的结果X
。
&{...}
(谓词)——“而且...
也必须是真的”。
X = &(...)
– 如果...
成功,则X
成功。...
不消耗任何输入。
有关更多信息,请参阅文档。
{{
console.clear()
console.log('Parser generated')
}}
{
let indentstack = []
let indent = ''
function found (what) {
let loc = location()
console.log(`[${loc.start.line}:${loc.start.column} - ${loc.end.line}:${loc.end.column}] found ${what}`)
}
console.log('Parser instantiated')
}
DOCUMENT = NEWLINES? @THINGS NEWLINES? _
THINGS = ( SAMEDENT @( OBJECT / LINE ) )*
OBJECT = key:KEY childs:(BLOCK / INLINE) {
found(`object "${key}"`)
let o = {}
o[key] = childs
return o
}
KEY = @$( [^ \t\r\n:]+ ) _ ':' _
BLOCK = NEWLINES INDENT @THINGS DEDENT
INLINE = line:LINE { return [line] }
LINE = text:$( (!EOL .)+ ) NEWLINES? {
found(`line "${text}"`)
return text
}
INDENT = &(
spaces:$( [ \t]+ ) &{
return spaces.length > indent.length
} {
indentstack.push(indent)
indent = spaces
}
) {
found('indent')
}
SAMEDENT = spaces:$( [ \t]* ) &{
return spaces === indent
} {
found('samedent')
}
/* Because of this rule, results cache must be disabled */
DEDENT = &{
indent = indentstack.pop()
return true
} {
found('dedent')
}
_ = [ \t]*
EOL = '\r\n' / '\n' / '\r'
NEWLINES = (_ EOL)+
/* Test with this input
H:
a
b
c
G:
d
e
f
*/
旧答案
这是在 PEG.js v 0.10.0 中工作的@Jakub Kulhan 语法的修复。最后一行需要更改为,= &{ 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 运算符,@
这将允许更简单地编写此语法,但由于它目前不在在线解析器中,我将避免将其添加到此示例中。