公開日:2025/10/18
title.png

36th Season


#36-7 Blockly→JavaScript変換

 Cmod A7ボード(FPGA)を使って開発を進めているオリジナル16ビットCPUコアMoscoviumのソフトウェア開発環境は、Blockly for Moscoviumです。

 今回は、Blockly for MoscoviumにJavaScriptへの変換機能を追加しようと思います。

Blockly for Moscovium

 以下の立ち上げ記事並びに、マニュアルを参照してください。

  「#31-6 Moscoviumの開発環境(カスカス)

  「Blockly.XML to Moscovium.ASM translator Manual

 元は、Googleが提供している「Blocklyデモ」という環境です。Blocklyデモ環境に対して、Moscoviumマイコンへ対応するためのカスタムブロックを追加したのが、Blockly for Moscoviumです。

各種プログラミング言語への変換機能

 元のBlocklyデモでは、Blocklyエディタでエントリしたプログラムを以下のプログラミング言語へ変換可能となっています。

 その他、エントリしたプログラムのデータ交換用として、XML、JSON形式での入出力に対応しており、Blockly for Moscoviumの中核をなすBlockly.XML→Moscovium.ASM変換スクリプトは、前者のXML形式を利用しています。

執筆時点の状況

 Blockly for Moscovium開発環境は、Blocklyデモ環境をカスタマイズした物なので、元々Blocklyデモが提供していたブロックだけを使ってエントリしたプログラムは、各種プログラミング言語へ変換可能です。

 ですが、Moscovium用に追加したカスタムブロックを使ってしまうと、途端に、変換を失敗してしまいます(下図)。

a367_errgen.png

 カスタムブロックを含むプログラムを変換するためには、追加したカスタムブロックを各種プログラミング言語のソースリストへ変換するジェネレータと呼ばれるコードをBlocklyに追加する必要があります。

変換結果比較

 前節で説明した通り、現段階でカスタムブロックを使ってしまうと変換を失敗するので、変換可能な様に、Blocklyデモへ元々備わっているブロックに限定してコーディングした、以下のプログラムを使います。

  サンプルプログラム:blky_fibonacci.bxml

※ブラウザによっては、XMLファイルをレンダリングして表示してしまうため、拡張子を.bxmlとしてあります。

 上のプログラムは、1,000以下のフィボナッチ数列を計算して表示するプログラムです。
 Blockly for MoscoviumのXMLタブに貼り付けて、その並びにある「JavaScript」や「Python」などのタブに切り替えると、各種プログラミング言語へ変換した結果が表示されます。

 各種プログラミング言語への変換結果を以下表にまとめて見ます。

Blockly blky_fibonacci.png
JavaScript var stra, numa, numb, numc;
// calculate Fibonacci sequence
stra = 'FIBO: ';
numa = 0;
numb = 1;
while (numa <= 1000) {
  stra += String(numa);
  stra += ', ';
  numc = numa + numb;
  numa = numb;
  numb = numc;
}
window.alert(stra);

Python stra = None
numa = None
numb = None
numc = None
# calculate Fibonacci sequence
stra = 'FIBO: '
numa = 0
numb = 1
while numa <= 1000:
  stra = str(stra) + str(numa)
  stra = str(stra) + ', '
  numc = numa + numb
  numa = numb
  numb = numc
print(stra)

PHP // calculate Fibonacci sequence
$stra = 'FIBO: ';
$numa = 0;
$numb = 1;
while ($numa <= 1000) {
  $stra .= $numa;
  $stra .= ', ';
  $numc = $numa + $numb;
  $numa = $numb;
  $numb = $numc;
}
print($stra);

Lua -- calculate Fibonacci sequence
stra = 'FIBO: '
numa = 0
numb = 1
while numa <= 1000 do
  stra = stra .. numa
  stra = stra .. ', '
  numc = numa + numb
  numa = numb
  numb = numc
end
print(stra)

Dart var stra, numa, numb, numc;
main() {
  // calculate Fibonacci sequence
  stra = 'FIBO: ';
  numa = 0;
  numb = 1;
  while (numa <= 1000) {
    stra = [stra, numa].join();
    stra = [stra, ', '].join();
    numc = numa + numb;
    numa = numb;
    numb = numc;
  }
  print(stra);
}

 各種プログラミング言語毎に、文法や書式が異なる事が見て取れます。PHPやLua、Dart等、使ったことのない筆者でも、「フィボナッチ数列の計算だな」と言う程度には理解することができます。

