protected override void IfZero() { var op = new InterpreterOperator { Operator = NumOperator.IF_NOT_ZERO, }; this.controlStack.Push(op); AddToken(op); }
protected override void WhileNotZero() { var op = new InterpreterOperator { Operator = NumOperator.WHILE_NOT_ZERO, }; // EndWhileで使用するために自分の位置を設定しておく op.JumpPosition = this.tokens.Count; this.controlStack.Push(op); AddToken(op); }
private void AddToken(InterpreterOperator iop) { this.tokens.Add(iop); }
protected override void Postprocess() { int length = tokens.Count; this.controlStack.Clear(); for (int i = 0; i < length; i++) { InterpreterOperator op = this.tokens[i]; switch (op.Operator) { case NumOperator.COUNT: this.stack.Push((uint)this.stack.Count); break; case NumOperator.POP: if (this.stack.Count < 1) { throw new ApplicationException($"empty stack: {op.Operator}"); } else { this.stack.Pop(); } break; case NumOperator.COPY: if (this.stack.TryPeek(out uint result)) { this.stack.Push(result); } else { throw new ApplicationException($"empty stack: {op.Operator}"); } break; case NumOperator.SWAP: if (this.stack.Count < 2) { throw new ApplicationException($"insufficient in stack: {op.Operator}"); } else { uint top = this.stack.Pop(); uint next = this.stack.Pop(); this.stack.Push(top); this.stack.Push(next); } break; case NumOperator.OVER: if (this.stack.Count < 2) { throw new ApplicationException($"insufficient in stack: {op.Operator}"); } else { uint top = this.stack.Pop(); uint next = this.stack.Peek(); this.stack.Push(top); this.stack.Push(next); } break; case NumOperator.INCREMENT: if (this.stack.Count < 1) { throw new ApplicationException($"insufficient in stack: {op.Operator}"); } else { uint top = this.stack.Pop(); this.stack.Push(top + 1); } break; case NumOperator.DECREMENT: if (this.stack.Count < 1) { throw new ApplicationException($"insufficient in stack: {op.Operator}"); } else { uint top = this.stack.Pop(); this.stack.Push(top - 1); } break; case NumOperator.NOT: if (this.stack.Count < 1) { throw new ApplicationException($"insufficient in stack: {op.Operator}"); } else { uint top = this.stack.Pop(); this.stack.Push(~top); } break; case NumOperator.ROTATE_DOWN: if (this.stack.Count < 3) { throw new ApplicationException($"insufficient in stack: {op.Operator}"); } else { uint top = this.stack.Pop(); uint next = this.stack.Pop(); uint bottom = this.stack.Pop(); this.stack.Push(next); this.stack.Push(top); this.stack.Push(bottom); } break; case NumOperator.ROTATE_UP: if (this.stack.Count < 3) { throw new ApplicationException($"insufficient in stack: {op.Operator}"); } else { uint top = this.stack.Pop(); uint next = this.stack.Pop(); uint bottom = this.stack.Pop(); this.stack.Push(top); this.stack.Push(bottom); this.stack.Push(next); } break; case NumOperator.AND: if (this.stack.Count < 2) { throw new ApplicationException($"insufficient in stack: {op.Operator}"); } else { uint top = this.stack.Pop(); uint next = this.stack.Pop(); this.stack.Push(next & top); } break; case NumOperator.OR: if (this.stack.Count < 2) { throw new ApplicationException($"insufficient in stack: {op.Operator}"); } else { uint top = this.stack.Pop(); uint next = this.stack.Pop(); this.stack.Push(next | top); } break; case NumOperator.XOR: if (this.stack.Count < 2) { throw new ApplicationException($"insufficient in stack: {op.Operator}"); } else { uint top = this.stack.Pop(); uint next = this.stack.Pop(); this.stack.Push(next ^ top); } break; case NumOperator.SHIFT_RIGHT: if (this.stack.Count < 2) { throw new ApplicationException($"insufficient in stack: {op.Operator}"); } else { uint top = this.stack.Pop(); uint next = this.stack.Pop(); this.stack.Push(next >> (int)top); } break; case NumOperator.SHIFT_LEFT: if (this.stack.Count < 2) { throw new ApplicationException($"insufficient in stack: {op.Operator}"); } else { uint top = this.stack.Pop(); uint next = this.stack.Pop(); this.stack.Push(next << (int)top); } break; case NumOperator.ADD: if (this.stack.Count < 2) { throw new ApplicationException($"insufficient in stack: {op.Operator}"); } else { uint top = this.stack.Pop(); uint next = this.stack.Pop(); this.stack.Push(next + top); } break; case NumOperator.SUBTRACT: if (this.stack.Count < 2) { throw new ApplicationException($"insufficient in stack: {op.Operator}"); } else { uint top = this.stack.Pop(); uint next = this.stack.Pop(); this.stack.Push(next - top); } break; case NumOperator.MULTIPLY: if (this.stack.Count < 2) { throw new ApplicationException($"insufficient in stack: {op.Operator}"); } else { uint top = this.stack.Pop(); uint next = this.stack.Pop(); this.stack.Push(next * top); } break; case NumOperator.DIVIDE: if (this.stack.Count < 2) { throw new ApplicationException($"insufficient in stack: {op.Operator}"); } else { uint top = this.stack.Pop(); uint next = this.stack.Pop(); this.stack.Push(next / top); } break; case NumOperator.REMAINDER: if (this.stack.Count < 2) { throw new ApplicationException($"insufficient in stack: {op.Operator}"); } else { uint top = this.stack.Pop(); uint next = this.stack.Pop(); this.stack.Push(next % top); } break; case NumOperator.GREATER_THAN: if (this.stack.Count < 2) { throw new ApplicationException($"insufficient in stack: {op.Operator}"); } else { uint top = this.stack.Pop(); uint next = this.stack.Pop(); this.stack.Push(next > top ? 1U : 0U); } break; case NumOperator.LESS_THAN: if (this.stack.Count < 2) { throw new ApplicationException($"insufficient in stack: {op.Operator}"); } else { uint top = this.stack.Pop(); uint next = this.stack.Pop(); this.stack.Push(next < top ? 1U : 0U); } break; case NumOperator.EQUAL: if (this.stack.Count < 2) { throw new ApplicationException($"insufficient in stack: {op.Operator}"); } else { uint top = this.stack.Pop(); uint next = this.stack.Pop(); this.stack.Push(next == top ? 1U : 0U); } break; case NumOperator.NOT_EQUAL: if (this.stack.Count < 2) { throw new ApplicationException($"insufficient in stack: {op.Operator}"); } else { uint top = this.stack.Pop(); uint next = this.stack.Pop(); this.stack.Push(next != top ? 1U : 0U); } break; case NumOperator.TEST: if (this.stack.Count < 2) { throw new ApplicationException($"insufficient in stack: {op.Operator}"); } else { uint top = this.stack.Pop(); uint next = this.stack.Peek(); this.stack.Push(top); this.stack.Push(next == top ? 1U : 0U); } break; case NumOperator.GREATER_THAN_OR_EQUAL: if (this.stack.Count < 2) { throw new ApplicationException($"insufficient in stack: {op.Operator}"); } else { uint top = this.stack.Pop(); uint next = this.stack.Pop(); this.stack.Push(next >= top ? 1U : 0U); } break; case NumOperator.LESS_THAN_OR_EQUAL: if (this.stack.Count < 2) { throw new ApplicationException($"insufficient in stack: {op.Operator}"); } else { uint top = this.stack.Pop(); uint next = this.stack.Pop(); this.stack.Push(next <= top ? 1U : 0U); } break; case NumOperator.EQUAL_ZERO: if (this.stack.Count < 1) { throw new ApplicationException($"insufficient in stack: {op.Operator}"); } else { uint top = this.stack.Pop(); this.stack.Push(top == 0 ? 1U : 0U); } break; case NumOperator.NOT_EQUAL_ZERO: if (this.stack.Count < 1) { throw new ApplicationException($"insufficient in stack: {op.Operator}"); } else { uint top = this.stack.Pop(); this.stack.Push(top != 0 ? 1U : 0U); } break; case NumOperator.TEST_NOT: if (this.stack.Count < 2) { throw new ApplicationException($"insufficient in stack: {op.Operator}"); } else { uint top = this.stack.Pop(); uint next = this.stack.Peek(); this.stack.Push(top); this.stack.Push(next != top ? 1U : 0U); } break; case NumOperator.IF_NOT_ZERO: if (this.stack.Count < 1) { throw new ApplicationException($"insufficient in stack: {op.Operator}"); } else { uint top = this.stack.Peek(); if (top == 0) { i = op.JumpPosition; } else { this.controlStack.Push(op); } } break; case NumOperator.IF_ZERO: if (this.stack.Count < 1) { throw new ApplicationException($"insufficient in stack: {op.Operator}"); } else { uint top = this.stack.Peek(); if (top != 0) { i = op.JumpPosition; } else { this.controlStack.Push(op); } } break; case NumOperator.END_IF: if (this.controlStack.Count < 1) { throw new ApplicationException($"insufficient in control stack: {op.Operator}"); } else { InterpreterOperator control = this.controlStack.Pop(); if (control.Operator != NumOperator.IF_NOT_ZERO && control.Operator != NumOperator.IF_ZERO) { throw new ApplicationException($"invalid control: {control.Operator} - {op.Operator}"); } } break; case NumOperator.WHILE_NOT_ZERO: if (this.stack.Count < 1) { throw new ApplicationException($"insufficient in stack: {op.Operator}"); } else { uint top = this.stack.Peek(); if (top == 0) { i = op.JumpPosition; } else { this.controlStack.Push(op); } } break; case NumOperator.END_WHILE: if (this.stack.Count < 1) { throw new ApplicationException($"insufficient in stack: {op.Operator}"); } else if (this.controlStack.Count < 1) { throw new ApplicationException($"insufficient in control stack: {op.Operator}"); } else { InterpreterOperator control = this.controlStack.Peek(); if (control.Operator != NumOperator.WHILE_NOT_ZERO) { throw new ApplicationException($"invalid control: {control.Operator} - {op.Operator}"); } uint top = this.stack.Peek(); if (top != 0) { i = op.JumpPosition; } else { this.controlStack.Pop(); } } break; case NumOperator.BREAK: if (this.controlStack.Count < 1) { throw new ApplicationException($"insufficient in control stack: {op.Operator}"); } else { InterpreterOperator control = this.controlStack.Pop(); while (control.Operator != NumOperator.WHILE_NOT_ZERO) { if (!this.controlStack.TryPop(out control)) { throw new ApplicationException($"insufficient in control stack: {op.Operator}"); } } i = control.JumpPosition; } break; case NumOperator.CONSTANT_8_BIT: case NumOperator.CONSTANT_16_BIT: case NumOperator.CONSTANT_32_BIT: this.stack.Push(op.Value); break; case NumOperator.INPUT_CHARACTER: this.stack.Push((uint)Console.Read()); break; case NumOperator.OUTPUT_CHARACTER: if (this.stack.Count < 1) { throw new ApplicationException("insufficient in stack"); } else { uint top = this.stack.Pop(); Console.Write(char.ConvertFromUtf32((int)top)); } break; case NumOperator.STORE_VARIABLE: if (this.stack.Count < 1) { throw new ApplicationException("insufficient in stack"); } else { this.variables[op.Value] = this.stack.Pop(); } break; case NumOperator.COPY_VAIRABLE: if (this.stack.Count < 1) { throw new ApplicationException("insufficient in stack"); } else { this.variables[op.Value] = this.stack.Peek(); } break; case NumOperator.LOAD_VARIABLE: if (this.stack.Count < 1) { throw new ApplicationException("insufficient in stack"); } else { this.stack.Push(this.variables[op.Value]); } break; case NumOperator.INPUT_INTEGER: string str = Console.ReadLine(); if (uint.TryParse(str, out uint value)) { this.stack.Push(value); } else { throw new ApplicationException($"invalid value: \"{str}\""); } break; case NumOperator.OUTPUT_INTEGER: if (this.stack.Count < 1) { throw new ApplicationException("insufficient in stack"); } else { uint top = this.stack.Pop(); Console.Write(top); } break; default: break; } } }