簡體   English   中英

第四:如何創建一個可以編譯其他單詞的單詞,直到找到某些定界符?

[英]Forth: How to create a word that compiles other words until certain delimiter is found?

我使用Forth(即Swapforth )通過I2C配置某些硬件 我有一句話:

i2c1-send ( reg-address byte -- )

將字節寫入特定芯片的特定內部寄存器。 初始化序列很長,因此由於內存消耗,無法按以下方式實現。

: i2c1-init
   $1201 $10 i2c1-send
   $2130 $43 i2c1-send
   [...]
   $0231 $43 i2c1-send
;

我創建了一個實現,該實現創建一個結構,該結構在第一個單元格中保留序列的長度,在下一個單元格中保留三字節。 (請注意,i2c1發送只是一個占位符,允許您在沒有我的硬件的情況下對其進行測試)。

: i2c1-send ( reg_addr byte -- )
  \ It is just a placeholder to show what will be written in HW
  swap
  ." addr=" hex . ." val=" . decimal CR
;    

: i2c1: ( "<spaces>name" -- )
  create here $326e9 0 ,
  does> dup cell+ swap 
  @ 0 do 
    dup c@ >r 1+
    dup c@ 8 lshift swap 1+
    dup c@ rot or r> i2c1-send
    1+
  loop 
  drop
; 

: i2c1-def ( addr val -- )
  c, ( adr )
  dup 8 rshift c,
  255 and c,
;

: i2c1; ( -- )
  \ Make sure that i2c1: was used before
  $326e9 <> abort" i2c1; without i2c1:"
  dup cell+ here swap - ( first_cell length )
  \ Verify that the length is a multiple of 3
  3 /mod swap 0<> abort" illegal length - not a multiple of 3"
  swap !
; 

使用上面的代碼,您可以類似地定義初始化列表:

i2c1: set1
  $1234 $11 i2c1-def
  $1521 $18 i2c1-def
  [...]
  $2313 $10 i2c1-def
i2c1;

但是顯着減少了內存消耗(對於J1B Forth CPU,減少了2倍)。

但是我不喜歡這種語法。 我希望可以通過數字定義初始化列表,直到找到某些定界符為止,如下所示:

i2c1-x: i2c1-init
  $1234 $11 
  $1521 $18 
  [...]
  $2313 $10 
i2c1-x;

我創建了如下所示的單詞:

: i2c-delim s" i2c1-x;" ;
: i2c1-x: create here 0 ,
  begin 
   parse-name
     2dup i2c-delim compare 0<> while
     evaluate \ We store the address later
   parse-name
     evaluate 
     c, 
     \ Now store the address
     dup 8 rshift c,
           255 and c,
  repeat
  2drop
  dup cell+ here swap - ( first_cell length )
  \ Verify that the length is a multiple of 3
  3 /mod swap 0<> abort" length not a multiple of 3"
  swap !
  does> dup cell+ swap 
  @ 0 do 
    dup c@ >r 1+ 
    dup c@ 8 lshift swap 1+ 
    dup c@ rot or r> i2c1-send 
    1+
  loop 
  drop
; 

它非常適合簡短定義:

i2c1-x: set2 $1234 $ac $6543 $78 $9871 $01 $3440 $02 i2c1-x;

但是對於使用多行的較長代碼則失敗:

i2c1-x: set2 
   $1234 $ac
   $6543 $78 
   $9871 $01 
   $3440 $02
i2c1-x;

是否可以定義i2c1-x以便處理多行,還是必須使用基於單獨的i2c1:i2c1-defi2c1;解決方案i2c1;

REFILL字來解析多行。

\ Get the next name (lexeme) possibly from the next lines
\ NB: Use the result of parse-name-sure immediate
\ since it may be garbled after the next refill
\ (the buffer may be be overwritten by the next line).
: parse-name-sure ( -- c-addr u|0 )
  begin parse-name dup 0= while refill 0= if exit then 2drop repeat
;

\ Check if the first string equals to the second
: equals ( c-addr2 u2 c-addr1 u1 -- flag )
  dup 3 pick <> if 2drop 2drop false exit then
  compare 0=
;

轉換輸入直到分隔符是一種常見的方法。 執行此方法的一般功能:

\ Translate the input till a delimiter
\ using xt as translator for a lexeme
2variable _delimiter
: translate-input-till-with ( i*x c-addr u xt -- j*x )
  >r _delimiter 2!
  begin parse-name-sure dup while
    2dup _delimiter 2@ equals 0= while
    r@ execute
  repeat then 2drop rdrop
;

還可以考慮將16位單元的操作納入庫中:

[undefined] w@ [if]
\ NB: little-endian endianness variant
: w! ( x addr -- ) dup 1+ >r >r dup 8 rshift r> c! r> c! ;
: w@ ( addr -- x ) dup c@ 8 lshift swap 1+ c@ or ;
: w, ( x -- ) here 2 allot w! ;
[then]

另外,將文本轉換為數字的功能應該在庫中。 為此使用evaluate不是衛生的。 請參閱“如何在Forth中輸入數字”問題中的StoN定義示例。 在您的Forth系統中可以找到轉換“ $”前綴數字的助手。

\ dummy definitions for test only
: s-to-n ( addr u -- x ) evaluate ;
: send-i2c1 ( addr x -- ) ." send: " . . CR ;

應用代碼:

\ Translate the input numbers till the delimiter into the special format
\ (the code could be simplified using the quotations)

: i2c-delim s" i2c1-x;" ;

: translate-i2c-pair ( c-addr u -- )
  s-to-n
  parse-name-sure
  2dup i2c-delim equals abort" translate-i2c: unexpected delimiter"
  s-to-n c, w,
;
: translate-i2c-input ( -- )
  i2c-delim ['] translate-i2c-pair translate-input-till-with
;


\ Send data from the special format

: send-i2c1-bulk ( addr u -- )
  3 /  0 ?do
    dup c@ swap 1+
    dup w@ swap 2+ >r send-i2c1 r>
  loop drop
;


\ The defining word

: i2c1-x:
  create here >r 0 , here >r translate-i2c-input here r> - r> !
  does> dup cell+ swap @ send-i2c1-bulk
;

一個測試用例

i2c1-x: test
1 2
3 4
5
6
i2c1-x;

test

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM