- 注册时间
- 2006-7-15
- 最后登录
- 1970-1-1
|
看到coolmoon的这个帖子:
------------------------
原来一个高手做的,可是我没看懂
以下是一个高手用BAS的计算器,但是我没看懂
0 GOTO 30
10 S=FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
20 GRAPHRINT N$;"=";S:INKEY$
30 CLEAR:TEXT:INPUT "请输入计算式:";N$
40 W=8207
50 FOR I=1 TO LEN(N$)
60 K$=MID$(N$,I,1):O=ASC(K$)
70 IF NOT(O>64 AND O<91)THEN 130
80 K$=MID$(N$,I,3):I=I+2
90 P=(K$="SIN")*220+(K$="COS")*202+(K$="SQR")*215+(K$="ABS")*213
100 P=P+(K$="ATN")*220+(K$="INT")*212+(K$="LOG")*217+(K$="SGN")*211
110 P=P+(K$="TAN")*221+(K$="EXP")*218+(K$="")*0+(K$="")*0
120 IF P=0 THEN PRINT "ERROR":INKEY$:0 ELSE 150
130 P=(K$="+")*201+(K$="-")*202+(K$="*")*203+(K$="/")*204+(K$="^")*205
140 P=P+O*(P=0)
150 REM IF W>THEN P=0:120
160 POKE W,P:W=W+1
170 NEXT
180 POKE W,58:W=W+1OKE W,147:GOTO 10
-------------------------
我试着自己来解释一下。
这是个动态修改程序的程序。
首先,那个W=8207是怎么来的?
编写出这个程序的机子肯定是将这个BAS程序加载到8192($2000)处运行的,于是程序起点为8192。如果是TC808这种把程序加载到12288($3000)处运行的机子,起点就应该是12288。
从起点开始是开头的5字节:第1字节是00,第2、3字节指向下一句开头的地址,第4、5字节是行号10。由于每行开头5字节格式是一样的,下面我就不再赘述。
这5字节之后就是 “GOTO 30 ”了,“GOTO 30”这一句占3字节:“GOTO”以在文件中以标识符$8D占1字节(而不是大家看到的4个字符,
“GOTO” 和 “30” 之间的空格是不占位的),“30” 以ASCII码形式占2字节。
然后又是第二行开头的5字节。
接下来,是“S=FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF”,我们这里先不管
后面的一串“F”,“S=”占2字节:“S”以ASCII码形式占1字节,“=”在文件里以标识符$D1占一字节。
引用一下George的帖:
--------------------------
这个其实很简单,没想到已经有人做出来了(我本来想将其用如函数绘图软件中去的)
bas编译文件时,会将一些运算符用一定的代号表示,这个程序就是处理一下输入的字符串,使字符串里的运算符被替换成相应的代号,再将字
符串poke到s=以后,这样bas就认为是一个表达式从而可以算出它的值
--------------------------
说的很正确啊。
现在我们来计算一下,8192+5+3+5+2=8207。这个地址恰好是在“S=”的后面。
如果你不明白我是怎么算出来的,请看我以前发的一张帖:浅探BASIC文件结构
引用一下不炫耀会死星人的帖:
---------------------------
如果我没猜错 这个应该是输入表达式就可以求出值的计算器 原理是将表达式按照POKE入内存中 运行即可 而第10行就是用来占内存空间用的 没有任何意义 你可以写成
10 CLS:CLS:CLS:CLS:CLS:CLS……
10 A$="QWEIYKSAJDHFKJAH FAKDHKJHCKJDHSFKAHF"
等等都没有关系 程序在运行中会将第10行覆盖成为别的程序 也就是表达式 然后goto10进行计算
---------------------------
他答对了一半。这个程序确实会把第10行改成别的程序,但是这一行不能随便改。只能改动“S=”后面的那些FFFFF...。改动后,程序就变成了“S=TAN(**)...”之类的东西。
引用coolmoon的帖:
---------------------------
我想移植这段程序到其他的程序里面去,但是不知道为什么总会出错,
当把这段程序排在比较后面的行号的时候(如在200行后面)不是(相当于第10行)出现语法错误就是(相当于第180行)出现"没有定义的行号"错误(其实是定义的行号)
如果排在前面也总是有莫名其妙的错误,请教这是怎么回事
---------------------------
一点都不改的话怎样引用啊,我试了一下把10行内容COPY到"11"行,再改10行为空语句,程序就出了.真无语了
---------------------------
他犯错误是因为不了解BASIC的文件结构。虽然他把“S=FFFFFF...”这一句改到别处去了,但是由于W=8207,程序在做动态修改时,仍然是修改的这个地方。
假设他把第10行改成了GRAPH,加入了一行“11 S=FFFFFFFFFFf...”,那么我们来算一下:行号“10”后面一位的地址是8205(去掉了“S=”,8027-2),然后是GRAPH占1 位,再然后是11行的开头5字节。现在W=8207这个地址实际上是指向11行的开头5字节。此时如果用POKE改动,实际改动了11指向下一行的地址和11行的行号以及11行后面的内容。如果这时再来个GOTO 11,要么根本找不到第11行(行号已经被动态修改过了),要么跳到11行去运行已经被改得面目全非的程序(这里显然可能出现语法错误)。如果运气再好点,这一行竟然顺利运行完了,程序接下来会从11行开头5字节中的第2、3字节取出下一行的地址(已经被改过了),跳到不知什么地方去。如果运气再好一点,居然刚好跳到某一行的开头(汗..),那他也仍然无法得到他所需要的结果。
如果想要成功引用,一定要弄清楚"S="的地址,把W=8207改掉。至于怎么弄清楚,计算也好,用EWay、pacmgr之类的程序查看也好,不在我们讨论的范围之内。
其次,我们再看一下以下程序:
P=(K$="SIN")*220+(K$="COS")*219+(K$="SQR")*215+(K$="ABS")*213
P=P+(K$="ATN")*220+(K$="INT")*212+(K$="LOG")*217+(K$="SGN")*211
P=P+(K$="TAN")*221+(K$="EXP")*218+(K$="")*0+(K$="")*0
IF P=0 THEN PRINT "ERROR":INKEY$:0 ELSE 150
P=(K$="+")*201+(K$="-")*202+(K$="*")*203+(K$="/")*204+(K$="^")*205
P=P+O*(P=0)
POKE W,P:W=W+1
POKE W,58:W=W+1OKE W,147:GOTO 10
这里就是动态修改程序的部分。关于这些数据怎么来的这个问题,请看前面提到的那个帖,后面有张附表。我想说的是关于最后两行的问题。
这个程序的作者在表达式结尾(其实是下一行的开头5字节)加了一个0,58,147。0表示这一行程序已经结束,可以跳转了。如果不加0,我们假设输入的是“TAN(45)”,我们希望表达式为“S=TAN(45)”,单由于没有加结束符0,表达时实际是“S=TAN(45)FFFFFFFF...”,显然要出现语法错误。58和147其实是地址$933A(147*256+58),到底指向那一行我没工夫算,但如果要引用这段程序,这里是绝对要改的。
好了,我就说这么多。 |
|