[5770 ]
Re^15: N88-BASICの中間語
konno
2025/04/09(Wed) 16:53
[
5766 ]へのコメント
> konnoさんが誠実な人であるのは間違いがないところでしょう。
根がいい加減なのでなるべく誠実なふりをしているとバレてるかもしれんが。(^^;
> > NP2でN88BASIC を使って RENUM や中間語に変換してみました。
> これ、変換に使ったツールの記述はありますが、変換後をどうやって表示している
> のかがよくわからない。文字化けっぽい表記になっている、というのもあって。
VZで開いて見えたイメージをテキストにしたのです。ここの人達ならわかるかと。(^^;
> ということで引っ張り出してきたのが、ASCIIの出版した「PC-Techkonw 8800」
> という本。ISBN4-87148-292-8。archive.orgにあるかなぁ。
ググったら MSX2のがありました。\(^^)/
https://archive.org/details/MSX2TechnicalHandBookFE1986/mode/2up
> この本には、ROM内のルーチンのどのアドレスに何をするコードがあるか、と
> いう表も載っていて、それによると、RENUMを行うルーチンは75DDH〜7673Hに
> あるとか。なんと、150バイト。もちろん、どこかよそのサブルーチンを呼んで
> いるのかもしれませんが、でもRENUMでも使うような汎用性のあるルーチンて
> ちょっと思いつかないので、これで全部のような気もする。
マシン語ならそのくらいで出来るかもしれませんね。
せっかくなので私も DEBUG の結果を張っておきます。
3D6A:0100 FE 15 00 0A 00 01 41 00-F1 0F 0A 3A A4 01 0E A0 ......A....:....
3D6A:0110 0F 00 27 31 30 00 0E 00-1E 00 01 A7 01 41 00 00 ..'10........A..
3D6A:0120 27 33 30 00 24 00 C8 00-02 A8 01 41 00 24 F1 FF '30.$......A.$..
3D6A:0130 9C 28 0F 0D 29 01 D6 01-0E B8 0B 01 3A 99 01 0E .(..).......:...
3D6A:0140 C8 00 00 27 32 30 30 00-2E 00 D2 00 01 00 27 69 ...'200.......'i
3D6A:0150 66 20 61 24 3D 63 68 72-24 28 31 33 29 20 74 68 f a$=chr$(13) th
3D6A:0160 65 6E 20 33 30 30 30 20-65 6C 73 65 20 32 30 30 en 3000 else 200
3D6A:0170 09 27 32 31 30 00 10 00-2C 01 02 A3 01 0E 1E 00 .'210...,.......
3D6A:0180 00 27 33 30 30 00 0D 00-B8 0B 01 9A 00 27 33 30 .'300........'30
3D6A:0190 30 30 00 19 00 A0 0F 01-9E 01 49 00 F1 11 01 DA 00........I.....
3D6A:01A0 01 41 00 3A B7 00 27 34-30 30 30 00 0D 00 68 10 .A.:..'4000...h.
3D6A:01B0 01 C6 00 27 34 32 30 30-00 1A 00 00 00 00 00 00 ...'4200........
10 A=10:GOSUB 4000'10
30 INPUT A'30
200 IF A$=CHR$(13) THEN 3000 ELSE 200'200
210 'if a$=chr$(13) then 3000 else 200 '210
300 GOTO 30'300
3000 END'3000
4000 FOR I=1 TO A:NEXT'4000
4200 RETURN'4200
よそ様で話題に出ていたネタです。長いです。90行を越えてしまった。
いにしえのN88-BASICには、行番号が必須です。
プログラムを作っている最中は行番号の並びなんてぐちゃぐちゃになってしまう
ことも多々ありますが、ある程度固まったら、例えば10番おきとかにきれいに
整列させたいという希望があります。
これ、BASICのインタプリタ環境にいるときはRENUMコマンド一発で行けますが、
Vzでコードを書いているときは、なかなか一筋縄ではいかない。なぜというに、
RENUMコマンドって、コードの中のGOTO文なんかの飛び先まで書き換えてくれる
のですが、これをVzマクロでやろうとするとなかなか大変。
この大変そうなものに挑戦しようと思いました。が、ほとんど思っただけ。
きちんと仕様を考えてたらとんでもないことがいろいろ発覚したので、まず最初
はサブセットで動くもの。とはいえ、できるかどうかわからない最終的な仕様を
目指して拡張性のあるものを作るくらいなら、最終仕様のものまで一気に作って
しまおうか、という気もする。
いろいろな例外条件はあるのですが、基本的な外部仕様というか、こういう入力
がこうなってくれる必要がある、という例を以下に示します。
まず変換元。
100 IF A=B THEN 130 ELSE 150
130 GOTO 200
150 GOSUB 330:END
330 REM SUBROUTINE
これを変換するとこうなってほしいという変換後。
100 IF A=B THEN 110 ELSE 120
110 GOTO 200
120 GOSUB 130:END
130 REM SUBROUTINE
ジャンプ先が実在する行番号は、行番号の付け替えに伴い、コードの中身も置き
換わってくれることが必須。一方で、ジャンプ先が実在しない場合は、変換例の
110行目のように、変換が発生しないようにしたい。実機でもこういう仕様だった
と記憶しています。
ところで、上記で「最初はサブセット」なんてことを書きました。フルセットに
しない理由は、N88-BASICの仕様では、行番号の最大値は65529。そんなに大きな
行数のプログラムを作ったことがないので知りませんでした。が、なかなか微妙
な値です。とはいえ、もし簡単にこの値を使ったコードが実現できるのならば、
一気に作りたい。
さて、ここまでは事前の仕様検討で気がついた点です。
ここから実際のマクロを作りながら仕様を検討したら、次々と問題点が発覚。
まずは行番号の上限値。
たとえば、仮にサブセットとして上限値は32700でもいいのですが、処理を始める
前に上限を突破するかを確認し、もし突破するようならメインルーチンに入る前
に中止したい。これは初期値と増分と論理行数がわかれば計算できそう。
ただ、条件判定で気になるのが、仮に増分を1000番刻みの場合、行番号が32000の
次は33000になるわけですが、素直に作ると、なんとなく比較が破綻しそうな値。
ここはサブセットならではの制限をかける必要がありそう。
あるいはフルセットにするか。
また、BASICとして正当ではない行がある場合。
この場合、このファイルはN88-BASICのコードではないという理由で変換開始前に
処理停止。要は、途中まで変換して、そこでやめた、ということは回避したい。
この正当性の要件ですが、とりあえず思いつくものとしては、行番号で始まって
いない論理行。空行がある場合も、これは行番号が付されていないわけですから
当然処理中止。また、行頭は数字でも、数字の並びのあとが半角空白かタブでは
ない場合、つまり数字のあとに英字や記号がくっついている場合も処理中止。
ということで、私の考えたマクロのラフスケッチが以下のとおり。
初期設定
増分はハードコーディング
初期値は、開いているファイル自体の最初の行の行頭から取得
ファイル正常性確認
初期値、増分、論理行数から上限チェック
全ての行の行頭が数値であることのチェック
メインループ
終了処理
ここでいくつか質問。
まず、論理行の要件チェック。
ループまわして各行チェック、というのはわかります。
そして、1文字ごとに cd で見ていくのが確実ですが、そうではない、なんか楽
な方法はないものか、と。
そして、行番号の上限チェック。
初期値の取得はカーソルをファイル先頭に移動させて &n ですが、論理行数って
カーソルをファイル末尾に移動して ln というのが常套手段でしょうかね。
そして、モロモロ掛け算とか足し算とかで、さて上限値を超えたときのチェック
はどうすればよいでしょうか。
さらに、将来的なフルセットの場合、行番号の初期値は40000だった、というもの
にも対応させたいわけですが、これって &n では対応できませんよね。ならどう
すればよいか、ということについてもアイディアをお伺いできればと思います。
> RENUMコマンドって、コードの中のGOTO文なんかの飛び先まで書き換えてくれる これは一番大事なキモというやつですが,色々なやり方があると思いますので,一旦置いておきましょう。
> 最終仕様のものまで一気に作ってしまおうか、という気もする。 そうですね。としきさんがサブセットで満足できるとは思えません。
ただ,現実的な一定の制限を持つ仕様は必要だと思います。
> ただ、条件判定で気になるのが、仮に増分を1000番刻みの場合、行番号が32000の > 次は33000になるわけですが、素直に作ると、なんとなく比較が破綻しそうな値。 増分が1000番刻みって,あまりにも非現実的な気がするのですが,本当にそういうものを目指すのですか? そもそも増分をどこで設定するのでしょう。ここがはっきりしないと先に進めないように思います。
> また、BASICとして正当ではない行がある場合。 この判定は,無理ということはないですか?
そもそも正当な行とは?
> 数字のあとに英字や記号がくっついている場合も処理中止。 これだけならそれほど問題はありませんが……
> 論理行の要件チェック。 この要件を列挙していただけますか?
でないと,なぜ「1文字ごとに cd で見ていくのが確実」なのか分かりません。
> 行番号の上限チェック。 行数と増分の積というわけではないのですか?
> 初期値の取得 例えば,初期値と増分を決めておいてはいけないのですか?
経験的には,番号初期値は 1000 に決めていたりしたように思いますが……。
フルセットを目指すのは大切だと思いますが,行番号の初期値が 40000 とか,自分にとっては相当の違和感があります。
それは別として,&n で対応できないロング整数の取得の方法はないわけではないですが,けっこう面倒です。例えば,
「カーソル位置の数字列を数値として取得するには」(VZマクロFAQ)
http://mezala.la.coocan.jp/vz/faq/opera.html#opera_015
まずはじめに。
> 一方で、ジャンプ先が実在しない場合は、変換例の
> 110行目のように、変換が発生しないようにしたい。実機でもこういう仕様だった
> と記憶しています。
タッチアンドゴーで実家に行き、ちょっとN88-BASICの仕様を確認してきました。
滞在時間5分。
結果、記憶違いもあって。
飛び先の部分の変換が発生しないという部分は正解でしたが、行番号の変換自体
は行われていました。そして、「Undefined line number」なるエラーを吐く。
このエラーは、例えばGOTOの飛び先がないときに発生するエラーなんで、わりと
よく見かけるものですが、まさかプログラムの実行時以外で見かけるとは覚えて
いなかった。
もうひとつ、RENUMコマンドの引数って「新行番号、旧行番号、増分」なんです
が、それぞれの引数は省略可能。そして増分を省略した場合のデフォルトは10。
ここで、先に例に出した4行のプログラムで「RENUM 65520」とかやると、最後
の行の行番号はデフォルトの最大値の65529を越えてしまいます。この場合は
「Illegal function call」エラーとなります。こちらはマニュアルにも明記
してあります。今回検討しているマクロでは、サブセット版であればこの上限値
は別の値でもいいでしょう。
ということで
> 増分が1000番刻みって,あまりにも非現実的な気がする
これはおっしゃるとおり。
ただ、「増分が1000」ではなく「初期値が65500」でもいいのですが、要は上限を
超えるときの挙動をあらかじめ決めておきたい、ということです。
そして、その挙動としては、変換を全くはじめることなくマクロが終了すること
を希望しています。
> そもそも増分をどこで設定するのでしょう。
これは、#5731 にも書きましたが、マクロのコード内にハードコーディング。
絶対にないと思いますが、将来的には可変にしたい。
> > また、BASICとして正当ではない行がある場合。
> この判定は,無理ということはないですか?
テキスト処理だけで行うと無理かもしれない。だけど、#5731 に書いた正統性要件
だけでもチェックしたい。つまり
・半角数字で始まっていない行がある
・行頭の半角数字を数値として取得したときに上限値を越えている
(上限値は別途定義)
・行頭の半角数字列のあとが半角空白でもタブでもない
これらいずれかの要件を満たす行が1つでもある場合は処理を開始したくない。
ということで、このチェックに当たって私が考えた方法が
「1文字ごとに cd で見ていく」
なのです。というか、これしか思いつかなかった。
もちろん、他にもっと良い方法があればご教示いただきたい。
> > 行番号の上限チェック。
> 行数と増分の積というわけではないのですか?
たぶんそれでいくと思うのですが、何か見落としがあることが怖い。
> > 初期値の取得
> 例えば,初期値と増分を決めておいてはいけないのですか?
上にも書きましたが、増分はマクロコード埋め込みでよいと思っております。
が、初期値については、BASICのコードから、すなわち処理対象ファイルから取得
したい。そして、どうやって取得するかというと、ファイル先頭の行の行番号を
採用するということで。って、このへんのことは#5731 にも書いていましたね。
> 「カーソル位置の数字列を数値として取得するには」(VZマクロFAQ)
ぅぉぉ、こういうのがほしかったんですよ。
とても参考になります。
> 要は上限を超えるときの挙動をあらかじめ決めておきたい、ということです。 それ,先に言ってくださいよ。(^^; こちらも察することができなくて申し訳ないですが,極論から入るみたいな論法って元公務員は慣れていないので苦手なんです。 先に不整合な値を確認して実行可不可を決めるのは至極真っ当だと思います。 将来的に,開始行番号や増分の初期値を可変にするのは簡単ですね。起動時にオプションの初期値メニューを表示して,そのままでよければ一打で実行というのはよくある。わたしもそういうマクロは作りますから,部品を流用できます。 列挙していただいた正統性要件であれば,わりにチェックは簡単ですね。 一行ごとに判定するのは時間がかかりますが,まぁ,そこは人間が目視で判断しようとするのは現実的でないのは明らかですから,これも至極真っ当。> 「1文字ごとに cd で見ていく」 カーソルの移動がともなうので,かなり速度が落ちますね。 他のやりようとしては,ラインバッファを文字列として取得し,文字列関数を使うという手が考えられます。実際に試してみないと,どの関数が適任かわからないけど例えば… &Sw(p) : 文字列pのスペース/タブまでの文字数 こんなのが如何にも使えそうじゃないですか?> ・半角数字で始まっていない行がある これは超簡単で,(cd<$30 || cd>$39) で判定できますね。 ただし,どのみち> ・行頭の半角数字を数値として取得 ということであれば, 行頭で &n を実行して戻り値が -1 なら数字ではないと判定しつつ 行番号も取得できます。 ただし,> したときに上限値を越えている ……かどうかは,正確な判定が必要ですね。 実は,わたしにはその必要性がちょっと理解できませんでした。 行番号の値が上限値を越えていても,処理の中で丸めてしまえばよくないですか? ・行頭の半角数字列のあとが半角空白でもタブでもない ここに &Sw(p) が使えそうですね。最初の空白文字まで5文字以下ならよさそう。 もちろん上限値も5文字に含まれるので,複数条件でチェックする必要がありますけれど,5桁で先頭の数字が5以下なら &n で取得した値で大丈夫(負になる可能性もあるので判定は慎重にすべきですが)。6だったら,より正確に判定が必要。5桁で先頭が7以上は不正な値確定。> ぅぉぉ、こういうのがほしかったんですよ。 上限値が16ビットで(正負を注意すれば)扱える範囲なので,ご参考までに。
> > 要は上限を超えるときの挙動をあらかじめ決めておきたい、ということです。 > それ,先に言ってくださいよ。(^^; いや、申し訳ない。
実のところ、
#5733 を読んで、自分の中で考えが熟成されたのですよ。
とはいえ、
#5731 で書いたような、増分が1000番刻みでもN88-BASICは対応しているわけでして、確かに非現実かもしれませんが、個人的にはぜひとも対応したい。
という思いが先走ってしまったというのもあるかもしれません。
結果、十分に一般化された日本語表現ができていなかった、と。
> &Sw(p) : 文字列pのスペース/タブまでの文字数 > こんなのが如何にも使えそうじゃないですか? そうか、文字列関数ってのがありましたね。
私がほとんど使ったことのない分野なんで、一から勉強、かな。
でも、ラインバッファを文字列として取得するってところからわからない。
別の変数にラインバッファの中身の実体をコピー?
それとも、ラインバッファのアドレスを別の変数にコピー?
はたまた、ラインバッファのアドレスを直接、文字列関数に渡す?
> 行番号の値が上限値を越えていても,処理の中で丸めてしまえばよくないですか? ここはそうかもしれない。
いろいろと手抜きしたら、結果的にそうなるかもしれず。
最短で次の週末あたりには、手抜きバージョンが動き始めているかも。
もちろん、そんな甘甘の見積もりどおりに行くわけはないけど。
> ラインバッファを文字列として取得するってところからわからない。
ごめんなさい。「取得」は不正確でした。
「ラインバッファの『文字列』化」と言うべきところでした。
どういうことかと言うと,文字列操作関数は対象が「文字列」でないと,
最悪暴走する可能性があるんですね。「文字列」とは釈迦に説法ですが,
終端にヌル(00h)がある文字キャラクタの並びです。ラインバッファは
他のバッファと異なり,もともと終端にヌルがありません。そのため
ラインバッファの終端にヌルを意図的に埋め込んで「文字列」にします。
そして,使い終わったら行編集のキャンセルコマンドをかませます。
> はたまた、ラインバッファのアドレスを直接、文字列関数に渡す?
要は,これになります。他のバッファに転送するわけではありません。
次のサンプルは対象とするコードの行番号正当性をチェックするだけのもの。
上限の値が16ビットに微妙に収まる範囲のようですので,より正確な判定は
もう少し仕様を固めてからでよいかと思いました。
= Test
*mad for vz!
1 ^\ "Bas_chk"
?.
; #^ ;ファイルの先頭からなら生かす
#<
e-, ;エラーのフラグ(仮) (e)
;; ==== メインのループ
:L &n (r+1)??{ e+, >E } ;行番号取得,不正なら終了
#28 wa..19.2-, ;ラインバッファの文字列化
a=wa..18, ;ラインバッファ先頭アドレス (a)
&Sw(a) b=r, ;行番号の桁数 (b)
c=a.0, ;行頭キャラクタ (c)
#54 ;行編集のキャンセル
(b>5)?>E ;行番号が5桁を超えるエラー
(b==5)?{ (c-$30>6)?>E } ;5桁の場合で先頭が6を超えるエラー
;; (上限を確認するか or 丸めるか)
#> #d (r)??>L
(e)?{ ;; ==== エラーの処理
:E &m("行番号不正またはファイルの最後")
}
:Z ;; ==== Quit
&d #] .
*
第一段階のチェックが終わったら,次は飛び先番号の洗い出しという手順かと。
> 第一段階のチェックが終わったら,次は飛び先番号の洗い出しという手順かと。 【\s[0-9]+】の正規表現で,もれなく拾えるでしょうか? 見たところ,番号の手前に必ず空白があるようですが,後ろは空白とは限らず改行やコロン(:END)があると見受けられます。 行番号の前に空白があったら不正ですよね。
今日、会社の昼休みに、ちょっとマクロをいじってみていました。> 【\s[0-9]+】の正規表現で,もれなく拾えるでしょうか? そうか、\s という表記がありましたね。 試してみたのは【[ \t]+[0-9]】でしたが、なんとなくうまく行っているっぽい。 ジャンプ先行番号の条件については、おそらくめざらさんは正しく認識されていると思います。 で、ちょっと悩んだのが、事前チェックの条件の一つである空行。 プログラムの終端というか最終行、大抵は空行なんですよね。 これの扱い、どうしようかな。
> 試してみたのは【[ \t]+[0-9]】でしたが、 飛び先の直前がタブということがあるのですか……むう。
ちょっと思ってるのと違った。この + は要ります?
> で、ちょっと悩んだのが、事前チェックの条件の一つである空行。 #5737 のテストマクロでは,
#> #d (r)??>L
行末からその先に進めない(#d の戻り値が -1)ときはループの先頭にジャンプ……つまり行末からカーソルが動かなければファイルの終端なので終了.
通常,この段階でエラーフラグが立っていないケースはほぼないと思いますが,念の為にこいつを入れています。
途中の空行は行頭に数字がないので,もちろんエラー通告で停止です。
> ちょっと思ってるのと違った。この + は要ります?
可読性向上のための桁そろえ、というのがあるかもしれないと考えました。
とりあえず、私のきちんと動かないバージョンはできました。
きちんと動かないことは理解していますが、条件がそろうと動くこともある、
といった感じ。
= renum.def
i:初期値 initial num
a:増分 addition
n:新行番号 new num
o:旧行番号 old num
*m
1 ^^ "renum.def"
;初期設定 ;vwxの常駐確認とか?
a=10,
n=o=0,
;RXとかの設定も念のためにするべき?
#^ #< ;カーソルを先頭行の行頭にして
&n i=r, ;初期値取得
;メインループ
;先頭行は行番号の変更なし
:w ;while(次の行に動ければ)
#> #d ;次の行にカーソルを移動し
#d (r==-1)?>u ;その結果が最終行ならループ脱出
#<
&n o=r, ;旧行番号取得
n=i+(ln-1)*a, ;新行番号算出
#t ;旧行番号削除
&?("%d",n) ;新行番号出力
#56 "GOTO\([ \t]+\)" &?("%d",o) "$$" #m
"GOTO\1" &?("%d",n) #m "ay"
#56 "GOTO\([ \t]+\)" &?("%d",o) "\([^0-9]\)" #m
"GOTO\1" &?("%d",n) "\2" #m "ay"
#56 "GOSUB\([ \t]+\)" &?("%d",o) "$$" #m
"GOSUB\1" &?("%d",n) #m "ay"
#56 "GOSUB\([ \t]+\)" &?("%d",o) "\([^0-9]\)" #m
"GOSUB\1" &?("%d",n) "\2" #m "ay"
>w
:u
*
すぐにわかることですが、このロジックでは、一旦変換した行番号が再変換の
対象になりうるわけです。なので、ここはやっぱり素直に変換表を作るような
ロジックにする必要がある。
逆にいうと、例えば100から始まって990までで終わっているプログラムを
1000からに変換する、みたいな感じで再変換が発生しないような変換だと、
なんとなくうまく動いているっぽい。もちろん、意図的に考慮していない
部分はいっぱいありますが、意図せざる考慮漏れというのがあれば、これで
あぶりだせたらちょっとはうれしいかも。
ということで、めざらさんに提示していただいたコード、これから読解して
いきます。
[5754 ]
Re^10: N88-BASICのRENUMのようなマクロ
konno
2025/04/06(Sun) 18:56
[
5753 ]へのコメント
> とりあえず、私のきちんと動かないバージョンはできました。
良いのが出来たら私もお世話になるかもしれないので試してみました。(^^;
以前素数でやった PN88-02.BAS です。
2024/04/03 21:03 4,173 PN88-02.BAS
初期値が必要なので、先頭に 100 ' を挿入して実行してみました。
1000 'prime88.bas 2024-03-22
↓
110 'prime88.bas 2024-03-22
結果は
1365 s=I:gosub 3200:s=n
↓
480 s=I:gosub 3200:s=n
3110 if xx <> lastx then 3080 'loop1
↓
1450 if xx <> lastx then 3080 'loop1
このように、gosub 文が変換されませんでした。
小文字だったからでしょうね。 まぁ普通は対象外ですよね。(^^;
> すぐにわかることですが、このロジックでは、一旦変換した行番号が再変換の
> 対象になりうるわけです。なので、ここはやっぱり素直に変換表を作るような
> ロジックにする必要がある。
私は別ファイルに書き出すものと思っていました。それだと GOTO GOSUB が問題か。
後方変換なら問題ないのかなぁ。具体的には何も考えていないもので。(^^;
なので私はテスターに徹しようと思います。(^^;
> 後方変換なら問題ないのかなぁ。 いやー,そんなことはないでしょう……(^_^;)> なので私はテスターに徹しようと思います。(^^; まぁ,そう言わんと,ゆっくりしていってくださりませ。
> 例えば100から始まって990までで終わっているプログラムを1000からに変換する、みたいな 開始初期値を先頭の番号で設定するというそもそもの前提が崩れますが,例えば起動時にメニューから初期値を指定するとかデフォルトでいいとか,あるいは先頭番号から取得するとか選択させる,という動きにするのでしょうかね。> vwxの常駐確認とか? これは可能なはずです。ただ,ふつう正規表現様の記載がプログラムに出現するかと言えば,まずありえないと思われるので,設定しなくてもマッチする文字列が存在しないということで停止又はスルーすることになると思われます。 敢えて確認するならシステムコールを使いますが,詳細は VWX.DOC を見てください。> RXとかの設定も念のためにするべき? としきさん個人用であれば,正規表現がデフォルトなのでしょうから別にどうでも…… 念の為ということなら,しておくに越したことはないでしょう。 それよりも,Konno さんの例で挙げれば,Ec(検索時の英大/小文字の同一視)を有効(デフォルトは無効)にしておくことに注意すべきかもしれません。> このロジックでは、一旦変換した行番号が再変換の対象になりうる それを「最悪」と。
> それよりも,Konno さんの例で挙げれば,Ec(検索時の英大/小文字の同一視)を有効(デフォルトは無効)にしておくことに注意すべきかもしれません。 なるほど、いろいろと注意すべきことが湧いて出てきます。> > このロジックでは、一旦変換した行番号が再変換の対象になりうる > それを「最悪」と。 御意。 ところで、夕方、風呂掃除をしているときに思いついたことです。 そもそも、BASICインタプリタでのRENUMコマンドの実装ってどうなっているんだろう、というのが出発点。例えば、行番号1から始まって1番刻みで32000行あるプログラム、これを増分2でRENUMコマンドをかましても、仕様上は問題なく動作するわけですよ。実際に試すとどうなるかわかりませんが、他のマシンを含め、RENUMコマンドで問題が発生したという話は聞いたことがありません。ということは、これってテーブル方式ではなさそう。だってテーブル方式だと、かなり高い確率で破綻をきたしそう。 だとすると、私がやったような逐次変換方式か、はたまた全く別の方式か。でも、仮に逐次変換方式だとしても、テキスト処理でやっているわけではなく内部表現での置き換えだから問題が生じないんだろうな、と、一旦は納得しました。 が、風呂掃除を終えて落ち着いて考えると、この推論はおかしい。 例えば110行が130行に変わったとして、既存の110行にジャンプしているGOTOを全て130に変更します。次に130行が150行に変わるので、130行にジャンプしているGOTOを書き換えるとして、これが変更前の130行なのか、それとも旧110だったものが130に書き換え済みのものなのか、どうやって判別するのか。これ、どんな方式でやろうと、ついて回る問題だと気がつきました。 フラグ? フラグなのか? う〜ん、一体どうなっているんだろう。
> どうやって判別するのか。これ、どんな方式でやろうと、ついて回る問題 何かマーキングしているんでしょうね。
あるいは,内部的には番号ではなくアドレスになっているのかも……って,いずれにしても数値である以上は同じ問題を内在しているわけだなぁ……。
飛び先番号の前に【必ず】スペースが配置されていれば,いや逆にそれを仕様とするなら出来るのではないかと思います。
例えば,空白類+番号のセットを,変換後は一旦,特定キャラクタ(列)+番号にしておいて,最後に特定キャラクタ(列)を空白に一括置換する……という感じ。
もちろん,その場合は,実行開始時に特定キャラクタ(列)が一切存在しないかどうかチェックする必要はありますが,比較的容易にできて,かつ実行条件としてもそれほどの障壁ではないと思います。自分ならそのようにします……と言うか,しばらく考えてみましたが,それ以外に(優劣はともかく)案が出てこない。
具体的には……
#56 "[\s\t]【旧行番号】" #m "※【新行番号】" #m "ay"
……のように1行単位で置換しておくと,空白類を前置しているのが前提なので,他の行番号のときは置換対象にはならず,
#56 "※\([0-9]+\)" #m " \1" #m "ay"
……という感じで最後にに全部スペースに戻す。(タブもスペースになるのは「仕様」)
滅多に使わない文字,キーボードから入力できる記号にそっくりな記号……例えば「♯」(#ではない),「♭」(bではない),「∃」(ヨではない……があまりに見分けがつかないけど)……などがよいのかな。
[5761 ]
Re^13: N88-BASICの中間語
konno
2025/04/07(Mon) 20:01
[
5760 ]へのコメント
NP2でN88BASIC を使って RENUM や中間語に変換してみました。
1000 'SQR.bas E8^C=$03E8=1000
1060 '入力待ち .^D=$042E=1070
1090 if a$="" then 1070 B^D=$0442=1090 ^N=then .^D=$042E=1070
行番号は ^@+16進数に、ラベルとしての番号は16進数+^@ のような感じかな。
以下は RENUM したソースと中間語の一部
10 'SQR.bas ^@$0A=10 ^@^T
20 'screen 0 ^@^T =20 ^@^R
30 PRINT " input "; ^@^^ 30 ^@$0A
40 INPUT A ^@( =40 ^@
50 PRINT " SQR(";A;")";SQR(A) ^@2 =50 ^@^H
60 ' ^@< =60 ^@^P
70 '入力待ち ^@F =70 ^@^[
80 PRINT " push eny key "; ^@P =80 ^@^O
90 A$=INPUT$(1) ^@Z =90 ^@^Z
100 IF A$="" THEN 80 ^@d =100 ^Aヨ^A^N=then P^@=80 ^@$09
110 CLS:END ^@n =110
先頭は行番号で、端は改行? ^@^@ と思いきや、謎のコードが挟まってたり?
100 IF A$="" THEN 80
↓
^@d^@^Aィ^AA^@$F1""^Aヨ^A^NP^@ 中間語
↓
^@d = 100 ^Aィ^A = IF A^@$F1"" = A$="" ^Aヨ^A^N = then P^@ = 80
RENUM はやっぱり中間語で検索しながら番号を置き換えているんでしょうね。
これ見るとスペースは要らないように思えますね。
重複防止の仕組みはわからないけど。
konnoさんが誠実な人であるのは間違いがないところでしょう。
ですが、この発言に関しては、ちょっと混乱を招くというか、資料的価値に
欠けるというか。
> NP2でN88BASIC を使って RENUM や中間語に変換してみました。
これ、変換に使ったツールの記述はありますが、変換後をどうやって表示している
のかがよくわからない。文字化けっぽい表記になっている、というのもあって。
ということで引っ張り出してきたのが、ASCIIの出版した「PC-Techkonw 8800」
という本。ISBN4-87148-292-8。archive.orgにあるかなぁ。
対象がPC-8801なので、PC-9801とは異なっているかもしれませんが、中間言語の
一覧が掲載されていたりします。これによると、例えば
FOR 82H
NEXT 83H
GOTO 89H
GOSUB 8DH
IF 8BH
PRINT 91H
などとなっているそうです。
また、プログラムの格納状況の具体例も載っています。
サンプルのプログラムは以下。
> 100 FOR I=0 TO 20 STEP .5
> 110 PRINT I,SQR(I)
> 120 NEXT I
これの中間言語での格納状況が以下。
> 8000 00 18 00 64 00 82 20 49 F1 11 20 DC 20 0F 14 20
> 8010 DF 20 1D 00 00 00 80 00 27 00 6E 00 20 91 20 49
> 8020 2C FF 87 28 49 29 00 2F 00 78 00 83 20 49 00 00
> 8030 00
転記に当たって間違いがあるかもしれません。
例えば、最初の「64 00」が行番号の100を表し、その次の82HはFORの中間言語。
行番号200は「6E 00」だけど、そこには字下げがあるから空白文字の20Hが
入っていて、その次にPRINTを表す91Hがある。
みたいな感じになっています。
この本には、ROM内のルーチンのどのアドレスに何をするコードがあるか、と
いう表も載っていて、それによると、RENUMを行うルーチンは75DDH〜7673Hに
あるとか。なんと、150バイト。もちろん、どこかよそのサブルーチンを呼んで
いるのかもしれませんが、でもRENUMでも使うような汎用性のあるルーチンて
ちょっと思いつかないので、これで全部のような気もする。
また、バッファとかワークエリアの一覧の表の掲載もあるけど、見た範囲では、
RENUM用のバッファって見つからない。やはり、あんまりその手のバッファを
使わないアルゴリズムであろうことが予想される。
ちなみに、PC-98用のTechknowを謳っている書籍はBNN社から発刊されている
と聞いています。さらにいうと、archive.orgに収録されているらしい。
もしかしたら、こちらには中間言語のもっと詳しくてわかりやすい説明が
載っているかもしれません。ないかもしれませんが。
> VZで開いて見えたイメージをテキストにしたのです。ここの人達ならわかるかと。(^^; 全くわかりません。 というか、テキストにしたことによって情報が化けてしまい、正確性が失われてしまっている。 化けた情報から元の情報を推測するなんてこと、konnoさんのようなニュータイプにしかできません。 どうもkonnoさん、善人かもしれませんが、自分の基準で他人を推し量る傾向が強いとみた。 もしくは、思考の柔軟性に欠けているのか。> マシン語ならそのくらいで出来るかもしれませんね。 > せっかくなので私も DEBUG の結果を張っておきます。 これこれ、こういうのがほしかった。 これなら例えば GOSUB は A4 01 0E あたりかな、INPUT は A7 っぽいな、とわかりやすい。 ちなみに私は常時RX+です。
> ちなみに私は常時RX+です。 「別にどうでも……」とは言ったものの,手元でだけなら問題はありませんが,場末とは言え「おおやけ」の場に書くなら RX の退避・復帰は必要かと思います。 赤く塗っても中身は一緒?
[5783 ]
Re^17: N88-BASICの中間語
konno
2025/04/11(Fri) 01:33
[
5775 ]へのコメント
> もしくは、思考の柔軟性に欠けているのか。 老化なのか最近はこれをよく感じます。 中間語ファイルをVZで開いたら読めそうだったのでそのまま使ってしまいました。 としきさんのDUMPを見るまでDEBUGが使えるとか思いもしなかったです。(>_<)> > せっかくなので私も DEBUG の結果を張っておきます。 > これこれ、こういうのがほしかった。 私もほんとはこういう表示にしたかったんです。(^^;> ちなみに私は常時RX+です。 私は正規表現をあまり知らないので誤動作が怖くて RX+ には出来ません。 そういえば、ZK じゃなくて、ZH+ 全/半同一視もVZでは使わないなぁ。 # ZKとは違うのだよ、ZK(ザク)とは! (゜゜)グフ☆\(--#)
チェックなしで,いきなり実行するものです。
飛び先番号の前に空白があることが必要で,これは「仕様」です。
= likereno.def = by H_ear
#if 0
Like RENUM
#endif
* mad for vz!
1 ^\ "" ?.
#^ #<
a=10, ;増分値 (a)
&n b=c=r, ;番号付開始値を取得 (b/c) 可変
(r+1)??{ &m(41) . } ;準備ができていないなら終了
mp[=2, ps[, RX[+, ;検索モード,正規表現有効
&01 ps=r,
mi[-, Ew[+, ;挿入,ワードサーチ有効
:L ; ---- main loop ----
#t &?("%u",b)
#56 &?("[\s\t]%u",c) #m &?("♭%u",b) #m "ay"
#> #d ;通常は r==-1 なら停止だが
&n c=r, ;旧行番号を取得 (c)
(r+1)?{ b+=a, >L } ;&n の値が不正になるので無視
:Q ; ---- 飛び先有効化 ----
#56 "♭" #m " " #m "ay"
:z ; ---- exit ----
Ew], mi],
RX], ps], mp],
&d #] .
01: ; ---- buffer ----
(5+$)."$(10,0)$[16]"
*
これ,一見うまく動いているように思われるわけですが,ワードサーチ有効
にもかかわらず,例えば 330 の行を 150 に変換するという場合に 3300 が
あったりすると,goto 3300 が goto 1500 になってしまいます。【謎】
同様のキーワードで,ナマで検索するときちんとワードサーチが効いており,
そういうことにはならない。マクロのバグ? VZのバグ? 【謎】
ワードサーチが効かないと,どうにも仕様がない。お手上げじゃ。
[5763 ]
Re^14: likereno.def
konno
2025/04/08(Tue) 23:05
[
5762 ]へのコメント
> = likereno.def = by H_ear
ちょっと意地悪なリストで試してみました。(^^;
10 a=1 '10
20 'input a '20
40 'a$=input$(1)'40
150 a$=inkey$ '150
200 if a$=chr$(13) then 3000 else 150 '200
210 'if a$=chr$(13) then 3000 else 150 '200
300 goto 40 '300
400 'goto 40 '400
3000 end '3000
これの結果は
10 a=1 '10
20 'input a '20
30 'a$=input$(1)'40
40 a$=inkey$ '150
50 if a$=chr$(13) then 700 else 40 '200
60 'if a$=chr$(13) then 700 else 40 '200
70 goto 30 '300
80 'goto 30 '400
90 end '3000
うーん、コメント行が除外出来ない? マクロが読めない。(>_<)
ちなみにとしきさんのマクロはここが違います。
50 if a$=chr$(13) then 3000 else 150 '200
60 'if a$=chr$(13) then 3000 else 150 '200
70 goto 40 '300
80 'goto 40 '400
THEN ELSE を GOTO ルーチンに倣ってコピペしても駄目でした。(>_<)
> 同様のキーワードで,ナマで検索するときちんとワードサーチが効いており,
> そういうことにはならない。マクロのバグ? VZのバグ? 【謎】
VWX.DOC には
> ■ 制限事項など
> (4) VZ側でのワードサーチは無視されます。
とありますが、違う話なのかな?
どこが「意地悪」なのか全然わかりませんが…… そもそも「コメント行」がどこなのかわからないし,そんなの知らんし。 さらに,飛び先に前置された命令にどんなものがあるか知らされていません。 としきさんに提示された仕様は…… ・行番号が論理行頭にあること ・ジャンプ先が実在する行番号は付け替えに同期すること ・ジャンプ先が実在しない場合は変換しないこと ・行番号の直後に空白類があること ……これだけなので,コメント行とか考慮しなくてよいわけです。 つまり仕様ですね。> > (4) VZ側でのワードサーチは無視されます。 ご教示ありがとうございます。やっぱりそっちか〜。 ……となると手がない。一括置換式はギブアップかな〜。
[5771 ]
Re^16: likereno.def
konno
2025/04/09(Wed) 16:54
[
5767 ]へのコメント
> そもそも「コメント行」がどこなのかわからないし,そんなの知らんし。 > さらに,飛び先に前置された命令にどんなものがあるか知らされていません。 > つまり仕様ですね。 なるほど。それぞれの思惑は羅生門のように一致しない、と。(^^;> > > (4) VZ側でのワードサーチは無視されます。 > やっぱりそっちか〜。となると手がない。一括置換式はギブアップかな〜。 としきさんのは一括置換式ですよね。見直したら正常動作するようになりました。 詳細は後ほど。(^^;
8日は残業1時間半だったので、likereno.defはまだ試せていません。 計画では10日も5時間程度の残業になる予定なので、9日は家事をこなさねばならず。 ということで、試せるのは週末になってしまうことでしょう。 フラグ付けに関してですが、そんな面倒な記号を使うまでもなく、単にGOTOやGOSUBの頭にフラグという意味で"F"をつけるだけでもいいのではないか、と考えています。 ところで、BASICのインタプリタのRENUMコマンドのアルゴリズムがどこかにないだろうかとネットを渉猟してみたのですがね。結果、面白そうなものが2つ、見つかりました。 1つは、UNIXで動くものなのかな、C++で書かれたRENUMを実行するコマンド。 もうひとつは、フリーの処理系なのかな、最近のマシンで動くBASICインタプリタ。 ただ、それらのアルゴリズムを見るといずれも、旧行番号と新行番号の対応表を作る、とある。 ちょっとびっくり。
お忙しいのにこちらばかり盛り上がって申し訳ない。
まだ学校が始まっていないので,超絶ヒマしてます。
その一方で畑仕事のエンジンはかからないままです。
週末以降に次の v0.20 を試してみてください。初版は破棄します。
= likereno v0.20 = by H_ear
#if 0
Like RENUM
#endif
* mad for vz!
1 ^\ "" ?.
#^ #<
a=10, ;増分値 (a)
&n b=c=r, ;番号付開始値を取得 (b/c) 可変
(r+1)??{ &m(41) . } ;準備ができていないなら終了
mp[=2, ps[, RX[+, ;検索モード,正規表現有効
&01 ps=r,
mi[-, ;挿入有効
:L ; ---- main loop ----
#t &?("%u",b)
&#M(1) ;戻る位置をマーク
; ---- 飛び先の処理
; #56 &?("[\s\t]%u",c) #m &?("♭%u",b) #m "ay" ; v0.10 ×
; \x は \w を無効化するため マッチした番号を &n で都度確認
#F &?("[\s\t]%u",c) #m
#^ #<
:J #c
(r)?{ ;見つからなければ
&#U(1) >N ;戻って次行へ
}?{ ;見つかったら
#f &n ;番号の照合
(r==c)?{ ;一致すれば
#t &?("♯%u",b) ;飛び先に書き換える+処理印
}
>J ;次を探す
}
:N #> #d ;通常は r==-1 なら停止だが
&n c=r, ;旧行番号を取得 (c)
(r+1)?{ b+=a, >L } ;&n の値が不正になるので無視
:Q ; ---- 飛び先有効化 ----
#56 "♯" #m "" #m "ay"
:z ; ---- exit ----
mi], RX], ps], mp],
&d #] .
01: ; ---- buffer ----
(5+$)."$(10,0)$[16]"
*
> 単にGOTOやGOSUBの頭にフラグという意味で"F"をつけるだけでもいい
このあたりは好きずきでしょうね。わたしは昔から一時文字使用派です。
確か,最初の実用仕事マクロでも使った手でした。骨身に染みてる。
FGO(Fateか)なんてキーワードがなきゃいいですが……でも,
カーソル移動とか発生しませんか?
> アルゴリズムを見るといずれも、旧行番号と新行番号の対応表を作る
最初はそうするものかなぁ……と思って,旧番号抽出マクロを作っては
みたのですが,ひどく面倒だったので付け替え単位にしました。
あと,ひとつ。重要な仕様の再確認なのですが……
goto gosub だけでよいのですか? then とか else は?
わたしはキーワードに束縛されないように組んでいるけど,気になる。
新バージョンありがとうございます。のちほど試させてただ来ます。 まずはこちらから。> あと,ひとつ。重要な仕様の再確認なのですが…… > goto gosub だけでよいのですか? then とか else は? > わたしはキーワードに束縛されないように組んでいるけど,気になる。 惑わせてしまって申し訳ない。 手元では GOTO GOSUB THEN ELSE RESTORE RESUME の置換を行うようになっています。 とはいえ、実は GOTO と GOSUB 以外はほとんどコメントアウトして実行しています。 それだけで十分に試験の役に立つと考えたからです。 GOTO だけでも試験できるかもしれませんが、1つだけだとうまくいっても複数だとうまくいかない、という経験があるもので、その2つを変換するようにしています。 で、一応、文法的には、その他に RETURN も行番号をとるので、フルスペックというかオリジナルに対する高い互換性ということを考えると対応したほうがいいのでしょうが、私にニーズがないので省略。 もうひとつ、これは当初は考慮漏れだったのですが、現実的にはニーズがないのでどうしよう、というのがあって。なにかというと、異体字、ではないな、表記の揺れ、といったほうがいいのかもしれない。実は、GOTO って、"GO TO" という、あいだに空白が入った表記を許容するのですよ。フルスペックを目指すなら、ここも対応が必要なところ。しないけど。 考慮漏れといえば、検索文字列バッファのすり替えというか退避も、全く考えていませんでした。完成バージョンでは必要でしょう。ただ、完成前の段階では、ヒストリーで残っていたほうがデバッグの役に立つな、と考えています。> FGO(Fateか)なんてキーワードがなきゃいいですが……でも, > カーソル移動とか発生しませんか? 厳密性を問わなければ、最初の変換で GOTO を FGOTO に変換。 そして最後に、FGOTO を GOTO に一括置換。 う〜ん、安直。
> 考慮漏れといえば、検索文字列バッファのすり替えというか退避 これは自前でなくても ps[=pa, …… ps], でも十分でしょう。 手元でちょっとした失敗があったので,ご参考までに。 自前バッファを最初は「行番号だから8バイトもあればいいだろう」ということにしたら,どうやってもうまくいかない。バッファの中身を見たら行番号が途中でちょん切れていました。[\s\t]+ のことをすっかり忘れていたわけです。 大は小を兼ねる。まぁ,大きすぎる必要もありませんが……。
[5780 ]
Re^17: N88-BASICのRENUMのようなマクロ
文太
2025/04/10(Thu) 15:18
[
5779 ]へのコメント
>[\s\t]+ のことをすっかり忘れて
[\s\t][0-9]+ ;直前の空白文字1つのみ
とすれば、バッファの節約になりませんか?
それぞれのやり方で完成に近づいているみたいですね!
そういえば,わたしのは + を入れてなかったんだっけ。 で,わたしの手法だと打ち止めです。限界がわかったので。
[5772 ]
Re^10: renum.def 改
konno
2025/04/09(Wed) 17:35
[
5753 ]へのコメント
#5753 のとしきさんのマクロを見直しました。
あれ? 正規表現を使っているのに RX+ が無い? としきさん、RX+ 派だったの? (^^;
ということで、めざらさんのマクロから部品を拝借して、マクロの冒頭に
mp[=2, ps[, RX[+, Ec[+, ;★ ;検索モード,正規表現,英大/小文字同一視有効
この行を追加
GOSUB ルーチンの後ろに
#56 "THEN\([ \t]+\)" &?("%d",o) "$$" #m ;★ これ以降コピペして追加
"THEN\1" &?("%d",n) #m "ay"
#56 "THEN\([ \t]+\)" &?("%d",o) "\([^0-9]\)" #m
"THEN\1" &?("%d",n) "\2" #m "ay"
#56 "ELSE\([ \t]+\)" &?("%d",o) "$$" #m
"ELSE\1" &?("%d",n) #m "ay"
#56 "ELSE\([ \t]+\)" &?("%d",o) "\([^0-9]\)" #m
"ELSE\1" &?("%d",n) "\2" #m "ay"
>w
:u
Ec], RX], ps], mp], . ;★ 追加
*
これらを追加、変更したら正常に動作するようになりました。
10 A=10:GOSUB 4000'10
30 INPUT A'30
200 IF A$=CHR$(13) THEN 3000 ELSE 200'200
210 'if a$=chr$(13) then 3000 else 200 '210
300 GOTO 30'300
3000 END'3000
4000 FOR I=1 TO A:NEXT'4000
4200 RETURN'4200
↓ ↓ ↓
10 A=10:GOSUB 70'10
20 INPUT A'30
30 IF A$=CHR$(13) THEN 60 ELSE 30'200
40 'if a$=chr$(13) THEN 60 ELSE 30 '210
50 GOTO 20'300
60 END'3000
70 FOR I=1 TO A:NEXT'4000
80 RETURN'4200
コメント行も変換されますが、むしろこの方がいいかも。
それにしても、RX+かぁ・・・ ハッ!! RX78・・・ガンダムネタか?
#「ようやくわかりましたよ、シャア少佐。よしんばこのネタを打ち漏らしても、
我が見方の方に引き寄せる、二段構えの作戦ですな」
> 4000 FOR I=1 TO A:NEXT'4000 ふ〜む。もしも I = 1 という記述だったら,わたしのだと変換の対象になりうるってことですね。1ならスルーされるとしても,2000 とかだったら必ず……。 やはり,キーワードを教えてもらわないとだな。 G寝た(笑)
> 最短で次の週末あたりには、手抜きバージョンが動き始めているかも。 次の週末って,今週の土曜付近ってことですか? 仕様のすり合わせが完了するとは思えないので難しいかと。 ただ,学校が春休みでヒマなため,先走って自分の案をひとつ出しておきます。 ■ goto や gosub の飛び先と振り直す行番号をどう同期するのか。 VZマクロは一般の高級言語と違い,無限に配列を確保できるわけではないので,そんな制限を何とかするには別に新規ファイルを開いて,そこに一時的にリストアップしてゆく方法が考えられます。 ・ファイル全体に対してチェックを行って,飛び先行番号リストを作る. ・初期値と増分の設定にしたがって,番号付替えを行ってゆく. ・行単位で,飛び先リストと照合し,一致したらファイル全体で置換. 問題は,部分一致で置換してしまう可能性をどうするのか。 これは検索オプション Ew(ワードサーチ)を有効にすればよいのかな。 あとは,複数回出現する飛び先があるときに,どうリストするのか。 一個を置換してしまった後で,他方を新しく付け替えた行番号にリンクしてしまったりしたら,それこそ最悪。 一旦,としきさんからの案を待ちます。
> 一旦,としきさんからの案を待ちます。
……と言いつつ,飛び先番号の抽出サンプルは作ってみました。
前段階の行番号整合性チェックを厳密にすれば16ビットの整数に収まる……
という想定でちょっと手抜きです。なお,この先に控えている番号置換で
200 を置換するつもりが 2000 の 200 部分だけ書き換えてしまうという
致命的なミスを犯さないためのテスト部品も組み込んであります。
= picknum.def = by H_ear
#if 0
Basic飛び先番号を別テキストに抽出
#endif
* mad for vz!
1 ^\ "" ?. &s
(wc==tc)?{ &m(6) . } ;オープン可能テキスト数確認
mp[=2, ps[, RX[+, ;検索モード,正規表現有効
mi[-, Je[, Je|=512, ;挿入,\w有効,自動字下げ無効
#^ #<
b=id, ;元ファイルid (b)
#R "nul" #m (s)?'y' ;作業ファイルをオープン
a=id, ;新規ファイルのid (a)
:L ; ---- main loop ----
&#T(-b) ;処理対象ファイル
ps="[\s\t][0-9]+", #c ;空白文字と数字列
(r)?>z ;見つからなければ終了
#d &n d=r, ;飛び先行番号 (d) の取得
&#T(-a) ;新規ファイルに移動
&?("%u",d) #m ;飛び先行番号の出力・保存
>L
:z ; ---- exit ----
Je], mi],
RX], ps], mp],
&d #] .
*
[5748 ]
Re^7: N88-BASICのRENUMのようなマクロ
文太
2025/04/06(Sun) 00:56
[
5747 ]へのコメント
めざらさん
お手本として最高です。Je[, Je|=512, ああ、懐かしい。
ただ、ちょっと前から気になっていたのは以下です。
ps="[\s\t][0-9]+", #c ;空白文字と数字列
↓
ps="[\s\t]?[0-9]+", #c ;空白文字がない場合もあると思う。
;gosub2000 も、たぶん、たしか許容される
;のじゃなかったっけ。
;行番号とステートメント群の間のスペースは
;必須。でも、以降はマルチステートメントの
;「:」を含め、スペースは完全無視される
;というのがBASICの文法みたいに理解していました。
;方言、あるのかな?
間違っていたら、ごめんなさいね。詳細はとしきさんがお教えくださるでしょう。
----- vwx.doc -----
(10)r?
正規表現 r の0回または1回を意味する。
-------------------
それ、あってもなくてもいいよ。なかなか使う場面のない正規表現ですよね!
でも、ここではたぶん、すごく有効。
[5749 ]
Re^8: N88-BASICのRENUMのようなマクロ
文太
2025/04/06(Sun) 01:07
[
5748 ]へのコメント
めざらさん そう、「ps="[\s\t]?[0-9]+"」だったら、数字全部ヒットしちゃうじゃないか、 とは思ってました。それでいいのか? 僕は、いちばん最初から、goto, gosub or then みたいな、前のキーワードを 含めて、文字グレップ(izgrep)をしてから処理するかな、なんて考えてました。 もちろん、としきさんの仕様を満たす1つの汎用的プログラムなんて、やだよ、 そんなの、とは思ってたのですが。 「1回だけだけど、この作業を完遂したい」という場面で、僕ならどうする? なんてことを考えてました。 まず、行番号カラムの形式を整備する。そして、そのカラム(矩形ブロック)を cut して切り出してしまう。そして、ワークファイルに変換辞書ファイルを作る、etc みたいな感じです。 辞書ファイルは、もちろん、キーワードつきで作ります。 最後は、cut の反対の paste。行番号置換は、どのタイミングでどうやろうか? など、です。
> 辞書ファイルは、もちろん、キーワードつきで作ります。 文太版はそういう方向なんですね。 どのような全体仕様になるか興味あるなぁ……
> Je[, Je|=512, ああ、懐かしい。 これを懐かしむなんて,あなた,だいぶ毒されてますよ。(^^; Ei と Ej を無効化するため je- にしたかったんだけど,Ew は有効じゃなきゃ続く段階の置換で処理できないじゃん!……というわけで,懐かしいビット毎の論理和なんて使ってみました。> gosub2000 も、たぶん、たしか許容されるのじゃなかったっけ。 そういう美しくないソースは嫌いだ,ボクは対応したくない! スペース+数字列であれば,マッチ後に #f の 1ステップで数字列の先頭に移動できるわけで,シンプルな動作のために空白類のデリミタは「必要」だと思います。 「仕様」で「許容」されているものの多くは邪魔なものだと思う。(極論)
> ps="[\s\t]?[0-9]+", #c ;空白文字がない場合もあると思う。 > ;gosub2000 も、たぶん、たしか許容される > ;のじゃなかったっけ。 許容されません。 N88-BASICでは、空白文字がないと、一体でトークンというか変数か何かという扱いにされてしまいます。 ただ、私も詳しくないのですが、PC-8001のN-BASICだと、もしかしたら許容されるかも。 なぜというに、N88-BASICでは変数名が40文字までOKなんですが、N-BASICの場合は確か変数名は2文字までだったような。もしかしたら6文字だったかなぁ。> ;必須。でも、以降はマルチステートメントの > ;「:」を含め、スペースは完全無視される > ;というのがBASICの文法みたいに理解していました。 スペースが完全無視されるというのはpascalですね。 そのかわり、ジャンプ用のラベルから変数からありとあらゆるものを使用前に登録しておく必要があります。そのくらいのことをすれば、トークン分離用の空白文字を使用せずにすみます。
[5757 ]
Re^9: N88-BASICのRENUMのようなマクロ
文太
2025/04/07(Mon) 00:34
[
5752 ]へのコメント
としきさん
了解です。お題は、N88-Basic 用 renum ですからね。
ただ、許容してほしい(ウソ&笑)。なぜなら、以下のようなのを見たことが
あったからです。
文字化け退治の試みは一切しておらず、失礼なのですが。
ただし改行だけ入れました。たとえば、行番号10は、1論理行でした。20も。
GALACTIC ARMY for PC-8201 (B-mag, 1985/01, p.143)
10 CLEAR256,61970!:DEFINTA-:DIMF(3),A(3,8),UXC3),UY(3),Al$(3),U$(1),C$(6)
:T$." "+CHR$(30)+CHRS(29)+CHR$(l32):U$(1)." "+CHR$(31)+CHRS(29)+CHR$(144)
:M$." "+CHR$(131)+" ":C$(1l." "+CHR$(31)+STRING$(2,29)+CHR$(139)
20 C$C2)=LEFT$(C$(l),4)+CHR$(137):C$(3).LEFTICCIC1),4)+CHR$(135)
:C$(4)." "+CHR$(31)+CHR$(13"3):C$(5l.LEFTS(C$(4),2)+CHRS(137)
:C$(6).LEFT$CC$(4),2)+CHRSC135):AD!=61970!:GOSU8330
文字化けはともかく、よくこのソースを投稿するよなぁ、そしてそれをそのまま
掲載するよなぁ、と思ったことがありました。
> ただ、許容してほしい(ウソ&笑)。なぜなら、以下のようなのを見たことが > あったからです。 すごい、PC-8201って、こんなリストを許容するんだ。知らなかった。 他のマシンでもあるかもしれませんが、予約語の内部表現の関係で、こういうワザが使えるのでしょう。> 文字化けはともかく、よくこのソースを投稿するよなぁ、そしてそれをそのまま > 掲載するよなぁ、と思ったことがありました。 良くも悪くも、それがベーマガ。
ちょっと興味が湧いて、PC-8201について調べてみました。
結果、Wikipediaの「PC-8201」の項には
> BASIC N82-BASIC(N-BASICをベース
という記述がありました。
次に、同じくWikipediaの「N-BASIC」の項には
> 命令や関数の前後は、必ずしも空白文字で区切らなくてもよい。
と明記してありました。なるほど。
そういえばそうだったような記憶もあるようなないような。
ん、その直後、いささか誤解を招くような記述がある。
> > FORTRAN=ATOK5
> と記述すると、
> 「変数『FORTRAN』に、変数『ATOK5』の値を代入する命令(LET文)」
> ではなく、「『TRAN』という変数を、変数『A』の値を初期値、変数『K5』
> の値を終値としてループを回す命令(FOR文)」として解釈された。
この記述で間違いではないのかもしれませんが、間違いかもしれない。
なぜというに、変数名は2文字でしか識別されないので、正確には
「『TR』という変数を、変数『A』の値を初期値、変数『K5』の値を終値
としてループを回す命令(FOR文)」
として解釈されるはず。
やだねぇ、こういう細かいところにこだわるオタクって。
> > 命令や関数の前後は、必ずしも空白文字で区切らなくてもよい。 「必ずしも」と言うからには,通るときも通らないときもあるってことで。 通らない危険性がある書き方を「わざわざ」するってのは理解できない。> やだねぇ、こういう細かいところにこだわるオタクって。 こだわりは必要ですよ,絶対。 どこにこだわるってのはありますけど,文法にこだわるのは大切。 また美しく読みやすくコーディングするって,一番大事なことだと思う。 もしかすると,仕様やアルゴリズムよりも……って,また極論。
> 「必ずしも」と言うからには,通るときも通らないときもあるってことで。 これは「省略可能」という用語をいささか曖昧というか厳密性を欠いた方向に言い換えただけのような気がする。> どこにこだわるってのはありますけど,文法にこだわるのは大切。 > また美しく読みやすくコーディングするって,一番大事なことだと思う。 文法は、こだわらないと、コンピュータ相手の場合は、きちんと動いてくれませんからね。ただ、美しく読みやすく、という点は、使い捨ての場合はこだわる必要もないと思う。もちろん、こだわったほうがいいのは間違いありません。でも、逆に、何回もみることになるコードの場合、見るのもうんざりするようなコードは、やっぱり見たくなくなるわけで。そんなコードは書きたくないな。
↑ このページの先頭