From: Adam Shelly Date: 2007-08-23T03:45:19+09:00 Subject: Re: [QUIZ] Process Rings (#135) On 8/17/07, Ruby Quiz wrote: > ... > I'll leave the definition of "processes" intentionally vague. Ruby doesn't have > an equivalent to Erlang processes so we will just say that each process should > represent a node where we could run some instructions concurrently. Be > creative. > I've been thinking about virtual machines recently, so I decided to implement one in Ruby for this quiz. My solution has 4 parts: - a pair of programs in an as yet unnamed language. Each program sends a message to the next process. One program implements a counter to stop the loop at the end. - A Compiler for this language. To keep the compiler simple, the parser has no look-ahead. One result of this is that all operators have left associativity, so 'n=n+1', 'n=1+n', and 'n=(n+1)' all set n to different values, and only the last one is unsuprising. The compiler returns an array containing 'assembly', which is essentially bytecode, except the codes are ruby symbols, not bytes. - The InstructionSet, which contains a method for each VM instruction - The virtual CPU. Schedules and runs a set of Proceses. A Process executes assembly by sending each symbol to the instruction set. This solution may be the slowest one submitted, but it was interesting to write. -Adam ---BEGIN SOLUTION--- #processring.rb # for Ruby Quiz #135 # Adam Shelly #Implements a virtual machine and a compiler for a simple language # language definition: # types: ints, strings # variables don't need to be declared in advance (works like ruby) # only 3 keywords: 'exit', 'if' and 'while', # the latter two take the form 'keyword (condition) { body }'. # the parens and brackets are required # only 2 operators: '+' and '-'. # 4 builtin functions: '_peek' returns true if any messages waiting for this proceses # '_get' returns first pending message. # '_send(id, message)' sends message to process with given id # '_puts(message)' writes message to stdout # '%' before a name indicates process variable. # process variables include: %id = current process id # %last = value of last expression # strictly left associative, use parentheses to group. # be careful with assignments: 'n = 1+1' == '(n=1)+1' # you usually want to do 'n = (1+1)' # Here are the two programs we will execute. # this one just forwards any message to the next process prog1 = < TIMESLICE) taskswap 0 end end end #switch to the next process waiting at this priority level def taskswap priority @cur_proc_id = @queue[priority].shift||@cur_proc_id (@queue[priority] << @cur_proc_id) if priority == 0 @timeslice = 0 end ## built-in messaging functions def _peek proc @messages[proc.id][0] end def _get proc retval = @messages[proc.id].shift taskswap 1 return retval end def _send proc #send puts the target process on the high priority queue args = @i.ungroup proc @messages[args[0]] << args[1] @queue[1]<