File Coverage

blib/lib/Lingua/Romana/Perligata.pm
Criterion Covered Total %
statement 316 568 55.6
branch 190 434 43.7
condition 85 169 50.3
subroutine 44 69 63.7
pod 1 19 5.2
total 636 1259 50.5


line stmt bran cond sub pod time code
1             package Lingua::Romana::Perligata;
2              
3             our $VERSION = '0.604';
4              
5 3     3   3997 use Filter::Util::Call;
  3         2811  
  3         183  
6 3     3   1599 use IO::Handle;
  3         18799  
  3         175  
7 3     3   1875 use Data::Dumper 'Dumper';
  3         21072  
  3         192  
8 3     3   24 no warnings 'once';
  3         6  
  3         11145  
9              
10             my $offset = 0;
11             my $translate = 0;
12             my $debug = 0;
13              
14             sub import {
15 3     3   69 filter_add({});
16 3         150 $offset = (caller)[2]+1;
17 3         18 $translate = grep /^converte?$/i, @_[1..$#_];
18 3         20 $debug = grep /^investiga?$/i, @_[1..$#_];
19 3         10 $lex = grep /^discribe?$/i, @_[1..$#_];
20 3         54 1;
21             }
22              
23             $translator = q{
24             BEGIN {
25             $SIG{__DIE__} = sub { die Lingua::Romana::Perligata::readversum($_[0]) };
26             $SIG{__WARN__} = sub { return if $_[0] =~ /(...) interpreted as function/;
27             warn Lingua::Romana::Perligata::readversum($_[0]) };
28             }
29             };
30              
31 0     0   0 sub unimport { filter_del() }
32              
33             sub filter {
34 6     6 0 271 my($self) = @_ ;
35              
36 6         15 my $status = 1;
37 6         180 $status = filter_read(100_000);
38 6 50       31 return $status if $status<0;
39 6         19 s/\A#!.*\n//;
40 6         109 s{^ \h* ecce \b .*? (?: ^ \h* ecce \h+ seco \h* $ | \Z )}{}gxmsi;
41 6         38 $tokens = tokenize($_);
42              
43 6         10 my @commands;
44 6         25 push @commands, conn_command($tokens,'END') while @$tokens;
45 6         19 $_ = join ";\n", map { $_->translate } @commands;
  11         36  
46              
47 6 0 33     32 if ($translate) { print "$_;\n" and exit }
  0 50       0  
    50          
48             elsif ($debug && /\S/) {
49 0         0 print "=" x 72,
50             "\nTranslated to:\n\n$_\n",
51             "=" x 72;
52             }
53 6         28 $_ = "$translator\n#line $offset\n;$_";
54 6         4648 return $status;
55             }
56              
57             #==========TOKENIZER============
58              
59 0     0 0 0 sub adversum { " ad versum " . to_rn($_[0]->{line}) . "\n" }
60 0 0   0 0 0 sub readversum { $_[0] =~ m{(.*)at\s+(\S+)\s+line\s+(\d+)(.*)}s or return $_[0];
61 0         0 return $1 . " ad $2 versum " . to_rn($3) . $4 }
62              
63             sub make_range {
64 30     30 0 58 my ($unit, $five, $ten) = @_;
65 30         79 my ($two, $three) = ($unit x 2, $unit x 3);
66 30         156 return [ "", $unit, $two, $three, $unit.$five, $five,
67             $five.$unit, $five.$two, $five.$three, $unit.$ten ];
68             }
69              
70             my @order = (
71             make_range(qw{ I V X }),
72             make_range(qw{ X L C }),
73             make_range(qw{ C D M }),
74             make_range(qw{ M I)) ((I)) }),
75             make_range(qw{ ((I)) I))) (((I))) }),
76             make_range(qw{ (((I))) I)))) ((((I)))) }),
77             make_range(qw{ ((((I)))) I))))) (((((I))))) }),
78             make_range(qw{ (((((I))))) I)))))) ((((((I)))))) }),
79             make_range(qw{ ((((((I)))))) I))))))) (((((((I))))))) }),
80             make_range(qw{ (((((((I))))))) I)))))))) ((((((((I)))))))) }),
81             );
82              
83             my %val;
84             foreach my $power (0..$#order) {
85             @val{@{$order[$power]}} = map {$_*10**$power} 0..9;
86             }
87              
88             my $roman = '(' . join(")(", map {join("|",map { quotemeta } reverse(@$_))} reverse @order) . '|)';
89              
90             sub from_rn {
91 2     2 0 6 my $val = shift;
92 2         566 @numerals = $val =~ /(?:$roman)/ix;
93 2 50       30 join("",@numerals) eq $val or return $val;
94 2         4 my $an = 0;
95 2         19 $an += $val{$_} foreach @numerals;
96 2         10 return $an;
97             }
98              
99             sub __beautify__ {
100 0     0   0 my ($text) = @_;
101 0         0 $text =~ s/\b(\d+)\b/to_rn($1)/ge;
  0         0  
102 0         0 return $text;
103             }
104              
105             sub to_rn {
106 0 0   0 0 0 return "nullum" if $_[0] == 0;
107 0         0 @digits = split '', $_[0];
108 0 0       0 return $_[0] if grep {/\D/} @digits;
  0         0  
109 0         0 my $power = 0;
110 0         0 my $rn = "";
111 0   0     0 $rn = $order[$power++][$_||0] . $rn foreach reverse @digits;
112 0         0 return $rn;
113             }
114              
115             sub getline {
116 1     1 0 8 my ($fh) = @_;
117 1 50       6 if (wantarray) {
118 0         0 my @lines = IO::Handle::getlines($fh);
119 0 0       0 s/\b($roman)\b/$1 ? from_rn($1) : $1/ge for @lines;
  0         0  
120 0         0 return @lines;
121             }
122             else {
123 1         30 my $line = IO::Handle::getline($fh);
124 1 50       322 $line =~ s/\b($roman)\b/$1 ? from_rn($1) : $1/ge;
  2         33  
125 1         6 return $line;
126             }
127             }
128              
129             sub multibless(\%$$)
130             {
131 99     99 0 184 my ($hash,$blesstype,$lextype) = @_;
132 99         462 foreach my $key (keys %$hash)
133             {
134 2277         3310 $hash->{$key}{lex} = $lextype;
135 2277         3683 bless $hash->{$key}, $blesstype;
136             }
137             }
138              
139             sub addres(\%$$)
140             {
141 24     24 0 57 my ($hash,$blesstype,$lextype) = @_;
142 24         33 my (%acc, %dat);
143 24         80 foreach my $key (keys %$hash)
144             {
145 387         578 $acc{$key.'mentum'} = { %{$hash->{$key}} };
  387         1482  
146 387         652 $acc{$key.'menta'} = { %{$hash->{$key}} };
  387         1336  
147 387         632 $dat{$key.'mento'} = { %{$hash->{$key}} };
  387         1259  
148 387         608 $dat{$key.'mentis'} = { %{$hash->{$key}} };
  387         1406  
149             }
150 24         102 multibless %acc, $blesstype, $lextype.'_ACCUSATIVE';
151 24         99 multibless %dat, $blesstype, $lextype.'_DATIVE';
152 24         988 %$hash = ( %$hash, %acc, %dat );
153             }
154              
155             sub add_genitives(\%$$$)
156             {
157 18     18 0 38 my ($hash, $blesstype, $from, $to) = @_;
158 18         86 foreach my $key (keys %$hash)
159             {
160 642         962 my $genkey = $key;
161 642 100       1950 $genkey =~ s/$from$/$to/ or next;
162 114         198 $hash->{$genkey} = bless { %{$hash->{$key}},
  114         513  
163             lex => 'GENITIVE' },
164             $blesstype;
165             }
166             }
167              
168             my %literals =
169             (
170             'novumversum' => { perl => '"\n"' },
171             'semicolon' => { perl => '";"' },
172             'biguttam' => { perl => '":"' },
173             'guttam' => { perl => '"."' },
174             'comma' => { perl => '","' },
175             'lacunam' => { perl => '" "' },
176             'stadium' => { perl => '"\t"' },
177             'parprimum' => { perl => '$1' },
178             'parsecundum' => { perl => '$2' },
179             'partertium' => { perl => '$3' },
180             'parquartum' => { perl => '$4' },
181             'parquintum' => { perl => '$5' },
182             'parsextum' => { perl => '$6' },
183             'parseptimum' => { perl => '$7' },
184             'paroctavum' => { perl => '$8' },
185             'parnonum' => { perl => '$9' },
186             'pardecimum' => { perl => '$10' },
187             'nomen' => { perl => '$<' },
188             );
189              
190             multibless %literals, 'Literal', 'ACCUSATIVE';
191             add_genitives %literals, 'Literal', 'um' => 'i';
192             add_genitives %literals, 'Literal', 'am' => 'ae';
193             add_genitives %literals, 'Literal', 'ma' => 'matis';
194             add_genitives %literals, 'Literal', 'ula' => 'uli';
195              
196              
197             my %numerals =
198             (
199             'nullum' => { perl => '0' },
200             'unum' => { perl => '1' },
201             'unam' => { perl => '1' },
202             'duo' => { perl => '2' },
203             'duas' => { perl => '2' },
204             'tres' => { perl => '3' },
205             'quattuor' => { perl => '4' },
206             'quinque' => { perl => '5' },
207             'sex' => { perl => '6' },
208             'septem' => { perl => '7' },
209             'octo' => { perl => '8' },
210             'novem' => { perl => '9' },
211             'decem' => { perl => '10' },
212             );
213              
214             multibless %numerals, 'Literal', 'NUMERAL';
215              
216              
217             my %ordinals_a =
218             (
219             'nullimum' => { perl => '0' },
220             'primum' => { perl => '1' },
221             'secundum' => { perl => '2' },
222             'tertium' => { perl => '3' },
223             'quartum' => { perl => '4' },
224             'quintum' => { perl => '5' },
225             'sextum' => { perl => '6' },
226             'septimum' => { perl => '7' },
227             'octavum' => { perl => '8' },
228             'nonum' => { perl => '9' },
229             'decimum' => { perl => '10' },
230             );
231              
232             foreach ( map substr($_,0,-2), keys %ordinals_a ) {
233             $ordinals_a{"${_}os"} = $ordinals_a{"${_}um"}; # MASC. PLURALS
234             $ordinals_a{"${_}am"} = $ordinals_a{"${_}um"}; # FEMININE
235             $ordinals_a{"${_}as"} = $ordinals_a{"${_}um"}; # FEM. PLURALS
236             }
237              
238             multibless %ordinals_a, 'Ordinal', 'ORDINAL';
239             add_genitives %ordinals_a, 'Ordinal', 'um' => 'i';
240             add_genitives %ordinals_a, 'Ordinal', 'am' => 'ae';
241             # add_genitives %ordinals_a, 'Ordinal', 'os' => 'orum';
242              
243             my %ordinals_d =
244             (
245             'nullimo' => { perl => '0' },
246             'primo' => { perl => '1' },
247             'secundo' => { perl => '2' },
248             'tertio' => { perl => '3' },
249             'quarto' => { perl => '4' },
250             'quinto' => { perl => '5' },
251             'sexto' => { perl => '6' },
252             'septimo' => { perl => '7' },
253             'octavo' => { perl => '8' },
254             'nono' => { perl => '9' },
255             'decimo' => { perl => '10' },
256             );
257              
258             multibless %ordinals_d, 'Ordinal', 'ORDINAL_DATIVE';
259              
260             my %special_vars =
261             (
262             'hoc' => { perl => '$_', lex => 'ACCUSATIVE' },
263             'huius' => { perl => '$_', lex => 'GENITIVE' },
264             'huic' => { perl => '$_', lex => 'DATIVE' },
265             'haec' => { perl => '@_', lex => 'ACCUSATIVE' },
266             'horum' => { perl => '@_', lex => 'GENITIVE' },
267             'his' => { perl => '@_', lex => 'DATIVE' },
268             'ianitorem' => { perl => '$/', lex => 'ACCUSATIVE' },
269             'ianitoris' => { perl => '$/', lex => 'GENITIVE' },
270             'ianitori' => { perl => '$/', lex => 'DATIVE' },
271             'programma' => { perl => '$0', lex => 'ACCUSATIVE' },
272             'programmati' => { perl => '$0', lex => 'DATIVE' },
273             'programmatis' => { perl => '$0', lex => 'GENITIVE' },
274             'parametra' => { perl => '@ARGV', lex => 'ACCUSATIVE' },
275             'parametris' => { perl => '@ARGV', lex => 'DATIVE' },
276             'parametrorum' => { perl => '@ARGV', lex => 'GENITIVE' },
277             );
278              
279             for my $key ( keys %special_vars )
280             {
281             bless $special_vars{$key}, 'Literal';
282             }
283              
284             my %varmods =
285             (
286             'loco' => bless ({ perl => 'local', lex => 'OWNER_D' },
287             'ScalarMod'),
288             'locis' => bless ({ perl => 'local', lex => 'OWNER_D' },
289             'ArrMod'),
290             'meo' => bless ({ perl => 'my', lex => 'OWNER_D' },
291             'ScalarMod'),
292             'meis' => bless ({ perl => 'my', lex => 'OWNER_D' },
293             'ArrMod'),
294             'nostro' => bless ({ perl => 'our', lex => 'OWNER_D' },
295             'ScalarMod'),
296             'nostris' => bless ({ perl => 'our', lex => 'OWNER_D' },
297             'ArrMod'),
298             );
299              
300             my %streams =
301             (
302             'parametro' => { perl => '*ARGV' },
303             'vestibulo' => { perl => '*STDIN' },
304             'egresso' => { perl => 'STDOUT' },
305             'oraculo' => { perl => 'STDERR' },
306             'nuntio' => { perl => '*Lingua::Romana::Perligata::DATA' },
307             );
308             multibless %streams, 'Literal', 'DATIVE';
309              
310             my %matchops =
311             (
312             'compara' => { perl => 'm' },
313             'substitue' => { perl => 's' },
314             'converte' => { perl => 'tr' },
315             );
316              
317             multibless %matchops, 'MatchOperator', 'SUBNAME';
318             addres %matchops, 'MatchOperator', 'SUBNAME';
319              
320             my %ops =
321             (
322             'adde' => { perl => '+' },
323             'deme' => { perl => '-' },
324             'multiplica' => { perl => '*' },
325             'itera' => { perl => 'x' },
326             'divide' => { perl => '/' },
327             'recide' => { perl => '%' },
328             'eleva' => { perl => '**' },
329             'consocia' => { perl => '&' },
330             'interseca' => { perl => '|' },
331             'discerne' => { perl => '^' },
332             'depone' => { perl => '' , prefix => 1 },
333             );
334              
335             $ops{$_}{operator} = 1 foreach keys %ops;
336             multibless %ops, 'Operator', 'SUBNAME_A';
337             addres %ops, 'Operator', 'SUBNAME_A';
338              
339             my %lops =
340             (
341             'da' => { perl => '=', operator => 1 },
342             );
343              
344             multibless %lops, 'Operator', 'SUBNAME_AD';
345             addres %lops, 'Operator', 'SUBNAME_AD';
346              
347             my %invarops =
348             (
349             'atque' => { perl => '&&' },
350             'vel' => { perl => '||' },
351             'praestantiam' => { perl => '<' },
352             'non praestantiam' => { perl => '>=' },
353             'praestantias' => { perl => 'lt' },
354             'non praestantias' => { perl => 'ge' },
355             'aequalitam' => { perl => '==' },
356             'non aequalitam' => { perl => '!=' },
357             'aequalitas' => { perl => 'eq' },
358             'non aequalitas' => { perl => 'ne' },
359             'comparitiam' => { perl => '<=>' },
360             'comparitias' => { perl => 'cmp' },
361             'non comparitiam' => { perl => '!<=>' },
362             'non comparitias' => { perl => '!cmp' },
363              
364             'non' => { perl => '!', prefix => 1 },
365             'nega' => { perl => '-', prefix => 1 },
366             );
367              
368             $invarops{$_}{operator} = 1 foreach keys %invarops;
369             multibless %invarops, 'Operator', 'SUBNAME_A_ACCUSATIVE';
370              
371             my %connectives =
372             (
373             'que' => { perl => 'and' },
374             've' => { perl => 'or' },
375             );
376              
377             @{$connectives{$_}}{'operator','raw'} = (1,-$_) foreach keys %connectives;
378             multibless %connectives, 'Operator', 'CONNECTIVE';
379              
380             my %funcs_td =
381             (
382             'excerpe' => { perl => 'substr' }, # SPECIAL: SEE BELOW
383              
384             'cumula' => { perl => 'push' },
385             'capita' => { perl => 'unshift' },
386             'iunge' => { perl => 'splice' },
387             'digere' => { perl => 'sort' },
388             'retexe' => { perl => 'reverse' },
389             'evolute' => { perl => 'open' },
390             'lege' => { perl => 'read' },
391             'scribe' => { perl => 'print' },
392             'describe' => { perl => 'printf' },
393             'subscribe' => { perl => 'write' },
394             'conquire' => { perl => 'seek' },
395             'benedice' => { perl => 'bless' },
396             'liga' => { perl => 'tie' },
397             'modera' => { perl => 'fcntl' },
398             'conflue' => { perl => 'flock' },
399             'impera' => { perl => 'ioctl' },
400             'trunca' => { perl => 'truncate' },
401             );
402              
403             multibless %funcs_td, 'Function', 'SUBNAME_AD';
404             addres %funcs_td, 'Function', 'SUBNAME_AD';
405              
406             # "bless" HAS A COMMON LATIN CONTRACTION...
407              
408             $funcs_td{benedictum} = $funcs_td{benedicementum};
409             $funcs_td{benedicto} = $funcs_td{benedicemento};
410              
411             # THE FOLLOWING IS LVALUABLE, SO ARG MUST AGREE IN CASE WITH FUNCTION'S CASE...
412              
413             for (qw( excerpe )) {
414             $funcs_td{"${_}mentum"}{lex} = 'SUBNAME_A_ACCUSATIVE';
415             }
416              
417              
418             my %funcs_bd =
419             (
420             'vanne' => { perl => 'grep' },
421             'applica' => { perl => 'map' },
422             'digere' => { perl => 'sort' },
423             );
424              
425             multibless %funcs_bd, 'Function', 'SUBNAME_AB';
426             addres %funcs_bd, 'Function', 'SUBNAME_AB';
427              
428             my %funcs_b =
429             (
430             'factorem' => { perl => 'sub' },
431             'factori' => { perl => 'sub' },
432             );
433              
434             multibless %funcs_b, 'Function', 'SUBNAME_B_ACCUSATIVE';
435             $funcs_b{'factori'}{lex} = 'SUBNAME_B_DATIVE';
436              
437              
438             my %funcs_t =
439             (
440             'morde' => { perl => 'chomp' },
441             'praecide' => { perl => 'chop' },
442             'stude' => { perl => 'study' },
443             'iani' => { perl => 'undef' },
444             'lusta' => { perl => 'reset' },
445             'decumula' => { perl => 'pop' },
446             'decapita' => { perl => 'shift' },
447             'claude' => { perl => 'close' },
448             'perlege' => { perl => 'Lingua::Romana::Perligata::getline' },
449             'sublege' => { perl => 'getc' },
450             'enunta' => { perl => 'tell' },
451             'dele' => { perl => 'delete' },
452             'quisque' => { perl => 'each' },
453             'adfirma' => { perl => 'exists' },
454             'solvere' => { perl => 'untie' },
455             'preincresce' => { perl => '++', prefix => 1, operator => 1 },
456             'postincresce' => { perl => '++', prefix => 0, operator => 1 },
457             'predecresce' => { perl => '--', prefix => 1, operator => 1 },
458             'postdecresce' => { perl => '--', prefix => 0, operator => 1 },
459              
460             'reperi' => { perl => 'pos' }, # SPECIAL: SEE BELOW
461             'nomina' => { perl => 'keys' }, # SPECIAL: SEE BELOW
462             );
463              
464             multibless %funcs_t, 'Function', 'SUBNAME_D';
465             addres %funcs_t, 'Function', 'SUBNAME_D';
466              
467              
468             # THE FOLLOWING ARE LVALUABLE, SO ARG MUST AGREE IN CASE WITH FUNCTION'S CASE...
469              
470             for (qw( reperi nomina )) {
471             $funcs_t{"${_}mentum"}{lex} = 'SUBNAME_A_ACCUSATIVE';
472             }
473              
474             my %funcs_d =
475             (
476             'admeta' => { perl => 'Lingua::Romana::Perligata::__lastelem__' },
477             'inque' => { perl => 'Lingua::Romana::Perligata::__enquote__' },
478             'conscribe' => { perl => 'Lingua::Romana::Perligata::__enlist__' },
479             'come' => { perl => 'Lingua::Romana::Perligata::__beautify__' },
480             'priva' => { perl => 'abs' },
481             'angula' => { perl => 'atan2' },
482             'oppone' => { perl => 'sin' },
483             'accuba' => { perl => 'cos' },
484             'decolla' => { perl => 'int' },
485             'succide' => { perl => 'log' },
486             'fode' => { perl => 'sqrt' },
487             'conice' => { perl => 'rand' },
488             'prosemina' => { perl => 'srand' },
489             'inde' => { perl => 'chr' },
490             'senidemi' => { perl => 'hex' },
491             'octoni' => { perl => 'oct' },
492             'numera' => { perl => 'ord' },
493             'deminue' => { perl => 'lc' },
494             'minue' => { perl => 'lcfirst' },
495             'amplifica' => { perl => 'uc' },
496             'amplia' => { perl => 'ucfirst' },
497             'excipe' => { perl => 'quotemeta' },
498             'huma' => { perl => 'crypt' },
499             'meta' => { perl => 'length' },
500             'convasa' => { perl => 'pack' },
501             'deconvasa' => { perl => 'unpack' },
502             'scinde' => { perl => 'split' },
503             'scruta' => { perl => 'index' },
504             'coniunge' => { perl => 'join' },
505             'confirma' => { perl => 'defined' },
506             'secerna' => { perl => 'scalar' },
507             'argue' => { perl => 'values' },
508             'extremus' => { perl => 'eof' },
509             'deside' => { perl => 'wantarray' },
510             'aestima' => { perl => 'eval' },
511             'exi' => { perl => 'exit' },
512             'redde' => { perl => 'return' },
513             'mori' => { perl => 'die' },
514             'mone' => { perl => 'warn' },
515             'coaxa' => { perl => 'Carp::croak' },
516             'carpe' => { perl => 'Carp::carp' },
517             'memora' => { perl => 'caller' },
518             'agnosce' => { perl => 'ref' },
519             'exhibere' => { perl => 'tied' },
520             'require' => { perl => 'require' },
521             'demigrare' => { perl => 'chdir' },
522             'permitte' => { perl => 'chmod' },
523             'vende' => { perl => 'chown' },
524             'inveni' => { perl => 'glob' },
525             'copula' => { perl => 'link' },
526             'decopula' => { perl => 'unlink' },
527             'aedifica' => { perl => 'mkdir' },
528             'renomina' => { perl => 'rename' },
529             'excide' => { perl => 'rmdir' },
530             'exprime' => { perl => 'stat' },
531             'terre' => { perl => 'alarm' },
532             'mitte' => { perl => 'dump' },
533             'commuta' => { perl => 'exec' },
534             'furca' => { perl => 'fork' },
535             'interfice' => { perl => 'kill' },
536             'dormi' => { perl => 'sleep' },
537             'obsecra' => { perl => 'system' },
538             'dissimula' => { perl => 'umask' },
539             'manta' => { perl => 'wait' },
540              
541             'inscribe' => { perl => ':' }, # SPECIAL: SEE BELOW
542             'arcesse' => { perl => '${' }, # SPECIAL: SEE BELOW
543              
544             'sere' => { perl => 'Lingua::Romana::Perligata::__encatenate__' },
545             );
546              
547             multibless %funcs_d, 'Function', 'SUBNAME_A';
548             addres %funcs_d, 'Function', 'SUBNAME_A';
549              
550             # 'inscribe' IS SPECIAL: ONLY IMPERATIVE
551              
552             delete @funcs_d{grep /^inscribement/, keys %funcs_d};
553              
554             # 'arcesse' IS SPECIAL: NO IMPERATIVE AND EXTRA (PSEUDO-)RESULTATIVES
555              
556             delete $funcs_d{'arcesse'};
557              
558             # SCALAR AS NON-TERMINAL INDEX
559              
560             $funcs_d{'arcessementi'} = { %{$funcs_d{'arcessementum'}},
561             lex => 'SUBNAME_A_GENITIVE' };
562              
563             # ARRAY DEREFERENCE
564              
565             $funcs_d{'arcessementa'}{perl} = '@{';
566             $funcs_d{'arcessementis'}{perl} = '@{';
567             $funcs_d{'arcessementorum'} = { %{$funcs_d{'arcessementa'}},
568             lex => 'SUBNAME_A_GENITIVE' };
569              
570             $funcs_d{'arcessementus'} = { %{$funcs_d{'arcessementa'}}, perl => '%{' };
571             $funcs_d{'arcessementibus'} = { %{$funcs_d{'arcessementis'}}, perl => '%{' };
572             $funcs_d{'arcessementuum'} = { %{$funcs_d{'arcessementus'}},
573             lex => 'SUBNAME_A_GENITIVE'};
574              
575              
576             my %funcs_dl =
577             (
578             'adi' => { perl => 'goto' },
579             'confectus' => { perl => 'continue' },
580             'domus' => { perl => 'package' },
581             'legatarius' => { perl => 'use base' },
582             'ute' => { perl => 'use' },
583             );
584              
585             multibless %funcs_dl, 'Function_Lit', 'SUBNAME_A';
586             addres %funcs_dl, 'Function_Lit', 'SUBNAME_A';
587              
588             my %funcs_dlo =
589             (
590             'ultimus' => { perl => 'last' },
591             'posterus' => { perl => 'next' },
592             'reconnatus' => { perl => 'redo' },
593             );
594              
595             multibless %funcs_dlo, 'Function_Lit', 'SUBNAME_OA';
596             # addres %funcs_dl, 'Function_Lit', 'SUBNAME_OA';
597              
598             my %misc =
599             (
600             'fac' => { lex => 'DO', perl => 'do' },
601             'per' => { lex => 'FOR', perl => 'for' },
602             'per quisque' => { lex => 'FOR', perl => 'foreach' },
603             'si' => { lex => 'CONTROL', perl => 'if' },
604             'nisi' => { lex => 'CONTROL', perl => 'unless' },
605             'donec' => { lex => 'CONTROL', perl => 'until' },
606             'dum' => { lex => 'CONTROL', perl => 'while' },
607             'cum' => { lex => 'WITH', perl => '' },
608             'intra' => { lex => 'WITHIN', perl => '::' },
609             'apud' => { lex => 'ARROW', perl => '->' },
610             'tum' => { lex => 'COMMA', perl => ',' },
611             'in' => { lex => 'IN', perl => '' },
612             'sic' => { lex => 'BEGIN', perl => '{' },
613             'cis' => { lex => 'END', perl => '}' },
614             'princeps' => { lex => 'NAME', raw=>'main', perl => 'main' },
615             'ad' => { lex => 'ADDRESS', perl => '\\' },
616             );
617              
618             my %tokens =
619             (
620             %literals, %numerals, %special_vars,
621             %numerals, %ordinals_a, %ordinals_d,
622             %varmods, %matchops, %ops, %lops, %invarops,
623             %funcs_td, %funcs_bd, %funcs_b, %funcs_t,
624             %funcs_d, %funcs_dl, %funcs_dlo,
625             %misc, %streams,
626             );
627              
628             # Handle likely captialization variations...
629             @tokens{map {ucfirst} keys %tokens} = values %tokens;
630              
631             foreach my $key ( keys %tokens )
632             {
633             $tokens{$key}{raw} = $key
634             unless $tokens{$key}{raw};
635             }
636              
637             my $distokens = join '|', reverse sort keys %tokens;
638             my $tokens = "\\A\\s*($distokens)\\b";
639             my $tokensque = "\\A\\s*($distokens)que\\b";
640             my $tokensve = "\\A\\s*($distokens)ve\\b";
641              
642             sub token($$$$)
643             {
644 28     28 0 92 my ($raw, $lex, $perl, $blesstype) = @_;
645 28         145 return bless { raw => $raw, lex => $lex, perl => $perl }, $blesstype;
646             }
647              
648             sub tokdup
649             {
650 94     94 0 190 my ($archetype) = @_;
651 94         659 bless { %$archetype }, $archetype->{lex};
652             }
653              
654             sub tokenize
655             {
656 6     6 0 18 my ($text) = @_;
657 6         12 my @tokens;
658 6         13 my $bad = "";
659 6         24 my $lines = $text =~ tr/\n/\n/;
660              
661 6         20 while (length $text)
662             {
663 125         493 $text =~ s/\A\s+//;
664 125         295 my $line = $lines - ($text =~ tr/\n/\n/) + $offset;
665 125 50 33     45390 if ($text =~ s/\A(adnota.*)//i)
    50 33        
    100 100        
    50          
    50          
    50          
    50          
    100          
    50          
    50          
    100          
    50          
    50          
    50          
    50          
    50          
    50          
    100          
    50          
    50          
    50          
    100          
    50          
    50          
    50          
    100          
    100          
    50          
    100          
    100          
666             {
667             # ignore comments
668             }
669             elsif ($text =~ s/\A(nuntius|finis)[ \t]*[.]?[ \t]*\n(.*)//smi)
670             {
671             # set up DATA stream
672 3     3   28 use vars '*DATA';
  3         7  
  3         10869  
673 0         0 local *Lingua::Romana::Perlidata::DATASRC;
674 0         0 my $pipe = pipe \*Lingua::Romana::Perligata::DATA,
675             \*Lingua::Romana::Perlidata::DATASRC;
676              
677 0         0 print Lingua::Romana::Perlidata::DATASRC $2;
678             }
679             elsif ($text =~ s/\Adic(?:emen)?tum(que|ve|)\s+sic\s+\b(.*?)\s+cis\b//si)
680             {
681 3 50       11 push @tokens, tokdup $connectives{lc $1} if $1;
682 3         11 push @tokens, token($2,'NAME',"$2",'Name');
683             }
684             elsif ($text =~ s/\Asic(que|ve|)\s+(.*?)\s+cis\s+dic(?:emen)?tum\b//si)
685             {
686 0 0       0 push @tokens, tokdup $connectives{lc $1} if $1;
687 0         0 push @tokens, token($2,'NAME',"$2",'Name');
688             }
689             elsif ($text =~ s/\A(atque|vel)\b//i)
690             {
691 0         0 push @tokens, tokdup $misc{'tum'};
692 0         0 push @tokens, tokdup $invarops{lc $1};
693             }
694             elsif ($text =~ s/\A(($roman)im(?:o|ae)(que|ve|))\b//ix && length $2)
695             {
696 0 0       0 push @tokens, tokdup $connectives{lc $+} if $+;
697 0         0 push @tokens, token($1,'ORDINAL_DATIVE',from_rn($2),'ORDINAL_DATIVE');
698             }
699             elsif ($text =~ s/\A(($roman)im(?:um|os|am|as)(que|ve|))\b//ix && length $2)
700             {
701 0 0       0 push @tokens, tokdup $connectives{lc $+} if $+;
702 0         0 push @tokens, token($1,'ORDINAL',from_rn($2),'ORDINAL');
703             }
704             elsif ($text =~ s/\A(($roman)(que|ve|))\b//ix && length $2)
705             {
706 2 50       13 push @tokens, tokdup $connectives{lc $+} if $+;
707 2         10 push @tokens, token($1,'NUMERAL',from_rn($2),'NUMERAL');;
708             }
709             elsif ($text =~ s/$tokensque//i)
710             {
711 0         0 push @tokens, tokdup $connectives{'que'};
712 0         0 push @tokens, tokdup $tokens{lc $1};
713             }
714             elsif ($text =~ s/$tokensve//i)
715             {
716 0         0 push @tokens, tokdup $connectives{'ve'};
717 0         0 push @tokens, tokdup $tokens{lc $1};
718             }
719             elsif ($text =~ s/$tokens//i)
720             {
721 94         416 push @tokens, tokdup $tokens{lc $1};
722             }
723             elsif ($text =~ s/\A(([a-z_][0-9a-z_]*?)(um|)ementum)(que|ve|)((?:\s+)sicut)?\b//i)
724             {
725 0 0       0 if ($5)
726             {
727 0 0       0 my $token = $4 ? $1.$4 : $1;
728 0         0 push @tokens, token($token,'NAME',$token,'Name');
729             }
730             else
731             {
732 0 0       0 push @tokens, tokdup $connectives{lc $4} if $4;
733 0 0       0 my $perl = $3 ? "\$$2->" : $2;
734 0         0 push @tokens, token($1,'SUBNAME_OA_ACCUSATIVE',$perl,'Literal');
735             }
736             }
737             elsif ($text =~ s/\A(([a-z_][0-9a-z_]*?)(um|)ementa)(que|ve|)((?:\s+)sicut)?\b//i)
738             {
739 0 0       0 if ($5)
740             {
741 0 0       0 my $token = $4 ? $1.$4 : $1;
742 0         0 push @tokens, token($token,'NAME',$token,'Name');
743             }
744             else
745             {
746 0 0       0 push @tokens, tokdup $connectives{lc $4} if $4;
747 0 0       0 my $perl = $3 ? "\$$2->" : $2;
748 0         0 push @tokens, token($1,'SUBNAME_OA_ACCUSATIVE',$perl,'Literal');
749             }
750             }
751             elsif ($text =~ s/\A(([a-z_][0-9a-z_]*?)(um|)emento)(que|ve|)((?:\s+)sicut)?\b//i)
752             {
753 0 0       0 if ($5)
754             {
755 0 0       0 my $token = $4 ? $1.$4 : $1;
756 0         0 push @tokens, token($token,'NAME',$token,'Name');
757             }
758             else
759             {
760 0 0       0 push @tokens, tokdup $connectives{lc $4} if $4;
761 0 0       0 my $perl = $3 ? "\$$2->" : $2;
762 0         0 push @tokens, token($1,'SUBNAME_OA_DATIVE',$perl,'Literal');
763             }
764             }
765             elsif ($text =~ s/\A(([a-z_][0-9a-z_]*?)(um|)ementis)(que|ve|)((?:\s+)sicut)?\b//i)
766             {
767 0 0       0 if ($5)
768             {
769 0 0       0 my $token = $4 ? $1.$4 : $1;
770 0         0 push @tokens, token($token,'NAME',"$token",'Name');
771             }
772             else
773             {
774 0         0 $bad .= "'-mentis' illicitum: '$1'"
775             . adversum({line=>$line});
776             # One day this may be:
777             #
778             # push @tokens, tokdup $connectives{lc $4} if $4;
779             # my $perl = $3 ? "\$$2->" : $2;
780             # push @tokens, token($1,'SUBNAME_OA_DATIVE',$perl,'Literal');
781             }
782             }
783             elsif ($text =~ s/\A(([a-z_][0-9a-z_]*)orum)(que|ve|)((?:\s+)sicut)?\b//i)
784             {
785 0 0       0 if ($4)
786             {
787 0 0       0 my $token = $3 ? $1.$3 : $1;
788 0         0 push @tokens, token($token,'NAME',$token,'Name');
789             }
790             else
791             {
792 0 0       0 push @tokens, tokdup $connectives{lc $3} if $3;
793 0         0 push @tokens, token($1,'GENITIVE',"\@$2",'Literal');
794             }
795             }
796             elsif ($text =~ s/\A(([a-z_][0-9a-z_]*)uum)(que|ve|)((?:\s+)sicut)?\b//i)
797             {
798 0 0       0 if ($4)
799             {
800 0 0       0 my $token = $3 ? $1.$3 : $1;
801 0         0 push @tokens, token($token,'NAME',$token,'Name');
802             }
803             else
804             {
805 0 0       0 push @tokens, tokdup $connectives{lc $3} if $3;
806 0         0 push @tokens, token($1,'GENITIVE',"\%$2",'Literal');
807             }
808             }
809             elsif ($text =~ s/\A(([a-z_][0-9a-z_]*)um)(que|ve|)((?:\s+)sicut)?\b//i)
810             {
811 5 50       28 if ($4)
812             {
813 0 0       0 my $token = $3 ? $1.$3 : $1;
814 0         0 push @tokens, token($token,'NAME',$token,'Name');
815             }
816             else
817             {
818 5 50       19 push @tokens, tokdup $connectives{lc $3} if $3;
819 5         26 push @tokens, token($1,'ACCUSATIVE',"\$$2",'Literal');
820             }
821             }
822             elsif ($text =~ s/\A(([a-z_][0-9a-z_]*)a)(que|ve|)((?:\s+)sicut)?\b//i)
823             {
824 0 0       0 if ($4)
825             {
826 0 0       0 my $token = $3 ? $1.$3 : $1;
827 0         0 push @tokens, token($token,'NAME',$token,'Name');
828             }
829             else
830             {
831 0 0       0 push @tokens, tokdup $connectives{lc $3} if $3;
832 0         0 push @tokens, token($1,'ACCUSATIVE',"\@$2",'Literal');
833             }
834             }
835             elsif ($text =~ s/\A(([a-z_][0-9a-z_]*)ibus)(que|ve|)((?:\s+)sicut)?\b//i)
836             {
837 0 0       0 if ($4)
838             {
839 0 0       0 my $token = $3 ? $1.$3 : $1;
840 0         0 push @tokens, token($token,'NAME',$token,'Name');
841             }
842             else
843             {
844 0 0       0 push @tokens, tokdup $connectives{lc $3} if $3;
845 0         0 push @tokens, token($1,'DATIVE',"\%$2",'Literal');
846             }
847             }
848             elsif ($text =~ s/\A(([a-z_][0-9a-z_]*)us)(que|ve|)((?:\s+)sicut)?\b//i)
849             {
850 0 0       0 if ($4)
851             {
852 0 0       0 my $token = $3 ? $1.$3 : $1;
853 0         0 push @tokens, token($token,'Name',$token,'Name');
854             }
855             else
856             {
857 0 0       0 push @tokens, tokdup $connectives{lc $3} if $3;
858 0         0 push @tokens, token($1,'ACCUSATIVE',"\%$2",'Literal');
859             }
860             }
861             elsif ($text =~ s/\A(([a-z_][0-9a-z_]*)o)(que|ve|)((?:\s+)sicut)?\b//i)
862             {
863 1 50       6 if ($4)
864             {
865 0 0       0 my $token = $3 ? $1.$3 : $1;
866 0         0 push @tokens, token($token,'NAME',$token,'Name');
867             }
868             else
869             {
870 1 50       4 push @tokens, tokdup $connectives{lc $3} if $3;
871 1         7 push @tokens, token($1,'DATIVE',"\$$2",'Literal');
872             }
873             }
874             elsif ($text =~ s/\A(([a-z_][0-9a-z_]*)is)(que|ve|)((?:\s+)sicut)?\b//i)
875             {
876 0 0       0 if ($4)
877             {
878 0 0       0 my $token = $3 ? $1.$3 : $1;
879 0         0 push @tokens, token($token,'NAME',$token,'Name');
880             }
881             else
882             {
883 0 0       0 push @tokens, tokdup $connectives{lc $3} if $3;
884 0         0 push @tokens, token($1,'DATIVE',"\@$2",'Literal');
885             }
886             }
887             elsif ($text =~ s/\A(([a-z_][0-9a-z_]*)tori)(que|ve|)((?:\s+)sicut)?\b//i)
888             {
889 0 0       0 if ($4)
890             {
891 0 0       0 my $token = $3 ? $1.$3 : $1;
892 0         0 push @tokens, token($token,'NAME',$token,'Name');
893             }
894             else
895             {
896 0 0       0 push @tokens, tokdup $connectives{lc $3} if $3;
897 0         0 push @tokens, token($1,'DATIVE',"\\&$2",'Literal');
898             }
899             }
900             elsif ($text =~ s/\A(([a-z_][0-9a-z_]*)i)(que|ve|)((?:\s+)sicut)?\b//i)
901             {
902 0 0       0 if ($4)
903             {
904 0 0       0 my $token = $3 ? $1.$3 : $1;
905 0         0 push @tokens, token($token,'NAME',$token,'Name');
906             }
907             else
908             {
909 0 0       0 push @tokens, tokdup $connectives{lc $3} if $3;
910 0         0 push @tokens, token($1,'GENITIVE',"\$$2",'Literal');
911             }
912             }
913             elsif ($text =~ s/\A(([a-z_][0-9a-z_]*)ere)(que|ve|)((?:\s+)sicut)?\b//i)
914             {
915 2 50       11 if ($4)
916             {
917 0 0       0 my $token = $3 ? $1.$3 : $1;
918 0         0 push @tokens, token($token,'NAME',$token,'Name');
919             }
920             else
921             {
922 2 50       7 push @tokens, tokdup $connectives{lc $3} if $3;
923 2         9 push @tokens, token($1,'INFINITIVE',"$2",'Literal');
924             }
925             }
926             elsif ($text =~ s/\A(([a-z_][0-9a-z_]*?)(um|)e)(que|ve|)((?:\s+)sicut)?\b//i)
927             {
928 2 50       9 if ($5)
929             {
930 0 0       0 my $token = $4 ? $1.$4 : $1;
931 0         0 push @tokens, token($token,'NAME',$token,'Name');
932             }
933             else
934             {
935 2 50       59 push @tokens, tokdup $connectives{lc $4} if $4;
936 2 50       9 my $perl = $3 ? "\$$2->" : $2;
937 2         6 push @tokens, token($1,'SUBNAME',$perl,'Literal');
938             }
939             }
940             elsif ($text =~ s/\A(([a-z_][0-9a-z_]*)torem)(que|ve|)((?:\s+)sicut)?\b//i)
941             {
942 0 0       0 if ($4)
943             {
944 0 0       0 my $token = $3 ? $1.$3 : $1;
945 0         0 push @tokens, token($token,'NAME',$token,'Name');
946             }
947             else
948             {
949 0 0       0 push @tokens, tokdup $connectives{lc $3} if $3;
950 0         0 push @tokens, token($1,'ACCUSATIVE',"\\&$2",'Literal');
951             }
952             }
953             elsif ($text =~ s/\A([.])//)
954             {
955 11         43 push @tokens, token($1,'PERIOD',";",'Separator');
956             }
957             elsif ($text =~ s/\A(\S+)(que|ve|)((?:\s+)sicut)?\b//)
958             {
959 2 50       9 if ($3)
960             {
961 0 0       0 my $token = $2 ? $1.$2 : $1;
962 0 0       0 push @tokens, token($token,'NAME',$token,'Name') if $token;
963             }
964             else
965             {
966 2 50       7 push @tokens, tokdup $connectives{lc $2} if $2;
967 2 50       13 push @tokens, token($1,'NAME',"$1",'Name') if $1;
968             }
969             }
970             else
971             {
972 3 50       24 $text =~ s/\A(\S+)// or next;
973 0         0 my $error = $1;
974 0         0 $bad .= "Aliquod barbarum inveni: '$error'"
975             . adversum({line=>$line});
976             }
977 122 50       1477 $tokens[-1]->{line} = $line if @tokens;
978             }
979 6 50 33     36 if (($lex ||$debug) && @tokens) {
      33        
980 0         0 my $format = "%-20s %-10s %-20s\n";
981 0         0 printf $format, qw(Word Role Meaning);
982 0         0 printf $format, qw(==== ==== =======);
983 0         0 foreach ( @tokens ) {
984 0         0 printf $format, @{$_}{qw(raw lex perl)};
  0         0  
985             }
986 0         0 print "\n", "="x72, "\n\n";
987 0 0       0 die "\n" if $lex;
988             }
989              
990 6 50       18 die $bad if $bad;
991 6         36 return [@tokens];
992             }
993              
994 3     3   29 use Carp;
  3         7  
  3         20412  
995              
996             sub conn_command {
997 21     21 0 56 my ($toks, $eatend, $noeatend) = @_;
998 21         55 my $command = &command;
999 21   66     86 while (@$toks && $toks->[0]{lex} eq 'CONNECTIVE') {
1000 0         0 local $Lingua::Romana::Perligata::connective = shift @$toks;
1001 0         0 $connective->{L} = $command;
1002 0         0 $connective->{R} = &command;
1003 0         0 $command = $connective;
1004             }
1005 21         63 return $command;
1006             }
1007              
1008              
1009             sub command {
1010 21     21 0 43 my ($toks, $eatend, $noeatend) = @_;
1011 21         62 my @Astack = { data => [], complete => 1 }; #SENTINEL ACCUSATIVE FRAME
1012 21         37 my (@Bstack, @Dstack, @Vstack, $Vdone);
1013 21         35 my $Dindir = 0;
1014 21         27 my @lastsubstantive;
1015 21         37 my $empty = 1;
1016              
1017 21         30 my $reduce;
1018             my $Astack_push = sub {
1019 39 100   39   83 if ($Astack[-1]{complete}) {
1020 16 50       36 $reduce->($_[0]) if @Astack > 1;
1021 16         48 push @Astack, { data => [ $_[0] ] };
1022             }
1023             else {
1024 23         33 push @{$Astack[-1]{data}}, $_[0];
  23         55  
1025             }
1026 39         71 $Astack[-1]{complete} = 1;
1027 21         91 };
1028              
1029             $reduce = sub {
1030 57     57   100 my ($lookahead) = @_;
1031 57 100       119 if (! @Vstack) {
1032 30 50 100     98 if (@Dstack && ($Dstack[-1]{V}{lex}||"") eq 'OWNER_D') {
      66        
1033 0         0 $Vdone = pop @Dstack;
1034 0         0 return 1
1035             }
1036 30         69 return 0;
1037             }
1038 27 100 100     221 return 0 if $Vstack[-1]{lex} =~ /^SUBNAME_?A?D?$/ && $lookahead->{lex} !~ /PERIOD|DO|END|CONNECTIVE/
      66        
1039             || ref $Vstack[-1] eq "STATEMENT";
1040 17         32 my $verb = $Vstack[-1];
1041 17         81 my ($needA, $needD) = $verb->{lex} =~ /_(O?A?)([BD])?/;
1042 17 100 100     67 $needA ||= $verb->{lex} eq 'SUBNAME' ? "OA" : "";
1043 17   100     53 $needD ||= "";
1044             return 0 if $needA && $needA ne "OA" && (@Astack<=1 || !$Astack[-1]{complete})
1045 17 100 100     157 || $needD eq 'D' && !@Dstack
      33        
      66        
      100        
      66        
      33        
      66        
1046             || $needD eq 'B' && !@Bstack;
1047 16 50       45 my $dat = $needD eq 'D' ? pop(@Dstack)
    100          
1048             : $needD eq 'B' ? pop(@Bstack)
1049             : undef;
1050 16 100 66     59 my $acc = $needA && @Astack>1 ? pop(@Astack)->{data} : undef;
1051 16         65 my $statement = bless { V=>pop(@Vstack), A=>$acc, D=>$dat }, "STATEMENT";
1052 16 100 33     144 if ($verb->{lex} =~ /SUBNAME_.*_ACCUSATIVE/
    100 66        
    50          
1053             || $Dindir && $verb->{lex} =~ /SUBNAME_.*_DATIVE|OWNER_D/ )
1054             {
1055 4 50       23 if ($verb->{lex} =~ /SUBNAME_.*_DATIVE|OWNER_D/) {
1056 0         0 $statement->{R} = $Dindir;
1057 0         0 $Dindir = 0;
1058             }
1059 4         11 $Astack_push->($statement);
1060 4         7 push @lastsubstantive, $Astack[-1]{data};
1061             }
1062             elsif ($verb->{lex} =~ /SUBNAME_.*_DATIVE|OWNER_D/ ) {
1063 3         9 push @Dstack, $statement;
1064 3         8 push @lastsubstantive, \@Dstack;
1065             }
1066             elsif ($verb->{lex} =~ /SUBNAME_.*_GENITIVE/ ) {
1067 0         0 my $lastsubstantive = pop @lastsubstantive;
1068 0 0       0 die "Genitivum non junctum: '$ord->{raw}'"
1069             . adversum($verb)
1070             unless $lastsubstantive;
1071 0         0 $ord = $lastsubstantive[-1][-1];
1072             die "Index '$ord->{raw}' ordinalis non est"
1073             . adversum($ord)
1074 0 0 0     0 if $ord->{lex} && $ord->{lex} eq 'NUMERAL';
1075 0         0 push @{$ord->{G}}, $statement;
  0         0  
1076 0         0 push @lastsubstantive, $Astack[-1]{data};
1077             }
1078 9         16 else { $Vdone = $statement }
1079 16 50       36 if ($debug) {
1080 0         0 print "reduced: ", Data::Dumper->Dump([$statement]);
1081             }
1082 16         67 return 1;
1083 21         89 };
1084              
1085 21         32 my $tok;
1086 21         58 while ( $tok = $toks->[0] ) {
1087 106 50       181 if ($debug) {
1088 0         0 print "Next: '$toks->[0]{raw}' ($toks->[0]{lex}):\n";
1089             }
1090 106 100 33     1083 if ($tok->{lex} =~ /^(NUMERAL|ORDINAL)$/
    50 66        
    50 33        
    100 66        
    50 33        
    50 0        
    100          
    100          
    100          
    100          
    50          
    100          
    100          
    50          
    100          
    100          
    100          
    50          
    50          
    0          
1091             || $Dindir && $tok->{lex} eq 'ORDINAL_DATIVE')
1092 11         22 { shift @$toks;
1093 11 50 66     58 if ($1 eq 'NUMERAL' && $toks->[0]{lex} eq 'ORDINAL') {
1094 0         0 $tok->{raw} .= " " . $toks->[0]{raw};
1095 0         0 $tok->{perl} /= $toks->[0]{perl};
1096 0         0 shift @$toks;
1097             }
1098 11 50       58 if ($tok->{lex} eq 'ORDINAL_DATIVE') {
1099 0         0 $tok->{R} = $Dindir;
1100 0         0 $Dindir = 0;
1101             }
1102 11         32 $Astack_push->($tok);
1103 11         17 $lastownable = $Astack[-1]{data};
1104 11         23 push @lastsubstantive, $lastownable;
1105             }
1106             elsif ($tok->{lex} eq 'ORDINAL_DATIVE')
1107 0         0 { shift @$toks;
1108 0         0 $reduce->($tok);
1109 0         0 push @Dstack, $tok;
1110 0         0 $lastownable = \@Dstack;
1111 0         0 push @lastsubstantive, $lastownable;
1112             }
1113             elsif ($tok->{lex} eq 'WITH') {
1114 0         0 push @Astack, { data=>[], complete=>0 };
1115 0         0 shift @$toks;
1116             }
1117             elsif ($tok->{lex} =~ /^(?:ACCUSATIVE|NAME)$/
1118             || $Dindir && $tok->{lex} eq 'DATIVE')
1119 24 50       54 { if ($tok->{lex} eq 'DATIVE') {
1120 0         0 $tok->{R} = $Dindir;
1121 0         0 $Dindir = 0;
1122             }
1123 24         56 $Astack_push->($tok);
1124 24         36 shift @$toks;
1125 24         40 $lastownable = $Astack[-1]{data};
1126 24         46 push @lastsubstantive, $lastownable;
1127             }
1128             elsif ( $tok->{lex} eq 'ARROW' ) {
1129 0         0 my $owner = $toks->[1];
1130             my $perl = $owner->{perl} =~ /^\W/
1131             ? $owner->{perl}
1132 0 0       0 : "$owner->{raw}::";
1133             $lastownable->[-1]->{perl}
1134 0         0 =~ s{^}{$perl->};
1135 0         0 splice @$toks, 0, 2;
1136             }
1137             elsif ( $tok->{lex} eq 'WITHIN' ) {
1138 0         0 my $owner = $toks->[1];
1139             $lastownable->[-1]->{raw}
1140 0         0 =~ s{^(\W*)}{$1$owner->{raw}::};
1141             $lastownable->[-1]->{perl}
1142 0         0 =~ s{^(\W*)}{$1$owner->{raw}::};
1143 0         0 splice @$toks, 0, 2;
1144             }
1145             elsif ( $tok->{lex} eq 'GENITIVE' ) {
1146 3         9 $reduce->($tok);
1147 3         8 my $gen = shift @$toks;
1148 3 50       9 die "Genitivum indominum: '$ord->{raw}'"
1149             . adversum($gen)
1150             unless @lastsubstantive;
1151 3         11 $ord = $lastsubstantive[-1][-1];
1152             die "Index '$ord->{raw}' ordinalis non est"
1153             . adversum($ord)
1154 3 50 33     28 if $ord->{lex} && $ord->{lex} eq 'NUMERAL';
1155 3         7 push @{$ord->{G}}, $gen;
  3         13  
1156 3         7 $lastownable = $ord->{G};
1157             }
1158             elsif ( $tok->{lex} eq 'INFINITIVE' )
1159 2         8 { $reduce->($tok); $Vdone = subdefn($toks); last }
  2         10  
  2         5  
1160             elsif ( $tok->{lex} eq 'CONTROL' )
1161 2         7 { $reduce->($tok); $Vdone = control($toks, \@Bstack); last }
  2         8  
  2         32  
1162             elsif ( $tok->{lex} eq 'FOR' )
1163 2         8 { $reduce->($tok); $Vdone = for_control($toks, \@Bstack); last }
  2         10  
  2         4  
1164             elsif ( $tok->{lex} eq 'BEGIN' )
1165 0         0 { push @Bstack, block($toks) }
1166             elsif ( $tok->{lex} eq 'OWNER_D' )
1167 1         4 { $reduce->($tok); push @Vstack, $tok; shift @$toks; }
  1         2  
  1         2  
1168             elsif ( $tok->{lex} eq 'COMMA' )
1169             { $reduce->($tok)
1170             unless $lastownable && @Astack>1 &&
1171 23 100 66     119 $lastownable == $Astack[-1]{data};
      100        
1172             die "'$tok->{raw}' immaturum est " . adversum($tok)
1173 23 50 33     83 unless @Astack>1 && $Astack[-1]{complete};
1174 23         40 $Astack[-1]{complete} = 0;
1175 23         37 shift @$toks;
1176             }
1177             elsif ( $tok->{lex} eq 'ADDRESS' )
1178 0         0 { $reduce->($tok);
1179 0         0 $Dindir++;
1180 0         0 shift @$toks;
1181             }
1182             elsif ( $tok->{lex} eq 'DATIVE' )
1183 8         24 { $reduce->($tok); push @Dstack, $tok; shift @$toks;
  8         17  
  8         15  
1184 8         12 $lastownable = \@Dstack;
1185 8         18 push @lastsubstantive, $lastownable;
1186             }
1187             elsif ( $tok->{lex} =~ /^SUBNAME/ ) # WAS: /SUBNAME_
1188 15 50       36 { if ($Astack[-1]{complete}) {
    0          
1189 15         31 $reduce->($tok)
1190             }
1191             elsif ($tok->{perl} !~ /^(and|or|[&|]{2})$/) {
1192 0         0 push @Astack, { data=>[] };
1193             }
1194 15         28 push @Vstack, $tok; shift @$toks;
  15         25  
1195 15         49 $lastownable = \@Vstack;
1196             }
1197             # elsif ( $tok->{lex} =~ /^SUBNAME$/ )
1198             # { if ($Astack[-1]{complete}) {
1199             # $reduce->($tok)
1200             # }
1201             # elsif ($tok->{perl} !~ /^[&|]{2}$/ {
1202             # push @Astack, { data=>[] };
1203             # }
1204             # push @Vstack, $tok; shift @$toks;
1205             # $lastownable = \@Vstack;
1206             # }
1207             elsif ( $tok->{lex} =~ /PERIOD/ )
1208 11   100     29 { 1 while $reduce->($tok) && !$Vdone;
1209             $Vdone = pop(@Astack)->{data}
1210 11 50 0     34 if $Lingua::Romana::Perligata::connective
      33        
1211             && !($Vdone || @Astack <= 1);
1212 11         20 shift @$toks;
1213             last
1214 11         20 }
1215             elsif ( $tok->{lex} =~ /CONNECTIVE/ )
1216 0   0     0 { 1 while $reduce->($tok) && !$Vdone;
1217             $Vdone = pop(@Astack)->{data}
1218 0 0 0     0 unless $Vdone || @Astack <= 1;
1219 0         0 last }
1220             elsif ( $eatend && $tok->{lex} =~ /$eatend/ )
1221 4         14 { 1 while $reduce->($tok);
1222             $Vdone or $Vdone = @Astack > 1
1223             ? pop(@Astack)->{data}
1224 4 100       17 : pop @Dstack;
    50          
1225 4         10 shift @$toks; last }
  4         10  
1226             elsif ( $noeatend && $tok->{lex} =~ /$noeatend/ )
1227 0         0 { 1 while $reduce->($tok);
1228             $Vdone or $Vdone = pop(@Astack)->{data}
1229 0 0 0     0 || pop @Dstack;
1230 0         0 last }
1231             else {
1232 0         0 die "Non intellexi: '$tok->{raw}'" . adversum($tok);
1233             }
1234             }
1235             continue {
1236 85         117 $empty = 0;
1237 85 50       258 if ($debug) {
1238 0         0 print "After '$tok->{raw}' ($tok->{lex}):\n";
1239 0         0 print Data::Dumper->Dump([\@Vstack, \@Astack, \@Bstack, \@Dstack, \@lastsubstantive, \$lastownable, \$Vdone], [qw{Vstack Astack Bstack Dstack LastS LastO Vdone}]);
1240             }
1241             }
1242             die "Iussum nefastum: '$Vstack[-1]{raw}'" . adversum($Vstack[-1])
1243 21 0 66     72 . ( $Vstack[-1]{lex} !~ /(ACCUSATIVE|DATIVE)$/
    50          
1244             ? "(Vellesne '$Vstack[-1]{raw}mentum' unumve ceteri)\n"
1245             : "" )
1246             if $Vdone && @Vstack;
1247             die "Accusativum non junctum: '"
1248 0         0 . join(" tum ", map {$_->{raw}} @{$Astack[-1]{data}})
  0         0  
1249             . "'"
1250 21 50 33     56 . adversum($Astack[-1]{data}[0])
1251             if @Astack > 1 && !@Vstack;
1252 21 50 33     48 die "Dativum non junctum: '$Dstack[-1]{raw}'" . adversum($Dstack[-1])
1253             if @Dstack && !@Vstack;
1254 21 50 66     54 die "Sententia imperfecta prope '$tok->{raw}'" . adversum($tok)
1255             unless $Vdone || $empty;
1256 21 100       119 return $empty ? $tok
    100          
1257             : ref $Vdone eq 'ARRAY' ? $Vdone->[0]
1258             : $Vdone;
1259             }
1260              
1261             sub block
1262             {
1263 6     6 0 14 my ($toks) = @_;
1264 6         11 my @self;
1265 6         10 my $next = shift @$toks;
1266             die "Exspectavi 'sic' sed inveni '$next->{raw}'" . adversum($next)
1267 6 50       21 unless $next->{lex} eq 'BEGIN';
1268 6         20 while ($toks->[0]{lex} ne 'END') {
1269 6         16 my $command = conn_command($_[0],'PERIOD','END');
1270 6 50       32 push @self, $command if $command;
1271             }
1272 6         27 $next = shift @$toks;
1273             die "Exspectavi 'cis' sed inveni '$next->{raw}'" . adversum($next)
1274 6 50       18 unless $next->{lex} eq 'END';
1275 6         35 return bless \@self, 'BLOCK';
1276             }
1277              
1278             sub subdefn
1279             {
1280 2     2 0 5 my ($toks) = @_;
1281 2         4 my $self = shift @$toks;
1282 2         6 $self->{B} = block($toks);
1283 2         5 return $self;
1284             }
1285              
1286             sub for_control
1287             {
1288 2     2 0 6 my ($toks, $Bstack) = @_;
1289 2         5 my $self = shift @$toks;
1290 2         4 my $var;
1291             $var = $toks->[0]{lex} eq 'ACCUSATIVE'
1292             ? shift @$toks
1293             : $toks->[0]{lex} ne 'IN'
1294             ? die "Exspectavi accusativum post 'per' sed inveni '$toks->[0]{raw}'" . adversum($toks->[0])
1295 2 0       10 : tokdup $tokens{'huic'};
    50          
1296 2         5 my $in = shift @$toks;
1297             die "'in' pro 'per' afuit" . adversum($in)
1298 2 50       8 unless $in->{lex} eq 'IN';
1299 2         7 $self->{D} = $var;
1300 2         9 $self->{C} = conn_command($toks,'DO', 'PERIOD');
1301 2 50 33     21 unless (($self->{C}{lex}||$self->{C}{V}{lex}) =~ /DATIVE|OWNER_D/) {
1302             my ($badraw, $bad) = $self->{C}{lex}
1303             ? ($self->{C}{raw}, $self->{C})
1304 0 0       0 : ($self->{C}{V}{raw}, $self->{C}{V});
1305 0         0 die "'$badraw' dativus non est in 'per'" . adversum($bad);
1306             }
1307 2 50       7 if ($toks->[0]{lex} =~ /PERIOD|CONNECTIVE/) {
1308 0 0       0 die "Iussa absentia per '$self->{raw}'" . adversum($self)
1309             unless @$Bstack;
1310 0         0 $self->{B} = pop @$Bstack;
1311 0 0       0 shift @$toks unless $toks->[0]{lex} eq 'CONNECTIVE';
1312             }
1313             else {
1314 2         8 $self->{B} = block($toks);
1315             }
1316 2         12 return $self;
1317             }
1318              
1319             sub control
1320             {
1321 2     2 1 7 my ($toks, $Bstack) = @_;
1322 2         4 my $self = shift @$toks;
1323 2         6 $self->{C} = conn_command($toks,'DO');
1324 2 50 50     17 if (($self->{perl}||"") eq 'while' &&
      0        
      33        
1325             ($self->{C}{V}{perl}||"") eq 'Lingua::Romana::Perligata::getline') {
1326 0         0 $self->{C}{V}{diamond} = 1;
1327             }
1328 2 50 33     21 if (!@$toks || $toks->[0]{lex} =~ /PERIOD|CONNECTIVE/) {
1329 0 0       0 die "Iussa absentia per '$self->{raw}'" . adversum($self)
1330             unless @$Bstack;
1331 0         0 $self->{B} = pop @$Bstack;
1332 0 0       0 shift @$toks unless $toks->[0]{lex} eq 'CONNECTIVE';
1333             }
1334             else {
1335 2         5 $self->{B} = block($toks);
1336             }
1337 2         5 return $self;
1338             }
1339              
1340              
1341             sub __enlist__ {
1342 2     2   36 return ($_[0]..$_[1]);
1343             }
1344              
1345             sub __enquote__ {
1346 0     0   0 return join " ", @_;
1347             }
1348              
1349             sub __encatenate__ {
1350 1     1   40 return join "", @_;
1351             }
1352              
1353             sub __lastelem__(\@) {
1354 0     0   0 return $#{$_[0]};
  0         0  
1355             }
1356              
1357             my %lb = ( '@'=>'[', '%'=>'{' );
1358             my %rb = ( '@'=>']', '%'=>'}' );
1359              
1360             sub STATEMENT::translate {
1361 16     16   41 my $verb = $_[0]{V}->translate;
1362 16         38 my $prefix = $_[0]{V}{prefix};
1363 16         43 my $hasblock = $verb =~ m{^(grep|map)$};
1364             my $noparen = $_[0]{V}{lex} eq 'OWNER_D' && $_[0]{V}{raw} =~ /o$/
1365 16   66     101 || $_[0]{V}{raw} =~ /^(finis|nuntius|factor(em|i))$/
1366             || $hasblock;
1367             my $dative = defined $_[0]{D}
1368             ? $_[0]{D}->translate
1369 16 100       56 : "";
1370 16 50 33     51 my $Dref = $verb =~ /^(bless)$/ && $dative =~ /^[%@]/ ? "\\" : "";
1371 16 100       39 $dative = $Dref . $dative if $dative;
1372 16 100 100     92 my $Dcomma = $dative && defined $_[0]{A} && !$hasblock && $verb !~ /^(print|printf)$/ ? "," : "";
1373 16 50 33     100 if ($verb =~ /^(package|use)$/) {
    50          
    50          
    50          
    100          
    50          
    50          
    100          
1374 0         0 return "$verb $_[0]{A}[0]{raw} ";
1375             }
1376             elsif ($verb eq ':') { # LABEL
1377 0         0 return " $_[0]{A}[0]{raw}: ";
1378             }
1379             elsif ($_[0]{V}{diamond}) {
1380 0         0 $result = "<" . substr($dative,1) . ">";
1381             }
1382             elsif ($verb =~ /^[\$%@]\{$/) {
1383 0         0 $result = $verb . $_[0]{A}[0]->translate . '}';
1384             }
1385             elsif (! $_[0]{V}{operator}) {
1386             $result = "$verb "
1387             . ($noparen ? "" : "(")
1388             . $dative . $Dcomma
1389             . " "
1390 12 100       54 . (defined $_[0]{A} ? join ", ", map({ $_->translate($_[0]{V}) } @{$_[0]{A}}) : "")
  31 100       75  
  10 100       28  
1391             . ($noparen ? "" : ")") ;
1392             }
1393             elsif ($prefix && $dative) {
1394 0         0 $result = " $verb $dative ";
1395             }
1396             elsif ($prefix) {
1397 0         0 $result = " $verb (" . $_[0]{A}[0]->translate . ")";
1398             }
1399             elsif ( $verb eq '=' ) {
1400             $result = " "
1401             . $dative
1402             . " $verb "
1403 2         8 . ( @{$_[0]{A}} > 1
1404 0         0 ? "(" . join(",", map($_->translate, @{$_[0]{A}})) . ")"
1405 2 50       9 : $_[0]{A}[0]->translate
1406             );
1407             }
1408             else
1409             {
1410 2 50       3 my $Acount = @{$_[0]{A}||[]};
  2         8  
1411 2 50       6 my $neg = $verb =~ s/^!(<=>|cmp)/$1/ ? "!" : "";
1412             $result = " $neg("
1413             . ( $dative ? $dative
1414 2         8 : $Acount-- ? shift(@{$_[0]{A}})->translate
1415             : "")
1416             . " $verb "
1417 2 50       7 . ( $Acount ? $_[0]{A}[0]->translate : "")
    50          
    50          
1418             . ")";
1419             }
1420 16 50       56 if ($_[0]->{G}) {
1421 0         0 my $perl = pop(@{$_[0]->{G}})->{perl}; # LAST GENITIVE IS THE VARIABLE
  0         0  
1422 0         0 $perl =~ s/^([\%\@])/\$/;
1423 0         0 my $type = $1;
1424 0         0 while (my $next = pop @{$_[0]->{G}}) {
  0         0  
1425 0         0 $perl .= $lb{$type} . $next->translate . $rb{$type};
1426             }
1427 0         0 $result = $perl . $lb{$type} . $result . $rb{$type};
1428             }
1429 16   50     99 return '\\'x($_[0]{R}||0) . $result;
1430             }
1431              
1432             sub BLOCK::translate {
1433             return "{"
1434 6     6   11 . join(";\n", map {$_->translate} @{$_[0]})
  6         14  
  6         25  
1435             . "}" ;
1436             }
1437              
1438             sub CONNECTIVE::translate {
1439 0     0   0 return $_[0]{L}->translate . " $_[0]{perl} " . $_[0]{R}->translate;
1440             }
1441              
1442             sub Separator::translate {
1443 2     2   7 return $_[0]{perl};
1444             }
1445              
1446             sub SUBNAME::translate {
1447 0     0   0 return $_[0]{perl};
1448             }
1449              
1450             sub SUBNAME_OA::translate {
1451 0     0   0 return $_[0]{perl};
1452             }
1453              
1454             sub SUBNAME_A::translate {
1455 0     0   0 return $_[0]{perl};
1456             }
1457              
1458             sub SUBNAME_D::translate {
1459 0     0   0 return $_[0]{perl};
1460             }
1461              
1462             sub SUBNAME_AD::translate {
1463 7     7   16 return $_[0]{perl};
1464             }
1465              
1466             sub SUBNAME_AB::translate {
1467 0     0   0 return $_[0]{perl};
1468             }
1469              
1470             sub SUBNAME_ACCUSATIVE::translate {
1471 0     0   0 return $_[0]{perl};
1472             }
1473              
1474             sub SUBNAME_A_ACCUSATIVE::translate {
1475 3     3   6 return $_[0]{perl};
1476             }
1477              
1478             sub SUBNAME_D_ACCUSATIVE::translate {
1479 1     1   4 return $_[0]{perl};
1480             }
1481              
1482             sub SUBNAME_AD_ACCUSATIVE::translate {
1483 0     0   0 return $_[0]{perl};
1484             }
1485              
1486             sub SUBNAME_AB_ACCUSATIVE::translate {
1487 0     0   0 return $_[0]{perl};
1488             }
1489              
1490             sub SUBNAME_B_ACCUSATIVE::translate {
1491 0     0   0 return $_[0]{perl};
1492             }
1493              
1494             sub SUBNAME_DATIVE::translate {
1495 0     0   0 return $_[0]{perl};
1496             }
1497              
1498             sub SUBNAME_A_DATIVE::translate {
1499 2     2   6 return $_[0]{perl};
1500             }
1501              
1502             sub SUBNAME_D_DATIVE::translate {
1503 0     0   0 return $_[0]{perl};
1504             }
1505              
1506             sub SUBNAME_AD_DATIVE::translate {
1507 0     0   0 return $_[0]{perl};
1508             }
1509              
1510             sub SUBNAME_AB_DATIVE::translate {
1511 0     0   0 return $_[0]{perl};
1512             }
1513              
1514             sub SUBNAME_B_DATIVE::translate {
1515 0     0   0 return $_[0]{perl};
1516             }
1517              
1518             sub DATIVE::translate {
1519 7     7   18 my ($self) = @_;
1520 7         15 my $perl = $self->{perl};
1521 7 50       19 if ($self->{G}) {
1522 0         0 my $gen = pop(@{$self->{G}})->{perl}; # LAST GENITIVE IS THE VARIABLE
  0         0  
1523 0         0 $gen =~ s/^([\%\@])/\$/;
1524 0         0 my $type = $1;
1525 0         0 while (my $next = pop @{$self->{G}}) {
  0         0  
1526 0         0 $gen .= $lb{$type} . $next->translate . $rb{$type};
1527             }
1528 0         0 $perl = $gen . $lb{$type} . $perl . $rb{$type};
1529             }
1530 7         13 return $perl;
1531             }
1532              
1533             sub OWNER_D::translate {
1534 1     1   2 return $_[0]{perl};
1535             }
1536              
1537             sub ACCUSATIVE::translate {
1538 16     16   31 my ($self) = @_;
1539 16         28 my $perl = $self->{perl};
1540 16 50       35 if ($self->{G}) {
1541 0         0 my $gen = pop(@{$self->{G}})->{perl}; # LAST GENITIVE IS THE VARIABLE
  0         0  
1542 0         0 $gen =~ s/^([\%\@])/\$/;
1543 0         0 my $type = $1;
1544 0         0 while (my $next = pop @{$self->{G}}) {
  0         0  
1545 0         0 $gen .= $lb{$type} . $next->translate . $rb{$type};
1546             }
1547 0         0 $perl = $gen . $lb{$type} . $perl . $rb{$type};
1548             }
1549 16   50     80 return '\\'x($_[0]{R}||0) . $perl;
1550             }
1551              
1552             sub CONTROL::translate {
1553             return $_[0]{perl}
1554             . " (" . $_[0]{C}->translate . ") "
1555             . $_[0]{B}->translate
1556 2     2   7 . "\n";
1557             }
1558              
1559             sub FOR::translate {
1560             return $_[0]{perl}
1561             . " " . $_[0]{D}->translate
1562             . " (" . $_[0]{C}->translate . ") "
1563             . $_[0]{B}->translate
1564 2     2   11 . "\n";
1565             }
1566              
1567             sub NUMERAL::translate {
1568 8     8   15 my ($self) = @_;
1569             # if ($self->{G}) {
1570             # return $self->{G}->index($self->{perl});
1571             # }
1572 8         29 return $self->{perl};
1573             }
1574              
1575             sub ORDINAL::translate {
1576 3     3   8 my ($self) = @_;
1577 3 50       9 return $self->{perl} unless $self->{G};
1578 3         7 my $perl = pop(@{$self->{G}})->translate; # LAST GENITIVE IS THE VARIABLE
  3         13  
1579 3         25 $perl =~ s/^([\%\@])/\$/;
1580 3         11 my $type = $1;
1581 3         6 while (my $next = pop @{$self->{G}}) {
  3         14  
1582 0         0 $perl .= $lb{$type} . $next->translate . $rb{$type};
1583             }
1584 3         16 return $perl . $lb{$type} . $self->{perl} . $rb{$type};
1585             }
1586              
1587             *ORDINAL_DATIVE::translate = *ORDINAL::translate;
1588              
1589             sub DISJUNCTION::translate {
1590 0     0   0 return $_[0]{perl};
1591             }
1592              
1593             sub CONJUNCTION::translate {
1594 0     0   0 return $_[0]{perl};
1595             }
1596              
1597             sub Literal::translate {
1598 10     10   20 my ($self, $context) = @_;
1599 10         19 my $perl;
1600 10 50 66     50 if ($context && $context->{raw} =~ /^inque/) {
    50          
    50          
    100          
1601 0         0 $perl = qq{'$_[0]{raw}'}
1602             }
1603             elsif ( $self->{lex} eq 'GENITIVE' ) {
1604 0         0 $perl = $self->GENITIVE::translate;
1605             }
1606             elsif ( $self->{lex} eq 'SUBNAME_A_GENITIVE' ) {
1607 0         0 $perl = $self->SUBNAME_A_GENITIVE::translate;
1608             }
1609             elsif ( $self->{lex} eq 'INFINITIVE' ) {
1610 2         9 $perl = "sub $_[0]{perl}\n" . $_[0]{B}->translate;
1611             }
1612             else {
1613             $perl = '\\'x($_[0]{R}||0) . $_[0]{perl}
1614 8   50     39 }
1615 10 50       25 if ($self->{G}) {
1616 0         0 my $gen = pop(@{$self->{G}})->{perl}; # LAST GENITIVE IS THE VARIABLE
  0         0  
1617 0         0 $gen =~ s/^([\%\@])/\$/;
1618 0         0 my $type = $1;
1619 0         0 while (my $next = pop @{$self->{G}}) {
  0         0  
1620 0         0 $gen .= $lb{$type} . $next->translate . $rb{$type};
1621             }
1622 0         0 $perl = $gen . $lb{$type} . $perl . $rb{$type};
1623             }
1624 10         36 return $perl;
1625             }
1626              
1627             sub GENITIVE::translate {
1628 3     3   8 return $_[0]{perl};
1629             };
1630              
1631             sub SUBNAME_A_GENITIVE::translate {
1632 0     0   0 return $_[0]{perl};
1633             };
1634              
1635             sub Name::translate {
1636 5     5   15 return qq{'$_[0]{raw}'}
1637             }
1638              
1639             1;
1640              
1641             __END__