Forth 输入流处理

时间:2021-08-08 03:45:48

body, table{font-family: 微软雅黑; font-size: 13.5pt}
table{border-collapse: collapse; border: solid gray; border-width: 2px 0 2px 0;}
th{border: 1px solid gray; padding: 4px; background-color: #DDD;}
td{border: 1px solid gray; padding: 4px;}
tr:nth-child(2n){background-color: #f8f8f8;}

    文本解释程序(解释程序):用空格为一个词的结束标记,摘取出命令行中的词,搜索词典以得到当前命令的执行代码并加以执行,如此反复直到处理完毕命令行中的最后一个成分。如果正在处理的字符串不是词典中的定义,则文本解释程序就试图把它转换成为一个数字,并把该数字放置到参数堆栈上。若接收到的既不是词典中已有的定义又不是数字,抛出错误信息。
    输入流就是输入命令行或输入字符串,他们存放在 TIB(终端输入缓冲区) 中或 磁盘缓冲区中。
TIB  ( - addr )   留下输入终端缓冲区的地址。
VARIABLE  #TIB  (- addr)这个变量留下的地址中存有当前文本输出缓冲区中的字节数,他不是缓冲区的长度,而是缓冲区中当前存在的输入流的长度
Forth 输入流处理
VARIABLE  >IN    ( - addr ) 是一个指针,它指着当前要被处理的字符。其值(@)为距离输入缓冲区起始地址的位移。
VARIABLE  BLK    ( - addr )  其值(@)是要被解释的磁盘块号。若为 0 表示输入取自终端输入缓冲区。所以不能 LOAD 0
DEFER  SOURCE  用以返回存放当前输入流的缓冲区的首地址。其 pfa 单元的内容是(SOURCE)的执行地址
(SOURCE) ( - addr len ) 返回文本解释程序行将处理的字符串。addr 和 len 分别是输入缓冲区的起始地址及长度
LABEL DONE 当输入流耗尽时的公共返回点
SKIP ( addr len char - addr1 len1 ) 根据一字符串的地址,长度和一个指定的字符从头开始扫描该字符串直到在字符串中发现一个与指定字符不相符的字符时停止。在参数堆栈上留下第一个不相符的地址及剩余字符串的长度
SCAN ( addr len char - addr1 len1 ) 到一指定字符串中寻找指定的字符直到找到为止。在参数堆栈上留下相符字符的地址及字符串的剩余长度
/STRING ( addr len n - addr1 len1 ) 丢弃指定字符串最左边的 n 个字符,addr1=addr+n;len1=len-n
MOVE ( from to len -  ) 把从地址from开始的一定量16位字移动到to开始的区域,不会有重叠发生。CMOVE什么的会有重叠
  // FORTH 中同一行每相邻的两个词之间的空格数目是任意的,SKIP 的目的就是忽略掉一个词前面的所有空格。SCAN 是扫描发现第一个相符字符后就停止。
P      ( char - addr len ) 忽略掉领头的字符 char , 接着扫描输入流直到下一次在遇到指定的字符 char 。更新指针 >IN 的内容。在参数堆栈上留下分离出来的词的地址和长度
PARSE ( char - addr len ) 同上,只是不忽略领头的字符 char
WORD ( char - addr ) 以 char 作为终止字符分解输入流。把分离出来的词放在由 HERE 处开始的词缓冲区中,第一个字节内存放词的长度,接着是组成该词的字符,最后一定跟有一个空格,该空格不计入词的长度。在参数堆栈上留下存放长度字节的地址
//使用定义 PARSE 的例子
:   (        forth的注释命令,它与)配对使用。文本解释程序对于位于圆括号内的内容不予理睬
        ASCII  )          使用)作为终止符,在参数堆栈上留下)的 ascii 代码
        PARSE           把 >IN 推至)后的那个字符
        2DROP         丢弃注释的地址和长度,因为不对注释做任何处理。
        ;     IMMEDIATE      使(成为立即词,这样在冒号定义内便执行而不是编译 
:   .(              
       ASCII  )
       PARSE           Forth 输入流处理       TYPE  ;  IMMEDIATE            

Forth 输入流处理

KEY?   ( - f )   如果已按过一个按键,返回真标志。
KEY    ( - char )  读入一个 ASCII 键。
EXPECT ( addr n -  ) 把n个字符从终端传送到主存中自地址 addr 开始的区域中。EXPECT 循环调用KEY,每读入一个键就把所键入的字符送到自 addr 开始的缓冲区中一次存放,一直到读进第n个或遇到回车键。所读入的字符个数存放在SPAN中,回车键不计入总数。EXPECT 允许键入的时候修改
QUERY ( - ) 从操作者终端输入80个字符文本。文本放置在地址TIB。把>IN和BLK置零,#TIB 等于接收的字符数。为系统解释接收进来的源行做好准备。
SPAN ( - addr ) 留下通过最后执行 EXPECT 实际收到和存储的字符计数变量的地址。
eg:
CREATE  BUFF1  DECIMAL  80  ALLOT            建立一个 80 字节的名叫 BUFF1 的缓冲区。
VARIABLE  SPAN1          用来保存下面输入字符的个数
READLINE                    把一行字符从终端传送到 BUFF1
              CR  BUFF1                         
              80      ( addr size -  )  
              EXPECT
              CR  ." SPAN= "  SPAN @
              DUP  .  SPAN1  !  ; 
Forth 输入流处理
:  QUERY  ( - )     
          TIB  80  EXPECT      从终端输入80个字符到TIB
          SPAN  @                 获取实际的长度
          #TIB  !     把实际长度存入 #TIB 中,这样解释程序将会知道输入流何时耗尽
          BLK  OFF          清零 BLK,这样文本解释程序将使用终端输入缓冲区
          >IN  OFF  ;        清零字符指针,于是扫描将从 TIB 的起点开始

输出:
:   COUNT  ( addr - addr+1 len )
        DUP  1+  SWAP  C@  ;       转换计数字节地址为 地址-长度 表示
:  TYPE  ( addr len -  )     在终端上显示出指定的字符串。其中 addr 是要显示的首字符地址,len 是要显示的字符个数。
        0  ?DO  
        DUP  C@  EMIT
        1+          递增字符地址
        LOOP  DROP  ;          清除堆栈上的无用地址
:   -TRAILING   ( addr len - addr len1 )   用改变长度的方法删去一字符串的结尾空格
          DUP  0
                ?DO
                       2DUP  +  1-      把最后一个字符的地址送到参数堆栈顶
                       C@  BL  <>       判断是不是空格
                       IF  LEAVE  THEN      如果不是就结束循环
                       1-      是,字符串长度减一
                LOOP  ;
Forth 输入流处理

Forth 输入流处理