繁体   English   中英

解析并计算C语言中的布尔表达式

[英]Parse and calculate boolean expression in C

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

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。 提前致谢。

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

   a&b|(~c&~a)

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

这是作为经典的递归下降解析器实现的; 请参见在8位嵌入式系统上是否可以使用flex / bison的替代方案? 有关一般如何执行此操作的更多详细信息。

我对它进行了编码,以指出这对于表达式来说有多简单。 这是未经测试的; 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);

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

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

在C语言中,返回/检查语法错误是尴尬的,并且由于调用子解析器反复需要对其进行检查,因此使实现混乱。 实现此可抛出异常会更好,但C不允许这样做。 您可以使用longjmp进行伪造。

无论它们是什么,您都必须对其进行扩展以处理您的(多字符)词汇复杂性。 为了快速而肮脏,坚持使用单字符运算符/操作数是很干净的。 处理多字符词素的秘诀是针对您希望遇到的每个词素进行测试,然后简单地将“扫描”指针备份到失败的词素的开头。 我为此使用了宏“拒绝”。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM