Skip to content

Snowman-s/JMind

Repository files navigation

JMind

これは何をしますか?

Mindで書かれたソースコードをJVM上で動くように、「.class」ファイルに変換します。

これは何をし「ない」ですか?

「.class」ファイルの実行はこのリポジトリではできません。JREをインストールし、「java」コマンドで実行してください。

初期化

  • Mind(最低バージョン8)をインストールする。
  • https://github.com/Snowman-s/MindTools をクローンし、手順に従ってセットアップする。
  • Mindのインストールディレクトリ内の「srclib」内にある、「uniencode.src」および「unidecode.src」を、このREADME.mdと同じパスにコピペする。
  • 「umind jmindc.src」を、このREADMEファイルのディレクトリで実行する。

実行

  • 「jmind/」内に、UTF8で好きなファイル名でMindプログラムを書く。(他の場所でもいいですが、jmind内に書けばgitに無視されるので、推奨します。)
  • .\sjmindc jmind\<file_name>でそのソースをコンパイルする。
    • パスの区切りとして「/」は使用できません。
  • 「cd jmind」を実行し、「java <file_name(no ext)>」でコンパイルした.classファイルが動作します。

現在の注意点(後々修正)

  • 機能は大幅に制限されている
  • 関数宣言は一つまで
  • 変数宣言は関数内でのみしかできない
  • イニシャライザ(コンストラクタ)未定義
  • JVMスタック使用数は255個を書き込みますが――

これを開発するときの注意点

  • 「jmindc.src」での「~を コンパイル。」の記述では、ファイル名先頭に「s」が必要になります。
  • debug.src内の「テストモード」の値は以下のように作用します。
    1. テストモードが1ならば、「~をログする」「~をテスト表示」系の単語が動作します。0ならばそれらはほぼ無処理扱いになります(スタックの整合性は取られます)。
    2. テストモードが1ならば、dataフォルダ(実行時に内部で使用されるファイル置き場)内のファイルは残ったままになります。0ならばそれらはすべて削除されます。

細かい仕様

  • 生成された「.class」ファイルにはpublicな一つのクラスのみが含まれます。
  • 関数は全て「public static」が付けられます。
  • 関数の名前は定義がそのまま使用されますが、「メイン」のみ「main」となります。
  • 関数の型は普通の関数なら「(java.util.LinkedList)void」ですが、「メイン」のみ「(java.lang.String[])void」となります。
  • 「メイン」では、LinkedListインスタンスが新しく1つ作成され、それが関数の引数に渡されます。これを使いまわしてプログラムが進行します。例えば「”こんにちは!世界!”」は、「”こんにちは!世界!”を引数にLinkedListインスタンスのaddFirstを呼ぶ処理」として扱います。
  • package宣言はありません。
  • dataフォルダ内には、このプログラム実行時に様々なファイルが書き込まれるので、使用しないようにしてください。

使用可能構文

分岐

  1. 「さもなければ」は省略可能です。
  2. 「もし」は無視されますので、日本語上必要な箇所に挿入することが可能です。
  3. 分岐内の文が一つの場合であっても、「つぎに」は省略不可です。
  • ならば~(さもなければ)~つぎに - スタックから数値を一つ取り出し、それが1(真)に等しい(正確には0と異なる)なら「ならば~さもなければ」内が、そうでなければ「さもなければ~つぎに」内が実行されます。
    • 所謂if-[else]-endif文に相当します。
  • でなければ~(さもなければ)~つぎに - スタックから数値を一つ取り出し、それが0(偽)に等しいなら「ならば~さもなければ」内が、そうでなければ「さもなければ~つぎに」内が実行されます。
    • しいて言えばif notやif!に相当します。

forループ

  1. 「回数」をforループ内に記述すると、それが何回目のループかの数値がスタックに積まれます。ただし、から始まることに注意してください。
  2. ループ内に「打ち切り」を記述するとその場でループを抜けます。
  3. ループ内に「もう一度」を記述するとその場でループをやり直します。
  • 回数指定し~繰り返し - スタックから数値を一つ取り出し、その回数だけ内部が繰り返し実行されます。
  • 逆向き回数指定し~繰り返し - スタックから数値を一つ取り出し、その回数だけ内部が繰り返し実行されます。「回数」の順番が逆になります。(n→1)

while(true)ループ

  1. 「回数」は機能しません。
  2. ループ内に「打ち切り」を記述するとその場でループを抜けます。
  3. ループ内に「もう一度」を記述するとその場でループをやり直します。
  • ここから~繰り返し - 内部がずっと繰り返し実行されます。「打ち切り」等でループを脱出する処理が通常は必要です。

選択する

  • 選択する~選択終わり - スタックから整数を一つ取り出し、それによって示される位置の単語を実行します。単語数を超える整数、または0以下が渡された場合、例外が投げられます。

