Recursion 如何使用多字母标识符和多位数整数递归地lex字符列表(SML中的lexing)
我正在用SML编写一个lexer。这是我第一次使用全函数语言。一般的递归是直观的,但我有一个嵌套的递归函数来标识字符串标识符,它是通过以字母(isAlpha)字符和consequentive字母和数字开头来标识的。我遇到的问题是,第一个递归函数(lexer)每次都在下一个字符上递归,而不是在字符串后面的第一个字符上递归。到目前为止,我已经想到了两种方法:保持计数并使用已经添加到字符串中的字符,或者添加另一个参数来跟踪最后一个字符,如果这两个字符都是alpha,则以某种方式跟踪它们。这些措施显然既没有效率,也不是实现这一目标的正确方法。这让我发疯,我无法概念化或形象化解决方案。任何帮助都将不胜感激Recursion 如何使用多字母标识符和多位数整数递归地lex字符列表(SML中的lexing),recursion,functional-programming,nested,sml,lexer,Recursion,Functional Programming,Nested,Sml,Lexer,我正在用SML编写一个lexer。这是我第一次使用全函数语言。一般的递归是直观的,但我有一个嵌套的递归函数来标识字符串标识符,它是通过以字母(isAlpha)字符和consequentive字母和数字开头来标识的。我遇到的问题是,第一个递归函数(lexer)每次都在下一个字符上递归,而不是在字符串后面的第一个字符上递归。到目前为止,我已经想到了两种方法:保持计数并使用已经添加到字符串中的字符,或者添加另一个参数来跟踪最后一个字符,如果这两个字符都是alpha,则以某种方式跟踪它们。这些措施显然既
exception LexerError;
datatype sign =
Plus
| Minus
;
datatype atom =
T
| NIL
| Int of int
| Ident of string
;
datatype token =
Lparen
| Rparen
| Dot
| Sign of sign
| Atom of atom
;
(* implement lexid *)
fun lexid (x::xs) = if Char.isAlpha(x) orelse Char.isDigit(x) then (String.str x) ^ lexid(xs)
else ""
| lexid [] = ""
;
(* implement lexint NOT COMPLETED*)
fun lexint x = valOf(Int.fromString(String.str x))
;
(* complete implementation of lexer *)
fun lexer (#"." :: t) = Dot :: lexer(t)
| lexer (#"(" :: t) = Lparen :: lexer(t)
| lexer (#")" :: t) = Rparen :: lexer(t)
| lexer (#"p" :: #"l" :: #"u" :: #"s" :: t) = Sign(Plus) :: lexer(t)
| lexer (#"m" :: #"i" :: #"n" :: #"u" :: #"s" :: t) = Sign(Minus) :: lexer(t)
| lexer (#"T" :: t) = Atom(T) :: lexer(t)
| lexer (#"N" :: #"I" :: #"L" :: t) = Atom(NIL) :: lexer(t)
| lexer (#" " :: t) = lexer(t)
| lexer (#"\n" :: t) = lexer(t)
| lexer (#"\t" :: t) = lexer(t)
| lexer (#"\r" :: t) = lexer(t)
| lexer (h :: t) =
if Char.isAlpha(h) then Atom(Ident((lexid (h::t)))) :: lexer(t)
else if Char.isDigit(h) then Atom(Int((lexint h))) :: lexer(t)
else Atom(Ident("test")) :: lexer(t)
| lexer [] = []
;
fun print_tokens [] = print("\n")
| print_tokens (Lparen :: t) = (print("Lparen "); print_tokens(t))
| print_tokens (Rparen :: t) = (print("Rparen "); print_tokens(t))
| print_tokens (Dot :: t) = (print("Dot "); print_tokens(t))
| print_tokens (Sign(Plus) :: t) = (print("Plus "); print_tokens(t))
| print_tokens (Sign(Minus) :: t) = (print("Minus "); print_tokens(t))
| print_tokens (Atom(a) :: t) =
(case a of
T => (print("Atom(T) "); print_tokens(t))
| NIL => (print("Atom(NIL) "); print_tokens(t))
| Int i => (print("Atom(Int(" ^ Int.toString(i) ^ ")) "); print_tokens(t))
| Ident s => (print("Atom(Ident(" ^ s ^ ")) "); print_tokens(t)))
;
fun reader(copt: char option, is, l) =
case copt of
NONE => (TextIO.closeIn is; l)
| SOME(c) => reader (TextIO.input1 is, is, (l@[c]))
;
val args = CommandLine.arguments();
val ins = TextIO.openIn(hd(args));
print_tokens(lexer(reader(TextIO.input1 ins, ins, [])));
val _ = OS.Process.exit(OS.Process.success)
常见的解决方案是使用一个函数,该函数使用单个令牌并返回一对
(令牌,剩余)
,其中剩余
是提取令牌之后的输入
然后可以在递归词法分析器中使用它
一个非常简单的例子:
fun lexer [] = []
| lexer ts = let (t, rest) = token ts
in
t :: lexer rest
end;
fun token (#"." :: t) = (Dot, t)
| token (#"(" :: t) = (Lparen, t)
| token (#")" :: t) = (Rparen, t)
| token (#"p" :: #"l" :: #"u" :: #"s" :: t) = (Sign Plus, t)
...
| token (#" " :: t) = token t
| token (#"\n" :: t) = token t
| token (#"\t" :: t) = token t
| token (#"\r" :: t) = token t
| token (h :: t) =
if Char.isAlpha h then lex_identifier (h::t)
else if Char.isDigit h then lex_integer (h::t)
else (Ident("test"), t)
| token [] = (Error, []);
请注意,我在孟菲斯上大学,由于缺水和极端的南方风暴,我们已经一个星期没有上课了,所以我非常渴望学习这些材料,非常担心我的班级落后。