4

私はここでロープの終わりにいます。ocamllex で何も動作させることができず、気が狂いそうです。これは私の.mllファイルです:

{

open Parser

}

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

入力として渡すファイルの内容は次のとおりです。

a=b;

しかし、コンパイルして実行すると、最初の文字が無効であるというエラーが表示されます。正直なところ、何が起こっているのかわかりません。Google はまったく役に立ちませんでした。どうすればこれが可能になるのでしょうか? ご覧のとおり、私はここで本当に困惑しています。

編集:

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

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

「line: 1, col: 1」を出力します。

4

4 に答える 4

10

対応する ocamlyacc パーサーがなければ、レクサーが完全に正常に動作するため、誰もコードの問題を見つけることができません!

識別子のペアのリストを構築する次の小さなパーサー (parser.mly) を自由に作成しました。シングルトン リスト [("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}
;

%%

パーサーが約束したことを実行するかどうかをテストするために、文字列 "a=b;" を解析する別のファイル (main.ml) を作成します。結果を出力します。

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 や Failure など) を示すことを意図した標準ライブラリの例外をキャッチすることは良い考えではないと思います。その理由は、それらがライブラリ全体で遍在的に使用されているため、通常、どの関数が例外を発生させ、なぜそれが発生したのかがわからないためです。

さらに、唯一の有用な情報であるエラー メッセージを破棄しています。エラー メッセージには、問題の原因が示されているはずです (私の推測では、IO 関連の問題です)。したがって、エラー メッセージを出力するか、例外をトップレベルに伝播させる必要があります。個人的には、後者のオプションを好みます。

ただし、構文的に不適切な入力を適切な方法で処理したい場合もあります。このために、レクサーで新しい例外を定義し、無効なトークンをキャッチするデフォルトのケースを追加できます。

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

これで、メイン ファイルで新しく定義された例外をキャッチできます。以前とは異なり、例外は構文的に無効な入力に固有のものです。その結果、例外のソースと原因の両方がわかるため、以前よりもはるかに意味のあることを行う機会が得られます。

かなりランダムな OCaml 開発のヒント: デバッグ情報を有効にしてプログラムをコンパイルする場合、環境変数OCAMLRUNPARAMを "b" に設定すると (例: export OCAMLRUNPARAM=b)、キャッチされていない例外のスタック トレースが有効になります!

于 2011-03-27T15:11:07.453 に答える
7

ところで。+ocamllexは、正規表現で「1つ以上」の演算子を実行することもできるため、これは

['a'-'z']+

あなたと同等です

['a'-'z']['a'-'z']*
于 2011-03-28T00:24:04.110 に答える
1

私はちょうど同じことに苦労していました(これが私がこの質問を見つけた方法です)が、入力ファイルへのパスを!Sys.argv.(0)の代わりに誤って指定したことに最終的に気づきました。Sys.argv.(1)LOL

それが役立つことを本当に願っています!:)

于 2013-01-14T22:37:28.557 に答える
-1

識別子の正規表現にスペースがあるようです。これにより、レクサーが a=b を認識できなくなる可能性がありますが、それでも a = b を認識する必要があります。

于 2013-04-02T22:04:10.403 に答える