This commit is contained in:
Peter Camilleri 2014-09-10 23:38:05 -04:00
parent 2bfd05ed9b
commit ada8df9b4e
9 changed files with 319 additions and 30 deletions

View file

@ -26,6 +26,7 @@ Gem::Specification.new do |s|
s.files += Dir['tests/*.rb']
s.files += ['rakefile.rb',
'sire.rb',
'license.txt',
'readme.txt',
'reek.txt']

View file

@ -2,6 +2,8 @@
# The fOOrth Language System implemented via a Ruby gem.
require_relative 'fOOrth/exceptions'
require_relative 'fOORth/core'
require_relative 'fOOrth/interpreter'
require_relative 'fOOrth/compiler'
require_relative 'fOOrth/main'
@ -13,7 +15,7 @@ module XfOOrth
#The version of this module.
#<br>Returns
#* A version string; <major>.<minor>.<step>
def version
def self.version
"00.06.00"
end
@ -25,7 +27,7 @@ module XfOOrth
#Create an new instance of a fOOrth virtual machine
#<br>Parameters:
#* name - An optional string that describes this virtual machine instance.
def initialize(name='----')
def initialize(name='-')
@name = name
#Bring the major sub-systems to a known state.

View file

@ -4,6 +4,7 @@
module XfOOrth
class VirtualMachine
attr_accessor :debug
end
end

16
lib/fOOrth/exceptions.rb Normal file
View file

@ -0,0 +1,16 @@
# coding: utf-8
#* exceptions.rb - Exception classes for the fOOrth language interpreter.
module XfOOrth
#The generalize exception used by all fOOrth specific exceptions.
class XfOOrthError < StandardError; end
#The exception raised to force the fOOrth language system to exit.
class ForceExit < StandardError; end
#The exception raised to silently force the fOOrth language system to exit.
class SilentExit < StandardError; end
#The exception raised to force the fOOrth language system to abort execution.
class ForceAbort < StandardError; end
end

View file

@ -6,6 +6,17 @@ require_relative 'interpreter/data_stack'
module XfOOrth
class VirtualMachine
#The fOOrth control stack. This is mostly used to hold information
#relating to control structures during compile and interpretation.
attr_reader :ctrl_stack
#Reset the state of the fOOrth inner interpreter.
def interpreter_reset
@data_stack = Array.new
@ctrl_stack = Array.new
@start_time = Time.now
end
end
end

View file

@ -2,8 +2,83 @@
#* data_stack.rb - The fOOrth language system data stack.
module XfOOrth
class VirtualMachine
end
#The fOOrth data stack. This is the primary means used to hold data
#for processing.
attr_reader :data_stack
#Add an entry to the data stack.
#<br>Parameters:
#* datum - The data to be added to the data stack.
def push(datum)
@data_stack << datum
end
#Remove the "top" entry from the data stack.
#<br>Returns:
#* The "top" element of the data stack.
#<br>Note:
#* If the stack is empty this will raise a XfOOrthError exception.
def pop
unless @data_stack.length >= 1
fail XfOOrthError, "Data Stack Underflow: pop"
end
@data_stack.pop
end
#Remove multiple entries from the "top" of the data stack.
#<br>Parameters:
#* count - the number of elements to be returned.
#<br>Returns:
#* An array containing the "top" count elements of the data stack.
#<br>Note:
#* Raises a XfOOrthError exception if the stack has too few data.
def popm(count)
unless @data_stack.length >= count
fail XfOOrthError, "Data Stack Underflow: popm"
end
@data_stack.pop(count)
end
#Remove the "top" entry from the data stack as a boolean.
#<br>Returns:
#* The "top" element of the data stack as a boolean
#<br>Note:
#* If the stack is empty this will raise a XfOOrthError exception.
def pop?
pop.to_fOOrth_b
end
#Read an entry from the data stack without modify that stack.
#<br>Parameters:
#* index - The (optional) entry to be retrieved. 1 corresponds to the
# "top" of the stack, 2 the next element, etc.
# This parameter defaults to 1.
#<br>Returns:
#* The element specified from the data stack.
#<br>Note:
#* Attempting to access an element deeper than the number of elements
# on the stack will fail with an XfOOrthError exception.
def peek(index=1)
unless @data_stack.length >= index
fail XfOOrthError, "Data Stack Underflow: Peek"
end
@data_stack[-index]
end
#Read an entry from the data stack as a boolean without modify that stack.
#<br>Parameters:
#* index - The (optional) entry to be retrieved. 1 corresponds to the "top"
# of the stack, 2 the next element, etc. This parameter defaults to 1.
#<br>Returns:
#* The element specified from the data stack as a boolean.
#<br>Note:
#* Attempting to access an element deeper than the number of elements on
# the stack will fail with an XfOOrthError exception.
def peek?(index=1)
peek(index).to_fOOrth_b
end
end
end

View file

