Посмотри на это:
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
имеет вид (для обёртки монады):
(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
может быть другой, например. для базовой оболочки это просто 3-кортеж: (Char,[Byte],String)
. Просто посмотрите на определение AlexInput
в сгенерированном файле .hs.
Последнее замечание... накапливать символы с помощью ++
, конечно, довольно неэффективно. Вероятно, вы захотите использовать Text
(или ByteString
) для аккумулятора.
person
ErikR
schedule
12.07.2014