まだプログラマーですが何か?

プログラマーネタ中心。たまに作成したウェブサービス関連の話も https://twitter.com/dotnsf

タグ:djc

このブログの続きです:
16bit PC-DOS 向け Java (サブセット)コンパイラ&VM "dosjava"

先日上記ページで紹介した開発中の 16bit PC-DOS 向け Java である "dosjava" 、この後で開発を進め、実装内容やテストもある程度進んできたので、正式公開を宣言します!
https://github.com/dotnsf/dosjava

2026050700



詳しくは上記 GiHub のページを参照いただきたいのですが、2026/05/26 時点で以下の機能を実装済みです:
・データ型
 * int, long, float, boolean, String
 * 配列(int, long, float, boolean のみ)
・制御構文
 * if/else, while, for, switch, break, return
 * try/catch/finally
・演算子
 * 四則演算、関係(>, >=, <, <=, ==)、論理(&&,||,!)、代入、型キャスト
・特殊クラス
 * File(テキストファイル入出力)
 * Date(日付時刻演算)
 * Math(算術演算)

以下の機能は現時点での制約事項です:
・1ファイル1クラス
・外部ファイル読み込み不可

また、以下の機能については今の時点では実装予定がありません:
・通常の class ファイルとの互換性
・マルチスレッド対応
・ネットワーク機能

samples\ フォルダ以下に動作確認済みのソースコードがあります。こちらを参考に PC-DOS と dosjava の環境を用意の上、以下の手順でコンパイルして実行してみてください。もちろん自分でソースコードを書いていただいても構いません:
(コンパイル)
> djc hello.jav
Compiled: hello.jav -> hello.djc

(実行)
> djvm hello.djc
Hello World!

本音をいうとネットワーク機能は実装したかったのですが(実際に挑戦したのですが)、16bit だととにかく メモリが足りないという問題に直面しました。それ以外でも利用するパケットドライバに依存してしまうので汎用性がなかったりして、、、ちょっとハードルが高すぎる機能だと判断しました。もしかすると将来的に、特定のパケットドライバに依存した上で HTTP クライアントくらいは・・・ と思っています。まあ、でもメモリ不足問題は時間が解決してくれるものではないので、ちょっと厳しいかなあ・・・

次に拡張しようと考えているのはバイナリファイルを扱えるようにすることと例外処理の強化です。今の時点でテキスト読み書き追加はできるのですが、バイナリファイルは未対応なのでその強化と、あと 実行中に Exeception が発生するパターンがまだ限られている(ゼロで割るとか、存在しないファイルを読みにいくとか)ので、その強化をしたいと思ってます。



この連休中に 16bit PC-DOS 向けの Java(正確には Java サブセット)コンパイラとその VM である "dosjava" を生成 AI 併用で作ってみました。まだまだ機能的には未熟ですが、今のタイミングで一度公開しておきます:
https://github.com/dotnsf/dosjava

2026050700

(↑ 細かすぎて伝わらないと思ったので書きますが、Java Duke を 16bit っぽく粗くしてみました)



【"dosjava" とは?】
16bit OS である PC-DOS(DOS/V)上で動く Java のサブセットです。Java は "Write Once, Run Anywhere!"(記述したコードはどの Java 環境でも動く)を提唱していましたが、色々な制約の事情もあり、残念ながらその理念は継承できていません(別環境の javac でコンパイルした .class ファイルを持ってきても動かない、という意味です)。ただ「ソースコードレベルではなるべく修正なしに動く」ことを開発目標の1つにしています。

PC-DOS 環境なので、例えばファイル名にも制約があります(ファイル名8文字以内、拡張子3文字以内)。コンパイラは "djc.exe" で、Java VM は "djvm.exe" ですが、ソースコードは "test.java" という名称を付けることができず "test.jav" のようなファイル名にする必要があります。これを djc.exe でコンパイルすると "test.djc" というファイルになりますが、これが "test.class" に相当するものです("djvm.exe" で実行可能です)。

ちなみに私の開発環境は 64bit の Windows11 で、クロスコンパイラには Open Watcom V2 を使っています。


