我在Bison& amp;编程中编写一个简单的计算器Flex,使用C / C ++(逻辑在Bison中完成,C / C ++部分负责数据结构,例如STL等)。
我有以下问题:
在我的计算器中,美元符号$
表示i ++和++ i(前缀和后缀),例如:
int y = 3;
-> $y = 4
-> y$ = 4
当用户点击:int_expression1 && int_expression2
时,如果int_expression1
被评估为0
(即为假),那么我不会想要评估int_expression2
!
例如:
int a = 0 ;
int x = 2 ;
用户点击:int z = a&&x$
...
因此,变量a
被评估为0
,因此,我不想评估x
,但它仍然增长1 ...这里是代码bison / c ++:
%union
{
int int_value;
double double_value;
char* string_value;
}
%type <int_value> int_expr
%type <double_value> double_expr
%type <double_value> cmp_expr
int_expr:
| int_expr '&&' int_expr { /* And operation between two integers */
if ($1 == 0)
$$ = 0;
else // calc
$$ = $1 && $3;
}
如果第一个表达式已被评估为假(即0
),我如何告诉bison不评估第二个表达式?
答案 0 :(得分:2)
将广泛的评论转化为答案:
如果第一个表达式已被评估为假,我如何告诉Bison不评估第二个表达式?
这是你的代码进行评估,而不是Bison;把'责备'放在它所属的地方。
在评估RHS之前,您需要检测到您正在处理&&
规则。如果第一个&&
评估为0,则需要在int_expr
之后和暂停评估的第二个int_expr
之前插入一些代码。您还需要修改所有代码其他评估代码,用于检查并遵守“不评估”标志。
或者,您可以让Bison进行解析并创建一个在解析完成时执行的程序,而不是在解析时进行评估。这是一个更大的变化。
您确定在第二个int_expr之前放置一些代码吗?我似乎无法找到合理的方法来做到这一点。这是一个很好的技巧,但我找不到一种方法来实际告诉Bison不要评估第二个
int_expr
,而不会破坏整个评估。
您必须编写代码,以便在不应评估时不进行评估。 Bison的语法是:
| int_expr '&&' {...code 1...} int_expr {...code 2...}
'代码1'将检查$1
并安排停止评估(设置全局变量或类似的东西)。 “代码2”将有条件地评估$4
(4因为“代码1”现在为3美元)。所有评估代码都必须遵守“代码1”的要求 - 它不能评估“代码1”是否表示“不评估”。或者你可以按我的建议行事aselle suggested;分别解析和评估。
我是第二个关于The UNIX Programming Environment的建议。有一整章关于开发一个计算器(他们称之为高阶计算器的hoc
)值得一读。但是要注意,这本书是在1984年出版的,并且在C标准之前有很大的优势。 C代码中没有原型,并且(按现代标准)它需要一些自由。我确实有hoc6
(他们描述的hoc
的最后一个版本;还有现代C版本1-3) - 如果你需要,请与我联系(参见我的个人资料)。
这就是问题所在:我无法停止在规则中间进行评估,因为我无法使用
return
(我可以,但没有用;它会导致程序退出)。| intExpr '&&' { if ($1 == 0) {/* turn off a flag */ } } intExpr { /* code */}
退出$3
后,$4
会自动评估。
您可以在规则中间停止评估,但必须对表达式评估代码块进行编码以考虑可能性。当我说“停止评估”时,我的意思是“停止计算”,而不是“停止解析器”。解析必须继续;计算值的代码必须仅在需要评估时评估,而不是在不需要评估时评估。这可能是一个(呃!)全局标志,或者你可能有其他一些机制。
最好将解析器转换为代码生成器,并在解析后执行代码。这种复杂性是为什么这是一个好策略。
@JonathanLeffler:你确实是国王!这应该是一个答案!!!
现在这是一个答案。
答案 1 :(得分:1)
在计算器中进行评估之前,您几乎肯定想要生成一些其他表示形式。解析树或ast是经典方法,但简单的堆栈机器也很受欢迎。有很多很好的例子说明如何做到这一点,但我最喜欢的是 http://www.amazon.com/Unix-Programming-Environment-Prentice-Hall-Software/dp/013937681X 这显示了如何使用像yacc(old bison)中所做的简单的直接评估工具,并将其一直带到一种几乎与BASIC一样强大的编程语言。所有这一切都在很少的页面这是一本非常古老的书,但非常值得一读。
您还可以查看SeExpr http://www.disneyanimation.com/technology/seexpr.html 这是一个简单的表达语言计算器,用于标量和3个向量。如果你看https://github.com/wdas/SeExpr/blob/master/src/SeExpr/SeExprNode.cpp 在313行,你会看到&amp;&amp;他执行eval()函数:
void
SeExprAndNode::eval(SeVec3d& result) const
{
// operands and result must be scalar
SeVec3d a, b;
child(0)->eval(a);
if (!a[0]) {
result[0] = 0;
} else {
child(1)->eval(b);
result[0] = (b[0] != 0.0);
}
}
该文件包含表示解析树中的操作的所有对象。在解析代码时生成这些对象(这些是yacc中的操作)。希望这会有所帮助。