Question

Dans mon question précédente que je cherchais un moyen de evaulating expressions mathématiques complexes en C, la plupart des suggestions nécessaires mettre en œuvre un certain type d'analyseur.

Cependant une réponse , a suggéré d'utiliser Lua pour évaluer l'expression. Je suis intéressé par cette approche, mais je ne sais rien à propos de Lua.

Peut quelqu'un avec expérience dans Lua faire la lumière?

Plus précisément ce que je voudrais savoir est Quelle API si tout ne Lua prévoient que peut évaluer des expressions mathématiques passées en tant que chaîne? S'il n'y a pas d'API pour faire une telle chose, peut-être quelqu'un peut faire la lumière sur la réponse liée comme semblait être une bonne approche:)

Merci

Le type d'expression que je voudrais évaluer est donnée une entrée utilisateur tel que

y = x ^ 2 + 1 / x - cos (x)

y évaluer pour une gamme de valeurs de x

Était-ce utile?

La solution

Il est facile de mettre en place une instance de l'interpréteur Lua, et transmettre expressions à évaluer, pour revenir une fonction pour appeler Evalue l'expression. Vous pouvez même laisser l'utilisateur ont des variables ...

Voici le code d'exemple que je cuisinais et dans mon autre edited réponse. Il est probablement mieux placé sur une question marquée Lua dans tous les cas, donc je l'ajouter ici. Je compilé cela et essayé quelques cas, mais il ne devrait certainement pas confiance dans le code de production sans une certaine attention à la gestion des erreurs et ainsi de suite. Toutes les mises en garde habituelles sont applicables ici.

Je compilé et testé ce sur Windows en utilisant Lua 5.1.4 de Lua pour Windows . Sur d'autres plates-formes, vous devez trouver Lua de votre source habituelle, ou de www.lua.org.

Mise à jour: Cet exemple utilise des techniques simples et directes pour cacher la pleine puissance et la complexité de l'API Lua derrière aussi simple que possible une interface. Il est sans doute utile en l'état, mais pourrait être améliorée de plusieurs façons.

J'encourage les lecteurs à regarder dans le beaucoup plus prêt pour la production lhf pour le code qui profite de l'API pour éviter certains des rapides et sale la manipulation de chaînes que je l'ai utilisé. Sa bibliothèque favorise également la bibliothèque de mathématiques dans l'espace de nom global afin que l'utilisateur puisse dire sin(x) ou 2 * pi sans avoir à dire math.sin et ainsi de suite.

Interface publique à LE

Voici le fichier le.h:

/* Public API for the LE library.
 */
int le_init();
int le_loadexpr(char *expr, char **pmsg);
double le_eval(int cookie, char **pmsg);
void le_unref(int cookie);
void le_setvar(char *name, double value);
double le_getvar(char *name);

Exemple de code en utilisant LE

Voici le fichier t-le.c, ce qui démontre une utilisation simple de cette bibliothèque. Il tire son seul argument de ligne de commande, il charge comme une expression, et il évalue le changement de variable globale x de 0,0 à 1,0 en 11 étapes consistant à:

#include <stdio.h>
#include "le.h"

int main(int argc, char **argv)
{
    int cookie;
    int i;
    char *msg = NULL;

    if (!le_init()) {
    printf("can't init LE\n");
    return 1;
    }
    if (argc<2) {
    printf("Usage: t-le \"expression\"\n");
    return 1;
    }
    cookie = le_loadexpr(argv[1], &msg);
    if (msg) {
    printf("can't load: %s\n", msg);
    free(msg);
    return 1;
    }
    printf("  x    %s\n"
       "------ --------\n", argv[1]);
    for (i=0; i<11; ++i) {
    double x = i/10.;
    double y;

    le_setvar("x",x);
    y = le_eval(cookie, &msg);
    if (msg) {
        printf("can't eval: %s\n", msg);
        free(msg);
        return 1;
    }
    printf("%6.2f %.3f\n", x,y);
    }
}

Voici quelques sorties de t-le:

E:...>t-le "math.sin(math.pi * x)"
  x    math.sin(math.pi * x)
------ --------
  0.00 0.000
  0.10 0.309
  0.20 0.588
  0.30 0.809
  0.40 0.951
  0.50 1.000
  0.60 0.951
  0.70 0.809
  0.80 0.588
  0.90 0.309
  1.00 0.000

E:...>

Mise en œuvre de LE

Voici le.c, la mise en œuvre de l'évaluateur d'expression Lua:

#include <lua.h>
#include <lauxlib.h>

#include <stdlib.h>
#include <string.h>

static lua_State *L = NULL;

/* Initialize the LE library by creating a Lua state.
 *
 * The new Lua interpreter state has the "usual" standard libraries
 * open.
 */
int le_init()
{
    L = luaL_newstate();
    if (L) 
    luaL_openlibs(L);
    return !!L;
}

