Parent Directory
|
Revision Log
removed unneccesary shebang lines
1 2 3 ## Last modification: 8/3/00 by akp 4 ## Originally written by Daniel Martin, Dept of Math, John Hopkins 5 ## Additions and modifications were made by James Martino, Dept of Math, John Hopkins 6 ## Additions and modifications were made by Arnold Pizer, Dept of Math, Univ of Rochester 7 8 #use Data::Dumper; 9 10 package AlgParser; 11 use HTML::Entities; 12 13 %close = (); 14 15 sub new { 16 my $package = shift; 17 my (%ret); 18 $ret{string} = ""; 19 $ret{posarray} = []; 20 $ret{parseerror} = ""; 21 $ret{parseresult} = []; 22 bless \%ret, $package; 23 return \%ret; 24 } 25 26 sub inittokenizer { 27 my($self, $string) = @_; 28 $self->{string} =~ m/\G.*$/g; 29 $self->{string} = undef; 30 $self->{string} = $string; 31 $self->{string} =~ m/\G.*$/g; 32 $self->{string} =~ m/^/g; 33 } 34 35 $close{'{'} = '}'; 36 $close{'['} = ']'; 37 $close{'('} = ')'; 38 39 $binoper3 = '(?:\\^|\\*\\*)'; 40 $binoper2 = '[/*]'; 41 $binoper1 = '[-+]'; 42 $openparen = '[{(\\[]'; 43 $closeparen = '[})\\]]'; 44 $varname = '[A-Za-z](?:_[0-9]+)?'; 45 $specialvalue = '(?:e|pi)'; 46 $numberplain = '(?:\d+(?:\.\d*)?|\.\d+)'; 47 $numberE = '(?:' . $numberplain . 'E[-+]?\d+)'; 48 $number = '(?:' . $numberE . '|' . $numberplain . ')'; 49 $trigfname = '(?:cosh|sinh|tanh|cot|(?:a(?:rc)?)?cos|(?:a(?:rc)?)?sin|' . 50 '(?:a(?:rc)?)?tan|sech?)'; 51 $otherfunc = '(?:exp|abs|logten|log|ln|sqrt|sgn|step|fact)'; 52 $funcname = '(?:' . $otherfunc . '|' . $trigfname . ')'; 53 54 $tokenregexp = "(?:($binoper3)|($binoper2)|($binoper1)|($openparen)|" . 55 "($closeparen)|($funcname)|($specialvalue)|($varname)|" . 56 "($numberE)|($number))"; 57 58 sub nexttoken { 59 my($self) = shift; 60 $self->{string} =~ m/\G\s+/gc; 61 my($p1) = pos($self->{string}) || 0; 62 if(scalar($self->{string} =~ m/\G$tokenregexp/gc)) { 63 push @{$self->{posarray}}, [$p1, pos($self->{string})]; 64 if (defined($1)) {return ['binop3', $1];} 65 if (defined($2)) {return ['binop2', $2];} 66 if (defined($3)) {return ['binop1', $3];} 67 if (defined($4)) {return ['openp', $4];} 68 if (defined($5)) {return ['closep', $5];} 69 if (defined($6)) {return ['func1', $6];} 70 if (defined($7)) {return ['special', $7];} 71 if (defined($8)) {return ['varname', $8];} 72 if (defined($9)) {return ['numberE', $9];} 73 if (defined($10)) {return ['number', $10];} 74 } 75 else { 76 push @{$self->{posarray}}, [$p1, undef]; 77 return undef; 78 } 79 } 80 81 sub parse { 82 my $self = shift; 83 $self->{parseerror} = ""; 84 $self->{posarray} = []; 85 $self->{parseresult} = ['top', undef]; 86 my (@backtrace) = (\$self->{parseresult}); 87 my (@pushback) = (); 88 89 my $currentref = \$self->{parseresult}->[1]; 90 my $curenttok; 91 92 my $sstring = shift; 93 $self->inittokenizer($sstring); 94 $currenttok = $self->nexttoken; 95 if (!$currenttok) { 96 if ($self->{string} =~ m/\G$/g) { 97 return $self->error("empty"); 98 } else { 99 my($mark) = pop @{$self->{posarray}}; 100 my $position = 1+$mark->[0]; 101 return $self->error("Illegal character at position $position", $mark); 102 } 103 } 104 # so I can assume we got a token 105 local $_; 106 while ($currenttok) { 107 $_ = $currenttok->[0]; 108 /binop1/ && do { 109 # check if we have a binary or unary operation here. 110 if (defined(${$currentref})) { 111 # binary - walk up the tree until we hit an open paren or the top 112 while (${$currentref}->[0] !~ /^(openp|top)/) { 113 $currentref = pop @backtrace; 114 } 115 my $index = ((${$currentref}->[0] eq 'top')?1:3); 116 ${$currentref}->[$index] = ['binop1', $currenttok->[1], 117 ${$currentref}->[$index], undef]; 118 push @backtrace, $currentref; 119 push @backtrace, \${$currentref}->[$index]; 120 $currentref = \${$currentref}->[$index]->[3]; 121 } else { 122 # unary 123 ${$currentref} = ['unop1', $currenttok->[1], undef]; 124 push @backtrace, $currentref; 125 $currentref = \${$currentref}->[2]; 126 } 127 }; 128 /binop2/ && do { 129 if (defined(${$currentref})) { 130 # walk up the tree until an open paren, the top, binop1 or unop1 131 # I decide arbitrarily that -3*4 should be parsed as -(3*4) 132 # instead of as (-3)*4. Not that it makes a difference. 133 134 while (${$currentref}->[0] !~ /^(openp|top|binop1)/) { 135 $currentref = pop @backtrace; 136 } 137 my $a = ${$currentref}->[0]; 138 my $index = (($a eq 'top')?1:3); 139 ${$currentref}->[$index] = ['binop2', $currenttok->[1], 140 ${$currentref}->[$index], undef]; 141 push @backtrace, $currentref; 142 push @backtrace, \${$currentref}->[$index]; 143 $currentref = \${$currentref}->[$index]->[3]; 144 } else { 145 # Error 146 my($mark) = pop @{$self->{posarray}}; 147 my $position =1+$mark->[0]; 148 return $self->error("Didn't expect " . $currenttok->[1] . 149 " at position $position" , $mark); 150 } 151 }; 152 /binop3/ && do { 153 if (defined(${$currentref})) { 154 # walk up the tree until we need to stop 155 # Note that the right-associated nature of ^ means we need to 156 # stop walking backwards when we hit a ^ as well. 157 while (${$currentref}->[0] !~ /^(openp|top|binop[123]|unop1)/) { 158 $currentref = pop @backtrace; 159 } 160 my $a = ${$currentref}->[0]; 161 my $index = ($a eq 'top')?1:($a eq 'unop1')?2:3; 162 ${$currentref}->[$index] = ['binop3', $currenttok->[1], 163 ${$currentref}->[$index], undef]; 164 push @backtrace, $currentref; 165 push @backtrace, \${$currentref}->[$index]; 166 $currentref = \${$currentref}->[$index]->[3]; 167 } else { 168 # Error 169 my($mark) = pop @{$self->{posarray}}; 170 my $position = 1+$mark->[0]; 171 return $self->error("Didn't expect " . $currenttok->[1] . 172 " at position $position", $mark); 173 } 174 }; 175 /openp/ && do { 176 if (defined(${$currentref})) { 177 # we weren't expecting this - must be implicit 178 # multiplication. 179 push @pushback, $currenttok; 180 $currenttok = ['binop2', 'implicit']; 181 next; 182 } else { 183 my($me) = pop @{$self->{posarray}}; 184 ${$currentref} = [$currenttok->[0], $currenttok->[1], $me, undef]; 185 push @backtrace, $currentref; 186 $currentref = \${$currentref}->[3]; 187 } 188 }; 189 /func1/ && do { 190 if (defined(${$currentref})) { 191 # we weren't expecting this - must be implicit 192 # multiplication. 193 push @pushback, $currenttok; 194 $currenttok = ['binop2', 'implicit']; 195 next; 196 } else { 197 # just like a unary operator 198 ${$currentref} = [$currenttok->[0], $currenttok->[1], undef]; 199 push @backtrace, $currentref; 200 $currentref = \${$currentref}->[2]; 201 } 202 }; 203 /closep/ && do { 204 if (defined(${$currentref})) { 205 # walk up the tree until we need to stop 206 while (${$currentref}->[0] !~ /^(openp|top)/) { 207 $currentref = pop @backtrace; 208 } 209 my $a = ${$currentref}->[0]; 210 if ($a eq 'top') { 211 my($mark) = pop @{$self->{posarray}}; 212 my $position = 1+$mark->[0]; 213 return $self->error("Unmatched close " . $currenttok->[1] . 214 " at position $position", $mark); 215 } elsif ($close{${$currentref}->[1]} ne $currenttok->[1]) { 216 my($mark) = pop @{$self->{posarray}}; 217 my $position = 1+$mark->[0]; 218 return $self->error("Mismatched parens at position $position" 219 , ${$currentref}->[2], $mark); 220 } else { 221 ${$currentref}->[0] = 'closep'; 222 ${$currentref}->[2] = pop @{${$currentref}}; 223 } 224 } else { 225 # Error - something like (3+4*) 226 my($mark) = pop @{$self->{posarray}}; 227 my $position = 1+$mark->[0]; 228 return $self->error("Premature close " . $currenttok->[1] . 229 " at position $position", $mark); 230 } 231 }; 232 /special|varname|numberE?/ && do { 233 if (defined(${$currentref})) { 234 # we weren't expecting this - must be implicit 235 # multiplication. 236 push @pushback, $currenttok; 237 $currenttok = ['binop2', 'implicit']; 238 next; 239 } else { 240 ${$currentref} = [$currenttok->[0], $currenttok->[1]]; 241 } 242 }; 243 if (@pushback) { 244 $currenttok = pop @pushback; 245 } else { 246 $currenttok = $self->nexttoken; 247 } 248 } 249 # ok, we stopped parsing. Now we need to see why. 250 if ($self->{parseresult}->[0] eq 'top') { 251 $self->{parseresult} = $self->arraytoexpr($self->{parseresult}->[1]); 252 } else { 253 return $self->error("Internal consistency error; not at top when done"); 254 } 255 if ($self->{string} =~ m/\G\s*$/g) { 256 if (!defined(${$currentref})) { 257 $self->{string} .= " "; 258 return $self->error("I was expecting more at the end of the line", 259 [length($self->{string})-1, length($self->{string})]); 260 } else { 261 # check that all the parens were closed 262 while (@backtrace) { 263 $currentref = pop @backtrace; 264 if (${$currentref}->[0] eq 'openp') { 265 my($mark) = ${$currentref}->[2]; 266 my $position = 1+$mark->[0]; 267 return $self->error("Unclosed parentheses beginning at position $position" 268 , $mark); 269 } 270 } 271 # Ok, we must really have parsed something 272 return $self->{parseresult}; 273 } 274 } else { 275 my($mark) = pop @{$self->{posarray}}; 276 my $position = 1+$mark->[0]; 277 return $self->error("Illegal character at position $position",$mark); 278 } 279 } 280 281 sub arraytoexpr { 282 my ($self) = shift; 283 return Expr->fromarray(@_); 284 } 285 286 sub error { 287 my($self, $errstr, @markers) = @_; 288 # print STDERR Data::Dumper->Dump([\@markers], 289 # ['$markers']); 290 $self->{parseerror} = $errstr; 291 my($htmledstring) = '<tt class="parseinput">'; 292 my($str) = $self->{string}; 293 # print STDERR Data::Dumper->Dump([$str], ['$str']); 294 my($lastpos) = 0; 295 $str =~ s/ /\240/g; 296 while(@markers) { 297 my($ref) = shift @markers; 298 my($pos1) = $ref->[0]; 299 my($pos2) = $ref->[1]; 300 if (!defined($pos2)) {$pos2 = $pos1+1;} 301 $htmledstring .= encode_entities(substr($str,$lastpos,$pos1-$lastpos)) . 302 '<b class="parsehilight">' . 303 encode_entities(substr($str,$pos1,$pos2-$pos1)) . 304 '</b>'; 305 $lastpos = $pos2; 306 } 307 # print STDERR Data::Dumper->Dump([$str, $htmledstring, $lastpos], 308 # ['$str', '$htmledstring', '$lastpos']); 309 $htmledstring .= encode_entities(substr($str,$lastpos)); 310 $htmledstring .= '</tt>'; 311 # $self->{htmlerror} = '<p class="parseerr">' . "\n" . 312 # '<span class="parsedesc">' . 313 # encode_entities($errstr) . '</span><br>' . "\n" . 314 # $htmledstring . "\n" . '</p>' . "\n"; 315 $self->{htmlerror} = $htmledstring ; 316 $self->{htmlerror} = 'empty' if $errstr eq 'empty'; 317 $self->{error_msg} = $errstr; 318 319 # warn $errstr . "\n"; 320 return undef; 321 } 322 323 sub tostring { 324 my ($self) = shift; 325 return $self->{parseresult}->tostring(@_); 326 } 327 328 sub tolatex { 329 my ($self) = shift; 330 return $self->{parseresult}->tolatex(@_); 331 } 332 333 sub tolatexstring { return tolatex(@_);} 334 335 sub exprtolatexstr { 336 return exprtolatex(@_); 337 } 338 339 sub exprtolatex { 340 my($expr) = shift; 341 my($exprobj); 342 if ((ref $expr) eq 'ARRAY') { 343 $exprobj = Expr->new(@$expr); 344 } else { 345 $exprobj = $expr; 346 } 347 return $exprobj->tolatex(); 348 } 349 350 sub exprtostr { 351 my($expr) = shift; 352 my($exprobj); 353 if ((ref $expr) eq 'ARRAY') { 354 $exprobj = Expr->new(@$expr); 355 } else { 356 $exprobj = $expr; 357 } 358 return $exprobj->tostring(); 359 } 360 361 sub normalize { 362 my ($self, $degree) = @_; 363 $self->{parseresult} = $self->{parseresult}->normalize($degree); 364 } 365 366 sub normalize_expr { 367 my($expr, $degree) = @_; 368 my($exprobj); 369 if ((ref $expr) eq 'ARRAY') { 370 $exprobj = Expr->new(@$expr); 371 } else { 372 $exprobj = $expr; 373 } 374 return $exprobj->normalize($degree); 375 } 376 377 package AlgParserWithImplicitExpand; 378 @ISA=qw(AlgParser); 379 380 sub arraytoexpr { 381 my ($self) = shift; 382 my ($foo) = ExprWithImplicitExpand->fromarray(@_); 383 # print STDERR Data::Dumper->Dump([$foo],['retval']); 384 return $foo; 385 } 386 387 package Expr; 388 389 sub new { 390 my($class) = shift; 391 my(@args) = @_; 392 my($ret) = [@args]; 393 return (bless $ret, $class); 394 } 395 396 sub head { 397 my($self) = shift; 398 return ($self->[0]); 399 } 400 401 402 sub normalize { 403 #print STDERR "normalize\n"; 404 #print STDERR Data::Dumper->Dump([@_]); 405 406 my($self, $degree) = @_; 407 my($class) = ref $self; 408 $degree = $degree || 0; 409 my($type, @args) = @$self; 410 local $_; 411 $_ = $type; 412 my ($ret) = [$type, @args]; 413 414 415 if(/closep/) { 416 $ret = $args[1]->normalize($degree); 417 } elsif (/unop1/) { 418 $ret = $class->new($type, $args[0], $args[1]->normalize($degree)); 419 } elsif (/binop/) { 420 $ret = $class->new($type, $args[0], $args[1]->normalize($degree), 421 $args[2]->normalize($degree)); 422 } elsif (/func1/) { 423 $args[0] =~ s/^arc/a/; 424 $ret = $class->new($type, $args[0], $args[1]->normalize($degree)); 425 } 426 427 428 if ($degree < 0) {return $ret;} 429 430 431 ($type, @args) = @$ret; 432 $ret = $class->new($type, @args); 433 $_ = $type; 434 if (/binop1/ && ($args[2]->[0] =~ 'unop1')) { 435 my($h1, $h2) = ($args[0], $args[2]->[1]); 436 my($s1, $s2) = ($h1 eq '-', $h2 eq '-'); 437 my($eventual) = ($s1==$s2); 438 if ($eventual) { 439 $ret = $class->new('binop1', '+', $args[1], $args[2]->[2] ); 440 } else { 441 $ret = $class->new('binop1', '-', $args[1], $args[2]->[2] ); 442 } 443 } elsif (/binop2/ && ($args[1]->[0] =~ 'unop1')) { 444 $ret = $class->new('unop1', '-', 445 $class->new($type, $args[0], $args[1]->[2], 446 $args[2])->normalize($degree) ); 447 } elsif (/binop[12]/ && ($args[2]->[0] eq $type) && 448 ($args[0] =~ /[+*]/)) { 449 # Remove frivolous right-association 450 # For example, fix 3+(4-5) or 3*(4x) 451 $ret = $class->new($type, $args[2]->[1], 452 $class->new($type, $args[0], $args[1], 453 $args[2]->[2])->normalize($degree), 454 $args[2]->[3]); 455 } elsif (/unop1/ && ($args[0] eq '+')) { 456 $ret = $args[1]; 457 } elsif (/unop1/ && ($args[1]->[0] =~ 'unop1')) { 458 $ret = $args[1]->[2]; 459 } 460 if ($degree > 0) { 461 } 462 return $ret; 463 } 464 465 sub tostring { 466 # print STDERR "Expr::tostring\n"; 467 # print STDERR Data::Dumper->Dump([@_]); 468 my($self) = shift; 469 my($type, @args) = @$self; 470 local $_; 471 $_ = $type; 472 /binop1/ && do { 473 my ($p1, $p2) = ('',''); 474 if ($args[2]->[0] eq 'binop1') {($p1,$p2)=qw{ ( ) };} 475 return ($args[1]->tostring() . $args[0] . $p1 . 476 $args[2]->tostring() . $p2); 477 }; 478 /unop1/ && do { 479 my ($p1, $p2) = ('',''); 480 if ($args[1]->[0] =~ /binop1/) {($p1,$p2)=qw{ ( ) };} 481 return ($args[0] . $p1 . $args[1]->tostring() . $p2); 482 }; 483 /binop2/ && do { 484 my ($p1, $p2, $p3, $p4)=('','','',''); 485 if ($args[0] =~ /implicit/) {$args[0] = ' ';} 486 if ($args[1]->[0] =~ /binop1/) {($p1,$p2)=qw{ ( ) };} 487 # if ($args[2]->[0] =~ /binop[12]/) {($p3,$p4)=qw{ ( ) };} 488 if ($args[2]->[0] =~ /binop[12]|unop1/) {($p3,$p4)=qw{ ( ) };} 489 return ($p1 . $args[1]->tostring() . $p2 . $args[0] . $p3 . 490 $args[2]->tostring() . $p4); 491 }; 492 /binop3/ && do { 493 my ($p1, $p2, $p3, $p4)=('','','',''); 494 # if ($args[1]->[0] =~ /binop[123]|numberE/) {($p1,$p2)=qw{ ( ) };} 495 if ($args[1]->[0] =~ /binop[123]|unop1|numberE/) {($p1,$p2)=qw{ ( ) };} 496 # if ($args[2]->[0] =~ /binop[12]|numberE/) {($p3,$p4)=qw{ ( ) };} 497 if ($args[2]->[0] =~ /binop[12]|unop1|numberE/) {($p3,$p4)=qw{ ( ) };} 498 return ($p1 . $args[1]->tostring() . $p2 . $args[0] . $p3 . 499 $args[2]->tostring() . $p4); 500 }; 501 /func1/ && do { 502 return ($args[0] . '(' . $args[1]->tostring() . ')'); 503 }; 504 /special|varname|numberE?/ && return $args[0]; 505 /closep/ && do { 506 my(%close) = %AlgParser::close; 507 508 509 510 return ($args[0] . $args[1]->tostring() . $close{$args[0]}); 511 }; 512 } 513 514 sub tolatex { 515 my($self) = shift; 516 my($type, @args) = @$self; 517 local $_; 518 $_ = $type; 519 /binop1/ && do { 520 my ($p1, $p2) = ('',''); 521 if ($args[2]->[0] eq 'binop1') {($p1,$p2)=qw{ \left( \right) };} 522 return ($args[1]->tolatex() . $args[0] . $p1 . 523 $args[2]->tolatex() . $p2); 524 }; 525 /unop1/ && do { 526 my ($p1, $p2) = ('',''); 527 if ($args[1]->[0] =~ /binop1/) {($p1,$p2)=qw{ \left( \right) };} 528 return ($args[0] . $p1 . $args[1]->tolatex() . $p2); 529 }; 530 /binop2/ && do { 531 my ($p1, $p2, $p3, $p4) = ('','','',''); 532 if ($args[0] =~ /implicit/) { 533 if ( (($args[1]->head eq qq(number)) && 534 ($args[2]->head eq qq(number))) || 535 (($args[1]->head eq qq(binop2)) && 536 ($args[1]->[2]->head eq qq(number))) ) { 537 $args[0] = '\\,'; 538 } else { 539 $args[0] = ' '; 540 } 541 } 542 if ($args[1]->[0] =~ /binop1|numberE/) 543 {($p1,$p2)=qw{ \left( \right) };} 544 # if ($args[2]->[0] =~ /binop[12]|numberE/) 545 if ($args[2]->[0] =~ /binop[12]|numberE|unop1/) 546 {($p3,$p4)=qw{ \left( \right) };} 547 if ($args[0] eq '/'){ 548 return('\frac{' . $p1 . $args[1]->tolatex() . $p2 . '}'. 549 '{' . $p3 . $args[2]->tolatex() . $p4 . '}' ); 550 } 551 else{ 552 return ($p1 . $args[1]->tolatex() . $p2 . $args[0] . $p3 . 553 $args[2]->tolatex() . $p4); 554 } 555 }; 556 /binop3/ && do { 557 my ($p1, $p2, $p3, $p4)=('','','',''); 558 # if ($args[1]->[0] =~ /binop[123]|numberE/) {($p1,$p2)=qw{ \left( \right) };} 559 if ($args[1]->[0] =~ /binop[123]|unop1|numberE/) {($p1,$p2)=qw{ \left( \right) };} 560 # Not necessary in latex 561 # if ($args[2]->[0] =~ /binop[12]/) {($p3,$p4)=qw{ \left( \right) };} 562 return ($p1 . $args[1]->tolatex() . $p2 . "^{" . $p3 . 563 $args[2]->tolatex() . $p4 . "}"); 564 }; 565 /func1/ && do { 566 my($p1,$p2); 567 if($args[0] eq "sqrt"){($p1,$p2)=qw{ \left{ \right} };} 568 else {($p1,$p2)=qw{ \left( \right) };} 569 570 $specialfunc = '(?:abs|logten|asin|acos|atan|sech|sgn|step|fact)'; 571 572 573 if ($args[0] =~ /$specialfunc/) { 574 return ('\mbox{' . $args[0] .'}'. $p1 . $args[1]->tolatex() . $p2); 575 } 576 else { 577 return ('\\' . $args[0] . $p1 . $args[1]->tolatex() . $p2); 578 } 579 }; 580 /special/ && do { 581 if ($args[0] eq 'pi') {return '\pi';} else {return $args[0];} 582 }; 583 /varname|(:?number$)/ && return $args[0]; 584 /numberE/ && do { 585 $args[0] =~ m/($AlgParser::numberplain)E([-+]?\d+)/; 586 return ($1 . '\times 10^{' . $2 . '}'); 587 }; 588 /closep/ && do { 589 my($backslash) = ''; 590 my(%close) = %AlgParser::close; 591 if ($args[0] eq '{') {$backslash = '\\';} 592 #This is for editors to match: } 593 return ('\left' . $backslash . $args[0] . $args[1]->tolatex() . 594 '\right' . $backslash . $close{$args[0]}); 595 }; 596 } 597 598 sub fromarray { 599 my($class) = shift; 600 my($expr) = shift; 601 if ((ref $expr) ne qq{ARRAY}) { 602 die "Program error; fromarray not passed an array ref."; 603 } 604 my($type, @args) = @$expr; 605 foreach my $i (@args) { 606 if (ref $i) { 607 $i = $class->fromarray($i); 608 } 609 } 610 return $class->new($type, @args); 611 } 612 613 package ExprWithImplicitExpand; 614 @ISA=qw(Expr); 615 616 617 sub tostring { 618 # print STDERR "ExprWIE::tostring\n"; 619 # print STDERR Data::Dumper->Dump([@_]); 620 my ($self) = shift; 621 622 my($type, @args) = @$self; 623 624 if (($type eq qq(binop2)) && ($args[0] eq qq(implicit))) { 625 my ($p1, $p2, $p3, $p4)=('','','',''); 626 if ($args[1]->head =~ /binop1/) {($p1,$p2)=qw{ ( ) };} 627 # if ($args[2]->head =~ /binop[12]/) {($p3,$p4)=qw{ ( ) };} 628 if ($args[2]->head =~ /binop[12]|unop1/) {($p3,$p4)=qw{ ( ) };} 629 return ($p1 . $args[1]->tostring() . $p2 . '*' . $p3 . 630 $args[2]->tostring() . $p4); 631 } else { 632 return $self->SUPER::tostring(@_); 633 } 634 }
| aubreyja at gmail dot com | ViewVC Help |
| Powered by ViewVC 1.0.9 |