2017-02-22 5 views
2

私はocamllexとmenhirで構築したレクサーとパーサを持っています。トップレベルでそれらを使用すると動作しますが、それらが構成するモジュールは未定義です。ocamlモジュールが定義されていないのはなぜですか?

~: ocamlbuild -clean 
~: ocamlbuild PhoebeParser.cma PhoebeLexer.cma 
ocamlopt.opt unix.cmxa -I /Users/Tim/.opam/system/lib/ocamlbuild /Users/Tim/.opam/system/lib/ocamlbuild/ocamlbuildlib.cmxa myocamlbuild.ml /Users/Tim/.opam/system/lib/ocamlbuild/ocamlbuild.cmx -o myocamlbuild 
menhir --infer --raw-depend --ocamldep 'ocamldep.opt -modules' PhoebeParser.mly > PhoebeParser.mly.depends 
ocamldep.opt -modules PhoebeAST.ml > PhoebeAST.ml.depends 
ocamlc.opt -c -o PhoebeAST.cmo PhoebeAST.ml 
menhir --ocamlc ocamlc.opt --infer PhoebeParser.mly 
ocamldep.opt -modules PhoebeParser.mli > PhoebeParser.mli.depends 
ocamlc.opt -c -o PhoebeParser.cmi PhoebeParser.mli 
ocamldep.opt -modules PhoebeParser.ml > PhoebeParser.ml.depends 
ocamlc.opt -c -o PhoebeParser.cmo PhoebeParser.ml 
ocamlc.opt -a PhoebeAST.cmo PhoebeParser.cmo -o PhoebeParser.cma 
ocamldep.opt -modules PhoebeLexer.mli > PhoebeLexer.mli.depends 
ocamlc.opt -c -o PhoebeLexer.cmi PhoebeLexer.mli 
ocamllex.opt -q PhoebeLexer.mll 
ocamldep.opt -modules PhoebeLexer.ml > PhoebeLexer.ml.depends 
ocamlc.opt -c -o PhoebeLexer.cmo PhoebeLexer.ml 
ocamlc.opt -a PhoebeAST.cmo PhoebeParser.cmo PhoebeLexer.cmo -o PhoebeLexer.cma 
~: cd _build/ 
~/_build: ocaml 
     OCaml version 4.04.0 

# PhoebeParser.phoebe_spec;; 
Characters -1--1: 
    PhoebeParser.phoebe_spec;; 

Error: Reference to undefined global `PhoebeParser' 
# PhoebeLexer.phoebe_lexer;; 
Characters -1--1: 
    PhoebeLexer.phoebe_lexer;; 

Error: Reference to undefined global `PhoebeLexer' 
# 

私は間違っていますか?

答えて

2

モジュールは、PhoebeLexer.cmaおよびPhoebeParser.cmaファイルでコンパイルおよびアーカイブされています。各モジュールには、そのインターフェイスを記述する.cmiファイルもあります。モジュールを最上位にロードするには、#loadまたは#load_recdirectivesを使用できます。 #useディレクティブはソースレベルで動作するため、便利ではありません(コピー貼り付けのショートカットと見ることができます)。

だから、あなたのケースでトップレベルの相互作用は、(_buildフォルダ内のトップレベルを開始していると仮定して)次のようになります。

# #load "PhoebeLexer.cma";; 
# #load "PhoebeParser.cma";; 

は、私ができるモジュールの違いは何です#loadと私が開くことができるモジュール?

具体的な質問があります。あなたはモジュールMを開いているとき

、トップレベルは現在のディレクトリに、OCamlのがインストールされているディレクトリにある、と#directoryディレクティブで明示的に追加されたすべてのディレクトリ内のファイルm.cmiを探しています。 cmiファイルには、機械可読凝縮モジュールインターフェイスが含まれています(コンパイルされたモジュールインターフェイスと考えることができます)。このファイルは、ロードされたモジュールのタイプを定義します。また、モジュールをロードせずにモジュールのタイプにアクセスすることもできます。モジュールの定義を取得するには、実装をロードする必要があります。これはcmo(コンパイルされたモジュールオブジェクトファイル)またはcma(コンパイルされたモジュールアーカイブ)に格納されます。 cmaファイルは複数のcmoの単なるコンテナです。 cmoファイルには、実際のコードが含まれています。このコードは、メインプログラム(ここではトップレベルプログラム)にロードしてリンクすることができます。

気付いたように、インターフェイスと実装は完全に異なるエンティティであり、独立して読み込むことができます。インターフェイスは暗黙のうちにルックアップされるため、手動でロードする必要はありませんが、ディレクトリを変更する(特定のディレクトリのトップレベルをロードするか、#cdディレクティブを使用する)か、 #directoryディレクティブでパスを検索します。実装には、常に#loadディレクティブを使用して明示的にロードする必要があります。

cmiを使用できますが、実装がロードされていない場合は、Undefined valueエラーが発生します。 cmiが利用できない場合、cmiファイルがないモジュールのインターフェイスで宣言された値にアクセスしようとすると、Unbound valueエラーが発生します(モジュールアーカイブ自体を読み込んだとしても)。

要約すると、インタフェースは利用可能なものを示し、実装は利用可能な場所を定義します。値がインタフェースにない場合は、バインドされません。値がインタフェースにあるが、定義が見つからなければ、それは未定義です。

+0

回答の最後にPhoebeLexer.cma ";;'(もちろん 'Parser')を意味していませんでしたか? – Virgile

+0

)、))おかげで、@ヴァージール! – ivg

+0

私がトップレベルのやりとりをしている限り、#loadが行います。しかし、私はまだPhoebeParserとPhoebeLexerが未定義のグローバルである理由を理解していません。 #loadできるモジュールと開くことができるモジュールの違いは何ですか? –

関連する問題