注意:我在用这个来自西蒙·马洛的亚历克斯模板。
我想为C风格的评论创建lexer。我的当前方法为开始注释、结束、中间和单线创建单独的标记。
%wrapper "monad"
tokens :-
<0> $white+ ;
<0> "/*" { mkL LCommentStart `andBegin` comment }
<comment> . { mkL LComment }
<comment> "*/" { mkL LCommentEnd `andBegin` 0 }
<0> "//" .*$ { mkL LSingleLineComment }
data LexemeClass
= LEOF
| LCommentStart
| LComment
| LCommentEnd
| LSingleLineComment/*blabla*/,我将得到8个令牌,而不是一个!//部件?monad包装器的情况下,lex注释可以吗?发布于 2014-07-12 08:18:22
看看这个:
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其中Lexeme代表您的令牌类型。AlexInput参数具有表单(用于monad包装):
(AlexPosn,Char,Bytes,String)
Int参数是存储在String字段中的匹配的长度。因此,大多数令牌处理程序的形式将是:
handler :: AlexInput -> Int -> Alex Lexeme
handler (pos,_,_,inp) len = ... do something with (take len inp) and pos ...一般来说,处理程序似乎可以忽略Char和[Bytes]字段。
处理程序commentBegin和commentEnd可以忽略AlexInput和Int参数,因为它们只匹配固定长度的字符串。
commentBody处理程序通过调用alexGetByte来积累注释体,直到找到"*/“。据我所知,C注释可能不是嵌套的,因此注释以"*/“的第一次出现结束。
注意,注释体的第一个字符位于match0变量中。事实上,我的代码中有一个错误,因为它不能正确匹配"/**/“。它应该看看match0来决定是从loop开始还是从loopStar开始。
您可以使用相同的技术来解析"//“样式注释-或任何需要非贪婪匹配的标记。
另一个关键点是,像$white+这样的模式使用开始代码进行限定:
<0>$white+这样做是为了使它们在处理注释时不处于活动状态。
您可以使用另一个包装器,但是请注意,AlexInput类型的结构可能不同--例如,对于基本包装器,它只是一个三元组:(Char,[Byte],String)。只需查看生成的AlexInput文件中的.hs定义即可。
最后一个音符..。当然,使用++积累字符的效率相当低。您可能希望对累加器使用Text (或ByteString)。
https://stackoverflow.com/questions/24709175
复制相似问题