変数

  1. 「~は 変数」を一つの単語定義中に含めると、以降「~」を整数型変数として扱えるようになります。
  2. 必ず初期化してから使用してください。
  3. 予期しないエラー・例外を防ぐため、単語定義の一番初めに書いてください。
  4. 暫定処置として、変数は5つまでしか定義できません。
  5. 詳しくは、変数操作単語の項を確認してください。

コメント

  1. 「※」の後、その行が終わるまでは全てコメントになります。
  2. 「(」「)」で囲まれた部分は、括弧の両端が他の文字と隣り合っていなければコメントになります。

使用可能単語

基本的なデータ

  • 文字列 - '「'と'」'で囲まれた単語は文字列として扱われます。空白や読点などの区切り文字も使用できます。
  • 文字 - 「'」で囲まれた単語は文字(等価な整数)として扱われます。Characterとしてではなく、 Integerとして扱われます。エンコードはUTF-16LEとなっています。
  • 数値 - 4バイトを超えると誤動作します。
  • 真偽値 - 単に「真」「偽」と記述してください。(Javaとは違いtrueは1,falseは0の整数として扱われます。)

表示

  1. 『何でも~』系単語に文字を渡すと、数値として扱われてしまいます。
  • 何でも表示 - スタックから1つ取り出し、何でもいいから標準出力します。(文字列でなくても表示されます。)
  • 何でも一行表示 - スタックから1つ取り出し、何でもいいから標準出力し、改行します(文字列でなくても表示されます。)
  • 表示 - スタックから1つ取り出し、その文字列を標準出力します。(文字列でなければエラーが出ます。)
  • 一行表示 - スタックから1つ取り出し、その文字列を標準出力し、改行します(文字列でなければエラーが出ます。)
  • エラー扱いで表示 - スタックから1つ取り出し、その文字列をエラーストリームへ出力します。(文字列でなければエラーが出ます。)
  • エラー扱いで一行表示 - スタックから1つ取り出し、その文字列をエラーストリームへ出力し、改行します(文字列でなければエラーが出ます。)
  • エラー扱いで何でも表示 - スタックから1つ取り出し、何でもいいからエラーストリームへ出力します。(文字列でなくても表示されます。)
  • エラー扱いで何でも一行表示 - スタックから1つ取り出し、何でもいいからエラーストリームへ出力し、改行します(文字列でなくても表示されます。)
  • 改行 - 標準出力で改行します。

標準入力

  • 一つ文字列入力 - 標準入力から文字列を受け付け、スタックに積みます。(空白などで区切られている場合、最初の部分だけ読みます。)
  • 文字列入力 - 標準入力から文字列を受け付け、スタックに積みます。(空白などで区切られているかに関わらず、必ず一行読み出します。)
  • 一つ数値入力 - 標準入力から整数を受け付け、スタックに積みます。
    1. 整数は10進数で受け取ります。
    2. 空白などで区切られている場合、最初の部分だけ読みます。
    3. 入力が数値でない場合、java.util.InputMismatchException例外が投げられます。

整数計算

  • 加える - スタックにある2つの整数を加えスタックに積みます。
  • 引く - スタックに2つ積まれている整数を使用して減算しスタックに積みます。
  • 掛ける - スタックにある2つの数を掛けスタックに積みます。
  • 割る - スタックに2つ積まれている整数を使用して除算しスタックに積みます。
  • 割った余り - スタックに2つ積まれている整数を使用して剰余計算しスタックに積みます。
  • AND - スタックにある整数2つを使用して「AND」ビット演算しスタックに積みます。
  • OR - スタックにある整数2つを使用して「OR」ビット演算しスタックに積みます。
  • XOR - スタックにある整数2つを使用して「XOR」ビット演算しスタックに積みます。
  • 左シフト - スタックにある整数2つを使用して左シフトしスタックに積みます。
  • 右シフト - スタックにある整数2つを使用して右シフトしスタックに積みます。符号ビットを特別扱いしません。
  • 負数 - スタックにある整数を1つ使用してそれの符号を反転し、スタックに積みます。(例:-5の 負数 ⇒ 5)
  • NOT - スタックにある整数を1つ使用して、「NOT」ビット演算し、スタックに積みます。
  • 一つ加え - スタックにある整数を1つ使用して、1を足して、スタックに積みます。
  • 二つ加え - スタックにある整数を1つ使用して、2を足して、スタックに積みます。
  • 一つ引き - スタックにある整数を1つ使用して、1を引き、スタックに積みます。
  • 二つ引き - スタックにある整数を1つ使用して、2を引き、スタックに積みます。

二値整数検査

  • 等しい - スタックにある数2つを使用して等しいか比較しその真偽値をスタックに積みます。
  • 異なる - スタックにある数2つを使用して異なるか比較しその真偽値をスタックに積みます。
  • 大きい - スタックにある数2つを使用して大きいか比較しその真偽値をスタックに積みます。
  • 小さい - スタックにある数2つを使用して小さいか比較しその真偽値をスタックに積みます。
  • 以上 - スタックにある数2つを使用して大きいまたは等しいか比較しその真偽値をスタックに積みます。
  • 以下 - スタックにある数2つを使用して小さいまたは等しいか比較しその真偽値をスタックに積みます。

