Chris said:
I have been looking for examples and illustrations on how to do this with no
luck. I have developed a set of grammer using bison/flex which basically
permits me to interpret my language when calling yyparse().
What I am trying to grasp and understand is once I have the grammer down to
where the parser doesn't complain and accepts the syntax as it is to be
understood, what are the next steps in moving toward generating a simple
instruction-based bytecode file that can be interpreted within a host VM?
Obviously creating the file
Seriously. You start with defining what your VM looks like. What instructions
or understood by your VM (what action has to be performed on what code,
the OpCodes).
Example: You write an expression parser. For simplicity I often define
the VM to be a stack machine, thus I don't have to deal with register
allocation on the compiler. This expression parser deals with addition
only, no variables, numbers are integers with 2 bytes each, high byte first
Your VM eg. then could interpret the opcodes (all numbers are hex)
01 push the number following the OpCode on the stack
02 add 2 numbers from the stack and push the result on the stack
03 display the topmost number from the stack
when your compiler sees the statement
2 + 5
it generates the opcode sequence
01 00 02 01 00 05 02 03
That would be the machine code for the above 'program' for your particular VM.
In 'assembler' syntax this would read
address opcode memnonic
**********************************
0000 01 00 02 push 2
0003 01 00 05 push 5
0006 02 add
0007 03 display_tos
Now comes the time that you want your compiler to understand subtraction. You need
to upgrade your VM to. But here you have two choices. You can either introduce
a negate operation in your VM or a subtract operation (You will want to introduce
both, but this is your choice). Lets say you have a negate operation.
04 negate top of stack
the sequence
2 - 5
then translates to:
01 00 02 01 00 05 04 02 03
or in assembler
0000 01 00 02 push 2
0003 01 00 05 push 5
0006 04 negate_tos
0007 02 add
0008 03 display_tos
But if you have a subtract operation:
05 subtract 2 numbers from the stack and push the result on the stack
the whole thing could be translated to
01 00 02 01 00 05 05 03
0000 01 00 02 push 2
0003 01 00 05 push 5
0006 05 subtract
0007 03 display_tos
Continuing with this, you will want to add multiplication, division, etc.
Depending on how mighty you want your VM to be, you will also want to add
jump instructions, call instructions, comparisons, conditonal jumps, increment,
decrement operations. Whatever you want. If your VM includes an opcode for
creating a window, well, so be it. You are the designer, you design your own
CPU (at least at the logical level
.