易码技术论坛

 找回密码
 加入易码
搜索
查看: 355023|回复: 7

关于一个计算器程序

[复制链接]
发表于 2007-5-2 22:20:28 | 显示全部楼层
以下是windybell的补充说明,他不能上网,所以让我带发。


更正!

   我在帖子最后面说58,147这两个数据是指向某行的地址,说错了。

   经仔细核对后发现,58是“:”的ASCII码,而147实际上是“REM”的标识符。该程序的作者巧妙地运用动态修改,加入了一个“:REM”,达到了让翻译程序忽略“S=...”表达式后面的其它语句的目的,确实非常巧妙!

   如果想引用该程序,结尾的数据(58,147)不用改。

   WindyBell按照该程序的思路,在TC808上写了一个相似的程序(附在后面)。说明一下几点不同之处:
   1.“W=12303”。TC808上,小于1K的程序加载到12288处,这个地址是重新计算得来的。
  2.“S=观自在...”。储存在BAS程序中的汉字,由于每个汉字前比正常情况下多出一个标志$1F,虽然看起来是两字节,实际上确占用了3字节。我将原来的一串“FFF...”改成了一串汉字,比之前多占用了三分之一的位置。我这么做是想减小因表达式太长而位置不够用而产生错误的可能性(这句话好拗口-_-U)。
   3.我将表达式后面的“:REM”换成了“GOTO 20”。并不是因为这么做更好,其实原来的“:REM”就已经非常巧妙了,我这里只是做个动态修改的示范。引用该程序时,你当然还可以改成“:RETURN”或者其它。

   附上程序代码。

---------------------
0 GOTO 30
10 S=观自在菩萨,行深般若波罗蜜多,时照见五色皆空,渡一切苦厄。舍利子,空不亦色,色不亦空。
20 GRAPHRINT N$;"=";S:INKEY$
30 CLEAR:TEXT:INPUT "请输入表达式:";N$:IF N$=""THEN 400
40 W=12303
50 FOR I=1 TO LEN(N$)
60 P$=MID$(N$,I,1)=ASC(P$)
70 IF P>96 OR P<37 THEN 400
80 IF P>47 AND P<58 THEN 140
90 IF P>64 AND P<91 THEN P$=MID$(N$,I,3):I=I+2
100 P=(P$="(")*40+(P$=")")*41+(P$="+")*201+(P$="-")*202+(P$="*")*203+(P$="/")*204+(P$="^")*205
110 P=P+(P$=":")*58+(P$=".")*46+(P$="INT")*212+(P$="SQR")*215+(P$="LOG")*217
120 P=P+(P$="EXP")*218+(P$="COS")*219+(P$="SIN")*220+(P$="TAN")*221+(P$="ATN")*222
130 IF P=0 THEN 400:
140 POKE W,P:W=W+1
150 NEXT
300 POKE W,58OKE W+1,141:POKE W+2,50:POKE W+3,48:GOTO 10
400 GRAPH:PRINT "ERROR.","按[跳出]离开":K=ASC(INKEY$):IF K<>27 THEN 0
410 POKE 199,155
420 PRINT "END PROGRAMMA.":END
发表于 2007-5-2 22:24:33 | 显示全部楼层
他确实很辛苦过,晚自习拿着我的tc808摸索了一个多小时。以上文字全是用tc808自带的文本编辑一个字一个字打出来的,精神可嘉。

若能加“精”,那当然最好。呵呵
发表于 2007-5-2 22:25:42 | 显示全部楼层
论述很精彩
发表于 2007-5-2 22:47:53 | 显示全部楼层
好辛苦,我顶顶吧(没看懂......)
发表于 2007-5-11 11:21:30 | 显示全部楼层
小弟们,加油呀,这个不是很难,多研究就能明白了。
发表于 2007-7-30 20:10:30 | 显示全部楼层
虽然作为新手
还不太明白不过先留着以后好好研究
发表于 2007-7-30 23:20:50 | 显示全部楼层
LS认真看看以上文章肯定能懂的,并不是很难理解。也可以看看我利用这篇文章的原理编的程序
http://www.emsky.net/bbs/read.php?tid=23125&fpage=3
 楼主| 发表于 2007-5-2 13:45:57 | 显示全部楼层 |阅读模式
看到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),到底指向那一行我没工夫算,但如果要引用这段程序,这里是绝对要改的。



   好了,我就说这么多。
您需要登录后才可以回帖 登录 | 加入易码

本版积分规则

Archiver|手机版|小黑屋|EMAX Studio

GMT+8, 2024-3-29 14:53 , Processed in 0.015692 second(s), 18 queries .

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表