I've created simple virtual machine, and for creating instructions bytes and switch I use c++ macros, it looks like this (thats simplified example):
typedef t_sint_b32 int;
typedef t_sint_b16 short;
(...)
typedef t_sfloat_b32 float;
enum InstructionOpSize{b8,b16,b32,b64};
enum InstructionOpSign{s, u};
enum InstructionOpType{int_, float_};
enum InstructionFunc{MOV, ADD, SUB, ...};
#define CreateInstruction(size1, sign1, type1, size2, ...) ((size1) | (sign1 << 3) | (type1 << 4) | .开发者_如何学Go..)
#define CASE_INSTRUCTION(size1, sign1, type1, size2, ..., operation) case CreateInstruction(size1, sign1, type1, size2, ...): ((t_##sign1##type1##size1) ARG1) operation ((t_##sign2##type2##size2) ARG2); break;
#define MULTI_CASE(size1, sign1, type1, ...)\
CASE_INSTRUCTION(size1, sign1, type1, b8, u, int_,...);\
(...)
CASE_INSTRUCTION(size1, sign1, type1, b64, s, float_,...);
#define MULTI_MULTI_CASE(...)\
MULTI_CASE(b8, u, int_,..);\
(...)
MULTI_CASE(b64, s, float_,..);
And then there is huge switch:
switch(opcode){
MULTI_MULTI_CASE(ADD, +=);
MULTI_MULTI_CASE(SUB, -=);
MULTI_MULTI_CASE(MUL, *=);
(...)
}
How you can see there is lots of code generated with little effort (with only 10 types of variables - 8 ints and 2 floats - and 4 functions its 10*10*4 lines of code), but in future I'd like to move it to language not supporting macros (I'm thinking of c# or Java). Only idea I came up was to make code generator, which will be generating code to paste into vm code, but then code won't be readable and it will be hard to change sth and maintain. Maybe you have some great ideas to share? :)
One option is to move to an external macro processor (e.g. M4) and then make it part of your build process to produce the macro-expanded version before it is compiled. Basically you just move from the C preprocessor to an external preprocessor (e.g. M4).
Another alternative is to restructure the code by hand :)
精彩评论