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ルールの解析に関するメッセージしか表示されません。

さらにデバッグメッセージは、パーサーがa式のまで到達してからa+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 }
4

1 に答える 1

4

最初のポイント:コンパイル可能なソースコードを提供しないことについて、私はあなたを少し嫌っていました。コードをテストするには、ASTタイプ、%token宣言などを再発明する必要がありました。

問題は、

| eof { raise End_of_file }

字句解析ルール、および文法。

Enf_of_file文法がファイルの終わりに自然に遭遇しない場合は、レクサーでEOFを上げることをお勧めします。たとえば、自然に\n終了または終了する文法は;;、この時点で解析を停止し、EOFトークンに到達することはありません。

しかし、あなたの文法はそれらの1つではありません。パーサーがに到達するDEF proto expr .と、次のトークンを要求して、そうでないかどうかを偶然に確認します。そのため、パーサーはOPレクサーを呼び出し、それを見つけEOFてブローします。

これが私の修正です:

lex.mllの場合:

    | eof { EOF }

parse.mlyの場合:%token EOF

%start stmt_eof
%type <Types.stmt> stmt_eof

[...]

stmt_eof: stmt EOF { $1 }

最後に、メンヒルをocamlyaccの代わりとして真剣に検討する必要があります。より明確な文法ファイル(たとえば、毎回非終端記号ocamlyaccを再発明する必要がない)、より優れたエラーメッセージ、デバッグ機能を使用して、すべてがより適切に実行されます...foo_list

于 2011-05-07T05:24:17.897 に答える