/* Load an expression, returning a cookie that can be used later to
 * select this expression for evaluation by le_eval(). Note that
 * le_unref() must eventually be called to free the expression.
 *
 * The cookie is a lua_ref() reference to a function that evaluates the
 * expression when called. Any variables in the expression are assumed
 * to refer to the global environment, which is _G in the interpreter.
 * A refinement might be to isolate the function envioronment from the
 * globals.
 *
 * The implementation rewrites the expr as "return "..expr so that the
 * anonymous function actually produced by lua_load() looks like:
 *
 *     function() return expr end
 *
 *
 * If there is an error and the pmsg parameter is non-NULL, the char *
 * it points to is filled with an error message. The message is
 * allocated by strdup() so the caller is responsible for freeing the
 * storage.
 * 
 * Returns a valid cookie or the constant LUA_NOREF (-2).
 */
int le_loadexpr(char *expr, char **pmsg)
{
    int err;
    char *buf;

    if (!L) {
    if (pmsg)
        *pmsg = strdup("LE library not initialized");
    return LUA_NOREF;
    }
    buf = malloc(strlen(expr)+8);
    if (!buf) {
    if (pmsg)
        *pmsg = strdup("Insufficient memory");
    return LUA_NOREF;
    }
    strcpy(buf, "return ");
    strcat(buf, expr);
    err = luaL_loadstring(L,buf);
    free(buf);
    if (err) {
    if (pmsg)
        *pmsg = strdup(lua_tostring(L,-1));
    lua_pop(L,1);
    return LUA_NOREF;
    }
    if (pmsg)
    *pmsg = NULL;
    return luaL_ref(L, LUA_REGISTRYINDEX);
}

/* Evaluate the loaded expression.
 * 
 * If there is an error and the pmsg parameter is non-NULL, the char *
 * it points to is filled with an error message. The message is
 * allocated by strdup() so the caller is responsible for freeing the
 * storage.
 * 
 * Returns the result or 0 on error.
 */
double le_eval(int cookie, char **pmsg)
{
    int err;
    double ret;

    if (!L) {
    if (pmsg)
        *pmsg = strdup("LE library not initialized");
    return 0;
    }
    lua_rawgeti(L, LUA_REGISTRYINDEX, cookie);
    err = lua_pcall(L,0,1,0);
    if (err) {
    if (pmsg)
        *pmsg = strdup(lua_tostring(L,-1));
    lua_pop(L,1);
    return 0;
    }
    if (pmsg)
    *pmsg = NULL;
    ret = (double)lua_tonumber(L,-1);
    lua_pop(L,1);
    return ret;
}


/* Free the loaded expression.
 */
void le_unref(int cookie)
{
    if (!L)
    return;
    luaL_unref(L, LUA_REGISTRYINDEX, cookie);    
}

/* Set a variable for use in an expression.
 */
void le_setvar(char *name, double value)
{
    if (!L)
    return;
    lua_pushnumber(L,value);
    lua_setglobal(L,name);
}

/* Retrieve the current value of a variable.
 */
double le_getvar(char *name)
{
    double ret;

    if (!L)
    return 0;
    lua_getglobal(L,name);
    ret = (double)lua_tonumber(L,-1);
    lua_pop(L,1);
    return ret;
}

Remarques

L'exemple ci-dessus se compose de 189 lignes du total de code, y compris un éclaboussement de commentaires, lignes blanches, et la démonstration. Pas mal pour un évaluateur de fonction rapide qui sait comment évaluer les expressions raisonnablement arbitraires d'une variable, et a riche bibliothèque de fonctions mathématiques standard à son entière disposition.

Vous avez un langage Turing-complet sous tout, et ce serait une extension facile à permettre à l'utilisateur de définir des fonctions complètes, ainsi que pour évaluer les expressions simples.

Autres conseils

Puisque vous êtes paresseux, comme la plupart des programmeurs, voici un lien vers un exemple simple que vous pouvez utiliser pour analyser certains code arbitraire utilisant Lua . A partir de là, il devrait être simple de créer votre analyseur d'expression.

Ceci est pour les utilisateurs Lua qui sont à la recherche d'un équivalent de Lua « eval ».

Le mot magique utilisé à LoadString mais il est maintenant, depuis Lua 5.2, une version améliorée de la charge .

 i=0
 f = load("i = i + 1") -- f is a function
 f() ; print(i) -- will produce 1
 f() ; print(i) -- will produce 2

Un autre exemple, qui fournit une valeur:

f=load('return 2+3')
print(f()) -- print 5

Comme un moyen rapide et sale à faire, vous pouvez envisager l'équivalent suivante de eval (s), où s est une chaîne à évaluer:

load(s)()

Comme toujours, les mécanismes eval devraient être évités autant que possible, car ils sont chers et produisent un code difficile à lire. Personnellement, j'utiliser ce mécanisme avec luatex / LuaLatex pour faire des opérations mathématiques en latex.

La documentation Lua contient une section intitulée L'interface de programmation d'application qui décrit comment appeler Lua à partir de votre programme C. La documentation de Lua est très bonne et vous pouvez même être en mesure de trouver un exemple de ce que vous voulez faire là-dedans.

Il est un grand monde là-bas, donc si vous choisissez votre propre solution d'analyse syntaxique ou un interprète intégrable comme Lua, vous allez avoir du travail à faire!

function calc(operation)
    return load("return " .. operation)()
end
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top