在C中解析并计算布尔表达式

时间:2014-11-15 14:56:38

标签: c arrays parsing boolean-logic boolean-operations

我有一个带有布尔表达式的文件,格式如下:

x0 x3+x4
x1+x2

这些对应于:

x0 AND x3 OR x4
x1 OR x2

假设我们知道表达式的数量(N = 2)和x的数量(M = 5)。 我想要一个大小为N的数组A和一个大小为M的数组Y. 数组A应包含在:

A[0] = y[0] && y[3] || y[4]
A[1] = y[1] || y[2]

等等。

到目前为止,我已经实现了一个python脚本,该脚本生成一个.c文件,其中给定的数组使用表达式初始化。但这意味着我需要为每个不同的实例重新编译我的程序。我想避免这种情况。欢迎任何想法。

是否有“脏”或快速技巧可以做到这一点?如果可能的话,我想纯粹使用C语言。提前谢谢。

1 个答案:

答案 0 :(得分:3)

这里是C解决方案的基本要点。它假设一个字母的变量名和一个字母的运算符。 (为了好玩,我包含了一个" not"运算符和子表达式的括号。) 它处理以下形式的字符串:

   a&b|(~c&~a)

(其中a..z对应于OP的X和Y实体)并计算表达式的布尔值。

这是作为经典的递归下降解析器实现的;有关如何执行此操作的详细信息,请参阅Is there an alternative for flex/bison that is usable on 8-bit embedded systems?

我对它进行了编码,指出这对于表达式来说有多简单。这是未经测试的; OP可以分担他的工作。

 #define syntax_error -1 // result of parser if expression is malformed

 bool variable_values[26]; // one for each letter a-z; initialized before parsing starts

 char* expression; // pointer to the expression string being processed

 int scan; // used to scan across the expression
 #define reject_character()  scan-- // used to back up scan when lexical error encountered
 #define skip_blanks() { while (expression[scan]==' ') scan++; }

 int boolean_primitive()
 // returns result of a subexpression consisting of just variable names or constants
 { int subexpression_result;
   skip_blanks();
   switch (expression[scan++])
   { case 'a','b', ... 'z': // variable name
       return variable_values[expression[scan-1]-"a"]; // look up value of variable
     case '0': // constant for "false"
       return 0;
     case '1': // constant for "true"
       return 1;
     default:
       return syntax_error;
   }
 }

 int boolean_term()
 // returns result of expression involving NOT or (...)
 { int subexpression_result;
   skip_blanks();
   switch (expression[scan++])
   { case '~': // not operator
       subexpression_result=boolean_primitive();
       if (subexpression_result==syntax_error)
          return syntax_error;
       return !subexpression_result;            
     case '(': // nested expression
       subexpression_result=boolean_or_sequence();
       if (subexpression_result==syntax_error)
          return syntax_error;
       skip_blanks();
       if (expression[scan++]==')')
          return subexpression_result;
       else return syntax_error;
     default:
       reject_character();
       return boolean_primitive();
   }
 }

 int boolean_and_sequence()
 // returns result of expression of form   s1 & s2 & ...
 { int subexpression_result=boolean_term();
   if (subexpression_result==syntax_error)
      return syntax_error;
   skip_blanks();
   while (expression[scan++]=='&') // "and" operator?
   { int subexpression2_result=boolean_term();
     if (subexpression2_result==syntax_error)
        return syntax_error;
     subexpression_result&=subexpression2_result;
     skip_blanks();
   }        
   reject_character; // undo overscan for '&'
   return subexpression_result;
}

 int boolean_or_sequence()
 // returns result of expression of form of s1 | s2 | ...
 { int subexpression_result=boolean_and_sequence();
   if (subexpression_result==syntax_error)
      return syntax_error;
   skip_blanks();
   while (expression[scan++]=='|') // "or" operator?
   { int subexpression2_result=boolean_primitive();
     if (subexpression2_result==syntax_error)
        return syntax_error;
     subexpression_result|=subexpression2_result;
     skip_blanks();
   }        
   reject_character; // undo overscan for '|'
   return subexpression_result;
}

 int calculate_boolean_expression(char* expression_to_evaluate)
 // returns int==0 for boolean false;
 // int==1 for boolean true
 // int==-1 for malformed expression
 {  int subexpression_result;
    scan=1;
    expression=expression_to_evaluate;
    subexpression_result=boolean_or_sequence();
    if (subexpression_result==syntax_error)
       return syntax_error;
    skip_blanks();
    if (expression[scan]==0) // expression ends without excess junk in string?
       return subexpression_result;
    else return syntax_error;
 }

初始化变量值后,将其调用为:

 int the_answer=calculate_boolean_expression(&some_expression_string);

显然,您想检查答案,看看解析器是否发现了语法错误。

如果您坚持,可以通过将它们全部作为参数传递来避免全局变量。

返回/检查syntax_error在C中是不方便的,并且由于重复需要从调用的子解析器检查它而使实现变得混乱。实现这个可抛出的异常会更好,但C不允许这样做。你可以用longjmp伪装它。

您必须扩展它以处理您的(多字符)词汇并发症,无论它们是什么。对于快速和脏,坚持单字符操作符/操作数非常干净。处理多字符词位的秘诀是测试你期望遇到它的每个词位,并简单地备份" scan"指向失败的lexeme开头的指针。我使用宏"拒绝"对此。