diff --git a/JS_Analyzer_parts/compiler.js b/JS_Analyzer_parts/compiler.js index 93109f3..969c9e8 100644 --- a/JS_Analyzer_parts/compiler.js +++ b/JS_Analyzer_parts/compiler.js @@ -36,8 +36,17 @@ export class CompilerVisitor extends BaseVisitor { node.izq.accept(this); // izq | node.der.accept(this); // izq | der - this.code.popObject(r.T0); // der - this.code.popObject(r.T1); // izq + const der = this.code.popObject(r.T0); // der + const izq = this.code.popObject(r.T1); // izq + + if (izq.type === 'string' && der.type === 'string') { + this.code.add(r.A0, r.ZERO, r.T1); + this.code.add(r.A1, r.ZERO, r.T0); + this.code.callBuiltin('concatString'); + this.code.pushObject({ type: 'string', length: 4 }); + return; + } + switch (node.op) { case '+': @@ -133,17 +142,54 @@ export class CompilerVisitor extends BaseVisitor { this.code.popObject(r.T0); // der this.code.popObject(r.T1); // izq - switch (node.op) { - case '&&': - this.code.and(r.T0, r.T0, r.T1); - this.code.push(r.T0); - break; - case '||': - this.code.or(r.T0, r.T1, r.T0); - this.code.push(r.T0); - break; + if (node.op === '&&') { + node.izq.accept(this); // izq + this.code.popObject(r.T0); // izq + + const labelFalse = this.code.getLabel(); + const labelEnd = this.code.getLabel(); + + this.code.beq(r.T0, r.ZERO, labelFalse); // if (!izq) goto labelFalse + node.der.accept(this); // der + this.code.popObject(r.T0); // der + this.code.beq(r.T0, r.ZERO, labelFalse); // if (!der) goto labelFalse + + this.code.li(r.T0, 1); + this.code.push(r.T0); + this.code.j(labelEnd); + this.code.addLabel(labelFalse); + this.code.li(r.T0, 0); + this.code.push(r.T0); + + this.code.addLabel(labelEnd); + this.code.pushObject({ type: 'bool', length: 4 }); + return + } + + if (node.op === '||') { + node.izq.accept(this); // izq + this.code.popObject(r.T0); // izq + + const labelTrue = this.code.getLabel(); + const labelEnd = this.code.getLabel(); + + this.code.bne(r.T0, r.ZERO, labelTrue); // if (izq) goto labelTrue + node.der.accept(this); // der + this.code.popObject(r.T0); // der + this.code.bne(r.T0, r.ZERO, labelTrue); // if (der) goto labelTrue + + this.code.li(r.T0, 0); + this.code.push(r.T0); + + this.code.j(labelEnd); + this.code.addLabel(labelTrue); + this.code.li(r.T0, 1); + this.code.push(r.T0); + + this.code.addLabel(labelEnd); + this.code.pushObject({ type: 'bool', length: 4 }); + return } - this.code.pushObject({ type: 'bool', length: 4 }); } /** @@ -310,21 +356,51 @@ visitVariableAssign(node) { * @type {BaseVisitor['visitIfNode']} */ visitIfNode(node) { - // Evaluar la condición - node.cond.accept(this); + this.code.comment('Inicio de If'); - this.code.li(r.T0, node.cond.value); - - // Hacer pop del valor de la condición + this.code.comment('Condicion'); + node.cond.accept(this); this.code.popObject(r.T0); - - // Crear etiquetas - const falseLabel = this.code.newLabel(); - const endLabel = this.code.newLabel(); + this.code.comment('Fin de condicion'); + /* + // no else + if (!cond) goto endIf + ... + endIf: + + // else + if (!cond) goto else + ... + goto endIf + else: + ... + endIf: + + */ + + const hasElse = !!node.stmtFalse + + if (hasElse) { + const elseLabel = this.code.getLabel(); + const endIfLabel = this.code.getLabel(); + + this.code.beq(r.T0, r.ZERO, elseLabel); + this.code.comment('Rama verdadera'); + node.stmtTrue.accept(this); + this.code.j(endIfLabel); + this.code.addLabel(elseLabel); + this.code.comment('Rama falsa'); + node.stmtFalse.accept(this); + this.code.addLabel(endIfLabel); + } else { + const endIfLabel = this.code.getLabel(); + this.code.beq(r.T0, r.ZERO, endIfLabel); + this.code.comment('Rama verdadera'); + node.stmtTrue.accept(this); + this.code.addLabel(endIfLabel); + } - //Bloque if - this.code.beqz(r.T0, falseLabel); - // No se que más hacer aquí + this.code.comment('Fin del If'); } diff --git a/RISC/builtins.js b/RISC/builtins.js new file mode 100644 index 0000000..78c8363 --- /dev/null +++ b/RISC/builtins.js @@ -0,0 +1,46 @@ +import { registers as r } from "./constants.js" +import { Generador } from "./generator.js" + +/** + * @param {Generador} code + */ +export const concatString = (code) => { + // A0 -> dirección en heap de la primera cadena + // A1 -> dirección en heap de la segunda cadena + // result -> push en el stack la dirección en heap de la cadena concatenada + + code.comment('Guardando en el stack la dirección en heap de la cadena concatenada') + code.push(r.HP); + + code.comment('Copiando la 1er cadena en el heap') + const end1 = code.getLabel() + const loop1 = code.addLabel() + + code.lb(r.T1, r.A0) + code.beq(r.T1, r.ZERO, end1) + code.sb(r.T1, r.HP) + code.addi(r.HP, r.HP, 1) + code.addi(r.A0, r.A0, 1) + code.j(loop1) + code.addLabel(end1) + + code.comment('Copiando la 2da cadena en el heap') + const end2 = code.getLabel() + const loop2 = code.addLabel() + + code.lb(r.T1, r.A1) + code.beq(r.T1, r.ZERO, end2) + code.sb(r.T1, r.HP) + code.addi(r.HP, r.HP, 1) + code.addi(r.A1, r.A1, 1) + code.j(loop2) + code.addLabel(end2) + + code.comment('Agregando el caracter nulo al final') + code.sb(r.ZERO, r.HP) + code.addi(r.HP, r.HP, 1) +} + +export const builtins = { + concatString: concatString +} \ No newline at end of file diff --git a/RISC/generator.js b/RISC/generator.js index fd1a366..1f270cd 100644 --- a/RISC/generator.js +++ b/RISC/generator.js @@ -1,5 +1,6 @@ import { registers as r } from "./constants.js"; -import { stringTo32BitsArray } from "./utils.js"; +import { stringTo32BitsArray, stringTo1ByteArray } from "./utils.js"; +import { builtins } from "./builtins.js"; class Instruction { @@ -26,26 +27,19 @@ export class Generador { this.instrucciones = [] this.objectStack = [] this.depth = 0 - this.labelCount = 0 - this.labels = new Set(); + this._usedBuiltins = new Set() + this._labelCounter = 0; } - newLabel() { - let label; - do { - label = `label${this.labelCount++}`; - } while (this.labels.has(label)); - this.labels.add(label); - this.instrucciones.push(new Instruction(`${label}:`)); - return label; + getLabel() { + return `L${this._labelCounter++}` } - label(label) { - if (!this.labels.has(label)) { - this.labels.add(label); - this.instrucciones.push(new Instruction(`${label}:`)); - } + addLabel(label) { + label = label || this.getLabel() + this.instrucciones.push(new Instruction(`${label}:`)) + return label } add(rd, rs1, rs2) { @@ -216,6 +210,10 @@ export class Generador { this.instrucciones.push(new Instruction('j', label)) } + ret() { + this.instrucciones.push(new Instruction('ret')) + } + /* ------------------------------------------------------------------- */ /* ------------------------ Instrucción de Break ---------------------- */ @@ -225,10 +223,18 @@ export class Generador { this.instrucciones.push(new Instruction('sw', rs1, `${inmediato}(${rs2})`)) } + sb(rs1, rs2, inmediato = 0) { + this.instrucciones.push(new Instruction('sb', rs1, `${inmediato}(${rs2})`)) + } + lw(rd, rs1, inmediato = 0) { this.instrucciones.push(new Instruction('lw', rd, `${inmediato}(${rs1})`)) } + lb(rd, rs1, inmediato = 0) { + this.instrucciones.push(new Instruction('lb', rd, `${inmediato}(${rs1})`)) + } + li(rd, inmediato) { this.instrucciones.push(new Instruction('li', rd, inmediato)) } @@ -259,6 +265,14 @@ export class Generador { this.instrucciones.push(new Instruction('ecall')) } + callBuiltin(builtinName) { + if (!builtins[builtinName]) { + throw new Error(`Builtin ${builtinName} not found`) + } + this._usedBuiltins.add(builtinName) + this.jal(builtinName) + } + printInt(rd = r.A0) { if (rd !== r.A0) { @@ -338,17 +352,21 @@ export class Generador { break; case 'string': - const stringArray = stringTo32BitsArray(object.value); + const stringArray = stringTo1ByteArray(object.value); this.comment(`Pushing string ${object.value}`); - this.addi(r.T0, r.HP, 4); - this.push(r.T0); + // this.addi(r.T0, r.HP, 4); + // this.push(r.T0); + this.push(r.HP); - stringArray.forEach((block32bits) => { - this.li(r.T0, block32bits); + stringArray.forEach((charCode) => { + this.li(r.T0, charCode); // this.push(r.T0); - this.addi(r.HP, r.HP, 4); - this.sw(r.T0, r.HP); + // this.addi(r.HP, r.HP, 4); + // this.sw(r.T0, r.HP); + + this.sb(r.T0, r.HP); + this.addi(r.HP, r.HP, 1); }); length = 4; @@ -444,7 +462,15 @@ export class Generador { } toString() { + this.comment('Fin del programa') this.endProgram() + this.comment('Builtins') + + Array.from(this._usedBuiltins).forEach(builtinName => { + this.addLabel(builtinName) + builtins[builtinName](this) + this.ret() + }) return ` .data diff --git a/RISC/utils.js b/RISC/utils.js index 520c5f5..1c33577 100644 --- a/RISC/utils.js +++ b/RISC/utils.js @@ -32,5 +32,17 @@ export const stringTo32BitsArray = (str) => { resultado.push(0); } + return resultado; +} + +export const stringTo1ByteArray = (str) => { + const resultado = [] + let elementIndex = 0 + + while (elementIndex < str.length) { + resultado.push(str.charCodeAt(elementIndex)) + elementIndex++ + } + resultado.push(0) return resultado; } \ No newline at end of file diff --git a/tests.txt b/tests.txt index 9b0d5ef..a48831e 100644 --- a/tests.txt +++ b/tests.txt @@ -63,4 +63,24 @@ int jose = 5*7; System.out.println(jose > 45); System.out.println(!true); -System.out.println(!false); \ No newline at end of file +System.out.println(!false); + +int goku = 5; + +if(goku > 45){ + System.out.println("Jose" + " Daniel"); +} else if(goku == 5) { + if(goku < 10){ + System.out.println("goku es igual a 5 y menor que 10"); + } else { + System.out.println("goku es igual a 5 pero no menor que 10"); + } +} else if(goku > 20 && goku <= 45){ + System.out.println("goku está entre 20 y 45"); +} else { + if(78 > 5 || (false && true)){ + System.out.println(true); + } else { + System.out.println(false); + } +}