diff --git a/src/table/ascii_util.odin b/src/table/ascii_util.odin deleted file mode 100644 index 335012a..0000000 --- a/src/table/ascii_util.odin +++ /dev/null @@ -1,15 +0,0 @@ -#+private -package table - -is_oct_digit :: proc(d: u8) -> bool { - return '0' <= d && d <= '7' -} - -is_digit :: proc(d: u8) -> bool { - return '0' <= d && d <= '9' -} - -from_digit :: proc(d: u8) -> u8 { - return d - '0' -} - diff --git a/src/table/markup.odin b/src/table/markup.odin deleted file mode 100644 index 4339ddd..0000000 --- a/src/table/markup.odin +++ /dev/null @@ -1,122 +0,0 @@ -#+private -package table - -import "core:fmt" -import "core:strings" - -@(private) -Marked_Entry :: struct { - line_no: int, - mnemonic: string, - opcode: string, - encoding_kind: Encoding_Kind, - opcode_rx: bool, - rx_spec: string, - eop: string, - flags: map[string]string, -} - -@(private) -mark_fields :: proc(line_no: int, fields: []string) -> (Marked_Entry, bool) { - // Parse mnemonic - idx := 0 - if idx >= len(fields) { - fmt.eprintfln("Line %d: Expected mnemonic", line_no) - return {}, false - } - mnemonic := fields[idx] - idx += 1 - // Parse opcode byte - opcode := fields[idx] - encoding_kind := Encoding_Kind.None - opcode_rx := false - if opcode[len(opcode)-1] == '+' { - opcode_rx = true - opcode = opcode[0:len(opcode)-1] - encoding_kind = .Rx_Embed - } - rx_spec := "" - opcode_slash := strings.index_byte(opcode, '/') - if opcode_slash != -1 { - rx_spec = opcode[opcode_slash+1:] - opcode = opcode[0:opcode_slash] - if encoding_kind != .None { - fmt.eprintfln("Line %d: Cannot specify RX extend and RX embed in the same opcode", line_no) - return {}, false - } - if len(rx_spec) != 1 { - fmt.eprintfln("Line %d: Opcode RX needs to be one character in length", line_no) - return {}, false - } - if !is_oct_digit(rx_spec[0]) { - fmt.eprintfln("Line %d: Opcode RX needs to be an octal digit", line_no) - return {}, false - } - encoding_kind = .Rx_Extend - } - idx += 1 - // Parse mod/rm specification - if idx < len(fields) && fields[idx][0] == '/' { - rx_spec = fields[idx][1:] - if encoding_kind != .None { - fmt.eprintfln("Line %d: Conflicting mod/rm behaviors", line_no) - return {}, false - } - if len(rx_spec) == 0 { - fmt.eprintfln("Line %d: Expected register type or digit after mod/rm specification", line_no) - return {}, false - } - if len(rx_spec) == 1 && is_oct_digit(rx_spec[0]) { - fmt.eprintfln("Line %d: Opcode RX needs to be adjacent to opcode", line_no) - return {}, false - } - encoding_kind = .Mod_Rm - idx += 1 - } - // Parse extra operand - eop := "" - if idx < len(fields) && fields[idx][0] != '+' { - eop = fields[idx] - idx += 1 - } - // Parse flags - flags := make(map[string]string) - for field in fields[idx:] { - if field[0] != '+' { - fmt.eprintfln("Line %d: Flags are expected to start with '+' (%s is not a valid flag)", line_no, field) - return {}, false - } - eq_pos := strings.index_byte(field, '=') - if eq_pos != -1 { - name := field[1:eq_pos] - value := field[eq_pos+1:] - if len(name) == 0 { - fmt.eprintfln("Line %d: Flags must have a name (%s)", line_no, field) - return {}, false - } - if len(value) == 0 { - fmt.eprintfln("Line %d: Expected flag value (%s)", line_no, field) - return {}, false - } - flags[name] = value - } else { - name := field[1:] - if len(name) == 0 { - fmt.eprintfln("Line %d: Flags must have a name (%s)", line_no, field) - return {}, false - } - flags[name] = name - } - } - entry := Marked_Entry { - line_no = line_no, - mnemonic = mnemonic, - opcode = opcode, - opcode_rx = opcode_rx, - encoding_kind = encoding_kind, - rx_spec = rx_spec, - eop = eop, - flags = flags, - } - return entry, true -} diff --git a/src/table/multistage.odin b/src/table/multistage.odin index 78b7449..ac53977 100644 --- a/src/table/multistage.odin +++ b/src/table/multistage.odin @@ -1,6 +1,5 @@ package table - Stage1_Encoding :: struct { mnemonic: string, kind: Encoding_Kind, @@ -45,14 +44,17 @@ mt_mnemonic :: proc(mt: ^Multistage_Tables, mnemonic: string) -> int { return mt.mnemonic_table[mnemonic] } +@(private="file") mt_add_s1 :: proc(mt: ^Multistage_Tables, opcode: u8) -> ^Stage1_Encoding { return &mt.s1_table[opcode] } +@(private="file") s1_present :: proc(s1: ^Stage1_Encoding) -> bool { return s1.entry_idx != 0 } +@(private="file") mt_ensure_s2 :: proc(mt: ^Multistage_Tables, entry: Entry) -> (^Stage2_Encoding, int) { find_encoding := Stage2_Encoding { flags = entry.flags, @@ -71,14 +73,13 @@ mt_ensure_s2 :: proc(mt: ^Multistage_Tables, entry: Entry) -> (^Stage2_Encoding, return &mt.s2_table[idx], idx } +@(private="file") mt_add_rx_ext :: proc(mt: ^Multistage_Tables) -> ([]RX_Ext_Encoding, int) { idx := len(mt.rx_table) append(&mt.rx_table, [8]RX_Ext_Encoding {}) return mt.rx_table[idx][:], idx } -import "core:fmt" - mt_add :: proc(mt: ^Multistage_Tables, entry: Entry) { mnemonic_idx := mt_mnemonic(mt, entry.mnemonic) stage2, stage2_idx := mt_ensure_s2(mt, entry) diff --git a/src/table/parser.odin b/src/table/parser.odin index 795d744..5cf7f3a 100644 --- a/src/table/parser.odin +++ b/src/table/parser.odin @@ -5,6 +5,21 @@ import "core:strconv" import "core:fmt" import "core:os" +@(private) +is_oct_digit :: proc(d: u8) -> bool { + return '0' <= d && d <= '7' +} + +@(private) +is_digit :: proc(d: u8) -> bool { + return '0' <= d && d <= '9' +} + +@(private) +from_digit :: proc(d: u8) -> u8 { + return d - '0' +} + @(private) parse_byte :: proc(line_no: int, byte_str: string) -> (u8, bool) { if len(byte_str) != 2 { @@ -110,7 +125,124 @@ parse_eop_kind :: proc(line_no: int, eop_kind: string) -> (EOP_Kind, bool) { } @(private) -parse_marked_entry :: proc(m: Marked_Entry) -> (entries: [dynamic]Entry, ok: bool) { +Entry_Fields :: struct { + line_no: int, + mnemonic: string, + opcode: string, + encoding_kind: Encoding_Kind, + opcode_rx: bool, + rx_spec: string, + eop: string, + flags: map[string]string, +} + +@(private) +parse_entry_fields :: proc(line_no: int, fields: []string) -> (Entry_Fields, bool) { + // Parse mnemonic + idx := 0 + if idx >= len(fields) { + fmt.eprintfln("Line %d: Expected mnemonic", line_no) + return {}, false + } + mnemonic := fields[idx] + idx += 1 + // Parse opcode byte + opcode := fields[idx] + encoding_kind := Encoding_Kind.None + opcode_rx := false + if opcode[len(opcode)-1] == '+' { + opcode_rx = true + opcode = opcode[0:len(opcode)-1] + encoding_kind = .Rx_Embed + } + rx_spec := "" + opcode_slash := strings.index_byte(opcode, '/') + if opcode_slash != -1 { + rx_spec = opcode[opcode_slash+1:] + opcode = opcode[0:opcode_slash] + if encoding_kind != .None { + fmt.eprintfln("Line %d: Cannot specify RX extend and RX embed in the same opcode", line_no) + return {}, false + } + if len(rx_spec) != 1 { + fmt.eprintfln("Line %d: Opcode RX needs to be one character in length", line_no) + return {}, false + } + if !is_oct_digit(rx_spec[0]) { + fmt.eprintfln("Line %d: Opcode RX needs to be an octal digit", line_no) + return {}, false + } + encoding_kind = .Rx_Extend + } + idx += 1 + // Parse mod/rm specification + if idx < len(fields) && fields[idx][0] == '/' { + rx_spec = fields[idx][1:] + if encoding_kind != .None { + fmt.eprintfln("Line %d: Conflicting mod/rm behaviors", line_no) + return {}, false + } + if len(rx_spec) == 0 { + fmt.eprintfln("Line %d: Expected register type or digit after mod/rm specification", line_no) + return {}, false + } + if len(rx_spec) == 1 && is_oct_digit(rx_spec[0]) { + fmt.eprintfln("Line %d: Opcode RX needs to be adjacent to opcode", line_no) + return {}, false + } + encoding_kind = .Mod_Rm + idx += 1 + } + // Parse extra operand + eop := "" + if idx < len(fields) && fields[idx][0] != '+' { + eop = fields[idx] + idx += 1 + } + // Parse flags + flags := make(map[string]string) + for field in fields[idx:] { + if field[0] != '+' { + fmt.eprintfln("Line %d: Flags are expected to start with '+' (%s is not a valid flag)", line_no, field) + return {}, false + } + eq_pos := strings.index_byte(field, '=') + if eq_pos != -1 { + name := field[1:eq_pos] + value := field[eq_pos+1:] + if len(name) == 0 { + fmt.eprintfln("Line %d: Flags must have a name (%s)", line_no, field) + return {}, false + } + if len(value) == 0 { + fmt.eprintfln("Line %d: Expected flag value (%s)", line_no, field) + return {}, false + } + flags[name] = value + } else { + name := field[1:] + if len(name) == 0 { + fmt.eprintfln("Line %d: Flags must have a name (%s)", line_no, field) + return {}, false + } + flags[name] = name + } + } + entry := Entry_Fields { + line_no = line_no, + mnemonic = mnemonic, + opcode = opcode, + opcode_rx = opcode_rx, + encoding_kind = encoding_kind, + rx_spec = rx_spec, + eop = eop, + flags = flags, + } + return entry, true +} + +@(private) +entries_from_fields :: proc(m: Entry_Fields) -> (entries: [dynamic]Entry, ok: bool) { rx_kind := RX_Kind.None rm_kind := RM_Kind.None rx_value := REG_NONE @@ -170,11 +302,11 @@ parse :: proc(table: string) -> []Entry { if len(line) == 0 || line[0] == '#' { continue } - marked_entry, m_ok := mark_fields(line_no, strings.fields(line)) + marked_entry, m_ok := parse_entry_fields(line_no, strings.fields(line)) if !m_ok { os.exit(1) } - table_entries, t_ok := parse_marked_entry(marked_entry) + table_entries, t_ok := entries_from_fields(marked_entry) if !t_ok { os.exit(1) }