سؤال

حسنا، دعنا نقول أن لدي سلسلة مثل هذا في ملف نصي:

((( var1 AND var2 AND var3) OR var4) AND ((var5 OR var6) AND var7))

بعد تحليل هذا في برنامج C ويتم التعامل مع المتغيرات وضبطها بشكل صحيح فسوف ينتهي الأمر بالنظر إلى شيء مثل هذا:

((( 1 AND 0 AND 0) OR 1) AND ((0 OR 1) AND 1))

هل هناك أي مكتبات مفيدة من أجل تقييم التعبيرات الممثلة كسلسلة واحدة مثل هذا؟ كنت أفكر في أنني أستطيع فقط استدعاء برنامج بيرل مع السلسلة كوسيطة ستكون قادرا على إعادة النتيجة بسهولة ولكن لم تكن متأكدة مما إذا كانت هناك مكتبة في C التي فعلت ذلك، أو إذا كانت هناك أي خوارزميات معروفة لحلها هذه التعبيرات؟

تحرير: ما أبحث عنه فعلا هو شيء من شأنه أن يبصق إجابة على هذا التعبير، وربما كانت تحليل كلمة سيئة. أي 1 أو 0

في قذيفة الجوز لها ملف يحتوي على مجموعة من التعبيرات العشوائية (المعروف بالفعل أن تكون في التنسيق الصحيح) التي تحتاج إلى تقييمها إلى 0 أو 1. (أعلاه) (أعلى تقيم إلى 1 لأنها تؤدي إلى (1 و 1).

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

المحلول

حاولت كتابة رمز C أكثر مدمجة لمشكلة تقييم تعبير BOOL. هنا الرمز النهائي الخاص بي:

تحرير: محذوف

هنا هو التعامل مع النفي الإضافي:

تحرير: إضافة رمز الاختبار

char *eval( char *expr, int *res ){
  enum { LEFT, OP1, MID, OP2, RIGHT } state = LEFT;
  enum { AND, OR } op;
  int mid=0, tmp=0, NEG=0;

  for( ; ; expr++, state++, NEG=0 ){
    for( ;; expr++ )
         if( *expr == '!'     ) NEG = !NEG;
    else if( *expr != ' '     ) break;

         if( *expr == '0'     ){ tmp  =  NEG; }
    else if( *expr == '1'     ){ tmp  = !NEG; }
    else if( *expr == 'A'     ){ op   = AND; expr+=2; }
    else if( *expr == '&'     ){ op   = AND; expr+=1; }
    else if( *expr == 'O'     ){ op   = OR;  expr+=1; }
    else if( *expr == '|'     ){ op   = OR;  expr+=1; }
    else if( *expr == '('     ){ expr = eval( expr+1, &tmp ); if(NEG) tmp=!tmp; }
    else if( *expr == '\0' ||
             *expr == ')'     ){ if(state == OP2) *res |= mid; return expr; }

         if( state == LEFT               ){ *res  = tmp;               }
    else if( state == MID   && op == OR  ){  mid  = tmp;               }
    else if( state == MID   && op == AND ){ *res &= tmp; state = LEFT; }
    else if( state == OP2   && op == OR  ){ *res |= mid; state = OP1;  }
    else if( state == RIGHT              ){  mid &= tmp; state = MID;  }
  }
}

اختبارات:

#include <stdio.h> 

void test( char *expr, int exprval ){
  int result;
  eval( expr, &result );
  printf("expr: '%s' result: %i  %s\n",expr,result,result==exprval?"OK":"FAILED");
}
#define TEST(x)   test( #x, x ) 

#define AND       && 
#define OR        || 

int main(void){
  TEST( ((( 1 AND 0 AND 0) OR 1) AND ((0 OR 1) AND 1)) );
  TEST( !(0 OR (1 AND 0)) OR !1 AND 0 );
}

نصائح أخرى

يمكنك تضمينها لوا في البرنامج الخاص بك، ثم استدعاء فوري مترجم لتقييم التعبير.

من السهل بما فيه الكفاية لفة خاصة بك المحلل النسب المتكرر للتعبيرات البسيطة مثل هذه.

لدي برنامج مماثل حول هذا ينفذ المحلل اللائحي المكرر لذلك أنا فرشاة ذلك وهنا.

 #include <stdio.h>
 #include <stdlib.h>

BOOR INT (INT POPRD1، POPRD2) {IF (POPRD1 == -1) إرجاع POPRD2؛ العودة POPRD1 ||. POPRD2؛ } Int Doand (Int Poprd1، Int Poprd2) {IF (POPRD1 == -1) إرجاع POPRD2؛ العودة POPRD1 && POPRD2؛ } Int Doprocess (Char Popert، Int Poprd1، Int Poprd2) {IF (Popert == '0') إرجاع POPRD2؛ إذا (popert == 'o') العودة الباب (POPRD1، POPRD2)؛ إذا (Popert == 'A') عودة Doand (POPRD1، POPRD2)؛ يضع ("مشغل غير معروف !!!")؛ الخروج (-1)؛ } Int * Doparse (char pstr، int pstart) {char c؛ int i = pstart؛ القيمة الدولية = -1؛ char المشغل = '0'؛ ل (؛ (c = pstr [i])! = 0؛ i ++) {if (c == '0') {value = doprocess (المشغل، القيمة، 0)؛ استمر؛ } إذا كان (c == '1') {value = doprocess (المشغل، القيمة، 1)؛ استمر؛ } إذا (C == '') إذا (c == ')') {int عودة؛ Areturn = Malloc (2 * ميفونوف Areturn)؛ Areturn [0] = القيمة؛ Areturn [1] = i + 1؛ عودة اريتورن. } إذا كان (c == '(') {int * aresult = doparse (pstr، i + 1)؛ قيمة = doprocess (المشغل، القيمة، aresult [0])؛ i = aresult [1]؛ إذا (pstr [i ] == 0) استراحة؛ متابعة؛} إذا ((C == 'A') && ((pstr [i + 1] == 'n') && (pstr [i + 2] == 'd') ) {if ((المشغل == '0') || (المشغل == 'A')) {المشغل = 'A'؛ I + = 2؛ متابعة؛} آخر {purs ) !!! ")؛ خروج (-1)؛}} إذا ((C == 'o') && (pstr [i + 1] == 'r')) {en. . )؛}}} printf ("حرف غير معروف:٪ C ("٪ c [٪ d])" !!! "، c، pstr، i)؛ الخروج (-1)؛} int * areturn؛ areturn = maloc (2 * sizeof areturn)؛ areturn [0] = القيمة؛ areturn [1] = i؛ return areturn؛}

وهذا رمز الاختبار:

int main(void) {
    char* aExpr   = "1";
    int*  aResult = doParse(aExpr, 0);
    printf("%s = %d\n", aExpr, ((int*)aResult)[0]);
    free(aResult);
    aExpr   = "0";
    aResult = doParse(aExpr, 0);
    printf("%s = %d\n", aExpr, ((int*)aResult)[0]);
    free(aResult);
    aExpr   = "1 AND 0";
    aResult = doParse(aExpr, 0);
    printf("%s = %d\n", aExpr, ((int*)aResult)[0]);
    free(aResult);
    aExpr   = "1 AND 1";
    aResult = doParse(aExpr, 0);
    printf("%s = %d\n", aExpr, ((int*)aResult)[0]);
    free(aResult);
    aExpr   = "0 OR 0 OR 0";
    aResult = doParse(aExpr, 0);
    printf("%s = %d\n", aExpr, ((int*)aResult)[0]);
    free(aResult);
    aExpr   = "1 OR 0 OR 0";
    aResult = doParse(aExpr, 0);
    printf("%s = %d\n", aExpr, ((int*)aResult)[0]);
    free(aResult);
    aExpr   = "1 OR 1 OR 0";
    aResult = doParse(aExpr, 0);
    printf("%s = %d\n", aExpr, ((int*)aResult)[0]);
    free(aResult);
    aExpr   = "(1 OR 0)";
    aResult = doParse(aExpr, 0);
    printf("%s = %d\n", aExpr, ((int*)aResult)[0]);
    free(aResult);
    aExpr   = "(0 OR 0)";
    aResult = doParse(aExpr, 0);
    printf("%s = %d\n", aExpr, ((int*)aResult)[0]);
    free(aResult);
    aExpr   = "((( 1 AND 0 AND 0) OR 1) AND ((0 OR 1) AND 1))";
    aResult = doParse(aExpr, 0);
    printf("%s = %d\n", aExpr, ((int*)aResult)[0]);
    free(aResult);
    puts("DONE!!!");
    return EXIT_SUCCESS;
}

هذا هو متعة :-D.

أعتقد LEX و YACC. لا تزال أفضل أدوات لمهام تحليل بسيطة مثل هذا.

منذ فترة، كتبت مقيم تعبير C الكامل (أي تعبيرات تقييمها مكتوبة باستخدام بناء جملة C) لمعالج سطر الأوامر ولغة البرمجة النصية على نظام مضمن. انا إستعملت هذه وصف الخوارزمية كنقطة انطلاق. يمكنك استخدام الرمز المرافق مباشرة، لكنني لم أكن أعجبني التنفيذ، وكتبت الخاصة بي من الخوارزمية الوصف. إنها بحاجة إلى بعض الأعمال لدعم جميع المشغلين C، ومكالمات الوظيفة والمتغيرات، ولكنها تفسير واضح وبالتالي نقطة انطلاق جيدة، خاصة إذا كنت لا تحتاج إلى مستوى الاكتمال.

المبدأ الأساسي هو أن تقييم التعبير هو أسهل لجهاز كمبيوتر باستخدام مكدس و "الترميز البولندي العكسي"، وبالتالي فإن الخوارزمية تقوم بتحويل تعبير تدوينات داخل الإصلاح مع ترتيب المرتبط بالأسبقية والأقواس إلى RPN، ثم يقوم بتقييمها عن طريق برغمات المعاملات، إجراء عمليات أداء، ودفع النتائج، حتى لا توجد عمليات متبقية وقيمة واحدة تركت على المكدس.

كتابة محلل التعبير سهل من حيث المبدأ، ولكنه يأخذ قدرا عاديا من الجهد.

إليك محيط التعبير العسكري النسبي الأساسي الذي كتبته في Java: http://david.trable.com/src/java/trigle/parse/sql/queryparser.java. http://david.treble.com/src/java/trible/parse/sql/exprlexer.java. http://david.treble.com/src/java/trible/parse/sql/exprlexer.java. http://david.treble.com/docs/trable/parse/sql/package-summary.html.

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

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top