문제
좋아, 텍스트 파일에 이와 같은 문자열이 있다고 가정 해 봅시다.
((( var1 AND var2 AND var3) OR var4) AND ((var5 OR var6) AND var7))
이것을 C 프로그램에 구문 분석하면 VARS가 처리되고 올바르게 설정된 후에는 다음과 같은 것을 보게됩니다.
((( 1 AND 0 AND 0) OR 1) AND ((0 OR 1) AND 1))
이와 같은 하나의 문자열로 표시되는 표현식을 평가하는 데 유용한 라이브러리가 있습니까? 나는 문자열이있는 Perl 프로그램을 문자열로 호출 할 수 있지만 결과를 쉽게 반환 할 수 있지만 C 에이 작업을 수행 한 라이브러리가 있는지 확실하지 않은 인수 또는 해결을위한 알려진 알고리즘이 있는지 확실하지 않았습니다. 그런 표현?
편집 : 내가 실제로 찾고있는 것은이 표현에 대한 답을 뱉어내는 것입니다. 아마도 구문 분석은 나쁜 단어 일 것입니다. 즉 1 또는 0
너트 쉘에서는 0 또는 1으로 평가 해야하는 무작위 표현식 (이미 올바른 형식으로 알려진 것으로 알려짐)이 포함 된 파일입니다 (위의 위는 (1 및 1)가 발생하기 때문에 1로 평가합니다.
해결책
이 bool 표현 평가 문제에 대해 가장 작곡 된 C 코드를 작성하려고했습니다. 내 최종 코드는 다음과 같습니다.
편집 : 삭제
추가 부정 취급은 다음과 같습니다.
편집 : 테스트 코드가 추가되었습니다
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>
int 도어 (int poprd1, int poprd2) {if (poprd1 == -1) return poprd2; POPRD1 ||를 반환합니다 poprd2; } int doand (int poprd1, int poprd2) {if (poprd1 == -1) return poprd2; POPRD1 && POPRD2를 반환합니다. } int doprocess (char popert, int poprd1, int poprd2) {if (popert == '0') return poprd2; if (popert == 'O') Return Door (Poprd1, Poprd2); if (popert == 'a') return doand (poprd1, poprd2); 풋 ( "알 수없는 연산자 !!!"); 출구 (-1); } int* doparse (char PSTR, int pstart) {char c; int i = pstart; int 값 = -1; char 연산자 = '0'; for (; 계속하다; } if (c == '1') {value = doprocess (연산자, 값, 1); 계속하다; } if (c == '') 계속; if (c == ')') {int Areturn; Areturn = Malloc (2*Areturn의 크기); Areturn [0] = 값; Areturn [1] = i + 1; Areturn의 귀환; } if (c == '(') {int * aresult = doparse (pstr, i + 1); value = doprocess (연산자, 값, aresult [0]); i = aresult [1]; if (pstr [i ] == 0) break; 계속;} if ((c == 'a') && ((pstr [i + 1] == 'n') && (pstr [i + 2] == 'd')) ) {if (((Operator == '0') || (Operator = 'a')) {Operator = 'a'; i += 2; 계속;} else {puts ( "믹스 연산자가 허용되지 않습니다 (그리고 ) !!! "); exit (-1);}} if ((c == 'o') && (pstr [i + 1] == 'r')) {if ((Operator == '0' ) || (OPERATOR == 'O')) {OPERATOR = 'O'; i += 1; 계속;} else {puts ( "믹스 연산자가 허용되지 않습니다 (또는) !!!"); 종료 (-1 );}} printf ( "알 수없는 문자 : '%c ("%s [%d]) !!!", c, pstr, i); exit (-1);} int* areturn; areturn = malloc (2*Areturn의 크기); Areturn [0] = value; 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으로 변환 한 다음, 오페라를 팝핑하여이를 평가합니다. 스택에 작동이 남지 않고 값 1 개가 남아있을 때까지 작업을 수행하고 결과를 누릅니다.
표현 파서를 작성하는 것은 원칙적으로 쉽지만 상당한 노력이 필요합니다.
다음은 Java에서 쓴 기본 to-down recursive descent expression 파서입니다. http://david.tribble.com/src/java/tribble/parse/sql/queryparser.java http://david.tribble.com/src/java/tribble/parse/sql/exprlexer.java http://david.tribble.com/src/java/tribble/parse/sql/exprlexer.java http://david.tribble.com/docs/tribble/parse/sql/package-summary.html
이것은 정확히 당신이 찾고있는 것이 아닐 수도 있지만, 필요한 것에 대한 아이디어를 줄 것입니다.