Pegjs: 如何保留空格分隔符?

创建于 2019-10-03  ·  6评论  ·  资料来源: pegjs/pegjs

问题类型

  • 错误报告: _no_
  • 功能请求: _no_
  • 问题: _是_
  • 不是问题: _no_

先决条件

  • 你能重现这个问题吗?: _是_
  • 您是否搜索了存储库问题?: _是_
  • 你检查过论坛吗?: _是_
  • 您是否执行过网络搜索(谷歌、雅虎等)?: _是_

我正在努力使 PEG.js 解析器保留等式的原始空格。

当前行为: 2 * 5 + SUM(1, 2, 3)

[
   "2",
   "*",
   "5",
   "+",
   "SUM",
   "(",
   [
      "1",
      ",",
      "2",
      ",",
      "3"
   ],
   ")"
]

期望的行为2 * 5 + SUM(1, 2, 3)

[
   "2",
   " ",
   "*",
   " ",
   "5",
   " ",
   "+",
   " ",
   "SUM",
   "(",
   [
      "1",
      ",",
      " ",
      "2",
      ",",
      " ",
      "3"
   ],
   ")"
]

要复制的语法: https ://pastebin.com/zpwqT6Uw
PEG.js 操场https://pegjs.org/online

我错过了什么?

最有用的评论

@marek-baranowski 另一个温和的 ping :smiley_cat:

另外,我编写了一个 PEG.js 插件pegjs-syntactic-actions来促进语法的调试,并专门查看哪些字符被独立于操作的规则捕获,这可能是您的问题,正如@StoneCypher 所解释的那样。

这个插件的原因是:我发现当全局结果不是我们所期望的时,它经常/有时很难理解,因为它是由许多小动作的组合产生的,并且找到表现不佳/异常的动作可能是耗时的。 使用这个插件,我们可以看到哪些规则捕获了哪些角色,并给出了要执行的操作的名称。

所有6条评论

@futagoza非常抱歉打扰您,但这是我第一次处理 PEG.js,这个问题对我来说至关重要。 我可以请你一点提示吗?

最好的祝福,
马立克

我尝试查看您的语法(昨天和刚刚),但因为它真的很难理解(除了命名约定,格式,老实说,到处都是),我花了一段时间才找到一个解决方案:

  1. 消耗空间和数据的规则返回它(例如const返回[left_space, cnst, right_space]
  2. 任何获取结果的规则/动作都必须执行如下操作: [].concat.apply([], con)

即便如此,老实说,这对我来说感觉像是一个 hacky 解决方案。 你有一个规范或其他东西的链接吗? 如果没有上述骇人听闻的解决方案,这将有助于了解我可以和无法更改哪些规则以获得所需的结果。

如果没有,只要你愿意花时间整理语法并重命名一些规则(这样更容易弄清楚你想要什么),那么我很乐意尝试再试一次😉

@marek-baranowski - 抱歉,我直到现在才看到这个。 希望这对您仍然有用

如果您想保留这些空间,只需将它们视为可匹配的内容。

目前还不清楚你想要的两个空间到底是什么。 您可以有一个由两个空格组成的字符串,也可以是一个由两个一个空格字符串组成的数组。 通常我会期待前者,但是......你所有的东西都是每个角色

另外......除了函数调用之外,你为什么想要这样的杂散字符? 解析器应该为你总结这些。

反正

这是你要求的:

Document = Expression*

Whitespace
  = tx:[ \r\n]+ { return tx.join(''); }

Number
  = str:[0-9]+ { return str.join(''); }

Oper
  = '+'
  / '-'
  / '/'
  / '*'
  / ','

Label
  = l:[a-zA-Z]+ { return l.join(''); }

Parens 
  = '(' Whitespace? ex:Expression* Whitespace? ')' { return ex; }

Expression 
  = Number 
  / Oper
  / Whitespace
  / Label
  / Parens
  / [^()]+

image

问题是,我不太相信这实际上是你想要的。 例如,您可以解析数字和运算符,并为每个返回一个标准化的节点形状:

Document = Expression*

Whitespace
  = tx:[ \r\n]+ { return { 
    ast: 'whitespace', value: tx.join('') 
  }; }

Number
  = str:[0-9]+ { return {
    ast: 'number', value: parseInt(str,10)
  }; }

Oper
  = '+' { return { ast: 'oper', value: 'add' }}
  / '-' { return { ast: 'oper', value: 'subtract' }}
  / '/' { return { ast: 'oper', value: 'divide' }}
  / '*' { return { ast: 'oper', value: 'multiply' }}
  / ',' { return { ast: 'oper', value: 'sequence' }}

Label
  = l:[a-zA-Z]+ { return { 
    ast: 'label', value: l.join('') 
  }; }

Parens 
  = '(' Whitespace? ex:Expression* Whitespace? ')' { 
    return { ast: 'parens', value: ex 
  }; }

Expression 
  = Number 
  / Oper
  / Whitespace
  / Label
  / Parens
  / [^()]+

现在你仍然有你的空白,但你也有一个正确的解析树,并且不需要编写解析器来解析解析器的输出,现在也很容易开始添加正则化特征,如行号等

image

@marek-baranowski - 我想稍微减小这个问题跟踪器的大小

如果以上是你需要的,你会考虑关闭这个问题吗? 谢谢😄

如果不是,请告诉我原因,我会再试一次

@marek-baranowski 另一个温和的 ping :smiley_cat:

另外,我编写了一个 PEG.js 插件pegjs-syntactic-actions来促进语法的调试,并专门查看哪些字符被独立于操作的规则捕获,这可能是您的问题,正如@StoneCypher 所解释的那样。

这个插件的原因是:我发现当全局结果不是我们所期望的时,它经常/有时很难理解,因为它是由许多小动作的组合产生的,并且找到表现不佳/异常的动作可能是耗时的。 使用这个插件,我们可以看到哪些规则捕获了哪些角色,并给出了要执行的操作的名称。

哦,哇,这真的很整洁

此页面是否有帮助?
0 / 5 - 0 等级

相关问题

richb-hanover picture richb-hanover  ·  7评论

dmajda picture dmajda  ·  20评论

mreinstein picture mreinstein  ·  12评论

StoneCypher picture StoneCypher  ·  6评论

mikeaustin picture mikeaustin  ·  7评论