Proyecto Universitario - Compilador

Como el título indica, ando con la idea maníaca de crear un compilador desde cero. Empezó como trabajo universitario, pero desde que me metí de lleno en el tema quedé completamente enamorado — así que me lo estoy tomando en serio como proyecto personal.

Por ahora tengo el analizador léxico funcionando: lee código fuente, lo tokeniza y escupe cada token con su tipo y lexema. Todo escrito en NASM x86-64, sin librerías, sin trampa. El compilador completo va a tener analizador sintáctico, semántico, generador de código intermedio, optimizador y generador de código final.

El problema es que los tokens por ahora son los de toda la vida: int, float, if, while… y eso es un bodrio.

Aquí es donde entran ustedes. Necesito ideas para el lenguaje:

  • ¿Cómo le pondrían a las palabras clave? (bruh en vez de int? porfa en vez de return? mandaeso en vez de print?)
  • ¿Qué sintaxis les parecería divertida pero que aún tenga sentido?
  • ¿Alguna feature absurda pero técnicamente implementable que les gustaría ver?
  • ¿Nombre para el lenguaje?

Ideas serias, ideas chistosas, o ideas que mezclen las dos — todas bienvenidas. El lenguaje tiene que funcionar de verdad al final, pero nadie dijo que no pueda tener personalidad.

El repo está en GitHub si alguien quiere ver el estado actual: GitHub - MrLaction/compiLATOR · GitHub

Agradecería mucho sus comentarios, sugerencias y preguntas. Estaré leyéndolos :stuck_out_tongue:

5 Me gusta

“entera” en lugar de “int”.

“vengaelresultado” en lugar de “return”.

“quepasariasi” en lugar de “if”.

“tresdoritosdespues” en lugar de “while”.

7 Me gusta

cuerda/cordel = string

Otras personas haciendo proyectos universitarios: hare una calculadora en python :cowboy_hat_face:

Este bro:

2 Me gusta

Ey, yo hice todo un punto de venta con control de stock, facturación, manejo de usuarios y ya no me acuerdo que más :joy:

2 Me gusta

y en vez de def (para funciones), “noteolvidesdeestoquelousarasmastarde“

1 me gusta

Real.

Pero créanme que no es algo tan complejo. Es verdad, requiere un nivel de conocimientos mínimos en estructuras de datos, hardware y transducción. Pero nada que un par de libros no puedan solucionar.

2 Me gusta

Y son estos proyectos los que más ayudan a entender el funcionamiento de la máquina.

1 me gusta

Totalmente.

Como ya dije varias veces a lo largo y ancho del foro, aplicar lo aprendido en algo que realmente solucione un problema o también, un proyecto “real” es lo que más ayuda a incorporar los conocimientos aprendidos.

2 Me gusta

que envía me gustaría estar en ese punto de conocimiento, estoy en lo básico pero me disfruto mi nivel, siempre inventando un poco!

Cuando estaba empezando programación, antes de pasarme a física, quice hacer una calculadora en SDL2 (aún no había salido SDL3, recién estaba en desarrollo), y por no usar estructuras (la forma de hacer programación orientada a objetos en C) con punteros a estructura en el primer parametro (en C++, puntero this, también se puede usar en ensamblador, vendría bien para que sea más solido el compilador que querés armar), la calculadora crazeaba continuamente, parece que se mezclaban las variables…

Para usar el puntero this en ensamblador, y que el compilador que armas quede más sólido, podrías ver:

2 Me gusta

Muchas gracias por el material. :stuck_out_tongue: .

Sí, realmente el hacer estos proyectos (bueno, en general todos) sin un uso correcto de las estructuras, es infernal. No solo porque se escribe código totalmente innecesario (y muchas veces inentendible), también porque pierdes un montón de neuronas complicándote con soluciones equívocas cuando con estructuras haces todo mucho más sencillo.

No te detengas. Aún cuando tengas frente a ti un montón de temas que sencillamente no te entran en la cabeza, créeme que el devolverse y seguir intentando comprender es lo que más te va servir a la hora de plantearte proyectos más desafiantes.

