#include #include #include #include #include // --- Definições Globais --- // Memória da máquina, igual à versão em Python int memory[256] = {0}; typedef enum { TOKEN_NUMBER, TOKEN_IDENTIFIER } TokenType; typedef struct { TokenType type; union { int number; char letter; } value; int line; int column; } Token; // Estrutura para uma única instrução (4 tokens) typedef struct { int tokens[4]; int line; } Instruction; // --- Funções Auxiliares --- // Converte um inteiro para uma string hexadecimal (para debug) // Em C, precisamos gerenciar o buffer de string manualmente. void to_hex_string(int val, char *hex_str, size_t size) { snprintf(hex_str, size, "%X", val); } // Analisa uma linha de código .redd e a converte em 4 inteiros. // Retorna 1 em caso de sucesso, 0 em caso de falha. int parse_line(char *line, int *instr_tokens) { // Remove comentários que começam com "//" char *comment = strstr(line, "//"); if (comment != NULL) { *comment = '\0'; // Termina a string no início do comentário } // Usa strtok para dividir a string pelo delimitador ";" // strtok é "destrutivo", ele modifica a string original. char *token = strtok(line, ";"); int i = 0; while (token != NULL && i < 4) { // strtol converte string para long, aqui usado para hex (base 16) instr_tokens[i] = (int)strtol(token, NULL, 16); token = strtok(NULL, ";"); i++; } // Se não tivermos exatamente 4 tokens, a linha é inválida if (i != 4) { // Ignora linhas vazias ou com erro de formatação if (i > 0) printf("[ERRO] Linha inválida (esperado 4 valores): %s\n", line); return 0; // Falha } return 1; // Sucesso } // --- Lógica de Execução --- void run_program(Instruction *program, int num_instructions, int debug) { int pc = 0; // Program Counter (Contador de Programa) while (pc < num_instructions) { Instruction instr = program[pc]; int cmd = instr.tokens[0]; if (debug) { char hex_instr[50]; char mem_preview[100]; // Monta a string de debug para a instrução snprintf(hex_instr, sizeof(hex_instr), "%X;%X;%X;%X", instr.tokens[0], instr.tokens[1], instr.tokens[2], instr.tokens[3]); // Monta a string de debug para a memória mem_preview[0] = '\0'; for(int i = 0; i < 16; i++) { char hex_val[4]; to_hex_string(memory[i], hex_val, sizeof(hex_val)); strcat(mem_preview, hex_val); strcat(mem_preview, " "); } printf("[DEBUG] PC=%02X, CMD=%s, MEM[0..F]=%s\n", pc + 1, hex_instr, mem_preview); } // Usa um switch-case, que é mais eficiente e idiomático em C do que if-else if. switch (cmd) { case 0: // HALT printf("[INFO] Programa finalizado.\n"); return; case 1: { // INPUT int a = instr.tokens[1]; int b = instr.tokens[2]; if (b != 0) { memory[a] = b; } else { printf("[INFO] Waiting for input...\n"); char value_str[10]; printf("Digite valor HEX para mem[%X]: ", a); scanf("%s", value_str); memory[a] = (int)strtol(value_str, NULL, 16); } break; } case 2: // OUTPUT printf("%X\n", memory[instr.tokens[1]]); break; case 3: // ADD memory[instr.tokens[3]] = memory[instr.tokens[1]] + memory[instr.tokens[2]]; break; case 4: // SUB memory[instr.tokens[3]] = memory[instr.tokens[1]] - memory[instr.tokens[2]]; break; case 5: // DIV if (memory[instr.tokens[2]] != 0) { memory[instr.tokens[3]] = memory[instr.tokens[1]] / memory[instr.tokens[2]]; } else { memory[instr.tokens[3]] = 0; } break; case 6: // MUL memory[instr.tokens[3]] = memory[instr.tokens[1]] * memory[instr.tokens[2]]; break; case 7: // COND JUMP if (memory[instr.tokens[1]] == instr.tokens[2]) { pc = instr.tokens[3] - 1; // -1 para compensar o pc++ no final do loop continue; } break; case 8: // JUMP pc = instr.tokens[1] - 1; // -1 para compensar o pc++ continue; case 9: // CLEAR memory[instr.tokens[1]] = 0; break; case 0xA: // RANDOM srand(time(NULL)); // Semente para o gerador de números aleatórios memory[instr.tokens[1]] = rand() % 16; break; case 0xB: // CMP GREATER memory[instr.tokens[3]] = (memory[instr.tokens[1]] > memory[instr.tokens[2]]) ? 1 : 0; break; case 0xC: // CMP LESS memory[instr.tokens[3]] = (memory[instr.tokens[1]] < memory[instr.tokens[2]]) ? 1 : 0; break; case 0xD: // MOVE memory[instr.tokens[2]] = memory[instr.tokens[1]]; break; case 0xE: // INC/DEC if (instr.tokens[2] == 1) memory[instr.tokens[1]]++; else if (instr.tokens[2] == 0) memory[instr.tokens[1]]--; else printf("[ERROR]: Invalid flag: %X\n", instr.tokens[2]); break; case 0xF: // WAIT printf("[INFO]: Waiting %d seconds...\n", instr.tokens[1]); sleep(instr.tokens[1]); // Em C, sleep está em (geralmente) break; default: printf( "CommandNotFoundError: opcode %X not found\n" " --> line %d\n", cmd, instr.line ); return; } pc++; } } // --- Função Principal --- int main(int argc, char *argv[]) { if (argc < 2) { printf("Uso: %s [--debug]\n", argv[0]); return 1; } // Checa por argumentos, como --version ou --debug if (strcmp(argv[1], "--version") == 0) { printf("RedDust Interpreter v3.1 (C-Version)\n"); return 0; } int debug = 0; if (argc > 2 && strcmp(argv[2], "--debug") == 0) { debug = 1; } // --- Leitura do Arquivo --- char *filename = argv[1]; if (!strstr(filename, ".redd")) { printf("[ERRO] Arquivo deve ter extensão .redd\n"); return 1; } FILE *file = fopen(filename, "r"); if (file == NULL) { printf("[ERRO] Arquivo '%s' não encontrado.\n", filename); return 1; } // Aloca memória para o programa. Começamos com espaço para 100 instruções. // Em C, precisamos gerenciar o tamanho do array dinamicamente se não soubermos o tamanho. int max_instr = 100; Instruction *program = malloc(max_instr * sizeof(Instruction)); if (program == NULL) { printf("[ERRO] Falha ao alocar memória para o programa.\n"); return 1; } char line[100]; int num_instructions = 0; int line_number = 1; while (fgets(line, sizeof(line), file)) { if (num_instructions >= max_instr) { max_instr *= 2; Instruction *new_program = realloc(program, max_instr * sizeof(Instruction)); if (new_program == NULL) { printf("[ERRO] Falha ao realocar memória para o programa.\n"); free(program); return 1; } program = new_program; } if (parse_line(line, program[num_instructions].tokens)) { program[num_instructions].line = line_number; num_instructions++; } line_number++; }; fclose(file); // --- Execução --- run_program(program, num_instructions, debug); // Libera a memória que foi alocada dinamicamente free(program); return 0; }