看看这个:
http://lpaste.net/107377
用类似的东西进行测试:
echo "This /* is a */ test" | ./c_comment
应该打印:
Right [W "This",CommentStart,CommentBody " is a ",CommentEnd,W "test"]
您需要使用的关键 alex 例程是:
alexGetInput -- gets the current input state
alexSetInput -- sets the current input state
alexGetByte -- returns the next byte and input state
andBegin -- return a token and set the current start code
每个例程commentBegin
,commentEnd
并commentBody
具有以下签名:
AlexInput -> Int -> Alex Lexeme
whereLexeme
代表你的令牌类型。该AlexInput
参数具有以下形式(对于 monad 包装器):
(AlexPosn,字符,[字节],字符串)
Int
参数是存储在String
字段中的匹配长度。因此,大多数令牌处理程序的形式将是:
handler :: AlexInput -> Int -> Alex Lexeme
handler (pos,_,_,inp) len = ... do something with (take len inp) and pos ...
一般来说,处理程序似乎可以忽略Char
and[Bytes]
字段。
处理程序commentBegin
和commentEnd
可以忽略AlexInput
和Int
参数,因为它们只匹配固定长度的字符串。
commentBody
处理程序通过调用累积注释正文来工作,alexGetByte
直到找到“*/”。据我所知,C 注释可能不会嵌套,因此注释在第一次出现“*/”时结束。
请注意,注释正文的第一个字符在match0
变量中。事实上,我的代码中有一个错误,因为它不能正确匹配“/**/”。它应该看match0
以决定是否从loop
或开始loopStar
。
您可以使用相同的技术来解析“//”样式注释 - 或任何需要非贪婪匹配的标记。
另一个关键点是,像这样的模式$white+
是用起始码限定的:
<0>$white+
这样做是为了使它们在处理评论时不活动。
您可以使用另一个包装器,但请注意AlexInput
类型的结构可能不同——例如,对于基本包装器,它只是一个 3-tuple: (Char,[Byte],String)
。只需查看AlexInput
生成的 .hs 文件中的定义即可。
++
最后一点......当然,使用累积字符是相当低效的。您可能希望使用Text
(或ByteString
) 作为累加器。