2011-05-06 4 views
0

나는 완전히 아이디어가 없습니다. 나는 이것에 매일 자유로운 분을 소비한다, 그러나 나는 아이디어에서 완전하게이다.파서 중지 중반 구문

이 내 Ocamlyacc 문법입니다 :

input: /* empty */ { } 
    | input stmt { } 

stmt: 
    extern { print_endline "Got an extern import" } 
    | func { print_endline "Got function definition" } 
    | call { print_endline "Got function call" } 

extern: 
    EXTERN proto { Extern $2 } 

func: 
    DEF proto expr { Function ($2, $3) } 

proto: 
    IDENTIFIER LPAREN id_list RPAREN { print_endline "Got prototype definition"; Prototype ($1, $3) } 

id_list: 
    /* empty */ { [] } 
    | IDENTIFIER { [$1] } 
    | id_list COMMA IDENTIFIER { $3 :: $1 } 

expr_list: 
    /* empty */ { [] } 
    | expr { [$1] } 
    | expr_list COMMA expr { $3 :: $1 } 

expr: 
    call { $1 } 
    | expr OP expr { Binary ($2, $1, $3) } 
    | IDENTIFIER { Variable $1 } 
    | NUMBER { Number $1 } 
    | LPAREN expr RPAREN { $2 } 

call: 
    IDENTIFIER LPAREN expr_list RPAREN { Call ($1, $3) } 

나는 그것이 디버그 메시지에 따라, 기능 및 프로토 타입 선언을 가지고 말해해야 def foo(a,b) a+b를 분석 시작합니다. 대신에, 나는 단지 proto 규칙을 파싱 할 때 메시지를 받는다.

추가 디버그 메시지는 aa+b까지 파서가 중단되었음을 보여줍니다. 오류 메시지가 없으며 그 밖의 것은 없습니다. stmt의 규칙 중 하나를 충족하지 않고 전체 텍스트 모자가 완전히 구문 분석 된 것처럼 멈 춥니 다.

시프트/축소 오류 또는 이와 유사한 오류가 없습니다. AST 유형도 문제가 아닙니다. 나는 더 이상 모른다, 어쩌면 다른 누군가는 도울 수있다. 분명히 그것은 명백한 것이지만 나는 그것을 볼 수 없다. 호평 렉서 :

편집

{ 
    open Parser 
} 

rule token = parse 
    | [' ' '\t' '\n'] { token lexbuf } 
    | "def" { DEF } 
    | "extern" { EXTERN } 
    | "if" { IF } 
    | "then" { THEN } 
    | "else" { ELSE } 
    | ['+' '-' '*' '/'] as c { OP c } 
    | ['A'-'Z' 'a'-'z'] ['A'-'Z' 'a'-'z' '0'-'9' '_']* as id { IDENTIFIER id } 
    | ['0'-'9']*'.'['0'-'9']+ as num { NUMBER (float_of_string num) } 
    | '(' { LPAREN } 
    | ')' { RPAREN } 
    | ',' { COMMA } 
    | '#' { comment lexbuf } 
    | _ { raise Parsing.Parse_error } 
    | eof { raise End_of_file } 
and comment = parse 
    | '\n' { token lexbuf } 
    | _ { comment lexbuf } 
+0

꽤 괜찮아 보입니다. 확실히 명백한 아무것도. lexxer? – nlucaroni

답변

4

첫 번째 점 : 나는 컴파일 가능한 소스 코드를 포기하지 않을 당신에게 조금 싫어. AST 유형, 코드를 테스트하기 위해 %token 선언문 등을 재발 명해야했습니다.

문제는

| eof { raise End_of_file } 

렉싱 규칙과 문법 사이의 미묘한 상호 작용이다.

문법이 자연스럽게 파일의 끝을 만난 적이없는 경우 렉서에서 EOF에 대해 Enf_of_file을 발생시키는 것이 좋습니다. 예를 들어, 자연스럽게 \n- 종료 또는 ;;- 종료 된 문법은이 시점에서 구문 분석을 중지하고 EOF 토큰에 도달하지 않습니다.

하지만 문법은 그 중 하나가 아닙니다. 파서가 DEF proto expr .이되면 우연히 그렇지 않은지 다음 토큰을 묻습니다. OP이므로 EOF이라는 렉서를 호출하고 불면합니다. lex.mll에서

: parse.mly에서

| eof { EOF } 

: 당신이 심각하게 같은 Menhir

%start stmt_eof 
%type <Types.stmt> stmt_eof 

[...] 

stmt_eof: stmt EOF { $1 } 

마지막으로 % 토큰 EOF 고려해야 여기

내 수정입니다 ocamlyacc에 대한 대체. 모든것을 수행합니다 ocamlyacc 더 명확하고 정확한 문법 파일 만 있습니다 (예 : 매번 foo_list 비 터미널을 재발견 할 필요가 없음). 더 나은 오류 메시지, 디버깅 기능 ...

+0

고마워, 나는'Menhir'로 전환하고'eof' 규칙을 대체했습니다. 또한 나를 미워하기는하지만 도와 줘서 고마워. – Lanbo

+0

@ Scán :'stmt' 다음에'EOF'를 요구하는 다른'stmt_eof' 규칙을 추가하는 것은 일반적으로 좋은 생각입니다 : 문법이 구문 분석 할 수있는 경우에만 구문 분석을 허용하는지 확인합니다. 전체 *. 그렇게하지 않고 문법에 버그가 있으면 문제를 경고하는 대신 구문 분석 할 수있는 가장 긴 접두사를 기꺼이 반환 할 수 있습니다. – gasche

+0

팁 주셔서 감사합니다. 이제 나의 유일한 문제는'ocamlbuild'가'Llvm' 모듈을 찾도록하는 것입니다. – Lanbo