File Coverage

lib/mb.pm
Criterion Covered Total %
statement 1320 1743 75.7
branch 1090 1620 67.2
condition 97 220 44.0
subroutine 107 107 100.0
pod 6 49 12.2
total 2620 3739 70.0


line stmt bran cond sub pod time code
1             package mb;
2             ######################################################################
3             #
4             # mb - run Perl script in MBCS encoding (not only CJK ;-)
5             #
6             # https://metacpan.org/release/mb
7             #
8             # Copyright (c) 2020 INABA Hitoshi in a CPAN
9             ######################################################################
10              
11 99     99   389216 use 5.00503; # Universal Consensus 1998 for primetools
  99         871  
12             # use 5.008001; # Lancaster Consensus 2013 for toolchains
13              
14             $VERSION = '0.08';
15             $VERSION = $VERSION;
16              
17             # internal use
18             $mb::last_s_passed = 0; # last s/// status (1 if s/// passed)
19              
20 99 50   99   2534 BEGIN { pop @INC if $INC[-1] eq '.' } # CVE-2016-1238: Important unsafe module load path flaw
21 99     99   649 use strict;
  99         220  
  99         4515  
22 99 50   99   2601 BEGIN { $INC{'warnings.pm'} = '' if $] < 5.006 } use warnings; local $^W=1;
  99     98   590  
  99         309  
  99         3508  
23 99     98   43608 use Symbol ();
  99         72938  
  98         479918  
