Now look at the CPU to simulate the execution of machine instructions, because the assembly code and machine instructions correspondence, so we can create a direct implementation of simulator assembly code.
Before creating a simulator, first to explain the operation of the relevant directive.
- Stack
In memory, the stack is characterized by insertion and deletion can only be operated at the same end, that is, only two operations push and pop.
- push
Effect of a push instruction is to push the stack operand.
- pop
Action pop instruction is to pop an operand stack.
- add
Action add instruction operation is performed twice pop, pop two operands a and B, and then performs a + b, then push the result onto the stack.
- sub
Action instruction is performed twice sub pop operation, a pop two operands and B, and then performs a - b, then push the result onto the stack.
- I have
Action mul instruction operation is performed twice pop, pop two operands a and B, and then performs a * b, and then push the result onto the stack.
- div
Action instruction is performed twice sub pop operation, a pop two operands and B, and then performs a / b, and then push the result onto the stack.
All four instructions explain operation has finished, it is not that simple?
Code
Note: The first two articles lexical analysis and parsing code that need to be introduced
function CpuEmulator(instructions) {
this.ins = instructions.split('\r\n')
this.memory = []
this.re = /^(push)\s\w+/
this.execute()
}
CpuEmulator.prototype = {
execute() {
this.ins.forEach(i => {
switch (i) {
case 'add':
this.add()
break
case 'sub':
this.sub()
break
case 'mul':
this.mul()
break
case 'div':
this.div()
break
default:
if (this.re.test(i)) {
this.push(i.split(' ')[1])
}
}
})
},
add() {
const b = this.pop()
const a = this.pop()
this.memory.push(a + b)
},
sub() {
const b = this.pop()
const a = this.pop()
this.memory.push(a - b)
},
mul() {
const b = this.pop()
const a = this.pop()
this.memory.push(a * b)
},
div() {
const b = this.pop()
const a = this.pop()
this.memory.push(a / b)
},
push(x) {
this.memory.push(parseInt(x))
},
pop() {
return this.memory.pop()
},
getResult() {
return this.memory[0]
}
}
const tokens = lexicalAnalysis('(100+ 10)* 10-100/ 10 +8* (4+2)')
const writer = new AssemblyWriter()
const parser = new Parser(tokens, writer)
const instructions = parser.getInstructions()
const emulator = new CpuEmulator(instructions)
console.log(emulator.getResult()) // 1138
- Compiler theory actual entry: use JavaScript to write a simple four operations compiler (a) lexical analysis
- Compiler theory actual entry: use JavaScript to write a simple four operations compiler (b) parsing
- Compiler theory actual entry: use JavaScript to write a simple four operations compiler (c) simulation execution
- Compiler theory actual entry: use JavaScript to write a simple four operations compiler (d) Conclusion
-
Reference: computer system elements