2011-01-27 7 views
11

Me gustaría convertir expresiones matemáticas parse (la) tex, y convertirlas a (cualquier tipo de!) Expresión de lenguaje de scripting, para poder evaluar expresiones. ¿Qué bibliotecas recomiendas?(La) Análisis matemático de Tex para C/C++

+3

Es una idea bastante extraña. ¿Cómo distingue $ a^n $ donde $ n $ es un índice de $ a^n $ que es pow (a, n)? ¿Qué es \ cdot en $ A \ cdot B $? La matemática de látex es puramente visual, no tiene semántica. –

+2

@SKlogic: tal vez esto solo va a ser usado para expresiones como '$ \ sqrt [4] {\ frac {a + b} {2}} $' – Benoit

+0

En este caso no es obvio por qué usar notación de látex en absoluto - se podría utilizar un tercer idioma, con traducción tanto al látex como a lo que sea conveniente evaluar. –

Respuesta

1

Quizás usando boost::spirit para tokenizar la expresión. ¡Tendrás que definir una gran gramática!

+4

... donde 'while (true) {huge * = huge; } 'es un comportamiento definido y observable. –

1

Puede ser que sea de ayuda - eche un vistazo a TeXmacs, especialmente en una forma en que interactúa con los sistemas de álgebra de la computadora.

0

Utilice un generador de analizador para crear un analizador apropiado. Pruebe ANTLR para esto, ya que incluye un IDE para la gramática, que es muy útil. Utilizando reglas de reescritura de árbol, puede convertir el árbol de análisis sintáctico a un árbol de sintaxis abstracta.

Comience quizás con el evaluador de expresiones del tutorial de ANTLR. Creo que esto es razonablemente lo suficientemente cerca.

0

Aquí hay un conjunto de posibles opciones de una pregunta similar. https://tex.stackexchange.com/questions/4223/what-parsers-for-latex-mathematics-exist-outside-of-the-tex-engines

Creo que Perl sería una buena elección para algo como esto, actuar sobre el texto es una de sus fortalezas.

Aquí hay alguna información sobre cómo hacer una prueba exclusiva flip-flop (para encontrar el contexto entre \ begin {} y \ end {} sin mantener esas líneas), http://www.effectiveperlprogramming.com/2010/11/make-exclusive-flip-flop-operators/

EDIT: Así que este problema tiene me comenzó a ir Aquí hay un primer intento de crear algo aquí es mi "math.pl" que toma un archivo .tex como argumento (es decir, $./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; 
    } 

} 

y aquí es una muestra de test.tex:

\documentclass{article} 

\begin{document} 

Hello World! 

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

\end{document} 
Cuestiones relacionadas