这个 C++ 解析器是如何工作的?
How does this C++ parser work?
我目前正在阅读 Bjarne Stroustrup 的 "Programming: Principles and Practice using C++",但我在理解这个特定语法的实现方式时遇到了问题。
语法及其规则如下:
Expression:
Term
Expression "+" Term
Expression "-" Term
Term:
Primary
Term "*" Primary
Term "/" Primary
Term "%" Primary
Primary:
Number
"(" Expression ")"
Number:
floating-point literal
但是,Term 是这样实现的:
double term()
{
double left = primary();
Token t = ts.get(); // get the next token from token stream
while(true) {
switch (t.kind) {
case '*':
left *= primary();
t = ts.get();
break;
case '/':
{
double d = primary();
if (d == 0) error("divide by zero");
left /= d;
t = ts.get();
break;
}
default:
ts.putback(t); // put t back into the token stream
return left;
}
}
}
为什么我们在 switch 语句中,如果标记等于“*”,则调用 left *= primary();
,而不是 left *= term()
?
我尝试用 left *= term()
替换 left *= primary();
(对除法做了同样的事情),程序仍然运行良好。但是,我不明白 Bjarne 的设计决定,即他为什么要按照他的方式实现功能。也许我在这里遗漏了什么?
提前致谢!
因为制作不是Term "*" Term
.
是Term "*" Primary
.
语法本身的原因是,如果表达式中有任何嵌套的 Term
,那么从解析的角度来看,它们将被迫 "appear" 在左侧.右侧被有效地说服仅包含主要表达式(不包含其他运算符)。当这应用于递归解析 "program" 时,结果是运算符是左关联的,导致 ((a*b)*c)
,而不是 (a*(b*c))
。
这样的文法只会"downwards",不会"upwards",否则你会陷入一大堆歧义,或者至少是一种不自然的联想,让试图写的人感到困惑用你的语言算术。
当然,对于乘法,不管怎样,算术结果在理论上都是一样的。但是,当您开始使用不同的运算符时,问题就变得很清楚了:((a*b)/c)
与 (a/(b*c))
不同。
Why do we, in the switch statement, call left *= primary();
if the token is equal to "*"
, instead of left *= term()?
因为语法说:
Term:
Primary
Term "*" Primary
Term "/" Primary
Term "%" Primary
请注意,如果 C++(和 C)有指数运算符,或者他的示例语法有一元运算符,您会看到更常见的:
Expression:
Term
Expression "+" Term
Expression "-" Term
Term:
Factor
Term "*" Factor
Term "/" Factor
Term "%" Factor
Factor:
Primary
Primary "**" Factor /* note right-associativity */
Primary:
"+" Primary
"-" Primary
Number
"(" Expression ")"
Number:
floating-point literal
我目前正在阅读 Bjarne Stroustrup 的 "Programming: Principles and Practice using C++",但我在理解这个特定语法的实现方式时遇到了问题。
语法及其规则如下:
Expression:
Term
Expression "+" Term
Expression "-" Term
Term:
Primary
Term "*" Primary
Term "/" Primary
Term "%" Primary
Primary:
Number
"(" Expression ")"
Number:
floating-point literal
但是,Term 是这样实现的:
double term()
{
double left = primary();
Token t = ts.get(); // get the next token from token stream
while(true) {
switch (t.kind) {
case '*':
left *= primary();
t = ts.get();
break;
case '/':
{
double d = primary();
if (d == 0) error("divide by zero");
left /= d;
t = ts.get();
break;
}
default:
ts.putback(t); // put t back into the token stream
return left;
}
}
}
为什么我们在 switch 语句中,如果标记等于“*”,则调用 left *= primary();
,而不是 left *= term()
?
我尝试用 left *= term()
替换 left *= primary();
(对除法做了同样的事情),程序仍然运行良好。但是,我不明白 Bjarne 的设计决定,即他为什么要按照他的方式实现功能。也许我在这里遗漏了什么?
提前致谢!
因为制作不是Term "*" Term
.
是Term "*" Primary
.
语法本身的原因是,如果表达式中有任何嵌套的 Term
,那么从解析的角度来看,它们将被迫 "appear" 在左侧.右侧被有效地说服仅包含主要表达式(不包含其他运算符)。当这应用于递归解析 "program" 时,结果是运算符是左关联的,导致 ((a*b)*c)
,而不是 (a*(b*c))
。
这样的文法只会"downwards",不会"upwards",否则你会陷入一大堆歧义,或者至少是一种不自然的联想,让试图写的人感到困惑用你的语言算术。
当然,对于乘法,不管怎样,算术结果在理论上都是一样的。但是,当您开始使用不同的运算符时,问题就变得很清楚了:((a*b)/c)
与 (a/(b*c))
不同。
Why do we, in the switch statement, call
left *= primary();
if the token is equal to"*"
, instead ofleft *= term()?
因为语法说:
Term:
Primary
Term "*" Primary
Term "/" Primary
Term "%" Primary
请注意,如果 C++(和 C)有指数运算符,或者他的示例语法有一元运算符,您会看到更常见的:
Expression:
Term
Expression "+" Term
Expression "-" Term
Term:
Factor
Term "*" Factor
Term "/" Factor
Term "%" Factor
Factor:
Primary
Primary "**" Factor /* note right-associativity */
Primary:
"+" Primary
"-" Primary
Number
"(" Expression ")"
Number:
floating-point literal