Moscoviumアセンブラソースリスト

 前節で示したプログラムは、Moscoviumマイコンでも実行することができます。
 良い機会なので、サンプルプログラムをMoscoviumアセンブラソースリストに変換した結果をご覧に入れたいと思います(以下参照)。

Moscovium.ASM テキストファイル(blky_fibonacci.asm)を表示できませんでした。

 「アセンブラなんて解んないよ〜」な、方でも、Blockly.XML→Moscovium.ASM変換スクリプトが事細かに注釈を残すようにしてあるので、注釈を追うだけでプログラムの動作は読み取る事ができると思います。コード最適化が未実施な事も、素直なアセンブラソースリストに貢献しているので読み易いと思います。
 間違いなく、「1,000以下のフィボナッチ数列を計算」しています。

※恥ずかしながら、コード最適化が未実施なので、時折、「pushした直後にpopする」様な、無意味なコード列なども見られます……。

実験はコードの実行

 Blocklyデモ環境では、JavaScriptに変換したプログラムをブラウザで実行することができます。
 Blocklyのコードエディタ画面(下図)で、右上に配置された赤色三角マークのアイコンをクリックすると、エントリしたプログラムを実行することができます(YouTube ▶ へのリンクではありません!)。

a316_blky_edit.png

※実行する時は、無限ループを作らない様に注意してください。

 本ページでは、以下のリンクをクリックする事で、JavaScriptに変換したコードを実行して見ることができます。

  実験サンプル: ▶ blky_fibonacci.js

 なお、一般的なMoscoviumのプログラムでは、I/Oユニットやメモリ空間へのアクセスなど、Moscoviumマイコン特有の機能を使うため、JavaScriptへの変換ができたとしても、実行する事はできません。従って、実行環境に関しては「おまけ」と言う位置付けです。実質(※)機能しないと思ってください。
 本ページでは、Blockly for Moscoviumでエントリしたプログラムを、テキスト形式のプログラミング言語に変換できる事に意義を見出し、その実現を目標とします。従って必ずしもJavaScript言語の文法に則ることを目的としません。Moscovium特有機能の変換などに関して、JavaScriptの文法に則ることができないケースは、文法から外れて「なんちゃってJavaScript」で変換します。

※上のサンプルプログラムでは、Moscoviumマイコン特有の機能を未使用なため、ブラウザでも実行可能です。

シミュレーションもしておこう

 Moscoviumマイコンでの実行に関しては、従来通り、コンパイルしてVivadoでシミュレーションするか、Cmod A7ボード(FPGA)に書き込んで動作確認することになります。以下に、サンプルプログラムVivadoでシミュレーションした結果を示します。

  実験サンプル:シミュレーション結果ログ
  FIBO: 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987,
  WRN: program encountered a halt code.
  Test Finish, you need verify waveform.
  CPI: 8453/ 6284( 1374)= 1345/1000
  finish: 357960 [ns]

 実際にCmod A7ボード(FPGA)に書き込んで実行しても、シミュレーションと同じ結果がシリアルモニタに送信されてきます。(@sim@オプションを削除してコンパイルしてください)。

プログラミング言語へ変換できる意義?

 Blockly for Moscovium開発環境は、Moscoviumマイコンで動作するプログラムを開発するための環境です。Blockly.XML→Moscovium.ASM変換スクリプトによって、Moscoviumマイコンで実行可能なオブジェクトを生成できるので、目的は果たせています。

 変換した所でどうせ実行できない、他のプログラミング言語へ変換できる意義は何でしょうか?

 データ交換用形式であるXMLでは、必要以上に記述量が多く、所謂プログラミング言語の体裁をなしていないので、プログラムの全体像をつかむことができません(以下参照)。

XML (一部抜粋、全体はこちらを参照)
<xml xmlns="https://developers.google.com/blockly/xml">
<variables>
<variable id="001">stra</variable>
<variable id="002">numa</variable>
<variable id="003">numb</variable>
<variable id="004">numc</variable>
</variables>
<block type="variables_set" id="005" x="13" y="13">
<field name="VAR" id="001">stra</field>
<comment pinned="false" h="245" w="302">@sim@
calculate Fibonacci sequence

: (中略)

</next>
</block>
</next>
</block>
</xml>

 情報としては、プログラム全体が含まれているのですが、上のXML形式を見てプログラムの流れを読み解く事は普通の人間には難しいでしょう。XMLは、あくまでデータ交換用の形式なのです。

