Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

(La)Tex math parsing for C/C++

I would like to convert parse (la)tex math expressions, and convert them to (any kind of!) scripting language expression, so I can evaluate expressions. What libraries do you recommend ?

like image 787
J.B. Avatar asked Jan 27 '11 15:01

J.B.


3 Answers

Here is a set of possible options from a similar question. https://tex.stackexchange.com/questions/4223/what-parsers-for-latex-mathematics-exist-outside-of-the-tex-engines

I think that Perl would make a fine choice for something like this, acting on text is one of its fortes.

Here is some info on how to make an exclusive flip-flop test (to find the context between \begin{} and \end{} without keeping those lines), http://www.effectiveperlprogramming.com/2010/11/make-exclusive-flip-flop-operators/

EDIT: So this problem has started me going. Here is a first attempt to create something here is my "math.pl" which takes a .tex file as an arguement (i.e. $./math.pl test.tex).

#!/usr/bin/env perl

use strict;
use warnings;

use Text::Balanced qw/extract_multiple extract_bracketed/;

my $re_num = qr/[+\-\dE\.]/;

my $file = shift;

open( my $fh, '<', $file);

#parsing this out for more than just the equation environment might be easier using Text::Balanced too.
my @equations;
my $current_equation = '';
while(<$fh>) {
  my $test;
  next unless ($test = /\\begin\{equation\}/ .. /\\end\{equation\}/);

  if ($test !~ /(^1|E0)$/ ) {
    chomp;
    $current_equation .= $_;
  } elsif ($test =~ /E0$/) {
    #print $current_equation . "\n";
    push @equations, {eq => $current_equation};
    $current_equation = '';
  }
}

foreach my $eq (@equations) {
  print "Full Equation: " . $eq->{'eq'} . "\n";
  solve($eq);
  print "Result: " . $eq->{'value'} . "\n\n";
}

sub solve {
  my $eq = shift;

  print $eq->{'eq'} . "\n";

  parse($eq);
  compute($eq);

  print "intermediate result: " . $eq->{'value'} . "\n";
}

sub parse {
  my $eq = shift;

  my ($command,@fields) = extract_multiple(
    $eq->{'eq'}, [ sub { extract_bracketed(shift,'{}') } ]
  );

  $command =~ s/^\\//;
  print "command: " . $command . "\n";

  @fields = map { s/^\{\ *//; s/\ *\}$//; print "arg: $_\n"; {value => $_}; } @fields;


  ($eq->{'command'}, @{ $eq->{'args'} }) = ($command, @fields);
}

sub compute {
  my ($eq) = @_;

  #check arguements ...
  foreach my $arg (@{$eq->{'args'}}) {
    #if arguement is a number, continue
    if ($arg->{'value'} =~ /^$re_num$/) {
      next;

    #if the arguement is a simple mathematical operation, do it and continue
    } elsif ($arg->{'value'} =~ /^($re_num)\ *(?:\ |\*|\\times)?\ *($re_num)$/) {
      $arg->{'value'} = $1 * $2;
    } elsif ($arg->{'value'} =~ /^($re_num)\ *(?:\+)?\ *($re_num)$/) {
      $arg->{'value'} = $1 + $2;
    } elsif ($arg->{'value'} =~ /^($re_num)\ *(?:\-)?\ *($re_num)$/) {
      $arg->{'value'} = $1 - $2;
    } elsif ($arg->{'value'} =~ /^($re_num)\ *(?:\/)?\ *($re_num)$/) {
      $arg->{'value'} = $1 / $2;
    } else {
      #parse it and calc it as if it were its own equation.
      $arg->{'eq'} = $arg->{'value'};
      solve($arg);
    }
  }

  my @args = @{$eq->{'args'}};

  ## add command processing here
  # frac
  if ($eq->{'command'} eq 'frac') {
    $eq->{'value'} = $args[0]->{'value'} / $args[1]->{'value'};
    return;
  }

}

and here is a sample test.tex:

\documentclass{article}

\begin{document}

Hello World!

\begin{equation}
\frac{\frac{1}{3}}{2}
\end{equation}

\end{document}
like image 141
Joel Berger Avatar answered Nov 19 '22 16:11

Joel Berger


May be it will help - take a look at TeXmacs, especially at a way it interacts with computer algebra systems.

like image 44
SK-logic Avatar answered Nov 19 '22 15:11

SK-logic


Maybe using boost::spirit in order to tokenize the expression. You will need to define a huge grammar!

like image 1
Benoit Avatar answered Nov 19 '22 15:11

Benoit