Guest User

Untitled

a guest
Dec 30th, 2015
138
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
TCL 6.50 KB | None | 0 0
  1. package require struct
  2. # Исходный текст.
  3. set input_buffer {}
  4. # Память. Список байтов.
  5. set output_buffer {}
  6. # Созданные слова.
  7. array set dict {}
  8. # Адрес последнего определенного слова.
  9. set last 0
  10. # Стек для условий и циклов.
  11. ::struct::stack stack
  12. # Слова - единичные инструкции.
  13. lappend istr      DUP    +      AND    OR     =      <     U<     NIP    DROP   NOT    1-
  14. lappend istr_code 0x6081 0x6203 0x6303 0x6403 0x6703 26627 0x6803 0x6003 0x6103 0x6600 0x6A00
  15. lappend istr      1<<   1>>   swap_bytes  A@    SWAP  DEPTH R@    OVER  >R    R>    {;}
  16. lappend istr_code 27904 26880 25856       27648 24960 28289 27585 24961 24903 27597 28684
  17. # Костыль для констант.
  18. array set constants {}
  19.  
  20. if {$argc != 2} {
  21.     puts {Incorrect command line arguments.}
  22.     exit
  23. }
  24.  
  25. set input_filename [lindex $argv 0]
  26. set output_filename [lindex $argv 1]
  27.  
  28. proc append_byte {byte} {
  29.     global output_buffer
  30.     lappend output_buffer $byte
  31. }
  32.  
  33. proc append_word {word} {
  34.     global output_buffer
  35.     lappend output_buffer [expr {$word & 0xFF}]
  36.     lappend output_buffer [expr {($word >> 8) & 0xFF}]
  37. }
  38.  
  39. # Если слово является инструкцией процессора, то компилирует его и возвращает true,
  40. # если не является инструкцией процессора, то возвращает false.
  41. proc istr_compile {word} {
  42.     global istr istr_code
  43.     if {$word == "A!"} {
  44.         append_word 24867
  45.         append_word 24835
  46.         return true
  47.     } else {
  48.         set pos [lsearch $istr $word]
  49.         if {$pos < 0} {
  50.             return false
  51.         } else {
  52.             append_word [lindex $istr_code $pos]
  53.             return true
  54.         }
  55.     }
  56. }
  57.  
  58. # Компиляция ранее определенного слова или предопределенного слова (инструкции).
  59. # Если слово есть в словаре, возвращает true, иначе возвращает false.
  60. proc compile_word {word} {
  61.     global dict
  62.     if {[info exists dict($word)]} {
  63.         append_word [expr {($dict($word) >> 1) | 0x4000}]
  64.         return true
  65.     } else {
  66.         return [istr_compile $word]
  67.     }
  68. }
  69.  
  70. proc compile_literal {number} {
  71.     set num [expr {$number & 0xFFFF}]
  72.     if {$num > 0x7FFF} {
  73.         append_word [expr {~$num | 0x8000}]
  74.         compile_word "NOT"
  75.     } else {
  76.         append_word [expr {$num | 0x8000}]
  77.     }
  78. }
  79.  
  80. proc compile_const {name} {
  81.     global constants
  82.     if {[info exists constants($name)]} {
  83.         compile_literal $constants($name)
  84.         return true
  85.     } else {
  86.         return false
  87.     }
  88. }
  89.  
  90. proc parse_word {} {
  91.     global input_buffer
  92.     set input_buffer [string trimleft $input_buffer " \t\n"]
  93.     regexp {^([^\s\t\n]*)(.*)} $input_buffer buf word input_buffer
  94.     return $word
  95. }
  96.  
  97. # Адрес начала незанятой памяти.
  98. proc here {} {
  99.     global output_buffer
  100.     return [llength $output_buffer]
  101. }
  102.  
  103. # Формат заголовка:
  104. # выравнивающий байт (при нечетной длине имени)
  105. # имя (побайтно)
  106. # терминирующий нулевой байт
  107. # признак immediate - 1байт (по умолчанию 0)
  108. # адрес предыдущего слова - 2 байта.
  109. proc new_word {name} {
  110.     global dict last
  111.     if {[string bytelength $name] % 2 != 0} {
  112.         # Выравнивающий байт.
  113.         append_byte 0
  114.     }
  115.     foreach char [split $name {}] {
  116.         append_byte [scan $char %c]
  117.     }
  118.     # Терминирующий байт.
  119.     append_byte 0
  120.     # Байт признака.
  121.     append_byte 0
  122.     # Адрес предыдущего слова.
  123.     append_word $last
  124.     set last [here]
  125.     # Добавление в словарь.
  126.     set dict($name) [here]
  127. }
  128.  
  129. proc read_word {addr} {
  130.     global output_buffer
  131.     set wordL [lindex $output_buffer $addr]
  132.     set wordH [lindex $output_buffer $addr+1]
  133.     return [expr {$wordL | ($wordH << 8)}]
  134. }
  135.  
  136. proc replace_word {addr word} {
  137.     global output_buffer
  138.     set wordL [expr {$word & 0xFF}]
  139.     set wordH [expr {($word >> 8) & 0xFF}]
  140.     set output_buffer [lreplace $output_buffer $addr $addr+1 $wordL $wordH]
  141. }
  142.  
  143. if [catch {open forth.f r} forth_file] {
  144.     puts stderr $forth_file
  145.     exit
  146. } else {
  147.     set input_buffer [read $forth_file]
  148.     close $forth_file
  149. }
  150.  
  151. while {[string trim $input_buffer " \t\n"] != {}} {
  152.     set word [parse_word]
  153.     switch $word {
  154.         : {
  155.             new_word [parse_word]
  156.         }
  157.         IMMEDIATE {
  158.             # Задает последнему слову признак немедленного исплонения.
  159.             set pos [expr [last] - 3]
  160.             set output_buffer [lreplace $output_buffer $pos $pos 1]
  161.         }
  162.         IF {
  163.             stack push [here]
  164.             # Опкод условного перехода.
  165.             append_word 0x2000
  166.         }
  167.         ELSE {
  168.             stack push [here]
  169.             stack rotate 2 1
  170.             # Опкод безусловного перехода.
  171.             append_word 0
  172.             set addr [stack pop]
  173.             set word [expr {[read_word $addr] | ([here] >> 1)}]
  174.             replace_word $addr $word
  175.         }
  176.         THEN {
  177.             set addr [stack pop]
  178.             set word [expr {[read_word $addr] | ([here] >> 1)}]
  179.             replace_word $addr $word
  180.         }
  181.         BEGIN {
  182.             stack push [expr {[here] >> 1}]
  183.         }
  184.         AGAIN {
  185.             append_word [stack pop]
  186.         }
  187.         UNTIL {
  188.             append_word [expr {[stack pop] | 0x2000}]
  189.         }
  190.         WHILE {
  191.             stack push [here]
  192.             append_word 0
  193.         }
  194.         REPEAT {
  195.             stack rotate 2 1
  196.             append_word [stack pop]
  197.             replace_word [stack pop] [expr {([here] >> 1) | 0x2000}]
  198.         }
  199.         "\\" {
  200.             # Комментарий.
  201.             regexp {[^\n]*(.*)} $input_buffer buf input_buffer
  202.         }
  203.         jump {
  204.             replace_word 0 [expr {[here] >> 1 }]
  205.         }
  206.         code {
  207.             append_word [parse_word]
  208.         }
  209.         # Костыль для костант.
  210.         const {
  211.             set const_name [parse_word]
  212.             set const_val [parse_word]
  213.             if {$const_val == {here}} {
  214.                 set constants($const_name) [here]
  215.             } else {
  216.                 set constants($const_name) $const_val
  217.             }
  218.         }
  219.         default {
  220.             if {![compile_word $word] && ![compile_const $word]} {
  221.                 if {[string is integer $word]} {
  222.                     compile_literal $word
  223.                 } else {
  224.                     puts "Unknown token: $word"
  225.                     exit
  226.                 }
  227.             }
  228.         }
  229.     }
  230. }
  231.  
  232. if [catch {open $output_filename w} out_file] {
  233.     puts stderr $out_file
  234. } else {
  235.     set addr 0
  236.     foreach byte $output_buffer {
  237.         incr addr
  238.         binary scan [binary format c $byte] B* bits
  239.         if {[expr {$addr % 2}] != 0} {
  240.             set bitsL $bits
  241.         } else {
  242.             puts $out_file "$bits$bitsL"
  243.         }
  244.     }
  245.     for {set i $addr} {$i < 16383} {set i [expr {$i + 2}]} {
  246.         puts $out_file 0000000000000000
  247.     }
  248.     close $out_file
  249. }
  250. puts "[llength $output_buffer] bytes"
  251. puts {Done.}
Advertisement
Add Comment
Please, Sign In to add comment