目次

FORTHシステム(Tcl/Tk)

 新しいマイコンの勉強をする場合、アセンブリ言語しか
 用意されていない場合があります。

 アセンブリ言語で簡単な処理系を構成する場合、構文解析が
 簡単なFORTHインタプリタを作成して利用することが多いです。

 スタック操作ができると、proper programを書きやすいので
 内蔵SRAMが4kバイト程度あれば、マイコンのハードウエアを
 テストする、小規模なOSなしのシステムを作成する等では
 FORTH利用で、作成しやすく、それなりに使えるシステムを
 構築できます。

 アセンブリ言語でいきなりFORTHシステムを作成するのは
 開発時間が長くなるため、Unix、Windowsの双方で使える
 Tcl/Tkのスクリプトで作成しました。

 コマンドラインから、コマンドとパラメータを
 入力するのは面倒なので、テキストファイルに
 次のような文字列を用意して確認することに。

1 2 + .
4 5 * .
10 1 2 - .
1 2 * 3 4 5 + .
9 2 / .
9 2 % .
100 10 inc .
100 22 dec .
1 dup . .
12 24 + . cr
10 0 < .
10 0 <= .
10 0 > .
10 0 >= .
10 10 == .
10 10 != .
10 0 < if 0 1 + . then
10 11 < if 2 3 + . then
10 0 <= if 0 1 + . else 4 3 * . then
10 0 >= if 0 1 + . else 4 1 - . then
10 0 == if 2 3 + . else 5 1 - . then
3 0 do I inc dec . loop
11 1 do I . loop
1 2 3 4 drop drop . .
3 3 == if 100 . else 0 . then
3 4 == if 100 . else 200 . then
3 4 >= if 100 . else 200 . then
: mul10 10 * ;
: mul3 3 * ;
: mulx 2 * 1 + ;
9 mul3 .
9 mulx .
1 2 3 4 drop drop . .
10 9 8 7 rot . . . .
1 << .
8 << .
15 3 & .
15 16 | .
15 3 ^ .
1 2 3 20 4 max .
10 2 3 20 4 min .
var aa 123 aa ! 321 aa !
aa @ .
0 3 2 -5 min .
0 3 2 -5 max .

 作成したFORTHシステムで、動作確認すると、以下となりました。

>1 2 + .
3
>4 5 * .
20
>10 1 2 - .
7
>1 2 * 3 4 5 + .
14
>9 2 / .
4
>9 2 % .
1
>100 10 inc .
11
>100 22 dec .
21
>1 dup . .
1
1
>12 24 + . cr
36

>10 0 < .
0
>10 0 <= .
0
>10 0 > .
1
>10 0 >= .
1
>10 10 == .
1
>10 10 != .
0
>10 0 < if 0 1 + . then
>10 11 < if 2 3 + . then
5
>10 0 <= if 0 1 + . else 4 3 * . then
12
>10 0 >= if 0 1 + . else 4 1 - . then
1
>10 0 == if 2 3 + . else 5 1 - . then
4
>3 0 do I inc dec . loop
0
1
2
>11 1 do I . loop
1
2
3
4
5
6
7
8
9
10
>1 2 3 4 drop drop . .
2
1
>3 3 == if 100 . else 0 . then
100
>3 4 == if 100 . else 200 . then
200
>3 4 >= if 100 . else 200 . then
200
>: mul10 10 * ;
 mul10
>: mul3 3 * ;
 mul10 mul3
>: mulx 2 * 1 + ;
 mul10 mul3 mulx
>9 mul3 .
27
>9 mulx .
19
>1 2 3 4 drop drop . .
2
1
>10 9 8 7 rot . . . .
8
9
7
10
>1 << .
2
>8 >> .
4
>15 3 & .
3
>15 16 | .
31
>15 3 ^ .
12
>1 2 3 20 4 max .
20
>10 2 3 20 4 min .
2
>var aa 123 aa ! 321 aa !
>aa @ .
321
>0 3 2 -5 min .
-5
>0 3 2 -5 max .
3

 450行程度で処理系を記述できました。
 スクリプトは以下。