24              
25             # set OSNAME
26             my $OSNAME = $^O;
27              
28             # encoding name of MBCS script
29             my $script_encoding = undef;
30              
31             # over US-ASCII
32             ${mb::over_ascii} = undef;
33              
34             # supports qr/./ in MBCS script
35             ${mb::x} = undef;
36              
37             # supports [\b] \d \h \s \v \w in MBCS script
38             ${mb::bare_backspace} = '\x08';
39             ${mb::bare_d} = '0123456789';
40             ${mb::bare_h} = '\x09\x20';
41             ${mb::bare_s} = '\t\n\f\r\x20';
42             ${mb::bare_v} = '\x0A\x0B\x0C\x0D';
43             ${mb::bare_w} = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_';
44              
45             # as many escapes as possible to avoid perl's feature
46             my $escapee_in_qq_like = join('', map {"\\$_"} grep( ! /[A-Za-z0-9_]/, map { CORE::chr } 0x21..0x7E));
47              
48             # as less escapes as possible to avoid over-escaping
49             my $escapee_in_q__like = '\\' . "\x5C";
50              
51             # generic linebreak
52             my $R = '(?>\\r\\n|\\r|\\n)';
53              
54             # check running perl interpreter
55             if ($^X =~ /jperl/i) {
56             die "script '@{[__FILE__]}' can run on only perl, not JPerl\n";
57             }
58              
59             # this file is used as command on command line
60             if ($0 eq __FILE__) {
61             main();
62             }
63              
64             ######################################################################
65             # main program
66             ######################################################################
67              
68             #---------------------------------------------------------------------
69             # running as module, runtime routines
70             sub import {
71 98     98   1320 my $self = shift @_;
72              
73             # confirm version
74 98 50 33     572 if (defined($_[0]) and ($_[0] =~ /\A [0-9] /xms)) {
75 3 0       6 if ($_[0] ne $mb::VERSION) {
76 3         87 die "@{[__FILE__]} just $_[0] required--but this is version $mb::VERSION, stopped";
  3         16  
77             }
78 3         4 shift @_;
79             }
80              
81             # set script encoding
82 98 50       514 if (defined $_[0]) {
83 3         14 my $encoding = $_[0];
84 3 0       5 if ($encoding =~ /\A (?: big5 | big5hkscs | eucjp | gb18030 | gbk | sjis | uhc | utf8 ) \z/xms) {
85 3         56 set_script_encoding($encoding);
86             }
87             else {
88 3         16 die "@{[__FILE__]} script_encoding '$encoding' not supported.\n";
  3         3  
89             }
90             }
91             else {
92 98         437 set_script_encoding(detect_system_encoding());
93             }
94              
95             # $^X($EXECUTABLE_NAME) for execute MBCS Perl script
96 98         328 $mb::PERL = qq{$^X @{[__FILE__]}};
  98         430  
97 98         282 $mb::PERL = $mb::PERL; # to avoid: Name "mb::PERL" used only once: possible typo at ...
98              
99             # original $0($PROGRAM_NAME) before transpile
100 98         454 ($mb::ORIG_PROGRAM_NAME = $0) =~ s/\.oo(\.[^.]+)\z/$1/;
101 98         6249 $mb::ORIG_PROGRAM_NAME = $mb::ORIG_PROGRAM_NAME; # to avoid: Name "mb::ORIG_PROGRAM_NAME" used only once: possible typo at ...
102             }
103              
104             #---------------------------------------------------------------------
105             # running as command
106             sub main {
107              
108             # usage
109 3 0   3 0 58 if (scalar(@ARGV) == 0) {
110 3         17 die <
111             usage:
112              
113             perl mb.pm MBCS_Perl_script.pl
114             perl mb.pm -e big5 MBCS_Perl_script.pl
115             perl mb.pm -e big5hkscs MBCS_Perl_script.pl
116             perl mb.pm -e eucjp MBCS_Perl_script.pl
117             perl mb.pm -e gb18030 MBCS_Perl_script.pl
118             perl mb.pm -e gbk MBCS_Perl_script.pl
119             perl mb.pm -e sjis MBCS_Perl_script.pl
120             perl mb.pm -e uhc MBCS_Perl_script.pl
121             perl mb.pm -e utf8 MBCS_Perl_script.pl
122              
123             END
124             }
125              
126             # set script encoding from command line
127 3         5 my $encoding = '';
128 3 0       56 if (($encoding) = $ARGV[0] =~ /\A -e ( .+ ) \z/xms) {
    0          
129 3 0       23 if ($encoding =~ /\A (?: big5 | big5hkscs | eucjp | gb18030 | gbk | sjis | uhc | utf8 ) \z/xms) {
130 3         16 set_script_encoding($encoding);
131 3         61 shift @ARGV;
132             }
133             else {
134 3         17 die "script_encoding '$encoding' not supported.\n";
135             }
136             }
137             elsif ($ARGV[0] =~ /\A -e \z/xms) {
138 3         5 $encoding = $ARGV[1];
139 3 0       57 if ($encoding =~ /\A (?: big5 | big5hkscs | eucjp | gb18030 | gbk | sjis | uhc | utf8 ) \z/xms) {
140 3         15 set_script_encoding($encoding);
141 3         6 shift @ARGV;
142 3         57 shift @ARGV;
143             }
144             else {
145 3         15 die "script_encoding '$encoding' not supported.\n";
146             }
147             }
148             else {
149 3         6 set_script_encoding(detect_system_encoding());
150             }
151              
152             # poor "make"
153 3         55 (my $script_oo = $ARGV[0]) =~ s{\A (.*) \. ([^.]+) \z}{$1.oo.$2}xms;
154 3 0 0     17 if (
      0        
155             (not -e $script_oo) or
156             (-M $script_oo <= -M $ARGV[0]) or
157             (-M $script_oo <= -M __FILE__)
158             ) {
159              
160             # read application script
161 3 0       6 mb::_open_r(my $fh, $ARGV[0]) or die "$0(@{[__LINE__]}): cant't open file: $ARGV[0]\n";
  3         56  
162 3         18 local $_ = CORE::do { local $/; <$fh> };
  3         5  
  3         54  
163 3         17 close $fh;
164              
165             # poor file locking
166 3     3   6 local $SIG{__DIE__} = sub { rmdir("$ARGV[0].lock"); };
  3         57  
167 3 0       15 if (mkdir("$ARGV[0].lock", 0755)) {
168 3 0       6 mb::_open_w(my $fh, ">$script_oo") or die "$0(@{[__LINE__]}): cant't open file: $script_oo\n";
  3         55  
169 3         16 print {$fh} mb::parse();
  3         5  
170 3         55 close $fh;
171 3         27 rmdir("$ARGV[0].lock");
172             }
173             else {
174 3         5 die "$0(@{[__LINE__]}): cant't mkdir: $ARGV[0].lock\n";
  3         56  
175             }
176             }
177              
178             # run octet-oriented script
179 3         16 my $module_path = '';
180 3         5 my $module_name = '';
181 3         56 my $quote = '';
182 3 0       15 if ($OSNAME =~ /MSWin32/) {
183 3 0       5 if ($0 =~ m{ ([^\/\\]+)\.pm \z}xmsi) {
184 3         54 ($module_path, $module_name) = ($`, $1);
185 3   0     23 $module_path ||= '.';
186 3         6 $module_path =~ s{ [\/\\] \z}{}xms;
187             }
188             else {
189 3         59 die "$0(@{[__LINE__]}): can't run as module.\n";
  3         18  
190             }
191 3         3 $quote = q{"};
192             }
193             else {
194 3 0       56 if ($0 =~ m{ ([^\/]+)\.pm \z}xmsi) {
195 3         18 ($module_path, $module_name) = ($`, $1);
196 3   0     6 $module_path ||= '.';
197 3         53 $module_path =~ s{ / \z}{}xms;
198             }
199             else {
200 3         26 die "$0(@{[__LINE__]}): can't run as module.\n";
  3         6  
201             }
202 3         82 $quote = q{'};
203             }
204              
205             # run octet-oriented script
206 3         16 $| = 1;
207 3 0       5 system($^X, "-I$module_path", "-M$module_name=$mb::VERSION,$script_encoding", map { / / ? "$quote$_$quote" : $_ } $script_oo, @ARGV[1..$#ARGV]);
  3         54  
208 3         14 exit($? >> 8);
209             }
210              
211             #---------------------------------------------------------------------
212             # cluck() for MBCS encoding
213             sub cluck {
214 3     3 0 6 my $i = 0;
215 3         54 my @cluck = ();
216 3         15 while (my($package,$filename,$line,$subroutine) = caller($i)) {
217 3         5 push @cluck, "[$i] $filename($line) $package::$subroutine\n";
218 3         54 $i++;
219             }
220 3         15 print STDERR CORE::reverse @cluck;
221 3         3 print STDERR "\n";
222 3         65 print STDERR @_;
223             }
224              
225             #---------------------------------------------------------------------
226             # confess() for MBCS encoding
227             sub confess {
228 3     3 0 16 my $i = 0;
229 3         6 my @confess = ();
230 3         54 while (my($package,$filename,$line,$subroutine) = caller($i)) {
231 3         15 push @confess, "[$i] $filename($line) $package::$subroutine\n";
232 3         5 $i++;
233             }
234 3         63 print STDERR CORE::reverse @confess;
235 3         15 print STDERR "\n";
236 3         5 print STDERR @_;
237 3         51 die "\n";
238             }
239              
240             ######################################################################
241             # subroutines for MBCS application programmers
242             ######################################################################
243              
244             #---------------------------------------------------------------------
245             # chop() for MBCS encoding
246             sub mb::chop {
247 21     21 0 767 my $chop = '';
248 21 100       45 for (@_ ? @_ : $_) {
249 29 100       263 if (my @x = /\G${mb::x}/g) {
250 23         51 $chop = pop @x;
251 23         55 $_ = join '', @x;
252             }
253             }
254 21         92 return $chop;
255             }
256              
257             #---------------------------------------------------------------------
258             # chr() for MBCS encoding
259             sub mb::chr {
260 7 100   7 0 2413 local $_ = shift if @_;
261 7         14 my @octet = ();
262 7         61 CORE::do {
263 9         30 unshift @octet, ($_ % 0x100);
264 9         28 $_ = int($_ / 0x100);
265             } while ($_ > 0);
266 7         78 return pack 'C*', @octet;
267             }
268              
269             #---------------------------------------------------------------------
270             # do FILE for MBCS encoding
271             sub mb::do {
272 8     8 0 1682 my($file) = @_;
273 8         19 for my $prefix_file ($file, map { "$_/$file" } @INC) {
  53         169  
274 8 50       100 if (-f $prefix_file) {
275              
276             # poor "make"
277 8         79 (my $prefix_file_oo = $prefix_file) =~ s{\A (.*) \. ([^.]+) \z}{$1.oo.$2}xms;
278 8 0 33     181 if (
      33        
279             (not -e $prefix_file_oo) or
280             (-M $prefix_file_oo <= -M $prefix_file) or
281             (-M $prefix_file_oo <= -M __FILE__)
282             ) {
283 8 50       43 mb::_open_r(my $fh, $prefix_file) or confess "$0(@{[__LINE__]}): cant't open file: $prefix_file\n";
  3         3  
284 8         69 local $_ = CORE::do { local $/; <$fh> };
  8         35  
  8         119  
285 8         112 close $fh;
286              
287             # poor file locking
288 8     3   66 local $SIG{__DIE__} = sub { rmdir("$prefix_file.lock"); };
  3         3  
289 8 50       338 if (mkdir("$prefix_file.lock", 0755)) {
290 8 50       49 mb::_open_w(my $fh, ">$prefix_file_oo") or confess "$0(@{[__LINE__]}): cant't open file: $prefix_file_oo\n";
  3         6  
291 8         71 print {$fh} mb::parse();
  8         36  
292 8         191 close $fh;
293 8         357 rmdir("$prefix_file.lock");
294             }
295             else {
296 3         15 confess "$0(@{[__LINE__]}): cant't mkdir: $prefix_file.lock\n";
  3         5  
297             }
298             }
299 8         80 $INC{$file} = $prefix_file_oo;
300              
301             # run as Perl script
302             # must use CORE::do to use , because CORE::eval cannot do it
303             # moreover "goto &CORE::do" doesn't work
304 8         351 return CORE::eval sprintf(<<'END', (caller)[0]);
305             package %s;
306             CORE::do "$prefix_file_oo";
307             END
308             }
309             }
310 3         4 confess "Can't find $file in \@INC";
311             }
312              
313             #---------------------------------------------------------------------
314             # DOS-like glob() for MBCS encoding
315             sub mb::dosglob {
316 11 50   11 0 908 my $expr = @_ ? $_[0] : $_;
317 11         30 my @glob = ();
318              
319             # works on not MSWin32
320 11 50       23 if ($OSNAME !~ /MSWin32/) {
321 11         3038 @glob = CORE::glob($expr);
322             }
323              
324             # works on MSWin32
325             else {
326              
327             # gets pattern
328 3         15 while ($expr =~ s{\A [\x20]* ( "(?:${mb::x})+?" | (?:(?!["\x20])${mb::x})+ ) }{}xms) {
329 3         5 my $pattern = $1;
330              
331             # avoids command injection
332 3 0       62 next if $pattern =~ /\G${mb::_anchor} \& /xms;
333 3 0       15 next if $pattern =~ /\G${mb::_anchor} \( /xms;
334 3 0       5 next if $pattern =~ /\G${mb::_anchor} \) /xms;
335 3 0       55 next if $pattern =~ /\G${mb::_anchor} \< /xms;
336 3 0       16 next if $pattern =~ /\G${mb::_anchor} \> /xms;
337 3 0       4 next if $pattern =~ /\G${mb::_anchor} \^ /xms;
338 3 0       53 next if $pattern =~ /\G${mb::_anchor} \| /xms;
339              
340             # makes globbing result
341 3         29 mb::tr($pattern, '/', "\x5C");
342 3 0       5 if (my($dir) = $pattern =~ m{\A (${mb::x}*) \\ }xms) {
343 3         58 push @glob, map { "$dir\\$_" } CORE::split /\n/, `DIR /B $pattern 2>NUL`;
  3         18  
344             }
345             else {
346 3         4 push @glob, CORE::split /\n/, `DIR /B $pattern 2>NUL`;
347             }
348             }
349             }
350              
351             # returns globbing result
352 11         92 my %glob = map { $_ => 1 } @glob;
  27         70  
353 11 50       46 return sort { (mb::uc($a) cmp mb::uc($b)) || ($a cmp $b) } keys %glob;
  25         129  
354             }
355              
356             #---------------------------------------------------------------------
357             # eval STRING for MBCS encoding
358             sub mb::eval {
359 1623 100   1623 0 4142344 local $_ = shift if @_;
360              
361             # run as Perl script
362 1623         3591 return CORE::eval mb::parse();
363             }
364              
365             #---------------------------------------------------------------------
366             # getc() for MBCS encoding
367             sub mb::getc {
368 12 50   12 0 646 my $fh = @_ ? shift(@_) : \*STDIN;
369 12 50 33     38 confess 'Too many arguments for mb::getc' if @_ and not wantarray;
370 12         57 my $getc = CORE::getc $fh;
371 12 50       109 if ($script_encoding =~ /\A (?: sjis ) \z/xms) {
    0          
    0          
    0          
    0          
372 12 100       39 if ($getc =~ /\A [\x81-\x9F\xE0-\xFC] \z/xms) {
373 9         17 $getc .= CORE::getc $fh;
374             }
375             }
376             elsif ($script_encoding =~ /\A (?: eucjp ) \z/xms) {
377 3 0       50 if ($getc =~ /\A [\xA1-\xFE] \z/xms) {
378 3         16 $getc .= CORE::getc $fh;
379             }
380             }
381             elsif ($script_encoding =~ /\A (?: gbk | uhc | big5 | big5hkscs ) \z/xms) {
382 3 0       5 if ($getc =~ /\A [\x81-\xFE] \z/xms) {
383 3         53 $getc .= CORE::getc $fh;
384             }
385             }
386             elsif ($script_encoding =~ /\A (?: gb18030 ) \z/xms) {
387 3 0       15 if ($getc =~ /\A [\x81-\xFE] \z/xms) {
388 3         5 $getc .= CORE::getc $fh;
389 3 0       52 if ($getc =~ /\A [\x81-\xFE] [\x30-\x39] \z/xms) {
390 3         16 $getc .= CORE::getc $fh;
391 3         4 $getc .= CORE::getc $fh;
392             }
393             }
394             }
395             elsif ($script_encoding =~ /\A (?: utf8 ) \z/xms) {
396 3 0       82 if ($getc =~ /\A [\xC2-\xDF] \z/xms) {
    0          
    0          
397 3         15 $getc .= CORE::getc $fh;
398             }
399             elsif ($getc =~ /\A [\xE0-\xEF] \z/xms) {
400 3         140 $getc .= CORE::getc $fh;
401 3         64 $getc .= CORE::getc $fh;
402             }
403             elsif ($getc =~ /\A [\xF0-\xF4] \z/xms) {
404 3         15 $getc .= CORE::getc $fh;
405 3         7 $getc .= CORE::getc $fh;
406 3         54 $getc .= CORE::getc $fh;
407             }
408             }
409 12 50       44 return wantarray ? ($getc,@_) : $getc;
410             }
411              
412             #---------------------------------------------------------------------
413             # index() for MBCS encoding
414             sub mb::index {
415 11     11 0 406 my $index = 0;
416 11 100       74 if (@_ == 3) {
417 7         144 $index = mb::index_byte($_[0], $_[1], CORE::length(mb::substr($_[0], 0, $_[2])));
418             }
419             else {
420 7         16 $index = mb::index_byte($_[0], $_[1]);
421             }
422 11 100       68 if ($index == -1) {
423 7         26 return -1;
424             }
425             else {
426 7         18 return mb::length(CORE::substr $_[0], 0, $index);
427             }
428             }
429              
430             #---------------------------------------------------------------------
431             # JPerl like index() for MBCS encoding
432             sub mb::index_byte {
433 19     19 0 492 my($str,$substr,$position) = @_;
434 19   100     69 $position ||= 0;
435 19         25 my $pos = 0;
436 19         89 while ($pos < CORE::length($str)) {
437 181 100       309 if (CORE::substr($str,$pos,CORE::length($substr)) eq $substr) {
438 15 100       29 if ($pos >= $position) {
439 11         74 return $pos;
440             }
441             }
442 173 50       529 if (CORE::substr($str,$pos) =~ /\A(${mb::x})/oxms) {
443 173         359 $pos += CORE::length($1);
444             }
445             else {
446 3         66 $pos += 1;
447             }
448             }
449 11         35 return -1;
450             }
451              
452             #---------------------------------------------------------------------
453             # universal lc() for MBCS encoding
454             sub mb::lc {
455 14 100   14 1 407 local $_ = shift if @_;
456             # A a B b C c D d E e F f G g H h I i J j K k L l M m N n O o P p Q q R r S s T t U u V v W w X x Y y Z z
457 14 100       337 return join '', map { {qw( A a B b C c D d E e F f G g H h I i J j K k L l M m N n O o P p Q q R r S s T t U u V v W w X x Y y Z z )}->{$_}||$_ } /\G${mb::x}/g;
  122         1491  
458             # A a B b C c D d E e F f G g H h I i J j K k L l M m N n O o P p Q q R r S s T t U u V v W w X x Y y Z z
459             }
460              
461             #---------------------------------------------------------------------
462             # universal lcfirst() for MBCS encoding
463             sub mb::lcfirst {
464 5 100   5 1 194 local $_ = shift if @_;
465 5 50       109 if (/\A(${mb::x})(.*)\z/s) {
466 5         24 return mb::lc($1) . $2;
467             }
468             else {
469 3         6 return '';
470             }
471             }
472              
473             #---------------------------------------------------------------------
474             # length() for MBCS encoding
475             sub mb::length {
476 19 100   19 0 512 local $_ = shift if @_;
477 19         275 return scalar(() = /\G${mb::x}/g);
478             }
479              
480             #---------------------------------------------------------------------
481             # ord() for MBCS encoding
482             sub mb::ord {
483 7 100   7 0 319 local $_ = shift if @_;
484 7         59 my $ord = 0;
485 7 50       75 if (/\A(${mb::x})/) {
486 7         23 for my $octet (unpack 'C*', $1) {
487 9         68 $ord = $ord * 0x100 + $octet;
488             }
489             }
490 7         26 return $ord;
491             }
492              
493             #---------------------------------------------------------------------
494             # require for MBCS encoding
495             sub mb::require {
496 8 50   8 0 1238 local $_ = shift if @_;
497              
498             # require perl version
499 8 50       79 if (/^[0-9]/) {
500 3 0       16 if ($] < $_) {
501 3         6 confess "Perl $_ required--this is only version $], stopped";
502             }
503             else {
504 3         57 return 1;
505             }
506             }
507              
508             # require expr
509             else {
510 8 100       32 if (exists $INC{$_}) {
511 4 50       12 return 1 if $INC{$_};
512 3         59 confess "Compilation failed in require";
513             }
514              
515             # find expr in @INC
516 7         21 my $file = $_;
517 7         16 for my $prefix_file ($file, map { "$_/$file" } @INC) {
  43         133  
518 7 50       82 if (-f $prefix_file) {
519              
520             # poor "make"
521 7         67 (my $prefix_file_oo = $prefix_file) =~ s{\A (.*) \. ([^.]+) \z}{$1.oo.$2}xms;
522 7 0 33     136 if (
      33        
523             (not -e $prefix_file_oo) or
524             (-M $prefix_file_oo <= -M $prefix_file) or
525             (-M $prefix_file_oo <= -M __FILE__)
526             ) {
527 7 50       41 mb::_open_r(my $fh, $prefix_file) or confess "$0(@{[__LINE__]}): cant't open file: $prefix_file\n";
  3         5  
528 7         65 local $_ = CORE::do { local $/; <$fh> };
  7         42  
  7         111  
529 7         111 close $fh;
530              
531             # poor file locking
532 7     3   63 local $SIG{__DIE__} = sub { rmdir("$prefix_file.lock"); };
  3         5  
533 7 50       300 if (mkdir("$prefix_file.lock", 0755)) {
534 7 50       52 mb::_open_w(my $fh, ">$prefix_file_oo") or confess "$0(@{[__LINE__]}): cant't open file: $prefix_file_oo\n";
  3         5  
535 7         77 print {$fh} mb::parse();
  7         29  
536 7         136 close $fh;
537 7         316 rmdir("$prefix_file.lock");
538             }
539             else {
540 3         16 confess "$0(@{[__LINE__]}): cant't mkdir: $prefix_file.lock\n";
  3         4  
541             }
542             }
543 7         125 $INC{$_} = $prefix_file_oo;
544              
545             # run as Perl script
546             # must use CORE::do to use , because CORE::eval cannot do it.
547 7         23 local $@;
548 7         294 my $result = CORE::eval sprintf(<<'END', (caller)[0]);
549             package %s;
550             CORE::do "$prefix_file_oo";
551             END
552              
553             # return result
554 7 50       88 if ($@) {
    50          
555 3         17 $INC{$_} = undef;
556 3         7 confess $@;
557             }
558             elsif (not $result) {
559 3         54 delete $INC{$_};
560 3         15 confess "$_ did not return true value";
561             }
562             else {
563 7         29 return $result;
564             }
565             }
566             }
567 3         55 confess "Can't find $_ in \@INC";
568             }
569             }
570              
571             #---------------------------------------------------------------------
572             # reverse() for MBCS encoding
573             sub mb::reverse {
574 7 100   7 0 277 if (wantarray) {
575 5         15 return CORE::reverse @_;
576             }
577             else {
578 5         122 return join '', CORE::reverse(join('',@_) =~ /\G${mb::x}/g);
579             }
580             }
581              
582             #---------------------------------------------------------------------
583             # rindex() for MBCS encoding
584             sub mb::rindex {
585 11     11 0 11466 my $rindex = 0;
586 11 100       36 if (@_ == 3) {
587 7         165 $rindex = mb::rindex_byte($_[0], $_[1], CORE::length(mb::substr($_[0], 0, $_[2])));
588             }
589             else {
590 7         28 $rindex = mb::rindex_byte($_[0], $_[1]);
591             }
592 11 100       23 if ($rindex == -1) {
593 7         65 return -1;
594             }
595             else {
596 7         27 return mb::length(CORE::substr $_[0], 0, $rindex);
597             }
598             }
599              
600             #---------------------------------------------------------------------
601             # JPerl like rindex() for MBCS encoding
602             sub mb::rindex_byte {
603 19     19 0 387 my($str,$substr,$position) = @_;
604 19   66     106 $position ||= CORE::length($str) - 1;
605 19         34 my $pos = 0;
606 19         22 my $rindex = -1;
607 19   100     107 while (($pos < CORE::length($str)) and ($pos <= $position)) {
608 233 100       343 if (CORE::substr($str,$pos,CORE::length($substr)) eq $substr) {
609 23         26 $rindex = $pos;
610             }
611 233 50       648 if (CORE::substr($str,$pos) =~ /\A(${mb::x})/oxms) {
612 233         603 $pos += CORE::length($1);
613             }
614             else {
615 3         4 $pos += 1;
616             }
617             }
618 19         83 return $rindex;
619             }
620              
621             #---------------------------------------------------------------------
622             # set OSNAME
623             sub mb::set_OSNAME {
624 3     3 0 27 $OSNAME = $_[0];
625             }
626              
627             #---------------------------------------------------------------------
628             # set script encoding name and more
629             sub mb::set_script_encoding {
630 193     193 0 1595 $script_encoding = $_[0];
631              
632             # over US-ASCII
633             ${mb::over_ascii} = {
634             'sjis' => '(?>[\x81-\x9F\xE0-\xFC][\x00-\xFF]|[\x80-\xFF])', # shift_jis ANSI/OEM Japanese; Japanese (Shift-JIS)
635             'gbk' => '(?>[\x81-\xFE][\x00-\xFF])', # gb2312 ANSI/OEM Simplified Chinese (PRC, Singapore); Chinese Simplified (GB2312)
636             'uhc' => '(?>[\x81-\xFE][\x00-\xFF])', # ks_c_5601-1987 ANSI/OEM Korean (Unified Hangul Code)
637             'big5' => '(?>[\x81-\xFE][\x00-\xFF])', # big5 ANSI/OEM Traditional Chinese (Taiwan; Hong Kong SAR, PRC); Chinese Traditional (Big5)
638             'big5hkscs' => '(?>[\x81-\xFE][\x00-\xFF])', # HKSCS support on top of traditional Chinese Windows
639             'eucjp' => '(?>[\xA1-\xFE][\x00-\xFF])', # EUC-JP Japanese (JIS 0208-1990 and 0121-1990)
640             'gb18030' => '(?>[\x81-\xFE][\x30-\x39][\x81-\xFE][\x30-\x39]|[\x81-\xFE][\x00-\xFF])', # GB18030 Windows XP and later: GB18030 Simplified Chinese (4 byte); Chinese Simplified (GB18030)
641             # 'utf8' => '(?>[\xC2-\xDF][\x80-\xBF]|[\xE0-\xEF][\x80-\xBF][\x80-\xBF]|[\xF0-\xF4][\x80-\xBF][\x80-\xBF][\x80-\xBF])', # utf-8 Unicode (UTF-8) RFC2279
642             'utf8' => '(?>[\xE1-\xEC][\x80-\xBF][\x80-\xBF]|[\xC2-\xDF][\x80-\xBF]|[\xEE-\xEF][\x80-\xBF][\x80-\xBF]|[\xF0-\xF0][\x90-\xBF][\x80-\xBF][\x80-\xBF]|[\xE0-\xE0][\xA0-\xBF][\x80-\xBF]|[\xED-\xED][\x80-\x9F][\x80-\xBF]|[\xF1-\xF3][\x80-\xBF][\x80-\xBF][\x80-\xBF]|[\xF4-\xF4][\x80-\x8F][\x80-\xBF][\x80-\xBF])', # utf-8 Unicode (UTF-8) optimized RFC3629 for ja_JP
643 193   50     2195 }->{$script_encoding} || '[\x80-\xFF]';
644              
645             # supports qr/./ in MBCS script
646 193         16009 ${mb::x} = qr/(?>${mb::over_ascii}|[\x00-\x7F])/;
647              
648             # regexp of multi-byte anchoring
649              
650             # Quantifiers
651             # {n,m} --- Match at least n but not more than m times
652             #
653             # n and m are limited to non-negative integral values less than a
654             # preset limit defined when perl is built. This is usually 32766 on
655             # the most common platforms.
656             #
657             # The following code is an attempt to solve the above limitations
658             # in a multi-byte anchoring.
659             #
660             # avoid "Segmentation fault" and "Error: Parse exception"
661             #
662             # perl5101delta
663             # http://perldoc.perl.org/perl5101delta.html
664             # In 5.10.0, the * quantifier in patterns was sometimes treated as {0,32767}
665             # [RT #60034, #60464]. For example, this match would fail:
666             # ("ab" x 32768) =~ /^(ab)*$/
667             #
668             # SEE ALSO
669             #
670             # Complex regular subexpression recursion limit
671             # http://www.perlmonks.org/?node_id=810857
672             #
673             # regexp iteration limits
674             # http://www.nntp.perl.org/group/perl.perl5.porters/2009/02/msg144065.html
675             #
676             # latest Perl won't match certain regexes more than 32768 characters long
677             # http://stackoverflow.com/questions/26226630/latest-perl-wont-match-certain-regexes-more-than-32768-characters-long
678             #
679             # Break through the limitations of regular expressions of Perl
680             # http://d.hatena.ne.jp/gfx/20110212/1297512479
681              
682 193 100       2108 if ($script_encoding =~ /\A (?: utf8 ) \z/xms) {
    50          
    50          
683 98         393 ${mb::_anchor} = qr{.*?}xms;
684             }
685             elsif ($] >= 5.030000) {
686             ${mb::_anchor} = {
687             'sjis' => qr{(?(?=.{0,65534}\z)(?:${mb::x})*?|(?(?=[^\x81-\x9F\xE0-\xFC]+\z).*?|.*?[^\x81-\x9F\xE0-\xFC](?>[\x81-\x9F\xE0-\xFC][\x81-\x9F\xE0-\xFC])*?))}xms,
688             'eucjp' => qr{(?(?=.{0,65534}\z)(?:${mb::x})*?|(?(?=[^\xA1-\xFE\xA1-\xFE]+\z).*?|.*?[^\xA1-\xFE\xA1-\xFE](?>[\xA1-\xFE\xA1-\xFE][\xA1-\xFE\xA1-\xFE])*?))}xms,
689             'gbk' => qr{(?(?=.{0,65534}\z)(?:${mb::x})*?|(?(?=[^\x81-\xFE\x81-\xFE]+\z).*?|.*?[^\x81-\xFE\x81-\xFE](?>[\x81-\xFE\x81-\xFE][\x81-\xFE\x81-\xFE])*?))}xms,
690             'uhc' => qr{(?(?=.{0,65534}\z)(?:${mb::x})*?|(?(?=[^\x81-\xFE\x81-\xFE]+\z).*?|.*?[^\x81-\xFE\x81-\xFE](?>[\x81-\xFE\x81-\xFE][\x81-\xFE\x81-\xFE])*?))}xms,
691             'big5' => qr{(?(?=.{0,65534}\z)(?:${mb::x})*?|(?(?=[^\x81-\xFE\x81-\xFE]+\z).*?|.*?[^\x81-\xFE\x81-\xFE](?>[\x81-\xFE\x81-\xFE][\x81-\xFE\x81-\xFE])*?))}xms,
692             'big5hkscs' => qr{(?(?=.{0,65534}\z)(?:${mb::x})*?|(?(?=[^\x81-\xFE\x81-\xFE]+\z).*?|.*?[^\x81-\xFE\x81-\xFE](?>[\x81-\xFE\x81-\xFE][\x81-\xFE\x81-\xFE])*?))}xms,
693             'gb18030' => qr{(?(?=.{0,65534}\z)(?:${mb::x})*?|(?(?=[^\x81-\xFE\x81-\xFE]+\z).*?|.*?[^\x81-\xFE\x81-\xFE](?>[\x81-\xFE\x81-\xFE][\x81-\xFE\x81-\xFE])*?))}xms,
694 3   0     16 }->{$script_encoding} || die;
695             }
696             elsif ($] >= 5.010001) {
697             ${mb::_anchor} = {
698             'sjis' => qr{(?(?=.{0,32766}\z)(?:${mb::x})*?|(?(?=[^\x81-\x9F\xE0-\xFC]+\z).*?|.*?[^\x81-\x9F\xE0-\xFC](?>[\x81-\x9F\xE0-\xFC][\x81-\x9F\xE0-\xFC])*?))}xms,
699             'eucjp' => qr{(?(?=.{0,32766}\z)(?:${mb::x})*?|(?(?=[^\xA1-\xFE\xA1-\xFE]+\z).*?|.*?[^\xA1-\xFE\xA1-\xFE](?>[\xA1-\xFE\xA1-\xFE][\xA1-\xFE\xA1-\xFE])*?))}xms,
700             'gbk' => qr{(?(?=.{0,32766}\z)(?:${mb::x})*?|(?(?=[^\x81-\xFE\x81-\xFE]+\z).*?|.*?[^\x81-\xFE\x81-\xFE](?>[\x81-\xFE\x81-\xFE][\x81-\xFE\x81-\xFE])*?))}xms,
701             'uhc' => qr{(?(?=.{0,32766}\z)(?:${mb::x})*?|(?(?=[^\x81-\xFE\x81-\xFE]+\z).*?|.*?[^\x81-\xFE\x81-\xFE](?>[\x81-\xFE\x81-\xFE][\x81-\xFE\x81-\xFE])*?))}xms,
702             'big5' => qr{(?(?=.{0,32766}\z)(?:${mb::x})*?|(?(?=[^\x81-\xFE\x81-\xFE]+\z).*?|.*?[^\x81-\xFE\x81-\xFE](?>[\x81-\xFE\x81-\xFE][\x81-\xFE\x81-\xFE])*?))}xms,
703             'big5hkscs' => qr{(?(?=.{0,32766}\z)(?:${mb::x})*?|(?(?=[^\x81-\xFE\x81-\xFE]+\z).*?|.*?[^\x81-\xFE\x81-\xFE](?>[\x81-\xFE\x81-\xFE][\x81-\xFE\x81-\xFE])*?))}xms,
704             'gb18030' => qr{(?(?=.{0,32766}\z)(?:${mb::x})*?|(?(?=[^\x81-\xFE\x81-\xFE]+\z).*?|.*?[^\x81-\xFE\x81-\xFE](?>[\x81-\xFE\x81-\xFE][\x81-\xFE\x81-\xFE])*?))}xms,
705 98   50     32251 }->{$script_encoding} || die;
706             }
707             else {
708 3         95 ${mb::_anchor} = qr{(?:${mb::x})*?}xms;
709             }
710              
711             # codepoint class shortcuts in qq-like regular expression
712 193         2554 @{mb::_dot} = "(?>${mb::over_ascii}|.)";
713 193         1320 @{mb::_B} = "(?:(?
714 193         859 @{mb::_D} = "(?:(?![0-9])${mb::x})";
715 193         771 @{mb::_H} = "(?:(?![\\x09\\x20])${mb::x})";
716 193         683 @{mb::_N} = "(?:(?!\\n)${mb::x})";
717 193         550 @{mb::_R} = "(?>\\r\\n|[\\x0A\\x0B\\x0C\\x0D])";
718 193         729 @{mb::_S} = "(?:(?![\\t\\n\\f\\r\\x20])${mb::x})";
719 193         696 @{mb::_V} = "(?:(?![\\x0A\\x0B\\x0C\\x0D])${mb::x})";
720 193         731 @{mb::_W} = "(?:(?![A-Za-z0-9_])${mb::x})";
721 193         1105 @{mb::_b} = "(?:(?
722 193         473 @{mb::_d} = "[0-9]";
723 193         471 @{mb::_h} = "[\\x09\\x20]";
724 193         461 @{mb::_s} = "[\\t\\n\\f\\r\\x20]";
725 193         443 @{mb::_v} = "[\\x0A\\x0B\\x0C\\x0D]";
726 193         1918 @{mb::_w} = "[A-Za-z0-9_]";
727             }
728              
729             #---------------------------------------------------------------------
730             # substr() for MBCS encoding
731             BEGIN {
732 98 50 100 98 1 2429914 CORE::eval sprintf <<'END', ($] >= 5.014) ? ':lvalue' : '';
  53 100   3   4403  
  53 100   53   273  
  5 100       66  
  51 50       145  
  19 100       51  
  19 50       97  
  19 100       51  
  27 100       138  
  27 100       144  
  26         118  
  26         249  
  10         73  
  8         61  
733             # VV--------------------------------AAAAAAA
734             sub mb::substr %s {
735             my @x = $_[0] =~ /\G${mb::x}/g;
736              
737             # If the substring is beyond either end of the string, substr() returns the undefined
738             # value and produces a warning. When used as an lvalue, specifying a substring that
739             # is entirely outside the string raises an exception.
740             # http://perldoc.perl.org/functions/substr.html
741              
742             # A return with no argument returns the scalar value undef in scalar context,
743             # an empty list () in list context, and (naturally) nothing at all in void
744             # context.
745              
746             if (($_[1] < (-1 * scalar(@x))) or (+1 * scalar(@x) < $_[1])) {
747             return;
748             }
749              
750             # substr($string,$offset,$length,$replacement)
751             if (@_ == 4) {
752             my $substr = join '', splice @x, $_[1], $_[2], $_[3];
753             $_[0] = join '', @x;
754             $substr; # "return $substr" doesn't work, don't write "return"
755             }
756              
757             # substr($string,$offset,$length)
758             elsif (@_ == 3) {
759             local $SIG{__WARN__} = sub {}; # avoid: Use of uninitialized value in join or string at here
760             my $octet_offset =
761             ($_[1] < 0) ? -1 * CORE::length(join '', @x[$#x+$_[1]+1 .. $#x]) :
762             ($_[1] > 0) ? CORE::length(join '', @x[0 .. $_[1]-1]) :
763             0;
764             my $octet_length =
765             ($_[2] < 0) ? -1 * CORE::length(join '', @x[$#x+$_[2]+1 .. $#x]) :
766             ($_[2] > 0) ? CORE::length(join '', @x[$_[1] .. $_[1]+$_[2]-1]) :
767             0;
768             CORE::substr($_[0], $octet_offset, $octet_length);
769             }
770              
771             # substr($string,$offset)
772             else {
773             my $octet_offset =
774             ($_[1] < 0) ? -1 * CORE::length(join '', @x[$#x+$_[1]+1 .. $#x]) :
775             ($_[1] > 0) ? CORE::length(join '', @x[0 .. $_[1]-1]) :
776             0;
777             CORE::substr($_[0], $octet_offset);
778             }
779             }
780             END
781             }
782              
783             #---------------------------------------------------------------------
784             # tr/// and y/// for MBCS encoding
785             sub mb::tr {
786 248     251 1 10862 my @x = $_[0] =~ /\G${mb::x}/g;
787 248         904 my @search = $_[1] =~ /\G${mb::x}/g;
788 248         740 my @replacement = $_[2] =~ /\G${mb::x}/g;
789 248 100       617 my %modifier = (defined $_[3]) ? (map { $_ => 1 } CORE::split //, $_[3]) : ();
  388         717  
790              
791 248         348 my %tr = ();
792 248         480 for (my $i=0; $i <= $#search; $i++) {
793              
794             # tr/AAA/123/ works as tr/A/1/
795 548 100       825 if (not exists $tr{$search[$i]}) {
796              
797             # tr/ABC/123/ makes %tr = ('A'=>'1','B'=>'2','C'=>'3',);
798 504 100 66     1154 if (defined $replacement[$i] and ($replacement[$i] ne '')) {
    100 66        
    100          
799 404         879 $tr{$search[$i]} = $replacement[$i];
800             }
801              
802             # tr/ABC/12/d makes %tr = ('A'=>'1','B'=>'2','C'=>'',);
803             elsif (exists $modifier{d}) {
804 64         137 $tr{$search[$i]} = '';
805             }
806              
807             # tr/ABC/12/ makes %tr = ('A'=>'1','B'=>'2','C'=>'2',);
808             elsif (defined $replacement[-1] and ($replacement[-1] ne '')) {
809 28         61 $tr{$search[$i]} = $replacement[-1];
810             }
811              
812             # tr/ABC// makes %tr = ('A'=>'A','B'=>'B','C'=>'C',);
813             else {
814 8         19 $tr{$search[$i]} = $search[$i];
815             }
816             }
817             }
818              
819 248         265 my $tr = 0;
820 248         294 my $replaced = '';
821              
822             # has /c modifier
823 248 100       331 if (exists $modifier{c}) {
824              
825             # has /s modifier
826 98 100       124 if (exists $modifier{s}) {
827 44         49 my $last_transliterated = undef;
828 44         71 while (defined(my $x = shift @x)) {
829              
830             # /c modifier works here
831 348 100       394 if (exists $tr{$x}) {
832 192         175 $replaced .= $x;
833 192         283 $last_transliterated = undef;
834             }
835             else {
836              
837             # /d modifier works here
838 156 100       182 if (exists $modifier{d}) {
    50          
839             }
840              
841             elsif (defined $replacement[-1]) {
842              
843             # /s modifier works here
844 42 100 66     96 if (defined($last_transliterated) and ($replacement[-1] eq $last_transliterated)) {
845             }
846              
847             # tr/// works here
848             else {
849 38         44 $replaced .= ($last_transliterated = $replacement[-1]);
850             }
851             }
852 156         215 $tr++;
853             }
854             }
855             }
856              
857             # has no /s modifier
858             else {
859 54         101 while (defined(my $x = shift @x)) {
860              
861             # /c modifier works here
862 282 100       314 if (exists $tr{$x}) {
863 198         314 $replaced .= $x;
864             }
865             else {
866              
867             # /d modifier works here
868 84 100       117 if (exists $modifier{d}) {
    50          
869             }
870              
871             # tr/// works here
872             elsif (defined $replacement[-1]) {
873 60         60 $replaced .= $replacement[-1];
874             }
875 84         129 $tr++;
876             }
877             }
878             }
879             }
880              
881             # has no /c modifier
882             else {
883              
884             # has /s modifier
885 150 100       184 if (exists $modifier{s}) {
886 76         89 my $last_transliterated = undef;
887 76         137 while (defined(my $x = shift @x)) {
888 516 100       586 if (exists $tr{$x}) {
889              
890             # /d modifier works here
891 368 100 100     706 if ($tr{$x} eq '') {
    100          
892             }
893              
894             # /s modifier works here
895             elsif (defined($last_transliterated) and ($tr{$x} eq $last_transliterated)) {
896             }
897              
898             # tr/// works here
899             else {
900 140         166 $replaced .= ($last_transliterated = $tr{$x});
901             }
902 368         541 $tr++;
903             }
904             else {
905 148         148 $replaced .= $x;
906 148         229 $last_transliterated = undef;
907             }
908             }
909             }
910              
911             # has no /s modifier
912             else {
913 74         162 while (defined(my $x = shift @x)) {
914 490 100       545 if (exists $tr{$x}) {
915 366         383 $replaced .= $tr{$x};
916 366         534 $tr++;
917             }
918             else {
919 124         175 $replaced .= $x;
920             }
921             }
922             }
923             }
924              
925             # /r modifier works here
926 248 100       303 if (exists $modifier{r}) {
927 88         769 return $replaced;
928             }
929              
930             # has no /r modifier
931             else {
932 160         180 $_[0] = $replaced;
933 160         468 return $tr;
934             }
935             }
936              
937             #---------------------------------------------------------------------
938             # universal uc() for MBCS encoding
939             sub mb::uc {
940 50 100   53 1 500 local $_ = shift if @_;
941             # a A b B c C d D e E f F g G h H i I j J k K l L m M n N o O p P q Q r R s S t T u U v V w W x X y Y z Z
942 50 100       866 return join '', map { {qw( a A b B c C d D e E f F g G h H i I j J k K l L m M n N o O p P q Q r R s S t T u U v V w W x X y Y z Z )}->{$_}||$_ } /\G${mb::x}/g;
  946         9039  
943             # a A b B c C d D e E f F g G h H i I j J k K l L m M n N o O p P q Q r R s S t T u U v V w W x X y Y z Z
944             }
945              
946             #---------------------------------------------------------------------
947             # universal ucfirst() for MBCS encoding
948             sub mb::ucfirst {
949 2 100   5 1 185 local $_ = shift if @_;
950 2 50       52 if (/\A(${mb::x})(.*)\z/s) {
951 2         7 return mb::uc($1) . $2;
952             }
953             else {
954 0         0 return '';
955             }
956             }
957              
958             ######################################################################
959             # runtime routines on all operating systems (used automatically)
960             ######################################################################
961              
962             #---------------------------------------------------------------------
963             # implement of special variable $1,$2,$3,...
964             sub mb::_CAPTURE {
965 90 100   93   386 if ($mb::last_s_passed) {
966 29 50       56 if (defined $_[0]) {
967              
968             # $1 is used for multi-byte anchoring
969 29         1220 return CORE::eval '$' . ($_[0] + 1);
970             }
971             else {
972 0         0 my @capture = ();
973 0 0       0 if ($] >= 5.006) {
974              
975             # $1 is used for multi-byte anchoring in s///
976 0         0 push @capture, map { CORE::eval('$'.$_) } 2 .. CORE::eval('$#-');
  0         0  
977             }
978             else {
979              
980             # @{^CAPTURE} doesn't work enough in perl 5.005
981 0         0 for (my $n_th=2; defined(CORE::eval('$'.$n_th)); $n_th++) {
982 0         0 push @capture, CORE::eval('$'.$n_th);
983             }
984             }
985 0         0 return @capture;
986             }
987             }
988             else {
989 61 50       153 if (defined $_[0]) {
990 61         2800 return CORE::eval '$' . $_[0];
991             }
992             else {
993 0         0 my @capture = ();
994 0 0       0 if ($] >= 5.006) {
995 0         0 push @capture, map { CORE::eval('$'.$_) } 1 .. CORE::eval('$#-');
  0         0  
996             }
997             else {
998              
999             # @{^CAPTURE} doesn't work enough in perl 5.005
1000 0         0 for (my $n_th=1; defined(CORE::eval('$'.$n_th)); $n_th++) {
1001 0         0 push @capture, CORE::eval('$'.$n_th);
1002             }
1003             }
1004 0         0 return @capture;
1005             }
1006             }
1007             }
1008              
1009             #---------------------------------------------------------------------
1010             # implement of special variable @+
1011             sub mb::_LAST_MATCH_END {
1012              
1013             # perl 5.005 does not support @+, so it need CORE::eval
1014              
1015 10 100   13   35 if ($mb::last_s_passed) {
1016 5 50       13 if (scalar(@_) >= 1) {
1017 5         276 return CORE::eval q{ ($+[0], @+[2..$#-])[ @_ ] };
1018             }
1019             else {
1020 0         0 return CORE::eval q{ ($+[0], @+[2..$#-]) };
1021             }
1022             }
1023             else {
1024 5 50       10 if (scalar(@_) >= 1) {
1025 5         190 return CORE::eval q{ @+[ @_ ] };
1026             }
1027             else {
1028 0         0 return CORE::eval q{ @+ };
1029             }
1030             }
1031             }
1032              
1033             #---------------------------------------------------------------------
1034             # implement of special variable @-
1035             sub mb::_LAST_MATCH_START {
1036              
1037             # perl 5.005 does not support @-, so it need CORE::eval
1038              
1039 18 100   21   51 if ($mb::last_s_passed) {
1040 9 50       19 if (scalar(@_) >= 1) {
1041 9         539 return CORE::eval q{ ($-[2], @-[2..$#-])[ @_ ] };
1042             }
1043             else {
1044 0         0 return CORE::eval q{ ($-[2], @-[2..$#-]) };
1045             }
1046             }
1047             else {
1048 9 50       16 if (scalar(@_) >= 1) {
1049 9         415 return CORE::eval q{ @-[ @_ ] };
1050             }
1051             else {
1052 0         0 return CORE::eval q{ @- };
1053             }
1054             }
1055             }
1056              
1057             #---------------------------------------------------------------------
1058             # implement of special variable $&
1059             sub mb::_MATCH {
1060 61 50   64   179 if (defined($&)) {
1061 61 100       117 if ($mb::last_s_passed) {
1062 8 50 33     57 if (defined($1) and (CORE::substr($&, 0, CORE::length($1)) eq $1)) {
1063 8         136 return CORE::substr($&, CORE::length($1));
1064             }
1065             else {
1066 0         0 confess 'Use of "$&", $MATCH, and ${^MATCH} need to /( capture all )/ in regexp';
1067             }
1068             }
1069             else {
1070 53 50 33     304 if (defined($1) and (CORE::substr($&, -CORE::length($1)) eq $1)) {
1071 53         929 return $1;
1072             }
1073             else {
1074 0         0 confess 'Use of "$&", $MATCH, and ${^MATCH} need to /( capture all )/ in regexp';
1075             }
1076             }
1077             }
1078             else {
1079 0         0 return '';
1080             }
1081             }
1082              
1083             #---------------------------------------------------------------------
1084             # implement of special variable $`
1085             sub mb::_PREMATCH {
1086 15 50   18   65 if (defined($&)) {
1087 15 100       32 if ($mb::last_s_passed) {
1088 8         131 return $1;
1089             }
1090             else {
1091 7 50 33     47 if (defined($1) and (CORE::substr($&,-CORE::length($1)) eq $1)) {
1092 7         104 return CORE::substr($&, 0, -CORE::length($1));
1093             }
1094             else {
1095 0         0 confess 'Use of "$`", $PREMATCH, and ${^PREMATCH} need to /( capture all )/ in regexp';
1096             }
1097             }
1098             }
1099             else {
1100 0         0 return '';
1101             }
1102             }
1103              
1104             #---------------------------------------------------------------------
1105             # flag off if last m// was pass
1106             sub mb::_m_passed {
1107 1089     1092   2999 $mb::last_s_passed = 0;
1108 1089         99354 return '';
1109             }
1110              
1111             #---------------------------------------------------------------------
1112             # flag on if last s/// was pass
1113             sub mb::_s_passed {
1114 83     86   139 $mb::last_s_passed = 1;
1115 83         7410 return '';
1116             }
1117              
1118             #---------------------------------------------------------------------
1119             # ignore case of m//i, qr//i, s///i
1120             sub mb::_ignorecase {
1121 40     43   125 local($_) = @_;
1122 40         63 my $regexp = '';
1123              
1124             # parse into elements
1125 40         998 while (/\G (
1126             \(\? \^? [a-z]* [:\)] | # cloister (?^x) (?^x: ...
1127             \(\? \^? [a-z]*-[a-z]+ [:\)] | # cloister (?^x-y) (?^x-y: ...
1128             \[ ((?: \\${mb::x} | ${mb::x} )+?) \] |
1129             \\x\{ [0-9A-Fa-f]{2} \} |
1130             \\o\{ [0-7]{3} \} |
1131             \\x [0-9A-Fa-f]{2} |
1132             \\ [0-7]{3} |
1133             \\@{mb::_dot} |
1134             @{mb::_dot}
1135             ) /xmsgc) {
1136 160         426 my($element, $classmate) = ($1, $2);
1137              
1138             # in codepoint class
1139 160 50       268 if (defined $classmate) {
1140 0         0 $regexp .= '[';
1141 0         0 while ($classmate =~ /\G (
1142             \\x\{ [0-9A-Fa-f]{2} \} |
1143             \\o\{ [0-7]{3} \} |
1144             \\x [0-9A-Fa-f]{2} |
1145             \\ [0-7]{3} |
1146             \\@{mb::_dot} |
1147             @{mb::_dot}
1148             ) /xmsgc) {
1149 0         0 my $element = $1;
1150             $regexp .= {qw(
1151             A Aa a Aa
1152             B Bb b Bb
1153             C Cc c Cc
1154             D Dd d Dd
1155             E Ee e Ee
1156             F Ff f Ff
1157             G Gg g Gg
1158             H Hh h Hh
1159             I Ii i Ii
1160             J Jj j Jj
1161             K Kk k Kk
1162             L Ll l Ll
1163             M Mm m Mm
1164             N Nn n Nn
1165             O Oo o Oo
1166             P Pp p Pp
1167             Q Qq q Qq
1168             R Rr r Rr
1169             S Ss s Ss
1170             T Tt t Tt
1171             U Uu u Uu
1172             V Vv v Vv
1173             W Ww w Ww
1174             X Xx x Xx
1175             Y Yy y Yy
1176             Z Zz z Zz
1177 0   0     0 )}->{$element} || $element;
1178             }
1179 0         0 $regexp .= ']';
1180             }
1181              
1182             # out of codepoint class
1183             else {
1184             $regexp .= {qw(
1185             A [Aa] a [Aa]
1186             B [Bb] b [Bb]
1187             C [Cc] c [Cc]
1188             D [Dd] d [Dd]
1189             E [Ee] e [Ee]
1190             F [Ff] f [Ff]
1191             G [Gg] g [Gg]
1192             H [Hh] h [Hh]
1193             I [Ii] i [Ii]
1194             J [Jj] j [Jj]
1195             K [Kk] k [Kk]
1196             L [Ll] l [Ll]
1197             M [Mm] m [Mm]
1198             N [Nn] n [Nn]
1199             O [Oo] o [Oo]
1200             P [Pp] p [Pp]
1201             Q [Qq] q [Qq]
1202             R [Rr] r [Rr]
1203             S [Ss] s [Ss]
1204             T [Tt] t [Tt]
1205             U [Uu] u [Uu]
1206             V [Vv] v [Vv]
1207             W [Ww] w [Ww]
1208             X [Xx] x [Xx]
1209             Y [Yy] y [Yy]
1210             Z [Zz] z [Zz]
1211 160   66     4113 )}->{$element} || $element;
1212             }
1213             }
1214 40         724 return qr{$regexp};
1215             }
1216              
1217             #---------------------------------------------------------------------
1218             # custom codepoint class in qq-like regular expression
1219             sub mb::_cc {
1220 350     353   745 my($classmate) = @_;
1221 350 100       1350 if ($classmate =~ s{\A \^ }{}xms) {
1222 174         424 return '(?:(?!' . parse_re_codepoint_class($classmate) . ")${mb::x})";
1223             }
1224             else {
1225 176         373 return '(?:(?=' . parse_re_codepoint_class($classmate) . ")${mb::x})";
1226             }
1227             }
1228              
1229             #---------------------------------------------------------------------
1230             # makes clustered code point from string
1231             sub mb::_clustered_codepoint {
1232 22 100   25   208 if (my @codepoint = $_[0] =~ /\G(${mb::x})/xmsgc) {
1233 10 100       29 if (CORE::length($codepoint[$#codepoint]) == 1) {
1234 5         173 return $_[0];
1235             }
1236             else {
1237 5         174 return join '', @codepoint[ 0 .. $#codepoint-1 ], "(?:$codepoint[$#codepoint])";
1238             }
1239             }
1240             else {
1241 12         376 return '';
1242             }
1243             }
1244              
1245             #---------------------------------------------------------------------
1246             # open for append by undefined filehandle
1247             sub mb::_open_a {
1248 0     3   0 $_[0] = Symbol::gensym();
1249 0         0 return open($_[0], ">>$_[1]");
1250             }
1251              
1252             #---------------------------------------------------------------------
1253             # open for read by undefined filehandle
1254             sub mb::_open_r {
1255 9     12   28 $_[0] = Symbol::gensym();
1256 9         448 return open($_[0], $_[1]);
1257             }
1258              
1259             #---------------------------------------------------------------------
1260             # open for write by undefined filehandle
1261             sub mb::_open_w {
1262 9     12   30 $_[0] = Symbol::gensym();
1263 9         600 return open($_[0], $_[1]);
1264             }
1265              
1266             #---------------------------------------------------------------------
1267             # split() for MBCS encoding
1268             # sub mb::_split (;$$$) {
1269             sub mb::_split {
1270 332 100   335   13051 my $pattern = defined($_[0]) ? $_[0] : ' ';
1271 332 100       575 my $string = defined($_[1]) ? $_[1] : $_;
1272 332         447 my @split = ();
1273              
1274             # split's first argument is more consistently interpreted
1275             #
1276             # After some changes earlier in v5.17, split's behavior has been simplified:
1277             # if the PATTERN argument evaluates to a string containing one space, it is
1278             # treated the way that a literal string containing one space once was.
1279             # http://search.cpan.org/dist/perl-5.18.0/pod/perldelta.pod#split's_first_argument_is_more_consistently_interpreted
1280             # if $pattern is also omitted or is the literal space, " ", the function splits
1281             # on whitespace, /\s+/, after skipping any leading whitespace
1282              
1283 332 100       603 if ($pattern eq ' ') {
1284 108         297 $pattern = qr/\s+/;
1285 108         320 $string =~ s{\A \s+ }{}xms;
1286             }
1287              
1288             # count '(' in pattern
1289 332         363 my @parsed = ();
1290 332         406 my $modifier = '';
1291 332 100 100     2041 if ((($modifier) = $pattern =~ /\A \(\?\^? (.+?) [\)\-\:] /xms) and ($modifier =~ /x/xms)) {
1292 30         597 @parsed = $pattern =~ m{ \G (
1293             \\ ${mb::x} |
1294             \# .*? $ | # comment on /x modifier
1295             \(\?\# (?:${mb::x})*? \) |
1296             \[ (?:${mb::x})+? \] |
1297             \(\? |
1298             \(\+ |
1299             \(\* |
1300             ${mb::x} |
1301             [\x00-\xFF]
1302             ) }xgc;
1303             }
1304             else {
1305 302         3624 @parsed = $pattern =~ m{ \G (
1306             \\ ${mb::x} |
1307             \(\?\# (?:${mb::x})*? \) |
1308             \[ (?:${mb::x})+? \] |
1309             \(\? |
1310             \(\+ |
1311             \(\* |
1312             ${mb::x} |
1313             [\x00-\xFF]
1314             ) }xgc;
1315             }
1316             my $last_match_no =
1317             1 + # first '(' is for substring
1318 332         734 scalar(grep { $_ eq '(' } @parsed); # other '(' are for pattern of split()
  2254         3002  
1319              
1320             # Repeated Patterns Matching a Zero-length Substring
1321             # https://perldoc.perl.org/perlre.html#Repeated-Patterns-Matching-a-Zero-length-Substring
1322 332 100       1754 my $substring_quantifier = ('' =~ / \A $pattern \z /xms) ? '+?' : '*?';
1323              
1324             # if $_[2] specified and positive
1325 332 100 100     743 if (defined($_[2]) and ($_[2] >= 1)) {
1326 21         25 my $limit = $_[2];
1327              
1328 21         955 CORE::eval q{ no warnings }; # avoid: Complex regular subexpression recursion limit (nnnnn) exceeded at ...
1329              
1330             # gets substrings by repeat chopping by pattern
1331 21   100     411 while ((--$limit > 0) and ($string =~ s<\A((?:${mb::x})$substring_quantifier)$pattern><>)) {
1332 42         103 for (my $n_th=1; $n_th <= $last_match_no; $n_th++) {
1333 42         1323 push @split, CORE::eval('$'.$n_th);
1334             }
1335             }
1336             }
1337              
1338             # if $_[2] is omitted or zero or negative
1339             else {
1340 311     7   14047 CORE::eval q{ no warnings }; # avoid: Complex regular subexpression recursion limit (nnnnn) exceeded at ...
  4     7   29  
  4     3   7  
  4     3   167  
  4     3   25  
  4     3   8  
  4     3   86  
        3      
        3      
        3      
        3      
        3      
        3      
        3      
        2      
1341              
1342             # gets substrings by repeat chopping by pattern
1343 311         5153 while ($string =~ s<\A((?:${mb::x})$substring_quantifier)$pattern><>) {
1344 734         1722 for (my $n_th=1; $n_th <= $last_match_no; $n_th++) {
1345 786         23776 push @split, CORE::eval('$'.$n_th);
1346             }
1347             }
1348             }
1349              
1350             # get last substring
1351 332 100 100     821 if (CORE::length($string) > 0) {
    100          
1352 299         430 push @split, $string;
1353             }
1354             elsif (defined($_[2]) and ($_[2] >= 1)) {
1355 6 50       14 if (scalar(@split) < $_[2]) {
1356 6         16 push @split, ('') x ($_[2] - scalar(@split));
1357             }
1358             }
1359              
1360             # if $_[2] is omitted or zero, trailing null fields are stripped from the result
1361 332 100 100     725 if ((not defined $_[2]) or ($_[2] == 0)) {
1362 305   33     1049 while ((scalar(@split) >= 1) and ($split[-1] eq '')) {
1363 0         0 pop @split;
1364             }
1365             }
1366              
1367             # old days, split had write its result to @_ on scalar context,
1368             # but this usage is no longer supported
1369              
1370 332 100       550 if (wantarray) {
1371 199         1791 return @split;
1372             }
1373             else {
1374 133         998 return scalar @split;
1375             }
1376             }
1377              
1378             ######################################################################
1379             # runtime routines for MSWin32 (used automatically)
1380             ######################################################################
1381              
1382             #---------------------------------------------------------------------
1383             # filetest -B for MSWin32
1384             sub mb::_B (;*@) {
1385 16 50   19   55 local $_ = shift if @_;
1386 16 50 33     33 confess 'Too many arguments for -B (mb::_B)' if @_ and not wantarray;
1387 16 100 33     41 if ($_ eq '_') {
    50          
    100          
    50          
1388 8 50       515 return wantarray ? (-B _,@_) : -B _;
1389             }
1390             elsif (defined fileno(my $fh = Symbol::qualify_to_ref $_)) {
1391 0 0       0 return wantarray ? (-B $fh,@_) : -B $fh;
1392             }
1393             elsif (-B $_) {
1394 4 50       329 return wantarray ? (1,@_) : 1;
1395             }
1396             elsif (($OSNAME =~ /MSWin32/) and ($script_encoding =~ /\A (?: sjis | gbk | uhc | big5 | big5hkscs | gb18030 ) \z/xms)) {
1397 0 0       0 if (-B qq{$_.}) {
1398 0 0       0 return wantarray ? (1,@_) : 1;
1399             }
1400             }
1401 4 50       224 return wantarray ? (undef,@_) : undef;
1402             }
1403              
1404             #---------------------------------------------------------------------
1405             # filetest -C for MSWin32
1406             sub mb::_C (;*@) {
1407 32 50   35   161 local $_ = shift if @_;
1408 32 50 33     64 confess 'Too many arguments for -C (mb::_C)' if @_ and not wantarray;
1409 32 100 33     84 if ($_ eq '_') {
    50          
    100          
    50          
1410 16 50       191 return wantarray ? (-C _,@_) : -C _;
1411             }
1412             elsif (defined fileno(my $fh = Symbol::qualify_to_ref $_)) {
1413 0 0       0 return wantarray ? (-C $fh,@_) : -C $fh;
1414             }
1415             elsif (-e $_) {
1416 10 50       544 return wantarray ? (-C $_,@_) : -C $_;
1417             }
1418             elsif (($OSNAME =~ /MSWin32/) and ($script_encoding =~ /\A (?: sjis | gbk | uhc | big5 | big5hkscs | gb18030 ) \z/xms)) {
1419 0 0       0 if (-e qq{$_.}) {
1420 0 0       0 return wantarray ? (-C qq{$_.},@_) : -C qq{$_.};
1421             }
1422             }
1423 6 50       327 return wantarray ? (undef,@_) : undef;
1424             }
1425              
1426             #---------------------------------------------------------------------
1427             # filetest -M for MSWin32
1428             sub mb::_M (;*@) {
1429 32 50   35   145 local $_ = shift if @_;
1430 32 50 33     59 confess 'Too many arguments for -M (mb::_M)' if @_ and not wantarray;
1431 32 100 33     82 if ($_ eq '_') {
    50          
    100          
    50          
1432 16 50       169 return wantarray ? (-M _,@_) : -M _;
1433             }
1434             elsif (defined fileno(my $fh = Symbol::qualify_to_ref $_)) {
1435 0 0       0 return wantarray ? (-M $fh,@_) : -M $fh;
1436             }
1437             elsif (-e $_) {
1438 10 50       459 return wantarray ? (-M $_,@_) : -M $_;
1439             }
1440             elsif (($OSNAME =~ /MSWin32/) and ($script_encoding =~ /\A (?: sjis | gbk | uhc | big5 | big5hkscs | gb18030 ) \z/xms)) {
1441 0 0       0 if (-e qq{$_.}) {
1442 0 0       0 return wantarray ? (-M qq{$_.},@_) : -M qq{$_.};
1443             }
1444             }
1445 6 50       316 return wantarray ? (undef,@_) : undef;
1446             }
1447              
1448             #---------------------------------------------------------------------
1449             # filetest -T for MSWin32
1450             sub mb::_T (;*@) {
1451 16 50   19   40 local $_ = shift if @_;
1452 16 50 33     30 confess 'Too many arguments for -T (mb::_T)' if @_ and not wantarray;
1453 16 100 33     63 if ($_ eq '_') {
    50          
    100          
    50          
1454 8 50       413 return wantarray ? (-T _,@_) : -T _;
1455             }
1456             elsif (defined fileno(my $fh = Symbol::qualify_to_ref $_)) {
1457 0 0       0 return wantarray ? (-T $fh,@_) : -T $fh;
1458             }
1459             elsif (-T $_) {
1460 2 50       173 return wantarray ? (1,@_) : 1;
1461             }
1462             elsif (($OSNAME =~ /MSWin32/) and ($script_encoding =~ /\A (?: sjis | gbk | uhc | big5 | big5hkscs | gb18030 ) \z/xms)) {
1463 0 0       0 if (-T qq{$_.}) {
1464 0 0       0 return wantarray ? (1,@_) : 1;
1465             }
1466             }
1467 6 50       312 return wantarray ? (undef,@_) : undef;
1468             }
1469              
1470             #---------------------------------------------------------------------
1471             # chdir() for MSWin32
1472             sub mb::_chdir {
1473              
1474             # works on MSWin32 only
1475 2 50 33 5   8 if (($OSNAME !~ /MSWin32/) or ($script_encoding !~ /\A (?: sjis | gbk | uhc | big5 | big5hkscs | gb18030 ) \z/xms)) {
1476 2         52 return CORE::chdir $_[0];
1477             }
1478              
1479 0 0 0     0 if (@_ == 0) {
    0 0        
    0          
1480 0         0 return CORE::chdir;
1481             }
1482             elsif (($script_encoding =~ /\A (?: sjis ) \z/xms) and ($_[0] =~ /\A ${mb::x}* [\x81-\x9F\xE0-\xFC][\x5C] \z/xms)) {
1483 0 0       0 if (defined wantarray) {
1484 0         0 return 0;
1485             }
1486             else {
1487 0         0 confess "mb::_chdir: Can't chdir '$_[0]'\n";
1488             }
1489             }
1490             elsif (($script_encoding =~ /\A (?: gbk | uhc | big5 | big5hkscs | gb18030 ) \z/xms) and ($_[0] =~ /\A ${mb::x}* [\x81-\xFE][\x5C] \z/xms)) {
1491 0 0       0 if (defined wantarray) {
1492 0         0 return 0;
1493             }
1494             else {
1495 0         0 confess "mb::_chdir: Can't chdir '$_[0]'\n";
1496             }
1497             }
1498             else {
1499 0         0 return CORE::chdir $_[0];
1500             }
1501             }
1502              
1503             #---------------------------------------------------------------------
1504             # filetest -d for MSWin32
1505             sub mb::_d (;*@) {
1506 14 50   17   37 local $_ = shift if @_;
1507 14 50 33     25 confess 'Too many arguments for -d (mb::_d)' if @_ and not wantarray;
1508 14 100 33     115 if ($_ eq '_') {
    100          
    50          
1509 7 50       203 return wantarray ? (-d _,@_) : -d _;
1510             }
1511             elsif (-d $_) {
1512 1 50       7 return wantarray ? (1,@_) : 1;
1513             }
1514             elsif (($OSNAME =~ /MSWin32/) and ($script_encoding =~ /\A (?: sjis | gbk | uhc | big5 | big5hkscs | gb18030 ) \z/xms)) {
1515 0 0       0 if (-d qq{$_.}) {
1516 0 0       0 return wantarray ? (1,@_) : 1;
1517             }
1518             }
1519 6 50       37 return wantarray ? (undef,@_) : undef;
1520             }
1521              
1522             #---------------------------------------------------------------------
1523             # filetest -e for MSWin32
1524             sub mb::_e (;*@) {
1525 17 50   20   52 local $_ = shift if @_;
1526 17 50 33     31 confess 'Too many arguments for -e (mb::_e)' if @_ and not wantarray;
1527 17 100 33     57 if ($_ eq '_') {
    50          
    100          
    50          
1528 7 50       205 return wantarray ? (-e _,@_) : -e _;
1529             }
1530             elsif (defined fileno(my $fh = Symbol::qualify_to_ref $_)) {
1531 0 0       0 return wantarray ? (-e $fh,@_) : -e $fh;
1532             }
1533             elsif (-e $_) {
1534 8 50       334 return wantarray ? (1,@_) : 1;
1535             }
1536             elsif (($OSNAME =~ /MSWin32/) and ($script_encoding =~ /\A (?: sjis | gbk | uhc | big5 | big5hkscs | gb18030 ) \z/xms)) {
1537 0 0       0 if (-e qq{$_.}) {
1538 0 0       0 return wantarray ? (1,@_) : 1;
1539             }
1540             }
1541 2 50       122 return wantarray ? (undef,@_) : undef;
1542             }
1543              
1544             #---------------------------------------------------------------------
1545             # filetest -f for MSWin32
1546             sub mb::_f (;*@) {
1547 14 50   17   36 local $_ = shift if @_;
1548 14 50 33     20 confess 'Too many arguments for -f (mb::_f)' if @_ and not wantarray;
1549 14 100 33     34 if ($_ eq '_') {
    50          
    100          
    50          
1550 7 50       218 return wantarray ? (-f _,@_) : -f _;
1551             }
1552             elsif (defined fileno(my $fh = Symbol::qualify_to_ref $_)) {
1553 0 0       0 return wantarray ? (-f $fh,@_) : -f $fh;
1554             }
1555             elsif (-f $_) {
1556 5 50       176 return wantarray ? (1,@_) : 1;
1557             }
1558             elsif (($OSNAME =~ /MSWin32/) and ($script_encoding =~ /\A (?: sjis | gbk | uhc | big5 | big5hkscs | gb18030 ) \z/xms)) {
1559 0 0       0 if (-f qq{$_.}) {
1560 0 0       0 return wantarray ? (1,@_) : 1;
1561             }
1562             }
1563 2 50       116 return wantarray ? (undef,@_) : undef;
1564             }
1565              
1566             #---------------------------------------------------------------------
1567             # lstat() for MSWin32
1568             sub mb::_lstat (;*) {
1569 5 50   8   184 local $_ = shift if @_;
1570 5 50 33     22 if ($_ eq '_') {
    50          
    100          
    50          
1571 0         0 confess qq{lstat doesn't support '_'\n};
1572             }
1573             elsif (defined fileno(my $fh = Symbol::qualify_to_ref $_)) {
1574 0         0 return CORE::stat $fh; # not CORE::lstat
1575             }
1576             elsif (-e $_) {
1577 2         127 return CORE::stat _; # not CORE::lstat
1578             }
1579             elsif (($OSNAME =~ /MSWin32/) and ($script_encoding =~ /\A (?: sjis | gbk | uhc | big5 | big5hkscs | gb18030 ) \z/xms)) {
1580 0 0       0 if (-e qq{$_.}) {
1581 0         0 return CORE::stat _; # not CORE::lstat
1582             }
1583             }
1584 3 50       147 return wantarray ? () : undef;
1585             }
1586              
1587             #---------------------------------------------------------------------
1588             # opendir() for MSWin32
1589             sub mb::_opendir (*$) {
1590 2     5   3 my $dh;
1591 2 50       7 if (defined $_[0]) {
1592 2         10 $dh = Symbol::qualify_to_ref($_[0], caller());
1593             }
1594             else {
1595 0         0 $dh = $_[0] = \do { local *_ };
  0         0  
1596             }
1597              
1598             # works on MSWin32 only
1599 2 50 33     70 if (($OSNAME !~ /MSWin32/) or ($script_encoding !~ /\A (?: sjis | gbk | uhc | big5 | big5hkscs | gb18030 ) \z/xms)) {
    0          
    0          
1600 2         84 return CORE::opendir $dh, $_[1];
1601             }
1602             elsif (-d $_[1]) {
1603 0         0 return CORE::opendir $dh, $_[1];
1604             }
1605             elsif (-d qq{$_[1].}) {
1606 0         0 return CORE::opendir $dh, qq{$_[1].};
1607             }
1608 0         0 return undef;
1609             }
1610              
1611             #---------------------------------------------------------------------
1612             # filetest -r for MSWin32
1613             sub mb::_r (;*@) {
1614 32 50   35   95 local $_ = shift if @_;
1615 32 50 33     53 confess 'Too many arguments for -r (mb::_r)' if @_ and not wantarray;
1616 32 100 33     69 if ($_ eq '_') {
    50          
    100          
    50          
1617 16 50       546 return wantarray ? (-r _,@_) : -r _;
1618             }
1619             elsif (defined fileno(my $fh = Symbol::qualify_to_ref $_)) {
1620 0 0       0 return wantarray ? (-r $fh,@_) : -r $fh;
1621             }
1622             elsif (-r $_) {
1623 10 50       384 return wantarray ? (1,@_) : 1;
1624             }
1625             elsif (($OSNAME =~ /MSWin32/) and ($script_encoding =~ /\A (?: sjis | gbk | uhc | big5 | big5hkscs | gb18030 ) \z/xms)) {
1626 0 0       0 if (-r qq{$_.}) {
1627 0 0       0 return wantarray ? (1,@_) : 1;
1628             }
1629             }
1630 6 50       227 return wantarray ? (undef,@_) : undef;
1631             }
1632              
1633             #---------------------------------------------------------------------
1634             # filetest -s for MSWin32
1635             sub mb::_s (;*@) {
1636 16 50   19   76 local $_ = shift if @_;
1637 16 50 33     28 confess 'Too many arguments for -s (mb::_s)' if @_ and not wantarray;
1638 16 100 33     36 if ($_ eq '_') {
    50          
    100          
    50          
1639 8 50       115 return wantarray ? (-s _,@_) : -s _;
1640             }
1641             elsif (defined fileno(my $fh = Symbol::qualify_to_ref $_)) {
1642 0 0       0 return wantarray ? (-s $fh,@_) : -s $fh;
1643             }
1644             elsif (-e $_) {
1645 5 50       211 return wantarray ? (-s $_,@_) : -s $_;
1646             }
1647             elsif (($OSNAME =~ /MSWin32/) and ($script_encoding =~ /\A (?: sjis | gbk | uhc | big5 | big5hkscs | gb18030 ) \z/xms)) {
1648 0 0       0 if (-e qq{$_.}) {
1649 0 0       0 return wantarray ? (-s qq{$_.},@_) : -s qq{$_.};
1650             }
1651             }
1652 3 50       131 return wantarray ? (undef,@_) : undef;
1653             }
1654              
1655             #---------------------------------------------------------------------
1656             # stat() for MSWin32
1657             sub mb::_stat (;*) {
1658 8 50   11   174 local $_ = shift if @_;
1659 8 100 33     29 if ($_ eq '_') {
    50          
    100          
    50          
1660 3 100       7 if (-e _) {
1661 2         35 return CORE::stat _;
1662             }
1663             }
1664             elsif (defined fileno(my $fh = Symbol::qualify_to_ref $_)) {
1665 0         0 return CORE::stat $fh;
1666             }
1667             elsif (-e $_) {
1668 4         257 return CORE::stat _;
1669             }
1670             elsif (($OSNAME =~ /MSWin32/) and ($script_encoding =~ /\A (?: sjis | gbk | uhc | big5 | big5hkscs | gb18030 ) \z/xms)) {
1671 0 0       0 if (-e qq{$_.}) {
1672 0         0 return CORE::stat _;
1673             }
1674             }
1675 2 50       97 return wantarray ? () : undef;
1676             }
1677              
1678             #---------------------------------------------------------------------
1679             # unlink() for MSWin32
1680             sub mb::_unlink {
1681              
1682             # works on MSWin32 only
1683 89 50 33 92   670 if (($OSNAME !~ /MSWin32/) or ($script_encoding !~ /\A (?: sjis | gbk | uhc | big5 | big5hkscs | gb18030 ) \z/xms)) {
1684 89 50       6024 return CORE::unlink(@_ ? @_ : $_);
1685             }
1686              
1687 0         0 my $unlink = 0;
1688 0 0       0 for (@_ ? @_ : $_) {
1689 0 0       0 if (CORE::unlink) {
    0          
1690 0         0 $unlink++;
1691             }
1692             elsif (CORE::unlink qq{$_.}) {
1693 0         0 $unlink++;
1694             }
1695             }
1696 0         0 return $unlink;
1697             }
1698              
1699             #---------------------------------------------------------------------
1700             # filetest -w for MSWin32
1701             sub mb::_w (;*@) {
1702 32 50   35   89 local $_ = shift if @_;
1703 32 50 33     57 confess 'Too many arguments for -w (mb::_w)' if @_ and not wantarray;
1704 32 100 33     79 if ($_ eq '_') {
    50          
    100          
    50          
1705 16 50       493 return wantarray ? (-w _,@_) : -w _;
1706             }
1707             elsif (defined fileno(my $fh = Symbol::qualify_to_ref $_)) {
1708 0 0       0 return wantarray ? (-w $fh,@_) : -w $fh;
1709             }
1710             elsif (-w $_) {
1711 10 50       378 return wantarray ? (1,@_) : 1;
1712             }
1713             elsif (($OSNAME =~ /MSWin32/) and ($script_encoding =~ /\A (?: sjis | gbk | uhc | big5 | big5hkscs | gb18030 ) \z/xms)) {
1714 0 0       0 if (-w qq{$_.}) {
1715 0 0       0 return wantarray ? (1,@_) : 1;
1716             }
1717             }
1718 6 50       219 return wantarray ? (undef,@_) : undef;
1719             }
1720              
1721             #---------------------------------------------------------------------
1722             # filetest -x for MSWin32
1723             sub mb::_x (;*@) {
1724 36 50   39   95 local $_ = shift if @_;
1725 36 50 33     60 confess 'Too many arguments for -x (mb::_x)' if @_ and not wantarray;
1726 36 100 33     89 if ($_ eq '_') {
    50          
    50          
    50          
1727 12 50       431 return wantarray ? (-x _,@_) : -x _;
1728             }
1729             elsif (defined fileno(my $fh = Symbol::qualify_to_ref $_)) {
1730 0 0       0 return wantarray ? (-x $fh,@_) : -x $fh;
1731             }
1732             elsif (-x $_) {
1733 0 0       0 return wantarray ? (1,@_) : 1;
1734             }
1735             elsif (($OSNAME =~ /MSWin32/) and ($script_encoding =~ /\A (?: sjis | gbk | uhc | big5 | big5hkscs | gb18030 ) \z/xms)) {
1736 0 0       0 if (-x qq{$_.}) {
1737 0 0       0 return wantarray ? (1,@_) : 1;
1738             }
1739             }
1740 24 50       1008 return wantarray ? (undef,@_) : undef;
1741             }
1742              
1743             #---------------------------------------------------------------------
1744             # filetest -z for MSWin32
1745             sub mb::_z (;*@) {
1746 16 50   19   43 local $_ = shift if @_;
1747 16 50 33     29 confess 'Too many arguments for -z (mb::_z)' if @_ and not wantarray;
1748 16 100 33     32 if ($_ eq '_') {
    50          
    100          
    50          
1749 8 50       248 return wantarray ? (-z _,@_) : -z _;
1750             }
1751             elsif (defined fileno(my $fh = Symbol::qualify_to_ref $_)) {
1752 0 0       0 return wantarray ? (-z $fh,@_) : -z $fh;
1753             }
1754             elsif (-e $_) {
1755 5 50       212 return wantarray ? (-z $_,@_) : -z $_;
1756             }
1757             elsif (($OSNAME =~ /MSWin32/) and ($script_encoding =~ /\A (?: sjis | gbk | uhc | big5 | big5hkscs | gb18030 ) \z/xms)) {
1758 0 0       0 if (-e qq{$_.}) {
1759 0 0       0 return wantarray ? (-z qq{$_.},@_) : -z qq{$_.};
1760             }
1761             }
1762 3 50       112 return wantarray ? (undef,@_) : undef;
1763             }
1764              
1765             ######################################################################
1766             # source code filter
1767             ######################################################################
1768              
1769             #---------------------------------------------------------------------
1770             # detect system encoding any of big5, big5hkscs, eucjp, gb18030, gbk, sjis, uhc, utf8
1771             sub detect_system_encoding {
1772              
1773             # running on Microsoft Windows
1774 95 50   98 0 865 if ($OSNAME =~ /MSWin32/) {
    50          
    50          
    50          
1775 0 0       0 if (my($codepage) = qx{chcp} =~ m/[^0123456789](932|936|949|950|951|20932|54936)\Z/) {
1776             return {qw(
1777             932 sjis
1778             936 gbk
1779             949 uhc
1780             950 big5
1781             951 big5hkscs
1782             20932 eucjp
1783             54936 gb18030
1784 0         0 )}->{$codepage};
1785             }
1786             else {
1787 0         0 return 'utf8';
1788             }
1789             }
1790              
1791             # running on Oracle Solaris
1792             elsif ($OSNAME =~ /solaris/) {
1793             my $LANG =
1794             defined($ENV{'LC_ALL'}) ? $ENV{'LC_ALL'} :
1795             defined($ENV{'LC_CTYPE'}) ? $ENV{'LC_CTYPE'} :
1796 0 0       0 defined($ENV{'LANG'}) ? $ENV{'LANG'} :
    0          
    0          
1797             '';
1798             return {qw(
1799             ja_JP.PCK sjis
1800             ja eucjp
1801             japanese eucjp
1802             ja_JP.eucJP eucjp
1803             zh gbk
1804             zh.GBK gbk
1805             zh_CN.GBK gbk
1806             zh_CN.EUC gbk
1807             zh_CN.GB18030 gb18030
1808             ko uhc
1809             ko_KR.EUC uhc
1810             zh_TW.BIG5 big5
1811             zh_HK.BIG5HK big5hkscs
1812 0   0     0 )}->{$LANG} || 'utf8';
1813             }
1814              
1815             # running on HP HP-UX
1816             elsif ($OSNAME =~ /hpux/) {
1817             my $LANG =
1818             defined($ENV{'LC_ALL'}) ? $ENV{'LC_ALL'} :
1819             defined($ENV{'LC_CTYPE'}) ? $ENV{'LC_CTYPE'} :
1820 0 0       0 defined($ENV{'LANG'}) ? $ENV{'LANG'} :
    0          
    0          
1821             '';
1822             return {qw(
1823             japanese sjis
1824             ja_JP.SJIS sjis
1825             japanese.euc eucjp
1826             ja_JP.eucJP eucjp
1827             zh_CN.hp15CN gbk
1828             zh_CN.gb18030 gb18030
1829             ko_KR.eucKR uhc
1830             zh_TW.big5 big5
1831             zh_HK.big5 big5hkscs
1832             zh_HK.hkbig5 big5hkscs
1833 0   0     0 )}->{$LANG} || 'utf8';
1834             }
1835              
1836             # running on IBM AIX
1837             elsif ($OSNAME =~ /aix/) {
1838             my $LANG =
1839             defined($ENV{'LC_ALL'}) ? $ENV{'LC_ALL'} :
1840             defined($ENV{'LC_CTYPE'}) ? $ENV{'LC_CTYPE'} :
1841 0 0       0 defined($ENV{'LANG'}) ? $ENV{'LANG'} :
    0          
    0          
1842             '';
1843             return {qw(
1844             Ja_JP sjis
1845             Ja_JP.IBM-943 sjis
1846             ja_JP eucjp
1847             ja_JP.IBM-eucJP eucjp
1848             zh_CN gbk
1849             zh_CN.IBM-eucCN gbk
1850             Zh_CN gb18030
1851             Zh_CN.GB18030 gb18030
1852             ko_KR uhc
1853             ko_KR.IBM-eucKR uhc
1854             Zh_TW big5
1855             Zh_TW.big-5 big5
1856             Zh_HK big5hkscs
1857             Zh_HK.BIG5-HKSCS big5hkscs
1858 0   0     0 )}->{$LANG} || 'utf8';
1859             }
1860              
1861             # running on Other Systems
1862             else {
1863             my $LANG =
1864             defined($ENV{'LC_ALL'}) ? $ENV{'LC_ALL'} :
1865             defined($ENV{'LC_CTYPE'}) ? $ENV{'LC_CTYPE'} :
1866 95 50       861 defined($ENV{'LANG'}) ? $ENV{'LANG'} :
    50          
    50          
1867             '';
1868             return {qw(
1869             japanese sjis
1870             ja_JP.SJIS sjis
1871             ja_JP.mscode sjis
1872             ja eucjp
1873             japan eucjp
1874             japanese.euc eucjp
1875             Japanese-EUC eucjp
1876             ja_JP eucjp
1877             ja_JP.ujis eucjp
1878             ja_JP.eucJP eucjp
1879             ja_JP.AJEC eucjp
1880             ja_JP.EUC eucjp
1881             Jp_JP eucjp
1882             zh_CN.EUC gbk
1883             zh_CN.GB2312 gbk
1884             zh_CN.hp15CN gbk
1885             zh_CN.gb18030 gb18030
1886             ko_KR.eucKR uhc
1887             zh_TW.Big5 big5
1888             zh_TW.big5 big5
1889             zh_HK.big5 big5hkscs
1890 95   50     3042 )}->{$LANG} || 'utf8';
1891             }
1892             }
1893              
1894             my $term = 0;
1895             my @here_document_delimiter = ();
1896              
1897             #---------------------------------------------------------------------
1898             # parse script
1899             sub parse {
1900 7161 100   7164 0 357348 local $_ = shift if @_;
1901              
1902 7161         9861 $term = 0;
1903 7161         10679 @here_document_delimiter = ();
1904              
1905             # transpile JPerl script to Perl script
1906 7161         9269 my $parsed_script = '';
1907 7161         23464 while (not /\G \z /xmsgc) {
1908 35508         55394 $parsed_script .= parse_expr();
1909             }
1910              
1911             # return octet-oriented Perl script
1912 7161         175227 return $parsed_script;
1913             }
1914              
1915             #---------------------------------------------------------------------
1916             # parse expression in script
1917             sub parse_expr {
1918 38173     38176 0 45940 my $parsed = '';
1919              
1920             # __END__ or __DATA__
1921 38173 100 100     787115 if (/\G ^ ( (?: __END__ | __DATA__ ) $R .* ) \z/xmsgc) {
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    50          
    50          
    100          
    100          
    100          
    50          
    50          
    100          
    50          
    100          
    100          
    50          
    100          
    100          
    50          
    50          
    50          
    100          
    100          
    100          
    100          
    100          
    50          
    0          
1922 2         8 $parsed .= $1;
1923             }
1924              
1925             # =pod ... =cut
1926             elsif (/\G ^ ( = [A-Za-z_][A-Za-z_0-9]* [\x00-\xFF]*? $R =cut \b [^\n]* $R ) /xmsgc) {
1927 1         6 $parsed .= $1;
1928             }
1929              
1930             # \r\n, \r, \n
1931             elsif (/\G (?= $R ) /xmsgc) {
1932 8533         21731 while (my $here_document_delimiter = shift @here_document_delimiter) {
1933 23         33 my($delimiter, $quote_type) = @{$here_document_delimiter};
  23         44  
1934 23 100       55 if ($quote_type eq 'qq') {
    50          
1935 14         30 $parsed .= parse_heredocument_as_qq_endswith($delimiter);
1936             }
1937             elsif ($quote_type eq 'q') {
1938              
1939             # perlop > Quote-Like Operators > < Single Quotes
1940             #
1941             # Single quotes indicate the text is to be treated literally
1942             # with no interpolation of its content. This is similar to
1943             # single quoted strings except that backslashes have no special
1944             # meaning, with \\ being treated as two backslashes and not
1945             # one as they would in every other quoting construct.
1946             # https://perldoc.perl.org/perlop.html#Quote-Like-Operators
1947              
1948 9         21 $parsed .= parse_heredocument_as_q_endswith($delimiter);
1949             }
1950             else {
1951 0         0 die "$0(@{[__LINE__]}): $ARGV[0] here document delimiter '$delimiter' not found.\n";
  0         0  
1952             }
1953             }
1954             }
1955              
1956             # \t
1957             # "\x20" [ ] SPACE (U+0020)
1958             elsif (/\G ( [\t ]+ ) /xmsgc) {
1959 5809         10744 $parsed .= $1;
1960             }
1961              
1962             # "\x3B" [;] SEMICOLON (U+003B)
1963             elsif (/\G ( ; ) /xmsgc) {
1964 997         1966 $parsed .= $1;
1965 997         1168 $term = 0;
1966             }
1967              
1968             # balanced bracket
1969             # "\x28" [(] LEFT PARENTHESIS (U+0028)
1970             # "\x7B" [{] LEFT CURLY BRACKET (U+007B)
1971             # "\x5B" [[] LEFT SQUARE BRACKET (U+005B)
1972             elsif (/\G ( [(\{\[] ) /xmsgc) {
1973 458         948 $parsed .= parse_expr_balanced($1);
1974 458         633 $term = 1;
1975             }
1976              
1977             # number
1978             # "\x30" [0] DIGIT ZERO (U+0030)
1979             # "\x31" [1] DIGIT ONE (U+0031)
1980             # "\x32" [2] DIGIT TWO (U+0032)
1981             # "\x33" [3] DIGIT THREE (U+0033)
1982             # "\x34" [4] DIGIT FOUR (U+0034)
1983             # "\x35" [5] DIGIT FIVE (U+0035)
1984             # "\x36" [6] DIGIT SIX (U+0036)
1985             # "\x37" [7] DIGIT SEVEN (U+0037)
1986             # "\x38" [8] DIGIT EIGHT (U+0038)
1987             # "\x39" [9] DIGIT NINE (U+0039)
1988             elsif (/\G (
1989             0x [0-9A-Fa-f_]+ |
1990             0b [01_]+ |
1991             0 [0-7_]* |
1992             [1-9] [0-9_]* (?: \.[0-9_]* )? (?: [Ee] [0-9_]+ )?
1993             ) /xmsgc) {
1994 654         1305 $parsed .= $1;
1995 654         773 $term = 1;
1996             }
1997              
1998             # any term then operator
1999             # "\x25" [%] PERCENT SIGN (U+0025)
2000             # "\x26" [&] AMPERSAND (U+0026)
2001             # "\x2A" [*] ASTERISK (U+002A)
2002             # "\x2E" [.] FULL STOP (U+002E)
2003             # "\x2F" [/] SOLIDUS (U+002F)
2004             # "\x3C" [<] LESS-THAN SIGN (U+003C)
2005             # "\x3F" [?] QUESTION MARK (U+003F)
2006             elsif ($term and /\G ( %= | % | &&= | && | &\.= | &\. | &= | & | \*\*= | \*\* | \*= | \* | \.\.\. | \.\. | \.= | \. | \/\/= | \/\/ | \/= | \/ | <=> | << | <= | < | \? ) /xmsgc) {
2007 122         232 $parsed .= $1;
2008 122         168 $term = 0;
2009             }
2010              
2011             # unimplemented file test operator on MSWin32
2012             # "\x2D" [-] HYPHEN-MINUS (U+002D)
2013             elsif (/\G ( -[ASORWXbcgkloptu] ) \b /xmsgc) {
2014 15         43 $parsed .= $1;
2015 15         20 $term = 1;
2016             }
2017              
2018             # implemented file test operator on MSWin32
2019             # implements run on any systems by transpiling once
2020             elsif (/\G -([BCMTdefrswxz]) \b /xmsgc) {
2021 285         610 $parsed .= "mb::_$1";
2022 285         326 $term = 1;
2023             }
2024              
2025             # yada-yada or triple-dot operator
2026             elsif (/\G ( \.\.\. ) /xmsgc) {
2027 1         3 $parsed .= $1;
2028 1         2 $term = 0;
2029             }
2030              
2031             # any operator
2032             # "\x21" [!] EXCLAMATION MARK (U+0021)
2033             # "\x2B" [+] PLUS SIGN (U+002B)
2034             # "\x2C" [,] COMMA (U+002C)
2035             # "\x3D" [=] EQUALS SIGN (U+003D)
2036             # "\x3E" [>] GREATER-THAN SIGN (U+003E)
2037             # "\x5C" [\] REVERSE SOLIDUS (U+005C)
2038             # "\x5E" [^] CIRCUMFLEX ACCENT (U+005E)
2039             # "\x7C" [|] VERTICAL LINE (U+007C)
2040             # "\x7E" [~] TILDE (U+007E)
2041             elsif (/\G ( != | !~ | ! | \+\+ | \+= | \+ | , | -- | -= | -> | - | == | => | =~ | = | >> | >= | > | \\ | \^\.= | \^\. | \^= | \^ | (?: and | cmp | eq | ge | gt | isa | le | lt | ne | not | or | x | x= | xor ) \b | \|\|= | \|\| | \|\.= | \|\. | \|= | \| | ~~ | ~\. | ~= | ~ ) /xmsgc) {
2042 2156         4342 $parsed .= $1;
2043 2156         2782 $term = 0;
2044             }
2045              
2046             # $` --> mb::_PREMATCH()
2047             # ${`} --> mb::_PREMATCH()
2048             # $PREMATCH --> mb::_PREMATCH()
2049             # ${PREMATCH} --> mb::_PREMATCH()
2050             # ${^PREMATCH} --> mb::_PREMATCH()
2051             elsif (/\G (?: \$` | \$\{`\} | \$PREMATCH | \$\{PREMATCH\} | \$\{\^PREMATCH\} ) /xmsgc) {
2052 20         40 $parsed .= 'mb::_PREMATCH()';
2053 20         40 $term = 1;
2054             }
2055              
2056             # $& --> mb::_MATCH()
2057             # ${&} --> mb::_MATCH()
2058             # $MATCH --> mb::_MATCH()
2059             # ${MATCH} --> mb::_MATCH()
2060             # ${^MATCH} --> mb::_MATCH()
2061             elsif (/\G (?: \$& | \$\{&\} | \$MATCH | \$\{MATCH\} | \$\{\^MATCH\} ) /xmsgc) {
2062 68         160 $parsed .= 'mb::_MATCH()';
2063 68         86 $term = 1;
2064             }
2065              
2066             # $1 --> mb::_CAPTURE(1)
2067             # $2 --> mb::_CAPTURE(2)
2068             # $3 --> mb::_CAPTURE(3)
2069             elsif (/\G \$ ([1-9][0-9]*) /xmsgc) {
2070 55         144 $parsed .= "mb::_CAPTURE($1)";
2071 55         83 $term = 1;
2072             }
2073              
2074             # @{^CAPTURE} --> mb::_CAPTURE()
2075             elsif (/\G \@\{\^CAPTURE\} /xmsgc) {
2076 3         51 $parsed .= 'mb::_CAPTURE()';
2077 3         6 $term = 1;
2078             }
2079              
2080             # ${^CAPTURE}[0] --> mb::_CAPTURE(1)
2081             # ${^CAPTURE}[1] --> mb::_CAPTURE(2)
2082             # ${^CAPTURE}[2] --> mb::_CAPTURE(3)
2083             elsif (/\G \$\{\^CAPTURE\} \s* (\[) /xmsgc) {
2084 3         8 my $n_th = quotee_of(parse_expr_balanced($1));
2085 3         7 $parsed .= "mb::_CAPTURE($n_th+1)";
2086 3         4 $term = 1;
2087             }
2088              
2089             # @- --> mb::_LAST_MATCH_START()
2090             # @LAST_MATCH_START --> mb::_LAST_MATCH_START()
2091             # @{LAST_MATCH_START} --> mb::_LAST_MATCH_START()
2092             # @{^LAST_MATCH_START} --> mb::_LAST_MATCH_START()
2093             elsif (/\G (?: \@- | \@LAST_MATCH_START | \@\{LAST_MATCH_START\} | \@\{\^LAST_MATCH_START\} ) /xmsgc) {
2094 12         29 $parsed .= 'mb::_LAST_MATCH_START()';
2095 12         30 $term = 1;
2096             }
2097              
2098             # $-[1] --> mb::_LAST_MATCH_START(1)
2099             # $LAST_MATCH_START[1] --> mb::_LAST_MATCH_START(1)
2100             # ${LAST_MATCH_START}[1] --> mb::_LAST_MATCH_START(1)
2101             # ${^LAST_MATCH_START}[1] --> mb::_LAST_MATCH_START(1)
2102             elsif (/\G (?: \$- | \$LAST_MATCH_START | \$\{LAST_MATCH_START\} | \$\{\^LAST_MATCH_START\} ) \s* (\[) /xmsgc) {
2103 22         53 my $n_th = quotee_of(parse_expr_balanced($1));
2104 22         83 $parsed .= "mb::_LAST_MATCH_START($n_th)";
2105 22         36 $term = 1;
2106             }
2107              
2108             # @+ --> mb::_LAST_MATCH_END()
2109             # @LAST_MATCH_END --> mb::_LAST_MATCH_END()
2110             # @{LAST_MATCH_END} --> mb::_LAST_MATCH_END()
2111             # @{^LAST_MATCH_END} --> mb::_LAST_MATCH_END()
2112             elsif (/\G (?: \@\+ | \@LAST_MATCH_END | \@\{LAST_MATCH_END\} | \@\{\^LAST_MATCH_END\} ) /xmsgc) {
2113 12         28 $parsed .= 'mb::_LAST_MATCH_END()';
2114 12         15 $term = 1;
2115             }
2116              
2117             # $+[1] --> mb::_LAST_MATCH_END(1)
2118             # $LAST_MATCH_END[1] --> mb::_LAST_MATCH_END(1)
2119             # ${LAST_MATCH_END}[1] --> mb::_LAST_MATCH_END(1)
2120             # ${^LAST_MATCH_END}[1] --> mb::_LAST_MATCH_END(1)
2121             elsif (/\G (?: \$\+ | \$LAST_MATCH_END | \$\{LAST_MATCH_END\} | \$\{\^LAST_MATCH_END\} ) \s* (\[) /xmsgc) {
2122 14         37 my $n_th = quotee_of(parse_expr_balanced($1));
2123 14         34 $parsed .= "mb::_LAST_MATCH_END($n_th)";
2124 14         23 $term = 1;
2125             }
2126              
2127             # mb::do { block } --> do { block }
2128             # mb::eval { block } --> eval { block }
2129             # do { block } --> do { block }
2130             # eval { block } --> eval { block }
2131             elsif (/\G (?: mb:: )? ( (?: do | eval ) \s* ) ( \{ ) /xmsgc) {
2132 4         12 $parsed .= $1;
2133 4         9 $parsed .= parse_expr_balanced($2);
2134 4         8 $term = 1;
2135             }
2136              
2137             # $#{}, ${}, @{}, %{}, &{}, *{}, do {}, eval {}, sub {}
2138             # "\x24" [$] DOLLAR SIGN (U+0024)
2139             elsif (/\G ((?: \$[#] | [\$\@%&*] | (?:CORE::)? do | (?:CORE::)? eval | sub ) \s* ) ( \{ ) /xmsgc) {
2140 11         29 $parsed .= $1;
2141 11         24 $parsed .= parse_expr_balanced($2);
2142 11         13 $term = 1;
2143             }
2144              
2145             # mb::do --> mb::do
2146             # mb::eval --> mb::eval
2147             # do --> mb::do
2148             # eval --> mb::eval
2149             elsif (/\G (?: mb:: )? ( do | eval ) \b /xmsgc) {
2150 4         14 $parsed .= "mb::$1";
2151 4         6 $term = 1;
2152             }
2153              
2154             # CORE::do --> CORE::do
2155             # CORE::eval --> CORE::eval
2156             elsif (/\G ( CORE:: (?: do | eval ) ) \b /xmsgc) {
2157 2         7 $parsed .= $1;
2158 2         3 $term = 1;
2159             }
2160              
2161             # last index of array
2162             elsif (/\G ( [\$] [#] (?: [A-Za-z_][A-Za-z_0-9]*(?:(?:'|::)[A-Za-z_][A-Za-z_0-9]*)* ) ) /xmsgc) {
2163 3         8 $parsed .= $1;
2164 3         5 $term = 1;
2165             }
2166              
2167             # scalar variable
2168             elsif (/\G ( [\$] [\$]* (?: [A-Za-z_][A-Za-z_0-9]*(?:(?:'|::)[A-Za-z_][A-Za-z_0-9]*)* | ^\{[A-Za-z_][A-Za-z_0-9]*\} | [0-9]+ | [!"#\$%&'()+,\-.\/:;<=>?\@\[\\\]\^_`|~] ) (?: \s* (?: \+\+ | -- ) )? ) /xmsgc) {
2169 593         1406 $parsed .= $1;
2170 593         702 $term = 1;
2171             }
2172              
2173             # array variable
2174             # "\x40" [@] COMMERCIAL AT (U+0040)
2175             elsif (/\G ( [\@\$] [\$]* (?: [A-Za-z_][A-Za-z_0-9]*(?:(?:'|::)[A-Za-z_][A-Za-z_0-9]*)* | [_] ) ) /xmsgc) {
2176 109         241 $parsed .= $1;
2177 109         131 $term = 1;
2178             }
2179              
2180             # hash variable
2181             elsif (/\G ( [\%\@\$] [\$]* (?: [A-Za-z_][A-Za-z_0-9]*(?:(?:'|::)[A-Za-z_][A-Za-z_0-9]*)* | [!+\-] ) ) /xmsgc) {
2182 11         32 $parsed .= $1;
2183 11         16 $term = 1;
2184             }
2185              
2186             # user subroutine call
2187             # type glob
2188             elsif (/\G ( [&*] [\$]* (?: [A-Za-z_][A-Za-z_0-9]*(?:(?:'|::)[A-Za-z_][A-Za-z_0-9]*)* ) ) /xmsgc) {
2189 12         36 $parsed .= $1;
2190 12         13 $term = 1;
2191             }
2192              
2193             # comment
2194             # "\x23" [#] NUMBER SIGN (U+0023)
2195             elsif (/\G ( [#] [^\n]* ) /xmsgc) {
2196 11         31 $parsed .= $1;
2197             }
2198              
2199             # 2-quotes
2200              
2201             # '...'
2202             # "\x27" ['] APOSTROPHE (U+0027)
2203 1476         3626 elsif (m{\G ( ' ) }xmsgc) { $parsed .= parse_q__like_endswith($1); $term = 1; }
  1476         2207  
2204              
2205             # "...", `...`
2206             # "\x22" ["] QUOTATION MARK (U+0022)
2207             # "\x60" [`] GRAVE ACCENT (U+0060)
2208 725         1618 elsif (m{\G ( ["`] ) }xmsgc) { $parsed .= parse_qq_like_endswith($1); $term = 1; }
  725         1005  
2209              
2210             # /.../
2211             elsif (m{\G ( [/] ) }xmsgc) {
2212 704         1611 my $regexp = parse_re_endswith('m',$1);
2213 704         1375 my($modifier_i, $modifier_not_cegir, $modifier_cegr) = parse_re_modifier();
2214 704 100       1363 if ($modifier_i) {
2215 15         61 $parsed .= sprintf('m{\\G${mb::_anchor}@{[mb::_ignorecase(qr%s%s)]}@{[mb::_m_passed()]}}%s', $regexp, $modifier_not_cegir, $modifier_cegr);
2216             }
2217             else {
2218 689         2699 $parsed .= sprintf('m{\\G${mb::_anchor}@{[' . 'qr%s%s ]}@{[mb::_m_passed()]}}%s', $regexp, $modifier_not_cegir, $modifier_cegr);
2219             }
2220 704         1198 $term = 1;
2221             }
2222              
2223             # ?...?
2224             elsif (m{\G ( [?] ) }xmsgc) {
2225 1         6 my $regexp = parse_re_endswith('m',$1);
2226 1         3 my($modifier_i, $modifier_not_cegir, $modifier_cegr) = parse_re_modifier();
2227 1 50       3 if ($modifier_i) {
2228 0         0 $parsed .= sprintf('m{\\G${mb::_anchor}@{[mb::_ignorecase(qr%s%s)]}@{[mb::_m_passed()]}}%s', $regexp, $modifier_not_cegir, $modifier_cegr);
2229             }
2230             else {
2231 1         47 $parsed .= sprintf('m{\\G${mb::_anchor}@{[' . 'qr%s%s ]}@{[mb::_m_passed()]}}%s', $regexp, $modifier_not_cegir, $modifier_cegr);
2232             }
2233 1         4 $term = 1;
2234             }
2235              
2236             # <<>> double-diamond operator
2237             elsif (/\G ( <<>> ) /xmsgc) {
2238 1         4 $parsed .= $1;
2239 1         2 $term = 1;
2240             }
2241              
2242             # diamond operator
2243             # <${file}>
2244             # <$file>
2245             #
2246             elsif (/\G (<) ((?:(?!\s)${mb::x})*?) (>) /xmsgc) {
2247 5         23 my($open_bracket, $quotee, $close_bracket) = ($1, $2, $3);
2248 5         7 $parsed .= $open_bracket;
2249 5         57 while ($quotee =~ /\G (${mb::x}) /xmsgc) {
2250 25         48 $parsed .= escape_qq($1, $close_bracket);
2251             }
2252 5         10 $parsed .= $close_bracket;
2253 5         9 $term = 1;
2254             }
2255              
2256             # qw/.../, q/.../
2257             elsif (/\G ( qw | q ) \b /xmsgc) {
2258 130         345 $parsed .= $1;
2259 130 100       612 if (/\G ( [#] ) /xmsgc) { $parsed .= parse_q__like_endswith($1); $term = 1; }
  2 100       6  
  2 100       4  
    100          
    100          
    50          
2260 2         5 elsif (/\G ( ['] ) /xmsgc) { $parsed .= parse_q__like_endswith($1); $term = 1; }
  2         3  
2261 8         21 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { $parsed .= parse_q__like_balanced($1); $term = 1; }
  8         15  
2262 2         7 elsif (m{\G( [/] ) }xmsgc) { $parsed .= parse_q__like_endswith($1); $term = 1; }
  2         4  
2263 48         98 elsif (/\G ( [\S] ) /xmsgc) { $parsed .= parse_q__like_endswith($1); $term = 1; }
  48         78  
2264 68         133 elsif (/\G ( \s+ ) /xmsgc) { $parsed .= $1;
2265 68         179 while (/\G ( \s+ | [#] [^\n]* ) /xmsgc) {
2266 4         13 $parsed .= $1;
2267             }
2268 68 100       298 if (/\G ( [A-Za-z_0-9] ) /xmsgc) { $parsed .= parse_q__like_endswith($1); $term = 1; }
  6 100       12  
  6 100       10  
    100          
    50          
2269 2         7 elsif (/\G ( ['] ) /xmsgc) { $parsed .= parse_q__like_endswith($1); $term = 1; }
  2         5  
2270 8         18 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { $parsed .= parse_q__like_balanced($1); $term = 1; }
  8         14  
2271 2         6 elsif (m{\G( [/] ) }xmsgc) { $parsed .= parse_q__like_endswith($1); $term = 1; }
  2         4  
2272 50         95 elsif (/\G ( [\S] ) /xmsgc) { $parsed .= parse_q__like_endswith($1); $term = 1; }
  50         92  
2273 0         0 else { die "$0(@{[__LINE__]}): $ARGV[0] has not closed:\n", $parsed; }
  0         0  
2274             }
2275 0         0 else { die "$0(@{[__LINE__]}): $ARGV[0] has not closed:\n", $parsed; }
  0         0  
2276             }
2277              
2278             # qq/.../
2279             elsif (/\G ( qq ) \b /xmsgc) {
2280 67         186 $parsed .= $1;
2281 67 100       341 if (/\G ( [#] ) /xmsgc) { $parsed .= parse_qq_like_endswith($1); $term = 1; }
  1 100       5  
  1 100       2  
    100          
    100          
    50          
2282 1         4 elsif (/\G ( ['] ) /xmsgc) { $parsed .= parse_qq_like_endswith($1); $term = 1; } # qq'...' works as "..."
  1         4  
2283 6         19 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { $parsed .= parse_qq_like_balanced($1); $term = 1; }
  6         12  
2284 1         6 elsif (m{\G( [/] ) }xmsgc) { $parsed .= parse_qq_like_endswith($1); $term = 1; }
  1         2  
2285 24         79 elsif (/\G ( [\S] ) /xmsgc) { $parsed .= parse_qq_like_endswith($1); $term = 1; }
  24         31  
2286 34         392 elsif (/\G ( \s+ ) /xmsgc) { $parsed .= $1;
2287 34         93 while (/\G ( \s+ | [#] [^\n]* ) /xmsgc) {
2288 2         11 $parsed .= $1;
2289             }
2290 34 100       151 if (/\G ( [A-Za-z_0-9] ) /xmsgc) { $parsed .= parse_qq_like_endswith($1); $term = 1; }
  3 100       7  
  3 100       7  
    100          
    50          
2291 1         38 elsif (/\G ( ['] ) /xmsgc) { $parsed .= parse_qq_like_endswith($1); $term = 1; } # qq'...' works as "..."
  1         3  
2292 4         10 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { $parsed .= parse_qq_like_balanced($1); $term = 1; }
  4         9  
2293 1         4 elsif (m{\G( [/] ) }xmsgc) { $parsed .= parse_qq_like_endswith($1); $term = 1; }
  1         3  
2294 25         50 elsif (/\G ( [\S] ) /xmsgc) { $parsed .= parse_qq_like_endswith($1); $term = 1; }
  25         38  
2295 0         0 else { die "$0(@{[__LINE__]}): $ARGV[0] has not closed:\n", $parsed; }
  0         0  
2296             }
2297 0         0 else { die "$0(@{[__LINE__]}): $ARGV[0] has not closed:\n", $parsed; }
  0         0  
2298             }
2299              
2300             # qx/.../
2301             elsif (/\G ( qx ) \b /xmsgc) {
2302 65         177 $parsed .= $1;
2303 65 100       314 if (/\G ( [#] ) /xmsgc) { $parsed .= parse_qq_like_endswith($1); $term = 1; }
  1 100       5  
  1 100       3  
    100          
    100          
    50          
2304 1         5 elsif (/\G ( ['] ) /xmsgc) { $parsed .= parse_q__like_endswith($1); $term = 1; }
  1         2  
2305 4         10 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { $parsed .= parse_qq_like_balanced($1); $term = 1; }
  4         5  
2306 1         4 elsif (m{\G( [/] ) }xmsgc) { $parsed .= parse_qq_like_endswith($1); $term = 1; }
  1         4  
2307 24         50 elsif (/\G ( [\S] ) /xmsgc) { $parsed .= parse_qq_like_endswith($1); $term = 1; }
  24         38  
2308 34         62 elsif (/\G ( \s+ ) /xmsgc) { $parsed .= $1;
2309 34         94 while (/\G ( \s+ | [#] [^\n]* ) /xmsgc) {
2310 2         7 $parsed .= $1;
2311             }
2312 34 100       158 if (/\G ( [A-Za-z_0-9] ) /xmsgc) { $parsed .= parse_qq_like_endswith($1); $term = 1; }
  3 100       9  
  3 100       6  
    100          
    50          
2313 1         4 elsif (/\G ( ['] ) /xmsgc) { $parsed .= parse_q__like_endswith($1); $term = 1; }
  1         3  
2314 4         9 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { $parsed .= parse_qq_like_balanced($1); $term = 1; }
  4         8  
2315 1         4 elsif (m{\G( [/] ) }xmsgc) { $parsed .= parse_qq_like_endswith($1); $term = 1; }
  1         4  
2316 25         46 elsif (/\G ( [\S] ) /xmsgc) { $parsed .= parse_qq_like_endswith($1); $term = 1; }
  25         47  
2317 0         0 else { die "$0(@{[__LINE__]}): $ARGV[0] has not closed:\n", $parsed; }
  0         0  
2318             }
2319 0         0 else { die "$0(@{[__LINE__]}): $ARGV[0] has not closed:\n", $parsed; }
  0         0  
2320             }
2321              
2322             # m/.../, qr/.../
2323             elsif (/\G ( m | qr ) \b /xmsgc) {
2324 1597         4166 $parsed .= $1;
2325 1597         2190 my $regexp = '';
2326 1597 100       5787 if (/\G ( [#] ) /xmsgc) { $regexp .= parse_re_endswith('m',$1); } # qr#...#
  2 100       6  
    100          
    100          
    100          
    100          
    50          
2327 631         1188 elsif (/\G ( ['] ) /xmsgc) { $regexp .= parse_re_as_q_endswith('m',$1); } # qr'...'
2328 8         21 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { $regexp .= parse_re_balanced('m',$1); } # qr{...}
2329 314         706 elsif (m{\G( [/] ) }xmsgc) { $regexp .= parse_re_endswith('m',$1); } # qr/.../
2330 530         1488 elsif (/\G ( [:\@] ) /xmsgc) { $regexp .= '`' . quotee_of(parse_re_endswith('m',$1)) . '`'; } # qr@...@
2331 44         95 elsif (/\G ( [\S] ) /xmsgc) { $regexp .= parse_re_endswith('m',$1); } # qr?...?
2332 68         109 elsif (/\G ( \s+ ) /xmsgc) { $parsed .= $1; $regexp .= $1; # qr SPACE ...
  68         98  
2333 68         179 while (/\G ( \s+ | [#] [^\n]* ) /xmsgc) {
2334 4         14 $parsed .= $1;
2335             }
2336 68 100       294 if (/\G ( [A-Za-z_0-9] ) /xmsgc) { $regexp .= parse_re_endswith('m',$1); } # qr SPACE A...A
  6 100       14  
    100          
    100          
    100          
    50          
2337 2         5 elsif (/\G ( ['] ) /xmsgc) { $regexp .= parse_re_as_q_endswith('m',$1); } # qr SPACE '...'
2338 8         19 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { $regexp .= parse_re_balanced('m',$1); } # qr SPACE {...}
2339 2         6 elsif (m{\G( [/] ) }xmsgc) { $regexp .= parse_re_endswith('m',$1); } # qr SPACE /.../
2340 4         12 elsif (/\G ( [:\@] ) /xmsgc) { $regexp .= '`' . quotee_of(parse_re_endswith('m',$1)) . '`'; } # qr SPACE @...@
2341 46         98 elsif (/\G ( [\S] ) /xmsgc) { $regexp .= parse_re_endswith('m',$1); } # qr SPACE ?...?
2342 0         0 else { die "$0(@{[__LINE__]}): $ARGV[0] has not closed:\n", $parsed; }
  0         0  
2343             }
2344 0         0 else { die "$0(@{[__LINE__]}): $ARGV[0] has not closed:\n", $parsed; }
  0         0  
2345              
2346             # /i modifier
2347 1597         3054 my($modifier_i, $modifier_not_cegir, $modifier_cegr) = parse_re_modifier();
2348 1597 100       2689 if ($modifier_i) {
2349 21         90 $parsed .= sprintf('{\\G${mb::_anchor}@{[mb::_ignorecase(qr%s%s)]}@{[mb::_m_passed()]}}%s', $regexp, $modifier_not_cegir, $modifier_cegr);
2350             }
2351             else {
2352 1576         5600 $parsed .= sprintf('{\\G${mb::_anchor}@{[' . 'qr%s%s ]}@{[mb::_m_passed()]}}%s', $regexp, $modifier_not_cegir, $modifier_cegr);
2353             }
2354 1597         2380 $term = 1;
2355             }
2356              
2357             # 3-quotes
2358              
2359             # s/.../.../
2360             elsif (/\G ( s ) \b /xmsgc) {
2361 1709         4867 $parsed .= $1;
2362 1709         2452 my $regexp = '';
2363 1709         2103 my $comment = '';
2364 1709         2443 my @replacement = ();
2365 1709 100       7573 if (/\G ( [#] ) /xmsgc) { $regexp .= parse_re_endswith('s',$1); @replacement = parse_qq_like_endswith($1); } # s#...#...#
  1 100       4  
  1 100       4  
    100          
    100          
    100          
    50          
2366 286         611 elsif (/\G ( ['] ) /xmsgc) { $regexp .= parse_re_as_q_endswith('s',$1); @replacement = parse_qq_like_endswith($1); } # s'...'...'
  286         637  
2367 240         517 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { $regexp .= parse_re_balanced('s',$1); # s{...}...
2368 240 50       1169 if (/\G ( [#] ) /xmsgc) { @replacement = parse_qq_like_endswith($1); } # s{}#...#
  0 100       0  
    100          
    100          
    100          
    50          
2369 4         16 elsif (/\G ( ['] ) /xmsgc) { @replacement = parse_qq_like_endswith($1); } # s{}'...'
2370 16         37 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { @replacement = parse_qq_like_balanced($1); } # s{}{...}
2371 4         13 elsif (m{\G( [/] ) }xmsgc) { @replacement = parse_qq_like_endswith($1); } # s{}/.../
2372 96         223 elsif (/\G ( [\S] ) /xmsgc) { @replacement = parse_qq_like_endswith($1); } # s{}?...?
2373 120         203 elsif (/\G ( \s+ ) /xmsgc) { $comment .= $1; # s{} SPACE ...
2374 120         342 while (/\G ( \s+ | [#] [^\n]* ) /xmsgc) {
2375 0         0 $comment .= $1;
2376             }
2377 120 50       538 if (/\G ( [A-Za-z_0-9] ) /xmsgc) { @replacement = parse_qq_like_endswith($1); } # s{} SPACE A...A
  0 100       0  
    100          
    100          
    50          
2378 4         16 elsif (/\G ( ['] ) /xmsgc) { @replacement = parse_qq_like_endswith($1); } # s{} SPACE '...'
2379 16         32 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { @replacement = parse_qq_like_balanced($1); } # s{} SPACE {...}
2380 4         206 elsif (m{\G( [/] ) }xmsgc) { @replacement = parse_qq_like_endswith($1); } # s{} SPACE /.../
2381 96         203 elsif (/\G ( [\S] ) /xmsgc) { @replacement = parse_qq_like_endswith($1); } # s{} SPACE ?...?
2382 0         0 else { die "$0(@{[__LINE__]}): $ARGV[0] has not closed:\n", $parsed; }
  0         0  
2383             }
2384 0         0 else { die "$0(@{[__LINE__]}): $ARGV[0] has not closed:\n", $parsed; }
  0         0  
2385             }
2386 350         804 elsif (m{\G( [/] ) }xmsgc) { $regexp .= parse_re_endswith('s',$1); @replacement = parse_qq_like_endswith($1); } # s/.../.../
  350         733  
2387 528         1133 elsif (/\G ( [:\@] ) /xmsgc) { $regexp .= '`' . quotee_of(parse_re_endswith('s',$1)) . '`';
2388 528         1127 @replacement = parse_qq_like_endswith($1); } # s@...@...@
2389 22         49 elsif (/\G ( [\S] ) /xmsgc) { $regexp .= parse_re_endswith('s',$1); @replacement = parse_qq_like_endswith($1); } # s?...?...?
  22         50  
2390 282         486 elsif (/\G ( \s+ ) /xmsgc) { $parsed .= $1; $regexp .= $1; # s SPACE ...
  282         359  
2391 282         825 while (/\G ( \s+ | [#] [^\n]* ) /xmsgc) {
2392 12         39 $parsed .= $1;
2393             }
2394 282 100       998 if (/\G ( [A-Za-z_0-9] ) /xmsgc) { $regexp .= parse_re_endswith('s',$1); @replacement = parse_qq_like_endswith($1); } # s SPACE A...A...A
  12 100       26  
  12 100       29  
    100          
    100          
    50          
2395 1         4 elsif (/\G ( ['] ) /xmsgc) { $regexp .= parse_re_as_q_endswith('s',$1); @replacement = parse_qq_like_endswith($1); } # s SPACE '...'...'
  1         4  
2396 244         538 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { $regexp .= parse_re_balanced('s',$1); # s SPACE {...}...
2397 244 100       1229 if (/\G ( [#] ) /xmsgc) { @replacement = parse_qq_like_endswith($1); } # s SPACE {}#...#
  1 100       3  
    100          
    100          
    100          
    50          
2398 4         15 elsif (/\G ( ['] ) /xmsgc) { @replacement = parse_qq_like_endswith($1); } # s SPACE {}'...'
2399 17         36 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { @replacement = parse_qq_like_balanced($1); } # s SPACE {}{...}
2400 4         15 elsif (m{\G( [/] ) }xmsgc) { @replacement = parse_qq_like_endswith($1); } # s SPACE {}/.../
2401 96         211 elsif (/\G ( [\S] ) /xmsgc) { @replacement = parse_qq_like_endswith($1); } # s SPACE {}?...?
2402 122         201 elsif (/\G ( \s+ ) /xmsgc) { $comment .= $1; # s SPACE {} SPACE ...
2403 122         327 while (/\G ( \s+ | [#] [^\n]* ) /xmsgc) {
2404 8         28 $comment .= $1;
2405             }
2406 122 50       544 if (/\G ( [A-Za-z_0-9] ) /xmsgc) { @replacement = parse_qq_like_endswith($1); } # s SPACE {} SPACE A...A
  0 100       0  
    100          
    100          
    50          
2407 4         18 elsif (/\G ( ['] ) /xmsgc) { @replacement = parse_qq_like_endswith($1); } # s SPACE {} SPACE '...'
2408 18         42 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { @replacement = parse_qq_like_balanced($1); } # s SPACE {} SPACE {...}
2409 4         18 elsif (m{\G( [/] ) }xmsgc) { @replacement = parse_qq_like_endswith($1); } # s SPACE {} SPACE /.../
2410 96         199 elsif (/\G ( [\S] ) /xmsgc) { @replacement = parse_qq_like_endswith($1); } # s SPACE {} SPACE ?...?
2411 0         0 else { die "$0(@{[__LINE__]}): $ARGV[0] has not closed:\n", $parsed; }
  0         0  
2412             }
2413 0         0 else { die "$0(@{[__LINE__]}): $ARGV[0] has not closed:\n", $parsed; }
  0         0  
2414             }
2415 1         4 elsif (m{\G( [/] ) }xmsgc) { $regexp .= parse_re_endswith('s',$1); @replacement = parse_qq_like_endswith($1); } # s SPACE /.../.../
  1         3  
2416 2         6 elsif (/\G ( [:\@] ) /xmsgc) { $regexp .= '`' . quotee_of(parse_re_endswith('s',$1)) . '`';
2417 2         6 @replacement = parse_qq_like_endswith($1); } # s SPACE @...@...@
2418 22         47 elsif (/\G ( [\S] ) /xmsgc) { $regexp .= parse_re_endswith('s',$1); @replacement = parse_qq_like_endswith($1); } # s SPACE ?...?...?
  22         52  
2419 0         0 else { die "$0(@{[__LINE__]}): $ARGV[0] has not closed:\n", $parsed; }
  0         0  
2420             }
2421 0         0 else { die "$0(@{[__LINE__]}): $ARGV[0] has not closed:\n", $parsed; }
  0         0  
2422              
2423 1709         3153 my($modifier_i, $modifier_not_cegir, $modifier_cegr) = parse_re_modifier();
2424 1709         2485 my $replacement = '';
2425 1709         2300 my $eval = '';
2426              
2427             # has /e modifier
2428 1709 100       5325 if (my $e = $modifier_cegr =~ tr/e//d) {
    100          
    100          
2429 9         17 $replacement = 'q'. $replacement[1]; # q-type quotee
2430 9         18 $eval = 'mb::eval ' x $e;
2431             }
2432              
2433             # s''q-quotee'
2434             elsif ($replacement[0] =~ /\A ' /xms) {
2435 300         444 $replacement = $replacement[1]; # q-type quotee
2436             }
2437              
2438             # s##qq-quotee#
2439             elsif ($replacement[0] =~ /\A [#] /xms) {
2440 2         5 $replacement = 'qq' . $replacement[0]; # qq-type quotee
2441             }
2442              
2443             # s//qq-quotee/
2444             else {
2445 1398         1992 $replacement = 'qq ' . $replacement[0]; # qq-type quotee
2446             }
2447              
2448             # /i modifier
2449 1709 100       2574 if ($modifier_i) {
2450 18         82 $parsed .= sprintf('{(\\G${mb::_anchor})@{[mb::_ignorecase(qr%s%s)]}@{[mb::_s_passed()]}}%s{$1 . %s%s}e%s', $regexp, $modifier_not_cegir, $comment, $eval, $replacement, $modifier_cegr);
2451             }
2452             else {
2453 1691         6654 $parsed .= sprintf('{(\\G${mb::_anchor})@{[' . 'qr%s%s ]}@{[mb::_s_passed()]}}%s{$1 . %s%s}e%s', $regexp, $modifier_not_cegir, $comment, $eval, $replacement, $modifier_cegr);
2454             }
2455 1709         3385 $term = 1;
2456             }
2457              
2458             # tr/.../.../, y/.../.../
2459             elsif (/\G (?: tr | y ) \b /xmsgc) {
2460 1250         2205 $parsed .= 's'; # not 'tr'
2461 1250         1497 my $search = '';
2462 1250         1304 my $comment = '';
2463 1250         1425 my $replacement = '';
2464 1250 100       4810 if (/\G ( [#] ) /xmsgc) { $search .= parse_q__like_endswith($1); $replacement .= parse_q__like_endswith($1); } # tr#...#...#
  2 100       7  
  2 100       5  
    100          
    100          
    50          
2465 128         282 elsif (/\G ( ['] ) /xmsgc) { $search .= parse_q__like_endswith($1); $replacement .= parse_q__like_endswith($1); } # tr'...'...'
  128         217  
2466 480         883 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { $search .= parse_q__like_balanced($1); # tr{...}...
2467 480 50       2492 if (/\G ( [#] ) /xmsgc) { $replacement .= parse_q__like_endswith($1); } # tr{}#...#
  0 100       0  
    100          
    100          
    100          
    50          
2468 8         28 elsif (/\G ( ['] ) /xmsgc) { $replacement .= parse_q__like_endswith($1); } # tr{}'...'
2469 32         57 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { $replacement .= parse_q__like_balanced($1); } # tr{}{...}
2470 8         24 elsif (m{\G( [/] ) }xmsgc) { $replacement .= parse_q__like_endswith($1); } # tr{}/.../
2471 192         330 elsif (/\G ( [\S] ) /xmsgc) { $replacement .= parse_q__like_endswith($1); } # tr{}?...?
2472 240         352 elsif (/\G ( \s+ ) /xmsgc) { $comment .= $1; # tr{} SPACE ...
2473 240         556 while (/\G ( \s+ | [#] [^\n]* ) /xmsgc) {
2474 0         0 $comment .= $1;
2475             }
2476 240 50       921 if (/\G ( [A-Za-z_0-9] ) /xmsgc) { $replacement .= parse_q__like_endswith($1); } # tr{} SPACE A...A
  0 100       0  
    100          
    100          
    50          
2477 8         26 elsif (/\G ( ['] ) /xmsgc) { $replacement .= parse_q__like_endswith($1); } # tr{} SPACE '...'
2478 32         49 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { $replacement .= parse_q__like_balanced($1); } # tr{} SPACE {...}
2479 8         25 elsif (m{\G( [/] ) }xmsgc) { $replacement .= parse_q__like_endswith($1); } # tr{} SPACE /.../
2480 192         305 elsif (/\G ( [\S] ) /xmsgc) { $replacement .= parse_q__like_endswith($1); } # tr{} SPACE ?...?
2481 0         0 else { die "$0(@{[__LINE__]}): $ARGV[0] has not closed:\n", $parsed; }
  0         0  
2482             }
2483 0         0 else { die "$0(@{[__LINE__]}): $ARGV[0] has not closed:\n", $parsed; }
  0         0  
2484             }
2485 36         67 elsif (m{\G( [/] ) }xmsgc) { $search .= parse_q__like_endswith($1); $replacement .= parse_q__like_endswith($1); } # tr/.../.../
  36         66  
2486 48         131 elsif (/\G ( [\S] ) /xmsgc) { $search .= parse_q__like_endswith($1); $replacement .= parse_q__like_endswith($1); } # tr?...?...?
  48         82  
2487 556         1144 elsif (/\G ( \s+ ) /xmsgc) { $parsed .= $1; # tr SPACE ...
2488 556         1335 while (/\G ( \s+ | [#] [^\n]* ) /xmsgc) {
2489 24         71 $parsed .= $1;
2490             }
2491 556 100       1726 if (/\G ( [A-Za-z_0-9] ) /xmsgc) { $search .= parse_q__like_endswith($1); $replacement .= parse_q__like_endswith($1); } # tr SPACE A...A...A
  16 100       40  
  16 100       33  
    100          
    50          
2492 2         9 elsif (/\G ( ['] ) /xmsgc) { $search .= parse_q__like_endswith($1); $replacement .= parse_q__like_endswith($1); } # tr SPACE '...'...'
  2         7  
2493 488         839 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { $search .= parse_q__like_balanced($1); # tr SPACE {...}...
2494 488 100       2171 if (/\G ( [#] ) /xmsgc) { $replacement .= parse_q__like_endswith($1); } # tr SPACE {}#...#
  2 100       5  
    100          
    100          
    100          
    50          
2495 8         27 elsif (/\G ( ['] ) /xmsgc) { $replacement .= parse_q__like_endswith($1); } # tr SPACE {}'...'
2496 34         51 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { $replacement .= parse_q__like_balanced($1); } # tr SPACE {}{...}
2497 8         25 elsif (m{\G( [/] ) }xmsgc) { $replacement .= parse_q__like_endswith($1); } # tr SPACE {}/.../
2498 192         350 elsif (/\G ( [\S] ) /xmsgc) { $replacement .= parse_q__like_endswith($1); } # tr SPACE {}?...?
2499 244         352 elsif (/\G ( \s+ ) /xmsgc) { $comment .= $1; # tr SPACE {} SPACE ...
2500 244         597 while (/\G ( \s+ | [#] [^\n]* ) /xmsgc) {
2501 16         51 $comment .= $1;
2502             }
2503 244 50       888 if (/\G ( [A-Za-z_0-9] ) /xmsgc) { $replacement .= parse_q__like_endswith($1); } # tr SPACE {} SPACE A...A
  0 100       0  
    100          
    100          
    50          
2504 8         23 elsif (/\G ( ['] ) /xmsgc) { $replacement .= parse_q__like_endswith($1); } # tr SPACE {} SPACE '...'
2505 36         56 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { $replacement .= parse_q__like_balanced($1); } # tr SPACE {} SPACE {...}
2506 8         24 elsif (m{\G( [/] ) }xmsgc) { $replacement .= parse_q__like_endswith($1); } # tr SPACE {} SPACE /.../
2507 192         320 elsif (/\G ( [\S] ) /xmsgc) { $replacement .= parse_q__like_endswith($1); } # tr SPACE {} SPACE ?...?
2508 0         0 else { die "$0(@{[__LINE__]}): $ARGV[0] has not closed:\n", $parsed; }
  0         0  
2509             }
2510 0         0 else { die "$0(@{[__LINE__]}): $ARGV[0] has not closed:\n", $parsed; }
  0         0  
2511             }
2512 2         10 elsif (m{\G( [/] ) }xmsgc) { $search .= parse_q__like_endswith($1); $replacement .= parse_q__like_endswith($1); } # tr SPACE /.../.../
  2         36  
2513 48         104 elsif (/\G ( [\S] ) /xmsgc) { $search .= parse_q__like_endswith($1); $replacement .= parse_q__like_endswith($1); } # tr SPACE ?...?...?
  48         87  
2514 0         0 else { die "$0(@{[__LINE__]}): $ARGV[0] has not closed:\n", $parsed; }
  0         0  
2515             }
2516 0         0 else { die "$0(@{[__LINE__]}): $ARGV[0] has not closed:\n", $parsed; }
  0         0  
2517              
2518             # modifier
2519 1250         2288 my($modifier_not_r, $modifier_r) = parse_tr_modifier();
2520 1250 50       2257 if ($modifier_r) {
    100          
2521 0         0 $parsed .= sprintf(q<{[\x00-\xFF]*> . q<}%s{mb::tr($&,q%s,q%s,'%sr')}er>, $comment, $search, $replacement, $modifier_not_r);
2522             }
2523             elsif ($modifier_not_r =~ /s/) {
2524             # these implementations cannot return right number of codepoints replaced. if you want number, you can use mb::tr().
2525 20         80 $parsed .= sprintf(q<{[\x00-\xFF]*> . q<}%s{mb::tr($&,q%s,q%s,'%sr')}e>, $comment, $search, $replacement, $modifier_not_r);
2526             # $parsed .= sprintf(q<{(\\G${mb::_anchor})(%s+)}%s{$1.mb::tr($2,q%s,q%s,'%sr')}eg>, codepoint_tr($search, $modifier_not_r), $comment, $search, $replacement, $modifier_not_r);
2527             }
2528             else {
2529 1230         2027 $parsed .= sprintf(q<{(\\G${mb::_anchor})(%s)}%s{$1.mb::tr($2,q%s,q%s,'%sr')}eg>, codepoint_tr($search, $modifier_not_r), $comment, $search, $replacement, $modifier_not_r);
2530             }
2531 1250         2098 $term = 1;
2532             }
2533              
2534             # indented here document
2535 1         4 elsif (/\G ( <<~ ([A-Za-z_][A-Za-z_0-9]*) ) /xmsgc) { $parsed .= $1; push @here_document_delimiter, ["[\\t ]*$2$R", 'qq']; $term = 1; }
  1         8  
  1         2  
2536 1         5 elsif (/\G ( <<~ \\([A-Za-z_][A-Za-z_0-9]*) ) /xmsgc) { $parsed .= $1; push @here_document_delimiter, ["[\\t ]*$2$R", 'q' ]; $term = 1; }
  1         6  
  1         3  
2537 3         10 elsif (/\G ( <<~ [\t ]* '([A-Za-z_][A-Za-z_0-9]*)' ) /xmsgc) { $parsed .= $1; push @here_document_delimiter, ["[\\t ]*$2$R", 'q' ]; $term = 1; }
  3         12  
  3         6  
2538 3         10 elsif (/\G ( <<~ [\t ]* "([A-Za-z_][A-Za-z_0-9]*)" ) /xmsgc) { $parsed .= $1; push @here_document_delimiter, ["[\\t ]*$2$R", 'qq']; $term = 1; }
  3         10  
  3         5  
2539 3         10 elsif (/\G ( <<~ [\t ]* `([A-Za-z_][A-Za-z_0-9]*)` ) /xmsgc) { $parsed .= $1; push @here_document_delimiter, ["[\\t ]*$2$R", 'qq']; $term = 1; }
  3         13  
  3         5  
2540              
2541             # here document
2542 1         4 elsif (/\G ( << ([A-Za-z_][A-Za-z_0-9]*) ) /xmsgc) { $parsed .= $1; push @here_document_delimiter, [ "$2$R", 'qq']; $term = 1; }
  1         5  
  1         2  
2543 1         3 elsif (/\G ( << \\([A-Za-z_][A-Za-z_0-9]*) ) /xmsgc) { $parsed .= $1; push @here_document_delimiter, [ "$2$R", 'q' ]; $term = 1; }
  1         16  
  1         5  
2544 4         13 elsif (/\G ( << [\t ]* '([A-Za-z_][A-Za-z_0-9]*)' ) /xmsgc) { $parsed .= $1; push @here_document_delimiter, [ "$2$R", 'q' ]; $term = 1; }
  4         16  
  4         9  
2545 3         10 elsif (/\G ( << [\t ]* "([A-Za-z_][A-Za-z_0-9]*)" ) /xmsgc) { $parsed .= $1; push @here_document_delimiter, [ "$2$R", 'qq']; $term = 1; }
  3         11  
  3         5  
2546 3         11 elsif (/\G ( << [\t ]* `([A-Za-z_][A-Za-z_0-9]*)` ) /xmsgc) { $parsed .= $1; push @here_document_delimiter, [ "$2$R", 'qq']; $term = 1; }
  3         11  
  3         6  
2547              
2548             # sub subroutine();
2549             elsif (/\G ( sub \s+ [A-Za-z_][A-Za-z_0-9]*(?:(?:'|::)[A-Za-z_][A-Za-z_0-9]*)* \s* ) /xmsgc) {
2550 10         36 $parsed .= $1;
2551 10         16 $term = 0;
2552             }
2553              
2554             # while (<<>>)
2555             elsif (/\G ( while \s* \( \s* ) ( <<>> ) ( \s* \) ) /xmsgc) {
2556 2         6 $parsed .= $1;
2557 2         5 $parsed .= $2;
2558 2         3 $parsed .= $3;
2559 2         3 $term = 0;
2560             }
2561              
2562             # while (<${file}>)
2563             # while (<$file>)
2564             # while ()
2565             # while ()
2566             elsif (/\G ( while \s* \( \s* ) (<) ((?:(?!\s)${mb::x})*?) (>) ( \s* \) ) /xmsgc) {
2567 8         23 $parsed .= $1;
2568 8         36 my($open_bracket, $quotee, $close_bracket) = ($2, $3, $4);
2569 8         17 my $close_bracket2 = $5;
2570 8         12 $parsed .= $open_bracket;
2571 8         73 while ($quotee =~ /\G (${mb::x}) /xmsgc) {
2572 50         91 $parsed .= escape_qq($1, $close_bracket);
2573             }
2574 8         15 $parsed .= $close_bracket;
2575 8         19 $parsed .= $close_bracket2;
2576 8         14 $term = 0;
2577             }
2578              
2579             # while <<>>
2580             elsif (/\G ( while \s* ) ( <<>> ) /xmsgc) {
2581 0         0 $parsed .= $1;
2582 0         0 $parsed .= $2;
2583 0         0 $term = 0;
2584             }
2585              
2586             # while <${file}>
2587             # while <$file>
2588             # while
2589             # while
2590             elsif (/\G ( while \s* ) (<) ((?:(?!\s)${mb::x})*?) (>) /xmsgc) {
2591 0         0 $parsed .= $1;
2592 0         0 my($open_bracket, $quotee, $close_bracket) = ($2, $3, $4);
2593 0         0 $parsed .= $open_bracket;
2594 0         0 while ($quotee =~ /\G (${mb::x}) /xmsgc) {
2595 0         0 $parsed .= escape_qq($1, $close_bracket);
2596             }
2597 0         0 $parsed .= $close_bracket;
2598 0         0 $term = 0;
2599             }
2600              
2601             # if (expr)
2602             # elsif (expr)
2603             # unless (expr)
2604             # while (expr)
2605             # until (expr)
2606             # given (expr)
2607             # when (expr)
2608             elsif (/\G ( (?: if | elsif | unless | while | until | given | when ) \s* ) ( \( ) /xmsgc) {
2609 25         259 $parsed .= $1;
2610              
2611             # outputs expr
2612 25         81 my $expr = parse_expr_balanced($2);
2613 25         306 $parsed .= $expr;
2614 25         185 $term = 0;
2615             }
2616              
2617             # else
2618             elsif (/\G ( else ) \b /xmsgc) {
2619 1         4 $parsed .= $1;
2620 1         2 $term = 0;
2621             }
2622              
2623             # ... if expr;
2624             # ... unless expr;
2625             # ... while expr;
2626             # ... until expr;
2627             elsif (/\G ( if | unless | while | until ) \b /xmsgc) {
2628 8         21 $parsed .= $1;
2629 8         12 $term = 0;
2630             }
2631              
2632             # foreach my $var (expr) --> foreach my $var (expr)
2633             # for my $var (expr) --> for my $var (expr)
2634             elsif (/\G ( (?: foreach | for ) \s+ my \s* [\$] [A-Za-z_][A-Za-z_0-9]* ) ( \( ) /xmsgc) {
2635 0         0 $parsed .= $1;
2636 0         0 $parsed .= parse_expr_balanced($2);
2637 0         0 $term = 0;
2638             }
2639              
2640             # foreach $var (expr) --> foreach $var (expr)
2641             # for $var (expr) --> for $var (expr)
2642             elsif (/\G ( (?: foreach | for ) \s* [\$] [\$]* (?: \{[A-Za-z_][A-Za-z_0-9]*(?:(?:'|::)[A-Za-z_][A-Za-z_0-9]*)*\} | [A-Za-z_][A-Za-z_0-9]*(?:(?:'|::)[A-Za-z_][A-Za-z_0-9]* ) ) ) ( \( ) /xmsgc) {
2643 0         0 $parsed .= $1;
2644 0         0 $parsed .= parse_expr_balanced($2);
2645 0         0 $term = 0;
2646             }
2647              
2648             # foreach (expr1; expr2; expr3) --> foreach (expr1; expr2; expr3)
2649             # foreach (expr) --> foreach (expr)
2650             # for (expr1; expr2; expr3) --> for (expr1; expr2; expr3)
2651             # for (expr) --> for (expr)
2652             elsif (/\G ( (?: foreach | for ) \s* ) ( \( ) /xmsgc) {
2653 4         14 $parsed .= $1;
2654 4         10 $parsed .= parse_expr_balanced($2);
2655 4         7 $term = 0;
2656             }
2657              
2658             # CORE::split --> CORE::split
2659             elsif (/\G ( CORE::split ) \b /xmsgc) {
2660 0         0 $parsed .= $1;
2661 0         0 $term = 1;
2662             }
2663              
2664             # split --> mb::_split by default
2665             elsif (/\G (?: mb:: )? ( split ) \b /xmsgc) {
2666 675         1444 $parsed .= "mb::_split";
2667              
2668             # parse \s and '('
2669 675         805 while (1) {
2670 1354 100       3792 if (/\G ( \s+ ) /xmsgc) {
    100          
    100          
2671 294         737 $parsed .= $1;
2672             }
2673             elsif (/\G ( \( ) /xmsgc) {
2674 385         899 $parsed .= $1;
2675             }
2676             elsif (/\G ( \# .* \n ) /xmgc) {
2677 16         33 $parsed .= $1;
2678 16         27 last;
2679             }
2680             else {
2681 659         981 last;
2682             }
2683             }
2684 675         952 my $regexp = '';
2685              
2686             # split /^/ --> mb::_split qr/^/m
2687             # split /.../ --> mb::_split qr/.../
2688 675 100       2265 if (m{\G ( [/] ) }xmsgc) {
    100          
2689 22         31 $parsed .= "qr";
2690 22         48 $regexp = parse_re_endswith('m',$1); # split /.../
2691 22         47 my($modifier_i, $modifier_not_cegir, $modifier_cegr) = parse_re_modifier();
2692              
2693             # P.794 29.2.161. split
2694             # in Chapter 29: Functions
2695             # of ISBN 0-596-00027-8 Programming Perl Third Edition.
2696              
2697             # P.951 split
2698             # in Chapter 27: Functions
2699             # of ISBN 978-0-596-00492-7 Programming Perl 4th Edition.
2700              
2701             # said "The //m modifier is assumed when you split on the pattern /^/",
2702             # but perl5.008 is not so. Therefore, this software adds //m.
2703             # (and so on)
2704              
2705 22 100       59 if ($modifier_not_cegir !~ /m/xms) {
2706 16         23 $modifier_not_cegir .= 'm';
2707             }
2708              
2709             # /i modifier
2710 22 100       36 if ($modifier_i) {
2711 6         22 $parsed .= sprintf('{@{[mb::_ignorecase(qr%s%s)]}}%s', $regexp, $modifier_not_cegir, $modifier_cegr);
2712             }
2713             else {
2714 16         60 $parsed .= sprintf('{@{[' . 'qr%s%s ]}}%s', $regexp, $modifier_not_cegir, $modifier_cegr);
2715             }
2716             }
2717              
2718             # split m/^/ --> mb::_split qr/^/m
2719             # split m/.../ --> mb::_split qr/.../
2720             elsif (/\G ( m | qr ) \b /xmsgc) {
2721 609         916 $parsed .= "qr";
2722              
2723 609 100       2811 if (/\G ( [#] ) /xmsgc) { $regexp = parse_re_endswith('m',$1); } # split qr#...#
  8 100       19  
    100          
    100          
    100          
    100          
    50          
2724 8         20 elsif (/\G ( ['] ) /xmsgc) { $regexp = parse_re_as_q_endswith('m',$1); } # split qr'...'
2725 32         69 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { $regexp = parse_re_balanced('m',$1); } # split qr{...}
2726 81         161 elsif (m{\G( [/] ) }xmsgc) { $regexp = parse_re_endswith('m',$1); } # split qr/.../
2727 16         39 elsif (/\G ( [:\@] ) /xmsgc) { $regexp = '`' . quotee_of(parse_re_endswith('m',$1)) . '`'; } # split qr@...@
2728 184         371 elsif (/\G ( [\S] ) /xmsgc) { $regexp = parse_re_endswith('m',$1); } # split qr?...?
2729 280         517 elsif (/\G ( \s+ ) /xmsgc) { $parsed .= $1; $regexp = $1; # split qr SPACE ...
  280         447  
2730 280         722 while (/\G ( \s+ | [#] [^\n]* ) /xmsgc) {
2731 32         95 $parsed .= $1;
2732             }
2733 280 100       1245 if (/\G ( [A-Za-z_0-9] ) /xmsgc) { $regexp .= parse_re_endswith('m',$1); } # split qr SPACE A...A
  24 100       51  
    100          
    100          
    100          
    50          
2734 8         18 elsif (/\G ( ['] ) /xmsgc) { $regexp .= parse_re_as_q_endswith('m',$1); } # split qr SPACE '...'
2735 32         81 elsif (/\G ( [\(\{\[\<] ) /xmsgc) { $regexp .= parse_re_balanced('m',$1); } # split qr SPACE {...}
2736 8         18 elsif (m{\G( [/] ) }xmsgc) { $regexp .= parse_re_endswith('m',$1); } # split qr SPACE /.../
2737 16         37 elsif (/\G ( [:\@] ) /xmsgc) { $regexp .= '`' . quotee_of(parse_re_endswith('m',$1)) . '`'; } # split qr SPACE @...@
2738 192         431 elsif (/\G ( [\S] ) /xmsgc) { $regexp .= parse_re_endswith('m',$1); } # split qr SPACE ?...?
2739 0         0 else { die "$0(@{[__LINE__]}): $ARGV[0] has not closed:\n", $parsed; }
  0         0  
2740             }
2741 0         0 else { die "$0(@{[__LINE__]}): $ARGV[0] has not closed:\n", $parsed; }
  0         0  
2742              
2743 609         1074 my($modifier_i, $modifier_not_cegir, $modifier_cegr) = parse_re_modifier();
2744              
2745 609 100       1284 if ($modifier_not_cegir !~ /m/xms) {
2746 605         753 $modifier_not_cegir .= 'm';
2747             }
2748              
2749             # /i modifier
2750 609 100       947 if ($modifier_i) {
2751 16         55 $parsed .= sprintf('{@{[mb::_ignorecase(qr%s%s)]}}%s', $regexp, $modifier_not_cegir, $modifier_cegr);
2752             }
2753             else {
2754 593         1917 $parsed .= sprintf('{@{[' . 'qr%s%s ]}}%s', $regexp, $modifier_not_cegir, $modifier_cegr);
2755             }
2756             }
2757              
2758 675         920 $term = 1;
2759             }
2760              
2761             # provides bare Perl and JPerl compatible functions
2762             elsif (/\G ( (?: lc | lcfirst | uc | ucfirst ) ) \b /xmsgc) {
2763 15         57 $parsed .= "mb::$1";
2764 15         27 $term = 1;
2765             }
2766              
2767             # CORE::function, mb::subroutine, function
2768             elsif (/\G (?: mb:: )? ( require ) (?= \s+ [0-9] ) /xmsgc) {
2769 0         0 $parsed .= $1;
2770 0         0 $term = 1;
2771             }
2772             elsif (/\G (?: mb:: )? ( require ) \b /xmsgc) {
2773 2         10 $parsed .= "mb::$1";
2774 2         4 $term = 1;
2775             }
2776             elsif (/\G ( CORE::require ) \b /xmsgc) {
2777 1         4 $parsed .= $1;
2778 1         3 $term = 1;
2779             }
2780              
2781             # mb::getc() --> mb::getc()
2782             elsif (/\G ( mb::getc (?: \s* \( )+ \s* \) ) /xmsgc) {
2783 0         0 $parsed .= $1;
2784 0         0 $term = 1;
2785             }
2786              
2787             # mb::getc($fh) --> mb::getc($fh)
2788             elsif (/\G ( mb::getc (?: \s* \( )+ \s* \$ ) /xmsgc) {
2789 0         0 $parsed .= $1;
2790 0         0 $term = 1;
2791             }
2792              
2793             # mb::getc(FILE) --> mb::getc(\*FILE)
2794             elsif (/\G ( mb::getc (?: \s* \( )+ \s* ) /xmsgc) {
2795 0         0 $parsed .= $1;
2796 0         0 $parsed .= '\\*';
2797 0         0 $term = 1;
2798             }
2799              
2800             elsif (/\G ( (?: CORE:: | mb:: )? (?: chop | chr | getc | index | lc | lcfirst | length | ord | reverse | rindex | substr | uc | ucfirst ) ) \b /xmsgc) {
2801 50         165 $parsed .= $1;
2802 50         80 $term = 1;
2803             }
2804              
2805             # mb::subroutine
2806             elsif (/\G ( mb:: (?: index_byte | rindex_byte ) ) \b /xmsgc) {
2807 2         8 $parsed .= $1;
2808 2         3 $term = 1;
2809             }
2810              
2811             # CORE::function, function
2812             elsif (/\G ( (?: CORE:: )? (?: _ | abs | chomp | cos | exp | fc | hex | int | __LINE__ | log | oct | pop | pos | quotemeta | rand | rmdir | shift | sin | sqrt | tell | time | umask | wantarray ) ) \b /xmsgc) {
2813 252         654 $parsed .= $1;
2814 252         312 $term = 1;
2815             }
2816              
2817             # function --> mb::subroutine on MSWin32
2818             # implements run on any systems by transpiling once
2819             elsif (/\G ( chdir | lstat | opendir | stat | unlink ) \b /xmsgc) {
2820 184         494 $parsed .= "mb::_$1";
2821 184         258 $term = 1;
2822             }
2823              
2824             # any word
2825             # "\x5F" [_] LOW LINE (U+005F)
2826             # "\x41" [A] LATIN CAPITAL LETTER A (U+0041)
2827             # "\x42" [B] LATIN CAPITAL LETTER B (U+0042)
2828             # "\x43" [C] LATIN CAPITAL LETTER C (U+0043)
2829             # "\x44" [D] LATIN CAPITAL LETTER D (U+0044)
2830             # "\x45" [E] LATIN CAPITAL LETTER E (U+0045)
2831             # "\x46" [F] LATIN CAPITAL LETTER F (U+0046)
2832             # "\x47" [G] LATIN CAPITAL LETTER G (U+0047)
2833             # "\x48" [H] LATIN CAPITAL LETTER H (U+0048)
2834             # "\x49" [I] LATIN CAPITAL LETTER I (U+0049)
2835             # "\x4A" [J] LATIN CAPITAL LETTER J (U+004A)
2836             # "\x4B" [K] LATIN CAPITAL LETTER K (U+004B)
2837             # "\x4C" [L] LATIN CAPITAL LETTER L (U+004C)
2838             # "\x4D" [M] LATIN CAPITAL LETTER M (U+004D)
2839             # "\x4E" [N] LATIN CAPITAL LETTER N (U+004E)
2840             # "\x4F" [O] LATIN CAPITAL LETTER O (U+004F)
2841             # "\x50" [P] LATIN CAPITAL LETTER P (U+0050)
2842             # "\x51" [Q] LATIN CAPITAL LETTER Q (U+0051)
2843             # "\x52" [R] LATIN CAPITAL LETTER R (U+0052)
2844             # "\x53" [S] LATIN CAPITAL LETTER S (U+0053)
2845             # "\x54" [T] LATIN CAPITAL LETTER T (U+0054)
2846             # "\x55" [U] LATIN CAPITAL LETTER U (U+0055)
2847             # "\x56" [V] LATIN CAPITAL LETTER V (U+0056)
2848             # "\x57" [W] LATIN CAPITAL LETTER W (U+0057)
2849             # "\x58" [X] LATIN CAPITAL LETTER X (U+0058)
2850             # "\x59" [Y] LATIN CAPITAL LETTER Y (U+0059)
2851             # "\x5A" [Z] LATIN CAPITAL LETTER Z (U+005A)
2852             # "\x61" [a] LATIN SMALL LETTER A (U+0061)
2853             # "\x62" [b] LATIN SMALL LETTER B (U+0062)
2854             # "\x63" [c] LATIN SMALL LETTER C (U+0063)
2855             # "\x64" [d] LATIN SMALL LETTER D (U+0064)
2856             # "\x65" [e] LATIN SMALL LETTER E (U+0065)
2857             # "\x66" [f] LATIN SMALL LETTER F (U+0066)
2858             # "\x67" [g] LATIN SMALL LETTER G (U+0067)
2859             # "\x68" [h] LATIN SMALL LETTER H (U+0068)
2860             # "\x69" [i] LATIN SMALL LETTER I (U+0069)
2861             # "\x6A" [j] LATIN SMALL LETTER J (U+006A)
2862             # "\x6B" [k] LATIN SMALL LETTER K (U+006B)
2863             # "\x6C" [l] LATIN SMALL LETTER L (U+006C)
2864             # "\x6D" [m] LATIN SMALL LETTER M (U+006D)
2865             # "\x6E" [n] LATIN SMALL LETTER N (U+006E)
2866             # "\x6F" [o] LATIN SMALL LETTER O (U+006F)
2867             # "\x70" [p] LATIN SMALL LETTER P (U+0070)
2868             # "\x71" [q] LATIN SMALL LETTER Q (U+0071)
2869             # "\x72" [r] LATIN SMALL LETTER R (U+0072)
2870             # "\x73" [s] LATIN SMALL LETTER S (U+0073)
2871             # "\x74" [t] LATIN SMALL LETTER T (U+0074)
2872             # "\x75" [u] LATIN SMALL LETTER U (U+0075)
2873             # "\x76" [v] LATIN SMALL LETTER V (U+0076)
2874             # "\x77" [w] LATIN SMALL LETTER W (U+0077)
2875             # "\x78" [x] LATIN SMALL LETTER X (U+0078)
2876             # "\x79" [y] LATIN SMALL LETTER Y (U+0079)
2877             # "\x7A" [z] LATIN SMALL LETTER Z (U+007A)
2878             elsif (/\G ( [A-Za-z_][A-Za-z_0-9]*(?:(?:'|::)[A-Za-z_][A-Za-z_0-9]*)* ) /xmsgc) {
2879 272         718 $parsed .= $1;
2880 272         378 $term = 0;
2881             }
2882              
2883             # any US-ASCII
2884             # "\x3A" [:] COLON (U+003A)
2885             # "\x29" [)] RIGHT PARENTHESIS (U+0029)
2886             # "\x7D" [}] RIGHT CURLY BRACKET (U+007D)
2887             # "\x5D" []] RIGHT SQUARE BRACKET (U+005D)
2888             elsif (/\G ([\x00-\x7F]) /xmsgc) {
2889 8907         22601 $parsed .= $1;
2890 8907         11387 $term = 0;
2891             }
2892              
2893             # otherwise
2894             elsif (/\G (${mb::x}) /xmsgc) {
2895 0         0 die "$0(@{[__LINE__]}): can't parse not US-ASCII '$1'.\n";
  0         0  
2896             }
2897              
2898 38173         124762 return $parsed;
2899             }
2900              
2901             #---------------------------------------------------------------------
2902             # parse expression in balanced blackets
2903             sub parse_expr_balanced {
2904 541     544 0 1155 my($open_bracket) = @_;
2905 541   50     2452 my $close_bracket = {qw| ( ) { } [ ] < > |}->{$open_bracket} || die;
2906 541         1343 my $parsed = $open_bracket;
2907 541         670 my $nest_bracket = 1;
2908 541         576 $term = 0;
2909 541         887 while (1) {
2910              
2911             # open bracket
2912 3232 100       13167 if (/\G (\Q$open_bracket\E) /xmsgc) {
    100          
2913 13         28 $parsed .= $1;
2914 13         16 $term = 0;
2915 13         21 $nest_bracket++;
2916             }
2917              
2918             # close bracket
2919             elsif (/\G (\Q$close_bracket\E) /xmsgc) {
2920 554         1076 $parsed .= $1;
2921 554         648 $term = 1;
2922 554 100       1073 if (--$nest_bracket <= 0) {
2923 541         844 last;
2924             }
2925             }
2926              
2927             # otherwise
2928             else {
2929 2665         6293 $parsed .= parse_expr();
2930             }
2931             }
2932 541         1137 return $parsed;
2933             }
2934              
2935             #---------------------------------------------------------------------
2936             # parse <<'HERE_DOCUMENT' as q-like
2937             sub parse_heredocument_as_q_endswith {
2938 9     12 0 17 my($endswith) = @_;
2939 9         12 my $parsed = '';
2940 9         20 while (1) {
2941 465 100       1604 if (/\G ( $R $endswith ) /xmsgc) {
    50          
2942 9         20 $parsed .= $1;
2943 9         16 last;
2944             }
2945             elsif (/\G (${mb::x}) /xmsgc) {
2946 456         701 $parsed .= $1;
2947             }
2948              
2949             # something wrong happened
2950             else {
2951 0         0 die sprintf(<
2952 0         0 $0(@{[__LINE__]}): something wrong happened in script at pos=%s
2953             ------------------------------------------------------------------------------
2954             %s
2955             ------------------------------------------------------------------------------
2956             END
2957             }
2958             }
2959 9         37 return $parsed;
2960             }
2961              
2962             #---------------------------------------------------------------------
2963             # parse <<"HERE_DOCUMENT" as qq-like
2964             sub parse_heredocument_as_qq_endswith {
2965 14     17 0 23 my($endswith) = @_;
2966 14         21 my $parsed = '';
2967 14         15 my $nest_escape = 0;
2968 14         16 while (1) {
2969 14 50       154 if (/\G ( $R $endswith ) /xmsgc) {
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
2970 14         30 $parsed .= ('>)]}' x $nest_escape);
2971 14         23 $parsed .= $1;
2972 14         26 last;
2973             }
2974              
2975             # \L\u --> \u\L
2976             elsif (/\G \\L \\u /xmsgc) {
2977 0         0 $parsed .= '@{[mb::ucfirst(qq<';
2978 0         0 $parsed .= '@{[mb::lc(qq<';
2979 0         0 $nest_escape++;
2980 0         0 $nest_escape++;
2981             }
2982              
2983             # \U\l --> \l\U
2984             elsif (/\G \\U \\l /xmsgc) {
2985 0         0 $parsed .= '@{[mb::lcfirst(qq<';
2986 0         0 $parsed .= '@{[mb::uc(qq<';
2987 0         0 $nest_escape++;
2988 0         0 $nest_escape++;
2989             }
2990              
2991             # \L
2992             elsif (/\G \\L /xmsgc) {
2993 0         0 $parsed .= '@{[mb::lc(qq<';
2994 0         0 $nest_escape++;
2995             }
2996              
2997             # \U
2998             elsif (/\G \\U /xmsgc) {
2999 0         0 $parsed .= '@{[mb::uc(qq<';
3000 0         0 $nest_escape++;
3001             }
3002              
3003             # \l
3004             elsif (/\G \\l /xmsgc) {
3005 0         0 $parsed .= '@{[mb::lcfirst(qq<';
3006 0         0 $nest_escape++;
3007             }
3008              
3009             # \u
3010             elsif (/\G \\u /xmsgc) {
3011 0         0 $parsed .= '@{[mb::ucfirst(qq<';
3012 0         0 $nest_escape++;
3013             }
3014              
3015             # \Q
3016             elsif (/\G \\Q /xmsgc) {
3017 0         0 $parsed .= '@{[quotemeta(qq<';
3018 0         0 $nest_escape++;
3019             }
3020              
3021             # \E
3022             elsif (/\G \\E /xmsgc) {
3023 0         0 $parsed .= ('>)]}' x $nest_escape);
3024 0         0 $nest_escape = 0;
3025             }
3026              
3027             # \o{...}
3028             elsif (/\G \\o\{ (.*?) \} /xmsgc) {
3029 0         0 $parsed .= escape_to_hex(mb::chr(oct $1), '\\');
3030             }
3031              
3032             # \x{...}
3033             elsif (/\G \\x\{ (.*?) \} /xmsgc) {
3034 0         0 $parsed .= escape_to_hex(mb::chr(hex $1), '\\');
3035             }
3036              
3037             # \any
3038             elsif (/\G (\\) (${mb::x}) /xmsgc) {
3039 0         0 $parsed .= ($1 . escape_qq($2, '\\'));
3040             }
3041              
3042             # $` --> @{[mb::_PREMATCH()]}
3043             # ${`} --> @{[mb::_PREMATCH()]}
3044             # $PREMATCH --> @{[mb::_PREMATCH()]}
3045             # ${PREMATCH} --> @{[mb::_PREMATCH()]}
3046             # ${^PREMATCH} --> @{[mb::_PREMATCH()]}
3047             elsif (/\G (?: \$` | \$\{`\} | \$PREMATCH | \$\{PREMATCH\} | \$\{\^PREMATCH\} ) /xmsgc) {
3048 0         0 $parsed .= '@{[mb::_PREMATCH()]}';
3049             }
3050              
3051             # $& --> @{[mb::_MATCH()]}
3052             # ${&} --> @{[mb::_MATCH()]}
3053             # $MATCH --> @{[mb::_MATCH()]}
3054             # ${MATCH} --> @{[mb::_MATCH()]}
3055             # ${^MATCH} --> @{[mb::_MATCH()]}
3056             elsif (/\G (?: \$& | \$\{&\} | \$MATCH | \$\{MATCH\} | \$\{\^MATCH\} ) /xmsgc) {
3057 0         0 $parsed .= '@{[mb::_MATCH()]}';
3058             }
3059              
3060             # $1 --> @{[mb::_CAPTURE(1)]}
3061             # $2 --> @{[mb::_CAPTURE(2)]}
3062             # $3 --> @{[mb::_CAPTURE(3)]}
3063             elsif (/\G \$ ([1-9][0-9]*) /xmsgc) {
3064 0         0 $parsed .= "\@{[mb::_CAPTURE($1)]}";
3065             }
3066              
3067             # @{^CAPTURE} --> @{[join $", mb::_CAPTURE()]}
3068             elsif (/\G \@\{\^CAPTURE\} /xmsgc) {
3069 0         0 $parsed .= '@{[join $", mb::_CAPTURE()]}';
3070             }
3071              
3072             # ${^CAPTURE}[0] --> @{[mb::_CAPTURE(1)]}
3073             # ${^CAPTURE}[1] --> @{[mb::_CAPTURE(2)]}
3074             # ${^CAPTURE}[2] --> @{[mb::_CAPTURE(3)]}
3075             elsif (/\G \$\{\^CAPTURE\} \s* (\[) /xmsgc) {
3076 0         0 my $n_th = quotee_of(parse_expr_balanced($1));
3077 0         0 $parsed .= "\@{[mb::_CAPTURE($n_th+1)]}";
3078             }
3079              
3080             # @- --> @{[mb::_LAST_MATCH_START()]}
3081             # @LAST_MATCH_START --> @{[mb::_LAST_MATCH_START()]}
3082             # @{LAST_MATCH_START} --> @{[mb::_LAST_MATCH_START()]}
3083             # @{^LAST_MATCH_START} --> @{[mb::_LAST_MATCH_START()]}
3084             elsif (/\G (?: \@- | \@LAST_MATCH_START | \@\{LAST_MATCH_START\} | \@\{\^LAST_MATCH_START\} ) /xmsgc) {
3085 0         0 $parsed .= '@{[mb::_LAST_MATCH_START()]}';
3086             }
3087              
3088             # $-[1] --> @{[mb::_LAST_MATCH_START(1)]}
3089             # $LAST_MATCH_START[1] --> @{[mb::_LAST_MATCH_START(1)]}
3090             # ${LAST_MATCH_START}[1] --> @{[mb::_LAST_MATCH_START(1)]}
3091             # ${^LAST_MATCH_START}[1] --> @{[mb::_LAST_MATCH_START(1)]}
3092             elsif (/\G (?: \$- | \$LAST_MATCH_START | \$\{LAST_MATCH_START\} | \$\{\^LAST_MATCH_START\} ) \s* (\[) /xmsgc) {
3093 0         0 my $n_th = quotee_of(parse_expr_balanced($1));
3094 0         0 $parsed .= "\@{[mb::_LAST_MATCH_START($n_th)]}";
3095             }
3096              
3097             # @+ --> @{[mb::_LAST_MATCH_END()]}
3098             # @LAST_MATCH_END --> @{[mb::_LAST_MATCH_END()]}
3099             # @{LAST_MATCH_END} --> @{[mb::_LAST_MATCH_END()]}
3100             # @{^LAST_MATCH_END} --> @{[mb::_LAST_MATCH_END()]}
3101             elsif (/\G (?: \@\+ | \@LAST_MATCH_END | \@\{LAST_MATCH_END\} | \@\{\^LAST_MATCH_END\} ) /xmsgc) {
3102 0         0 $parsed .= '@{[mb::_LAST_MATCH_END()]}';
3103             }
3104              
3105             # $+[1] --> @{[mb::_LAST_MATCH_END(1)]}
3106             # $LAST_MATCH_END[1] --> @{[mb::_LAST_MATCH_END(1)]}
3107             # ${LAST_MATCH_END}[1] --> @{[mb::_LAST_MATCH_END(1)]}
3108             # ${^LAST_MATCH_END}[1] --> @{[mb::_LAST_MATCH_END(1)]}
3109             elsif (/\G (?: \$\+ | \$LAST_MATCH_END | \$\{LAST_MATCH_END\} | \$\{\^LAST_MATCH_END\} ) \s* (\[) /xmsgc) {
3110 0         0 my $n_th = quotee_of(parse_expr_balanced($1));
3111 0         0 $parsed .= "\@{[mb::_LAST_MATCH_END($n_th)]}";
3112             }
3113              
3114             # any
3115             elsif (/\G (${mb::x}) /xmsgc) {
3116 0         0 $parsed .= escape_qq($1, '\\');
3117             }
3118              
3119             # something wrong happened
3120             else {
3121 0         0 die sprintf(<
3122 0         0 $0(@{[__LINE__]}): something wrong happened in script at pos=%s
3123             ------------------------------------------------------------------------------
3124             %s
3125             ------------------------------------------------------------------------------
3126             END
3127             }
3128             }
3129 14         48 return $parsed;
3130             }
3131              
3132             #---------------------------------------------------------------------
3133             # parse q{string} in balanced blackets
3134             sub parse_q__like_balanced {
3135 1118     1121 0 2112 my($open_bracket) = @_;
3136 1118   50     4434 my $close_bracket = {qw| ( ) { } [ ] < > |}->{$open_bracket} || die;
3137 1118         2270 my $parsed = $open_bracket;
3138 1118         1159 my $nest_bracket = 1;
3139 1118         1095 while (1) {
3140 2266 50       12387 if (/\G (\Q$open_bracket\E) /xmsgc) {
    100          
    50          
3141 0         0 $parsed .= $1;
3142 0         0 $nest_bracket++;
3143             }
3144             elsif (/\G (\Q$close_bracket\E) /xmsgc) {
3145 1118         1766 $parsed .= $1;
3146 1118 50       1834 if (--$nest_bracket <= 0) {
3147 1118         1867 last;
3148             }
3149             }
3150             elsif (/\G (\\ \Q$close_bracket\E) /xmsgc) {
3151 0         0 $parsed .= $1;
3152             }
3153             else {
3154 1148         1806 $parsed .= parse_q__like($close_bracket);
3155             }
3156             }
3157 1118         1980 return $parsed;
3158             }
3159              
3160             #---------------------------------------------------------------------
3161             # parse q/string/ that ends with a character
3162             sub parse_q__like_endswith {
3163 2990     2993 0 6626 my($endswith) = @_;
3164 2990         3894 my $parsed = $endswith;
3165 2990         3413 while (1) {
3166 7811 100       38679 if (/\G (\Q$endswith\E) /xmsgc) {
    50          
3167 2990         5155 $parsed .= $1;
3168 2990         4421 last;
3169             }
3170             elsif (/\G (\\ \Q$endswith\E) /xmsgc) {
3171 0         0 $parsed .= $1;
3172             }
3173             else {
3174 4821         8297 $parsed .= parse_q__like($endswith);
3175             }
3176             }
3177 2990         5267 return $parsed;
3178             }
3179              
3180             #---------------------------------------------------------------------
3181             # parse q/string/ common routine
3182             sub parse_q__like {
3183 5969     5972 0 8211 my($closewith) = @_;
3184 5969 50       24039 if (/\G (\\\\) /xmsgc) {
    50          
3185 0         0 return $1;
3186             }
3187             elsif (/\G (${mb::x}) /xmsgc) {
3188 5969         10619 return escape_q($1, $closewith);
3189             }
3190              
3191             # something wrong happened
3192             else {
3193 0         0 die sprintf(<
3194 0         0 $0(@{[__LINE__]}): something wrong happened in script at pos=%s
3195             ------------------------------------------------------------------------------
3196             %s
3197             ------------------------------------------------------------------------------
3198             END
3199             }
3200             }
3201              
3202             #---------------------------------------------------------------------
3203             # parse qq{string} in balanced blackets
3204             sub parse_qq_like_balanced {
3205 85     88 0 185 my($open_bracket) = @_;
3206 85   50     377 my $close_bracket = {qw| ( ) { } [ ] < > |}->{$open_bracket} || die;
3207 85         206 my $parsed_as_q = $open_bracket;
3208 85         99 my $parsed_as_qq = $open_bracket;
3209 85         104 my $nest_bracket = 1;
3210 85         108 my $nest_escape = 0;
3211 85         109 while (1) {
3212 317 50       2980 if (/\G (\Q$open_bracket\E) /xmsgc) {
    100          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
3213 0         0 $parsed_as_q .= $1;
3214 0         0 $parsed_as_qq .= $1;
3215 0         0 $nest_bracket++;
3216             }
3217             elsif (/\G (\Q$close_bracket\E) /xmsgc) {
3218 85 50       169 if (--$nest_bracket <= 0) {
3219 85         182 $parsed_as_q .= $1;
3220 85         145 $parsed_as_qq .= ('>)]}' x $nest_escape);
3221 85         113 $parsed_as_qq .= $1;
3222 85         141 last;
3223             }
3224             else {
3225 0         0 $parsed_as_q .= $1;
3226 0         0 $parsed_as_qq .= $1;
3227             }
3228             }
3229              
3230             # \L\u --> \u\L
3231             elsif (/\G (\\L \\u) /xmsgc) {
3232 0         0 $parsed_as_q .= $1;
3233 0         0 $parsed_as_qq .= '@{[mb::ucfirst(qq<';
3234 0         0 $parsed_as_qq .= '@{[mb::lc(qq<';
3235 0         0 $nest_escape++;
3236 0         0 $nest_escape++;
3237             }
3238              
3239             # \U\l --> \l\U
3240             elsif (/\G (\\U \\l) /xmsgc) {
3241 0         0 $parsed_as_q .= $1;
3242 0         0 $parsed_as_qq .= '@{[mb::lcfirst(qq<';
3243 0         0 $parsed_as_qq .= '@{[mb::uc(qq<';
3244 0         0 $nest_escape++;
3245 0         0 $nest_escape++;
3246             }
3247              
3248             # \L
3249             elsif (/\G (\\L) /xmsgc) {
3250 0         0 $parsed_as_q .= $1;
3251 0         0 $parsed_as_qq .= '@{[mb::lc(qq<';
3252 0         0 $nest_escape++;
3253             }
3254              
3255             # \U
3256             elsif (/\G (\\U) /xmsgc) {
3257 0         0 $parsed_as_q .= $1;
3258 0         0 $parsed_as_qq .= '@{[mb::uc(qq<';
3259 0         0 $nest_escape++;
3260             }
3261              
3262             # \l
3263             elsif (/\G (\\l) /xmsgc) {
3264 0         0 $parsed_as_q .= $1;
3265 0         0 $parsed_as_qq .= '@{[mb::lcfirst(qq<';
3266 0         0 $nest_escape++;
3267             }
3268              
3269             # \u
3270             elsif (/\G (\\u) /xmsgc) {
3271 0         0 $parsed_as_q .= $1;
3272 0         0 $parsed_as_qq .= '@{[mb::ucfirst(qq<';
3273 0         0 $nest_escape++;
3274             }
3275              
3276             # \Q
3277             elsif (/\G (\\Q) /xmsgc) {
3278 0         0 $parsed_as_q .= $1;
3279 0         0 $parsed_as_qq .= '@{[quotemeta(qq<';
3280 0         0 $nest_escape++;
3281             }
3282              
3283             # \E
3284             elsif (/\G (\\E) /xmsgc) {
3285 0         0 $parsed_as_q .= $1;
3286 0         0 $parsed_as_qq .= ('>)]}' x $nest_escape);
3287 0         0 $nest_escape = 0;
3288             }
3289              
3290             else {
3291 232         383 my($as_qq, $as_q) = parse_qq_like($close_bracket);
3292 232         295 $parsed_as_q .= $as_q;
3293 232         328 $parsed_as_qq .= $as_qq;
3294             }
3295             }
3296              
3297             # return qq-like and q-like quotee
3298 85 100       129 if (wantarray) {
3299 67         190 return ($parsed_as_qq, $parsed_as_q);
3300             }
3301             else {
3302 18         38 return $parsed_as_qq;
3303             }
3304             }
3305              
3306             #---------------------------------------------------------------------
3307             # parse qq/string/ that ends with a character
3308             sub parse_qq_like_endswith {
3309 2479     2482 0 5038 my($endswith) = @_;
3310 2479         3361 my $parsed_as_q = $endswith;
3311 2479         2932 my $parsed_as_qq = $endswith;
3312 2479         3014 my $nest_escape = 0;
3313 2479         2796 while (1) {
3314 10088 100       51496 if (/\G (\Q$endswith\E) /xmsgc) {
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
3315 2479         4282 $parsed_as_q .= $1;
3316 2479         3751 $parsed_as_qq .= ('>)]}' x $nest_escape);
3317 2479 50       6206 $parsed_as_qq .= "\n" if CORE::length($1) >= 2; # here document
3318 2479         3444 $parsed_as_qq .= $1;
3319 2479         3832 last;
3320             }
3321              
3322             # \L\u --> \u\L
3323             elsif (/\G (\\L \\u) /xmsgc) {
3324 0         0 $parsed_as_q .= $1;
3325 0         0 $parsed_as_qq .= '@{[mb::ucfirst(qq<';
3326 0         0 $parsed_as_qq .= '@{[mb::lc(qq<';
3327 0         0 $nest_escape++;
3328 0         0 $nest_escape++;
3329             }
3330              
3331             # \U\l --> \l\U
3332             elsif (/\G (\\U \\l) /xmsgc) {
3333 0         0 $parsed_as_q .= $1;
3334 0         0 $parsed_as_qq .= '@{[mb::lcfirst(qq<';
3335 0         0 $parsed_as_qq .= '@{[mb::uc(qq<';
3336 0         0 $nest_escape++;
3337 0         0 $nest_escape++;
3338             }
3339              
3340             # \L
3341             elsif (/\G (\\L) /xmsgc) {
3342 0         0 $parsed_as_q .= $1;
3343 0         0 $parsed_as_qq .= '@{[mb::lc(qq<';
3344 0         0 $nest_escape++;
3345             }
3346              
3347             # \U
3348             elsif (/\G (\\U) /xmsgc) {
3349 0         0 $parsed_as_q .= $1;
3350 0         0 $parsed_as_qq .= '@{[mb::uc(qq<';
3351 0         0 $nest_escape++;
3352             }
3353              
3354             # \l
3355             elsif (/\G (\\l) /xmsgc) {
3356 0         0 $parsed_as_q .= $1;
3357 0         0 $parsed_as_qq .= '@{[mb::lcfirst(qq<';
3358 0         0 $nest_escape++;
3359             }
3360              
3361             # \u
3362             elsif (/\G (\\u) /xmsgc) {
3363 0         0 $parsed_as_q .= $1;
3364 0         0 $parsed_as_qq .= '@{[mb::ucfirst(qq<';
3365 0         0 $nest_escape++;
3366             }
3367              
3368             # \Q
3369             elsif (/\G (\\Q) /xmsgc) {
3370 0         0 $parsed_as_q .= $1;
3371 0         0 $parsed_as_qq .= '@{[quotemeta(qq<';
3372 0         0 $nest_escape++;
3373             }
3374              
3375             # \E
3376             elsif (/\G (\\E) /xmsgc) {
3377 0         0 $parsed_as_q .= $1;
3378 0         0 $parsed_as_qq .= ('>)]}' x $nest_escape);
3379 0         0 $nest_escape = 0;
3380             }
3381              
3382             else {
3383 7609         11524 my($as_qq, $as_q) = parse_qq_like($endswith);
3384 7609         9530 $parsed_as_q .= $as_q;
3385 7609         9140 $parsed_as_qq .= $as_qq;
3386             }
3387             }
3388              
3389             # return qq-like and q-like quotee
3390 2479 100       3701 if (wantarray) {
3391 1642         4395 return ($parsed_as_qq, $parsed_as_q);
3392             }
3393             else {
3394 837         1635 return $parsed_as_qq;
3395             }
3396             }
3397              
3398             #---------------------------------------------------------------------
3399             # parse qq/string/ common routine
3400             sub parse_qq_like {
3401 7841     7844 0 10182 my($closewith) = @_;
3402 7841         8620 my $parsed_as_q = '';
3403 7841         8072 my $parsed_as_qq = '';
3404              
3405             # \o{...}
3406 7841 50       64263 if (/\G ( \\o\{ (.*?) \} ) /xmsgc) {
    50          
    100          
    100          
    100          
    100          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
3407 0         0 $parsed_as_q .= $1;
3408 0         0 $parsed_as_qq .= escape_to_hex(mb::chr(oct $2), $closewith);
3409             }
3410              
3411             # \x{...}
3412             elsif (/\G ( \\x\{ (.*?) \} ) /xmsgc) {
3413 0         0 $parsed_as_q .= $1;
3414 0         0 $parsed_as_qq .= escape_to_hex(mb::chr(hex $2), $closewith);
3415             }
3416              
3417             # \any
3418             elsif (/\G ( (\\) (${mb::x}) ) /xmsgc) {
3419 188         383 $parsed_as_q .= $1;
3420 188         371 $parsed_as_qq .= ($2 . escape_qq($3, $closewith));
3421             }
3422              
3423             # $` --> @{[mb::_PREMATCH()]}
3424             # ${`} --> @{[mb::_PREMATCH()]}
3425             # $PREMATCH --> @{[mb::_PREMATCH()]}
3426             # ${PREMATCH} --> @{[mb::_PREMATCH()]}
3427             # ${^PREMATCH} --> @{[mb::_PREMATCH()]}
3428             elsif (/\G ( \$` | \$\{`\} | \$PREMATCH | \$\{PREMATCH\} | \$\{\^PREMATCH\} ) /xmsgc) {
3429 2         5 $parsed_as_q .= $1;
3430 2         4 $parsed_as_qq .= '@{[mb::_PREMATCH()]}';
3431             }
3432              
3433             # $& --> @{[mb::_MATCH()]}
3434             # ${&} --> @{[mb::_MATCH()]}
3435             # $MATCH --> @{[mb::_MATCH()]}
3436             # ${MATCH} --> @{[mb::_MATCH()]}
3437             # ${^MATCH} --> @{[mb::_MATCH()]}
3438             elsif (/\G ( \$& | \$\{&\} | \$MATCH | \$\{MATCH\} | \$\{\^MATCH\} ) /xmsgc) {
3439 2         5 $parsed_as_q .= $1;
3440 2         4 $parsed_as_qq .= '@{[mb::_MATCH()]}';
3441             }
3442              
3443             # $1 --> @{[mb::_CAPTURE(1)]}
3444             # $2 --> @{[mb::_CAPTURE(2)]}
3445             # $3 --> @{[mb::_CAPTURE(3)]}
3446             elsif (/\G ( \$ ([1-9][0-9]*) ) /xmsgc) {
3447 23         44 $parsed_as_q .= $1;
3448 23         46 $parsed_as_qq .= "\@{[mb::_CAPTURE($2)]}";
3449             }
3450              
3451             # @{^CAPTURE} --> @{[join $", mb::_CAPTURE()]}
3452             elsif (/\G ( \@\{\^CAPTURE\} ) /xmsgc) {
3453 0         0 $parsed_as_q .= $1;
3454 0         0 $parsed_as_qq .= '@{[join $", mb::_CAPTURE()]}';
3455             }
3456              
3457             # ${^CAPTURE}[0] --> @{[mb::_CAPTURE(1)]}
3458             # ${^CAPTURE}[1] --> @{[mb::_CAPTURE(2)]}
3459             # ${^CAPTURE}[2] --> @{[mb::_CAPTURE(3)]}
3460             elsif (/\G (\$\{\^CAPTURE\}) \s* (\[) /xmsgc) {
3461 0         0 my $indexing = parse_expr_balanced($2);
3462 0         0 $parsed_as_q .= ($1 . $indexing);
3463 0         0 my $n_th = quotee_of($indexing);
3464 0         0 $parsed_as_qq .= "\@{[mb::_CAPTURE($n_th)]}";
3465             }
3466              
3467             # @- --> @{[mb::_LAST_MATCH_START()]}
3468             # @LAST_MATCH_START --> @{[mb::_LAST_MATCH_START()]}
3469             # @{LAST_MATCH_START} --> @{[mb::_LAST_MATCH_START()]}
3470             # @{^LAST_MATCH_START} --> @{[mb::_LAST_MATCH_START()]}
3471             elsif (/\G (?: \@- | \@LAST_MATCH_START | \@\{LAST_MATCH_START\} | \@\{\^LAST_MATCH_START\} ) /xmsgc) {
3472 0         0 $parsed_as_q .= $&;
3473 0         0 $parsed_as_qq .= '@{[mb::_LAST_MATCH_START()]}';
3474             }
3475              
3476             # $-[1] --> @{[mb::_LAST_MATCH_START(1)]}
3477             # $LAST_MATCH_START[1] --> @{[mb::_LAST_MATCH_START(1)]}
3478             # ${LAST_MATCH_START}[1] --> @{[mb::_LAST_MATCH_START(1)]}
3479             # ${^LAST_MATCH_START}[1] --> @{[mb::_LAST_MATCH_START(1)]}
3480             elsif (/\G ( \$- | \$LAST_MATCH_START | \$\{LAST_MATCH_START\} | \$\{\^LAST_MATCH_START\} ) \s* (\[) /xmsgc) {
3481 0         0 my $indexing = parse_expr_balanced($2);
3482 0         0 $parsed_as_q .= ($1 . $indexing);
3483 0         0 my $n_th = quotee_of($indexing);
3484 0         0 $parsed_as_qq .= "\@{[mb::_LAST_MATCH_START($n_th)]}";
3485             }
3486              
3487             # @+ --> @{[mb::_LAST_MATCH_END()]}
3488             # @LAST_MATCH_END --> @{[mb::_LAST_MATCH_END()]}
3489             # @{LAST_MATCH_END} --> @{[mb::_LAST_MATCH_END()]}
3490             # @{^LAST_MATCH_END} --> @{[mb::_LAST_MATCH_END()]}
3491             elsif (/\G ( \@\+ | \@LAST_MATCH_END | \@\{LAST_MATCH_END\} | \@\{\^LAST_MATCH_END\} ) /xmsgc) {
3492 0         0 $parsed_as_q .= $1;
3493 0         0 $parsed_as_qq .= '@{[mb::_LAST_MATCH_END()]}';
3494             }
3495              
3496             # $+[1] --> @{[mb::_LAST_MATCH_END(1)]}
3497             # $LAST_MATCH_END[1] --> @{[mb::_LAST_MATCH_END(1)]}
3498             # ${LAST_MATCH_END}[1] --> @{[mb::_LAST_MATCH_END(1)]}
3499             # ${^LAST_MATCH_END}[1] --> @{[mb::_LAST_MATCH_END(1)]}
3500             elsif (/\G ( \$\+ | \$LAST_MATCH_END | \$\{LAST_MATCH_END\} | \$\{\^LAST_MATCH_END\} ) \s* (\[) /xmsgc) {
3501 0         0 my $indexing = parse_expr_balanced($2);
3502 0         0 $parsed_as_q .= ($1 . $indexing);
3503 0         0 my $n_th = quotee_of($indexing);
3504 0         0 $parsed_as_qq .= "\@{[mb::_LAST_MATCH_END($n_th)]}";
3505             }
3506              
3507             # any
3508             elsif (/\G (${mb::x}) /xmsgc) {
3509 7626         12894 $parsed_as_q .= escape_q ($1, $closewith);
3510 7626         11730 $parsed_as_qq .= escape_qq($1, $closewith);
3511             }
3512              
3513             # something wrong happened
3514             else {
3515 0         0 die sprintf(<
3516 0         0 $0(@{[__LINE__]}): something wrong happened in script at pos=%s
3517             ------------------------------------------------------------------------------
3518             %s
3519             ------------------------------------------------------------------------------
3520             END
3521             }
3522              
3523             # return qq-like and q-like quotee
3524 7841 50       11717 if (wantarray) {
3525 7841         16533 return ($parsed_as_qq, $parsed_as_q);
3526             }
3527             else {
3528 0         0 return $parsed_as_qq;
3529             }
3530             }
3531              
3532             #---------------------------------------------------------------------
3533             # parse code point class
3534             sub parse_re_codepoint_class {
3535 912     915 0 1467 my($classmate) = @_;
3536 912         1249 my $parsed = '';
3537 912         1251 my @sbcs = ();
3538 912         1122 my @xbcs = (); # "xbcs" means DBCS, TBCS, QBCS, ...
3539 912         1146 while (1) {
3540 2042 100       17680 if ($classmate =~ /\G \z /xmsgc) {
    50          
    50          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    50          
    50          
    100          
    100          
    100          
    50          
3541 912 50 100     5557 $parsed =
    100 66        
    100 33        
3542             ( @sbcs and @xbcs) ? join('|', @xbcs, '['.join('',@sbcs).']') :
3543             (!@sbcs and @xbcs) ? join('|', @xbcs ) :
3544             ( @sbcs and !@xbcs) ? '['.join('',@sbcs).']' :
3545             die;
3546 912         1592 last;
3547             }
3548             elsif ($classmate =~ /\G (\\ \]) /xmsgc) {
3549 0         0 push @sbcs, $1;
3550             }
3551             elsif ($classmate =~ /\G (\\\\) /xmsgc) {
3552 0         0 push @sbcs, $1;
3553             }
3554              
3555             # classic perl codepoint class shortcuts
3556 34         120 elsif ($classmate =~ /\G \\D /xmsgc) { push @xbcs, "(?:(?![$mb::bare_d])${mb::x})"; }
3557 10         40 elsif ($classmate =~ /\G \\H /xmsgc) { push @xbcs, "(?:(?![$mb::bare_h])${mb::x})"; }
3558             # elsif ($classmate =~ /\G \\N /xmsgc) { push @xbcs, "(?:(?!\\n)${mb::x})"; } # \N in a codepoint class must be a named character: \N{...} in regex
3559             # elsif ($classmate =~ /\G \\R /xmsgc) { push @xbcs, "(?>\\r\\n|[$mb::bare_v])"; } # Unrecognized escape \R in codepoint class passed through in regex
3560 19         71 elsif ($classmate =~ /\G \\S /xmsgc) { push @xbcs, "(?:(?![$mb::bare_s])${mb::x})"; }
3561 16         61 elsif ($classmate =~ /\G \\V /xmsgc) { push @xbcs, "(?:(?![$mb::bare_v])${mb::x})"; }
3562 193         651 elsif ($classmate =~ /\G \\W /xmsgc) { push @xbcs, "(?:(?![$mb::bare_w])${mb::x})"; }
3563 6         17 elsif ($classmate =~ /\G \\b /xmsgc) { push @sbcs, $mb::bare_backspace; }
3564 34         86 elsif ($classmate =~ /\G \\d /xmsgc) { push @sbcs, $mb::bare_d; }
3565 10         26 elsif ($classmate =~ /\G \\h /xmsgc) { push @sbcs, $mb::bare_h; }
3566 19         50 elsif ($classmate =~ /\G \\s /xmsgc) { push @sbcs, $mb::bare_s; }
3567 16         39 elsif ($classmate =~ /\G \\v /xmsgc) { push @sbcs, $mb::bare_v; }
3568 193         441 elsif ($classmate =~ /\G \\w /xmsgc) { push @sbcs, $mb::bare_w; }
3569              
3570             # [:POSIX:]
3571 18         34 elsif ($classmate =~ /\G \[:alnum:\] /xmsgc) { push @sbcs, '\x30-\x39\x41-\x5A\x61-\x7A'; }
3572 2         6 elsif ($classmate =~ /\G \[:alpha:\] /xmsgc) { push @sbcs, '\x41-\x5A\x61-\x7A'; }
3573 2         5 elsif ($classmate =~ /\G \[:ascii:\] /xmsgc) { push @sbcs, '\x00-\x7F'; }
3574 2         7 elsif ($classmate =~ /\G \[:blank:\] /xmsgc) { push @sbcs, '\x09\x20'; }
3575 2         7 elsif ($classmate =~ /\G \[:cntrl:\] /xmsgc) { push @sbcs, '\x00-\x1F\x7F'; }
3576 2         5 elsif ($classmate =~ /\G \[:digit:\] /xmsgc) { push @sbcs, '\x30-\x39'; }
3577 2         5 elsif ($classmate =~ /\G \[:graph:\] /xmsgc) { push @sbcs, '\x21-\x7F'; }
3578 2         105 elsif ($classmate =~ /\G \[:lower:\] /xmsgc) { push @sbcs, 'abcdefghijklmnopqrstuvwxyz'; } # /i modifier requires 'a' to 'z' literally
3579 2         5 elsif ($classmate =~ /\G \[:print:\] /xmsgc) { push @sbcs, '\x20-\x7F'; }
3580 2         6 elsif ($classmate =~ /\G \[:punct:\] /xmsgc) { push @sbcs, '\x21-\x2F\x3A-\x3F\x40\x5B-\x5F\x60\x7B-\x7E'; }
3581 2         7 elsif ($classmate =~ /\G \[:space:\] /xmsgc) { push @sbcs, '\s\x0B'; } # "\s" and vertical tab ("\cK")
3582 2         6 elsif ($classmate =~ /\G \[:upper:\] /xmsgc) { push @sbcs, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; } # /i modifier requires 'A' to 'Z' literally
3583 2         6 elsif ($classmate =~ /\G \[:word:\] /xmsgc) { push @sbcs, '\x30-\x39\x41-\x5A\x5F\x61-\x7A'; }
3584 2         6 elsif ($classmate =~ /\G \[:xdigit:\] /xmsgc) { push @sbcs, '\x30-\x39\x41-\x46\x61-\x66'; }
3585              
3586             # [:^POSIX:]
3587 2         7 elsif ($classmate =~ /\G \[:\^alnum:\] /xmsgc) { push @xbcs, "(?:(?![\\x30-\\x39\\x41-\\x5A\\x61-\\x7A])${mb::x})"; }
3588 2         8 elsif ($classmate =~ /\G \[:\^alpha:\] /xmsgc) { push @xbcs, "(?:(?![\\x41-\\x5A\\x61-\\x7A])${mb::x})"; }
3589 2         10 elsif ($classmate =~ /\G \[:\^ascii:\] /xmsgc) { push @xbcs, "(?:(?![\\x00-\\x7F])${mb::x})"; }
3590 2         9 elsif ($classmate =~ /\G \[:\^blank:\] /xmsgc) { push @xbcs, "(?:(?![\\x09\\x20])${mb::x})"; }
3591 2         9 elsif ($classmate =~ /\G \[:\^cntrl:\] /xmsgc) { push @xbcs, "(?:(?![\\x00-\\x1F\\x7F])${mb::x})"; }
3592 2         9 elsif ($classmate =~ /\G \[:\^digit:\] /xmsgc) { push @xbcs, "(?:(?![\\x30-\\x39])${mb::x})"; }
3593 2         11 elsif ($classmate =~ /\G \[:\^graph:\] /xmsgc) { push @xbcs, "(?:(?![\\x21-\\x7F])${mb::x})"; }
3594 2         7 elsif ($classmate =~ /\G \[:\^lower:\] /xmsgc) { push @xbcs, "(?:(?![abcdefghijklmnopqrstuvwxyz])${mb::x})"; } # /i modifier requires 'a' to 'z' literally
3595 2         12 elsif ($classmate =~ /\G \[:\^print:\] /xmsgc) { push @xbcs, "(?:(?![\\x20-\\x7F])${mb::x})"; }
3596 2         9 elsif ($classmate =~ /\G \[:\^punct:\] /xmsgc) { push @xbcs, "(?:(?![\\x21-\\x2F\\x3A-\\x3F\\x40\\x5B-\\x5F\\x60\\x7B-\\x7E])${mb::x})"; }
3597 2         9 elsif ($classmate =~ /\G \[:\^space:\] /xmsgc) { push @xbcs, "(?:(?![\\s\\x0B])${mb::x})"; } # "\s" and vertical tab ("\cK")
3598 2         9 elsif ($classmate =~ /\G \[:\^upper:\] /xmsgc) { push @xbcs, "(?:(?![ABCDEFGHIJKLMNOPQRSTUVWXYZ])${mb::x})"; } # /i modifier requires 'A' to 'Z' literally
3599 2         10 elsif ($classmate =~ /\G \[:\^word:\] /xmsgc) { push @xbcs, "(?:(?![\\x30-\\x39\\x41-\\x5A\\x5F\\x61-\\x7A])${mb::x})"; }
3600 2         10 elsif ($classmate =~ /\G \[:\^xdigit:\] /xmsgc) { push @xbcs, "(?:(?![\\x30-\\x39\\x41-\\x46\\x61-\\x66])${mb::x})"; }
3601              
3602             # \o{...}
3603             elsif ($classmate =~ /\G \\o\{ (.*?) \} /xmsgc) {
3604 0         0 push @xbcs, '(?:' . escape_to_hex(mb::chr(oct $1), ']') . ')';
3605             }
3606              
3607             # \x{...}
3608             elsif ($classmate =~ /\G \\x\{ (.*?) \} /xmsgc) {
3609 0         0 push @xbcs, '(?:' . escape_to_hex(mb::chr(hex $1), ']') . ')';
3610             }
3611              
3612             # \any
3613             elsif ($classmate =~ /\G (\\) (${mb::x}) /xmsgc) {
3614 12 50       39 if (CORE::length($2) == 1) {
3615 12         38 push @sbcs, ($1 . $2);
3616             }
3617             else {
3618 0         0 push @xbcs, '(?:' . $1 . escape_to_hex($2, ']') . ')';
3619             }
3620             }
3621              
3622             # supported character ranges
3623             elsif ($classmate =~ /\G ((?:[\x20-\x7E]|\\[0-3][0-7][0-7]|\\x[0-9A-Fa-f][0-9A-Fa-f])-(?:[\x20-\x7E]|\\[0-3][0-7][0-7]|\\x[0-9A-Fa-f][0-9A-Fa-f])) /xmsgc) {
3624 24         56 push @sbcs, $1;
3625             }
3626              
3627             # other character ranges are no longer supported
3628             # range specification by '-' in codepoint class of regular expression supports US-ASCII only
3629             # this limitation makes it easier to change the script encoding
3630             elsif ($classmate =~ /\G (-) /xmsgc) {
3631 1 50       6 if ($^W) {
3632 0         0 cluck <
3633             [$parsed...] in regular expression
3634              
3635             range specification by '-' in codepoint class of regular expression supports US-ASCII only.
3636             this limitation makes it easier to change the script encoding.
3637             END
3638             }
3639 1         3 push @sbcs, '\\x2D';
3640             }
3641              
3642             # any
3643             elsif ($classmate =~ /\G (${mb::x}) /xmsgc) {
3644 471 100       1011 if (CORE::length($1) == 1) {
3645 127         292 push @sbcs, $1;
3646             }
3647             else {
3648 344         663 push @xbcs, '(?:' . escape_to_hex($1, ']') . ')';
3649             }
3650             }
3651              
3652             # something wrong happened
3653             else {
3654 0         0 die sprintf(<
3655 0         0 $0(@{[__LINE__]}): something wrong happened in script at pos=%s
3656             ------------------------------------------------------------------------------
3657             %s
3658             ------------------------------------------------------------------------------
3659             END
3660             }
3661             }
3662 912         22957 return $parsed;
3663             }
3664              
3665             #---------------------------------------------------------------------
3666             # parse qr'regexp' as q-like
3667             sub parse_re_as_q_endswith {
3668 936     939 0 2571 my($operator, $endswith) = @_;
3669 936         1452 my $parsed = $endswith;
3670 936         1115 while (1) {
3671 1932 100       10465 if (/\G (\Q$endswith\E) /xmsgc) {
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    50          
    50          
    50          
    50          
    50          
    50          
3672 936         1535 $parsed .= $1;
3673 936         1356 last;
3674             }
3675              
3676             # get codepoint class
3677             elsif (/\G \[ /xmsgc) {
3678 562         880 my $classmate = '';
3679 562         607 while (1) {
3680 1758 100       6434 if (/\G \] /xmsgc) {
    100          
    100          
    50          
3681 562         785 last;
3682             }
3683             elsif (/\G (\[:\^[a-z]*:\]) /xmsgc) {
3684 28         65 $classmate .= $1;
3685             }
3686             elsif (/\G (\[:[a-z]*:\]) /xmsgc) {
3687 44         95 $classmate .= $1;
3688             }
3689             elsif (/\G (${mb::x}) /xmsgc) {
3690 1124         1995 $classmate .= $1;
3691             }
3692              
3693             # something wrong happened
3694             else {
3695 0         0 die sprintf(<
3696 0         0 $0(@{[__LINE__]}): something wrong happened in script at pos=%s
3697             ------------------------------------------------------------------------------
3698             %s
3699             ------------------------------------------------------------------------------
3700             END
3701             }
3702             }
3703              
3704             # parse codepoint class
3705 562 100       1159 if ($classmate =~ s{\A \^ }{}xms) {
3706 168         225 $parsed .= '(?:(?!';
3707 168         282 $parsed .= parse_re_codepoint_class($classmate);
3708 168         425 $parsed .= ")${mb::x})";
3709             }
3710             else {
3711 394         488 $parsed .= '(?:(?=';
3712 394         692 $parsed .= parse_re_codepoint_class($classmate);
3713 394         1037 $parsed .= ")${mb::x})";
3714             }
3715             }
3716              
3717             # /./ or \any
3718 2         9 elsif (/\G \. /xmsgc) { $parsed .= "(?:${mb::over_ascii}|.)"; } # after ${mb::over_ascii}, /s modifier wants "." (not [\x00-\xFF])
3719 2         16 elsif (/\G \\B /xmsgc) { $parsed .= "(?:(?
3720 12         43 elsif (/\G \\D /xmsgc) { $parsed .= "(?:(?![$mb::bare_d])${mb::x})"; }
3721 4         53 elsif (/\G \\H /xmsgc) { $parsed .= "(?:(?![$mb::bare_h])${mb::x})"; }
3722 2         7 elsif (/\G \\N /xmsgc) { $parsed .= "(?:(?!\\n)${mb::x})"; }
3723 2         10 elsif (/\G \\R /xmsgc) { $parsed .= "(?>\\r\\n|[$mb::bare_v])"; }
3724 7         29 elsif (/\G \\S /xmsgc) { $parsed .= "(?:(?![$mb::bare_s])${mb::x})"; }
3725 6         23 elsif (/\G \\V /xmsgc) { $parsed .= "(?:(?![$mb::bare_v])${mb::x})"; }
3726 65         240 elsif (/\G \\W /xmsgc) { $parsed .= "(?:(?![$mb::bare_w])${mb::x})"; }
3727 2         13 elsif (/\G \\b /xmsgc) { $parsed .= "(?:(?
3728 12         34 elsif (/\G \\d /xmsgc) { $parsed .= "[$mb::bare_d]"; }
3729 4         13 elsif (/\G \\h /xmsgc) { $parsed .= "[$mb::bare_h]"; }
3730 7         20 elsif (/\G \\s /xmsgc) { $parsed .= "[$mb::bare_s]"; }
3731 6         18 elsif (/\G \\v /xmsgc) { $parsed .= "[$mb::bare_v]"; }
3732 65         166 elsif (/\G \\w /xmsgc) { $parsed .= "[$mb::bare_w]"; }
3733              
3734             # \o{...}
3735             elsif (/\G \\o\{ (.*?) \} /xmsgc) {
3736 0         0 $parsed .= '(?:';
3737 0         0 $parsed .= escape_to_hex(mb::chr(oct $1), $endswith);
3738 0         0 $parsed .= ')';
3739             }
3740              
3741             # \x{...}
3742             elsif (/\G \\x\{ (.*?) \} /xmsgc) {
3743 0         0 $parsed .= '(?:';
3744 0         0 $parsed .= escape_to_hex(mb::chr(hex $1), $endswith);
3745 0         0 $parsed .= ')';
3746             }
3747              
3748             # \0... octal escape
3749             elsif (/\G (\\ 0[1-7]*) /xmsgc) {
3750 0         0 $parsed .= $1;
3751             }
3752              
3753             # \100...\x377 octal escape
3754             elsif (/\G (\\ [1-3][0-7][0-7]) /xmsgc) {
3755 0         0 $parsed .= $1;
3756             }
3757              
3758             # \1...\99, ... n-th previously captured string (decimal)
3759             elsif (/\G (\\) ([1-9][0-9]*) /xmsgc) {
3760 0         0 $parsed .= $1;
3761 0 0       0 if ($operator eq 's') {
3762 0         0 $parsed .= ($2 + 1);
3763             }
3764             else {
3765 0         0 $parsed .= $2;
3766             }
3767             }
3768              
3769             # any
3770             elsif (/\G (${mb::x}) /xmsgc) {
3771 236 100       538 if (CORE::length($1) == 1) {
3772 91         183 $parsed .= $1;
3773             }
3774             else {
3775 145         171 $parsed .= '(?:';
3776 145         273 $parsed .= escape_to_hex($1, $endswith);
3777 145         281 $parsed .= ')';
3778             }
3779             }
3780              
3781             # something wrong happened
3782             else {
3783 0         0 die sprintf(<
3784 0         0 $0(@{[__LINE__]}): something wrong happened in script at pos=%s
3785             ------------------------------------------------------------------------------
3786             %s
3787             ------------------------------------------------------------------------------
3788             END
3789             }
3790             }
3791 936         1728 return $parsed;
3792             }
3793              
3794             #---------------------------------------------------------------------
3795             # parse qr{regexp} in balanced blackets
3796             sub parse_re_balanced {
3797 564     567 0 1674 my($operator, $open_bracket) = @_;
3798 564   50     3120 my $close_bracket = {qw| ( ) { } [ ] < > |}->{$open_bracket} || die;
3799 564         1343 my $parsed = $open_bracket;
3800 564         727 my $nest_bracket = 1;
3801 564         673 my $nest_escape = 0;
3802 564         644 while (1) {
3803 1133 50       7977 if (/\G (\Q$open_bracket\E) /xmsgc) {
    100          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
3804 0         0 $parsed .= $1;
3805 0         0 $nest_bracket++;
3806             }
3807             elsif (/\G (\Q$close_bracket\E) /xmsgc) {
3808 564 50       1059 if (--$nest_bracket <= 0) {
3809 564         909 $parsed .= ('>)]}' x $nest_escape);
3810 564         817 $parsed .= $1;
3811 564         996 last;
3812             }
3813             else {
3814 0         0 $parsed .= $1;
3815             }
3816             }
3817              
3818             # \L\u --> \u\L
3819             elsif (/\G \\L \\u /xmsgc) {
3820 0         0 $parsed .= '@{[mb::ucfirst(qq<';
3821 0         0 $parsed .= '@{[mb::lc(qq<';
3822 0         0 $nest_escape++;
3823 0         0 $nest_escape++;
3824             }
3825              
3826             # \U\l --> \l\U
3827             elsif (/\G \\U \\l /xmsgc) {
3828 0         0 $parsed .= '@{[mb::lcfirst(qq<';
3829 0         0 $parsed .= '@{[mb::uc(qq<';
3830 0         0 $nest_escape++;
3831 0         0 $nest_escape++;
3832             }
3833              
3834             # \L
3835             elsif (/\G \\L /xmsgc) {
3836 0         0 $parsed .= '@{[mb::lc(qq<';
3837 0         0 $nest_escape++;
3838             }
3839              
3840             # \U
3841             elsif (/\G \\U /xmsgc) {
3842 0         0 $parsed .= '@{[mb::uc(qq<';
3843 0         0 $nest_escape++;
3844             }
3845              
3846             # \l
3847             elsif (/\G \\l /xmsgc) {
3848 0         0 $parsed .= '@{[mb::lcfirst(qq<';
3849 0         0 $nest_escape++;
3850             }
3851              
3852             # \u
3853             elsif (/\G \\u /xmsgc) {
3854 0         0 $parsed .= '@{[mb::ucfirst(qq<';
3855 0         0 $nest_escape++;
3856             }
3857              
3858             # \Q
3859             elsif (/\G \\Q /xmsgc) {
3860 0         0 $parsed .= '@{[quotemeta(qq<';
3861 0         0 $nest_escape++;
3862             }
3863              
3864             # \E
3865             elsif (/\G \\E /xmsgc) {
3866 0         0 $parsed .= ('>)]}' x $nest_escape);
3867 0         0 $nest_escape = 0;
3868             }
3869              
3870             else {
3871 569         1251 $parsed .= parse_re($operator, $open_bracket);
3872             }
3873             }
3874 564         1087 return $parsed;
3875             }
3876              
3877             #---------------------------------------------------------------------
3878             # parse qr/regexp/ that ends with a character
3879             sub parse_re_endswith {
3880 3142     3145 0 8986 my($operator, $endswith) = @_;
3881 3142         5383 my $parsed = $endswith;
3882 3142         3886 my $nest_escape = 0;
3883 3142         3763 while (1) {
3884 7436 100       41254 if (/\G (\Q$endswith\E) /xmsgc) {
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
3885 3142         6015 $parsed .= ('>)]}' x $nest_escape);
3886 3142         5173 $parsed .= $1;
3887 3142         4951 last;
3888             }
3889              
3890             # \L\u --> \u\L
3891             elsif (/\G \\L \\u /xmsgc) {
3892 0         0 $parsed .= '@{[mb::ucfirst(qq<';
3893 0         0 $parsed .= '@{[mb::lc(qq<';
3894 0         0 $nest_escape++;
3895 0         0 $nest_escape++;
3896             }
3897              
3898             # \U\l --> \l\U
3899             elsif (/\G \\U \\l /xmsgc) {
3900 0         0 $parsed .= '@{[mb::lcfirst(qq<';
3901 0         0 $parsed .= '@{[mb::uc(qq<';
3902 0         0 $nest_escape++;
3903 0         0 $nest_escape++;
3904             }
3905              
3906             # \L
3907             elsif (/\G \\L /xmsgc) {
3908 0         0 $parsed .= '@{[mb::lc(qq<';
3909 0         0 $nest_escape++;
3910             }
3911              
3912             # \U
3913             elsif (/\G \\U /xmsgc) {
3914 0         0 $parsed .= '@{[mb::uc(qq<';
3915 0         0 $nest_escape++;
3916             }
3917              
3918             # \l
3919             elsif (/\G \\l /xmsgc) {
3920 0         0 $parsed .= '@{[mb::lcfirst(qq<';
3921 0         0 $nest_escape++;
3922             }
3923              
3924             # \u
3925             elsif (/\G \\u /xmsgc) {
3926 0         0 $parsed .= '@{[mb::ucfirst(qq<';
3927 0         0 $nest_escape++;
3928             }
3929              
3930             # \Q
3931             elsif (/\G \\Q /xmsgc) {
3932 0         0 $parsed .= '@{[quotemeta(qq<';
3933 0         0 $nest_escape++;
3934             }
3935              
3936             # \E
3937             elsif (/\G \\E /xmsgc) {
3938 0         0 $parsed .= ('>)]}' x $nest_escape);
3939 0         0 $nest_escape = 0;
3940             }
3941              
3942             else {
3943 4294         8451 $parsed .= parse_re($operator, $endswith);
3944             }
3945             }
3946 3142         6440 return $parsed;
3947             }
3948              
3949             #---------------------------------------------------------------------
3950             # parse qr/regexp/ common routine
3951             sub parse_re {
3952 4863     4866 0 7483 my($operator, $closewith) = @_;
3953 4863         6125 my $parsed = '';
3954              
3955             # codepoint class
3956 4863 100       56256 if (/\G \[ /xmsgc) {
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    50          
    50          
    50          
    50          
    100          
    100          
    50          
    50          
    100          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
3957 1484         2190 my $classmate = '';
3958 1484         1902 while (1) {
3959 4398 100       18086 if (/\G \] /xmsgc) {
    100          
    100          
    100          
    50          
3960 1484         2067 last;
3961             }
3962             elsif (/\G (\\) /xmsgc) {
3963 510         963 $classmate .= "\\$1";
3964             }
3965             elsif (/\G (\[:\^[a-z]*:\]) /xmsgc) {
3966 84         152 $classmate .= $1;
3967             }
3968             elsif (/\G (\[:[a-z]*:\]) /xmsgc) {
3969 100         196 $classmate .= $1;
3970             }
3971             elsif (/\G (${mb::x}) /xmsgc) {
3972 2220         4475 $classmate .= escape_qq($1, ']');
3973             }
3974              
3975             # something wrong happened
3976             else {
3977 0         0 die sprintf(<
3978 0         0 $0(@{[__LINE__]}): something wrong happened in script at pos=%s
3979             ------------------------------------------------------------------------------
3980             %s
3981             ------------------------------------------------------------------------------
3982             END
3983             }
3984             }
3985 1484         3174 $parsed .= "\@{[mb::_cc(qq[$classmate])]}";
3986             }
3987              
3988             # /./ or \any
3989 20         44 elsif (/\G \. /xmsgc) { $parsed .= '(?:@{[@mb::_dot]})'; }
3990 7         18 elsif (/\G \\B /xmsgc) { $parsed .= '(?:@{[@mb::_B]})'; }
3991 18         38 elsif (/\G \\D /xmsgc) { $parsed .= '(?:@{[@mb::_D]})'; }
3992 10         24 elsif (/\G \\H /xmsgc) { $parsed .= '(?:@{[@mb::_H]})'; }
3993 8         20 elsif (/\G \\N /xmsgc) { $parsed .= '(?:@{[@mb::_N]})'; }
3994 12         33 elsif (/\G \\R /xmsgc) { $parsed .= '(?:@{[@mb::_R]})'; }
3995 14         33 elsif (/\G \\S /xmsgc) { $parsed .= '(?:@{[@mb::_S]})'; }
3996 12         29 elsif (/\G \\V /xmsgc) { $parsed .= '(?:@{[@mb::_V]})'; }
3997 71         134 elsif (/\G \\W /xmsgc) { $parsed .= '(?:@{[@mb::_W]})'; }
3998 7         50 elsif (/\G \\b /xmsgc) { $parsed .= '(?:@{[@mb::_b]})'; }
3999 17         40 elsif (/\G \\d /xmsgc) { $parsed .= '(?:@{[@mb::_d]})'; }
4000 10         24 elsif (/\G \\h /xmsgc) { $parsed .= '(?:@{[@mb::_h]})'; }
4001 18         39 elsif (/\G \\s /xmsgc) { $parsed .= '(?:@{[@mb::_s]})'; }
4002 14         29 elsif (/\G \\v /xmsgc) { $parsed .= '(?:@{[@mb::_v]})'; }
4003 70         135 elsif (/\G \\w /xmsgc) { $parsed .= '(?:@{[@mb::_w]})'; }
4004              
4005             # \o{...}
4006             elsif (/\G \\o\{ (.*?) \} /xmsgc) {
4007 0         0 $parsed .= '(?:';
4008 0         0 $parsed .= escape_to_hex(mb::chr(oct $1), $closewith);
4009 0         0 $parsed .= ')';
4010             }
4011              
4012             # \x{...}
4013             elsif (/\G \\x\{ (.*?) \} /xmsgc) {
4014 0         0 $parsed .= '(?:';
4015 0         0 $parsed .= escape_to_hex(mb::chr(hex $1), $closewith);
4016 0         0 $parsed .= ')';
4017             }
4018              
4019             # \0... octal escape
4020             elsif (/\G (\\ 0[1-7]*) /xmsgc) {
4021 0         0 $parsed .= $1;
4022             }
4023              
4024             # \100...\x377 octal escape
4025             elsif (/\G (\\ [1-3][0-7][0-7]) /xmsgc) {
4026 0         0 $parsed .= $1;
4027             }
4028              
4029             # \1...\99, ... n-th previously captured string (decimal)
4030             elsif (/\G (\\) ([1-9][0-9]*) /xmsgc) {
4031 24         43 $parsed .= $1;
4032 24 50       50 if ($operator eq 's') {
4033 0         0 $parsed .= ($2 + 1);
4034             }
4035             else {
4036 24         35 $parsed .= $2;
4037             }
4038             }
4039              
4040             # \any
4041             elsif (/\G (\\) (${mb::x}) /xmsgc) {
4042 5 50       14 if (CORE::length($2) == 1) {
4043 5         37 $parsed .= ($1 . $2);
4044             }
4045             else {
4046 0         0 $parsed .= ('(?:' . $1 . escape_qq($2, $closewith) . ')');
4047             }
4048             }
4049              
4050             # $` --> @{[mb::_clustered_codepoint(mb::_PREMATCH())]}
4051             # ${`} --> @{[mb::_clustered_codepoint(mb::_PREMATCH())]}
4052             # $PREMATCH --> @{[mb::_clustered_codepoint(mb::_PREMATCH())]}
4053             # ${PREMATCH} --> @{[mb::_clustered_codepoint(mb::_PREMATCH())]}
4054             # ${^PREMATCH} --> @{[mb::_clustered_codepoint(mb::_PREMATCH())]}
4055             elsif (/\G (?: \$` | \$\{`\} | \$PREMATCH | \$\{PREMATCH\} | \$\{\^PREMATCH\} ) /xmsgc) {
4056 0         0 $parsed .= '@{[mb::_clustered_codepoint(mb::_PREMATCH())]}';
4057             }
4058              
4059             # $& --> @{[mb::_clustered_codepoint(mb::_MATCH())]}
4060             # ${&} --> @{[mb::_clustered_codepoint(mb::_MATCH())]}
4061             # $MATCH --> @{[mb::_clustered_codepoint(mb::_MATCH())]}
4062             # ${MATCH} --> @{[mb::_clustered_codepoint(mb::_MATCH())]}
4063             # ${^MATCH} --> @{[mb::_clustered_codepoint(mb::_MATCH())]}
4064             elsif (/\G (?: \$& | \$\{&\} | \$MATCH | \$\{MATCH\} | \$\{\^MATCH\} ) /xmsgc) {
4065 0         0 $parsed .= '@{[mb::_clustered_codepoint(mb::_MATCH())]}';
4066             }
4067              
4068             # $1 --> @{[mb::_clustered_codepoint(mb::_CAPTURE(1))]}
4069             # $2 --> @{[mb::_clustered_codepoint(mb::_CAPTURE(2))]}
4070             # $3 --> @{[mb::_clustered_codepoint(mb::_CAPTURE(3))]}
4071             elsif (/\G \$ ([1-9][0-9]*) /xmsgc) {
4072 24         75 $parsed .= "\@{[mb::_clustered_codepoint(mb::_CAPTURE($1))]}";
4073             }
4074              
4075             # @{^CAPTURE} --> @{[mb::_clustered_codepoint(join $", mb::_CAPTURE())]}
4076             elsif (/\G \@\{\^CAPTURE\} /xmsgc) {
4077 0         0 $parsed .= '@{[mb::_clustered_codepoint(join $", mb::_CAPTURE())]}';
4078             }
4079              
4080             # ${^CAPTURE}[0] --> @{[mb::_clustered_codepoint(mb::_CAPTURE(1))]}
4081             # ${^CAPTURE}[1] --> @{[mb::_clustered_codepoint(mb::_CAPTURE(2))]}
4082             # ${^CAPTURE}[2] --> @{[mb::_clustered_codepoint(mb::_CAPTURE(3))]}
4083             elsif (/\G \$\{\^CAPTURE\} \s* (\[) /xmsgc) {
4084 0         0 my $n_th = quotee_of(parse_expr_balanced($1));
4085 0         0 $parsed .= "\@{[mb::_clustered_codepoint(mb::_CAPTURE($n_th+1))]}";
4086             }
4087              
4088             # @- --> @{[join $", mb::_LAST_MATCH_START()]}
4089             # @LAST_MATCH_START --> @{[join $", mb::_LAST_MATCH_START()]}
4090             # @{LAST_MATCH_START} --> @{[join $", mb::_LAST_MATCH_START()]}
4091             # @{^LAST_MATCH_START} --> @{[join $", mb::_LAST_MATCH_START()]}
4092             elsif (/\G (?: \@- | \@LAST_MATCH_START | \@\{LAST_MATCH_START\} | \@\{\^LAST_MATCH_START\} ) /xmsgc) {
4093 0         0 $parsed .= '@{[join $", mb::_LAST_MATCH_START()]}';
4094             }
4095              
4096             # $-[1] --> @{[mb::_LAST_MATCH_START(1)]}
4097             # $LAST_MATCH_START[1] --> @{[mb::_LAST_MATCH_START(1)]}
4098             # ${LAST_MATCH_START}[1] --> @{[mb::_LAST_MATCH_START(1)]}
4099             # ${^LAST_MATCH_START}[1] --> @{[mb::_LAST_MATCH_START(1)]}
4100             elsif (/\G (?: \$- | \$LAST_MATCH_START | \$\{LAST_MATCH_START\} | \$\{\^LAST_MATCH_START\} ) \s* (\[) /xmsgc) {
4101 0         0 my $n_th = quotee_of(parse_expr_balanced($1));
4102 0         0 $parsed .= "\@{[mb::_LAST_MATCH_START($n_th)]}";
4103             }
4104              
4105             # @+ --> @{[join $", mb::_LAST_MATCH_END()]}
4106             # @LAST_MATCH_END --> @{[join $", mb::_LAST_MATCH_END()]}
4107             # @{LAST_MATCH_END} --> @{[join $", mb::_LAST_MATCH_END()]}
4108             # @{^LAST_MATCH_END} --> @{[join $", mb::_LAST_MATCH_END()]}
4109             elsif (/\G (?: \@\+ | \@LAST_MATCH_END | \@\{LAST_MATCH_END\} | \@\{\^LAST_MATCH_END\} ) /xmsgc) {
4110 0         0 $parsed .= '@{[join $", mb::_LAST_MATCH_END()]}';
4111             }
4112              
4113             # $+[1] --> @{[mb::_LAST_MATCH_END(1)]}
4114             # $LAST_MATCH_END[1] --> @{[mb::_LAST_MATCH_END(1)]}
4115             # ${LAST_MATCH_END}[1] --> @{[mb::_LAST_MATCH_END(1)]}
4116             # ${^LAST_MATCH_END}[1] --> @{[mb::_LAST_MATCH_END(1)]}
4117             elsif (/\G (?: \$\+ | \$LAST_MATCH_END | \$\{LAST_MATCH_END\} | \$\{\^LAST_MATCH_END\} ) \s* (\[) /xmsgc) {
4118 0         0 my $n_th = quotee_of(parse_expr_balanced($1));
4119 0         0 $parsed .= "\@{[mb::_LAST_MATCH_END($n_th)]}";
4120             }
4121              
4122             # any
4123             elsif (/\G (${mb::x}) /xmsgc) {
4124 3018 100       6821 if (CORE::length($1) == 1) {
4125 2457         3962 $parsed .= $1;
4126             }
4127             else {
4128 561         1175 $parsed .= ('(?:' . escape_qq($1, $closewith) . ')');
4129             }
4130             }
4131              
4132             # something wrong happened
4133             else {
4134 0         0 die sprintf(<
4135 0         0 $0(@{[__LINE__]}): something wrong happened in script at pos=%s
4136             ------------------------------------------------------------------------------
4137             %s
4138             ------------------------------------------------------------------------------
4139             END
4140             }
4141 4863         11345 return $parsed;
4142             }
4143              
4144             #---------------------------------------------------------------------
4145             # parse modifiers of qr///here
4146             sub parse_re_modifier {
4147 4642     4645 0 6210 my $modifier_i = '';
4148 4642         5578 my $modifier_not_cegir = '';
4149 4642         5838 my $modifier_cegr = '';
4150 4642         5250 while (1) {
4151 4832 50       18903 if (/\G [adlpu] /xmsgc) {
    100          
    100          
    100          
4152             # drop modifiers
4153             }
4154             elsif (/\G ([i]) /xmsgc) {
4155 76         143 $modifier_i .= $1;
4156             }
4157             elsif (/\G ([cegr]) /xmsgc) {
4158 35         70 $modifier_cegr .= $1;
4159             }
4160             elsif (/\G ([a-z]) /xmsgc) {
4161 79         131 $modifier_not_cegir .= $1;
4162             }
4163             else {
4164 4642         5842 last;
4165             }
4166             }
4167 4642         11408 return ($modifier_i, $modifier_not_cegir, $modifier_cegr);
4168             }
4169              
4170             #---------------------------------------------------------------------
4171             # parse modifiers of tr///here
4172             sub parse_tr_modifier {
4173 1250     1253 0 1457 my $modifier_not_r = '';
4174 1250         1310 my $modifier_r = '';
4175 1250         1219 while (1) {
4176 1314 50       3395 if (/\G ([r]) /xmsgc) {
    100          
4177 0         0 $modifier_r .= $1;
4178             }
4179             elsif (/\G ([a-z]) /xmsgc) {
4180 64         108 $modifier_not_r .= $1;
4181             }
4182             else {
4183 1250         1383 last;
4184             }
4185             }
4186 1250         2370 return ($modifier_not_r, $modifier_r);
4187             }
4188              
4189             #---------------------------------------------------------------------
4190             # makes code point class from string
4191             sub codepoint_tr {
4192 1230     1233 0 4398 my($searchlist) = $_[0] =~ /\A [\x00-\xFF] (.*) [\x00-\xFF] \z/xms;
4193 1230 100       2180 my $look_ahead = ($_[1] =~ /c/) ? '(?:(?!' : '(?:(?=';
4194 1230         1389 my $charclass = '';
4195 1230         1451 my @sbcs = ();
4196 1230         1279 my @xbcs = (); # "xbcs" means DBCS, TBCS, QBCS, ...
4197 1230         1302 while (1) {
4198 2472 100       8595 if ($searchlist =~ /\G \z /xmsgc) {
    50          
    50          
4199 1230 50 100     8008 $charclass =
    100 66        
    100 33        
4200             ( @sbcs and @xbcs) ? $look_ahead . join('|', @xbcs, '['.join('',@sbcs).']') . ")${mb::x})" :
4201             (!@sbcs and @xbcs) ? $look_ahead . join('|', @xbcs ) . ")${mb::x})" :
4202             ( @sbcs and !@xbcs) ? $look_ahead . '['.join('',@sbcs).']' . ")${mb::x})" :
4203             die;
4204 1230         1790 last;
4205             }
4206              
4207             # range specification by '-' in tr/// is not supported
4208             # this limitation makes it easier to change the script encoding
4209             elsif ($searchlist =~ /\G (-) /xmsgc) {
4210 0 0       0 if ($^W) {
4211 0         0 cluck <
4212             "$searchlist" in tr///
4213              
4214             range specification by '-' in tr/// is not supported.
4215             this limitation makes it easier to change the script encoding.
4216             END
4217             }
4218 0         0 push @sbcs, '\\x2D';
4219             }
4220              
4221             # any
4222             elsif ($searchlist =~ /\G (${mb::x}) /xmsgc) {
4223 1242 100       2509 if (CORE::length($1) == 1) {
4224 1104         2215 push @sbcs, $1;
4225             }
4226             else {
4227 138         269 push @xbcs, '(?:' . escape_to_hex($1, ']') . ')';
4228             }
4229             }
4230              
4231             # something wrong happened
4232             else {
4233 0         0 die sprintf(<
4234 0         0 $0(@{[__LINE__]}): something wrong happened in script at pos=%s
4235             ------------------------------------------------------------------------------
4236             %s
4237             ------------------------------------------------------------------------------
4238             END
4239             }
4240             }
4241 1230         5252 return $charclass;
4242             }
4243              
4244             #---------------------------------------------------------------------
4245             # get quotee from quoted "quotee"
4246             sub quotee_of {
4247 1135 50   1138 0 2147 if (CORE::length($_[0]) >= 2) {
4248 1135         2751 return CORE::substr($_[0],1,-1);
4249             }
4250             else {
4251 0         0 die;
4252             }
4253             }
4254              
4255             #---------------------------------------------------------------------
4256             # escape q/string/ as q-like quote
4257             sub escape_q {
4258 13595     13598 0 24162 my($codepoint, $endswith) = @_;
4259 13595 50       82041 if ($codepoint =~ /\A ([^\x00-\x7F]) (\Q$endswith\E) \z/xms) {
    100          
4260 0         0 return "$1\\$2";
4261             }
4262             elsif ($codepoint =~ /\A ([^\x00-\x7F]) ($escapee_in_q__like) \z/xms) {
4263 96         312 return "$1\\$2";
4264             }
4265             else {
4266 13499         33813 return $codepoint;
4267             }
4268             }
4269              
4270             #---------------------------------------------------------------------
4271             # escape qq/string/ as qq-like quote
4272             sub escape_qq {
4273 10670     10673 0 17640 my($codepoint, $endswith) = @_;
4274              
4275             # m@`@ --> m`\x60`
4276             # qr@`@ --> qr`\x60`
4277             # s@`@``@ --> s`\x60`\x60\x60`
4278             # m:`: --> m`\x60`
4279             # qr:`: --> qr`\x60`
4280             # s:`:``: --> s`\x60`\x60\x60`
4281 10670 50       69713 if ($codepoint eq '`') {
    100          
    100          
4282 0         0 return '\\x60';
4283             }
4284             elsif ($codepoint =~ /\A ([^\x00-\x7F]) (\Q$endswith\E) \z/xms) {
4285 38         138 return "$1\\$2";
4286             }
4287             elsif ($codepoint =~ /\A ([^\x00-\x7F]) ([$escapee_in_qq_like]) \z/xms) {
4288 413         1577 return "$1\\$2";
4289             }
4290             else {
4291 10219         23396 return $codepoint;
4292             }
4293             }
4294              
4295             #---------------------------------------------------------------------
4296             # escape qq/string/ or qr/regexp/ to hex
4297             sub escape_to_hex {
4298 627     630 0 1235 my($codepoint, $endswith) = @_;
4299 627 100       3939 if ($codepoint =~ /\A ([^\x00-\x7F]) (\Q$endswith\E) \z/xms) {
    100          
4300 30         155 return sprintf('\x%02X\x%02X', CORE::ord($1), CORE::ord($2));
4301             }
4302              
4303             # in qr'...', $escapee_in_qq_like is right, not $escapee_in_q__like
4304             elsif ($codepoint =~ /\A ([^\x00-\x7F]) ([$escapee_in_qq_like]) \z/xms) {
4305 108         702 return sprintf('\x%02X\x%02X', CORE::ord($1), CORE::ord($2));
4306             }
4307             else {
4308 489         1691 return $codepoint;
4309             }
4310             }
4311              
4312             #---------------------------------------------------------------------
4313              
4314             1;
4315              
4316             __END__