0

我正在设计一个对流数据执行某些操作的程序。操作由运行时提供的 RPN(反向波兰表示法)表达式定义。数据从文件源流式传输,一次一个固定大小的部分。操作引用了一些当前输入的数据部分,例如data[1]. 该程序对所有输入部分应用相同的操作(并输出结果)。

实现一个 RPN 解析器非常容易,它对数字和算术运算进行运算以给出结果。然而,使用这样的实现将意味着为每个数据部分重新解析 RPN。

我想要实现的是以某种方式构建一个对象,该对象将基于数据基本操作的字母表保存曾经解析过的 RPN 实现,程序将提供输入数据(或填写输入),调用对象的operator()获取并输出结果。

一个人将如何实现这样一个类(a callable expression)并使用“非现代”C++(否C++11C++14)构造这样一个对象?

4

1 回答 1

1

由于其 RPN,操作可以建模为堆栈的一系列转换。在堆栈上加载一个输入部分,然后按顺序执行您的操作就可以了。不需要树,它隐含在操作顺序中。也不需要重新解析,它确实是一系列操作(函数或函子),而不是表示操作的符号序列。

我会选择仿函数,因为我更喜欢存储对象的引用或指针,而不是存储函数的引用或指针。您将其实现为具有重载运算符 () 的类,该运算符执行所需的堆栈转换(例如,如果它是乘法函子,则将两个顶部元素相乘)。

古老的设备就是这样工作的……

上图:古代设备以这种方式工作......

至于堆栈中存储的内容和未存储的内容:

  • 首先,您的操作数存储在与输入顺序匹配的队列中
  • 您的运算符对象,解析一次且永不更改的结果,分别存储在运算符队列中。
  • 应用“get”运算符会将一个操作数从队列传输到操作数堆栈

因此,例如,如果您想计算

sin (3 + 4) / (5 + 6)

你的操作数队列是:

[start] 3 4 5 6 [end]

您的运算符对象队列(它包含指向函子的指针,而不是符号,每个函子只有一个实例,但可能被多次引用)是:

[start] &getFunctor &getFunctor &addFunctor &sinFunctor &getFunctor &getFunctor &addFunctor &divideFunctor [begin]

您的操作数堆栈开始为空:

[top][bottom]

应用操作员队列将随后为您提供:

(get)    [top] 3 [bottom]
(get)    [top] 3 4 [bottom]
(add)    [top] 7 [bottom]
(sin)    [top] 0.657 [bottom]
(get)    [top] 5  0.657 [bottom]
(get)    [top] 5 6  0.657 [bottom]
(add)    [top] 11  0.657[bottom]
(divide) [top] 0.0597 [bottom]

如果您想将完全相同的操作应用于例如

[start]10 20 30 40[end]

只需替换操作数队列(或让您的操作数队列的开始指针指向您的操作数文件的下一个“块”,然后再次针对这个新的操作数序列运行您的操作员队列。

请注意,如上所述,操作员队列不包含操作员符号,而是指向随时可用的函数对象的指针,这些对象将在您调用它们时立即执行它们的操作,而无需重新解析或重新生成代码。

因此,如果您有大量数据:

[start of file]3 4 5 6   10 20 30 40   -1 -10 15 80 ...[end of file]

您只需继续应用相同的操作员队列,一切都会正常工作。

于 2015-07-11T21:48:36.893 回答