存储前缀表达式(递归)

Storing Prefix Expression (Recursive)

本文关键字:递归 表达式 前缀 存储      更新时间:2023-10-16

感谢阅读。我真的需要一些帮助。我遇到了一个问题,涉及到我使用递归方法来存储用户输入的完全标记前缀表达式。在这个特殊的例子中,数字用符号"n"来标识,而符号和诸如此类的东西就是它们本身。例如:

%18+14/(12-11)-1183%17

将输入命令提示符如下:

  • %n18/n14-n12 n11%n1183 n17

现在,在项目的早期,我的任务是存储中缀表达式,但已经构建的代码给了我很多帮助。下面是我对一个完全括号化的中缀函数的处理。我必须使用类似的方式创建一个方法(实际上是在同一个文件中),然后从那里开始使用它。我已经让打印功能正常工作了,所以我现在真的只是想让存储器正常工作。以下是读取中缀表达式的代码:

Expr * readFPInfix(std::istream & infile)
{
    static std::string ops("*+/%-");
    char symbol;
    infile >> symbol;
    if (symbol == 'n')
    {
        long number;
        infile >> number;
        return new Atom(number);
    }
    else if (symbol == '(')
    {
        Expr * left = readFPInfix(infile);
        char op;
        infile >> op;
        if (ops.find(op) == std::string::npos) {
            std::cout << "Unknown operator symbol '" << op << "'" << std::endl;
            system("pause");
            exit(0);
        }
        Expr * right = readFPInfix(infile);
        infile >> symbol;
        // read the ending right parenthesis
        if (symbol != ')') {
            std::cout << "Invalid symbol '" << symbol << "':  ')' expected" << std::endl;
            system("pause");
            exit(0);
        }
        switch (op)
        {
        case '*':
            return new Times(left, right);
        case '+':
            return new Plus(left, right);
        case '/':
            return new Divide(left, right);
        case '%':
            return new Mod(left, right);
        case '-':
            return new Subtract(left, right);
        default:
            std::cout << "Read error" << std::endl;
            system("pause");
            exit(0);
        }
    }
    else
    {
        std::cout << "Invalid symbol '" << symbol << "':  'n' or '(' expected" << std::endl;
        system("pause");
        exit(0);
    }
}

现在,我假设我们必须使用相同的东西,所以我的主要问题是阅读这个该死的表达式。我知道,在这种方法中,我们逐个符号地读取它,然后根据提示测试该符号,以测试它是运算符还是数字。好吧,很酷。但是我如何左右移动,这样我就可以把它输入到Plus(左,右)之类的东西中。我真的很挣扎,所以任何帮助都将不胜感激。

注意:这是一项家庭作业,所以如果有人给我答案,那就没问题,或者伪代码也没问题。非常感谢。

现在。。。正如我在上面所评论的,这不是一个我们简单地交给你设计或编码的地方。然而,我想我仍然可以解释中缀是如何分解为左操作数和右操作数的。

中缀中只有两种类型的操作数:终端(常量或变量)和表达式。

每个表达式都有相同的形式:

operator left-operand right-operand

事实证明,您可以使用以下两条规则轻松地解析复杂的表达式:每次点击运算符时,都会启动一个新的表达式(即进行递归调用)。让我们来看看您给定示例的法律版本:

% 18 + 14 / - 12 11 % 1183 17

我们发现的第一件事是%;保存运算符,然后在剩下的字符串18 + 14 / - 12 11 % 1183 17中查找左右操作数。左派是微不足道的;那里有一个常数。

// expression 1
operator = '%'
left = '18'
right = '+ 14 / - 12 11 % 1183 17'

这为我们提供了整个顶级表达式。但是,我们仍然需要解析正确的操作数。这是另一种表达方式。将+作为运算符,并解析两个操作数。

同样,左派是微不足道的;右边是表达式的其余部分:

// expression 2
operator = '+'
left = '14'
right = '/ - 12 11 % 1183 17'

同样,我们仍然需要解析正确的操作数。指定/为操作员,然后。。。哈这一次,左边的操作数是一个表达式。我们仍然将整个字符串传递给表达式解析器。

// expression 3
operator = '/'
left = <something from> '- 12 11 % 1183 17'
right = <on hold>

以下是我迄今为止跳过的步骤。当我们进行递归调用时,我们传递整个表达式。左边的操作数求值将吃掉它需要的任何东西,剩下的留给右边的求值。让我们现在更仔细地了解一下。。。

//表达式4运算符='-'左侧=12右侧=11余数="%1183 17"

这个余数必须传递回调用实例,以便用于正确的运算符。找到左操作数(并将其求值为1)后,我们将返回表达式3:的解析

// expression 3
operator = '/'
left = 1
right = '% 1183 17'

现在,我们同样解析正确的字符串,得到1183%17或10的值。请注意,我并不是在引导我们完成这个表达式5;与表达式4一样,这是一个简单的操作,['%',1183,17]。

最后,我们返回到表达式3并执行1/10(整数运算为0)。0成为表达式2的右侧,我们在表达式2中计算14+0。最后,这个结果变成了表达式1的右侧,最终答案是18%14或4。

现在。。。你能在那里编程吗?