1.1 --- a/micropython/ast.py Thu Apr 17 23:04:50 2008 +0200
1.2 +++ b/micropython/ast.py Mon Apr 21 00:13:09 2008 +0200
1.3 @@ -448,7 +448,7 @@
1.4 "Make the invocation and tidy up afterwards."
1.5
1.6 self.new_op(LoadCallable()) # uses the start of the frame to get the callable
1.7 - self.new_op(Jump())
1.8 + self.new_op(JumpWithFrame())
1.9
1.10 # NOTE: Exception handling required.
1.11
1.12 @@ -823,7 +823,9 @@
1.13
1.14 else:
1.15 self.dispatch(node.code)
1.16 - self.new_op(Return())
1.17 + if not isinstance(self.last_op(), Return):
1.18 + self.dispatch(compiler.ast.Name("None"))
1.19 + self.new_op(Return())
1.20
1.21 def visitGenExpr(self, node): pass
1.22
1.23 @@ -904,6 +906,8 @@
1.24 def visitReturn(self, node):
1.25 if node.value is not None:
1.26 self.dispatch(node.value)
1.27 + else:
1.28 + self.dispatch(compiler.ast.Name("None"))
1.29 self.new_op(Return())
1.30
1.31 def visitRightShift(self, node): pass
1.32 @@ -932,21 +936,32 @@
1.33
1.34 self.add_exception_labels(handler_label, exit_label)
1.35
1.36 + # Try...
1.37 + # Produce the code, then jump to the exit.
1.38 +
1.39 self.dispatch(node.body)
1.40 self.new_op(Jump(exit_label))
1.41
1.42 + # Start of handlers.
1.43 +
1.44 self.set_label(handler_label)
1.45 for name, assignment, handler in node.handlers:
1.46 next_label = self.new_label()
1.47
1.48 + # Test the given exception against the current exception.
1.49 +
1.50 if name is not None:
1.51 self.dispatch(name)
1.52 self.new_op(CheckException())
1.53 self.new_op(JumpIfFalse(next_label))
1.54
1.55 + # Handle assignment to exception variable.
1.56 +
1.57 if assignment is not None:
1.58 self.dispatch(assignment)
1.59
1.60 + # Produce the handler code, then jump to the exit.
1.61 +
1.62 self.dispatch(handler)
1.63 self.new_op(Jump(exit_label))
1.64
2.1 --- a/micropython/rsvp.py Thu Apr 17 23:04:50 2008 +0200
2.2 +++ b/micropython/rsvp.py Mon Apr 21 00:13:09 2008 +0200
2.3 @@ -95,17 +95,18 @@
2.4 # ... DropObject not defined: Assume garbage collection.
2.5 class LoadAttr(AR): "Load the object from the given attribute."
2.6 class StoreAttr(AR): "Store an object in the given attribute."
2.7 -class LoadAttrIndex(Instruction): "Load the object for the attribute with the given index."
2.8 -class StoreAttrIndex(Instruction): "Store an object in the attribute with the given index."
2.9 +class LoadAttrIndex(Immediate): "Load the object for the attribute with the given index."
2.10 +class StoreAttrIndex(Immediate): "Store an object in the attribute with the given index."
2.11
2.12 # Access to invocation frames in preparation.
2.13
2.14 class MakeFrame(Instruction): "Make a new invocation frame."
2.15 -class ReserveFrame(Instruction): "Reserve the given number of entries for the invocation frame."
2.16 +class ReserveFrame(Immediate): "Reserve the given number of entries for the invocation frame."
2.17 class DropFrame(Instruction): "Drop an invocation frame."
2.18 class StoreFrame(Instruction): "Store an argument at the given frame location."
2.19 -class StoreFrameIndex(Instruction): "Store an argument for the parameter with the given index."
2.20 +class StoreFrameIndex(Immediate): "Store an argument for the parameter with the given index."
2.21 class CheckFrame(Instruction): "Check the invocation frame for the target."
2.22 +class JumpWithFrame(Instruction): "Jump, adopting the invocation frame."
2.23
2.24 # Invocation-related instructions.
2.25
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
3.2 +++ b/rsvp.py Mon Apr 21 00:13:09 2008 +0200
3.3 @@ -0,0 +1,351 @@
3.4 +#!/usr/bin/env python
3.5 +
3.6 +"""
3.7 +A really simple virtual processor employing a simple set of instructions which
3.8 +ignore low-level operations and merely concentrate on variable access, structure
3.9 +access, structure allocation and function invocations.
3.10 +
3.11 +Copyright (C) 2007, 2008 Paul Boddie <paul@boddie.org.uk>
3.12 +
3.13 +This program is free software; you can redistribute it and/or modify it under
3.14 +the terms of the GNU General Public License as published by the Free Software
3.15 +Foundation; either version 3 of the License, or (at your option) any later
3.16 +version.
3.17 +
3.18 +This program is distributed in the hope that it will be useful, but WITHOUT
3.19 +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
3.20 +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
3.21 +details.
3.22 +
3.23 +You should have received a copy of the GNU General Public License along with
3.24 +this program. If not, see <http://www.gnu.org/licenses/>.
3.25 +
3.26 +--------
3.27 +
3.28 +The execution model of the virtual processor involves the following things:
3.29 +
3.30 + * Memory
3.31 + * PC (program counter) stack
3.32 + * Value stack
3.33 + * Frame stack (containing pointers to the value stack)
3.34 + * Current frame and arguments pointers
3.35 +
3.36 +The memory contains constants, global variable references and program code.
3.37 +
3.38 +The PC stack contains the return address associated with each function
3.39 +invocation.
3.40 +
3.41 +The value stack contains references to objects that are being manipulated, along
3.42 +with pointers to previous stack frames.
3.43 +
3.44 +The frame stack tracks the position of stack frames within the value stack.
3.45 +"""
3.46 +
3.47 +class IllegalInstruction(Exception):
3.48 + pass
3.49 +
3.50 +class IllegalAddress(Exception):
3.51 + pass
3.52 +
3.53 +class EmptyPCStack(Exception):
3.54 + pass
3.55 +
3.56 +class EmptyMetadataStack(Exception):
3.57 + pass
3.58 +
3.59 +class RSVPMachine:
3.60 +
3.61 + "A really simple virtual processor."
3.62 +
3.63 + def __init__(self, memory, pc=None, debug=0):
3.64 +
3.65 + """
3.66 + Initialise the processor with a 'memory' (a list of values containing
3.67 + instructions and data) and the optional program counter 'pc'.
3.68 + """
3.69 +
3.70 + self.memory = memory
3.71 + self.pc = pc or 0
3.72 + self.debug = debug
3.73 + self.pc_stack = []
3.74 + self.value_stack = []
3.75 + self.frame_stack = []
3.76 + self.frame_sp = 0
3.77 +
3.78 + def load(self, address):
3.79 +
3.80 + "Return the value at the given 'address'."
3.81 +
3.82 + try:
3.83 + return self.memory[address]
3.84 + except IndexError:
3.85 + raise IllegalAddress, address
3.86 +
3.87 + def save(self, address, value):
3.88 +
3.89 + "Save to the given 'address' the specified 'value'."
3.90 +
3.91 + try:
3.92 + self.memory[address] = value
3.93 + except IndexError:
3.94 + raise IllegalAddress, address
3.95 +
3.96 + def new(self, size):
3.97 +
3.98 + """
3.99 + Allocate space of the given 'size', returning the address of the space.
3.100 + """
3.101 +
3.102 + addr = len(self.memory)
3.103 + for i in range(0, size):
3.104 + self.memory.append(None)
3.105 + return addr
3.106 +
3.107 + def push(self, data):
3.108 +
3.109 + "Push 'data' onto the value stack."
3.110 +
3.111 + self.value_stack.append(data)
3.112 +
3.113 + def pull(self):
3.114 +
3.115 + "Pull a value from the value stack and return it."
3.116 +
3.117 + return self.value_stack.pop()
3.118 +
3.119 + def push_pc(self, data):
3.120 +
3.121 + "Push 'data' onto the PC stack."
3.122 +
3.123 + self.pc_stack.append(data)
3.124 +
3.125 + def pull_pc(self):
3.126 +
3.127 + "Pull a value from the PC stack and return it."
3.128 +
3.129 + try:
3.130 + return self.pc_stack.pop()
3.131 + except IndexError:
3.132 + raise EmptyPCStack
3.133 +
3.134 + def add_frame(self, data):
3.135 +
3.136 + "Add 'data' to the frame stack without updating the stack pointer."
3.137 +
3.138 + self.frame_stack.append(data)
3.139 +
3.140 + def push_frame(self, data):
3.141 +
3.142 + "Push 'data' onto the frame stack."
3.143 +
3.144 + self.frame_stack.append(data)
3.145 + self.frame_sp += 1
3.146 +
3.147 + def pull_frame(self):
3.148 +
3.149 + "Pull a value from the frame stack and return it."
3.150 +
3.151 + try:
3.152 + self.frame_sp -= 1
3.153 + return self.frame_stack.pop()
3.154 + except IndexError:
3.155 + raise EmptyMetadataStack
3.156 +
3.157 + def execute(self):
3.158 +
3.159 + "Execute code in the memory, starting from the current PC address."
3.160 +
3.161 + try:
3.162 + while 1:
3.163 + instruction = self.load(self.pc)
3.164 + if self.debug:
3.165 + print "%8d %s" % (self.pc, instruction)
3.166 + method = getattr(self, instruction, None)
3.167 + if method is None:
3.168 + raise IllegalInstruction, self.pc
3.169 + else:
3.170 + method()
3.171 + except EmptyPCStack:
3.172 + pass
3.173 +
3.174 + def jump(self, addr, next):
3.175 +
3.176 + """
3.177 + Jump to the subroutine at (or identified by) 'addr'. If 'addr'
3.178 + identifies a library function then invoke the library function and set
3.179 + PC to 'next' afterwards; otherwise, set PC to 'addr'.
3.180 + """
3.181 +
3.182 + if isinstance(addr, str):
3.183 + getattr(self, addr)()
3.184 + self.pc = next
3.185 + else:
3.186 + self.push_pc(self.pc + 2)
3.187 + self.pc = addr
3.188 +
3.189 + # Instructions.
3.190 +
3.191 + def MakeFrame(self):
3.192 + top = len(self.value_stack)
3.193 + self.add_frame(top)
3.194 + self.pc += 1
3.195 +
3.196 + def DropFrame(self):
3.197 + result = self.pull()
3.198 + frame = self.pull_frame()
3.199 + self.value_stack = self.value_stack[:frame] # reset stack before call
3.200 + self.push(result)
3.201 + self.pc += 1
3.202 +
3.203 + def JumpWithFrame(self):
3.204 + addr = self.load(self.pc + 1)
3.205 + self.frame_sp += 1 # adopt the added frame
3.206 + self.jump(addr, self.pc + 2)
3.207 +
3.208 + def LoadName(self):
3.209 +
3.210 + """
3.211 + LoadName #n
3.212 + Load from position n in frame: get position n from the current stack
3.213 + frame, push the retrieved value onto the stack.
3.214 + """
3.215 +
3.216 + n = self.load(self.pc + 1)
3.217 + frame = self.frame_stack[self.frame_sp]
3.218 + self.push(self.value_stack[frame + n])
3.219 + self.pc += 2
3.220 +
3.221 + def StoreName(self):
3.222 +
3.223 + """
3.224 + StoreName #n
3.225 + Save to position n in frame: pull a value from the stack and set it as
3.226 + position n in the current stack frame.
3.227 + """
3.228 +
3.229 + n = self.load(self.pc + 1)
3.230 + frame = self.frame_stack[self.frame_sp]
3.231 + self.value_stack[frame + n] = self.pull()
3.232 + self.pc += 2
3.233 +
3.234 + def LoadConst(self):
3.235 +
3.236 + """
3.237 + LoadConst addr
3.238 + Load the reference to memory: get the address addr, push the value onto
3.239 + the stack.
3.240 +
3.241 + This is useful for loading constants.
3.242 + """
3.243 +
3.244 + addr = self.load(self.pc + 1)
3.245 + self.push(addr)
3.246 + self.pc += 2
3.247 +
3.248 + def LoadAttr(self):
3.249 +
3.250 + """
3.251 + LoadAttr #n
3.252 + Load from position n in reference: get the contents of position n in the
3.253 + memory referenced by the value on the top of the stack, replacing the
3.254 + value on the top of the stack with the retrieved value.
3.255 + """
3.256 +
3.257 + n = self.load(self.pc + 1)
3.258 + ref = self.pull()
3.259 + self.push(self.load(ref + n))
3.260 + self.pc += 2
3.261 +
3.262 + def StoreAttr(self):
3.263 +
3.264 + """
3.265 + StoreAttr #n
3.266 + Save to position n in reference: pull a value from the stack and save it
3.267 + to position n in the memory referenced by the next value on the stack,
3.268 + also removing the next value on the stack.
3.269 + """
3.270 +
3.271 + n = self.load(self.pc + 1)
3.272 + value = self.pull()
3.273 + self.save(self.pull() + n, value)
3.274 + self.pc += 2
3.275 +
3.276 + def Return(self):
3.277 +
3.278 + """
3.279 + Return
3.280 + Return to the address of the caller: pull a value from the PC stack and
3.281 + set it in the PC.
3.282 + """
3.283 +
3.284 + self.pc = self.pull_pc()
3.285 +
3.286 + def JumpIfTrue(self):
3.287 +
3.288 + """
3.289 + JumpIfTrue addr
3.290 + Jump to address addr if true: pull a value from the stack and if it
3.291 + represents a true value, jump to address addr.
3.292 + """
3.293 +
3.294 + addr = self.load(self.pc + 1)
3.295 + value = self.pull()
3.296 + if value:
3.297 + self.pc = addr
3.298 + else:
3.299 + self.pc += 2
3.300 +
3.301 + def JumpIfFalse(self):
3.302 +
3.303 + """
3.304 + JumpIfFalse addr
3.305 + Jump to address addr if false: pull a value from the stack and if it
3.306 + represents a false value, jump to address addr.
3.307 + """
3.308 +
3.309 + addr = self.load(self.pc + 1)
3.310 + value = self.pull()
3.311 + if not value:
3.312 + self.pc = addr
3.313 + else:
3.314 + self.pc += 2
3.315 +
3.316 + def StoreFrame(self):
3.317 +
3.318 + """
3.319 + StoreFrame #n
3.320 + Move the value from the top of the stack to the argument in position n:
3.321 + pull a value from the stack and store it in the argument frame at the
3.322 + given position.
3.323 + """
3.324 +
3.325 + pos = self.load(self.pc + 1)
3.326 + value = self.pull()
3.327 + frame = self.frame_stack[-1] # different from the current frame after MakeFrame
3.328 + self.value_stack[frame + pos] = value
3.329 + self.pc += 2
3.330 +
3.331 + # Library functions.
3.332 +
3.333 + def rsvp___printnl(self):
3.334 + print self.load(self.value_stack[-1])
3.335 +
3.336 + def rsvp___print(self):
3.337 + print self.load(self.value_stack[-1]),
3.338 +
3.339 + def int_____gt__(self):
3.340 + self.push(self.load(self.value_stack[-2]) > self.load(self.value_stack[-1]))
3.341 +
3.342 + def int_____sub__(self):
3.343 + result = self.load(self.value_stack[-2]) - self.load(self.value_stack[-1])
3.344 + addr = self.new(1)
3.345 + self.push(addr)
3.346 + self.save(addr, result)
3.347 +
3.348 + def int_____mul__(self):
3.349 + result = self.load(self.value_stack[-2]) * self.load(self.value_stack[-1])
3.350 + addr = self.new(1)
3.351 + self.push(addr)
3.352 + self.save(addr, result)
3.353 +
3.354 +# vim: tabstop=4 expandtab shiftwidth=4