我有一个带有布尔表达式的文件,格式如下:
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语言。提前谢谢。
答案 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开头的指针。我使用宏"拒绝"对此。