REBOL[ Title: "Tiny Asm" Date: 08-Nov-2005 File: %Asm.r Author: "Tim Wylie" Purpose: "Assemble Tiny asm code to Tiny machine code" ] ;variables FileName: none LocCtr: 0 FileLine: 0 Symbol: none ;output files Filelis: copy [] Filetnc: copy [] ;Symbol table objects Symbol_Table: copy [] 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] Pseudo_Table:["DC" "DB" "DS"] Rom_Table:["PRINTN" 900 "PRINTC" 925 "INPUTN" 950 "INPUTC" 975] Error_Table:["NF" "File Not Found" "UW" "Unable to write file" "DS" "Bad DS Space Definition" "DC" "Bad DC String Definition" "DB" "Bad DB Byte Definition" "OP" "Bad Opcode or Symbol" "NC" "Missing ';' For Comment"] Error: func["Send Error Message and Halt" err [String!] "Error" errline [Integer!]"Error Line"/local errstr] [ errstr: none if all[err <> "NF" err <> "UW"][errstr: rejoin["Error on line " errline ": "] ] print join errstr Error_Table/:err halt ] Fill: func["Fill in zeros" num [String!] "Number" size [Integer!]"Size to make string"] [while [(length? num) <= size][insert num: head num "0"]] either[system/script/args = none][ print "FileName: " ;wait for input and set filename ;if nothing is entered will continue while[not exists? to-file FileName: input][print "File Not Found"] ][FileName: system/scripts/args] if error? try[File: read/lines to-file FileName][Error "NF" 0] File_Copy: copy/deep File ;first pass - builds the symbol table foreach Line File[ FileLine: FileLine + 1 if cindex: find Line ";"[Line: copy/part Line cindex] ;strip out comments ;check for symbol either cindex: find Line ":"[ Symbol: copy/part Line cindex Line: remove cindex ][Symbol: none] SplitLine: parse Line none ;parse line based on whitespace if Symbol <> none[ ;put symbol in symbol table Symbol_Table: tail Symbol_Table insert Symbol_Table LocCtr ;inserts the line the symbol is on insert Symbol_Table uppercase Symbol ] ;if there is code on the line change the line appropriately if not empty? SplitLine[ if find Pseudo_Table (Op: uppercase first SplitLine)[ if error? try[ if Op = "DS" [LocCtr: LocCtr + to-integer (second SplitLine) LocCtr: LocCtr - 1 ] ][Error "DS" FileLine] if error? try[ if Op = "DC"[ str: parse/all Line "'" ;get the string LocCtr: LocCtr + (length? (second str)) LocCtr: LocCtr - 1 ] ][Error "DC" FileLine] ] LocCtr: LocCtr + 1 ] ] ;reset variables LocCtr: 0 FileLine: 0 Symbol_Table: head Symbol_Table Symbol_Table: union Symbol_Table Rom_Table ;second pass - assembles code and creates lis and tnc output files. insert Filelis rejoin["Tiny Assembler Listing of " FileName " on " now/date " at " now/time] insert Filelis: tail Filelis " " insert Filelis: tail Filelis "ADR VALUE SOURCE LINE" insert Filelis: tail Filelis "--- ----- -----------" foreach SourceLine File_Copy[ Line: copy/deep SourceLine FileLine: FileLine + 1 Filelis: tail Filelis Filetnc: tail Filetnc if cindex: find Line ";"[Line: copy/part Line cindex] if cindex: find Line ":"[Line: remove cindex] SplitLine: parse Line none either not empty? SplitLine[ either find Pseudo_Table (Op: uppercase first SplitLine)[ if Op = "DS" [ if error? try[ insert Filetnc rejoin[(Fill to-string LocCtr 3) ", " "00000"] insert Filelis rejoin[(Fill to-string LocCtr 3) " " "00000" " " SourceLine] LocCtr: LocCtr + to-integer (second SplitLine) ][Error "DS" FileLine] if (length? SplitLine) > 2[Error "NC" FileLine] ] if Op = "DC"[ if error? try[ str: parse/all Line "'" if (length? str) > 2[Error "NC" FileLine] str: second str insert Filelis: tail Filelis rejoin[(Fill to-string LocCtr 3) " " (Fill to-string (to-integer str/1) 5) " " SourceLine] foreach char str[ insert Filetnc: tail Filetnc rejoin[(Fill to-string LocCtr 3) ", " (Fill to-string (to-integer char) 5)] ;insert Filelis: tail Filelis rejoin[(Fill to-string LocCtr 3) " " (Fill to-string (to-integer char) 5) " " char] LocCtr: LocCtr + 1 ] ][Error "DC" FileLine] ] if Op = "DB"[ if error? try[ insert Filetnc rejoin[(Fill to-string LocCtr 3) ", " (Fill to-string (to-integer (second SplitLine)) 5)] insert Filelis rejoin[(Fill to-string LocCtr 3) " " (Fill to-string (to-integer (second SplitLine)) 5) " " SourceLine] LocCtr: LocCtr + 1 ][Error "DB" FileLine] if (length? SplitLine) > 2[Error "NC" FileLine] ] ][ Opc: uppercase first SplitLine either (length? SplitLine) > 1[ if error? try[ ;Oper: second (find Symbol_Table (second SplitLine)) Oper: select Symbol_Table (second SplitLine) insert Filetnc rejoin [(Fill to-string LocCtr 3) ", " (Fill to-string Opcode_Table/:Opc 2) (Fill to-string Oper 3)] insert Filelis rejoin [(Fill to-string LocCtr 3) " " (Fill to-string Opcode_Table/:Opc 2) (Fill to-string Oper 3) " " SourceLine] ][Error "OP" FileLine] if (length? SplitLine) > 2[Error "NC" FileLine] ][ if error? try[ insert Filetnc rejoin [(Fill to-string LocCtr 3) ", " (Fill to-string Opcode_Table/:Opc 5)] insert Filelis rejoin [(Fill to-string LocCtr 3) " " (Fill to-string Opcode_Table/:Opc 5) " " SourceLine] ][Error "OP" FileLine] ] LocCtr: LocCtr + 1 ] ][if not empty? SourceLine [insert Filelis rejoin[" " SourceLine]]] ] append (FileNametnc: copy/part FileName dot: find FileName ".") ".tnc" append (FileNamelis: copy/part FileName dot) ".lis" if error? try[write/lines (to-file FileNametnc) head Filetnc][Error "W" 0] if error? try[write/lines (to-file FileNamelis) head Filelis][Error "W" 0] halt