一値整数検査

  • ゼロ? - スタックにある数1つを取り出し、0に等しいかどうかの真偽値をスタックに積みます。
  • ゼロ以外? - スタックにある数1つを取り出し、0と異なるかどうかの真偽値をスタックに積みます。
  • 正? - スタックにある数1つを使用して0以上かどうかの真偽値をスタックに積みます。
  • 負? - スタックにある数1つを使用して0より小さいかどうかの真偽値をスタックに積みます。
  • 正の数? - スタックにある数1つを使用して0より大きいかどうかの真偽値をスタックに積みます。

変数操作単語

  1. 逆転介入は働きません。作用を受ける変数を直前に書いてください。
  2. この系列の単語には、変数に送り仮名が強制されます。
  3. 予め「入れる」「クリア」等で必ず変数の初期化をしてください。
  • [変数]に 入れる - スタックから整数を1つ取り出し、指定された変数に入れます。(「に」は「へ」でも可)
  • [変数]を 増加させ - スタックから整数を1つ取り出し、指定された変数の数値をその分増加させます。
  • [変数]を 減少させ - スタックから整数を1つ取り出し、指定された変数の数値をその分減少させます。
  • [変数]を 一つ増加させ - 指定された変数の数値を一つ増加させます。「1つ 増加させ」よりも高速です。
  • [変数]を 一つ減少させ - 指定された変数の数値を一つ減少させます。「1つ 減少させ」よりも高速です。
  • [変数]を クリア - 指定された変数に0を代入します。
  • [変数]を セット - 指定された変数に1を代入します。

スタック操作単語

  • 指定番号のスタック要素を得る - スタックから整数を1つ取り出し、スタックの手前からその番号の要素を取り出し、スタックの先頭に置きます。例:[10,20,30,2] -> [10,30,20]
    1. 番号は1から始まります。
  • 捨てる - スタックのもっとも手前のデータを削除します。例:[10,20,30] -> [10,20]
  • 複写する - スタックのもっとも手前のデータを複製し、それをスタックに積みます。例:[10,20,30] -> [10,20,30,30]
  • スタックサイズ - 現在のスタックのサイズを得て、スタックに積みます。例:[10,20,30] -> [10,20,30,3]
  • 二番目を捨てる - スタックの手前から2番目のデータを削除します。例:[10,20,30] -> [10,30]
  • スワップ - スタックの最も手前のデータと手前から2番目のデータの場所を入れ替えます。例:[10,20,30] -> [10,30,20]

文字列操作単語

  • 文字数 - スタックから一つ文字列を取り出し、その文字数を得て、スタックに積みます。
  • 文字数 - スタックから一つ文字列を取り出し、その文字数がゼロかどうかの真偽値を得て、スタックに積みます。
  • 等しい文字列? - スタックから二つ文字列を取り出し、その文字数が同じ文字の並びかどうかの真偽値を得て、スタックに積みます。
  • 一文字検索 - スタックから文字列と文字を取り出し、その文字が文字列のどこにあるかの数値をインデックスに積みます。位置は1から始まります。 ただし、見つからなかった場合、0が積まれます。
  • 検索 - スタックから文字列1と文字列2を取り出し、その文字列2が文字列1のどこにあるかの数値をインデックスに積みます。位置は1から始まります。 ただし、見つからなかった場合、0が積まれます。
  • 合成 - スタックから文字列1と文字列2を取り出し、文字列1の後ろに文字列2をつなげた文字列をスタックに積みます。

その他

  • 無処理 - 何もしません。
  • 終わり - その関数を終了(return void)します。
  • 実行終わり - 現在実行中のこのプログラムを終了します。
  • 大きい方 - スタックから二つ整数を取り出し、その内大きい方一つをスタックに積みます。
  • 小さい方 - スタックから二つ整数を取り出し、その内小さい方一つをスタックに積みます。
  • 絶対値 - スタックから一つ整数を取り出し、その整数の絶対値をスタックに積みます。
  • 日時を値で得る - UNIX協定時間(1970年/1月/1日 9:00)からいくらだけ時間が過ぎたかの整数をスタックに積みます。(JavaのSystem.currentTimeMillisを利用しますが、整数は4バイトなので、情報が一部欠損するかもしれません。)

その他の仕様

逆転介入

コンパイラは、2つのデータを使用する計算・検査単語に対し、助詞を見て自然な処理をするように工夫されています。

  • 例:「3を 6から 引く」と「6から 3を 引く」は等価です。

詳しくはMindのドキュメントを参照してください。

Releases

No releases published

Packages

No packages published