C++中'&'符号和'*'符号在递归调用中的具体区别是什么?
时间: 2024-10-23 11:03:09 浏览: 11
在C++中,`&`(取地址运算符)和`*`(解引用运算符)在递归调用中的作用完全不同。
1. `&`符号:当你看到函数名后面跟着`&`,通常表示你在请求函数的指针。例如,在递归函数里,如果声明了一个返回自身指针的递归函数,如:
```cpp
int* recursive(int n) {
if (n == 0)
return &recursive; // 返回指向自身的指针
else
return nullptr;
```
这里`&recursive`获取的是`recursive`函数本身在内存中的地址,用于递归调用的控制。
2. `*`符号:在递归调用中,`*`通常用于解引用函数指针或数组指针,以便调用实际的函数。比如:
```cpp
void (*funcPointer)(int) = &recursive;
funcPointer(4); // 通过函数指针调用recursive(4)
```
如果递归函数需要传递自身作为参数,可以使用`*this`关键字,它实际上是一个隐含的指针,代表了当前的对象实例。
总结来说,`&`在递归中用于获取函数的地址,而`*`用于调用这个地址所指向的实际函数。在非递归上下文中,它们有着完全不同的含义。
相关问题
C++实现9+5*2/3-6递归下降语法分析器,按照使用生产使过程输出,要求有完整输出程序
实现一个递归下降语法分析器,可以分为三个步骤:词法分析、语法分析和计算表达式。
1. 词法分析
词法分析的目的是将输入的字符串分解成若干个符号,这些符号可以是数字、操作符、括号等。在本题中,我们仅需要考虑四种符号:加号、减号、乘号、除号和数字。因此,我们可以用一个枚举类型来表示这些符号:
```c++
enum Token {
TOKEN_PLUS,
TOKEN_MINUS,
TOKEN_TIMES,
TOKEN_DIVIDE,
TOKEN_NUMBER,
TOKEN_END
};
```
其中,TOKEN_END 表示输入的字符串已经全部读取完毕。
读取符号的过程可以用一个 getNextToken() 函数来实现。该函数读取输入字符串中的下一个符号,并返回它所代表的 Token 类型和数值(如果是数字)。如果输入的字符串不符合要求,函数应该返回 TOKEN_END。
```c++
#include <cctype>
#include <iostream>
#include <string>
using namespace std;
class Lexer {
public:
Lexer(const string& input) : input(input), pos(0) {}
// 读取下一个 Token
Token getNextToken() {
// 跳过空格
while (pos < input.length() && isspace(input[pos]))
pos++;
if (pos == input.length())
return TOKEN_END;
// 读取数字
if (isdigit(input[pos])) {
int value = 0;
while (pos < input.length() && isdigit(input[pos])) {
value = value * 10 + input[pos] - '0';
pos++;
}
return TOKEN_NUMBER;
}
// 读取操作符
switch (input[pos]) {
case '+':
pos++;
return TOKEN_PLUS;
case '-':
pos++;
return TOKEN_MINUS;
case '*':
pos++;
return TOKEN_TIMES;
case '/':
pos++;
return TOKEN_DIVIDE;
default:
return TOKEN_END;
}
}
private:
const string& input; // 输入的字符串
size_t pos; // 当前读取的位置
};
```
2. 语法分析
语法分析的任务是将输入的符号序列转换成抽象语法树(AST),其中每个节点表示一个表达式或者操作符。在本题中,我们只需要考虑加、减、乘、除四种操作符,因此可以用一个 enum 类型来表示它们:
```c++
enum Operator {
OP_PLUS,
OP_MINUS,
OP_TIMES,
OP_DIVIDE
};
```
对于每个符号序列,我们可以定义一个对应的产生式来描述它的语法结构。例如,对于表达式 9+5*2/3-6,它的语法结构如下所示:
```
expression -> term { ( '+' | '-' ) term }
term -> factor { ( '*' | '/' ) factor }
factor -> NUMBER | '(' expression ')'
```
其中,expression、term、factor 都是非终结符号,NUMBER 是终结符号。
为了实现语法分析,我们需要用一个 Parser 类来表示语法分析器。该类的主要方法是 parseExpression(),它根据上述的产生式递归地解析输入的符号序列,并返回对应的抽象语法树。
```c++
class Parser {
public:
Parser(const string& input) : lexer(input) {}
// 解析表达式
int parseExpression() {
int value = parseTerm();
while (true) {
Token token = lexer.getNextToken();
if (token == TOKEN_PLUS) {
value += parseTerm();
} else if (token == TOKEN_MINUS) {
value -= parseTerm();
} else {
break;
}
}
return value;
}
private:
// 解析项
int parseTerm() {
int value = parseFactor();
while (true) {
Token token = lexer.getNextToken();
if (token == TOKEN_TIMES) {
value *= parseFactor();
} else if (token == TOKEN_DIVIDE) {
value /= parseFactor();
} else {
lexer.pos--; // 回退一个符号
break;
}
}
return value;
}
// 解析因子
int parseFactor() {
Token token = lexer.getNextToken();
if (token == TOKEN_NUMBER) {
return lexer.number;
} else if (token == TOKEN_PLUS) {
return parseFactor();
} else if (token == TOKEN_MINUS) {
return -parseFactor();
} else if (token == TOKEN_END) {
return 0;
} else {
// 读取括号内的表达式
int value = parseExpression();
token = lexer.getNextToken();
if (token != TOKEN_END && token != TOKEN_PLUS && token != TOKEN_MINUS && token != TOKEN_TIMES && token != TOKEN_DIVIDE) {
throw runtime_error("Invalid input");
}
return value;
}
}
private:
Lexer lexer; // 词法分析器
};
```
3. 计算表达式
最后,我们用一个 main() 函数来调用上述的 Lexer 和 Parser 类,并计算输入的表达式的值:
```c++
int main() {
string input = "9+5*2/3-6";
Parser parser(input);
int result = parser.parseExpression();
cout << input << " = " << result << endl;
return 0;
}
```
完整代码如下:
在编译原理实验中,如何使用C++实现一个自顶向下分析的递归下降解析器?请结合NUAA的具体要求提供实现思路。
在《南航计算机专业编译原理实验教程与满分代码分享》中,详细介绍了如何使用C++实现编译器的核心部分。自顶向下的递归下降解析器是一种语法分析技术,它根据语言的语法规则递归地分析输入的词法单元序列,构建出语法树。
参考资源链接:[南航计算机专业编译原理实验教程与满分代码分享](https://wenku.csdn.net/doc/4gjp97qrp4?spm=1055.2569.3001.10343)
首先,你需要定义语法规则,这通常以文法的形式给出,如BNF(巴科斯-诺尔范式)或EBNF(扩展的巴科斯-诺尔范式)。以一个简单的算术表达式为例,其语法规则可能包含以下几个部分:
Expr ::= Term { (“+” | “-”) Term }
Term ::= Factor { (“*” | “/”) Factor }
Factor ::= num | “(” Expr “)”
接下来,为每个非终结符编写一个对应的C++函数。例如:
void Expr() {
Term();
while (lookahead == '+' || lookahead == '-') {
Match(lookahead);
Term();
}
}
这里的`Match`函数用于匹配当前词法单元与预期的符号,并移动到下一个词法单元。`lookahead`变量保存了下一个要匹配的词法单元。
每个函数都按照其语法规则递归调用,如果遇到非终结符则继续解析,如果是终结符则使用`Match`函数进行匹配。如果在解析过程中遇到不符合规则的输入,递归下降解析器应该能够通过回溯机制来尝试其他可能的语法规则,或者产生错误信息。
为了处理文法的左递归问题,可能需要对文法进行适当的改写,以避免解析器进入无限循环。此外,还需要为词法分析器提供一个接口,它能够读取源代码并输出对应的词法单元序列,以供解析器分析。
通过以上步骤,你可以根据NUAA的具体实验要求,使用C++实现一个自顶向下分析的递归下降解析器。建议你参考《南航计算机专业编译原理实验教程与满分代码分享》中的具体代码和讲解,这将帮助你更深入地理解实现过程,并给出正确的实验结果。
参考资源链接:[南航计算机专业编译原理实验教程与满分代码分享](https://wenku.csdn.net/doc/4gjp97qrp4?spm=1055.2569.3001.10343)
阅读全文