Domanda

Nel mio domanda precedente ero alla ricerca di un modo di evaulating espressioni matematiche complesse in C, la maggior parte dei suggerimenti richiesti attuare un certo tipo di parser.

una risposta , suggerito di usare Lua per valutare l'espressione. Sono interessato a questo approccio, ma io non so niente di Lua.

Può qualcuno con esperienza in Lua far luce?

In particolare quello che mi piacerebbe sapere è Quali API se uno vuol Lua prevede che può valutare le espressioni matematiche passati come una stringa? Se non c'è API per fare una cosa del genere, può essere qualcuno può far luce sulla risposta collegato come sembrava un buon approccio:)

Grazie

Il tipo di espressione che vorrei valutare è dato un certo input dell'utente come ad esempio

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

valutare y per un intervallo di valori di x

È stato utile?

Soluzione

E 'semplice da impostare un'istanza interprete Lua, e passarlo espressioni da valutare, il recupero di una funzione da chiamare che valuta l'espressione. Si può anche consentire all'utente di avere le variabili ...

Ecco il codice di esempio ho cucinato e curato nella mia altra risposta. Probabilmente è meglio posizionato su una domanda etichettato Lua, in ogni caso, quindi sto aggiungendo che anche qui. Ho compilato questo e l'ho provato per un paio di casi, ma di certo non dovrebbe essere attendibile nel codice di produzione, senza una certa attenzione per la gestione degli errori e così via. Tutte le solite avvertenze applicano qui.

ho compilato e testato questo su Windows utilizzando Lua 5.1.4 da Lua per Windows . Su altre piattaforme, dovrete trovare Lua dalla solita fonte, oppure da www.lua.org.

Aggiornamento: Questo esempio utilizza tecniche semplici e diretti per nascondere tutta la potenza e la complessità delle API Lua dietro il più semplice possibile un'interfaccia. Probabilmente è utile come-è, ma potrebbe essere migliorata in molti modi.

Vorrei incoraggiare i lettori a esaminare il più pronto per la produzione ae libreria LHF per il codice che sfrutta le API per evitare alcune delle rapido e sporco manipolazione di stringhe che ho usato. La sua biblioteca promuove anche la libreria matematica nello spazio dei nomi globale in modo che l'utente può dire sin(x) o 2 * pi senza dover dire math.sin e così via.

Interfaccia pubblica a Le

Ecco il file 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);

Esempio di codice utilizzando LE

Ecco il file t-le.c, dimostrando un semplice uso di questa libreria. Prende suo argomento singola riga di comando, carica come espressione, e valuta con la variabile globale x cambia da 0,0 a 1,0 in 11 passi:

#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);
    }
}

Ecco qualche uscita da 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:...>

Attuazione LE

Ecco le.c, l'attuazione della valutazione delle espressioni 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;
}

Commento

L'esempio precedente è composto da 189 linee di codice totale, compreso uno schizzi di commenti, righe vuote, e la dimostrazione. Non male per un valutatore funzione quick che sa valutare le espressioni ragionevolmente arbitrarie di una variabile, ed ha ricca libreria di funzioni matematiche standard a sua completa disposizione.

Si dispone di un linguaggio Turing-complete sotto sotto, e sarebbe un'estensione facile per consentire all'utente di definire funzioni complete, nonché per valutare le espressioni semplici.

Altri suggerimenti

Dal momento che siete pigri, come la maggior parte dei programmatori, ecco un link ad un semplice esempio che è possibile utilizzare per analizzare alcune codice arbitrario utilizzando Lua . Da lì, dovrebbe essere semplice per tenere la parser di espressioni.

Questo è per gli utenti Lua che sono alla ricerca di un Lua equivalente di "eval".

La parola magica usata da LoadString ma è ora, dal momento che Lua 5.2, una versione aggiornata di Carica .

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

Un altro esempio, che offre un valore:

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

Come un modo rapido e-sporco da fare, si può considerare il seguente equivalente di eval (s), dove s è una stringa di valutare:

load(s)()

Come sempre, i meccanismi eval dovrebbe essere evitato quando possibile, in quanto essi sono costosi e producono un codice difficile da leggere. Io personalmente uso questo meccanismo con LuaTEX / LuaLatex per fare operazioni matematiche in lattice.

La documentazione Lua contiene una sezione intitolata L'Application Programming Interface che descrive come chiamare Lua dal vostro programma C. La documentazione per Lua è molto buona e si può anche essere in grado di trovare un esempio di ciò che si vuole fare in là.

E 'un grande mondo in là, quindi se si sceglie la propria soluzione di analisi o di un interprete embeddable come Lua, si sta andando ad avere un po' di lavoro da fare!

function calc(operation)
    return load("return " .. operation)()
end
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top