2023/07/26 · The BNF Converter (bnfc) is a compiler construction tool generating a compiler front-end from a Labelled BNF (LBNF) grammar. It is currently ...
Centre for Language Technology Chalmers University of Technology and University of Gothenburg What is the BNF Converter? The BNF Converter is a compiler construction tool generating a compiler front-end from a Labelled BNF grammar. It is currently generating code for the target languages Haskell, Agda, C, C++, Java, and OCaml, as well as XML representations and Pygment syntax highlighters. Given a
入力ストリームの実装から独立したパーサーを定義したい。 そこでまずは入力ストリームのデータ型を定義する。 module type INSTREAM = sig type instream (* 本当はinstreamに対する色々な操作を含むつもり *) end 実際の入力元はチャネルだったりメモリ上の文字列だったりする。 module ChanIns = struct type instream = in_channel end module StringIns = struct type instream = string end パーサーのシグニチャと実装はこんな感じになる。 module type PARSE = sig type instream type result val parse : instream -> result end module Parse(I: INSTR
入力ストリームの実装から独立したパーサーを定義したい。 そこでまずは入力ストリームのデータ型を定義する。 module type INSTREAM = sig type instream (* 本当はinstreamに対する色々な操作を含むつもり *) end 実際の入力元はチャネルだったりメモリ上の文字列だったりする。 module ChanIns = struct type instream = in_channel end module StringIns = struct type instream = string end パーサーのシグニチャと実装はこんな感じになる。 module type PARSE = sig type instream type result val parse : instream -> result end module Parse(I: INSTR
以前 Joel on Software の「間違ったコードは間違って見えるようにする」という記事 [1] を読んだ。彼はこの記事の中でハンガリアン記法のうち変数のデータ型/タイプ (type) を示すに過ぎない「システムハンガリアン」を否定する一方で、タイプでは区別できないような種類 (kind) を示す「アプリケーションハンガリアン」を支持している。 この記事にはとても感心したのだけど、彼の出している「安全な文字列」と「安全でない文字列」の例をみてこうも思った。このくらいのことなら面倒見てくれるコンパイラやツールがあったっていいんじゃないだろうか。種類とタイプの違いというのは先験的にあるもの(と Joel Spolsky が書いているわけではないが)じゃなくて、コンパイラや IDE などのツールがサポートするところまでがタイプで、残りが種類なんじゃないだろうか。 とはいえ、口で言えても実
Camomile について調べたメモ。 普通の文字列型 (string) と Camomile 内部のユニコード文字列型との間の変換を行うエンコーダ/デコーダを作る。内部エンコーディングとして UTF-8 を使う場合は以下のようにする。UTF8 以外にも UText, XString, UTF16, UCS4 が選べるようだ。 KURO-BOX% ocaml bigarray.cma camomile.cma Objective Caml version 3.10.0 # module U = CamomileLibrary.Default.Camomile.CharEncoding.Make(CamomileLibrary.UTF8);; module U : sig type text = CamomileLibrary.UTF8.t val decode : CamomileLibr
Camomile についてさらに調べる。 Camomile のユニコード文字列型には何種類かあるけれども文字型は UChar という1つしかない。 特定のエンコーディングで書かれたテキストファイルから読み込むには以下のようにする。hyoji.txt は Shift_JIS で「表示」の2文字だけが書かれたファイルとする。 # let inc = open_in "hyoji.txt";; val inc : in_channel = <abstr> # let sjis = CamomileLibrary.Default.Camomile.CharEncoding.of_name "SHIFT_JIS";; val sjis : CamomileLibrary.Default.Camomile.CharEncoding.t = <abstr> # let inc' = new Camomi
抽象データ型とリテラルというのがそもそも相容れないのかもしれないが Camomile の文字列型にはリテラルがない。ソースを書いた時点で固定的な情報をランタイムに計算するのはちょっと癪なのでいろいろ考えてみたのだけど、結局文字列型としては UTF8.t を、リテラルとしては通常の OCaml の文字列リテラルを使って abstraction barrier を破って UTF8.t と認識させるのが一番簡単であろうという結論に達した。 ただしこれだとソースファイルも UTF-8 で書かないといけないという問題がある。これを解決するために Java でいう native2ascii のような簡単なツールを作った。 (* wchar2latin.ml *) open CamomileLibrary.Default.Camomile;; open CamomileLibrary.Default.C
無い知恵を絞って「どう書く?org」の「分数を小数に展開」という問題 [1] にOCaml で投稿してみた [2]。 投稿した後で別の方が「2147483645 / 2147483647 で~」と書いていたので、そういえば問題文の境界値 2^31-1 は OCaml の int では満たせないんだったと気がついたのだけど、じゃあ 2^30-1 の 1073741823 までならできるんだっけと思ってやってみると、 # pretty_fmt (decimal_of_frac 1073741823 1073741823);; - : string = "1." # pretty_fmt (decimal_of_frac 1073741823 1073741822);; - : string = "1.00000000000000000000000000000-1{000000000000000
前回 [1] の myprintf は2引数をとる関数だったから部分適用できる。 # let f = myprintf "%s";; val f : '_a -> unit = <fun> '_a という、これまた馴染みのない型が出てきた。 調べてみるとこれは多相型ではなくて、まだ型が決まっていないというだけの状態を示すものらしい。続けて以下のように打ち込む。 # f "hello!";; hello!- : unit = () そしてもう1回 f の型を確認してみる。 # f;; - : string -> unit = <fun> さっきとちがう。一度関数が完全に適用されると型が確定して string になるということのようだ。こうなると文字列以外を与えて f を呼び出すとコンパイルエラーになる。 # f 123;; Characters 2-5: f 123;; ^^^ This e
OCaml の printf 関係で検索していたら Caml-list の過去ログ [1] で紹介されていた論文 [2] に ML で printf っぽいものを作る一つのやり方が書いてあった。(ちなみにそのスレッドのフォローアップに OCaml には special typechecking rules for format strings があるようなことが書いてあるのでやはり printf は特別ということらしい) さて、[2] を参考に見よう見まねで当初の目的であった書式化バイナリ出力関数を作ってみた。fout というのが作りたかった関数だ。 # let ($) f g x = f (g x);; val ( $ ) : ('a -> 'b) -> ('c -> 'a) -> 'c -> 'b = <fun> # let a k s x = k (output_string s x
前回 [1] はバイナリ出力関数を作ったけど入力のほうを作っていなかった。 入力のほうは読み込んだ値をどのように取り出すかで何通りかの実装が考えられると思う。思いついた順に3種類のコードを載せる。 まずは参照を使う方法。これは出力版をひっくり返しただけでシンプルだ。 let ($) f g x = f (g x) let a len k s x = let buf = String.make len ' ' in really_input s buf 0 len; x := buf; k s let c k s x = k (x := input_char s; s) let b k s x = k (x := input_byte s; s) let i k s x = k (x := input_binary_int s; s) let fin ich p = p (fun s ->
An Introduction to Compilers and Interpreters by Aarne Ranta, with an appendix coauthored by Markus Forsberg Publication Details Aarne Ranta, Implementing Programming Languages. An Introduction to Compilers and Interpreters, with an appendix coauthored by Markus Forsberg, College Publications, London, 2012. ISBN 978-1-84890-064-6 Publisher's web page Where to buy amazon.com $18.00 amazon.co.uk £1
「ふつうのHaskell」によると Haskell には words 関数というのがあってこういうふうに使うらしい。 Prelude> words "This is a pen" ["This","is","a","pen"] OCaml には似たような関数はないようなのでこれを作ってみる。 Haskell の words は「文字列 -> 文字列のリスト」だけど、「ストリーム -> ストリーム」で作ってみた。 以下の words のストリームビルダーの関数は呼ばれるとまずストリームの最初の空白を除去して最初の一語を切り出して返す。 let stdinstr = Stream.of_channel stdin;; let words str = let is_space c = String.contains " \t\r\n" c in let rec trim_leading char
Haskell 、Erlang の次のブームは Coq に違いありません。とりあえず基本ということで、Coq でひねりのない brainfuck インタプリタを書いてみました。動作例。Coq のコードが色づけできないとは何事か。 Eval compute in (finite_execute " +++++++++[>++++++++>+++++++++++>+++++<<< -]>.>++.+++++++..+++.>-.------------.<++ ++++++.--------.+++.------.--------.>+. " "" 500). = "Hello, world!"%string : string 残念ながら (?) Coq では停止性が保障された関数しか定義できません。ここでは最大評価ステップを指定しないといけないという仕様にしてごまかしています (引数の 50
「ふつうの Haskell」を買ったので OCaml の実用レッスンをするのにちょうどよさそうな問題をこの中から探して OCaml に書き換えて実装してみようと思う。 まずは cat コマンド。といっても標準入力から読んで標準出力へ出すだけの簡易版。Ocaml だとこんな感じだろうか。 let _ = let stdinstr = Stream.of_channel stdin in Stream.iter print_char stdinstr ;; Stream.of_channel は入力チャネルからストリームを作って文字の列のストリームを作る。 stdin から作ったその入力ストリームの1文字1文字に対して print_char を適用するので標準入力から標準出力へ1文字ずつ流すということになるわけだ。 実際のプログラミングでは行単位で処理を行うことが多いだろう。行単位のストリーム
関連リンク: OCaml 標準ライブラリ探訪 第0回 その他の回は第0回のトラックバックよりご覧ください。 printf って OCaml でも便利ですよね。C から連綿と続いている半ば常識の % インターフェースに加え、ちょっと不思議な型推論のおかげで型安全性も保証されてます。printf 使ってて型エラーが見つかるたびに、あー C だったら seg fault してたかもしれんな、、、良かった良かった、と思います。今日はそんな printf 系の関数を提供する Printf モジュールのお話。 OCaml では printf系の関数は、何か知らんけど書いたら動く、だから深く詮索するな、という不思議(適当) API として提供されています。私はこの清濁併せ呑む OCaml の姿勢が好きなんですが、、、まあ人それぞれですな。 お品書き Printf の特殊な型付けについて / format
某製造業の現役IT担当者が実体験を基に、新たなIT部門の在り方を提起する。10人の人員を抱えたIT部門がリストラで消滅。たった1人のIT担当者になった著者が、いわゆる「ひとり情シス」としてIT開発・運用体制の再確立に挑んだ。その実践経験を基に、弱体化したIT部門が抱える問題点、IT部門の再建の道筋などを示す。 私は従業員400人の企業で、社内の情報システムを担当している。250台のサーバーから成るインフラの構築・運営を中心に、業務システムの内製、データ管理や統制など仕事は多岐にわたる。だが体制は、私ひとり。つまり「ひとり情シス」である。私自身は「ソロインテグレータ(Solo Integrator)」と呼んでいる。ソロインテグレータについては、この連載の後半で説明するが、まずは現在の状態に至るまでの長く困難な道のりを説明し、主に中堅中小企業のIT部門が抱える課題への現実解を指し示したい。 自
リリース、障害情報などのサービスのお知らせ
最新の人気エントリーの配信
j次のブックマーク
k前のブックマーク
lあとで読む
eコメント一覧を開く
oページを開く