2010-12-04 9 views
6

ocamllex 매뉴얼을 참조로 여유 시간에 Lua fslex 렉서에서 작업했습니다.fslex의 Lua 긴 문자열

긴 문자열을 올바르게 토큰 화하는 동안 약간의 장애가 발생했습니다. "긴 문자열"은 '[' ('=')* '['']' ('=')* ']' 토큰으로 구분됩니다. = 기호의 수가 동일해야합니다.

은 첫 번째 구현에서는, 렉서는 올바르게 인식 곳 [=[ 및 변형 반면, 가장 긴 경기 규칙에도 불구하고 두 LBRACKET 토큰을 생성 [[ 패턴을 인식하지 보였다. 또한 정규 표현식은 올바른 긴 토큰 "level"과 상관없이 첫 번째 ']' ('=')* ']' 캡처에서 멈추는 올바른 닫기 토큰이 사용되었는지 확인하지 못했습니다. 또한 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로 토큰화할 수 있습니까? 읽어 주셔서 감사합니다.

+0

Offhand, 그냥 언급하고 싶었 : 당신은 항상 그것을 렉스보다 구문 분석하도록 선택할 수 있습니다. – Brian

+0

@ 브라이언, 좀 자세히 설명해 주시겠습니까?:) 나는 원래 긴 문자열을 생성하기 위해 관련없는 토큰 시퀀스를 파싱하는 방법을 이해하려고 노력하면서 손실을 조금 겪고 있습니다. 렉서가 문자열의 모든 내용에 대해 토큰을 생성 할 수 있다면 말입니다. 귀하의 의견에 감사드립니다. – Raine

+0

그래, 좋은 전략은 아닐거야, 그냥 던져 버릴 뿐이야. – Brian

답변

5

나는 내 자신의 질문에 답변을해도 사과하지만 나중에 참조 할 수 있도록 문제에 대한 해결책을 제공하고 싶습니다.

LexBuffer < _>을 사용하여 lexer 함수 호출간에 상태를 유지합니다. BufferLocalStore 속성, 쓰기 가능한 IDictionary 인스턴스입니다.

참고 : 긴 괄호는 긴 문자열과 여러 줄 주석 모두에서 사용됩니다. 이것은 종종 루아 문법의 간과 된 부분입니다.

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 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에 저장하는 데이터를 단순화하는 데 사용하는 함수입니다.

  • 긴 브래킷의 시작은 longstring 규칙 및 루프
  • 스위치를 찾을 때까지
  • 상점과 일치하지 않는 모든 어휘를 발견 동일한 수준의 닫는 긴 브래킷 때까지 토큰 화 규칙을 사용 LexBuffer BufferLocalStore에 저장되는 StringBuilder에 같은 레벨의 닫는 긴 대괄호.
  • longstring이 끝나면 BufferLocalStore를 지 웁니다.

편집 : 프로젝트는 http://ironlua.codeplex.com에서 찾을 수 있습니다. 렉싱과 구문 분석은 괜찮습니다. DLR을 사용할 계획입니다. 논평과 건설적인 비판을 환영합니다.

+0

작동하는 경우 대답을 수락 ;-) –