groovy如何区分分裂?

时间:2017-07-21 09:59:02

标签: parsing groovy groovyshell

Groovy支持/作为除法运算符:

groovy> 1 / 2
===> 0.5

它支持/作为字符串分隔符,甚至可以是多行:

groovy> x = /foo/
===> foo
groovy:000> x = /foo
groovy:001> bar/
===> foo
bar

鉴于此,为什么我不能在groovysh中评估一个斜线字符串文字?

groovy:000> /foo/
groovy:001>
很明显,groovysh认为这种情况由于某种原因而未被终止。

groovy如何避免在分裂和字符串之间混淆?这段代码意味着什么:

groovy> f / 2

这是一个函数调用f(/2 .../),其中/开始多行斜线字符串,或f除以2?

1 个答案:

答案 0 :(得分:2)

Groovy如何区分分区和字符串?

我不完全确定Groovy是如何做到的,但我会描述我是如何做到的,如果Groovy没有以类似的方式工作,我会非常惊讶。

我听说过的大多数解析算法(Shunting-yardPratt等)都能识别两种不同的令牌:

  • 期望以表达式开头的那些(中缀运算符,后缀运算符,右括号等)。如果其中一个前面没有表达式,则表示语法错误。
  • 那些不希望以表达式开头的人(前缀运算符,左括号,标识符,文字等)。如果其中一个前面有表达式,则表示语法错误。

为了方便起见,从这一点开始,我将把前一种令牌称为运算符,将后者称为非运算符

现在,关于这种区别的有趣之处在于它不是基于令牌实际上是什么,而是基于直接上下文,特别是前面的令牌。因此,根据代码中的位置以及解析器是将其分类为运算符还是非运算符,可以对相同的标记进行非常不同的解释。例如,如果在操作员位置,则“-”标记表示减法,但非操作员位置中的相同标记是否定。决定“-”是否为减法运算符没有问题,因为您可以根据其上下文来判断。

一般来说,对于Groovy中的“/”字符也是如此。如果前面有表达式,则将其解释为运算符,这意味着它是一个除法。否则,它是一个非运算符,使其成为字符串文字。所以,你通常可以通过查看紧接在它之前的令牌来判断'/'是否是一个除法:

  • /”是分区,如果它跟在标识符,文字,后缀运算符,右括号或表示表达式结尾的其他标记之后。
  • 如果/'跟在前缀运算符,中缀运算符,左括号或其他此类标记之后,或者如果它开始一行,则“println / foo ”开始字符串

当然,在实践中并不是那么简单。 Groovy设计为在面对各种样式和用途时具有灵活性,因此分号或括号等内容通常是可选的。这有时会使解析有些模棱两可。例如,假设我们的解析器遇到以下行:

foo

这很可能是打印多行字符串的尝试:println是作为参数传递给groovysh的字符串的开头,并且省略了参数列表周围的可选括号。当然,对于一个简单的解析器,它看起来像一个分区。我希望Groovy解析器可以通过向前读取以下行来看出差异,看看哪个解释没有给出错误,但是像groovysh这样的东西实际上是不可能的(因为,作为repl,它不会但是可以访问更多行),所以它被迫只是猜测。

为什么我不能在groovysh中评估一个slashy-string文字?

和以前一样,我不知道确切的原因,但我确实知道因为groovysh是一个repl,它对于更模糊的规则会遇到更多麻烦。即便如此,一个简单的单行斜线字符串也是非常明确的,所以我相信其他东西可能会在这里发生。以下是我在> /foo - unexpected char: '/' @ line 2, column 1. > /foo/ - awaits further input > /foo/bar - unexpected char: '/' @ line 2, column 1. > /foo/bar/ - awaits further input > /foo/ + 'bar' - unexpected char: '/' @ line 2, column 1. > 'foo' + /bar/ - evaluates to 'foobar' > /foo/ - evaluates to 'foo' > /foo - awaits further input > /foo/bar - Unknown property: bar 中使用各种表单的结果:

/

当'unexpected char: '/' @ line 2, column 1.'字符是一行中的第一个字符时,似乎会发生奇怪的事情。它似乎遵循的模式(据我所知)是:

  • 斜线作为一行的第一个字符开始一种奇怪的解析模式。
  • 在这种模式下,每个以斜杠结尾的行后面只有空格,导致repl等待更多的行。
  • 在以斜杠(或斜杠后面的空格)结尾的第一行结束时,将打印错误/

我也注意到了一些有趣的观点:

  • 在这种特殊模式下,正斜杠(\)和反斜杠(groovyConsole)似乎都很重要,似乎完全可以互换。
  • 这似乎在groovysh或实际的Groovy文件中根本没有发生。
  • 在开始斜杠字符前放置任何空格会导致groovysh正确解释它,但前提是斜杠是正斜杠而不是反斜杠。

所以,我个人认为这只是{{1}}的一个怪癖,要么是一个我没有听说过的错误或一些记录不足的功能。