rebol[Title: "Tiny Asm 2" Date: 27-April-2007 File: %tiny_asm.r Author: "Tim Wylie" Purpose: "Assemble tiny code."] tiny-asm: make object![ make-row: func[rn[integer!] /opcode opc[string!] /asm-opcode aopc /operand oper /asm-operand aoper /byte b][ make object![rownum: rn opcode: opc opcode-asm: aopc operand: oper operand-asm: aoper memory: b]] pad: func [value [string! number!] length [integer!] /fill char [char!] /locals field][ if not string? value [value: form value] if none? char [char: #"0"] insert/dup field: copy "" char length change/part field head reverse value length? value head reverse field ] tiny-assembler: func[][ if error? err: try[ foreach line program-lines[ if all[line/opcode (none? line/opcode-asm)][line/opcode-asm: (select opcode-table line/opcode)] if all[line/opcode-asm (none? line/opcode)][line/opcode: first back (find opcode-table line/opcode-asm)] if line/operand[ line/operand-asm: (pad (select symbol-table line/operand) 3) if none? line/operand-asm[ numbers: charset[#"0" - #"9"] either (parse/all line/operand [some numbers])[ line/operand-asm: (pad line/operand 3)][throw rejoin["Illegal operand line" line/rownum]] ] either line/memory[line/memory: (pad to-string line/memory 5) ][line/memory: rejoin[(pad line/opcode-asm 2) (pad to-integer line/operand-asm 3)]] ] ][print rejoin["Error assembling: " err/type err/code]] ] tiny-parser: func[data [string!]][ validchars: charset [#"0" - #"9" #"A" - #"Z" #"a" - #"z" #"_" #"#"] numbers: charset[#"0" - #"9"] stringchars: complement charset[#"'"] whitespace: charset [#"^-" #"^/" " "] program-lines: copy [] line-counter: 0 ;verify syntax/build symbol table if error? try[ foreach str parse/all data "^/"[ opcode: none operand: none parse/all str [ any[ [copy opcode ["lda"|"ldi"|"ld"|"sti"|"st"|"add"|"sub"|"mul"|"div"|"bz"|"bp"|"bn"|"b"|"jsb"] some whitespace copy operand some validchars (append program-lines (make-row/opcode/operand/asm-opcode line-counter opcode operand (select opcode-table opcode)) line-counter: line-counter + 1)] |[["db"] some whitespace copy operand some numbers (append program-lines (make-row/byte line-counter operand) line-counter: line-counter + 1)] |[["ds"] some whitespace copy operand some numbers (loop to-integer operand [append program-lines (make-row line-counter) line-counter: line-counter + 1])] |[["dc"] any whitespace "'" copy operand some stringchars "'"(foreach let operand [append program-lines (make-row/byte line-counter to-integer let) line-counter: line-counter + 1])] |[copy opcode ["stop"|"in"|"out"|"push"|"pop"|"rsb"](append program-lines (make-row/opcode/asm-opcode line-counter opcode (select opcode-table opcode)) line-counter: line-counter + 1)] |[copy symbol some validchars ":"(repend symbol-table [symbol line-counter])] |[any whitespace ";" to end] |[some whitespace] ] ] ] ][print rejoin["Error parsing tiny code line: " line-counter] return false] return true ] set 'assemble-tiny func[file [file!]][ either[tiny-parser read file tiny-assembler write-asm file][print rejoin["Error reading file: " file]] ] write-asm: func[file [file!]][ if error? try[ new-file: second split-path file new-file: join (copy/part new-file find new-file ".tny") ".tnc" if exists? new-file[delete new-file] foreach x program-lines[ write/append new-file rejoin[(pad x/rownum 3) ", " (pad x/memory 5)newline] ] ][print rejoin["Error writing file: " new-file] ] opcode-table: ["stop" 00 "ld" 01 "ldi" 02 "lda" 03 "st" 04 "sti" 05 "add" 06 "sub" 07 "mul" 08 "div" 09 "in" 10 "out" 11 "b" 12 "bp" 13 "bn" 14 "bz" 15 "jsb" 16 "rsb" 17 "push" 18 "pop" 19] symbol-table: ["printn" 900 "printc" 925 "inputn" 950 "inputc" 975] program-lines: none ] either[system/script/args = none][print "FileName: " while[not exists? to-file filename: input]] [filename: system/scripts/args] assemble-tiny to-file filename