Perl自定义后缀或自定义后缀运算符的语法

ale*_*del 5 perl parsing postfix-operator

我想知道如何运行这样的操作

$T = 25 C;
@specs = (273.15 K, 23 bar, 2.0 mol/s);
Run Code Online (Sandbox Code Playgroud)

并让他们编译.我不会挑剔他们的结果是什么,或者它是如何实现的.我的目标是让传统后缀单元注释的物理量表达式编译为这些单元的perl表达式.

我想我需要使用自定义解析技术,但我更喜欢使用任何现有功能或解析模块,而不仅仅是将regex过滤器应用于我的原始源.

Parse :: Keyword看起来很有希望,但我看不出它是否可以解析postfix操作,并声称它已被弃用.

编辑:我想尽可能避免源过滤器,因为我不想为Perl的语法极端情况编写正则表达式(例如"25(J/K)").

Perl在这里产生的错误告诉我:

perl -E "25 C"
Bareword found where operator expected at -e line 1, near "25 C"
(Missing operator before C?)
Run Code Online (Sandbox Code Playgroud)

看起来我需要挂钩Perl在数字文字之后检测运算符的地方.

可以Devel :: Declare添加后缀运算符吗?如果是这样,怎么样?

Dav*_*oss 3

您可以滥用重载来获得接近您想要的东西。

#!/usr/bin/perl

use strict;
use warnings;
use 5.010;

use Data::Dumper;
use MyUnits;

my $T = '25 C';

say Dumper $T;

my @specs = ('273.15 K', '23 bar', '2.0 mol/s');

say Dumper \@specs;
Run Code Online (Sandbox Code Playgroud)

正如您将看到的,您将获得带有“值”和“类型”属性的对象。

MyUnits.pm 看起来像这样:

package MyUnits;

use strict;
use warnings;

use overload
  '""' => \&to_string;

my %_const_handlers = (
  q => \&string_parser,
);

sub string_parser {
  my $c = eval { __PACKAGE__->new($_[0]) };
  return $_[1] if $@;
  return $c;
}

sub import {
  overload::constant %_const_handlers;
}

sub new {
  my $class = shift;

  # ->new(type => ..., value => ...)
  if (@_ == 4) {
    return bless { @_ }, $class;
  }
  # ->new({ type => ..., value => ...)
  if (@_ == 1 and ref $_[0] eq 'HASH') {
    return bless $_[0], $class;
  }
  # -> new('999xxx')
  if (@_ == 1 and ! ref $_[0]) {
    my ($val, $type) = $_[0] =~ /(\d+\.?\d*)\s*(.+)/;
    return bless({
      value => $val, type => $type,
    });
  }
}

sub to_string {
  return "$_[0]->{value}$_[0]->{type}";
}

1;
Run Code Online (Sandbox Code Playgroud)

您需要添加更多方法以使其能够执行一些有用的操作。

在大多数情况下,重载并不比源过滤器更不合时宜。它几乎肯定会让你的程序变慢很多。