エピ16 値の評価はどうなっているか
***
エピ16 値の評価はどうなっているか
***
さて。ここまでの整理です。
エピ11で初期化処理を調べたら変数の領域が明らかになりました。数値変数や数値ワークがあって、特に数値ワークでは逆ポーランド記法を想起させる動作が興味深かったです。
それで、エピ12で LET 命令文に取組みました。LET A=0 で、0 という値を評価して変数 A に代入する様子を見ました。0 の評価は 2251h で行ってましたがアプローチできず。
エピ13では FOR ループを調べました。ここでも 2251h が登場。ああ 2251h か。
エピ14で思い切って数式の調査に取り組みました。LET A=0+1 なのに難解でした。1)〜4) の4つのルーチンの連鎖で演算子の優先順位を実現し、22D4h のルーチンで算術演算子の処理を、231Dh のルーチンで値の評価をしていると推測しました。
エピ15では 22D4h のルーチンを調査して、...とても、...とても難解でしたが。...だいたい、その通りでした。ROPに詳しくなりましたよ。
と、すると次は 231Dh について調べるのが順当。
ですが。2251h の処理の大部分は 231Dh のルーチンが占めていて、ここが本丸なのです。とても気が重いのです。イイねって応援が欲しいけど。
外堀は埋めてしまいましたから。ここが最期のはず。ならばやらねば。おれがやらねば誰がやるッ(...誰?)。
*
今回は 231Dh 番地のルーチンについて触れてみます。値とは何か、そして値の評価はどうなっているか? 分かるといいなぁ(弱気!)
***
231Dh からのコードを見ていきます。25FEh まで続くので目を細くしてルーチン単位で見ます。
*
最初に全貌を示しましょう。木構造っぽく表示してますが実際は入り組んでいて不正確な部分があります。イメージだけ感じてね。
・231D:符号の処置
・2340:文字(A-Z)か否かで分岐
・23C7:A-Z の場合
・23D2:数値変数の場合 ex. A
・2405:関数定義(FN)の場合 ex. FNA
・2486:文字変数の場合 ex. A$
・250C:文字配列の場合 ex. A$()
・2511:数値配列の場合 ex. A()
・2362:A-Z 以外の場合(=数値,記号,中間コードなど)
・18B3:文字列の場合 ex. "ABC"
・2F75:数値の場合 ex. 123
・2377:数値以外の場合
・237B:FFhの場合(=π)
・2384:括弧の場合 ex. (1+2)*3
・2392:中間コードの場合
*
では。コードの様子を鳥瞰しましょう。上空から見てみるだけよ。
231Ch:
inc HL して 231Dh へ
231Dh: 値の評価のスタート
A の値で分岐します。
・A = BCh('+')なら 2340h へ
・A = BDh('-')なら 2328h へ
・それ以外なら 2341h へ
2328h: '-' の場合
2340h をコールして、値が 0 でなければ符号を反転して、RET
2340h: '+' の場合('-' の場合はここをコール)
inc HL して 2341h へ
2341h: 値の評価の本体はここから
2556h をコールして変数名(A-Z)かをチェックします
・変数名ではないなら 2362h へ(数値・記号・中間コードなどね)
・変数名が FN なら 2405h へ(関数定義ね)
・それ以外なら
23C7h をコールして変数を検索します
・B==00h なら
2311h へ(数値ワークに転送して、RET)
・B!=00h なら
18CE をコール(文字ワークに転送)して pop HL, A=[HL], RET
2362h: 変数名ではない場合
A の値で分岐します。
・A = 28h('(')括弧なら 2384h へ
・A = 22h('"')文字列なら 18B3h へ(文字ワークに転送して、RET)
・それ以外なら
192Ch をコールして数値(0-9)かを判定します
・数値なら 2F75h へ(...。)
・数値以外なら 2377h へ
2377h: 変数・数値以外の場合
A の値で分岐します。
・A!=FFh なら 2392h へ
・A==FFh なら(FFhは 'π' です)
円周率を設定(DE=1624h)、2311h へ(数値ワークに転送して、RET)
2384h: 括弧の場合
BC=0000h で 174Ah をコール(メモリサイズのチェック)
21FEh をコール(ルーチンの連鎖の 1) ですよ)
169Ah(29h) をコール(29h は ')' です)
RET
2392h: 文字列関数か数値関数の場合
ジャンプテーブル2と3の分岐処理
23C7h: 変数の場合(...エピ12で登場しましたよ)
A の値で分岐します。
・A==24h('$')なら 2486h へ(文字変数の場合)
・A==28h('(')なら 2511h へ(数値配列の場合ね)
・それ以外なら 23D2h へ
23D2h: 数値変数の場合
数値変数の処理
2405h: 関数定義の場合
関数定義の処理
2486h: 文字変数の場合
A の値で分岐します。
・A==28h('(')なら 250Ch へ
・それ以外なら 248Eh へ
248Eh: 文字変数の場合
文字変数の処理, TI$の場合は 24C5h へ
24C5h: TI$の場合
TI$の処理
250Ch: 文字配列の場合
BC=0100hして、2541h へ
2511h: 数値配列の場合
BC=0000hして、2541h へ
2514h: 配列の場合
配列変数の共通の処理
2555h:
inc HL して 2556h へ
2556h:
変数名をチェック
259Bh:
2556h をコールして、'FN'なら エラー
25ADh: ジャンプテーブル1
B0h..BFh と CFh(比較演算子と算術演算子)
25CFh: ジャンプテーブル2
C0h..CBh (文字列関数 LEFTS(, RIGHT$(, MID$(, ... など)
25E7h: ジャンプテーブル3
D0h..DBh (数値関数 RND(, SIN(, COS(, ... など)
***
**
*
一気に、...、ゼイゼイ...。走りきりました。
*
2384h のルーチンによると、括弧を使うと 2251h らのルーチン連鎖の先頭である 1) 21FFh からの処理になるのです。
LET A = 1=1
...、は SYNTAX ERROR ですが
LET A = (1=1)
...、とすれば、括弧の中の '=' は比較演算子として処理されて変数 A に真理値が入ります。21FFh で処理する演算子は優先順位が最低ですが、大丈夫です。
ですが、真理値という型などは無くて、真なら -1、偽なら 0 という数値が入るだけなのです。0 とは 80 00 00 00 00 という5バイトですし、-1 は 41 00 00 00 80 なのです。
これは少々困った感じになります。
SP5030の解説書では、論理演算子の説明で論理和 '+' と論理積 '*' を挙げているのですけど。エピ14で説明したね。
実際には(括弧を付けようが)'+' と '*' は加算や乗算として処理するしか無いのです。'+' の中間コードは BCh で、BCh の分岐先は 2D0Eh しか無いのですからね。
(1=1) ⇒ -1 になる(真ですから)
(1=1)*(1=1) ⇒ 1 になる(真 and 真 は 真?)
ここまでは支障無いです。0 以外は真と扱うならね。
(1=1)*(1=1)+(1=1) ⇒ 0 になる(真 and 真 or 真 は偽かよ!)
ここで破綻します。1 と -1 を加算すれば 0 だから。
そもそもですね。21FFh には論理和や論理積を扱うコードがありませんからね。キーワードには AND, OR, NOT がありますけどね。ジャンプテーブルにも分岐先がありますけどね。分岐先では実装していないのです!
解説書で論理演算子として説明している演算子のうち、実装しているのは比較演算子だけです。
だからせめて。真は 1 とすれば、
0*0 = 0 0+0 = 0
0*1 = 0 0+1 = 1
1*0 = 0 1+0 = 1
1*1 = 1 1+1 = 2
...、ですから、論理積を乗算、論理和を加算で処理しても(1+1=2 ってなる点にだけ注意してね)、なんとかなるのに。どうしてですかー
*
N-BASICでは '=' や '>' のことを関係演算子と言っていて、論理演算子として 'AND', 'OR', 'NOT' 等が用意されている。いいなー
F-BASICも同様に関係演算子や論理演算子があって、...だけど、F-BASICの 'AND' や 'OR' はビット単位の演算ですって。
真と偽は -1 と 0 です。-1 は FFFFh で、0 は 0000h なので大丈夫か。むしろ 1 AND 2 で 0 になり、3 OR 6 で 7 になるとか便利かも。
...、よく調べたらN-BASICの論理演算子もビット単位の演算でした。
N-BASICとF-BASICは整数なら2バイトなのに対して、SP5030の数値は全て5バイトの浮動小数点数だからな。同様にはできないな。
はッ! もしかしてだけど、...、だからSP5030では 'AND' を実装できなかったのか?
*
ひとつの回避方法として、
(0<>((0<>((0<>(1=1))*(0<>(1=1))))+(0<>(1=1))))
のように、論理演算をする毎に (0<>(論理式)) と括弧を付けて 0 との比較をする、...ことを考えました。括弧が沢山で楽しいです。
(0 <> 真) ⇒ -1 (真になる)
(0 <> 偽) ⇒ 0 (偽になる)
比較演算子の結果は安全なので 0 との比較は不要で、論理和と論理積のときだけ処置すればよいか。0 との比較は後付けにすれば括弧を減らせるし。
(((1=1)*(1=1)<>0)+(1=1)<>0)
これならシンプルで分かり易いですね。
LET A=-1:B=0:C=-1
のように真理値を持つ変数で、
IF ((A*B<>0)+C<>0) THEN ...
と言った処理ができます。
*
実際に使っている人がいそうな予感が、...パソコン雑誌を探してみようか。
*
DEF FN 命令文を使うと、
IF FNL(FNL(A*B)+C) THEN ...
と表記できるけど、どちらが見やすい?
***
**
*
2392h ではジャンプテーブルが出て来ました。
中間コードの C0h〜CBh 用と D0h〜DBh 用とで2つあります。C0h〜 は文字列関数、D0h〜 は数値関数です。テーブルジャンプの仕組みは既出と同じ感じかな。
これで中間コードの分岐先が出揃いました。分岐先のコードは個別に見ていけばよいですし、全部を見なくても良いですね。SIN() を読めば、COS() と TAN() のことは察しが付きますから。
乗算のアルゴリズムは、カラツバとかFFTとかをしているか確認したい? ...あまり興味ないね。...、散々と苦労したから。
直接実行命令文もね。'IF' 命令文をみたら 21FFh をコールして結果を判定して GOTO なり、THEN 以降の命令文を実行するかを決める感じで。それで分かった、もういいです、...って感じ。
'MUSIC' 命令文とか、'SET' 命令文とか見ていないコードは沢山あります。
でも、SP5030で興味があるコードはたいだい把握できたかも。うーん、あとはどうしよう?
感想欄で要望があれば(できる範囲でね)調べますけど、...どうですか? 何か無いですかー 無い、...です、...か。そうですか。
***
**
*
眠れない夜に。
最近のマイブームですけど。
キノコをオリーブ油に浸して、適当な調味料、...シャンタンをひとすくいとか、...を入れて、グツグツと煮たものを食べてます。ブナシメジとかエリンギとか。マッシュルームも良いかも。
食べた後には油が残るので、茹でたパスタを投入して、...。
そんな感じで夜は更けていきます。
***
間違いの指摘とか疑問とか、ご意見・ご感想とかありましたら、どうぞ感想欄に!
***
2026.3.12 加筆と推敲
2026.3.17 微推敲
2026.3.20 微推敲
2026.4.1 微推敲