# computing built-in instruction
proc cmd_execute {xcmd x} {
  # get parameters
  set car [lindex $x 0]
  set cdr [lrange $x 1 end]
  # ADD
  if { $xcmd == "+" } {
    foreach i $cdr {
      set car [expr $car + $i]
    }
  }
  # SUBTRACT
  if { $xcmd == "-" } {
    foreach i $cdr {
      set car [expr $car - $i]
    }
  }
  # MULTIPLY
  if { $xcmd == "*" } {
    foreach i $cdr {
      set car [expr $car * $i]
    }
  }
  # DIVIDE
  if { $xcmd == "/" } {
    foreach i $cdr {
      if { $i != 0 } {
        set car [expr $car / $i]
      }
    }
  }
  # REMAINDER
  if { $xcmd == "%" } {
    foreach i $cdr {
      if { $i != 0 } {
        set car [expr $car % $i]
      }
    }
  }
  # INCREMENT
  if { $xcmd == "inc" } {
    set car [expr $car + 1]
  }
  # DECREMENT
  if { $xcmd == "dec" } {
    set car [expr $car - 1]
  }
  # LESS THAN
  if { $xcmd == "<" } {
    set cdr [lindex $cdr 0]
    if { $car < $cdr } {
      set car 1
    } else {
      set car 0
    }
  }
  # LESS THAN or EQUAL
  if { $xcmd == "<=" } {
    set cdr [lindex $cdr 0]
    if { $car <= $cdr } {
      set car 1
    } else {
      set car 0
    }
  }
  # GREATER THAN
  if { $xcmd == ">" } {
    set cdr [lindex $cdr 0]
    if { $car > $cdr } {
      set car 1
    } else {
      set car 0
    }
  }
  # GREATER THAN or EQUAL
  if { $xcmd == ">=" } {
    set cdr [lindex $cdr 0]
    if { $car >= $cdr } {
      set car 1
    } else {
      set car 0
    }
  }
  # EQUAL
  if { $xcmd == "==" } {
    set cdr [lindex $cdr 0]
    if { $car == $cdr } {
      set car 1
    } else {
      set car 0
    }
  }
  # NOT EQUAL
  if { $xcmd == "!=" } {
    set cdr [lindex $cdr 0]
    if { $car != $cdr } {
      set car 1
    } else {
      set car 0
    }
  }
  # &
  if { $xcmd == "&" } {
    set cdr [lindex $cdr 0]
    set car [expr $car & $cdr]
  }
  # |
  if { $xcmd == "|" } {
    set cdr [lindex $cdr 0]
    set car [expr $car | $cdr]
  }
  # ^
  if { $xcmd == "^" } {
    set cdr [lindex $cdr 0]
    set car [expr $car ^ $cdr]
  }
  # <<
  if { $xcmd == "<<" } {
    set car [expr $car * 2]
  }
  # >>
  if { $xcmd == ">>" } {
    set car [expr $car / 2]
  }

  return $car
}

proc isvariable {x} {
  global varnametbl
  #
  set result 0
  # judge
  if { [lsearch -exact $varnametbl $x] >= 0 } {
    set result 1
  }

  return $result
}

proc interpret {x} {
  global wordnametbl wordstack varnametbl varstack
  # copy
  set xx $x
  # show
  puts ">$xx"
  # clear
  set result ""
  set ustack ""
  # replace word
  set yy ""
  foreach i $xx {
    # copy
    set tmp $i
    # ? word
    if { [lsearch -exact $wordnametbl $i] >= 0 } {
      set tmp $wordstack($i)
    }
    # update
    set yy "$yy $tmp"
  }
  set xx $yy
  # initialize
  set last 0
  set xcnt 0
  # loop
  set len [llength $xx]
  set ptr 0
  while { $ptr < $len } {
    # get token
    set i [lindex $xx $ptr]
    # ?digit
    if { [string is digit -strict $i] == 1 } {
      # store digit
      set ustack "$ustack $i"
      # increment
      incr ptr
    }
    if { [string length $i] > 1 && [string index $i 0] == "-" } {
      # store digit
      set ustack "$ustack $i"
      # increment
      incr ptr
    }
    # + , - , * , /
    if { $i == "+" || $i == "-" || $i == "*" || $i == "/" || $i == "%" } {
      # calculate stack top
      set result [cmd_execute $i $ustack]
      # poke
      set ustack $result
      # increment
      incr ptr
    }
    # inc
    if { $i == "inc" || $i == "dec" } {
      # calculate stack top
      set result [cmd_execute $i [lindex $ustack end]]
      # remove stack top
      set ustack [lrange $ustack 0 end-1]
      # add stack top
      set ustack "$ustack $result"
      incr ptr
    }
    # dup
    if { $i == "dup" } {
      # get stack top
      set result [lindex $ustack end]
      # add stack top
      set ustack "$ustack $result"
      # increment
      incr ptr
    }
    # cr
    if { $i == "cr" } {
      # show empty list
      puts ""
      # increment
      incr ptr
    }
    # < , <= , > , >= 
    if { $i == "<" || $i == "<=" || $i == ">" || $i == ">=" } {
      #
      set ptrl [lsearch -exact $xx $i]
      # judge
      if { [llength $ustack] >= 2 } {
        # calculate
        set result [cmd_execute $i [lrange $ustack end-1 end]]
        # remove 2 digit
        set ustack [lrange $ustack 0 end-2]
        # add result
        set ustack "$ustack $result"
      }
      # increment
      set ptr [expr $ptrl+1]
    }
    # == , != 
    if { $i == "==" || $i == "!=" } {
      #
      set ptrl [lsearch -exact $xx $i]
      # judge
      if { [llength $ustack] >= 2 } {
        # calculate
        set result [cmd_execute $i [lrange $ustack end-1 end]]
        # remove 2 digit
        set ustack [lrange $ustack 0 end-2]
        # add result
        set ustack "$ustack $result"
      }
      # increment
      set ptr [expr $ptrl+1]
    }
    # drop
    if { $i == "drop" } {
      # remove stack top
      set ustack [lrange $ustack 0 end-1]
      # increment
      incr ptr
    }
    # rot
    if { $i == "rot" } {
      set result ""
      # judge
      if { [llength $ustack] >= 3 } {
        # get stack top
        set fx [lindex $ustack end]
        set ustack [lrange $ustack 0 end-1]
        # get stack top
        set sx [lindex $ustack end]
        set ustack [lrange $ustack 0 end-1]
        # get stack top
        set tx [lindex $ustack end]
        set ustack [lrange $ustack 0 end-1]
        # append
        set ustack "$ustack $fx $tx $sx"
      }
      # increment
      incr ptr
    }
    # swap
    if { $i == "swap" } {
      set result ""
      # judge
      if { [llength $ustack] >= 2 } {
        # get stack top
        set fx [lindex $ustack end]
        set ustack [lrange $ustack 0 end-1]
        # get stack top
        set sx [lindex $ustack end]
        set ustack [lrange $ustack 0 end-1]
        # append
        set ustack "$ustack $fx $sx"
      }
      # increment
      incr ptr
    }
    # << , >> 
    if { $i == "<<" || $i == ">>"} {
      # calculate
      set result [cmd_execute $i [lindex $ustack end]]
      # remove stack top
      set ustack [lrange $ustack 0 end-1]
      # append
      set ustack "$ustack $result"
      # increment
      incr ptr
    }
    # & , | , ^
    if { $i == "&" || $i == "|" || $i == "^" } {
      set result ""
      # judge
      if { [llength $ustack] >= 2 } {
        # get stack top
        set sx [lindex $ustack end]
        set ustack [lrange $ustack 0 end-1]
        # get stack top
        set fx [lindex $ustack end]
        set ustack [lrange $ustack 0 end-1]
        # calculate
        set tmp "$fx $sx"
        set result [cmd_execute $i $tmp]
        # append
        set ustack "$ustack $result"
      }
      # increment
      incr ptr
    }
    # if
    if { $i == "if" } {
      # get result
      set result [lindex $ustack end]
      # remove stack top
      set ustack [lindex $ustack end-1]
      # else location
      set ptrelse [lsearch -exact $xx "else"]
      # judge
      if { $result == 1 } {
        # increment
        incr ptr
      } else {
        # update
        if { $ptrelse >= 0 } {
          set ptr [expr $ptrelse+1]
        } else {
          set ptr [lsearch -exact $xx "then"]
        }
      }
    }
    # else
    if { $i == "else" } {
      # update
      set ptr [lsearch -exact $xx "then"]
    }
    # then
    if { $i == "then" } {
      # increment
      incr ptr
    }
    # do
    if { $i == "do" } {
      # judge
      if { [llength $ustack] >= 2 } {
        # get end count
        set last [lindex $ustack end-1]
        # get start count
        set xcnt [lindex $ustack end]
        # remove 2 digit
        set ustack [lrange $ustack 0 end-2]
      }
      # increment
      incr ptr
    }
    # I
    if { $i == "I" } {
      # poke I(xcnt)
      set ustack "$ustack $xcnt"
      # increment
      incr ptr
    }
    # loop
    if { $i == "loop" } {
      # increment control counter
      set xcnt [expr $xcnt+1]
      # judge
      if { $xcnt < $last } {
        set ptrdo [lsearch -exact $xx "do"]
        set ptr [expr $ptrdo+1]
      } else {
        # increment
        incr ptr
      }
    }
    # word definition :
    if { $i == ":" } {
      # word name
      set wdn [lindex $xx [expr $ptr+1]]
      # memory
      set wordnametbl "$wordnametbl $wdn"
      # word body
      set wdbody [lrange $xx [expr $ptr+2] end-1]
      # store
      set wordstack($wdn) $wdbody
      # 
      set ptr [lsearch -exact $xx ";"]
    }
    # word definition ;
    if { $i == ";" } {
      puts $wordnametbl
      # increment
      incr ptr
    }
    # max
    if { $i == "max" } {
      # get first datum
      set result [lindex $ustack 0]
      # loop
      foreach i $ustack {
        # compare
        if { $result < $i } {
          set result $i
        }
      }
      # update
      set ustack "$ustack $result"
      # increment
      incr ptr
    }
    # min
    if { $i == "min" } {
      # get first datum
      set result [lindex $ustack 0]
      # loop
      foreach i $ustack {
        # compare
        if { $result > $i } {
          set result $i
        }
      }
      # update
      set ustack "$ustack $result"
      # increment
      incr ptr
    }
    # var
    if { $i == "var" } {
      # get variable name
      set varn [lindex $xx [expr $ptr+1]]
      # store variable name
      set varnametbl "$varnametbl $varn"
      # set pseudo value
      set varstack($varn) 0
      # increment
      set ptr [expr $ptr+2]
    }
    # .
    if { $i == "." } {
      # get stack top
      set result [lindex $ustack end]
      # delete
      set ustack [lrange $ustack 0 end-1]
      # show
      puts $result
      # increment
      incr ptr
    }
    # set value to variable
    if { $i == "!" } {
      # get variable name
      set varn [lindex $ustack end]
      # get variable
      set result [lindex $ustack end-1]
      # remove
      set ustack [lrange $ustack 0 end-2]
      # store
      set varstack($varn) $result
      # increment
      incr ptr
    }
    # get value from variable
    if { $i == "@" } {
      # get variable name
      set varn [lindex $ustack end]
      # remove
      set ustack [lrange $ustack 0 end]
      # get variable
      set result $varstack($varn)
      # store
      set ustack "$ustack $result"
      # increment
      incr ptr
    }
    # variable handling
    if { [isvariable $i] == 1 } {
      # poke
      set ustack "$ustack $i"
      # increment
      incr ptr
    }
  }
}

