В свободное время я работал над лексером Lua fslex, используя руководство ocamllex в качестве справочного материала.
Я столкнулся с несколькими проблемами, пытаясь правильно токенизировать длинные строки. «Длинные строки» разделены токенами '[' ('=')* '['
и ']' ('=')* ']'
; количество знаков =
должно быть одинаковым.
В первой реализации лексер, казалось, не распознавал шаблоны [[
, создавая две лексемы LBRACKET
, несмотря на правило наибольшего совпадения, тогда как [=[
и варианты распознавались правильно. Кроме того, регулярное выражение не могло гарантировать, что используется правильный токен закрытия, останавливаясь при первом захвате ']' ('=')* ']'
, независимо от фактического «уровня» длинной строки. Кроме того, fslex, похоже, не поддерживает конструкции as в регулярных выражениях.
let lualongstring = '[' ('=')* '[' ( escapeseq | [^ '\\' '[' ] )* ']' ('=')* ']'
(* ... *)
| lualongstring { (* ... *) }
| '[' { LBRACKET }
| ']' { RBRACKET }
(* ... *)
Я пытался решить проблему с другим правилом в лексере:
rule tokenize = parse
(* ... *)
| '[' ('=')* '[' { longstring (getLongStringLevel(lexeme lexbuf)) lexbuf }
(* ... *)
and longstring level = parse
| ']' ('=')* ']' { (* check level, do something *) }
| _ { (* aggregate other chars *) }
(* or *)
| _ {
let c = lexbuf.LexerChar(0);
(* ... *)
}
Но я застрял по двум причинам: во-первых, я не думаю, что смогу, так сказать, "подтолкнуть" токен к следующему правилу, как только закончу чтение длинной строки; во-вторых, мне не нравится идея чтения char за char, пока не будет найден правильный закрывающий токен, что делает текущий дизайн бесполезным.
Как я могу токенизировать длинные строки Lua в fslex? Спасибо за чтение.