※JSON形式も、XML形式と同様な状況であることを申し添えておきます。

 プログラミング言語形式のソースリストが入手できる意義は大きいのです。

ジェネレータ

 ここからは、Blockly for MoscoviumでエントリしたプログラムをJavaScript言語へ変換するため、Moscovium用に追加したカスタムブロックに対するジェネレータと呼ばれるコードを追加して行きます。

 Blocklyデモ自身も、ブラウザ上で実行されるJavaScriptと言う実行環境で動作しています。言い換えると、「BlocklyはJavaScript言語でコーディングされている」のです。よって、追加すべきジェネレータもJavaScriptで記述する必要があります。

 例えば、Blockly for Moscoviumで追加した、以下の様なカスタムブロック(digitalWriteブロック)を取り上げます。

a367_digwrt.png

 ジェネレータのひな型は、Blocklyデモの「Blockly Developer Tools」でカスタムブロックを作成すると、そのツールから出力可能です(Blockly Developer Tools ⇒ Block Exporter ⇒ Generator Stub)。
 以下コードは、上図に示したdigitalWriteブロックのジェネレータです。

  ジェネレータ例:
  javascript.javascriptGenerator.forBlock['mcoc_port_write'] = function(block, generator) {
    var value_pin = generator.valueToCode(block, 'PIN', javascript.Order.ATOMIC);
    var value_val = generator.valueToCode(block, 'VAL', javascript.Order.ATOMIC);
    // TODO: Assemble javascript into code variable.
    var code = 'digitalWrite (' + value_pin + ',' + value_val + ');\n';
    return code;
  };


 上のジェネレータに於いて、緑色文字の部分がBlockly for Moscoviumへ向けて変更した所、それ以外(紫色文字)の部分はBlockly Developer Toolsが出力したコードそのままです。部分的な変更でジェネレータを作成することができました。お陰で実際に作成(修正)すべきコード量は大した量ではありません。中々至れり尽くせり(Gの癖に)。

 上のジェネレータで変換した結果は、以下の様になります。

  変換結果:
  digitalWrite (port_0,high);

 Arduinoプログラマにとっては良く目にする、digitalWrite()関数を呼び出してI/Oポートport_0にロジックレベルhighを出力したかのような記述でしょう?ブラウザのJavaScript実行環境にはdigitalWrite()関数なんて存在しないので、実行しようとするとエラーになります。ですが、プログラミング言語への変換は上に示した通り、エラー無く終了します。

 同様にして、全てのカスタムブロックに対するジェネレータを作成して、Blockly for Moscoviumに組み込んだら完了です。

  完成したジェネレータ:mcvm_genjs.js

 Blockly for Moscovium開発環境の構築・更新方法については、こちらの記事をご参照ください。

結果確認

 過去作成したプログラムの中から、キッチンスケールのプログラムを選択して、JavaScriptへの変換結果を確かめたいと思います(過去記事は以下参照)。

  「#35-7 重量測定

  プログラム(kitchen_scale.bxml)

 Blockly for MoscoviumのXMLタブに貼り付けて、その並びにあるJavaScriptタブに切り替えると、変換した結果が表示されます。変換結果は以下リンクでご確認ください。

  変換結果:kitchen_scale.js

 Blockly for Moscoviumの数値型は、符号付整数@int@と浮動小数@float@を注釈中のオプションで切り替える方式です。テキスト形式のプログラミング言語となったことで、注釈中のオプションが視認できる様になり、どこからどこまでが@int@で、どこからが@float@なのか、解り易くなりました(こういう使い道もあった!)。

 なお、今回作成したジェネレータはJavaScript用なので、それ以外のプログラミング言語には変換できません。変換可能な言語の中では、JavaScriptが一番癖が無く(→C言語に近く)使い易そうだったので、これだけ対応しておきました。

 考えてみると:

 等と、随分ややこしい事になっていますね……(1^^;)。


 正直、ろくなことをしない印象のGoogleには眉をひそめる事が多いのですが、Blocklyだけは「褒めて使わす」、善哉。
P.S. Windows10がサポート終了とかぬかすので、嫌々ながらWindows11をインストールして見たが、糞過ぎる……。Microsoftのやる事もまた、眉をひそめる事、過多。
※沢山の天才たちが働いているのだろうに、その合成ベクタが馬鹿方向に向いているのは残念の極み(GもMも)。


btn_arduino.png

btn_prev.png btn_next.png

home