F# fslex中的Lua长字符串

F# fslex中的Lua长字符串,f#,lua,fslex,ocamllex,F#,Lua,Fslex,Ocamllex,我在业余时间一直在使用Ocamlex手册作为参考,开发LuaFSlex lexer 我在尝试正确地标记长字符串时遇到了一些障碍。“长字符串”由'['('=')*'['和']'('='))*']'标记分隔;=符号的数量必须相同 在第一个实现中,lexer似乎无法识别[[模式,尽管有最长的匹配规则,但仍生成两个LBRACKET标记,而[=[和正确识别的变体。此外,正则表达式未能确保使用正确的结束标记,在第一个']'('=')*']'捕获时停止,而不管实际的长字符串“级别”。此外,fslex似乎不支持

我在业余时间一直在使用Ocamlex手册作为参考,开发LuaFSlex lexer

我在尝试正确地标记长字符串时遇到了一些障碍。“长字符串”由
'['('=')*'['
']'('='))*']'
标记分隔;
=
符号的数量必须相同

在第一个实现中,lexer似乎无法识别
[[
模式,尽管有最长的匹配规则,但仍生成两个
LBRACKET
标记,而
[=[
和正确识别的变体。此外,正则表达式未能确保使用正确的结束标记,在第一个
']'('=')*']'
捕获时停止,而不管实际的长字符串“级别”。此外,fslex似乎不支持正则表达式中的“as”构造


let lualongstring =    '[' ('=')* '[' ( escapeseq | [^ '\\' '[' ] )* ']' ('=')* ']'

(* ... *)
    | lualongstring    { (* ... *) }
    | '['              { LBRACKET }
    | ']'              { RBRACKET }
(* ... *)

我一直试图用lexer中的另一条规则来解决这个问题:


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);
               (* ... *)           
           }
但是我被卡住了,原因有两个:第一,我不认为我可以在读完长字符串后“推”下一个规则的标记;第二,我不喜欢在找到正确的结束标记之前逐字符读取的想法,这使得当前的设计毫无用处


如何在fslex中标记Lua长字符串?感谢阅读。

如果我回答了自己的问题,我表示歉意,但我想用我自己的解决方案来解决这个问题,以供将来参考

我使用LexBuffer.BufferLocalStore属性在lexer函数调用中保持状态,该属性只是一个可写IDictionary实例

注意:长括号用于长字符串和多行注释。这通常是Lua语法中被忽略的部分



let beginlongbracket =    '[' ('=')* '['
let endlongbracket =      ']' ('=')* ']'

rule tokenize = parse
    | beginlongbracket 
    { longstring (longBracketLevel(lexeme lexbuf)) lexbuf }

(* ... *)

and longstring level = parse
    | endlongbracket 
    { if longBracketLevel(lexeme lexbuf) = level then 
          LUASTRING(endLongString(lexbuf)) 
      else 
          longstring level lexbuf 
    }

    | _ 
    { toLongString lexbuf (lexeme lexbuf); longstring level lexbuf }

    | eof 
    { failwith "Unexpected end of file in string." }

以下是我用来简化将数据存储到BufferLocalStore的函数:

let longBracketLevel (str : string) =
    str.Count(fun c -> c = '=')

let createLongStringStorage (lexbuf : LexBuffer<_>) =
    let sb = new StringBuilder(1000)
    lexbuf.BufferLocalStore.["longstring"] <- box sb
    sb

let toLongString (lexbuf : LexBuffer<_>) (c : string) =
    let hasString, sb = lexbuf.BufferLocalStore.TryGetValue("longstring")
    let storage = if hasString then (sb :?> StringBuilder) else (createLongStringStorage lexbuf)
    storage.Append(c.[0]) |> ignore

let endLongString (lexbuf : LexBuffer<_>) : string = 
    let hasString, sb = lexbuf.BufferLocalStore.TryGetValue("longstring")
    let ret = if not hasString then "" else (sb :?> StringBuilder).ToString()
    lexbuf.BufferLocalStore.Remove("longstring") |> ignore
    ret
let longBracketLevel(str:string)=
str.Count(有趣的c->c='=')
让createLongStringStorage(lexbuf:LexBuffer)=
设sb=新的StringBuilder(1000)
lexbuf.BufferLocalStore。[“longstring”]StringBuilder)else(createLongStringStorage lexbuf)
storage.Append(c[0])|>ignore
let endLongString(lexbuf:LexBuffer):字符串=
让hastring,sb=lexbuf.BufferLocalStore.TryGetValue(“longstring”)
让ret=如果不是hastring,则为“”else(sb:?>StringBuilder).ToString()
lexbuf.BufferLocalStore.Remove(“longstring”)|>ignore
ret
也许它不是很实用,但它似乎正在完成工作

  • 使用标记化规则,直到找到长括号的开头
  • 切换到longstring规则和循环,直到找到相同级别的结束长括号
  • 将与同一级别的结束长括号不匹配的每个词素存储到StringBuilder中,然后将其存储到LexBuffer BufferLocalStore中
  • longstring结束后,清除BufferLocalStore

编辑:你可以在上找到该项目。词法分析和解析应该可以。我正计划使用DLR。欢迎评论和建设性批评。

顺便说一句:你可以选择解析它,而不是词法分析。@Brian,你能详细说明一下吗?:)我在试图理解如何解析一系列的非结构化数据时有点不知所措创建原始长字符串的相关标记-前提是lexer可以为字符串的所有内容生成标记。谢谢你的评论。是的,这可能不是一个好策略,我只是把它扔出去了。@Brian还是要谢谢你,我仍然在与F#和fslex打交道,每一点都有帮助。@Raine无论如何,请随时通知我们;我也对F#和Lua感兴趣。