2011-03-27 5 views
5

私のロープの最後です。私はocamllexで働くことが何もできません、そして、それはナッツを運転しています。ここでOCaml lex:まったく動作しません。

{ 

open Parser 

} 

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

は、私が入力として渡すファイルの内容は次のとおりです:

a=b; 

しかし、私は事をコンパイルして実行すると、私は非常にエラーが出るこれは私の.mllファイルです最初の文字は、それが有効でないと言っています。私は正直に何が起こっているのか分かりませんし、Googleは私を助けてくれていません。どのようにこれを可能にすることができますか?ご覧のとおり、私は本当にここで困惑しています。

EDIT:

私はパーサをあきらめたことをあまりにも長い間働いていました。これは私のメインファイル内の関連コードです:

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")]を与える必要があります。パーサが、我々は、文字列解析し、別のファイル(main.ml)を作成し、私は約束しかどうかをテストするために

%{%} 

%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} 
; 

%% 

「= 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"に設定すると(たとえば、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を認識する必要があります。

関連する問題