So, musings on how assembly can be represented . . .
For x86 and x86-64 assembly, intel format (I am personally most familliar with
intel assembly), an instruction consists of an opcode and a series of
operands, like so:
mov rax, 0xff00
^ ^ ^
| \---v---/
opcode operands
In x86 assembly, an operand can have a maximum of three operands -- two
registers and one constant, to be exact. In other words, a std::vector<> of
operands should do nicely.
Operands are one of four things: a register, a constant, a dereferenced
constant, or a dereferenced offset from a register. Think of it this way:
mov rax, 0xff00
Consists of a register and a constant. The instruction:
mov rax, [rbp-16]
Consists of a register and a dereferenced register offset.
Therefore, an operand can be represented as a single class, with an enum
describing what type it is.
The tricky part here is representing the opcodes. For example, the mov
instruction in x86_64 isn't just "mov", it can be "movzx", "movzx", "movq",
"movsx", and more, all representing slightly different versions of the basic
command to move a value from one place to another.
So . . . what if it was represented as a tree of sorts? "Instructions/Memory
Operations/Move/With Sign-Extension" for "movsx"?
Something to think on, anyhow.