diff --git a/MVaP/MVaP-v0/MVaP/index.html b/MVaP/MVaP-v0/MVaP/index.html new file mode 100644 index 0000000..7b40946 --- /dev/null +++ b/MVaP/MVaP-v0/MVaP/index.html @@ -0,0 +1,72 @@ + + + + + MVàP + + + + + + + + +

Machine Virtuelle à Pile

+ +

Historique

+ Blabla sur la MVàP... + +

Documentation

+ Toute la doc +

+ lorem ipsum +

La MVàP

+

Entrez le code

+
+ +
+ +

Exécution

+ + + + + + + + + +
+
+    
+
+ + + + diff --git a/MVaP/MVaP-v0/MVaP/js/CBaP.js b/MVaP/MVaP-v0/MVaP/js/CBaP.js new file mode 100644 index 0000000..9864c57 --- /dev/null +++ b/MVaP/MVaP-v0/MVaP/js/CBaP.js @@ -0,0 +1,216 @@ +/** + * Code Binaire pour Machine Virtuelle à Pile. + * Les flottants sont des double qui prennent la place de 2 ints. + * Les adresses sont des int. + * CALL empile l'adresse de retour et la vauler du framePointer dans la pile. + */ +public class CBaP { + + + + pc = 0; + fp = 0; + stack; + program; + const SizeofDouble = 2; + + _debug = false; + + CBaP(program, debug, stackSize) { + this.program = program; + this._debug = debug; + this.stack = new Pile(stackSize); + } + + dumpInstruction(ii, out) { + let i = ii; + switch(program.get_int(i)) { + case AssembleMVaP.ADD: out.print("ADD "); break; + case AssembleMVaP.SUB: out.print("SUB "); break; + case AssembleMVaP.MUL: out.print("MUL "); break; + case AssembleMVaP.DIV: out.print("DIV "); break; + case AssembleMVaP.INF: out.print("INF "); break; + case AssembleMVaP.INFEQ: out.print("INFEQ "); break; + case AssembleMVaP.SUP: out.print("SUP "); break; + case AssembleMVaP.SUPEQ: out.print("SUPEQ "); break; + case AssembleMVaP.EQUAL: out.print("EQUAL "); break; + case AssembleMVaP.NEQ: out.print("NEQ "); break; + + case AssembleMVaP.FADD: out.print("FADD "); break; + case AssembleMVaP.FSUB: out.print("FSUB "); break; + case AssembleMVaP.FMUL: out.print("FMUL "); break; + case AssembleMVaP.FDIV: out.print("FDIV "); break; + case AssembleMVaP.FINF: out.print("FINF "); break; + case AssembleMVaP.FINFEQ: out.print("FINFEQ"); break; + case AssembleMVaP.FSUP: out.print("FSUP "); break; + case AssembleMVaP.FSUPEQ: out.print("FSUPEQ"); break; + case AssembleMVaP.FEQUAL: out.print("FEQUAL"); break; + case AssembleMVaP.FNEQ: out.print("FNEQ "); break; + case AssembleMVaP.ITOF: out.print("ITOF "); break; + case AssembleMVaP.FTOI: out.print("FTOI "); break; + + case AssembleMVaP.RETURN: out.print("RETURN"); break; + case AssembleMVaP.POP: out.print("POP "); break; + case AssembleMVaP.READ: out.print("READ "); break; + case AssembleMVaP.WRITE: out.print("WRITE "); break; + case AssembleMVaP.WRITEF: out.print("WRITEF"); break; + case AssembleMVaP.PADD: out.print("PADD "); break; + case AssembleMVaP.PUSHGP: out.print("PUSHGP"); break; + case AssembleMVaP.PUSHFP: out.print("PUSHFP"); break; + case AssembleMVaP.DUP: out.print("DUP "); break; + + case AssembleMVaP.PUSHI: out.print("PUSHI "); out.format("%7d ", program.get_int(++i)); break; + case AssembleMVaP.PUSHG: out.print("PUSHG "); out.format("%7d ", program.get_int(++i)); break; + case AssembleMVaP.STOREG: out.print("STOREG"); out.format("%7d ", program.get_int(++i)); break; + case AssembleMVaP.PUSHL: out.print("PUSHL "); out.format("%7d ", program.get_int(++i)); break; + case AssembleMVaP.STOREL: out.print("STOREL"); out.format("%7d ", program.get_int(++i)); break; + case AssembleMVaP.PUSHR: out.print("PUSHR "); out.format("%7d ", program.get_int(++i)); break; + case AssembleMVaP.STORER: out.print("STORER"); out.format("%7d ", program.get_int(++i)); break; + case AssembleMVaP.FREE: out.print("FREE "); out.format("%7d ", program.get_int(++i)); break; + case AssembleMVaP.ALLOC: out.print("ALLOC "); out.format("%7d ", program.get_int(++i)); break; + + case AssembleMVaP.PUSHF: out.print("PUSHF "); ++i; out.format("%7.3f ", program.get_double(++i)); break; + + case AssembleMVaP.JUMP: out.print("JUMP "); out.format("%7d ", program.get_int(++i)); break; + case AssembleMVaP.JUMPF: out.print("JUMPF "); out.format("%7d ", program.get_int(++i)); break; + case AssembleMVaP.JUMPI: out.print("JUMPI "); out.format("%7d ", program.get_int(++i)); break; + case AssembleMVaP.CALL: out.print("CALL "); out.format("%7d ", program.get_int(++i)); break; + case AssembleMVaP.HALT: out.print("HALT "); break; + default: System.err.println("Code inconnu "+program.get_int(i)+" ligne "+i); + } + if (i == ii) out.print(" "); + return i; + } + + public void dumpProgram(PrintStream out) { + // out.println(program.toString(true)); + // out.println(program.toString()); + out.println(" Adr | Instruction"); + out.println("-----+---------------"); + for(int i = 0; i < program.getSize(); i++) { + out.format("%4d | ", i); + i = dumpInstruction(i, out); + out.println(); + } + } + + private void _call(int label) { + push(pc+1); + push(fp); + fp = size(); + pc = label; + } + + private void _return() { + while(size() > fp) + pop(); + fp = pop(); + pc = pop(); + } + + private BufferedReader input = null; + private int _read() { + try { + if (input == null) + input = new BufferedReader(new InputStreamReader(System.in)); + return Integer.parseInt(input.readLine()); + } catch (Exception e) { + System.err.println(e); + System.exit(1); + return 0; + } + } + + public boolean execute() { + if (_debug) { + dumpProgram(System.out); + System.err.println(); + System.err.println(" pc | | fp pile"); + System.err.println("===================================================="); + } + pc = 0; + while (true) { + if (_debug) { + System.err.format("%4d | ", pc); + dumpInstruction(pc, System.err); + System.err.format("| %4d %s\n", fp, stack.toString()); + } + try { + int p1, p2; // utile pour être sûr de l'ordre des pop() ! + double d1, d2; + switch(program.get_int(pc++)) { + case AssembleMVaP.ADD: p1 = pop(); p2 = pop(); push(p2 + p1); break; + case AssembleMVaP.SUB: p1 = pop(); p2 = pop(); push(p2 - p1); break; + case AssembleMVaP.MUL: p1 = pop(); p2 = pop(); push(p2 * p1); break; + case AssembleMVaP.DIV: p1 = pop(); p2 = pop(); push(p2 / p1); break; + case AssembleMVaP.INF: p1 = pop(); p2 = pop(); push(p2 < p1 ? 1 : 0); break; + case AssembleMVaP.INFEQ: p1 = pop(); p2 = pop(); push(p2 <= p1 ? 1 : 0); break; + case AssembleMVaP.SUP: p1 = pop(); p2 = pop(); push(p2 > p1 ? 1 : 0); break; + case AssembleMVaP.SUPEQ: p1 = pop(); p2 = pop(); push(p2 >= p1 ? 1 : 0); break; + case AssembleMVaP.EQUAL: p1 = pop(); p2 = pop(); push(p2 == p1 ? 1 : 0); break; + case AssembleMVaP.NEQ: p1 = pop(); p2 = pop(); push(p2 != p1 ? 1 : 0); break; + + case AssembleMVaP.FADD: d1 = pop_double(); d2 = pop_double(); push(d2 + d1); break; + case AssembleMVaP.FSUB: d1 = pop_double(); d2 = pop_double(); push(d2 - d1); break; + case AssembleMVaP.FMUL: d1 = pop_double(); d2 = pop_double(); push(d2 * d1); break; + case AssembleMVaP.FDIV: d1 = pop_double(); d2 = pop_double(); push(d2 / d1); break; + case AssembleMVaP.FINF: d1 = pop_double(); d2 = pop_double(); push(d2 < d1 ? 1 : 0); break; + case AssembleMVaP.FINFEQ: d1 = pop_double(); d2 = pop_double(); push(d2 <= d1 ? 1 : 0); break; + case AssembleMVaP.FSUP: d1 = pop_double(); d2 = pop_double(); push(d2 > d1 ? 1 : 0); break; + case AssembleMVaP.FSUPEQ: d1 = pop_double(); d2 = pop_double(); push(d2 >= d1 ? 1 : 0); break; + case AssembleMVaP.FEQUAL: d1 = pop_double(); d2 = pop_double(); push(d2 == d1 ? 1 : 0); break; + case AssembleMVaP.FNEQ: d1 = pop_double(); d2 = pop_double(); push(d2 != d1 ? 1 : 0); break; + + case AssembleMVaP.FTOI: push((int)pop_double()); break; + case AssembleMVaP.ITOF: push((double)pop()); break; + + case AssembleMVaP.RETURN: _return(); break; + case AssembleMVaP.POP: pop(); break; + case AssembleMVaP.READ: push(_read()); break; + case AssembleMVaP.WRITE: System.out.format("%7d\n", peek()); break; + case AssembleMVaP.WRITEF: System.out.format("%7.3f\n", peek_double()); break; + case AssembleMVaP.PADD: p1 = pop(); p2 = pop(); push(p2 + p1); break; + case AssembleMVaP.PUSHGP: push(0); break; + case AssembleMVaP.PUSHFP: push(fp); break; + case AssembleMVaP.DUP: push(peek()); break; + + case AssembleMVaP.PUSHI: push(program.get_int(pc++)); break; + case AssembleMVaP.PUSHG: push(get(program.get_int(pc++))); break; + case AssembleMVaP.STOREG: set(program.get_int(pc++), pop()); break; + // ajouter -2 si adresse négative ? + case AssembleMVaP.PUSHL: push(get(fp+program.get_int(pc++))); break; + case AssembleMVaP.STOREL:set(fp+program.get_int(pc++), pop()); break; + case AssembleMVaP.PUSHR: push(get(pop()+program.get_int(pc++)));break; + case AssembleMVaP.STORER:p1 = pop(); p2 = pop(); set(p2+program.get_int(pc++), p1); break; + case AssembleMVaP.FREE: doPop(program.get_int(pc++)); break; + case AssembleMVaP.ALLOC: doPush(program.get_int(pc++)); break; + + case AssembleMVaP.PUSHF: push(program.get_int(pc++)); push(program.get_int(pc++)); break; + + case AssembleMVaP.JUMP: pc = program.get_int(pc); break; + case AssembleMVaP.JUMPF: if (pop() == 0) pc = program.get_int(pc); else pc++; break; + case AssembleMVaP.JUMPI: pc = program.get_int(pc)+pop(); break; + case AssembleMVaP.CALL: _call(program.get_int(pc)); break; + case AssembleMVaP.HALT: return true; + default: System.err.println("Code inconnu "+program.get_int(pc)+" ligne "+pc); return false; + } + } catch (ArrayIndexOutOfBoundsException e) { + System.err.println(stack.getException()); + return false; + } + } + } + + void push(int i) { stack.push(i); } + int pop() { return stack.pop_int(); } + void push(double d) { stack.push(d); } + double pop_double() { return stack.pop_double(); } + int peek() { return stack.peek_int(); } + double peek_double() { return stack.peek_double(); } + int size() { return stack.getSize(); } + void set(int index, int i) { stack.set(index, i); } + int get(int index) { return stack.get_int(index); } + + void doPop(int nb) { for(; nb > 0; nb--) stack.pop_int(); } + void doPush(int nb) { for(; nb > 0; nb--) stack.push(0); } +} diff --git a/MVaP/MVaP-v0/MVaP/js/LexerMVaP.dot b/MVaP/MVaP-v0/MVaP/js/LexerMVaP.dot new file mode 100644 index 0000000..be9c7c5 --- /dev/null +++ b/MVaP/MVaP-v0/MVaP/js/LexerMVaP.dot @@ -0,0 +1,33 @@ +digraph LexerMVaP { + Start -> Start [label="space "]; + Start -> Id [label="[A-Z]"]; + Id -> Id [label="[A-Z]"]; + + Start -> Int [label="[-+0-9]"]; + Int -> Int [label="[0-9]"]; + Int -> Decimal [label="."]; + Int -> E [label="E"]; + + Decimal -> Decimal [label="[0-9]"]; + Decimal -> E [label="E"]; + + E -> Exponent [label="[-+0-9]"]; + Exponent -> Exponent [label="[0-9]"]; + + Start -> error [label="*"]; + Id -> error [label="*"]; + Int -> error [label="*"]; + Decimal -> error [label="*"]; + E -> error [label="*"]; + Exponent -> error [label="*"]; + +edge [color=red, fontcolor=red]; + + Start -> Start [label="NL/[Newline] "]; + Id -> Start [label="space/ID"]; + Int -> Start [label="space/Int"]; + Decimal -> Start [label="space/Float"]; + Exponent -> Start [label="space/Float"]; + + { rank = same; Decimal E Exponent } +} diff --git a/MVaP/MVaP-v0/MVaP/js/LexerMVaP.png b/MVaP/MVaP-v0/MVaP/js/LexerMVaP.png new file mode 100644 index 0000000..684d618 Binary files /dev/null and b/MVaP/MVaP-v0/MVaP/js/LexerMVaP.png differ diff --git a/MVaP/MVaP-v0/MVaP/js/MVaP.js b/MVaP/MVaP-v0/MVaP/js/MVaP.js new file mode 100644 index 0000000..6466a56 --- /dev/null +++ b/MVaP/MVaP-v0/MVaP/js/MVaP.js @@ -0,0 +1,374 @@ +// MVàP + +let debugLexer = false; +let debug = true; + +/** token lexicaux */ +const T_ID = 0; +const T_INT = 1; +const T_FLOAT = 2; +const T_SPACE = 3; +const T_NL = 4; +const T_ERROR = 5; +const T_EOF = 6; + +T_Text = [ "T_ID", "T_INT", "T_FLOAT", "T_SPACE", "T_NL", "T_ERROR", "T_EOF" ]; + +/** token grammaticaux */ +const INSTR1 = 0; +const INSTR2 = 1; +const INT = 2; +const INSTR2F = 3; +const FLOAT = 4; +const LABEL = 5; +const JUMP = 6; +const NEWLINE = 7; + +class MVaP { + + codes = [ // pour l'interprète de MVàP + [ "ADD", INSTR1, () => { let p1 = this.stack.pop(); let p2 = this.stack.pop(); this.stack.push(p2+p1); } ], + [ "SUB", INSTR1, () => { let p1 = this.stack.pop(); let p2 = this.stack.pop(); this.stack.push(p2-p1); } ], + [ "MUL", INSTR1, () => { let p1 = this.stack.pop(); let p2 = this.stack.pop(); this.stack.push(p2*p1); } ], + [ "DIV", INSTR1, () => { let p1 = this.stack.pop(); let p2 = this.stack.pop(); this.stack.push(Math.floor(p2/p1)); } ], + [ "INF", INSTR1, () => { let p1 = this.stack.pop(); let p2 = this.stack.pop(); this.stack.push(p2 { let p1 = this.stack.pop(); let p2 = this.stack.pop(); this.stack.push(p2<=p1?1:0); } ], + [ "SUP", INSTR1, () => { let p1 = this.stack.pop(); let p2 = this.stack.pop(); this.stack.push(p2>p1?1:0); } ], + [ "SUPEQ", INSTR1, () => { let p1 = this.stack.pop(); let p2 = this.stack.pop(); this.stack.push(p2>=p1?1:0); } ], + [ "EQUAL", INSTR1, () => { let p1 = this.stack.pop(); let p2 = this.stack.pop(); this.stack.push(p2==p1?1:0); } ], + [ "NEQ", INSTR1, () => { let p1 = this.stack.pop(); let p2 = this.stack.pop(); this.stack.push(p2!=p1?1:0); } ], + [ "FADD", INSTR1, () => { let d1 = this.stack.popFloat64(); let d2 = this.stack.popFloat64(); this.stack.pushFloat64(d2+d1); } ], + [ "FSUB", INSTR1, () => { let d1 = this.stack.popFloat64(); let d2 = this.stack.popFloat64(); this.stack.pushFloat64(d2-d1); } ], + [ "FMUL", INSTR1, () => { let d1 = this.stack.popFloat64(); let d2 = this.stack.popFloat64(); this.stack.pushFloat64(d2*d1); } ], + [ "FDIV", INSTR1, () => { let d1 = this.stack.popFloat64(); let d2 = this.stack.popFloat64(); this.stack.pushFloat64(d2/d1); } ], + [ "FINF", INSTR1, () => { let d1 = this.stack.popFloat64(); let d2 = this.stack.popFloat64(); this.stack.push(d2 { let d1 = this.stack.popFloat64(); let d2 = this.stack.popFloat64(); this.stack.push(d2<=d1?1:0); } ], + [ "FSUP", INSTR1, () => { let d1 = this.stack.popFloat64(); let d2 = this.stack.popFloat64(); this.stack.push(d2>d1?1:0); } ], + [ "FSUPEQ", INSTR1, () => { let d1 = this.stack.popFloat64(); let d2 = this.stack.popFloat64(); this.stack.push(d2>=d1?1:0); } ], + [ "FEQUAL", INSTR1, () => { let d1 = this.stack.popFloat64(); let d2 = this.stack.popFloat64(); this.stack.push(d2==d1?1:0); } ], + [ "FNEQ", INSTR1, () => { let d1 = this.stack.popFloat64(); let d2 = this.stack.popFloat64(); this.stack.push(d2!=d1?1:0); } ], + [ "ITOF", INSTR1, () => { let p1 = this.stack.pop(); this.trace("ITOF "+p1); this.stack.pushFloat64(p1); } ], + [ "FTOI", INSTR1, () => { this.stack.push(Math.round(this.stack.popFloat64())); } ], + [ "RETURN", INSTR1, () => { while(this.stack.getSize() > this.fp) this.stack.pop(); + this.fp = this.stack.pop(); this.pc = this.stack.pop(); } ], + [ "POP", INSTR1, () => { this.stack.pop(); } ], + [ "READ", INSTR1, () => { this.stack.push(0); } ], // on lit toujours 0 (idée : prendre le contenu d'un input de type text spécial + [ "WRITE", INSTR1, () => { this.trace(this.stack.peek()+"\n"); } ], + [ "WRITEF", INSTR1, () => { this.trace(this.stack.peekFloat64()+"\n"); } ], + [ "PADD", INSTR1, () => { let p1 = this.stack.pop(); let p2 = this.stack.pop(); this.stack.push(p2+p1); } ], + [ "PUSHGP", INSTR1, () => { this.stack.push(0); } ], + [ "PUSHFP", INSTR1, () => { this.stack.push(this.fp); } ], + [ "DUP", INSTR1, () => { this.stack.push(this.stack.peek()); } ], + + [ "PUSHI", INSTR2, () => { this.stack.push(this.program.get(this.pc++)); } ], + [ "PUSHG", INSTR2, () => { this.stack.push(this.stack.get(this.program.get(this.pc++)));} ], + [ "STOREG", INSTR2, () => { this.stack.set(this.program.get(this.pc++), this.stack.pop())} ], + [ "PUSHL", INSTR2, () => { this.stack.push(this.stack.get(this.fp+this.program.get(this.pc++))); } ], + [ "STOREL", INSTR2, () => { this.stack.set(this.fp+this.program.get(this.pc++), this.stack.pop()); } ], + [ "PUSHR", INSTR2, () => { this.stack.push(this.stack.get(this.stack.pop()+this.program.get(this.pc++))); } ], + [ "STORER", INSTR2, () => { let p1 = this.stack.pop(); let p2 = this.stack.pop(); this.stack.set(p2+this.program.get(this.pc++)); } ], + [ "FREE", INSTR2, () => { this.stack.doPop(this.program.get(this.pc++)); } ], + [ "ALLOC", INSTR2, () => { this.stack.doPush(this.program.get(this.pc++)); } ], + [ "PUSHF", INSTR2F, () => { this.stack.pushFloat64(this.program.getFloat64(this.pc)); this.pc += 2; } ], + [ "CALL", JUMP, () => { this.stack.push(this.pc+1); this.stack.push(this.fp); + this.fp = this.stack.getSize(); + this.pc = this.program.get(this.pc); } ], + [ "JUMP", JUMP, () => { this.pc = this.program.get(this.pc); } ], + [ "JUMPF", JUMP, () => { if (this.stack.pop()==0) this.pc = this.program.get(this.pc); + else this.pc++; } ], + [ "JUMPI", JUMP, () => { this.pc = this.program.get(this.pc)+this.stack.pop();} ], + + [ "HALT", INSTR1, () => { return true; } ], + + [ "LABEL", LABEL, /* erreur interne */ ] + ]; + /*** Ajouter instr : READF WRITEF POPF */ + + tokens = []; // indexe le tableau codes sur son premier élément + + text = ""; + + // + // see LexerMVaP.png for the DFA diagram + state = "Start"; + text; // le texte à analyser + index = 0; // index dans la chaîne text + lineNumber = 1; + + transitions = [ + { state: "Start", next: "Start", test: (c) => { return c == "\n"; }, token: T_NL }, + { state: "Start", next: "Start", test: (c) => { return c.trim() == ""; }, token: false }, + { state: "Start", next: "Id", test: (c) => { return "A" <= c && c <= "Z"; }, token: false }, + { state: "Id", next: "Id", test: (c) => { return "A" <= c && c <= "Z"; }, token: false}, + { state: "Id", next: "Start", test: (c) => { return c.trim() == ""; }, token: T_ID}, + { state: "Start", next: "Int", test: (c) => { return ("0" <= c && c <= "9")||c=="-"||c=="+"; }, token: false }, + { state: "Int", next: "Int", test: (c) => { return "0" <= c && c <= "9"; }, token: false }, + { state: "Int", next: "Start", test: (c) => { return c.trim() == ""; }, token: T_INT }, + { state: "Int", next: "Decimal", test: (c) => { return c == "."; }, token: false }, + { state: "Int", next: "E", test: (c) => { return c == "E"; }, token: false }, + { state: "Decimal", next: "Decimal", test: (c) => { return "0" <= c && c <= "9"; }, token: false }, + { state: "Decimal", next: "E", test: (c) => { return c == "E"; }, token: false }, + { state: "Decimal", next: "Start", test: (c) => { return c.trim() == ""; }, token: T_FLOAT }, + { state: "E", next: "Exponent", test: (c) => { return ("0"<=c && c<="9")||c=="-"||c=="+"; }, token: false }, + { state: "Exponent", next: "Exponent", test: (c) => { return "0" <= c && c <= "9"; }, token: false }, + { state: "Exponent", next: "Start", test: (c) => { return c.trim() == ""; }, token: T_FLOAT } + // else: error + ]; + + initLexer() { + this.index = 0; + this.lineNumber = 1 + console.log("*****************\n* C'est parti *\n*****************"); + } + + // Donne la transition correspondante à l'état courant et au caractère entrant + transition(c) { + for (let v of this.transitions.values()) { + // on aurait pu indexer les transitions sur state au lieu de tout énumérer + if (this.state == v.state && v.test(c)) { + return v; + } + } + return T_ERROR; + } + + yytext = ""; // contient le texte du jeton syntaxique (nommé comme dans lex/yacc) + + + nextToken() { + let c; + let trans; + while (true) { + c = this.text[this.index]; + if (c === undefined) + return T_EOF; + c = c.toUpperCase(); + trans = this.transition(c); + if (trans == T_ERROR) { this.yytext += c; return T_ERROR; } + if (this.state != trans.next && this.state == "Start") this.yytext =""; + + this.state = trans.next; + this.index++; + + if (Number.isInteger(trans.token)) { + break; + } + this.yytext += c; + } + + // séparateur significatif + if (c == "\n") { + if (trans.token != T_NL) { + this.index--; // ne pas manger la fin de ligne non prise en compte + // une autre façon de dire est que l'on n'incrémente pas l'index sur le renvoi de token + // sauf en cas de token constitué de séparateur + } else + this.lineNumber++; // on en profite pour compter la ligne + } + // console.log(" line " + this.lineNumber + " " + trans.token + " '" + yytex + "' i="+i); + return trans.token; + } + // + + // + + /** Grammaire des instructions + instr + : INSTR1 T_NL + | INSTR2 T_INT T_NL + | JUMP T_INT T_NL + | INSTR2F T_FLOAT T_NL + | LABEL T_NL + | T_NL + ; + */ + + program;// Pile contenant le programme compilé + adressesLabels; // adresse des étiquettes pour l'assemblage + + analyse() { + + this.initLexer(); + + let token; // le jeton lexical courant + let state = NEWLINE; // état de l'analyseur grammatical (ici le précédent syntagme grammatical) + this.program = new Pile(); + this.adressesLabels = []; + + while (true) { + this.yytext = ""; + token = this.nextToken(); + if (debugLexer) + console.log("** nextToken line "+this.lineNumber+" token "+token+" "+T_Text[token]+" '" +this.yytext+"' index "+this.index+" state "+state); + + switch(token) { + case T_EOF: + return true; + case T_ID: + let k = this.tokens[this.yytext]; + if (k === undefined || state != NEWLINE) return false; + state = this.codes[k][1]; + if (state != LABEL) { // pas d'instruction LABEL dans le code + this.program.push(k); + } + break; + case T_INT: + if (state == LABEL) { // on mémorise juste l'adresse pour la passe d'assemblage + this.adressesLabels[Number(this.yytext)] = this.program.getSize(); // ± 1 who knows? + } else if(state == INSTR2 || state == JUMP) { + this.program.push(Number(this.yytext)); + } else return false; + state = INT; + break; + case T_FLOAT: + if (state != INSTR2F) return false; + state = FLOAT; + this.program.pushFloat64(Number(this.yytext)); + break; + case T_NL: + if (state == INSTR2 || state == JUMP || state == INSTR2F) return false; + state = NEWLINE; + break; + case T_ERROR: + return false; + default: + alert("Erreur interne prévenir la maintenance d'urgence"); + return false; + } + } + console.log("Programme correct syntaxiquement"); + return true; + } + + assemble() { + // change les numéros d'étiquettes par les adresses des instructions pointées. + console.log("Label "+this.adressesLabels); + console.log(this.dumpProgram()); + + for (let i = 0; i < this.program.getSize(); i++) { + let k = this.program.get(i); + // Attention il faut compter si par malchance un entier = code d'un saut + switch (this.codes[k][1]) { + case INSTR1: + break; + case INSTR2: + i++; // on saute l'entier qui suit + break; + case INSTR2F: + i += 2; // on saute le flottant qui suit + break; + case JUMP: // met à jour l'adresse du saut + i++; + console.log("--- set "+i); + this.program.set(i, this.adressesLabels[this.program.get(i)]); + break; + default: + alert("Erreur assemblage"); + } + } + // console.log(this.dumpProgram()); + } + // + + + dumpInstruction(i, result) { + let code = this.codes[this.program.get(i)]; + result += code[0].padEnd(6, ' '); + switch (code[1]) { + case INSTR2: + case JUMP: + result += this.program.get(++i).toString().padStart(7, ' '); + break; + case INSTR2F: + result += this.program.getFloat64(++i).toString().padStart(7, ' '); + i++; + break; + default: + result += " "; + } + + return [i, result]; + } + + dumpProgram() { + let result = ""; + result += this.program + "\n"; + + result += " Adr | Instruction\n-----+---------------\n"; + for(let i = 0; i < this.program.getSize(); i++) { + result += i.toString().padStart(4, " ")+" | "; + [i, result] = this.dumpInstruction(i, result); + result += "\n"; + } + return result; + } + + constructor() { + // init tokens + for (let k of this.codes.keys()) + this.tokens[this.codes[k][0]] = k; + } + + // charge et compile le code + load(text) { + this.text = text; + // on insère une fin de ligne si le texte n'en a pas à sa fin + if (text[text.length-1] != "\n") this.text = text+"\n"; + if (! this.analyse()) { + alert("Erreur ligne "+this.lineNumber+" sur '" +this.yytext+"'"); + return; + } + this.assemble(); + } + + pc = 0; + fp = 0; + stack; + + runcode(maxSteps, d) { + debug = d; + //for (let i = 0; i < this.codes.length; i++) console.log(i+ " "+ this.codes[i][0]); + this.pc = 0; + this.fp = 0; + this.stack = new Pile(); + + try { + if (debug) + this.trace("Programme\n"+this.dumpProgram() + "\nTraces exécution\n" + + " pc | Instruction | fp pile\n" + + "=====+===============+=============================\n"); + + for (let i= 0; i < maxSteps; i++) // while (true) + { + if (this.pc < 0 || this.pc >= this.program.getSize()) + break; + + if (debug) { + let s = this.pc.toString().padStart(4, " ")+" | "; + let junk; + [junk, s] = this.dumpInstruction(this.pc, s); + s += " |"+this.fp.toString().padStart(4,' ')+' '+this.stack.toString()+"\n"; + this.trace(s); + } + + if (this.codes[this.program.get(this.pc++)][2]() === true) + break; + } + } catch(e) { + this.trace(e); + console.error(e); + } + } + + trace(s) { + traces.innerText += s; + console.log(s); + } + +} + + + + + + diff --git a/MVaP/MVaP-v0/MVaP/js/Pile.js b/MVaP/MVaP-v0/MVaP/js/Pile.js new file mode 100644 index 0000000..f78f210 --- /dev/null +++ b/MVaP/MVaP-v0/MVaP/js/Pile.js @@ -0,0 +1,153 @@ +// Class Pile +// Auteur : Jacques Madelaine + +// Une Pile est essentiellement une pile d'entiers ("int32") +// Elle peut aussi empiler et dépiler des flottants définis sur 64 bits. +// L'index est sur les entiers. + +// Rappel : en JavaScript les Number sont tous stockés comme des flottants 64 bits. +// Il faut donc voir cette Pile comme un objet pédagogique +// et non une implémentation optimale en JavaScipt. + +"use strict"; + +class Pile { + buffer; // ArrayBuffer de bytes + pile; // On va utiliser 4 bytes pour les entiers et 8 pour les flottants + haut = 0; // index de sommet de pile en bytes + + // size : taille en bytes de la pile + constructor(size) { + if (size === undefined) + size = 1000; + + this.buffer = new ArrayBuffer(size); + this.pile = new DataView(this.buffer); + } + + push(i) { + if (! Number.isInteger(i)) + throw new TypeError("Try to push a non integer"); + this.pile.setInt32(this.haut, i); + this.haut += 4; + } + + doPush(nb) { for(; nb > 0; nb--) this.push(0); } + + pop() { + this.haut -= 4; + return this.pile.getInt32(this.haut); + } + + doPop(nb) { for(; nb > 0; nb--) this.pop(); } + + peek() { + return this.pile.getInt32(this.haut-4); + } + + set(index, i) { + if (! Number.isInteger(i)) + throw new TypeError("Try to set a non integer"); + this.pile.setInt32(index*4, i); + } + + get(index) { + return this.pile.getInt32(index*4); + } + + + pushFloat64(f) { + this.pile.setFloat64(this.haut, f); + this.haut += 8; + } + + popFloat64() { + this.haut -= 8; + return this.pile.getFloat64(this.haut); + } + + peekFloat64() { + return this.pile.getFloat64(this.haut-8); + } + + setFloat64(index, f) { + this.pile.setFloat64(index*4, f); + } + + getFloat64(index) { + return this.pile.getFloat64(index*4); + } + + getMaxSize() { + return this.buffer.byteLength/2; + } + + getSize() { + return this.haut/4; + } + + toString() { + let out = "[ "; + for (let i = 0; i < this.getSize(); i++) + out += this.get(i) + ", "; + return out + " ] " + this.getSize(); + } + +} + + +/* + +let p = new Pile(); +try { + let d = 12.34; + let i = 0x7FFFFFFF; + let j = 0; + p.push(i); + j = p.peek(); + console.log(i + " =?= " + j); + + let N = 5; + for(let n = 0; n < N; n++) { + p.push(n); + console.log("push "+n+" " + n); + } + + console.log("get(2) " + p.get(2)); + console.log(p.toString()); + + for(let n = N; n > 0; n--) { + let m = p.pop(); + // if (2*n != m) + console.log("push "+ n + " pop " + m); + } + p.pop(); + + p.push(40); + p.pushFloat64(d); + p.pushFloat64(13.34); + p.push(i); + console.log(p.toString()); + + for (let n = 0; n<6;n++) + console.log("p.getFloat64("+n+") = "+p.getFloat64(n)); + + p.pop(); + p.popFloat64(); + let e = p.popFloat64(); + console.log(d + " =?= " + e); + + + d = -1; + p.pushFloat64(d); + e = p.popFloat64(); + console.log(d + " =?= " + e); + // + // for (i = 0 ; i < 1000000; i++) + // p.push(i); +} catch(e) { + console.error(e); +} +*/ + +