@ -5,35 +5,124 @@ require 'getoptlong'
#* main.rb - The entry point for a stand-alone fOOrth session.
module XfOOrth
class VirtualMachine
@library_loaded = false
@library_loaded = false
#Has the fOOrth run time library been loaded?
def library_loaded?
@library_loaded
end
#Has the fOOrth run time library been loaded?
def self.library_loaded?
@library_loaded
end
#The fOOrth run time library has been loaded!
def library_loaded
@library_loaded = true
end
#The fOOrth run time library has been loaded!
def self.library_loaded
@library_loaded = true
end
#The starting point for an interactive fOOrth programming session.
#This method only returns when the session is closed.
#<br>To launch a fOOrth session, simply use:
# XfOOrth::VirtualMachine.new.main
def main
#The starting point for an interactive fOOrth programming session.
#This method only returns when the session is closed.
#<br>Returns:
#* The virtual machine used to run the session.
#<br>To launch a fOOrth interactive session, simply use:
# XfOOrth::main
def self.main
vm = VirtualMachine.new('main')
begin
loop do
begin
running ||= start_up(vm)
vm.eceute_console
rescue ForceAbort => forced_abort
vm.display_abort(forced_abort)
break unless running
end
end
rescue Interrupt
puts "\nProgram interrupted. Exiting fOOrth."
rescue ForceExit
puts "\nQuit command received. Exiting fOOrth."
rescue SilentExit
puts
rescue Exception => err
puts "\n#{err.class.to_s.gsub(/.*::/, '')} detected: #{err}"
puts err.backtrace
end
#Process the command line arguments. A string is returned containing
#fOOrth commands to be executed after the dictionary is loaded.
#<br>Returns
#A string of fOOrth commands to be executed after the dictionary is loaded.
def process_command_line_options
vm
end
#Perform one time start-up actions.
def self.start_up(vm)
announcement
vm.debug = false
vm.exec_str.process_command_line_options
true
end
#Display the start-up messages for the interactive session.
def self.announcement
puts "fOOrth Reference Implementation Version: #{XfOOrth.version}"
fmt = '%Y-%m-%d at %I:%M%P'
puts "Session began on date: #{Time.now.strftime(fmt)}"
end
#Process the command line arguments. A string is returned containing
#fOOrth commands to be executed after the dictionary is loaded.
#<br>Returns
#A string of fOOrth commands to be executed after the dictionary is loaded.
def self.process_command_line_options
begin
defer, found = "", false
opts = GetoptLong.new(
[ "--help", "-h", "-?", GetoptLong::NO_ARGUMENT ],
[ "--load", "-l", GetoptLong::REQUIRED_ARGUMENT ],
[ "--debug", "-d", GetoptLong::NO_ARGUMENT ],
[ "--quit", "-q", GetoptLong::NO_ARGUMENT ],
[ "--words", "-w", GetoptLong::NO_ARGUMENT ])
# Translate the parsed options into fOOrth.
opts.each do |opt, arg|
unless found
puts; found = true
end
case opt
when "--debug"
@debug = true
when "--load"
defer << "load\"#{arg}\" "
when "--quit"
defer << ")quit "
when "--words"
defer << ")words "
else
fail SilentExit
end
end
puts if found
rescue Exception
puts
puts "fOOrth available options:"
puts
puts "--help -h -? Display this message and exit."
puts "--load -l <filename> Load the specified fOOrth source file."
puts "--debug -d Default to debug ON."
puts "--quit -q Quit after processing the command line."
puts "--words -w List the current vocabulary."
puts
raise SilentExit
end
defer
end
end

View file

@ -4,21 +4,26 @@
require 'rake/testtask'
require 'rdoc/task'
#Generate internal documentation with rdoc.
RDoc::Task.new do |rdoc|
rdoc.rdoc_dir = "rdoc"
#List out all the files to be documented.
rdoc.rdoc_files = ["lib/fOOrth.rb",
"lib/fOOrth/exceptions.rb",
"lib/fOOrth/core.rb",
"lib/fOOrth/interpreter.rb",
"lib/fOOrth/interpreter/data_stack.rb",
"lib/fOOrth/compiler.rb",
"lib/fOOrth/main.rb",
"license.txt", "README.txt"]
"license.txt",
"README.txt"]
#Make all access levels visible.
rdoc.options << '--visibility' << 'private'
end
#Run the fOOrth test suite.
Rake::TestTask.new do |t|
#List out all the test files.
t.test_files = []
@ -26,15 +31,12 @@ Rake::TestTask.new do |t|
t.verbose = false
end
#Run a scan for smelly code!
task :reek do |t|
`reek --no-color lib > reek.txt`
end
def eval_puts(str)
puts str
eval str
end
#Fire up an IRB session with fOOrth preloaded.
task :console do
require 'irb'
require 'irb/completion'
@ -43,3 +45,17 @@ task :console do
ARGV.clear
IRB.start
end
#Run the Simple Interactive Ruby Environment.
task :sire do
require './lib/fOOrth'
require './sire'
SIRE.new.run_sire
end
#Run an Interactive fOOrth Session.
task :run do
require './lib/fOOrth'
ARGV.clear
XfOOrth::main
end

78
sire.rb Normal file
View file

@ -0,0 +1,78 @@
# coding: utf-8
# A Simple Interactive Ruby Environment
require 'readline'
require 'pp'
include Readline
class Object
#Generate the class lineage of the object.
def classes
begin
klass = self
begin
klass = klass.class unless klass.instance_of?(Class)
print klass
klass = klass.superclass
print " < " if klass
end while klass
puts
end
end
end
class SIRE
#Set up the interactive session.
def initialize
@done = false
@running = false
puts "Welcome to a Simple Interactive Ruby Environment\n"
puts "Use command 'q' to quit.\n\n"
end
#Quit the interactive session.
def q
@done = true
puts
"Bye bye for now!"
end
#Run the interactive session.
def run_sire
until @done
begin
line = readline('SIRE>', true)
@running = true
result = eval line
@running = false
pp result unless line.length == 0
rescue Interrupt => e
if @running
@running = false
puts "\nExecution Interrupted!"
puts "\n#{e.class} detected: #{e}\n"
puts e.backtrace
else
puts "\nI'm outta here!'"
@done = true
end
puts "\n"
rescue Exception => e
puts "\n#{e.class} detected: #{e}\n"
puts e.backtrace
puts
end
end
puts "\n\n"
end
end