首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

Perl 6 Grammars,Part 1

Perl 6 Grammars, Part 1

Perl 6 语言内置了对 grammar 的支持。您可以将 grammars 视为众所周知的正则表达式和诸如 或 等实用程序或更复杂的 grammar 工具(如ANTLR)的组合。所有这些 - 词法分析器,语法分析器和语义处理 - 通常是编译器的独立部分,在 Perl 6 中它们都是内置的,并且可以通过全新的 Perl 6 安装 进行开箱即用。

要感受 grammar 的力量,Perl 6 自己的 grammar 就是用 Perl 6 庞大的 grammar 类 Perl6::Grammar写成的就足以说明了。

在本文中,我将通过几个例子来说明 grammar 的基础知识。所有必需的语言结构将在我们进行的时候进行解释。

解析数字

在你开始思考用户可以使用不同格式的数字,包括负数,浮点数,科学记数法中的数字,特殊形式的数字(如C的长整数)之前,解析数字似乎是一项简单的任务。

让我们从最简单的形式开始:一个数字作为数字序列。例如,1,42,123 或 1000. Perl 6 中的 grammar 是一种特殊的类,它有自己的关键字。grammar 的第一个 rule 必须(默认情况下)称为 ,以下是解析第一组数字的完整程序:

grammarN{

tokenTOP{

}

}

for ->$n{

sayN.parse($n) ??"OK $n"!!"NOT OK $n";

}

当调用 grammar 的 方法时,Perl 会尝试将给定的字符串与 方法进行匹配。在我们的例子中,这是一个 ,这意味着字符串不能在 token 的各个部分之间包含任何可选空格。 只在消耗整个字符串时才成功,因此不需要使用显式锚点 和 来绑定 token 的边缘。

与正则表达式一样,token 和 rule 可以包含其他 tokens,rules 或由其名称引用的正则表达式。在我们的第一个例子中, token 需要与数字匹配的 内置方法。 量词与标准的 Perl 5 正则表达式中的量词相同:它允许前一个原子重复一次或多次。

我们简单的 grammar 到目前为止只能解析无符号整数。任何负数都不能被解析:

OK 1

OK 42

OK 123

OK 1000

NOT OK -3

让我们更新 grammar 并引入可选符号的 token,它可以是 或 :

grammarN{

tokenTOP{

['+''-']?

}

}

在这里,方括号将两个选项组合在一起:。 量词要求只有一个这样的字符,或者没有。在 Perl 6 中,方括号只创建一个分组,但不捕获它的内容。还要注意, 和 都被引号引住了,因为 Perl 6 将任何非字母数字字符视为特殊字符,除非它被引号引起来或被转义。

下一步是添加对浮点的支持。临时解决方案可以创建包含数字和 符号的字符类。但这是完全错误的,例如,带有两个点的字符串(如 )通过此过滤器。所以,做点不一样的事情:

grammarN{

tokenTOP{

['+''-']?

['.' +]?

}

}

该 grammar 现在允许包含一个可选的点和另一个数字序列,并且在数字是整数或包含明确的小数部分(例如 )时可以很好地工作。对于其中一个部分丢失的那些数字,则失败: 或 。

通过使用量词使得零件可选的尝试使得 grammar 变得难以阅读并且容易出错。例如,以下 token 匹配上述所有数字,还有单个 :

grammarN{

tokenTOP{

['+''-']?

['.' *]?

}

}

现在是时候引入更多的 token 了。将数字序列分解为单独的 token 并明确列出所有变体:

grammarN{

tokenTOP{

}

tokensign{

'+''-'

}

tokendigits{

}

tokenvalue{

'.'

'.'

'.'

}

}

token 封装了这些变体:它包含可接受数字的四种替代表示。垂直条 分割它们。为了统一起见,允许在第一个备选分支之前添加一个附加的竖线 ,以便所有这些都通过简单的 ASCII 艺术强调。

当前的 grammar 已经足够聪明以拒绝单个点号:

OK 1

OK 42

OK 123

OK 1000

OK -3

OK 3.14

OK 3.

OK .14

NOT OK .

最后一步是以科学记数法支持数字。增加另一个备选分支易如反掌:

grammarN{

tokenTOP{

[

?

]

}

tokensign{

'+''-'

}

tokenexp{

'e''E'

}

tokendigits{

}

tokenvalue{

'.'

'.'

'.'

}

}

用以下例子测试我们的 grammar:

for

3.14 3. .14 .

-3.14 -3. -.14

10E210e2-10e2-1.2e310e-3 -10e-3 -10.2e-33

sayN.parse($n) ??"OK $n"!!"NOT OK $n";

}

一切正常。但在 Perl 中,数字中也允许有下划线! 有一个合适的语法,增加对此的支持是容易的; 应只修改 token:

tokendigits{

+ ['_' +]?

}

不遵循该 rule 的字符串仍然会被忽略:

OK 100_000

NOT OK _1

NOT OK 1_

NOT OK 1__0

结论

只需几个简单的步骤,我们就可以创建一个能够理解不同格式数字的 grammar。作为练习,您可以添加前缀 ,,(十六进制,二进制和八进制)和后缀(如C中的 )的支持。Grammars 只被用来检查数字格式的有效性,并且它们的能力并没有在那里结束。在 Perl 6 中,您可以将actions添加到 grammar 中; 这些是在相应的 rule 或 token 已成功匹配时执行的代码块。但那是另一天的故事。

  • 发表于:
  • 原文链接http://kuaibao.qq.com/s/20180216G0PEEL00?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券