PageRenderTime 53ms CodeModel.GetById 32ms RepoModel.GetById 0ms app.codeStats 0ms

/libtvm/tvm_program.c

https://github.com/wujiangthu/tinyvm
C | 254 lines | 182 code | 59 blank | 13 comment | 40 complexity | e8440f1a28a921991db72a8d90483559 MD5 | raw file
  1. #include <tvm/tvm_file.h>
  2. #include <tvm/tvm_program.h>
  3. #include <tvm/tvm_lexer.h>
  4. const char* tvm_opcode_map[] = {"nop", "int", "mov", "push", "pop", "pushf", "popf", "inc", "dec", "add", "sub", "mul", "div", "mod", "rem",
  5. "not", "xor", "or", "and", "shl", "shr", "cmp", "jmp", "call", "ret", "je", "jne", "jg", "jge", "jl", "jle", "prn", 0};
  6. const char* tvm_register_map[] = {"eax", "ebx", "ecx", "edx", "esi", "edi", "esp", "ebp", "eip", "r08", "r09", "r10", "r11", "r12", "r13", "r14", "r15", 0};
  7. static int parse_labels(tvm_program_t* p, const char*** tokens);
  8. static void parse_instruction(tvm_program_t* p, const char** tokens, tvm_memory_t* pMemory);
  9. static int* token_to_register(const char* token, tvm_memory_t* pMemory);
  10. static int instr_to_opcode(const char* instr);
  11. tvm_program_t* create_program()
  12. {
  13. tvm_program_t* p = (tvm_program_t*)calloc(1, sizeof(tvm_program_t));
  14. p->label_htab = create_htab();
  15. return p;
  16. }
  17. int interpret_program(tvm_program_t* p, char* filename, tvm_memory_t* pMemory)
  18. {
  19. int i;
  20. FILE* pFile = NULL;
  21. int source_length = 0;
  22. char* source = NULL;
  23. tvm_lexer_t* lexer = NULL;
  24. /* Attempt to open the file. If the file cannot be opened, try once more. */
  25. if(filename)
  26. for(i = 0; i < 2; i++)
  27. if(!pFile) pFile = tvm_fopen(filename, ".vm", "r");
  28. if(!pFile)
  29. {
  30. printf("File was not found, or does not exist. Unable to interpret.\n");
  31. return 1;
  32. }
  33. source_length = tvm_flength(pFile);
  34. source = malloc(source_length);
  35. tvm_fcopy(source, source_length, pFile);
  36. lexer = lexer_create();
  37. lex(lexer, source);
  38. free(source);
  39. fclose(pFile);
  40. if(parse_labels(p, (const char***)lexer->tokens) != 0)
  41. return 1;
  42. for(i = 0; lexer->tokens[i]; i++)
  43. {
  44. p->instr = (int*)realloc(p->instr, sizeof(int) * (i + 2));
  45. p->instr[i] = 0;
  46. p->args = (int***)realloc(p->args, sizeof(int**) * (i + 2));
  47. p->args[i] = (int**)calloc(MAX_ARGS, sizeof(int*));
  48. parse_instruction(p, (const char**)lexer->tokens[i], pMemory);
  49. }
  50. lexer_destroy(lexer);
  51. p->args[i] = NULL;
  52. p->instr[i] = -0x1;
  53. return 0;
  54. }
  55. void destroy_program(tvm_program_t* p)
  56. {
  57. int i = 0;
  58. destroy_htab(p->label_htab);
  59. for(i = 0; i < p->num_values; i++) free(p->values[i]);
  60. free(p->values);
  61. for(i = 0; p->args[i]; i++) free(p->args[i]);
  62. free(p->args);
  63. free(p->instr);
  64. free(p);
  65. }
  66. int parse_labels(tvm_program_t* p, const char*** tokens)
  67. {
  68. int i, num_instructions = 0;
  69. for(i = 0; tokens[i]; i++)
  70. {
  71. int token_idx, valid_instruction = 0;
  72. for(token_idx = 0; token_idx < MAX_TOKENS; token_idx++)
  73. {
  74. char* label_delimiter;
  75. /* If the token is empty, or non-existent, skip it */
  76. if(!tokens[i][token_idx]) continue;
  77. /* Figure out if the source line we're on contains a valid instruction */
  78. if(instr_to_opcode(tokens[i][token_idx]) != -1) valid_instruction = 1;
  79. /* Figure out if the token we're dealing with has a label delimiter */
  80. label_delimiter = strchr(tokens[i][token_idx], ':');
  81. if(label_delimiter != NULL)
  82. {
  83. *label_delimiter = 0;
  84. /* If the label is "start," set the program to begin there */
  85. if(strcmp(tokens[i][token_idx], "start") == 0) p->start = num_instructions;
  86. /* Check if the label already exists */
  87. if(htab_find(p->label_htab, tokens[i][token_idx]) != -1)
  88. {
  89. printf("Label '%s' defined twice\n", tokens[i][token_idx]);
  90. return 1;
  91. }
  92. else
  93. {
  94. /* Add that fucker to the hash table with the corresponding instruction index */
  95. htab_add(p->label_htab, tokens[i][token_idx], num_instructions);
  96. }
  97. continue;
  98. }
  99. }
  100. if(valid_instruction) num_instructions++;
  101. }
  102. return 0;
  103. }
  104. void parse_instruction(tvm_program_t* p, const char** tokens, tvm_memory_t* pMemory)
  105. {
  106. int token_idx;
  107. for(token_idx = 0; token_idx < MAX_TOKENS; token_idx++)
  108. {
  109. int opcode = 0;
  110. /* Skip empty tokens */
  111. if(!tokens[token_idx]) continue;
  112. opcode = instr_to_opcode(tokens[token_idx]);
  113. /* If it *is* an opcode, parse the arguments */
  114. if(opcode != -1)
  115. {
  116. int i, instr_idx = 0, num_instr = p->num_instructions;
  117. p->instr[p->num_instructions++] = opcode;
  118. for(i = ++token_idx; i < (token_idx + 2); ++i)
  119. {
  120. char* newline;
  121. if(!tokens[i] || strlen(tokens[i]) <= 0) continue;
  122. newline = strchr(tokens[i], '\n');
  123. if(newline) *newline = 0;
  124. /* Check to see if the token specifies a register */
  125. int* pRegister = token_to_register(tokens[i], pMemory);
  126. if(pRegister)
  127. {
  128. p->args[num_instr][i - token_idx] = pRegister;
  129. continue;
  130. }
  131. /* Check to see whether the token specifies an address */
  132. if(tokens[i][0] == '[')
  133. {
  134. char* end_symbol = strchr(tokens[i], ']');
  135. if(end_symbol)
  136. {
  137. *end_symbol = 0;
  138. p->args[num_instr][i - token_idx] = &((int*)pMemory->mem_space)[tvm_parse_value(tokens[i] + 1)];
  139. continue;
  140. }
  141. }
  142. /* Check if the argument is a label */
  143. instr_idx = htab_find(p->label_htab, tokens[i]);
  144. if(instr_idx >= 0)
  145. {
  146. p->args[num_instr][i - token_idx] = tvm_add_value(p, instr_idx);
  147. continue;
  148. }
  149. /* Fuck it, parse it as a value */
  150. p->args[num_instr][i - token_idx] = tvm_add_value(p, tvm_parse_value(tokens[i]));
  151. }
  152. }
  153. }
  154. }
  155. int* token_to_register(const char* token, tvm_memory_t* pMemory)
  156. {
  157. int i = 0;
  158. while(tvm_register_map[i])
  159. {
  160. if(strcmp(token, tvm_register_map[i]) == 0)
  161. return &pMemory->registers[i].i32;
  162. i++;
  163. }
  164. return NULL;
  165. }
  166. int instr_to_opcode(const char* instr)
  167. {
  168. int i;
  169. for(i = 0; tvm_opcode_map[i]; i++)
  170. if(strcmp(instr, tvm_opcode_map[i]) == 0)
  171. return i;
  172. return -1;
  173. }
  174. int* tvm_add_value(tvm_program_t* p, const int val)
  175. {
  176. p->values = realloc(p->values, sizeof(int*) * (p->num_values + 1));
  177. p->values[p->num_values] = (int*)calloc(1, sizeof(int));
  178. *p->values[p->num_values] = val;
  179. return p->values[p->num_values++];
  180. }
  181. int tvm_parse_value(const char* str)
  182. {
  183. char* delimiter = strchr(str, '|'), base = 0;
  184. if(delimiter)
  185. {
  186. char* identifier = delimiter + 1;
  187. switch(*identifier)
  188. {
  189. case 'h': base = 16; break;
  190. case 'b': base = 2; break;
  191. default: base = 0; break;
  192. }
  193. }
  194. return strtoul(str, NULL, base);
  195. }