No es tan complicado armar un compilador, gcc lo que hace es convertir la sintaxis de C a ensamblador.

Es decir, convertir texto a texto.

Luego se lo pasa a un ensamblador y por último al linker, lo que si es difícil. Ahí necesitas entenderle a nivel experto al código máquina. Aunque hay algunos tutoriales por ahí de como hacer un hola mundo byte por byte sin llamar comandos ni programas. Solo con un editor hexadecimal, y ejecutar sin nada más.

yo hace tiempo hice un transpilador de un lenguaje que hice a ensamblador para compilar en mi kernel sin ayuda de otro OS y va bien, ya portee una version a NodeJs , aqui esta el codigo

// dependencia de carpetas
const {PathDependy, checkDependenceTree} = require("./dependy.js")
// sistema de archivos
const fs = require("fs");
// enumeradores
class Enums {
  // tipo de dato
  static TypeOfData = {
    // funciones
    Function: 0,
    // variables
    Variable: 1
  };
  // objetivos
  static Targets = {
    // modo real i386
    I386RealMode: 0,
    // modo protegido i386
    I386ProtectedMode: 1,
    // ARMv7
    ARMv7: 2,
    // ARM64 aarch64
    ARM64: 3
  }
}
// mapa de registros
var RegisterMaps = {
  // registros de modo real
  [Enums.Targets.I386RealMode]: {
    r1: "ax", r2: "cx", r3: "dx", r4: "bx", r5: "sp", r6: "bp", r7: "si", r8: "di"
  },
  // registros de modo protegido
  [Enums.Targets.I386ProtectedMode]: {
    r1: "eax", r2: "ecx", r3: "edx", r4: "ebx", r5: "esp", r6: "ebp", r7: "esi", r8: "edi"
  },
  // registros de ARMv7
  [Enums.Targets.ARMv7]: {
    r1: "r0", r2: "r1", r3: "r2", r4: "r3", r5: "sp", r6: "r4", r7: "r5", r8: "r6"
  },
  // registros de ARM aarch64
  [Enums.Targets.ARM64]: {
    r1: "x0", r2: "x1", r3: "x2", r4: "x3", r5: "sp", r6: "x4", r7: "x5", r8: "x6"
  }
};
// emitir addicion
function emitAdd(dest, src) {
  // target
  switch (ActualTarget) {
    // i386
    case Enums.Targets.I386RealMode:
    case Enums.Targets.I386ProtectedMode:
      return `add ${dest},${src}\n`;
    // ARMv7
    case Enums.Targets.ARMv7: return `add ${dest}, ${dest}, ${src}\n`;
    // ARM aarch64
    case Enums.Targets.ARM64: return `add ${dest}, ${dest}, ${src}\n`;
  }
}
// emitir substraccion
function emitSub(dest, src) {
  // target
  switch (ActualTarget) {
    // i386
    case Enums.Targets.I386RealMode:
    case Enums.Targets.I386ProtectedMode:
      return `sub ${dest},${src}\n`;
    // ARMv7
    case Enums.Targets.ARMv7: return `sub ${dest}, ${dest}, ${src}\n`;
    // ARM aarch64
    case Enums.Targets.ARM64: return `sub ${dest}, ${dest}, ${src}\n`;
  }
}
// emitir multiplicacion
function emitMul(dest, src) {
  // target
  switch (ActualTarget) {
    // i386
    case Enums.Targets.I386ProtectedMode:
    case Enums.Targets.I386RealMode:
      return `imul ${dest},${src}\n`;
    // ARMv7
    case Enums.Targets.ARMv7: return `mul ${dest}, ${dest}, ${src}\n`;
    // ARM aarch64
    case Enums.Targets.ARM64: return `mul ${dest}, ${dest}, ${src}\n`;
  }
}
// emitir division
function emitDiv(dest, src, Tabulators) {
  switch (ActualTarget) {
    // i386
    case Enums.Targets.I386RealMode:
    case Enums.Targets.I386ProtectedMode:
      return  `push eax\n`                      +
              `${Tabulators}push edx\n`         +
              `${Tabulators}mov eax, ${dest}\n` +
              `${Tabulators}cdq\n`              +
              `${Tabulators}idiv ${src}\n`      +
              `${Tabulators}mov ${dest}, eax\n` +
              `${Tabulators}pop edx\n`          +
              `${Tabulators}pop eax\n`
  ;
    // ARMv7
    case Enums.Targets.ARMv7: return `sdiv ${dest}, ${dest}, ${src}\n`;
    // ARM aarch64
    case Enums.Targets.ARM64: return `sdiv ${dest}, ${dest}, ${src}\n`;
  }
}
// emitir je
function emitJumpEQ(label) {
  // target
  switch (ActualTarget) {
    // i386
    case Enums.Targets.I386RealMode:
    case Enums.Targets.I386ProtectedMode:
      return `je ${candyVarToRegister(label)}\n`;
    // ARMv7 o aarch64
    case Enums.Targets.ARMv7:
    case Enums.Targets.ARM64:
      return `beq ${candyVarToRegister(label)}\n`;
  }
}
function emitPush(reg) {
  // target
  switch (ActualTarget) {
    // i386
    case Enums.Targets.I386RealMode:
    case Enums.Targets.I386ProtectedMode:
      return `push ${reg}\n`;
    // ARMv7
    case Enums.Targets.ARMv7: return `push {${reg}}\n`;
    // ARM aarch64
    case Enums.Targets.ARM64: return `str ${reg}, [sp, #-16]!\n`;
  }
}
function emitPop(reg) {
  // target
  switch (ActualTarget) {
    // i386
    case Enums.Targets.I386RealMode:
    case Enums.Targets.I386ProtectedMode:
      return `pop ${reg}\n`;
    // ARMv7
    case Enums.Targets.ARMv7: return `pop {${reg}}\n`;
    // ARM aarch64
    case Enums.Targets.ARM64: return `ldr ${reg}, [sp], #16\n`;
  }
}
function emitJumpGT(label) {
  // target
  switch (ActualTarget) {
    // i386
    case Enums.Targets.I386RealMode:
    case Enums.Targets.I386ProtectedMode:
      return `jg ${label}\n`;
    // ARMv7 o aarch64
    case Enums.Targets.ARMv7:
    case Enums.Targets.ARM64:
      return `bgt ${label}\n`;
  }
}
function emitJumpLT(label) {
  // target
  switch (ActualTarget) {
    // i386
    case Enums.Targets.I386RealMode:
    case Enums.Targets.I386ProtectedMode:
      return `jl ${label}\n`;
    // ARMv7 o aarch64
    case Enums.Targets.ARMv7:
    case Enums.Targets.ARM64:
      return `blt ${label}\n`;
  }
}
// no namespace with guion
var gnspwg = false;
// simbolos que se expandiran
var globalSymbolsExpands = new Map();
// objetivo actual
var ActualTarget = Enums.Targets.I386ProtectedMode;
// permitir code position independient, esto solo funciona en Enums.Targets.I386ProtectedMode y Enums.Targets.I386RealMode
var AllowStackPic = true;
// que el nombre no se va a hacer mayusculas
var NoNameUpper = false;
// variable a registro
function candyVarToRegister(candyVar) {
  // t32
  if (candyVar.startsWith("[Uint32]") || candyVar.startsWith("[Int32]")) { return "dword " + candyVarToRegister(candyVar.startsWith("[Uint32]") ? candyVar.substring(8) : candyVar.substring(7)); } 
  // t16
  else if (candyVar.startsWith("[Uint16]") || candyVar.startsWith("[Int16]")) { return "word " + candyVarToRegister(candyVar.startsWith("[Uint16]") ? candyVar.substring(8) : candyVar.substring(7)); } 
  // t8
  else if (candyVar.startsWith("[Uint8]") || candyVar.startsWith("[Int8]")) { return "byte " + candyVarToRegister(candyVar.startsWith("[Uint8]") ? candyVar.substring(7) : candyVar.substring(6)); }
  // direccionamiento
  if (candyVar.startsWith("[") && candyVar.endsWith("]")) { return "[" + candyVarToRegister(candyVar.slice(1, -1)) + "]"; }
  // si contiene expansion entonces expandir
  if (globalSymbolsExpands.has(candyVar)) return globalSymbolsExpands.get(candyVar)
  // mapa
  const map = RegisterMaps[ActualTarget];
  // si contiene el mapa y aparte hay candvar
  if (map && map[candyVar]) {
    // retornar
    return map[candyVar];
  }
  // retornar el candyVar original
  return (gnspwg ? candyVar.replaceAll("::", "__") :  candyVar);
}
// no necesariamente tiene que ser letra si no un caracter admitido para sentencias del parser
function isLetter(c) {
  return (
    (c >= 'A' && c <= 'Z') ||
    (c >= 'a' && c <= 'z') ||
    (c >= '0' && c <= '9') ||
    c === '_' ||
    c === '[' ||
    c === ']' ||
    c === ':' ||
    c === '.'
  );
}
// variable de ModuCandy/FooCandy
class VariableModuCandy {
  constructor(name, type, offset) {
    this.name = name;
    this.type = type;
    this.offset = offset;
  }
}
// parsea el codigo interno
function parseCodeInternal(code) {
  /** simbolos @type { Map<string, number>} */
  let Symbols = new Map();
  // estructuras como macros
  let structsAsMacros = [];
  // expresiones de estructuras
  let structsExp = new Map();
  // tabuladores
  let Tabulators = "   ";
  // codigo que retornara
  let codeRet = "";
  // simbolo de la palabra
  let wordSymbol = "";
  // tipo a usar
  let typeUse = "";
  // seccion de datos
  let dataSection =
`DATA_MODUCANDY_DATA:
   call DATA_MODUCANDY_DATA_GETEIP
   ret
   ;datas
`;
  // datos reales
  let datasReal = "";
  // funciones auxiliares de datos
  let datasFunctions =
`; ModuCandy: eip get runtime for data calc
DATA_MODUCANDY_DATA_GETEIP:
   pop eax
   push eax
   inc eax
   ret
`;
  // variabkes
  let variables = [];
  // offset actual
  let offsetActual = 0;
  // atributos
  let atributes = "";
  // si esta en comentario
  let inComment = false;
  // usando tipo
  let typeUsage = false;
  // recorrer parse
  for (let i = 0; i < code.length; i++) {
    // caracter
    const c = code[i];
    // comentario
    if (inComment) {
      // comentario
      codeRet += c;
      // si termina
      if (c === '\n') inComment = false;
      // continuar
      continue;
    }

    // acumulación de símbolo
    if (isLetter(c)) {
      // se usara un tipo
      if (wordSymbol.length === 0 && c >= 'A' && c <= 'Z') typeUsage = true;
      // si usa un tipo
      if (typeUsage) typeUse += c;
      // simbolo de palabra
      wordSymbol += c;
      continue;
    }

    // cierre de palabra
    if (typeUsage) typeUsage = false;
    // es null
      else if (typeUse !== "") {
          // funcion
          if (wordSymbol === "fn") {
            // saltar tabuladores
            i++; while (code[i] === ' ' || code[i] === '\t') i++;
            // obtener nombre
            let funcName = ""; while (isLetter(code[i])) { funcName += code[i++]; }
            // setear funcion
            Symbols.set((gnspwg ? funcName.replaceAll("::", "__") :  funcName), Enums.TypeOfData.Function);
            // sumar codigo
            codeRet += `; type=${typeUse}\n${(gnspwg ? funcName.replaceAll("::", "__") :  funcName)}:\n`;
          }
          // let
          else if (wordSymbol === "let") {
            // saltar espacios
            i++; while (code[i] === ' ' || code[i] === '\t') i++;
            // detectar nombre
            let varName = ""; while (isLetter(code[i])) varName += code[i++];
            // si lo encontro
            let imaginaryFinded = false;
            // si sera imaginaria
            if (atributes.includes("imaginary=true"))
            {
              // si es un org
              if (atributes.includes("org=")) {
                // setaer
                let org = Number(atributes.split("org=")[1].split(",")[0]); globalSymbolsExpands.set(varName, org.toString())

                if (structsExp.has(typeUse)) {
                  // abc
                  for (const abc of structsExp.get(typeUse)) globalSymbolsExpands.set(varName + "." + abc.field, (org + abc.offset).toString())
                  // se encontro imaginario
                  imaginaryFinded = true;
                }
              }
            }

            // si lo encontro setear
            if (!imaginaryFinded) { if (structsAsMacros.includes(typeUse)) {codeRet += "instance_" + typeUse + " " + varName;}
            else {
            let compileAsStru = false;
            for (let av of variables)
            {
              let a = typeUse;
              a += "::__New__";

              if (av.name == a)
              {
                compileAsStru = true;
                for (let av2 of variables) {
                  let str2 = av2.name;
                  let str1 = typeUse + "::";
                  let len = str1.length;
                  let comparate = str2.startsWith(str1) ? 0 : -1;

                  if (comparate == 0)
                  {
                    str2 = str2.substring(len);
                    // simular el ret ;place for a struct field
                    for (let i = 0; i < (av2.type === "u32" ? 4 : ( av2.type == "stru" ? 0 : 1)); i++) {
                        datasReal += "   ret ;place for a struct field\n";
                    }

                    let Variable = new VariableModuCandy(varName + "::" + str2, av2.type, offsetActual);

                    offsetActual += (av2.type === "u32" ? 4 : ( av2.type == "stru" ? 0 : 1));
                    Symbols.set(Variable.name, Enums.TypeOfData.Variable);
                    variables.push(Variable);
                  }
                }
                break;
              }
            }
            if (compileAsStru == false) {
              Symbols.set(varName, Enums.TypeOfData.Variable);
            if (typeUse === "BuiltIn_u32" || typeUse === "BuiltIn_i32") {
              for (let a = 0; a < 4; a++) {
                datasReal += "   ret ;place for variable (u/i32)\n";
              }

              variables.push(
                new VariableModuCandy(varName, "u32", offsetActual)
              );
              offsetActual += 4;
            }
            else if (typeUse === "BuiltIn_u8" || typeUse === "BuiltIn_i8") {
              datasReal += "   ret ;place for variable (u/i8)\n";

              variables.push(
                new VariableModuCandy(varName, "u8", offsetActual)
              );
              offsetActual += 1;
            }
          }
            }
          }
        }
        // vaciar tipo de uso
        typeUse = "";
      }
      // retornar
      if (wordSymbol === "return") { codeRet += Tabulators + ((ActualTarget == Enums.Targets.ARMv7) ? "bx lr\n" :  (ActualTarget == Enums.Targets.ARM64 || ActualTarget) ? "ret\n" : "ret\n"); }
      // pragma
      else if (wordSymbol == "__pragma__") {
        i++;
        if (code.slice(i, -1).startsWith("ifarch=")) {
          i+= 7;
          let candyVar = "";
          while (isLetter(code[i])) {
              candyVar += code[i];
              i++;
          }

          if (ActualTargetStr != candyVar) {
            let str_engached = "";
            while (!str_engached.endsWith("__endif__"))
            {
              str_engached += code[i];
              i++;
            }
          }
        }
      }
      // safe
      else if (wordSymbol == "safe") {
          i++;
          let word = "";
          while (isLetter(code[i])) {
              word += code[i];
              i++;
          }

          switch (word) {
              // incrementar
              case "increments": {
                  i++;
                  let candyVar = "";
                  while (isLetter(code[i])) candyVar += code[i++];

                  codeRet += Tabulators + emitAdd(candyVarToRegister(candyVar), "1");
                  break;
              }
              // decrementar
              case "decrements": {
                  i++;
                  let candyVar = "";
                  while (isLetter(code[i])) candyVar += code[i++];

                  codeRet += Tabulators + emitSub(candyVarToRegister(candyVar), "1");
                  break;
              }
              // lista de numeros
              case "numlist": {
                i++;
                let Name = "";
                while (isLetter(code[i])) Name += code[i++];
                if (code[i] == '<')
                {
                  i++;
                  let type = "";
                  while (code[i] != ">") type += code[i++];
                  i++;
                  while (code[i].replaceAll("\n", "").replaceAll("\r", "").replaceAll("\t", "").replaceAll(" ", "") == "") i++;
                  if (code[i] == '{') {
                    i++;
                    let enumE = "";
                    while (code[i] != "}") {
                      enumE += code[i];
                      i++;
                    }
                    let fields = enumE.replaceAll("\n", "").replaceAll("\r", "").replaceAll("\t", "").replaceAll(" ", "").split(",");
                    let fieldsOffset = 0;
                    for (const member of fields) {
                      if (member.includes("="))
                      {
                        globalSymbolsExpands.set(Name + "::" + member.split("=")[0], member.split("=")[1]);
                        fieldsOffset = Number(member.split("=")[1]) + 1;
                      }
                      else {
                        globalSymbolsExpands.set(Name + "::" + member.split("=")[0], fieldsOffset.toString());
                        fieldsOffset++;
                      }
                    }
                  }
                }
                break;
              }
              // salto incondicional
              case "jumps": {
                  i++;
                  let label = "";
                  while (isLetter(code[i])) label += code[i++];

                  switch (ActualTarget) {
                      case Enums.Targets.I386RealMode:
                      case Enums.Targets.I386ProtectedMode:
                          codeRet += Tabulators + "jmp " + (NoNameUpper ? label : label.toUpperCase()) + "\n";
                          break;
                      case Enums.Targets.ARMv7:
                          codeRet += Tabulators + "b " + candyVarToRegister(label) + "\n";
                          break;
                      case Enums.Targets.ARM64:
                          codeRet += Tabulators + "b " + candyVarToRegister(label) + "\n";
                          break;
                  }
                  break;
              }
              default:
                  break;
          }
      }
      // estructuras
      else if (wordSymbol == "stru") {
        let make_struct_macro = false;
        if (atributes !== "") {
          if (atributes.includes("useMacros=true")) {
            make_struct_macro = true;
          }
        }

        atributes = "";

          i++;
        let candyVar = "";
        while (isLetter(code[i])) {
            candyVar += code[i];
            i++;
        }
  
        if (make_struct_macro) {
          while (code[i] == ' ') { i++; }
          if (code[i] == '{') {
            i++;
            let struct = "";
            while (code[i] != '}')
            { 
                struct += code[i];
                i++;
            }
            let offsets_expand = "";
            let macro_expand = "%macro instance_" + candyVar + " 1\n%1:\n"
            let offset_struct = 0;
            let regex = /\b([A-Z]\w*)\b\s+\blet\b\s+([\w:.]+)/g;

            let match;
            let results = [];

            while ((match = regex.exec(struct)) !== null) {
              macro_expand += `   .${match[2]} ${
                (match[1] == "Int32" || match[1] == "Uint32") ? "dd" :
                (match[1] == "Int16" || match[1] == "Uint16") ? "dw" :
                (match[1] == "Int8" || match[1] == "Uint8") ? "db" : "db"
              } 0\n`;
              offsets_expand += `Offset_${candyVar}_${match[2]} equ ${offset_struct.toString()}\n`
              results.push({
                type: match[1],   // Grupo 1: nombre de la estructura
                field: match[2],   // Grupo 2: campo con tipo
                offset: offset_struct
              });
              offset_struct += (match[1] == "Int32" || match[1] == "Uint32") ? 4 :
                (match[1] == "Int16" || match[1] == "Uint16") ? 2 :
                (match[1] == "Int8" || match[1] == "Uint8") ? 1 : 1;
            }

            structsAsMacros.push(candyVar);
            structsExp.set(candyVar, results);
            macro_expand += "%endmacro\n";
            codeRet += macro_expand;
            codeRet += offsets_expand;
          }
        }
        else {
        Symbols.set(candyVar + "::__New__", Enums.TypeOfData.Variable);
        variables.push(new VariableModuCandy(candyVar + "::__New__", "stru", 0));
        }
      }
      // importar modulos
      else if (wordSymbol === "candy") {
        i++;
        let candyVar = "";
        while (isLetter(code[i])) {
            candyVar += code[i];
            i++;
        }

        try {
          let deptree = checkDependenceTree();
          
          for (const dep of deptree) {
            if (dep.logica_nsp == candyVar)
            {
              let depa = parseCodeInternal(fs.readFileSync(dep.directory, "utf-8"));
              codeRet += depa.codeRet;
              Symbols = new Map([...Symbols, ...depa.Symbols]);
              break;
            }
          }
        } catch (error) {
        }
      }
      // codigo ensamblador
      else if (wordSymbol === "unsafe") {
          i++;
          if (code[i] === '"') {
              // detectar codigo
              let assemblyCode = ""; i++; while (code[i] !== '"' && i < code.length) { assemblyCode += code[i]; i++; }
              // spliteado
              let asmsplit = assemblyCode.split("\n")
              // sumar lineas
              for (let index = 0; index < asmsplit.length; index++) {           
                const linea = asmsplit[index].trim();   
                codeRet += Tabulators + linea + "\n";
              }
          }
      }
      // atributos
      else if (wordSymbol == "__attr__") {
        // detectar
        i++; if (code[i] === '"') { let assemblyCode = ""; i++; while (code[i] !== '"' && i < code.length) { assemblyCode += code[i]; i++; } atributes = assemblyCode;
        }
      }
      // comentarios
      else if (c === '/' && code[i + 1] === '/') {
        inComment = true;
        codeRet += Tabulators + (ActualTarget == Enums.Targets.ARM64 ? '//' : ';');
        i++;
      }
      // funciones
      else if (c === '(' && code[i + 1] === ')') {
          i++;
          let upper = (NoNameUpper ? wordSymbol : wordSymbol.toUpperCase());

          if (ActualTarget == Enums.Targets.ARMv7 || ActualTarget == Enums.Targets.ARM64) {
              // Apilar LR antes de llamar
              codeRet += Tabulators + emitPush("lr");
              codeRet += Tabulators + "bl " + candyVarToRegister(upper) + "\n";
              codeRet += Tabulators + emitPop("lr");
          } else {
              // x86
              codeRet += Tabulators + "call " + candyVarToRegister(upper) + "\n";
          }
      }
      // variables
      else if (c === '<' && code[i + 1] === '=') {
      i += 2;

      let candyVar = "";
      while (isLetter(code[i])) {
          candyVar += code[i];
          i++;
      }

      for (const v of variables) {
          if (v.name === candyVar) {
          codeRet += Tabulators +
              "call DATA_MODUCANDY_DATA\n" + Tabulators +
              "mov ebx," + v.offset + "\n" + Tabulators +
              "add eax,ebx\n";
          }
      }
      }
      // comparar
      else if (c === '?') {
      i++;

      let candyVar = "";
      while (isLetter(code[i])) {
          candyVar += code[i];
          i++;
      }

      codeRet += Tabulators +
          "cmp " +
          candyVarToRegister(wordSymbol) +
          "," +
          candyVarToRegister(candyVar) +
          "\n";
      }
      // saltar si es mayor
      else if (c === '>' && wordSymbol === "") {
      i++;

      let label = "";
      while (isLetter(code[i])) {
          label += code[i];
          i++;
      }

      codeRet += Tabulators + emitJumpGT((NoNameUpper ? label : label.toUpperCase()));
      }
      // saltar si es menor
      else if (c === '<' && wordSymbol === "") {
      i++;

      let label = "";
      while (isLetter(code[i])) {
          label += code[i];
          i++;
      }

      codeRet += Tabulators + emitJumpLT(NoNameUpper ? label : label.toUpperCase());
      }
      // sumar
      else if (c === '+') {
      i++;

      let candyVar = "";
      while (isLetter(code[i])) {
          candyVar += code[i];
          i++;
      }

      codeRet += Tabulators + emitAdd(candyVarToRegister(wordSymbol), candyVarToRegister(candyVar));
      }
      // multiplicar
      else if (c === '*') {
      i++;

      let candyVar = "";
      while (isLetter(code[i])) {
          candyVar += code[i];
          i++;
      }

      codeRet += Tabulators + emitMul(candyVarToRegister(wordSymbol), candyVarToRegister(candyVar));
      }
      // dividir
      else if (c === '/') {
      i++;

      let candyVar = "";
      while (isLetter(code[i])) {
          candyVar += code[i];
          i++;
      }

      codeRet += Tabulators + emitDiv(candyVarToRegister(wordSymbol), candyVarToRegister(candyVar), Tabulators);
      }
      // hacer pop
      else if (c === '-' && code[i + 1] === '>') {
      i += 2;

      let candyVar = "";
      while (isLetter(code[i])) {
          candyVar += code[i];
          i++;
      }

      codeRet += Tabulators + emitPop(candyVarToRegister(candyVar));
      }
      // hacer push
      else if ((c === '<' && code[i + 1] === '-') && wordSymbol !== "") {
      i += 2;

      codeRet += Tabulators + emitPush(candyVarToRegister(wordSymbol));
      }
      // restar
      else if (c === '-') {
      i++;

      let candyVar = "";
      while (isLetter(code[i])) {
          candyVar += code[i];
          i++;
      }

      codeRet += Tabulators + emitSub(candyVarToRegister(wordSymbol), candyVarToRegister(candyVar));
      }
      // asignar
      else if (c === '=' && wordSymbol !== "") {
      i++;

      let candyVar = "";
      while (isLetter(code[i])) {
          candyVar += code[i];
          i++;
      }

      codeRet += Tabulators + 
          "mov " +
          candyVarToRegister(wordSymbol) +
          "," +
          candyVarToRegister(candyVar) +
          "\n";
      }
      // si es equal
      else if (c === '=' && wordSymbol === "") {
      i++;

      let label = "";
      while (isLetter(code[i])) {
          label += code[i];
          i++;
      }

      codeRet += Tabulators + emitJumpEQ(NoNameUpper ? label : label.toUpperCase());
      }
  
    
      wordSymbol = "";
  }

  
  return {codeRet: codeRet , dataSection: dataSection , datasReal: datasReal, datasFunctions: datasFunctions, final:codeRet+(AllowStackPic == true ? dataSection+datasReal+datasFunctions : "") , Symbols:Symbols};
}

function parseCode(code, target=Enums.Targets.I386ProtectedMode, allowPic=true, no_name_upper=false, archstr="i386_protected", nspwg=false)
{
  globalSymbolsExpands.clear();
  ActualTargetStr = archstr;
  ActualTarget = target;
  AllowStackPic = allowPic;
  NoNameUpper = no_name_upper;
  gnspwg = nspwg;
  let abc = parseCodeInternal(code);
  return abc.final;
}

module.exports = { candyVarToRegister,isLetter, VariableModuCandy, parseCode, parseCodeInternal, Enums}

y compila a algo parecido a nasm en el caso de en mi OS y fuera de este compila ya a nasm normal

1 me gusta

Para nada complicado. Realmente es muy fácil sí se entiende la estructura. La implementación con, por ejemplo mi caso, assembly es lo de menos en comparación a entender la lógica detrás del mismo.