1

使用 Alex 词法分析器我正在创建一个词法分析器来标记电子邮件“来自标头”。这是一个示例标题:

From: "John Doe" <john@doe.org>

“John Doe”被称为“显示名称”,我们假设它可以包含任何 ASCII 字符。

同样让我们假设电子邮件地址的部分可以由任何 ASCII 字符组成。

下面是我的 Alex 程序。当我在上面的“From header”上运行它时,我只得到一个令牌:

[TokenString "From: \"John Doe\" <john@doe.org>"]

显然这条规则:

$us_ascii_character+    { \s -> TokenString s }

优先于所有其他规则。为什么?

我认为优先级基于规则在我的程序中物理列出的顺序:检查输入字符串是否匹配第一个规则,如果不匹配则检查输入字符串是否匹配第二个规则,等等。不?

如何表达我的规则,以便词法分析器将“From header”标记为这些标记:

From, :, "John Doe", <, john, @, doe, ., org, >

并且显示名称和电子邮件部分可以包含任何 ASCII 字符?

这是我的亚历克斯词法分析器:

{
module Main (main) where
}

%wrapper "posn"

$digit      = 0-9           
$alpha      = [a-zA-Z]      
$us_ascii_character     = [\t\n\r\ !\"\#\$\%\&\'\(\)\*\+\,\-\.\/0123456789\:\;\<\=\>\?\@ABCDEFGHIJKLMNOPQRSTUVWXYZ\[\\\]\^_`abcdefghijklmnopqrstuvwxyz\{\|\}~\DEL]

tokens :-

  $white+           ;
  \(.*\)           ;
  From             { \s -> TokenFrom }
  :                { \s -> TokenColon }
  "                { \s -> TokenQuote }
  \<               { \s -> TokenLeftAngleBracket }
  >                { \s -> TokenRightAngleBracket }
  @                { \s -> TokenAtSign }
  \.               { \s -> TokenPeriod }
  $us_ascii_character+     { \s -> TokenString s }

{
-- Each action has type :: String -> Token

-- The token type:
data Token =
    TokenFrom                 |
    TokenColon                |
    TokenQuote                |
    TokenLeftAngleBracket     |
    TokenRightAngleBracket    |
    TokenAtSign               |
    TokenPeriod               |
    TokenString String      
    deriving (Eq,Show)
4

1 回答 1

4

您误解了选择规则的规则:

当输入流匹配多个规则时,匹配输入流最长前缀的规则获胜。如果仍有多个规则匹配相同数量的字符,则文件中最早出现的规则获胜。

文档中所述。只有当多个规则匹配一个同样长的前缀时,它们被指定的顺序才重要。

自从

$us_ascii_character+

匹配整个输入,你只会得到一个[TokenString "From: \"John Doe\" <john@doe.org>"].

要根据需要标记输入,如果我理解正确,您需要使用类似的规则

\" [^\"]* \"      { \s -> TokenString s }

(免责声明:我不知道 alex 的语法,实际上可能会有所不同)。

于 2013-06-20T22:10:25.343 回答