使用Alex lexer我正在创建一个lexer来标记化电子邮件“From headers”。这是一个示例标题:
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标头”标记为这些标记:
From, :, "John Doe", <, john, @, doe, ., org, >
并且显示名称和电子邮件部分可以包含任何ASCII字符?
这是我的Alex lexer:
{
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)
答案 0 :(得分:4)
您误解了选择规则的规则:
当输入流匹配多个规则时,匹配输入流的最长前缀的规则将获胜。如果仍有多个规则匹配相同数量的字符,则规则它最早出现在文件中。
如上所述in the documentation。只有当多个规则匹配同样长的前缀时,它们的指定顺序才有意义。
由于
$us_ascii_character+
匹配整个输入,只得到一个[TokenString "From: \"John Doe\" <john@doe.org>"]
。
要根据需要标记输入,如果我理解正确,您需要使用像
这样的规则\" [^\"]* \" { \s -> TokenString s }
(免责声明:我不知道alex'的语法,实际上可能会有所不同。)