2011-03-19 61 views
11

为了教育目的,我正在为IMAP协议编写一个词法分析器,而且我很难理解我应该在词法分析器和解析器之间划清界限。采取本实施例中的IMAP服务器响应的:我应该在词法分析器和分析器之间划清界限?

* FLAGS (\Answered \Deleted) 

此响应在正式的语法定义如下:

mailbox-data = "FLAGS" SP flag-list 
flag-list  = "(" [flag *(SP flag)] ")" 
flag   = "\Answered"/"\Deleted" 

由于它们被指定为字符串(又名“终端”标记)将它更正确的词法分析器发出的每一个唯一令牌,如:

(TknAnsweredFlag) 
(TknSpace) 
(TknDeletedFlag) 

或者它会同样正确发出someth荷兰国际集团这样的:

(TknBackSlash) 
(TknString "Answered") 
(TknSpace) 
(TknBackSlash) 
(TknString "Deleted") 

我的困惑是,前一种方法可能过于复杂的词法分析器 - 如果\Answered有两种不同的情况下两层含义词法分析器不会发出正确的令牌。作为一个人为的例子(这种情况不会发生,因为电子邮件地址用引号引起来),词法分析器如何处理像\ [email protected]这样的电子邮件地址?还是正式的语法旨在永远不会出现这种模糊性?

回答

7

作为一般规则,您不希望词法语法传播到语法中,因为它只是细节。例如,像C这样的计算机编程语言的词法分析器肯定会识别数字,但生成HEXNUMBER和DECIMALNUMBER标记通常是不恰当的,因为这对语法并不重要。

我想你想要什么是最抽象的标记,它允许你的语法区分与你的目的有关的情况。您可以通过在语法的一部分中引起的混淆来调解这种情况,也可以通过您在其他部分中做出的选择来进行调解。

如果您的目标仅仅是读取标志值,那么实际上您不需要区分它们,而没有关联内容的TknFlag就足够了。

如果您的目标是单独处理标志值,您需要知道您是否收到ANSWERED和/或DELETED指示。他们如何拼写拼写是无关紧要的;所以我会选择你的TknAnsweredFlag解决方案。我会转储TknSpace,因为在任何标志序列中,都必须有间隔空格(你的规格说明),所以我会尽量消除你使用任何空格压缩机制。

有时,我遇到有几十个这样的标志性事物的情况。然后你的语法开始变得混乱,如果你有每个令牌。如果语法不需要知道特定的标志,那么你应该有一个TknFlag和相关的字符串值。如果文法需要一小部分标志来区分,但其中大部分不是,那么你应该妥协:对那些对语法有影响的标志有单独的标志,并且捕捉所有TknFlag和其余的关联字符串。

关于难以有两种不同的解释:这是这些折衷之一。如果你有这个问题,那么你的标记或者需要在语法中需要它们的地方有足够好的细节,这样你就可以区分了。如果“\”在语法中的其他位置作为标记相关,则肯定可以同时生成TknBackSlash和TknAnswered。但是,如果在语法的一部分中处理某些东西的方式与另一部分不同,那么通常可以使用模式驱动的词法分析器解决此问题。将模式看作是一个有限状态机,每个都有一个关联的(子)词法分析器。模式之间的转换由作为线索的令牌触发(您必须有一个FLAGS令牌;它恰好就是您即将拿起标志值的提示)。在某种模式下,您可以生成其他模式不会生成的令牌;因此在一种模式下,您可能会生成“\”标记,但在标记模式下,您不需要。模式支持在词法分析器中非常普遍,因为这个问题比较常见,您可能会期望。有关示例,请参阅Flex文档。

事实上,你问这个问题表明你正在做出正确的选择。您需要平衡最小化令牌的可维护性目标(技术上,您可以使用令牌来解析任何ASCII字符!),并具有基本的要求,可以根据您的需要进行足够的区分。在构建了一打语法之后,这种权衡似乎很容易,但我认为我提供的经验法则非常好。

0

我建议避免分离词法分析器和分析器 - 现代分析方法(如PEGs)允许混合使用lexing和分析。这样你根本不需要令牌。

1

我想出了CFG的第一个,它需要做的任何终端是词法分析器应该识别的;否则你只是猜测正确的方式来标记字符串。