将节点放入不应存在的分析树中
我正在为一种语言编写解析器,并且该扫描器被设计用于
基于布尔标志。
现在,在解析器中,我不想把所有这些终端的语法混淆在一起,它们应该被我正在构建的解析树“自动地”自动“吞噬”。
要做到这一点“魔术”,我想我会链接终端(简单链接的循环列表),所以我可以迭代它们并在发生缩减时“填空”(我使用LALR(1)解析器生成器) 。
这听起来像一个理智的想法,虽然有一个问题。 记得我说过“要么退还要么没有”? 在情景(2)中,我会释放终端,因为谁知道接下来会发生什么? 我不想要任何内存泄漏。
但在情景(1)中,我无法解放终端,因为基于他们,我将决定进一步减少“填空”过程应该停止的地方。
我也无法有条件地释放它,因为同样的原因:我不知道接下来会发生什么。 如果没有任何“填充空白”过程触发? 如果根本没有进一步减少会怎样?
你有类似的问题吗? 你是如何解决它的?
注意:这是我的想法,我可能没有足够清楚地解释它,请问,我会编辑我的问题。 这个场景实际上有点复杂,我不是从头开始写的,我可以利用我的想象力,我将它融入其他东西,所以很可能我会回答“我做不到这一点由于环境的限制“。
附录
我想到的唯一一个真正的好主意是分叉和改进解析器生成器,我已经在一些小的地方在这里和那里做了一些解决,以克服上面提到的一些限制。
你的词汇有点奇怪。 大多数解析器旨在识别语言的语法。 通常语言定义定义了终端的一些概念,并且明确地排除了“空白”,其包括终端文本之间无意义的文本序列,通常包括空白,标签和各种独立评论。 所以解析中使用的“终端”这个词通常意味着“那些不是空白的语言原子”。 你已经明确地将其定义为包含空格,并且我认为这会导致你的悲伤。
从这个角度来看,避免使用空格解析解析器所使用的语法定义的最简单方法是简单地让词法分析器不将空白传递给解析器。 那么你的语法不需要指出它们是如何处理的(是的,这样做的语法真的很混乱),解析器不必担心它们,它们也不会出现在树中。
如果你正在构建一个编译器或解释器,那么忽略空白是最简单的。
如果您正在构建一个重新构建的解析器(请参阅我们的DMS Software Reengineering Toolkit,然后在AST中捕获注释(至少)非常重要,因为最终需要从构建的AST中重新生成文本,并且如果重新生成的文本包含评论也是如此[你可以用其他方式做到这一点,但它们并不那么容易]。
DMS词法分析器在内部生成“微型”标记,这是您的语言标记,空白和注释的概念。 它抛出空白微型令牌,因为它们根本不添加任何东西(参见上面的讨论)。 正如您所期望的,它将传统令牌传递给解析器。 它将注释标记粘贴到前面或后面的语言标记,具体取决于标记类型和遇到的位置; 对于C,a / * ... * /在将令牌附加到它之前看到,并且// ...注释附加到前一个令牌(具有一些更细微的细节,这里未讨论)。 然后,解析仍然只能看到语言标记,所以语法不是不必要的复杂,并且如果附加到标记的所有信息都放置在树中,则评论会继续进行。
现在,人们通常需要“抽象”语法树; 他们想要抛弃诸如“(”和“)”之类的东西。 我上面描述的方案附加了对这些甚至具体的令牌的评论。 现在有一个复杂的问题:如果你将(..)令牌从树中移出,附加的评论就会消失。 哎呀。 因此,DMS解析器做了一件复杂的事情:在树中具有逻辑位置但实际上并不存在的令牌(“消除的终端”)被附加到父树节点,注释表明它们属于丢失的子令牌。 是的,实施这个确实是一个PITA。 好消息是,我们只需要在DMS的一般解析机器中执行一次,并且它适用于许多种语言。 但这意味着您必须愿意构建一个不寻常的(“重构”)解析器,并且我们有商业动机来这样做。
编辑:目前尚不清楚OP为什么要这样做,但他坚持要在树中捕获空白。 由于他没有告诉我们为什么,我会猜测:他想要令牌/树节点的精确列信息。 这并不困难:教授词法分析器跟踪位置(行/列),并将每个标记(例如注释等微型标记)与开始/结束位置贴在一起,并让解析存储该信息那个树。 这样避免了在树中留下空白。 (DMS也是这样做的,因为在报告问题时,精确的信息是有用的,并且在重新生成代码时,通常需要将代码放回原始位置(至少是同一列)。
编辑2:如果OP坚持捕获空白,他可能会考虑探索无扫描GLR分析。 这会保留输入流中的每个字符,包括空格。
链接地址: http://www.djcxy.com/p/8807.html上一篇: Putting nodes into the parse tree which shouldn't be there
下一篇: Url.Action() includes unwanted parameters, trying to have more control