سؤال

في السؤال السابق كنت أبحث عن طريقة لإباحة التعبيرات الرياضية المعقدة في ج، فإن معظم الاقتراحات تتطلب تنفيذ نوع من المحللين.

ومع ذلك إجابة واحدة, اقترح استخدام LUA لتقييم التعبير. أنا مهتم بهذا النهج لكنني لا أعرف أي شيء عن لوا.

يمكن أن بعض واحد مع خبرة في لوا سقيفة بعض الضوء؟

على وجه التحديد ما أود أن أعرفه هوأي واجهة برمجة التطبيقات التي توفرها LUA التي توفرها التي يمكن أن تقيم التعبيرات الرياضية التي تم تمريرها كسلسلة؟ إذا لم يكن هناك واجهة برمجة تطبيقات فعلية للقيام بمثل هذا الشيء، فقد يكون بعضها يمكن أن يلقي بعض الضوء على الإجابة المرتبطة كما بدا وكأنه نهج جيد :)

شكرا

يتم إعطاء نوع التعبير الذي أود تقييمه ببعض مدخلات المستخدم مثل

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

تقييم Y لمجموعة من قيم X

هل كانت مفيدة؟

المحلول

من الواضح أن إعداد مثيل مترجم LUA، وتمرير تعبيرات تكنولوجيا المعلومات المراد تقييمها، واستعادة وظيفة للاتصال بها التي تقيم التعبير. يمكنك حتى السماح للمستخدم بمتغيرات ...

إليك نموذج التعليمات البرمجية التي طهيها وتحريرها في إجابتي الأخرى. من المحتمل أن يتم وضع أفضل على سؤال وضع علامة LUA في أي حال، لذلك أنا أضيف ذلك هنا أيضا. لقد جمعت هذا وحاولها لبضع حالات، لكن من المؤكد أنه لا ينبغي موثوقية في قانون الإنتاج دون أن يناه بعض الاهتمام لمعالجة الأخطاء وما إلى ذلك. جميع التحذيرات المعتادة تنطبق هنا.

قمت بتجميعها واختبارها على Windows باستخدام LUA 5.1.4 من لوا لنظام التشغيل Windows. وبعد على منصات أخرى، عليك أن تجد LUA من المصدر المعتاد، أو من www.lua.org.

تحديث: تستخدم هذه العينة تقنيات بسيطة ومباشرة لإخفاء الطاقة الكاملة وتعقيد LUA API وراء بسيطة قدر الإمكان. ربما يكون مفيدا كما هو، ولكن يمكن تحسينه بعدة طرق.

أود أن أشجع القراء على النظر إلى المزيد من الإنتاج جاهز أخر مكتبة من قبل LHF. للحصول على التعليمات البرمجية التي تستفيد من API لتجنب بعض التلاعبات السريعة والقذرة التي استخدمتها. تروج مكتبته أيضا مكتبة الرياضيات في مساحة الاسم العالمي بحيث يمكن للمستخدم أن يقول sin(x) أو 2 * pi دون الحاجة إلى القول math.sin وهكذا دواليك.

الواجهة العامة إلى LE

هنا هو الملف 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);

نموذج التعليمات البرمجية باستخدام LE

هنا هو ملف T-Le.c، مما يدل على استخدام بسيط لهذه المكتبة. يستغرق حجة سطر الأوامر الفردي، وتحميله كتعبير، ويقيمه باستخدام المتغير العالمي X المتغير من 0.0 إلى 1.0 بخطوات 11 خطوة:

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

إليك بعض الإخراج من 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.409 0.40 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: ...>

تنفيذ جنيه

هنا le.c, ، تنفيذ مقيم تعبير 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;
}

ملاحظات

تتكون العينة المذكورة أعلاه من 189 خطا من مجموع التعليمات البرمجية، بما في ذلك Spattering of التعليقات والخطوط الفارغة والمظاهرة. ليس سيئا لتقييم وظيفة سريعة يعرف كيفية تقييم التعبيرات التعسفية المعقولة عن متغير واحد، ولديها مكتبة غنية من وظائف الرياضيات القياسية في بيك والدعوة.

لديك لغة كاملة تورينج تحت كل شيء، وسيكون امتداد سهل للسماح للمستخدم بتحديد الوظائف الكاملة وكذلك لتقييم التعبيرات البسيطة.

نصائح أخرى

نظرا لأنك كسول، مثل معظم المبرمجين، فإليك رابط إلى مثال بسيط يمكنك استخدامه لتحليل بعض الرمز التعسفي استخدام لوا. وبعد من هناك، يجب أن يكون سهلا لإنشاء محلل التعبير الخاص بك.

هذا هو بالنسبة لمستخدمي LUA الذين يبحثون عن ما يعادل LUA "eval".

الكلمة السحرية المستخدمة لتكون loadstring ولكنها الآن، منذ LUA 5.2، نسخة مطورة من حمل.

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

مثال آخر، يسلم قيمة القيمة:

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

كوسيلة سريعة والقذرة للقيام بها، يمكنك التفكير في ما يعادل التقييم (S) التالي، حيث S هي سلسلة لتقييم:

load(s)()

كما هو الحال دائما، يجب تجنب آليات التقييم عند الإمكان لأنها باهظة الثمن وإنتاج كود يصعب قراءتها. أنا شخصيا استخدم هذه الآلية مع Leordex / Lualatex لجعل عمليات الرياضيات في اللاتكس.

يحتوي وثائق LUA على قسم بعنوان واجهة برمجة التطبيق الذي يصف كيفية الاتصال LUA من برنامج C الخاص بك. وثائق LUA جيدة جدا وقد تكون قادرا حتى العثور على مثال على ما تريد القيام به هناك.

إنه عالم كبير هناك، لذلك سواء اخترت محلول تحليلك الخاص أو مترجم مغرور مثل Lua، فسوف يكون لديك بعض العمل للقيام به!

function calc(operation)
    return load("return " .. operation)()
end
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top