2011-03-27 2 views
5

여기 내 로프 끝에 있습니다. 나는 ocamllex에서 일할 수있는 어떤 것도 얻을 수 없으며, 그것은 나를 미치게합니다. 내가 컴파일하고 일을 실행할 때, 나는 매우에 오류가 발생, 그러나OCaml lex : 전혀 작동하지 않습니다.

a=b; 

: 여기

{ 

open Parser 

} 

rule next = parse 
    | (['a'-'z'] ['a'-'z']*) as id { Identifier id } 
    | '=' { EqualsSign } 
    | ';' { Semicolon } 
    | '\n' | ' ' { next lexbuf } 
    | eof { EOF } 

내가 입력로 전달하는 파일의 내용은 다음과 같습니다이 내 .mll 파일입니다 첫 번째 문자는 유효하지 않다고 말합니다. 정직하게 무슨 일이 일어나고 있는지 전혀 모르겠다. 구글은 나를 전혀 도와주지 않았다. 이것이 어떻게 가능한가? 보시다시피, 저는 정말로 여기에서 곤란합니다.

편집 :

내가 파서에 포기 너무 오랫동안 일하고 있었다. 이제이 파일이 내 주 파일의 관련 코드입니다.

let parse_file filename = 
    let l = Lexing.from_channel (open_in filename) in 
    try 
     Lexer.next l;() 
    with 
     | Failure msg -> 
     printf "line: %d, col: %d\n" l.lex_curr_p.pos_lnum l.lex_curr_p.pos_cnum 

"줄 : 1, col : 1"을 인쇄합니다.

+0

식별자와 같은 생성자를 정의한 ML 파일을 제공 할 수 있습니까? 또한 ocamllex와 ocamlc가 컴파일 타임에 불평하지 않았 음을 확인할 수 있습니까? – Surikator

+0

이들은 parser.mly에서 표준으로 정의되었으며 불평하지도 않았습니다. – marsolk

+1

@marsolk : 궁금합니다. 이것을 알아 냈습니까? 문제는 무엇 이었습니까? – lebowski

답변

10

해당 ocamlyacc 파서가 없으면 렉서가 완벽하게 작동하므로 아무도 코드에서 문제를 찾을 수 없습니다!

필자는 식별자 쌍의 목록을 구성하는 다음과 같은 작은 파서 (parser.mly)를 작성했습니다. 입력 "a = b;" 싱글 톤 목록 [("a", "b")]을 제공해야합니다.

%{%} 

%token <string> Identifier 
%token EqualsSign 
%token Semicolon 
%token EOF 

%start start 
%type <(string * string) list> start 

%% 

start: 
| EOF {[]} 
| Identifier EqualsSign Identifier Semicolon start {($1, $3) :: $5} 
; 

%% 

파서 나는, 우리는 문자열을 구문 분석하는 다른 파일 (main.ml)를 만들 약속 무엇을 사용하는지 여부를 테스트하려면 "A = B가;" 결과를 인쇄합니다. 불만없이

let print_list = List.iter (fun (a, b) -> Printf.printf "%s = %s;\n" a b) 
let() = print_list (Parser.start Lexer.next (Lexing.from_string "a=b;")) 

코드를 컴파일한다 (예컨대 ocamlbuild main.byte) 및 프로그램을 출력해야 "A = B를 「 약속대로 최신 편집에 대응


:

일반적으로, 나는 (Invalid_argument 또는 실패 등) 고장이나 오용을 표시하기위한 것입니다 표준 라이브러리의 예외를 잡는 것은 좋은 아이디어라고 생각하지 않습니다. 그 이유는 라이브러리를 통해 어디에서나 사용되어 어떤 함수가 예외를 발생 시켰는지, 왜 그렇게했는지 알 수 없기 때문입니다.

또한 유용한 정보만을 던지고 있습니다. 오류 메시지! 오류 메시지는 문제의 원인이 무엇인지 알려 주어야합니다 (최선의 추측은 IO 관련 문제입니다). 따라서 오류 메시지를 인쇄하거나 예외를 최상위로 전달해야합니다. 개인적으로 나는 후자의 옵션을 선호한다.

그러나 구문 적으로 부적절한 입력을 적절한 방식으로 처리하려고합니다. 이를 위해 렉서에서 새로운 예외를 정의하고 유효하지 않은 토큰을 포착하는 기본 케이스를 추가 할 수 있습니다.

{ 
    exception Unexpected_token 
} 
... 
| _ {raise Unexpected_token} 

지금, 당신은 이전과는 달리, 예외가 구문 적으로 유효하지 않은 입력에 특정, 주요 파일에 새로 정의 된 예외를 잡을 수 있습니다. 결과적으로 예외의 근원과 원인을 알기 때문에 이전보다 훨씬 의미있는 일을 할 기회를 얻게됩니다.

매우 임의의 OCaml 개발 힌트 : 디버그 정보가 활성화 된 상태에서 프로그램을 컴파일하면 환경 변수 OCAMLRUNPARAM을 "b"(예 : export OCAMLRUNPARAM = b)로 설정하면 캐치되지 않은 예외에 대한 스택 추적이 가능합니다!

+1

필자는 오랫동안 노력한 후에 필자가 파서를 사용하지 않고 테스트 했음에도 불구하고 여전히이 오류를 제공한다고 언급 했어야한다고 생각합니다. 주 파일의 코드로 게시물을 편집합니다. – marsolk

+0

일반적으로, 나는 그렇지 않다. 이 경우,'Failure ("lexing : empty token")'을 얻었는데, 이것은 렉서의 어떤 것과도 일치하지 않는 문자를 보았다는 것을 발견했다. 결국, 나는 또 다른 규칙을 넣었다 :'| _ as c {Printf.printf "인식 할 수없는 문자 : % c \ n"c; raise (Failure "")}' , 그리고 이제는 "Unrecognized character : a"를 출력합니다. 그러나, 나는 디버깅 정보로 무슨 일이 일어나는지 보려고 노력할 것이다. – marsolk

6

btw. ocamllex는 정규 표현식에서 '하나 더'에 대한 + 연산자를 할 수 있기 때문에이

['a'-'z']+ 

방법이다 (당신의

['a'-'z']['a'-'z']* 
1

난 그냥 똑같은 고민했다 동일합니다 I 이 질문을 발견했다), 마침내 내가 실수로 입력 파일에 대한 경로를 대신 Sys.argv.(1)으로 지정했다는 것을 깨달았다. LOL

정말 도움이 되길 바랍니다! :)

-1

정규 표현식에 식별자가있는 것처럼 보입니다. 이렇게하면 렉서가 a = b를 인식하지 못하게되지만 여전히 a = b를 인식해야합니다.