From 6f6c0caf1a507543ab1b091835238f9946c1bc2c Mon Sep 17 00:00:00 2001 From: Erick Leonardo Weil Date: Mon, 18 Mar 2019 22:13:51 -0400 Subject: [PATCH] =?UTF-8?q?adicionado=20la=C3=A7os=20de=20repeti=C3=A7?= =?UTF-8?q?=C3=A3o?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adicionado: - Botão 'mostrar bytecode' no canto direito do editor - Laços de repetição enquanto e faca-enquanto - Sistema de execução do código retrabalhado, ainda assim funciona 10 vezes mais lento que código no portugol Corrigido: - Expressões com operadores de mesma prioridade é calculada corretamente agora. - nem lembro mais. entre outras coisinhas. --- index.html | 35 +-- parser.js | 42 +++- vm.js | 672 ++++++++++++++++++++++++-------------------------- vmcompiler.js | 37 ++- 4 files changed, 409 insertions(+), 377 deletions(-) diff --git a/index.html b/index.html index fb33efe..723ec47 100644 --- a/index.html +++ b/index.html @@ -59,7 +59,7 @@ } } -
+
@@ -68,12 +68,16 @@
+
- - + + + - - + + + + @@ -180,7 +184,7 @@ interpreter.run(); }*/ - var lastvm = false; + //var lastvm = false; var lastvmState = STATE_ENDED; function executar() { @@ -194,15 +198,18 @@ var relevantTokens = tokenizer.getRelevantTokens(); var tree = new Parser(relevantTokens,string_cod).parse(); - console.log(tree.funcoes[0].statements); + console.log(tree); var compiler = new Compiler(tree,relevantTokens,string_cod,div_saida); compiler.compile(); - lastvm = new Vm(compiler.functions,string_cod,div_saida); - document.getElementById("hidden").innerHTML = lastvm.toString(); - lastvmState = lastvm.run(); - if(lastvmState == STATE_ENDED) lastvm.escreva("\n\nPrograma Terminado."); + //lastvm = new Vm(compiler.functions,string_cod,div_saida); + VMsetup(compiler.functions,string_cod,div_saida); + document.getElementById("hidden").innerHTML = VMtoString(); + //lastvmState = lastvm.run(); + lastvmState = VMrun(); + //VM_saidaDiv.value = VM_saida; + if(lastvmState == STATE_ENDED) escreva("\n\nPrograma Terminado."); } function receiveInput(textarea) @@ -210,12 +217,12 @@ if(lastvmState == STATE_WAITINGINPUT) { var saidadiv = textarea.value; - var entrada = saidadiv.substring(lastvm.saida.length,saidadiv.length); + var entrada = saidadiv.substring(VM_saida.length,saidadiv.length); if(entrada.endsWith("\n")) { - lastvmState = lastvm.run(); - if(lastvmState == STATE_ENDED) lastvm.escreva("\n\nPrograma Terminado."); + lastvmState = VMrun(); + if(lastvmState == STATE_ENDED) escreva("\n\nPrograma Terminado."); } } } diff --git a/parser.js b/parser.js index c41e192..9507965 100644 --- a/parser.js +++ b/parser.js @@ -2,6 +2,8 @@ var STATEMENT_declVar = 1; var STATEMENT_expr = 2; var STATEMENT_block = 3; var STATEMENT_se = 4; +var STATEMENT_enquanto = 5; +var STATEMENT_facaEnquanto = 6; function pmatch(index,tokens) @@ -192,11 +194,45 @@ class Parser { // "faca" block "enquanto" ( expression ) else if(t == T_enquanto) { - this.erro(tokens[i],"enquanto não implementado ainda"); + var logic_Expr = []; + var statements = []; + // i --> + // enquanto ( expr ) + i++; + if(tokens[i].id != T_parO) this.erro(tokens[i],"esqueceu de abrir os parênteses da condição do enquanto"); + i = this.parseExpressao(i,tokens,logic_Expr,0); + // i --> + // enquanto ( expr ) statementOrBlock + if(tokens[i].id != T_parC) this.erro(tokens[i],"esqueceu de fechar os parênteses da condição do enquanto"); + i++; + i = this.parseStatementOrBlock(i,tokens,statements); + + tree.push({id:STATEMENT_enquanto,index:tIndex,expr:logic_Expr[0],statements:statements}); } else if(t == T_faca) { - this.erro(tokens[i],"faca não implementado ainda"); + var logic_Expr = []; + var statements = []; + // i --> + // faca statementOrBlock enquanto ( expr ) + i++; + i = this.parseStatementOrBlock(i,tokens,statements); + + // i --> + // faca statementOrBlock enquanto ( expr ) + i++; + if(tokens[i].id != T_enquanto) this.erro(tokens[i],"esperando 'enquanto' aqui, a estrutura faca está incompleta"); + + // i --> + // faca statementOrBlock enquanto ( expr ) + i++; + if(tokens[i].id != T_parO) this.erro(tokens[i],"esqueceu de abrir os parênteses da condição do enquanto"); + i = this.parseExpressao(i,tokens,logic_Expr,0); + // i --> + // enquanto ( expr ) statementOrBlock + if(tokens[i].id != T_parC) this.erro(tokens[i],"esqueceu de fechar os parênteses da condição do enquanto"); + + tree.push({id:STATEMENT_facaEnquanto,index:tIndex,expr:logic_Expr[0],statements:statements}); } @@ -363,7 +399,7 @@ class Parser { var op = tokens[i].id; - if(getOpPrecedence(op) < prevPrecedence) // acabou aqui, tem que voltar pro operador anterior + if(getOpPrecedence(op) <= prevPrecedence) // acabou aqui, tem que voltar pro operador anterior { // voltar para o operador anterior tree.push(member0); diff --git a/vm.js b/vm.js index 101aa60..66dfb43 100644 --- a/vm.js +++ b/vm.js @@ -1,71 +1,71 @@ -var B_TRUE = 0; -var B_FALSE = 1; +const B_TRUE = 0; +const B_FALSE = 1; -var B_PUSH = 1; -var B_POP = 2; -var B_ADD = 3; -var B_SUB = 4; -var B_MUL = 5; -var B_DIV = 6; -var B_REM = 7; +const B_PUSH = 1; +const B_POP = 2; +const B_ADD = 3; +const B_SUB = 4; +const B_MUL = 5; +const B_DIV = 6; +const B_REM = 7; -var B_GOTO = 8; -var B_IFEQ = 9; -var B_IFNE = 10; -var B_IFLT = 11; -var B_IFGE = 12; -var B_IFGT = 13; -var B_IFLE = 14; +const B_GOTO = 8; +const B_IFEQ = 9; +const B_IFNE = 10; +const B_IFLT = 11; +const B_IFGE = 12; +const B_IFGT = 13; +const B_IFLE = 14; -var B_DUP = 15; -var B_INVOKE = 16; +const B_DUP = 15; +const B_INVOKE = 16; -var B_STORE = 17; -var B_LOAD = 18; +const B_STORE = 17; +const B_LOAD = 18; -var B_RET = 19; -var B_RETVALUE = 20; +const B_RET = 19; +const B_RETVALUE = 20; -var B_SHL = 21; -var B_SHR = 22; -var B_XOR = 23; -var B_AND = 24; //bitwise -var B_OR = 25; //bitwise +const B_SHL = 21; +const B_SHR = 22; +const B_XOR = 23; +const B_AND = 24; //bitwise +const B_OR = 25; //bitwise -var B_IFCMPEQ = 26; -var B_IFCMPNE = 27; -var B_IFCMPLT = 28; -var B_IFCMPLE = 29; -var B_IFCMPGT = 30; -var B_IFCMPGE = 31; -var B_NEG = 32; // arithmetic negation -var B_NOT = 33; // bitwise negation +const B_IFCMPEQ = 26; +const B_IFCMPNE = 27; +const B_IFCMPLT = 28; +const B_IFCMPLE = 29; +const B_IFCMPGT = 30; +const B_IFCMPGE = 31; +const B_NEG = 32; // arithmetic negation +const B_NOT = 33; // bitwise negation -var B_STOREGLOBAL = 34; -var B_LOADGLOBAL = 35; +const B_STOREGLOBAL = 34; +const B_LOADGLOBAL = 35; -var B_F2I = 36; // float to int +const B_F2I = 36; // float to int //var B_I2F = 37; // int to float -var B_I2S = 37; // int to str -var B_F2S = 38; // float to str -var B_B2S = 39; // bool to str -var B_C2S = 40; // char to str +const B_I2S = 37; // int to str +const B_F2S = 38; // float to str +const B_B2S = 39; // bool to str +const B_C2S = 40; // char to str -var B_SWAP = 41; // swap the elemtns of the stack +const B_SWAP = 41; // swap the elemtns of the stack // não existem opcodes pro or e and logico. //var B_LAND = 32; // logical or //var B_LOR = 33; // logical or // private -var B_WRITE = 100; -var B_WAITINPUT = 101; -var B_READ_INT = 102; -var B_READ_FLOAT = 103; -var B_READ_STRING = 104; -var B_READ_CHAR = 105; -var B_READ_BOOL = 106; +const B_WRITE = 100; +const B_WAITINPUT = 101; +const B_READ_INT = 102; +const B_READ_FLOAT = 103; +const B_READ_STRING = 104; +const B_READ_CHAR = 105; +const B_READ_BOOL = 106; function bytecodeName(c) { @@ -180,347 +180,307 @@ case B_INVOKE : } } + var STATE_ENDED = 0; var STATE_WAITINGINPUT = 1; -class StackFrame{ - constructor(parentFrame, globalVars,functionIndex, nVars, args) { - this.parentFrame = parentFrame; - this.globalVars = globalVars; - this.functionIndex = functionIndex; - this.vars = new Array(nVars); - if(args) for(var i=0;i= this.functions[this.frame.functionIndex].bytecode.length) - { - if(this.frame.parentFrame) + case B_PUSH: VM_stack[VM_si++] = VM_code[VM_i++]; break; + case B_POP: VM_si--; break; + case B_DUP: VM_stack[VM_si] = VM_stack[VM_si-1]; VM_si++; break; // o valor atual é colocado na frente. + case B_SWAP: + var v = VM_stack[VM_si-1]; + VM_stack[VM_si-1] = VM_stack[VM_si-2]; + VM_stack[VM_si-2] = v; + break; + case B_STORE: VM_vars[VM_code[VM_i++]] = VM_stack[--VM_si]; break; + case B_LOAD: VM_stack[VM_si++] = VM_vars[VM_code[VM_i++]]; break; + + case B_STOREGLOBAL: VM_globals[VM_code[VM_i++]] = VM_stack[--VM_si]; break; + case B_LOADGLOBAL: VM_stack[VM_si++] = VM_globals[VM_code[VM_i++]]; break; + + + case B_ADD: VM_stack[VM_si-2] = VM_stack[VM_si-2]+VM_stack[VM_si-1]; VM_si--; break; + case B_SUB: VM_stack[VM_si-2] = VM_stack[VM_si-2]-VM_stack[VM_si-1]; VM_si--; break; + case B_MUL: VM_stack[VM_si-2] = VM_stack[VM_si-2]*VM_stack[VM_si-1]; VM_si--; break; + case B_DIV: VM_stack[VM_si-2] = VM_stack[VM_si-2]/VM_stack[VM_si-1]; VM_si--; break; + case B_REM: VM_stack[VM_si-2] = VM_stack[VM_si-2]%VM_stack[VM_si-1]; VM_si--; break; + + case B_SHL: VM_stack[VM_si-2] = VM_stack[VM_si-2]>>VM_stack[VM_si-1]; VM_si--; break; + case B_SHR: VM_stack[VM_si-2] = VM_stack[VM_si-2]< VM_stack[VM_si-1] ? VM_code[VM_i++] : VM_i+1); VM_si -= 2; break; + case B_IFCMPGE: VM_i = (VM_stack[VM_si-2] >= VM_stack[VM_si-1] ? VM_code[VM_i++] : VM_i+1); VM_si -= 2; break; + + case B_GOTO: VM_i = VM_code[VM_i++]; break; + case B_IFEQ: VM_i = (VM_stack[--VM_si] == 0 ? VM_code[VM_i++] : VM_i+1); break; + case B_IFNE: VM_i = (VM_stack[--VM_si] != 0 ? VM_code[VM_i++] : VM_i+1); break; + case B_IFLT: VM_i = (VM_stack[--VM_si] < 0 ? VM_code[VM_i++] : VM_i+1); break; + case B_IFGE: VM_i = (VM_stack[--VM_si] >= 0 ? VM_code[VM_i++] : VM_i+1); break; + case B_IFGT: VM_i = (VM_stack[--VM_si] > 0 ? VM_code[VM_i++] : VM_i+1); break; + case B_IFLE: VM_i = (VM_stack[--VM_si] <= 0 ? VM_code[VM_i++] : VM_i+1); break; + + + case B_INVOKE: + // precisa criar um stackFrame + var methIndex = VM_code[VM_i++]; + var methArgsN = VM_code[VM_i++]; + var methArgs = []; + for(var i = 0;i 0) + { + var vI = VM_frame.length -1; + VM_funcIndex = VM_frame[vI].funcIndex; + VM_code = VM_functions[VM_funcIndex].bytecode; + VM_i = VM_frame[vI].i; + VM_stack = VM_frame[vI].stack; + VM_si = VM_frame[vI].si; + VM_vars = VM_frame[vI].vars; + + VM_frame.pop(); + } + else + { + return STATE_ENDED; + } + break; - var code = this.next(); - /*while(!code) - { - if(this.frame.parentFrame) + case B_RETVALUE: // return ; // com valor + var v = VM_stack[--VM_si]; + if(VM_frame.length > 0) { - this.frame = this.frame.parentFrame; - var code = this.next(); + var vI = VM_frame.length -1; + VM_funcIndex = VM_frame[vI].funcIndex; + VM_code = VM_functions[VM_funcIndex].bytecode; + VM_i = VM_frame[vI].i; + VM_stack = VM_frame[vI].stack; + VM_si = VM_frame[vI].si; + VM_vars = VM_frame[vI].vars; + + VM_frame.pop(); + //push + VM_stack[VM_si++] = v; } else { - return; + console.log("retornou:"+v); + return STATE_ENDED; } - }*/ - if(!code) code = B_RET; - switch(code) - { - case B_PUSH: this.frame.push(this.next()); break; - case B_POP: this.frame.pop(); break; - case B_DUP: var v = this.frame.pop(); this.frame.push(v); this.frame.push(v); break; - case B_SWAP: - var va = this.frame.pop(); - var vb = this.frame.pop(); - this.frame.push(va); - this.frame.push(vb); - break; - - case B_STORE: this.frame.setVar(this.next(),this.frame.pop()); break; - case B_LOAD: this.frame.push(this.frame.getVar(this.next())); break; - - case B_STOREGLOBAL: this.frame.setGlobal(this.next(),this.frame.pop()); break; - case B_LOADGLOBAL: this.frame.push(this.frame.getGlobal(this.next())); break; - - case B_ADD: - case B_SUB: - case B_MUL: - case B_DIV: - case B_REM: - case B_SHL: - case B_SHR: - case B_XOR: - case B_AND: - case B_OR: - case B_IFCMPEQ: - case B_IFCMPNE: - case B_IFCMPLT: - case B_IFCMPLE: - case B_IFCMPGT: - case B_IFCMPGE: - var vb = this.frame.pop(); - var va = this.frame.pop(); - switch(code) - { - case B_ADD: this.frame.push(va+vb); break; - case B_SUB: this.frame.push(va-vb); break; - case B_MUL: this.frame.push(va*vb); break; - case B_DIV: this.frame.push(va/vb); break; - case B_REM: this.frame.push(va%vb); break; - - case B_SHL: this.frame.push(va>>vb); break; - case B_SHR: this.frame.push(va< vb ? this.next() : this.frame.index+1); break; - case B_IFCMPGE: this.frame.index = (va >= vb ? this.next() : this.frame.index+1); break; - } - break; - - case B_GOTO: this.frame.index = this.next(); break; - case B_IFEQ: this.frame.index = (this.frame.pop() == 0 ? this.next() : this.frame.index+1); break; - case B_IFNE: this.frame.index = (this.frame.pop() != 0 ? this.next() : this.frame.index+1); break; - case B_IFLT: this.frame.index = (this.frame.pop() < 0 ? this.next() : this.frame.index+1); break; - case B_IFGE: this.frame.index = (this.frame.pop() >= 0 ? this.next() : this.frame.index+1); break; - case B_IFGT: this.frame.index = (this.frame.pop() > 0 ? this.next() : this.frame.index+1); break; - case B_IFLE: this.frame.index = (this.frame.pop() <= 0 ? this.next() : this.frame.index+1); break; - - - case B_INVOKE: - // precisa criar um stackFrame - var methIndex = this.next(); - var methArgsN = this.next(); - var methArgs = []; - for(var i = 0;i; // com valor - var v = this.frame.pop(); - if(this.frame.parentFrame) - { - this.frame = this.frame.parentFrame; - this.frame.push(v); - } - else - { - console.log("retornou:"+v); - return STATE_ENDED; - } - break; - - + break; + + - case B_NEG: this.frame.push(-this.frame.pop()); break; - case B_NOT: this.frame.push(~this.frame.pop()); break; - - case B_F2I: this.frame.push(Math.trunc(this.frame.pop())); break; - - case B_I2S: this.frame.push(""+this.frame.pop()); break; - case B_F2S: - var strFloat = ""+this.frame.pop(); - if(!strFloat.includes(".")) strFloat += ".0"; - this.frame.push(strFloat); - break; - case B_B2S: this.frame.push(this.frame.pop() == 0 ? "verdadeiro" : "falso"); break; - - case B_WRITE: - this.escreva(this.frame.pop()); - break; - case B_WAITINPUT: - return STATE_WAITINGINPUT; - break; - case B_READ_INT: - this.frame.push(parseInt(this.leia().trim())); - break; - case B_READ_FLOAT: - this.frame.push(parseFloat(this.leia().trim())); - break; - case B_READ_STRING: - this.frame.push(this.leia()); - break; - case B_READ_CHAR: - this.frame.push(this.leia()[0]); - break; - case B_READ_BOOL: - this.frame.push(this.leia().trim() == "verdadeiro"); - break; - default: - this.erro("invalid bytecode:"+code); - break; + case B_NEG: VM_stack[VM_si-1] = -VM_stack[VM_si-1]; break; + case B_NOT: VM_stack[VM_si-1] = ~VM_stack[VM_si-1]; break; + + case B_F2I: VM_stack[VM_si-1] = Math.trunc(VM_stack[VM_si-1]); break; + + case B_I2S: VM_stack[VM_si-1] = ""+VM_stack[VM_si-1]; break; + case B_F2S: + var strFloat = ""+VM_stack[VM_si-1]; + if(!strFloat.includes(".")) strFloat += ".0"; + VM_stack[VM_si-1] = strFloat; + break; + case B_B2S: VM_stack[VM_si-1] = (VM_stack[VM_si-1] == 0 ? "verdadeiro" : "falso"); break; + + case B_WRITE: + escreva(VM_stack[--VM_si]); + break; + case B_WAITINPUT: + return STATE_WAITINGINPUT; + break; + case B_READ_INT: + VM_stack[VM_si++] = parseInt(leia().trim()); + break; + case B_READ_FLOAT: + VM_stack[VM_si++] = parseFloat(leia().trim()); + break; + case B_READ_STRING: + VM_stack[VM_si++] = leia(); + break; + case B_READ_CHAR: + VM_stack[VM_si++] = leia()[0]; + break; + case B_READ_BOOL: + VM_stack[VM_si++] = leia().trim() == "verdadeiro"; + break; + default: + erro("invalid bytecode:"+code); + return STATE_ENDED; + break; + } + } + +} + +function VMtoString() +{ + var str = ""; + + for(var i =8;i