# clear user stack
set wordnametbl ""
set wordstack("CODE") ""
set varnametbl ""
set varstack("aa") ""
set loopcnt 0
# open
set finx [open "ftxt.txt" "r"]
# loop
while { [gets $finx sbuf] >= 0 } {
  # interpret
  if { $sbuf == "" } {
    continue
  }
  # interpret
  interpret $sbuf
}
#
close $finx

 built-inの命令(FORTHではワード)を用意し、選択は
 if...else...then、繰返しはdo...loopだけにしました。

 built-inのワードは、以下。

 シェルに相当するコマンドインタプリタは
 次のシーケンスで動かしてみました。
  1. バッファから1行取得
  2. トークンに分割
  3. トークンが数値なら、スタックに転送
  4. トークンがユーザー定義ワードなら、展開してbuilt-inワードのシーケンスに変換
  5. ユーザーのワード定義指定があれば、専用エリアにbuilt-inワードのシーケンスに変換
  6. ワードを実行
  7. 1に戻る
 シェル相当のコマンドインタプリタは、プロシージャ  「interpret」にまとめました。  プロシージャ「interpret」内で利用するビルトイン  ワードを実現するために、トークンはスタック操作の  他に、do...loop、if...else...thenに使う文字列を  含めました。  トークンの判定で、スタックに数値を積みます。  スタックを実現するデータ構造にはリストを採用しました。  1行をリストで表現すると、トークンの判別が  簡便にできました。  Tcl/Tkでは、foreachを使うと、リストからトークンを  抽出するのは簡単になります。  ユーザー定義ワードは、連想配列の中にワード名と  処理シーケンスをペアで格納します。  イメージは、次のようになります。 "mul10" -> POKE 10 MUL "mul3" -> POKE 3 MUL "mulx" -> POKE 2 MUL POKE 1 ADD  ユーザー定義ワードを使う場合、文字列を利用して  該当するシーケンスに置換するので、マクロを使う  イメージとなります。  構文解析は、トークンスキャナーを定義し  トークンを逐次調べて解釈します。  ワードならば展開して、1行の内容を置換し  次のトークンの調査に行きます。  構文解析のプロシージャは、以下。 proc interpret {x} { global wordnametbl wordstack varnametbl varstack # copy set xx $x # show puts ">$xx" # clear set result "" set ustack "" # replace word set yy "" foreach i $xx { # copy set tmp $i # ? word if { [lsearch -exact $wordnametbl $i] >= 0 } { set tmp $wordstack($i) } # update set yy "$yy $tmp" } set xx $yy # initialize set last 0 set xcnt 0 # loop set len [llength $xx] set ptr 0 while { $ptr < $len } { # get token set i [lindex $xx $ptr] # ?digit if { [string is digit -strict $i] == 1 } { # store digit set ustack "$ustack $i" # increment incr ptr } if { [string length $i] > 1 && [string index $i 0] == "-" } { # store digit set ustack "$ustack $i" # increment incr ptr } # + , - , * , / if { $i == "+" || $i == "-" || $i == "*" || $i == "/" || $i == "%" } { # calculate stack top set result [cmd_execute $i $ustack] # poke set ustack $result # increment incr ptr } # inc if { $i == "inc" || $i == "dec" } { # calculate stack top set result [cmd_execute $i [lindex $ustack end]] # remove stack top set ustack [lrange $ustack 0 end-1] # add stack top set ustack "$ustack $result" incr ptr } # dup if { $i == "dup" } { # get stack top set result [lindex $ustack end] # add stack top set ustack "$ustack $result" # increment incr ptr } # cr if { $i == "cr" } { # show empty list puts "" # increment incr ptr } # < , <= , > , >= if { $i == "<" || $i == "<=" || $i == ">" || $i == ">=" } { # set ptrl [lsearch -exact $xx $i] # judge if { [llength $ustack] >= 2 } { # calculate set result [cmd_execute $i [lrange $ustack end-1 end]] # remove 2 digit set ustack [lrange $ustack 0 end-2] # add result set ustack "$ustack $result" } # increment set ptr [expr $ptrl+1] } # == , != if { $i == "==" || $i == "!=" } { # set ptrl [lsearch -exact $xx $i] # judge if { [llength $ustack] >= 2 } { # calculate set result [cmd_execute $i [lrange $ustack end-1 end]] # remove 2 digit set ustack [lrange $ustack 0 end-2] # add result set ustack "$ustack $result" } # increment set ptr [expr $ptrl+1] } # drop if { $i == "drop" } { # remove stack top set ustack [lrange $ustack 0 end-1] # increment incr ptr } # rot if { $i == "rot" } { set result "" # judge if { [llength $ustack] >= 3 } { # get stack top set fx [lindex $ustack end] set ustack [lrange $ustack 0 end-1] # get stack top set sx [lindex $ustack end] set ustack [lrange $ustack 0 end-1] # get stack top set tx [lindex $ustack end] set ustack [lrange $ustack 0 end-1] # append set ustack "$ustack $fx $tx $sx" } # increment incr ptr } # << , >> if { $i == "<<" || $i == ">>"} { # calculate set result [cmd_execute $i [lindex $ustack end]] # remove stack top set ustack [lrange $ustack 0 end-1] # append set ustack "$ustack $result" # increment incr ptr } # & , | , ^ if { $i == "&" || $i == "|" || $i == "^" } { set result "" # judge if { [llength $ustack] >= 2 } { # get stack top set sx [lindex $ustack end] set ustack [lrange $ustack 0 end-1] # get stack top set fx [lindex $ustack end] set ustack [lrange $ustack 0 end-1] # calculate set tmp "$fx $sx" set result [cmd_execute $i $tmp] # append set ustack "$ustack $result" } # increment incr ptr } # if if { $i == "if" } { # get result set result [lindex $ustack end] # remove stack top set ustack [lindex $ustack end-1] # else location set ptrelse [lsearch -exact $xx "else"] # judge if { $result == 1 } { # increment incr ptr } else { # update if { $ptrelse >= 0 } { set ptr [expr $ptrelse+1] } else { set ptr [lsearch -exact $xx "then"] } } } # else if { $i == "else" } { # update set ptr [lsearch -exact $xx "then"] } # then if { $i == "then" } { # increment incr ptr } # do if { $i == "do" } { # judge if { [llength $ustack] >= 2 } { # get end count set last [lindex $ustack end-1] # get start count set xcnt [lindex $ustack end] # remove 2 digit set ustack [lrange $ustack 0 end-2] } # increment incr ptr } # I if { $i == "I" } { # poke I(xcnt) set ustack "$ustack $xcnt" # increment incr ptr } # loop if { $i == "loop" } { # increment control counter set xcnt [expr $xcnt+1] # judge if { $xcnt < $last } { set ptrdo [lsearch -exact $xx "do"] set ptr [expr $ptrdo+1] } else { # increment incr ptr } } # word definition : if { $i == ":" } { # word name set wdn [lindex $xx [expr $ptr+1]] # memory set wordnametbl "$wordnametbl $wdn" # word body set wdbody [lrange $xx [expr $ptr+2] end-1] # store set wordstack($wdn) $wdbody # set ptr [lsearch -exact $xx ";"] } # word definition ; if { $i == ";" } { puts $wordnametbl # increment incr ptr } # max if { $i == "max" } { # get first datum set result [lindex $ustack 0] # loop foreach i $ustack { # compare if { $result < $i } { set result $i } } # update set ustack "$ustack $result" # increment incr ptr } # min if { $i == "min" } { # get first datum set result [lindex $ustack 0] # loop foreach i $ustack { # compare if { $result > $i } { set result $i } } # update set ustack "$ustack $result" # increment incr ptr } # var if { $i == "var" } { # get variable name set varn [lindex $xx [expr $ptr+1]] # store variable name set varnametbl "$varnametbl $varn" # set pseudo value set varstack($varn) 0 # increment set ptr [expr $ptr+2] } # . if { $i == "." } { # get stack top set result [lindex $ustack end] # delete set ustack [lrange $ustack 0 end-1] # show puts $result # increment incr ptr } # set value to variable if { $i == "!" } { # get variable name set varn [lindex $ustack end] # get variable set result [lindex $ustack end-1] # remove set ustack [lrange $ustack 0 end-2] # store set varstack($varn) $result # increment incr ptr } # get value from variable if { $i == "@" } { # get variable name set varn [lindex $ustack end] # remove set ustack [lrange $ustack 0 end] # get variable set result $varstack($varn) # store set ustack "$ustack $result" # increment incr ptr } # variable handling if { [isvariable $i] == 1 } { # poke set ustack "$ustack $i" # increment incr ptr } } }  1行をリストとみなして、トークンに分割します。  トークンがユーザーが定義したワードであるかを調べ  もしユーザー定義ワードであれば、展開します。  トークンの種別を判定し、数値であればスタックに  積み、ワードなら対応する処理を実行します。  四則演算のような単純な計算は、関数を定義して使います。 proc cmd_execute {xcmd x} { # get parameters set car [lindex $x 0] set cdr [lrange $x 1 end] # ADD if { $xcmd == "+" } { foreach i $cdr { set car [expr $car + $i] } } # SUBTRACT if { $xcmd == "-" } { foreach i $cdr { set car [expr $car - $i] } } # MULTIPLY if { $xcmd == "*" } { foreach i $cdr { set car [expr $car * $i] } } # DIVIDE if { $xcmd == "/" } { foreach i $cdr { if { $i != 0 } { set car [expr $car / $i] } } } # REMAINDER if { $xcmd == "%" } { foreach i $cdr { if { $i != 0 } { set car [expr $car % $i] } } } # INCREMENT if { $xcmd == "inc" } { set car [expr $car + 1] } # DECREMENT if { $xcmd == "dec" } { set car [expr $car - 1] } # LESS THAN if { $xcmd == "<" } { set cdr [lindex $cdr 0] if { $car < $cdr } { set car 1 } else { set car 0 } } # LESS THAN or EQUAL if { $xcmd == "<=" } { set cdr [lindex $cdr 0] if { $car <= $cdr } { set car 1 } else { set car 0 } } # GREATER THAN if { $xcmd == ">" } { set cdr [lindex $cdr 0] if { $car > $cdr } { set car 1 } else { set car 0 } } # GREATER THAN or EQUAL if { $xcmd == ">=" } { set cdr [lindex $cdr 0] if { $car >= $cdr } { set car 1 } else { set car 0 } } # EQUAL if { $xcmd == "==" } { set cdr [lindex $cdr 0] if { $car == $cdr } { set car 1 } else { set car 0 } } # NOT EQUAL if { $xcmd == "!=" } { set cdr [lindex $cdr 0] if { $car != $cdr } { set car 1 } else { set car 0 } } # & if { $xcmd == "&" } { set cdr [lindex $cdr 0] set car [expr $car & $cdr] } # | if { $xcmd == "|" } { set cdr [lindex $cdr 0] set car [expr $car | $cdr] } # ^ if { $xcmd == "^" } { set cdr [lindex $cdr 0] set car [expr $car ^ $cdr] } # << if { $xcmd == "<<" } { set car [expr $car * 2] } # >> if { $xcmd == ">>" } { set car [expr $car / 2] } return $car }  if...else...thenに関しては、スタックに保存した  数値から1か0を生成します。1では、ifに連なる  ブロックを実行、0では、elseに連なるブロックを  実行します。  do...loopでは、doの位置で初期値、終了値をスタック  から取出します。初期値を内部カウンタに設定しておき  loopの位置で、内部カウンタを更新。内部カウンタ値が  終了値ならば終了します。内部カウンタが最終値未満で  あれば、doの右に連なるブロックを実行。  do...loopのdo、loopは、制御で必要になる初期化、判定  制御変数更新のタイミングを指定するラベルと考えました。  計算と比較処理は、シーケンスで利用する文字列さえ  判断できれば、ひとつのブロックにまとめられますが  可読性が悪くなるので、分割して記述しています。  可読性を無視して、高速動作をとれば、シーケンスで  利用する文字列を数値にします。後からワードを追加  と考えると、数値では判読しにくいと思い、文字列に  しています。

目次

inserted by FC2 system