From addd54dc31603dc204773d3108dba4e000cd7657 Mon Sep 17 00:00:00 2001
From: A404M <ahmadmahmoudiprogrammer@gmail.com>
Date: Tue, 8 Oct 2024 04:16:27 +0330
Subject: added fasm support added compiler options tried to compile to fasm
 first

---
 src/fasm/linker/linker.c | 870 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 870 insertions(+)
 create mode 100644 src/fasm/linker/linker.c

(limited to 'src/fasm/linker/linker.c')

diff --git a/src/fasm/linker/linker.c b/src/fasm/linker/linker.c
new file mode 100644
index 0000000..faa3cd8
--- /dev/null
+++ b/src/fasm/linker/linker.c
@@ -0,0 +1,870 @@
+#include "linker.h"
+
+#include <compiler/error_helper/error_helper.h>
+#include <compiler/source_code/source_code.h>
+#include <fasm/lexer/lexer.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <utils/memory/memory.h>
+
+void fasmVariablePrint(FasmVariable variable) {
+  printf(" {name='%.*s',value=0x%ld}\n", (int)(variable.end - variable.begin),
+         variable.begin, variable.value);
+}
+
+void fasmLinkedLinePrint(FasmLinkedLine line) {
+  printf(" {instruction='%s',operands=[\n",
+         FASM_TOKEN_STRINGS[line.instruction]);
+  for (size_t i = 0; i < line.operands_size; ++i) {
+    printf("  0x%x,\n", line.operands[i]);
+  }
+  printf(" ]}\n");
+}
+
+void fasmLinkedLinesPrint(FasmLinkedLines lines) {
+  printf("{lines=[\n");
+  for (size_t i = 0; i < lines.lines_size; ++i) {
+    fasmLinkedLinePrint(lines.lines[i]);
+  }
+  printf("],\ndata=[\n");
+  for (size_t i = 0; i < lines.data_size; ++i) {
+    printf(" 0x%.2x,\n", lines.data[i]);
+  }
+  printf("],\nvariable=[\n");
+  for (size_t i = 0; i < lines.variables_size; ++i) {
+    fasmVariablePrint(lines.variables[i]);
+  }
+  printf("]}\n");
+}
+
+void fasmLinkedLineDeleteInner(FasmLinkedLine line) { free(line.operands); }
+
+void fasmLinkedLinesDeleteInner(FasmLinkedLines lines) {
+  for (size_t i = 0; i < lines.lines_size; ++i) {
+    fasmLinkedLineDeleteInner(lines.lines[i]);
+  }
+  free(lines.lines);
+  free(lines.variables);
+  free(lines.data);
+}
+
+FasmLinkedLines fasmLinker(const FasmLines *lines, SourceCode *sourceCode) {
+  FasmLinkedLines linkedLines = {
+      .lines = a404m_malloc(0),
+      .lines_size = 0,
+      .variables = a404m_malloc(0),
+      .variables_size = 0,
+      .data = a404m_malloc(0),
+      .data_size = 0,
+  };
+
+  fasmLinesSetVariables(&linkedLines, lines, sourceCode);
+  fasmLinesSetLines(&linkedLines, lines, sourceCode);
+  fasmLinesSetData(&linkedLines, lines, sourceCode);
+
+  return linkedLines;
+
+  // RETURN_ERROR:
+  const FasmLinkedLines ERROR = {
+      .lines = NULL,
+      .lines_size = ERROR_SIZE,
+      .variables = NULL,
+      .variables_size = ERROR_SIZE,
+      .data = NULL,
+      .data_size = ERROR_SIZE,
+  };
+
+  return ERROR;
+}
+
+void fasmLinesSetVariables(FasmLinkedLines *linkedLines, const FasmLines *lines,
+                           SourceCode *sourceCode) {
+  size_t inserted = 0;
+
+  for (size_t i = 0; i < sourceCode->size; ++i) {
+    const FasmLines linesHolder = lines[i];
+    for (size_t j = 0; j < linesHolder.lines_size; ++j) {
+      const FasmLine line = lines->lines[j];
+      if (line.labelBegin != line.labelEnd) {
+        const FasmVariable variable = {
+            .begin = line.labelBegin,
+            .end = line.labelEnd,
+            .value = inserted,
+        };
+        fasmLinesPushVariable(linkedLines, variable);
+      }
+      inserted += getSizeOfLine(line);
+    }
+  }
+
+  inserted = 0;
+
+  for (size_t i = 0; i < sourceCode->size; ++i) {
+    const FasmLines linesHolder = lines[i];
+    for (size_t j = 0; j < linesHolder.data_size; ++j) {
+      const FasmLine line = lines->data[j];
+      if (line.labelBegin != line.labelEnd) {
+        const FasmVariable variable = {
+            .begin = line.labelBegin,
+            .end = line.labelEnd,
+            .value = inserted,
+        };
+        fasmLinesPushVariable(linkedLines, variable);
+      }
+      inserted += getSizeOfLine(line);
+    }
+  }
+}
+
+void fasmLinesSetLines(FasmLinkedLines *linkedLines, const FasmLines *lines,
+                       SourceCode *sourceCode) {
+  for (size_t i = 0; i < sourceCode->size; ++i) {
+    const FasmLines linesHolder = lines[i];
+    for (size_t j = 0; j < linesHolder.lines_size; ++j) {
+      const FasmLine line = lines->lines[j];
+      fasmLinesPushLine(linkedLines,
+                        fasmLinesParseLine(linkedLines, line, sourceCode));
+    }
+  }
+}
+
+extern void fasmLinesSetData(FasmLinkedLines *linkedLines,
+                             const FasmLines *lines, SourceCode *sourceCode) {
+  for (size_t i = 0; i < sourceCode->size; ++i) {
+    const FasmLines linesHolder = lines[i];
+    for (size_t j = 0; j < linesHolder.data_size; ++j) {
+      const FasmLine line = lines->data[j];
+      FasmLinkedLine linkedLine =
+          fasmLinesParseLine(linkedLines, line, sourceCode);
+      fasmLinesPushData(linkedLines, linkedLine.operands,
+                        linkedLine.operands_size);
+      fasmLinkedLineDeleteInner(linkedLine);
+    }
+  }
+}
+
+FasmLinkedLine fasmLinesParseLine(FasmLinkedLines *linkedLines, FasmLine line,
+                                  SourceCode *sourceCode) {
+  const FasmLinkedLine linkedLine = {
+      .begin = line.begin,
+      .end = line.end,
+      .instruction = line.instruction,
+      .operands = a404m_malloc(getSizeOfLineOperands(line)),
+      .operands_size = getSizeOfLineOperands(line),
+  };
+
+  const size_t elementSize = getSizeOfLineOperandElementSize(line);
+
+  size_t inserted = 0;
+
+  for (size_t i = 0; i < line.operands_size; ++i) {
+    const FasmOperand operand = line.operands[i];
+    if (isOperandString(operand)) {
+      for (char *iter = operand.begin + 1; iter + 1 < operand.end; ++iter) {
+        switch (elementSize) {
+          case 1:
+            ((uint8_t *)linkedLine.operands)[inserted] = *iter;
+            break;
+          case 2:
+            ((uint16_t *)linkedLine.operands)[inserted] = *iter;
+            break;
+          case 4:
+            ((uint32_t *)linkedLine.operands)[inserted] = *iter;
+            break;
+          case 8:
+            ((uint64_t *)linkedLine.operands)[inserted] = *iter;
+            break;
+        }
+        inserted += 1;
+      }
+    } else {
+      switch (elementSize) {
+        case 1:
+          ((uint8_t *)linkedLine.operands)[inserted] =
+              getOperandValue(linkedLines, operand, sourceCode);
+          break;
+        case 2:
+          ((uint16_t *)linkedLine.operands)[inserted] =
+              getOperandValue(linkedLines, operand, sourceCode);
+          break;
+        case 4:
+          ((uint32_t *)linkedLine.operands)[inserted] =
+              getOperandValue(linkedLines, operand, sourceCode);
+          break;
+        case 8:
+          ((uint64_t *)linkedLine.operands)[inserted] =
+              getOperandValue(linkedLines, operand, sourceCode);
+          break;
+      }
+      inserted += 1;
+    }
+  }
+
+  return linkedLine;
+}
+
+bool fasmLinkerOperandSizeCorrect(FasmToken token, int size) {
+  switch (token) {
+    case FASM_TOKEN_NOOP:
+      return size == 0;
+    case FASM_TOKEN_PUSH8:
+    case FASM_TOKEN_PUSH16:
+    case FASM_TOKEN_PUSH32:
+    case FASM_TOKEN_PUSH64:
+      return size == 1;
+    case FASM_TOKEN_LOAD8:
+    case FASM_TOKEN_LOAD16:
+    case FASM_TOKEN_LOAD32:
+    case FASM_TOKEN_LOAD64:
+    case FASM_TOKEN_POP8:
+    case FASM_TOKEN_POP16:
+    case FASM_TOKEN_POP32:
+    case FASM_TOKEN_POP64:
+    case FASM_TOKEN_DUP8:
+    case FASM_TOKEN_DUP16:
+    case FASM_TOKEN_DUP32:
+    case FASM_TOKEN_DUP64:
+    case FASM_TOKEN_SWAP8:
+    case FASM_TOKEN_SWAP16:
+    case FASM_TOKEN_SWAP32:
+    case FASM_TOKEN_SWAP64:
+    case FASM_TOKEN_DROP8:
+    case FASM_TOKEN_DROP16:
+    case FASM_TOKEN_DROP32:
+    case FASM_TOKEN_DROP64:
+    case FASM_TOKEN_ADD_I8:
+    case FASM_TOKEN_ADD_I16:
+    case FASM_TOKEN_ADD_I32:
+    case FASM_TOKEN_ADD_I64:
+    case FASM_TOKEN_ADD_F32:
+    case FASM_TOKEN_ADD_F64:
+    case FASM_TOKEN_SUB_I8:
+    case FASM_TOKEN_SUB_I16:
+    case FASM_TOKEN_SUB_I32:
+    case FASM_TOKEN_SUB_I64:
+    case FASM_TOKEN_SUB_F32:
+    case FASM_TOKEN_SUB_F64:
+    case FASM_TOKEN_NEG_I8:
+    case FASM_TOKEN_NEG_I16:
+    case FASM_TOKEN_NEG_I32:
+    case FASM_TOKEN_NEG_I64:
+    case FASM_TOKEN_NEG_F32:
+    case FASM_TOKEN_NEG_F64:
+    case FASM_TOKEN_MUL_I8:
+    case FASM_TOKEN_MUL_I16:
+    case FASM_TOKEN_MUL_I32:
+    case FASM_TOKEN_MUL_I64:
+    case FASM_TOKEN_MUL_U8:
+    case FASM_TOKEN_MUL_U16:
+    case FASM_TOKEN_MUL_U32:
+    case FASM_TOKEN_MUL_U64:
+    case FASM_TOKEN_MUL_F32:
+    case FASM_TOKEN_MUL_F64:
+    case FASM_TOKEN_DIV_I8:
+    case FASM_TOKEN_DIV_I16:
+    case FASM_TOKEN_DIV_I32:
+    case FASM_TOKEN_DIV_I64:
+    case FASM_TOKEN_DIV_U8:
+    case FASM_TOKEN_DIV_U16:
+    case FASM_TOKEN_DIV_U32:
+    case FASM_TOKEN_DIV_U64:
+    case FASM_TOKEN_DIV_F32:
+    case FASM_TOKEN_DIV_F64:
+    case FASM_TOKEN_REM_I8:
+    case FASM_TOKEN_REM_I16:
+    case FASM_TOKEN_REM_I32:
+    case FASM_TOKEN_REM_I64:
+    case FASM_TOKEN_REM_U8:
+    case FASM_TOKEN_REM_U16:
+    case FASM_TOKEN_REM_U32:
+    case FASM_TOKEN_REM_U64:
+    case FASM_TOKEN_CAST_I8_I64:
+    case FASM_TOKEN_CAST_I16_I64:
+    case FASM_TOKEN_CAST_I32_I64:
+    case FASM_TOKEN_CAST_I64_I8:
+    case FASM_TOKEN_CAST_I64_I16:
+    case FASM_TOKEN_CAST_I64_I32:
+    case FASM_TOKEN_CAST_F64_I64:
+    case FASM_TOKEN_CAST_I64_F64:
+    case FASM_TOKEN_CAST_U8_U64:
+    case FASM_TOKEN_CAST_U16_U64:
+    case FASM_TOKEN_CAST_U32_U64:
+    case FASM_TOKEN_CAST_U64_U8:
+    case FASM_TOKEN_CAST_U64_U16:
+    case FASM_TOKEN_CAST_U64_U32:
+    case FASM_TOKEN_CAST_F64_U64:
+    case FASM_TOKEN_CAST_U64_F64:
+    case FASM_TOKEN_CAST_F32_F64:
+    case FASM_TOKEN_CAST_F64_F32:
+    case FASM_TOKEN_JUMP:
+    case FASM_TOKEN_JZ_I8:
+    case FASM_TOKEN_JNZ_I8:
+    case FASM_TOKEN_JN_I8:
+    case FASM_TOKEN_JNN_I8:
+    case FASM_TOKEN_JP_I8:
+    case FASM_TOKEN_JNP_I8:
+    case FASM_TOKEN_JZ_I16:
+    case FASM_TOKEN_JNZ_I16:
+    case FASM_TOKEN_JN_I16:
+    case FASM_TOKEN_JNN_I16:
+    case FASM_TOKEN_JP_I16:
+    case FASM_TOKEN_JNP_I16:
+    case FASM_TOKEN_JZ_I32:
+    case FASM_TOKEN_JNZ_I32:
+    case FASM_TOKEN_JN_I32:
+    case FASM_TOKEN_JNN_I32:
+    case FASM_TOKEN_JP_I32:
+    case FASM_TOKEN_JNP_I32:
+    case FASM_TOKEN_JZ_I64:
+    case FASM_TOKEN_JNZ_I64:
+    case FASM_TOKEN_JN_I64:
+    case FASM_TOKEN_JNN_I64:
+    case FASM_TOKEN_JP_I64:
+    case FASM_TOKEN_JNP_I64:
+    case FASM_TOKEN_JZ_F32:
+    case FASM_TOKEN_JNZ_F32:
+    case FASM_TOKEN_JN_F32:
+    case FASM_TOKEN_JNN_F32:
+    case FASM_TOKEN_JP_F32:
+    case FASM_TOKEN_JNP_F32:
+    case FASM_TOKEN_JZ_F64:
+    case FASM_TOKEN_JNZ_F64:
+    case FASM_TOKEN_JN_F64:
+    case FASM_TOKEN_JNN_F64:
+    case FASM_TOKEN_JP_F64:
+    case FASM_TOKEN_JNP_F64:
+    case FASM_TOKEN_ALLOC_HEAP:
+    case FASM_TOKEN_ALLOC_STACK:
+    case FASM_TOKEN_FREE_HEAP:
+    case FASM_TOKEN_GET_STACK_ADDRESS:
+    case FASM_TOKEN_GET_GLOBAL_ADDRESS:
+    case FASM_TOKEN_CALL:
+    case FASM_TOKEN_RET:
+      return size == 0;
+    case FASM_TOKEN_SYSCALL:
+      return size == 1;
+    case FASM_TOKEN_DEFINE_BYTE:
+    case FASM_TOKEN_DEFINE_WORD:
+    case FASM_TOKEN_DEFINE_DWORD:
+    case FASM_TOKEN_DEFINE_QWORD:
+      return size > 1;
+    case FASM_TOKEN_NONE:
+      return false;
+  }
+  fprintf(stderr, "Bad fasm token '%d' at %s:%d", token, __FILE_NAME__,
+          __LINE__);
+  exit(1);
+}
+
+size_t getSizeOfLine(const FasmLine line) {
+  return sizeof(line.instruction) + getSizeOfLineOperands(line);
+}
+
+size_t getSizeOfLineOperands(const FasmLine line) {
+  switch (line.instruction) {
+    case FASM_TOKEN_PUSH8:
+      return 1;
+    case FASM_TOKEN_PUSH16:
+      return 2;
+    case FASM_TOKEN_PUSH32:
+      return 4;
+    case FASM_TOKEN_PUSH64:
+      return 8;
+    case FASM_TOKEN_LOAD8:
+    case FASM_TOKEN_LOAD16:
+    case FASM_TOKEN_LOAD32:
+    case FASM_TOKEN_LOAD64:
+    case FASM_TOKEN_POP8:
+    case FASM_TOKEN_POP16:
+    case FASM_TOKEN_POP32:
+    case FASM_TOKEN_POP64:
+    case FASM_TOKEN_DUP8:
+    case FASM_TOKEN_DUP16:
+    case FASM_TOKEN_DUP32:
+    case FASM_TOKEN_DUP64:
+    case FASM_TOKEN_SWAP8:
+    case FASM_TOKEN_SWAP16:
+    case FASM_TOKEN_SWAP32:
+    case FASM_TOKEN_SWAP64:
+    case FASM_TOKEN_DROP8:
+    case FASM_TOKEN_DROP16:
+    case FASM_TOKEN_DROP32:
+    case FASM_TOKEN_DROP64:
+    case FASM_TOKEN_ADD_I8:
+    case FASM_TOKEN_ADD_I16:
+    case FASM_TOKEN_ADD_I32:
+    case FASM_TOKEN_ADD_I64:
+    case FASM_TOKEN_ADD_F32:
+    case FASM_TOKEN_ADD_F64:
+    case FASM_TOKEN_SUB_I8:
+    case FASM_TOKEN_SUB_I16:
+    case FASM_TOKEN_SUB_I32:
+    case FASM_TOKEN_SUB_I64:
+    case FASM_TOKEN_SUB_F32:
+    case FASM_TOKEN_SUB_F64:
+    case FASM_TOKEN_NEG_I8:
+    case FASM_TOKEN_NEG_I16:
+    case FASM_TOKEN_NEG_I32:
+    case FASM_TOKEN_NEG_I64:
+    case FASM_TOKEN_NEG_F32:
+    case FASM_TOKEN_NEG_F64:
+    case FASM_TOKEN_MUL_I8:
+    case FASM_TOKEN_MUL_I16:
+    case FASM_TOKEN_MUL_I32:
+    case FASM_TOKEN_MUL_I64:
+    case FASM_TOKEN_MUL_U8:
+    case FASM_TOKEN_MUL_U16:
+    case FASM_TOKEN_MUL_U32:
+    case FASM_TOKEN_MUL_U64:
+    case FASM_TOKEN_MUL_F32:
+    case FASM_TOKEN_MUL_F64:
+    case FASM_TOKEN_DIV_I8:
+    case FASM_TOKEN_DIV_I16:
+    case FASM_TOKEN_DIV_I32:
+    case FASM_TOKEN_DIV_I64:
+    case FASM_TOKEN_DIV_U8:
+    case FASM_TOKEN_DIV_U16:
+    case FASM_TOKEN_DIV_U32:
+    case FASM_TOKEN_DIV_U64:
+    case FASM_TOKEN_DIV_F32:
+    case FASM_TOKEN_DIV_F64:
+    case FASM_TOKEN_REM_I8:
+    case FASM_TOKEN_REM_I16:
+    case FASM_TOKEN_REM_I32:
+    case FASM_TOKEN_REM_I64:
+    case FASM_TOKEN_REM_U8:
+    case FASM_TOKEN_REM_U16:
+    case FASM_TOKEN_REM_U32:
+    case FASM_TOKEN_REM_U64:
+    case FASM_TOKEN_CAST_I8_I64:
+    case FASM_TOKEN_CAST_I16_I64:
+    case FASM_TOKEN_CAST_I32_I64:
+    case FASM_TOKEN_CAST_I64_I8:
+    case FASM_TOKEN_CAST_I64_I16:
+    case FASM_TOKEN_CAST_I64_I32:
+    case FASM_TOKEN_CAST_F64_I64:
+    case FASM_TOKEN_CAST_I64_F64:
+    case FASM_TOKEN_CAST_U8_U64:
+    case FASM_TOKEN_CAST_U16_U64:
+    case FASM_TOKEN_CAST_U32_U64:
+    case FASM_TOKEN_CAST_U64_U8:
+    case FASM_TOKEN_CAST_U64_U16:
+    case FASM_TOKEN_CAST_U64_U32:
+    case FASM_TOKEN_CAST_F64_U64:
+    case FASM_TOKEN_CAST_U64_F64:
+    case FASM_TOKEN_CAST_F32_F64:
+    case FASM_TOKEN_CAST_F64_F32:
+    case FASM_TOKEN_JUMP:
+    case FASM_TOKEN_JZ_I8:
+    case FASM_TOKEN_JNZ_I8:
+    case FASM_TOKEN_JN_I8:
+    case FASM_TOKEN_JNN_I8:
+    case FASM_TOKEN_JP_I8:
+    case FASM_TOKEN_JNP_I8:
+    case FASM_TOKEN_JZ_I16:
+    case FASM_TOKEN_JNZ_I16:
+    case FASM_TOKEN_JN_I16:
+    case FASM_TOKEN_JNN_I16:
+    case FASM_TOKEN_JP_I16:
+    case FASM_TOKEN_JNP_I16:
+    case FASM_TOKEN_JZ_I32:
+    case FASM_TOKEN_JNZ_I32:
+    case FASM_TOKEN_JN_I32:
+    case FASM_TOKEN_JNN_I32:
+    case FASM_TOKEN_JP_I32:
+    case FASM_TOKEN_JNP_I32:
+    case FASM_TOKEN_JZ_I64:
+    case FASM_TOKEN_JNZ_I64:
+    case FASM_TOKEN_JN_I64:
+    case FASM_TOKEN_JNN_I64:
+    case FASM_TOKEN_JP_I64:
+    case FASM_TOKEN_JNP_I64:
+    case FASM_TOKEN_JZ_F32:
+    case FASM_TOKEN_JNZ_F32:
+    case FASM_TOKEN_JN_F32:
+    case FASM_TOKEN_JNN_F32:
+    case FASM_TOKEN_JP_F32:
+    case FASM_TOKEN_JNP_F32:
+    case FASM_TOKEN_JZ_F64:
+    case FASM_TOKEN_JNZ_F64:
+    case FASM_TOKEN_JN_F64:
+    case FASM_TOKEN_JNN_F64:
+    case FASM_TOKEN_JP_F64:
+    case FASM_TOKEN_JNP_F64:
+    case FASM_TOKEN_ALLOC_HEAP:
+    case FASM_TOKEN_ALLOC_STACK:
+    case FASM_TOKEN_FREE_HEAP:
+    case FASM_TOKEN_GET_STACK_ADDRESS:
+    case FASM_TOKEN_GET_GLOBAL_ADDRESS:
+    case FASM_TOKEN_CALL:
+    case FASM_TOKEN_RET:
+    case FASM_TOKEN_NOOP:
+    case FASM_TOKEN_SYSCALL:
+      return 0;
+    case FASM_TOKEN_DEFINE_BYTE:
+    case FASM_TOKEN_DEFINE_WORD:
+    case FASM_TOKEN_DEFINE_DWORD:
+    case FASM_TOKEN_DEFINE_QWORD: {
+      size_t elementSize;
+
+      switch (line.instruction) {
+        case FASM_TOKEN_DEFINE_BYTE:
+          elementSize = 1;
+          break;
+        case FASM_TOKEN_DEFINE_WORD:
+          elementSize = 2;
+          break;
+        case FASM_TOKEN_DEFINE_DWORD:
+          elementSize = 4;
+          break;
+        case FASM_TOKEN_DEFINE_QWORD:
+          elementSize = 8;
+          break;
+        default:
+      }
+
+      size_t size = 0;
+
+      for (size_t i = 0; i < line.operands_size; ++i) {
+        const FasmOperand operand = line.operands[i];
+        if (isOperandString(operand)) {
+          size += (operand.end - operand.begin - 2) * elementSize;
+        } else {
+          size += elementSize;
+        }
+      }
+
+      return size;
+    }
+    case FASM_TOKEN_NONE:
+  }
+  fprintf(stderr, "Bad fasm token '%d' at %s:%d", line.instruction,
+          __FILE_NAME__, __LINE__);
+  exit(1);
+}
+
+size_t getSizeOfLineOperandElementSize(const FasmLine line) {
+  switch (line.instruction) {
+    case FASM_TOKEN_NOOP:
+      return 0;
+    case FASM_TOKEN_PUSH8:
+      return 1;
+    case FASM_TOKEN_PUSH16:
+      return 2;
+    case FASM_TOKEN_PUSH32:
+      return 4;
+    case FASM_TOKEN_PUSH64:
+      return 8;
+    case FASM_TOKEN_LOAD8:
+    case FASM_TOKEN_LOAD16:
+    case FASM_TOKEN_LOAD32:
+    case FASM_TOKEN_LOAD64:
+    case FASM_TOKEN_POP8:
+    case FASM_TOKEN_POP16:
+    case FASM_TOKEN_POP32:
+    case FASM_TOKEN_POP64:
+    case FASM_TOKEN_DUP8:
+    case FASM_TOKEN_DUP16:
+    case FASM_TOKEN_DUP32:
+    case FASM_TOKEN_DUP64:
+    case FASM_TOKEN_SWAP8:
+    case FASM_TOKEN_SWAP16:
+    case FASM_TOKEN_SWAP32:
+    case FASM_TOKEN_SWAP64:
+    case FASM_TOKEN_DROP8:
+    case FASM_TOKEN_DROP16:
+    case FASM_TOKEN_DROP32:
+    case FASM_TOKEN_DROP64:
+    case FASM_TOKEN_ADD_I8:
+    case FASM_TOKEN_ADD_I16:
+    case FASM_TOKEN_ADD_I32:
+    case FASM_TOKEN_ADD_I64:
+    case FASM_TOKEN_ADD_F32:
+    case FASM_TOKEN_ADD_F64:
+    case FASM_TOKEN_SUB_I8:
+    case FASM_TOKEN_SUB_I16:
+    case FASM_TOKEN_SUB_I32:
+    case FASM_TOKEN_SUB_I64:
+    case FASM_TOKEN_SUB_F32:
+    case FASM_TOKEN_SUB_F64:
+    case FASM_TOKEN_NEG_I8:
+    case FASM_TOKEN_NEG_I16:
+    case FASM_TOKEN_NEG_I32:
+    case FASM_TOKEN_NEG_I64:
+    case FASM_TOKEN_NEG_F32:
+    case FASM_TOKEN_NEG_F64:
+    case FASM_TOKEN_MUL_I8:
+    case FASM_TOKEN_MUL_I16:
+    case FASM_TOKEN_MUL_I32:
+    case FASM_TOKEN_MUL_I64:
+    case FASM_TOKEN_MUL_U8:
+    case FASM_TOKEN_MUL_U16:
+    case FASM_TOKEN_MUL_U32:
+    case FASM_TOKEN_MUL_U64:
+    case FASM_TOKEN_MUL_F32:
+    case FASM_TOKEN_MUL_F64:
+    case FASM_TOKEN_DIV_I8:
+    case FASM_TOKEN_DIV_I16:
+    case FASM_TOKEN_DIV_I32:
+    case FASM_TOKEN_DIV_I64:
+    case FASM_TOKEN_DIV_U8:
+    case FASM_TOKEN_DIV_U16:
+    case FASM_TOKEN_DIV_U32:
+    case FASM_TOKEN_DIV_U64:
+    case FASM_TOKEN_DIV_F32:
+    case FASM_TOKEN_DIV_F64:
+    case FASM_TOKEN_REM_I8:
+    case FASM_TOKEN_REM_I16:
+    case FASM_TOKEN_REM_I32:
+    case FASM_TOKEN_REM_I64:
+    case FASM_TOKEN_REM_U8:
+    case FASM_TOKEN_REM_U16:
+    case FASM_TOKEN_REM_U32:
+    case FASM_TOKEN_REM_U64:
+    case FASM_TOKEN_CAST_I8_I64:
+    case FASM_TOKEN_CAST_I16_I64:
+    case FASM_TOKEN_CAST_I32_I64:
+    case FASM_TOKEN_CAST_I64_I8:
+    case FASM_TOKEN_CAST_I64_I16:
+    case FASM_TOKEN_CAST_I64_I32:
+    case FASM_TOKEN_CAST_F64_I64:
+    case FASM_TOKEN_CAST_I64_F64:
+    case FASM_TOKEN_CAST_U8_U64:
+    case FASM_TOKEN_CAST_U16_U64:
+    case FASM_TOKEN_CAST_U32_U64:
+    case FASM_TOKEN_CAST_U64_U8:
+    case FASM_TOKEN_CAST_U64_U16:
+    case FASM_TOKEN_CAST_U64_U32:
+    case FASM_TOKEN_CAST_F64_U64:
+    case FASM_TOKEN_CAST_U64_F64:
+    case FASM_TOKEN_CAST_F32_F64:
+    case FASM_TOKEN_CAST_F64_F32:
+    case FASM_TOKEN_JUMP:
+    case FASM_TOKEN_JZ_I8:
+    case FASM_TOKEN_JNZ_I8:
+    case FASM_TOKEN_JN_I8:
+    case FASM_TOKEN_JNN_I8:
+    case FASM_TOKEN_JP_I8:
+    case FASM_TOKEN_JNP_I8:
+    case FASM_TOKEN_JZ_I16:
+    case FASM_TOKEN_JNZ_I16:
+    case FASM_TOKEN_JN_I16:
+    case FASM_TOKEN_JNN_I16:
+    case FASM_TOKEN_JP_I16:
+    case FASM_TOKEN_JNP_I16:
+    case FASM_TOKEN_JZ_I32:
+    case FASM_TOKEN_JNZ_I32:
+    case FASM_TOKEN_JN_I32:
+    case FASM_TOKEN_JNN_I32:
+    case FASM_TOKEN_JP_I32:
+    case FASM_TOKEN_JNP_I32:
+    case FASM_TOKEN_JZ_I64:
+    case FASM_TOKEN_JNZ_I64:
+    case FASM_TOKEN_JN_I64:
+    case FASM_TOKEN_JNN_I64:
+    case FASM_TOKEN_JP_I64:
+    case FASM_TOKEN_JNP_I64:
+    case FASM_TOKEN_JZ_F32:
+    case FASM_TOKEN_JNZ_F32:
+    case FASM_TOKEN_JN_F32:
+    case FASM_TOKEN_JNN_F32:
+    case FASM_TOKEN_JP_F32:
+    case FASM_TOKEN_JNP_F32:
+    case FASM_TOKEN_JZ_F64:
+    case FASM_TOKEN_JNZ_F64:
+    case FASM_TOKEN_JN_F64:
+    case FASM_TOKEN_JNN_F64:
+    case FASM_TOKEN_JP_F64:
+    case FASM_TOKEN_JNP_F64:
+    case FASM_TOKEN_ALLOC_HEAP:
+    case FASM_TOKEN_ALLOC_STACK:
+    case FASM_TOKEN_FREE_HEAP:
+    case FASM_TOKEN_GET_STACK_ADDRESS:
+    case FASM_TOKEN_GET_GLOBAL_ADDRESS:
+    case FASM_TOKEN_CALL:
+    case FASM_TOKEN_RET:
+    case FASM_TOKEN_SYSCALL:
+      return 0;
+    case FASM_TOKEN_DEFINE_BYTE:
+      return 1;
+    case FASM_TOKEN_DEFINE_WORD:
+      return 2;
+    case FASM_TOKEN_DEFINE_DWORD:
+      return 4;
+    case FASM_TOKEN_DEFINE_QWORD:
+      return 8;
+    case FASM_TOKEN_NONE:
+  }
+
+  fprintf(stderr, "Bad fasm token '%d' at %s:%d", line.instruction,
+          __FILE_NAME__, __LINE__);
+  exit(1);
+}
+
+void fasmLinesPushVariable(FasmLinkedLines *linkedLines,
+                           FasmVariable variable) {
+  const size_t size = a404m_malloc_usable_size(linkedLines->variables) /
+                      sizeof(*linkedLines->variables);
+  if (size == linkedLines->variables_size) {
+    linkedLines->variables =
+        a404m_realloc(linkedLines->variables,
+                      (size + size / 2 + 1) * sizeof(*linkedLines->variables));
+  }
+  linkedLines->variables[linkedLines->variables_size] = variable;
+  linkedLines->variables_size += 1;
+}
+
+void fasmLinesPushLine(FasmLinkedLines *linkedLines, FasmLinkedLine line) {
+  const size_t size = a404m_malloc_usable_size(linkedLines->lines) /
+                      sizeof(*linkedLines->lines);
+  if (size == linkedLines->lines_size) {
+    linkedLines->lines =
+        a404m_realloc(linkedLines->lines,
+                      (size + size / 2 + 1) * sizeof(*linkedLines->lines));
+  }
+  linkedLines->lines[linkedLines->lines_size] = line;
+  linkedLines->lines_size += 1;
+}
+
+void fasmLinesPushData(FasmLinkedLines *linkedLines, uint8_t *data,
+                       size_t size) {
+  linkedLines->data =
+      a404m_realloc(linkedLines->data, (linkedLines->data_size + size) *
+                                           sizeof(*linkedLines->data));
+  memcpy(linkedLines->data + linkedLines->data_size, data, size);
+  linkedLines->data_size += size;
+}
+
+FasmVariable fasmLinesGetVariable(const FasmLinkedLines *linkedLines,
+                                  char const *nameBegin, char const *nameEnd) {
+  const size_t size = nameEnd - nameBegin;
+  for (size_t i = 0; i < linkedLines->variables_size; ++i) {
+    const FasmVariable variable = linkedLines->variables[i];
+    const size_t variable_str_size = variable.end - variable.begin;
+    if (size == variable_str_size &&
+        strncmp(variable.begin, nameBegin, size) == 0) {
+      return variable;
+    }
+  }
+
+  FasmVariable ERROR = {
+      .begin = NULL,
+      .end = NULL,
+      .value = 0,
+  };
+
+  return ERROR;
+}
+
+bool isOperandString(FasmOperand operand) { return *(operand.begin) == '"'; }
+
+uint64_t getOperandValue(FasmLinkedLines *linkedLines, FasmOperand operand,
+                         SourceCode *sourceCode) {
+  char c = *(operand.begin);
+
+  if (c == '"') {
+    fprintf(stderr, "It shoulden't be here");
+    exit(1);
+  } else if (c == '0') {
+    ++(operand.begin);
+    if (operand.begin == operand.end) {
+      return 0;
+    }
+    c = *(operand.begin);
+    if (c == 'x') {
+      return hexStrToInt(operand.begin + 1, operand.end, sourceCode);
+    } else if (c == 'b') {
+      return binStrToInt(operand.begin + 1, operand.end, sourceCode);
+    } else {
+      return strToInt(operand.begin + 1, operand.end, sourceCode);
+    }
+  } else if (c == '-') {
+    ++(operand.begin);
+    if (operand.begin == operand.end) {
+      printError("Expected value after -", sourceCode, operand.begin,
+                 operand.end);
+      exit(1);
+    }
+    c = *(operand.begin);
+    if (c == '0') {
+      ++(operand.begin);
+      if (operand.begin == operand.end) {
+        return 0;
+      }
+      c = *(operand.begin);
+      if (c == 'x') {
+        return -hexStrToInt(operand.begin + 1, operand.end, sourceCode);
+      } else if (c == 'b') {
+        return -binStrToInt(operand.begin + 1, operand.end, sourceCode);
+      } else {
+        return -strToInt(operand.begin + 1, operand.end, sourceCode);
+      }
+    }
+  } else if ('0' <= c && c <= '9') {
+    return strToInt(operand.begin, operand.end, sourceCode);
+  } else {
+    const FasmVariable variable =
+        fasmLinesGetVariable(linkedLines, operand.begin, operand.end);
+    if (variable.begin == NULL) {
+      printError("Label '%.*s' not found", sourceCode, operand.begin,
+                 operand.end, (int)(operand.end - operand.begin),
+                 operand.begin);
+      exit(1);
+    }
+    return variable.value;
+  }
+  printError("Should not come here %s:%d", sourceCode, operand.begin,
+             operand.end, __FILE_NAME__, __LINE__);
+  exit(1);
+}
+
+uint64_t strToInt(const char *begin, const char *end, SourceCode *sourceCode) {
+  uint64_t result = 0;
+  for (char const *iter = begin; iter < end; ++iter) {
+    const char c = *iter;
+    result *= 10;
+    if ('0' <= c && c <= '9') {
+      result += c - '0';
+    } else {
+      printError("Unexpected character", sourceCode, iter, iter + 1);
+      exit(1);
+    }
+  }
+  return result;
+}
+uint64_t hexStrToInt(const char *begin, const char *end,
+                     SourceCode *sourceCode) {
+  uint64_t result = 0;
+  for (char const *iter = begin; iter < end; ++iter) {
+    const char c = *iter;
+    result *= 16;
+    if ('0' <= c && c <= '9') {
+      result += c - '0';
+    } else if ('A' <= c && c < 'F') {
+      result += c - 'A' + 10;
+    } else if ('a' <= c && c < 'f') {
+      result += c - 'a' + 10;
+    } else {
+      printError("Unexpected character", sourceCode, iter, iter + 1);
+      exit(1);
+    }
+  }
+  return result;
+}
+uint64_t binStrToInt(const char *begin, const char *end,
+                     SourceCode *sourceCode) {
+  uint64_t result = 0;
+  for (char const *iter = begin; iter < end; ++iter) {
+    const char c = *iter;
+    result *= 2;
+    if ('0' <= c && c <= '1') {
+      result += c - '0';
+    } else {
+      printError("Unexpected character", sourceCode, iter, iter + 1);
+      exit(1);
+    }
+  }
+  return result;
+}
-- 
cgit v1.2.3