【「とりあえず動かしてみたい」人向け】
PC-DOS エミュレータである DOSBox を使うことをおススメします(私自身の動作確認でも DOSBox を使っています)。2026-05-07 時点での最新バージョンは 0.74-3 で、かなり枯れて(安定して)いるものです。Windows 環境であればコマンドプロンプトから winget を使って以下のコマンドでインストールすることも可能です:
> winget install -e --id DOSBox.DOSBox

"dosjava" を DOSBox から使えるようにします。端的に言えば "djc.exe" と "djvm.exe" を PC-DOS 上のパスの通ったディレクトリに置くだけでいいのですが、DOSBox の場合はホスト PC の特定フォルダをマウントする機能があるので、以下はその方法で "dosjava" を使えるようにする手順を紹介します。

まず git clone(又は zip ダウンロード&展開など)で dosjava 一式をホスト PC にコピーします(ちなみに Windows 用の git を持っていない場合はこちらからインストールしてください):
> git clone https://github.com/dotnsf/dosjava
(ホームディレクトリ直下に git clone したものとします)

この時点でホームディレクトリ(C:\Users\myname\ とします)の直下に dosjava というフォルダが作られ、一式がコピーされているものとします(ちなみに実行バイナリは dosjava\build\bin\ 以下に djc.exe と djvm.exe があります)。

これを DOSBox から使えるようにマウントします。DOSBox の設定ファイルを編集するため、"dosbox" で検索して "DOSBox 0.74-3 Options" と書かれた箇所をクリックします(上で紹介した winget 以外の方法で DOSBox をインストールした場合はこの方法では設定ファイルを編集できない可能性があるので、インストール先ディレクトリを探すなどして dosbox.conf ファイルを探してください):
2026050701


設定ファイルをテキストエディタで開いた状態になります:
2026050702


一番下までスクロールして、[autoexec] と書かれた箇所を表示します。そしてその下に以下を記載して保存します(先ほどクローンした dosjava フォルダを DOSBox の c: ドライブとしてマウントし、かつ djc.exe や djvm.exe がある build\bin\ ディレクトリにパスを通して c: ドライブに移動する、という内容です):
mount c c:\Users\(ユーザー名)\dosjava
set PATH=%PATH%;c:\build\bin
c:

2026050703

この状態で DOSBox を起動します(dosbox のアプリを開きます):
2026050704


