Skip to content

Commit

Permalink
Refactor table parser
Browse files Browse the repository at this point in the history
  • Loading branch information
flysand7 committed Oct 11, 2024
1 parent 5d03dc0 commit c72b65a
Show file tree
Hide file tree
Showing 4 changed files with 139 additions and 143 deletions.
15 changes: 0 additions & 15 deletions src/table/ascii_util.odin

This file was deleted.

122 changes: 0 additions & 122 deletions src/table/markup.odin

This file was deleted.

7 changes: 4 additions & 3 deletions src/table/multistage.odin
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package table


Stage1_Encoding :: struct {
mnemonic: string,
kind: Encoding_Kind,
Expand Down Expand Up @@ -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,
Expand All @@ -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)
Expand Down
138 changes: 135 additions & 3 deletions src/table/parser.odin
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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)
}
Expand Down

0 comments on commit c72b65a

Please sign in to comment.