Haskell 中的 Lexer - 如何模式匹配特定案例?
Lexer in Haskell - How to Pattern Match specific case?
我目前正在研究用 Haskell 编写的词法分析器,快完成了,但是 运行 遇到了一个特殊情况标记的问题。目前,我的词法分析器接受一个输入字符串并将语句分解为数字标记、变量名和特定标记,例如 "if"、"else" 和 "then"。
除了“000...”之外,它对我的所有标记都非常有效。
我被教导使用 span 函数,所以我让我的词法分析器使用 isDigit 和 isAlphaNum 布尔函数来解析输入。但是,因为“000...”以零开头,它会自动 returns 作为数字。此外,句点也是语法中的标记,因此在我的词法分析器中输入“000 ...”的结果当前为“0”“。” “。” “.”。
我不精通Haskell的语言,但是否可以使用isPrint来匹配一个字符串,并用case来处理字符串和整数的实例?我现在不知所措,似乎我尝试过的一切都破坏了我的程序。我当前的模式匹配部分如下所示:
lexer (c:cs)
| isSpace c = lexer cs
| isDigit c = lexDigit (c:cs)
| isAlphaNum c = lexString (c:cs)
| True = InvalidToken c : lexer cs
lexString
| s1 == "if" = IfToken : lexer s2
| s1 == "else" = ElseToken : lexer s2
| s1 == "then" = ThenToken : lexer s2
| s1 == "000..." = Zero : lexer s2
| True = StringToken s1 : lexer s2
where (s1,s2) = (span isAlphaNum cs)
欢迎任何帮助!
首先请注意,在 Haskell 中处理此类任务的惯用方法是使用 解析器组合器库 ,例如 parsec. (It may make sense to go the traditional parser/lexer route for some applications, but this isn't really something you should code by hand – use a lexer generator, i.e. alex。)
现在,如果您决定手动执行此操作,并且没有更具表现力的解析器组合器...您将需要在 lexDigit
中处理这种特殊情况,而不是 lexString
:
lexDigit :: String -> [Token] -- Always use type signatures!
lexDigit cs
| ("000...",s2) <- splitAt 6 cs = Zero : lexer s2
lexDigit cs = ... -- your original definition of `lexDigit`
lexString :: String -> [Token]
lexString cs = case s1 of
"if" -> IfToken : lexer s2
"else" -> ElseToken : lexer s2
"then" -> ThenToken : lexer s2
-- no clause for "000...", since it can't happen here anyway
_ -> StringToken s1 : lexer s2
where (s1,s2) = (span isAlphaNum cs)
lexer :: String -> [Token]
lexer cs@(c:cs')
| isSpace c = lexer cs'
| isDigit c = lexDigit cs
| isAlphaNum c = lexString cs
| otherwise = InvalidToken c : lexer cs'
我目前正在研究用 Haskell 编写的词法分析器,快完成了,但是 运行 遇到了一个特殊情况标记的问题。目前,我的词法分析器接受一个输入字符串并将语句分解为数字标记、变量名和特定标记,例如 "if"、"else" 和 "then"。
除了“000...”之外,它对我的所有标记都非常有效。
我被教导使用 span 函数,所以我让我的词法分析器使用 isDigit 和 isAlphaNum 布尔函数来解析输入。但是,因为“000...”以零开头,它会自动 returns 作为数字。此外,句点也是语法中的标记,因此在我的词法分析器中输入“000 ...”的结果当前为“0”“。” “。” “.”。
我不精通Haskell的语言,但是否可以使用isPrint来匹配一个字符串,并用case来处理字符串和整数的实例?我现在不知所措,似乎我尝试过的一切都破坏了我的程序。我当前的模式匹配部分如下所示:
lexer (c:cs)
| isSpace c = lexer cs
| isDigit c = lexDigit (c:cs)
| isAlphaNum c = lexString (c:cs)
| True = InvalidToken c : lexer cs
lexString
| s1 == "if" = IfToken : lexer s2
| s1 == "else" = ElseToken : lexer s2
| s1 == "then" = ThenToken : lexer s2
| s1 == "000..." = Zero : lexer s2
| True = StringToken s1 : lexer s2
where (s1,s2) = (span isAlphaNum cs)
欢迎任何帮助!
首先请注意,在 Haskell 中处理此类任务的惯用方法是使用 解析器组合器库 ,例如 parsec. (It may make sense to go the traditional parser/lexer route for some applications, but this isn't really something you should code by hand – use a lexer generator, i.e. alex。)
现在,如果您决定手动执行此操作,并且没有更具表现力的解析器组合器...您将需要在 lexDigit
中处理这种特殊情况,而不是 lexString
:
lexDigit :: String -> [Token] -- Always use type signatures!
lexDigit cs
| ("000...",s2) <- splitAt 6 cs = Zero : lexer s2
lexDigit cs = ... -- your original definition of `lexDigit`
lexString :: String -> [Token]
lexString cs = case s1 of
"if" -> IfToken : lexer s2
"else" -> ElseToken : lexer s2
"then" -> ThenToken : lexer s2
-- no clause for "000...", since it can't happen here anyway
_ -> StringToken s1 : lexer s2
where (s1,s2) = (span isAlphaNum cs)
lexer :: String -> [Token]
lexer cs@(c:cs')
| isSpace c = lexer cs'
| isDigit c = lexDigit cs
| isAlphaNum c = lexString cs
| otherwise = InvalidToken c : lexer cs'