FORTH 程序员利用堆栈来保存数据,对于要保存的临时数据可以用返回栈来暂存。但是如果要长时间的保存某些数就要用变量和常数。
变量
VARIABLE 使用形式 VARIABLE 名称 执行VARIABLE时,它生成<名称>的定义并在它的参数域分配两个字节。应用程序负责对生成变量的内容初始化。当以后执行<名称>时,参数域地址留在堆栈。
VARIABLE DATE 定义一个名为DATE的变量 |
12 DATE ! 12压入堆栈,然后给出变量名 !表示存储赋值;就是把12 存入变量DATE |
DATE @ @表示取出数据,这个短语表示取出DATE的值压入堆栈 |
: ? @ . ; 定义一个词,每次直接取出数据 |
我们可以用这个方法存年月日,然后再定义一个词组合这个年月日。
FORTH 系统中有已经被定义的变量 BASE
所以系统中的HEX DECIMAL OCTAL的定义都是
: DECIMAL 10 BASE ! ;
: HEX 16 BASE ! ;
: OCTAL 8 BASE ! ;
变量详解
定义变量时,已经把一个称为DATE的新词编译进了词典,该词典条目的简化结构
DATE是用VARIABLE而不是用;来定义的;除这个区别外没有其他区别,词VARIABLE本身已经告诉了DATE应该做的事情。比如当我们键入 12 DATE ! 的时候它的执行过程是
①12 进栈;
②文本解释程序在词典中查找DATE,若找到,则把它指向 EXECUTE ;
③EXECUTE 把该变量的“空”单元(将存放实际值的单元)地址复制到栈顶;
④词!从栈顶取出该地址,从下一项取出数值存入相应的内存单元。在该单元中无论什么值都将被新的数值锁代替;
词 @ 只要一个自变量的地址,它拿到自变量的地址,取出里面的值压入栈顶。
//DATE 会把自己要存贮实际值的空间的地址压入栈中 //@ 从栈中取出地址然后拿出地址中存的值再压入栈顶
! ( n addr --- ) 将16位的n存入地址。称为“存储”。
@ ( addr --- n ) 留下addr中的16位数据内容。称为“读取(fetch)”
!@ ( n addr --- ) 将n加到地址为addr中的数值上。称为"加-存储"
利用变量作为计数器
eg: 鸡蛋计数
//这里设置EGGS变量,EGG每次对值+1;可以计数,看出EGG执行了多少次;
// ? 这个词我的FORTH系统没有,要自己定义一个。
常数
常数用来表示无须再变更的值,定义的时候就必须给他赋值,之后就不会再次改变它的值。和变量的区别是使用定义得到的不是它的存放数据的地址,而是它的值。
eg: 220 CONSTANT LIMIT //定义一个名叫LIMIT的常数,并且赋值为220。使用LIMIT得到220。
用途之一:给硬件地址命名。
双字长变量和常数
2VARIABLE 定义一个双字长度的变量
2CONSTANT 定义一个双字长常数
eg:定义一个词把 400000 和栈顶的双字长数相加。
*/ ( n1 n2 n3 --- n4 ) n1 与 n2相乘产生32带符号的中间结果,在被n3除,得到下整商n4。如果除数为零或者商大于16位就存在错误。
可以用一个2CONSTANT 定义的词存储两个单字长度的数对。这样既方便又能节省词典空间。
数组
定义一个变量可以用 ALLOT 分配多个空间(默认是一个)
VARIABLE DATE 2 ALLOT 这个结果和使用 2VARIABLE 一样。通过 ALLOT 定义多个空间就成了数组。
//定义变量的时候存储数据的单元都是分配两个字节。这里定义的LIMITS又多分配了6个字节,也就是可以多存放3个单字数据。加上定义变量时默认带的一个,总共就有四个。LIMITS每次取出的地址都是第一个,要偏移到第二个就要+2 ,第三个 +4 ……;定义 LIMIT 的目的就是实现输入要访问的单元号就直接计算出偏移;
//ERASE 用来给变量数组各个元素置0,前面要给一个参数,表示要置0的范围。 还可以对栈进行清空
FILL ( addr 字节数 b --- ) 从addr地址开始把字节数个b填入存储区; LIMITS 8 0 FILL ( 这里我把b写成其他的就显示不正常了 )
DUMP ( addr len --- ) 以十六进制和ASCII码显示存储地址addr到addr+len中的内容
LIMITS 的4个单元放的是(100(64)、200(C8)、300(12C)、400(190)) 内存的0—7 下存放的就是想要的数值,因为LIMITS每个单元是两个字节,存放数据都是从低位开始存放的,放不下在放到高位。一个单元最大能存放的数据是65535
字节数组
FORTH能够让元素只存储在一个字节而不是一个单元两个字节。用8位二进制数表示的数据好处是能以一半的存贮空间取得同样多的数据。
C! 相对于 ! 把n的最低有效8位数据存入地址addr中。
C@ 相对于 @ 在堆栈中留下存储地址addr中的8位数据内容,堆栈中的高8位为0。
//定义变量数组CHAR 长度为2(variable本身就带两个空间)+3 ;0,1,2,3,4
//依次赋值1、2、3、4;
//试过用两个用屏面文件编写的数组查看内存最开头都有一个19;
(这里我没有往第五个空间里存放数值)
数组初始化
定义变量数组的时候可以直接给它们赋值;
CREATE VAR 1 , 2 , 3 , 4 , //定义一个变量,这个变量存放的数据为1,2,3,4;后面可以用上面的定义给它修改
CREATE (——) 定义词汇使用形式,CREATE 名称 生成<名称>的词典项目。在<名称>生成之后,下一个可利用的词典单元就是<名称>的参数域中的第一个字节,随后执行<名称>时,<名称>的参数域中的第一个字节的地址被留在堆栈中,CREATE并不给<名称>的参数域分配空间。
, 将16位的n存入词典指针的当前位置,然后指针前移两个字节。(把一个单子长数值存入词典中下一个可利用单元) //词的功能是从栈中取出一个数并把它存入数组,所以每写一个数并跟随一个 , 时,就给该数组增加一个单元。
C, 与上面的,对应,是用来初始化一个字节的数组
LEAVE ( —— ) 执行转移至下一个LOOP或+LOOP外的代码。循环被终止而循环参数被舍弃;
DO ... LEAVE ... LOOP 或者 DO ... LEAVE ... +LOOP