正しく DOSBox が起動できると以下のような画面になります(上で [autoexec] 以下に書いたコマンドが実行されていることを確認します)。ちなみに DOSBox 内では英語キーボード配列になっているので注意してください(ディレクトリ区切り記号である半角\を日本語キーボードで入力するには右上の(SHIFT キーを併用すると "|" になる)キーではなく、右下の(SHIFT キーを併用すると "_" になる)キーを入力する必要がある点に注意してください:
2026050705


いくつかの動作確認済み Java ソースコードが c:\samples\ フォルダ内に格納されています。試しにこれらをコンパイル&実行してみましょう。

まずは DOSBox 内で以下のコマンドを入力して samples\ フォルダ内のファイル一覧を確認します:
c:\>cd samples
c:\samples\>dir

2026050706


例えば "hello.jav" というファイルの内容を確認するには "type hello.jav" と入力します(関数呼び出しのテストを兼ねているので少しだけ複雑化していますが、いわゆる「ハローワールド」の Java ソースコードです):
2026050707


ではこの hello.jav をコンパイル&実行してみます。まずは djc.exe でコンパイルします。"djc hello.jav" と入力します:
c:\samples\>djc hello.jav

2026050708


コンパイルに成功すると上図のように "Compiled: hello.jav -> hello.djc" と表示されます。これは「hello.jav をコンパイルし、結果を hello.djc として保存した」という意味です。この hello.jdc は一般的な Java でいう所の "hello.class" に相当するものです。

コンパイルした "hello.djc" を実行するには Java VM である "djvm.exe" を使います:
c:\samples\>djvm hello.djc

2026050709


成功すると元のソースコードで記述されていたように "Hello World!" という文字が出力されます。

この samples\ フォルダには他にも(現在の dosjava でテスト済みの)多くのサンプル Java ソースコードがあるので、同様に色々試して(コンパイル&実行)みてください。

自分でソースコードを書きたい、という場合は Windows 環境で dosjava ディレクトリ以下にソースコードを作っていただいてもいいのですが、DOSBox 内のあくまで PC-DOS 環境内で記述したい、という場合は別途 16bit PC-DOS 用のスクリーンエディタを用意して(上述のようにそのフォルダもマウントして、パスを通すなどして)利用してください。個人的には 2024 年にオープンソース化された Vz Editor がおススメです。


【(2026-05-07 時点での)仕様】
dosjava は Java と「なるべくソースコード互換」になるよう設計/開発していますが、残念ながら Java との互換性確保の優先順位を下げて実装したものもあります。

具体的には 2026-05-07 時点のビルドでは Java の以下の機能は実装済みです:
  • 型は int, String 、および int 配列
  • 以下の算術演算: +, -, *, /, %, ++, --, +=, -=
  • 以下の比較演算: ==, !=, <, >, <=, >=
  • 以下の論理演算: &&, ||, !
  • 以下の制御構造: if~else~, for ループ, while ループ
  • System.out.println( 文字列または整数 );
  • String 変数には以下のメソッドを実装済み: length(), toUpperCase(), toLowerCase(), equals(), compareTo(), startsWith(), endsWith(), indexOf(), lastIndexOf(), substr()

以下の機能は Java との互換なしに実装済みです("import java.io.File"; は不要):
  • File 関連テキスト読み書き追加関数: File.open(), File.readLine(), File.writeLine(), File.close()

以下の機能は現時点では未実装(実装予定なし)です。16bit では厳しいことに加え、関連機能(例えば浮動小数点演算を実装すると、それらの配列処理や java.lang.Math との互換性などが必要になる)との兼ね合いで優先順位を下げざるを得なかったものとご理解ください:
  • 浮動小数点演算(float, double, Float, Double)
  • ネットワーク処理
  • 日付時刻演算
  • 外部クラスの import 機能

今後の予定では日本語文字列処理やファイル処理のバイナリファイル対応の実装、そして DOSBox ではない PC-DOS での動作確認あたりを考えています。要望などあれば issues から教えてください。プルリクは大歓迎です。


【おまけ】
この dosjava は生成 AI を併用して開発しています。普通のアプリケーションサービスであれば、今のコーディング生成 AI であればソースコード実装だけでなく、ビルド、テストなども実行させ、途中で失敗する場合は原因を考えさせた上で修正→再ビルド→再テスト・・ と一通り動くようになるまでを能動的に行わせることができます(この方法で進めていくらかかるかは別の話だけど)。とても便利なのですが、本プロジェクトのように「開発環境と実行環境が別」な場合、つまりクロスコンパイルが必要なものに対して、生成 AI をどのように使っていくべきか? というのは面白いテーマのように感じています。

今回の dosjava の場合、動作確認には Windows アプリである DOSBox を使っています。残念ながら DOSBox は生成 AI が外から手を出すことができない(毎回設定ファイルを書き換えて初期実行コマンドを変えればできないことはないんだろうけど・・・)ものです。この環境だとコーディングとビルド成功までは生成 AI に任せて、動作確認やテストは手動実行する必要があります。

つまり、
  • とりあえず開発目標を定めて(人間の役割)、
  • その目標のための開発計画を考えさせて(生成 AI の役割)、
  • 開発計画に沿って、ビルドできるようになるまで実装させて(生成 AI の役割)、
  • 動作確認する。期待通りの結果が出なかった場合はエラー内容や現在の挙動内容を使える(人間の役割)
  • 現在の挙動内容をヒントにソースコードの修正プランを考えさせて、修正を実装する(生成 AI の役割)
  • (期待通りの結果になるまで上の繰り返し)
という役割分担で作業する時間が多かったと感じています。図らずも TDD(Test Driven Development : テスト駆動開発)のスタイルで開発することが感覚的にも合っていた、と思いました。


このページのトップヘ