共享迭代器

4
我正在用Scala编写一个(简单的)编译器,已经将分词器变成了可迭代对象,现在需要编写解析器。计划使用递归下降策略,因此解析器将被分成多个方法,每个方法都调用其他一些方法。
我认为维护分词器迭代器的状态并在各个方法之间共享它是必要/可取的。这是正确的吗?如果是,我该如何做?如果不是,有哪些替代方案?

读完标题后,我的第一个想法是“不要这样做!” - ziggystar
2个回答

5
如果你必须维护迭代器的状态,不要使用迭代器!迭代器适用于当你可以随着操作破坏它们的状态时。
可能可以使用流。流有一个习惯,就是因为引用在不应该存在的地方持续存在(但如果你思考一下,你可以发现它们存在),所以它们不会释放内存。因此,如果你从一个迭代器开始,你可以将其.toStream并传入子流,然后将流传递给进一步处理。但是,如果你想避免保留所有内容,请务必小心,不要保留对流头的引用。
另一种方法是将所有内容都倒入向量或数组中,并将整个问题保留在内存中;然后你可以在进行操作时删除不相关的部分(或提前索引)。
最后,如果你绝对确定不需要回溯,那么你可以直接使用迭代器而不必担心“维护状态”的问题。也就是说,当你从子方法返回时,你已经恰好消耗了正确的标记,没有多余的标记,你可以自由地继续解析。为了使这个工作正常,返回值不能至少有一个“我没有消耗的下一个标记”,你需要能够预测最后一个标记的位置(例如,一个长度不受限制的列表必须以一个列表中的标记结尾,所以{1,2,3}可以是一个列表(如果你在看到{时进入列表处理,并在遇到}时退出),但不是1,2,3+7(因为你会在意识到列表已经结束之前消耗掉+))。

1
你可以构建令牌迭代器并将其传递给每个递归解析器调用,以便令牌级别的解析从中读取:
def parse2(tokens: Iterator[String]) = List(tokens.next, tokens.next)
def parse1(tokens: Iterator[String]) = List(parse2(tokens), parse2(tokens))

val tokens = List("a","b","c","d").iterator
val parsed = parse1(tokens) //List(List(a, b), List(c, d))

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接