Noting- for relative newcomers to the industry- that VM in this case has the classical interpreter/JIT meaning, rather than some sort of containerisation.
Well done. You might find investigating Meta-2 and possibly Tree Meta rewarding for the compiler part.
Meta-2 will parse an input program and directly emit assembler-like mnemonics, so is an easy fit for what you've got. There's multiple implementations floating around, the best thing is usually to use one of these as a reference implementation and redo in the language etc. of your choice.
Tree Meta builds on that to parse the input into a tree in memory, which is then "unparsed" to (e.g.) your mnemonics. The notable part is that it also includes ways that the tree can be optimised by rules in the language description. Implementation information is fragmentary, there's multiple people scraping around trying to find stuff but some was lost (together with the rest of somebody's home and belongings) in one of the California fires.
Otherwise there's plenty of other compiler-writing toolkits, but I find the above easy to understand and they work for me.
MarkMLl