Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Josep M. Bach
committed
May 4, 2011
1 parent
c2f8a7f
commit 17f89d2
Showing
9 changed files
with
421 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,3 @@ | ||
#!/usr/bin/env ruby | ||
require 'brainfuck' | ||
Brainfuck.run File.read(ARGV.first) | ||
Brainfuck::Main.new.main ARGV.first |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
module Brainfuck | ||
class CodeLoader | ||
|
||
def self.execute_code(code, binding, from_module, print = Compiler::Print.new) | ||
cm = Compiler.compile_for_eval(code, binding.variables, | ||
"(eval)", 1, print) | ||
cm.scope = binding.static_scope.dup | ||
cm.name = :__eval__ | ||
|
||
script = Rubinius::CompiledMethod::Script.new(cm, "(eval)", true) | ||
script.eval_binding = binding | ||
script.eval_source = code | ||
|
||
cm.scope.script = script | ||
|
||
be = Rubinius::BlockEnvironment.new | ||
be.under_context(binding.variables, cm) | ||
be.from_eval! | ||
be.call | ||
end | ||
|
||
# Takes a .py file name, compiles it if needed and executes it. | ||
# Sets the module name to be __main__, so this should be called | ||
# only on the main program. For loading other python modules from | ||
# it use the load_module method. | ||
def self.execute_file(name, compile_to = nil, print = Compiler::Print.new) | ||
cm = Compiler.compile_if_needed(name, compile_to, print) | ||
ss = ::Rubinius::StaticScope.new Object | ||
code = Object.new | ||
::Rubinius.attach_method(:__run__, cm, ss, code) | ||
code.__run__ | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
module Brainfuck | ||
class Compiler < Rubinius::Compiler | ||
|
||
def self.compiled_filename(filename) | ||
if filename =~ /.bf$/ | ||
filename + "c" | ||
else | ||
filename + ".compiled.bfc" | ||
end | ||
end | ||
|
||
def self.always_recompile=(flag) | ||
@always_recompile = flag | ||
end | ||
|
||
def self.compile_if_needed(file, output = nil, print = Print.new) | ||
puts file.inspect | ||
compiled = output || compiled_filename(file) | ||
needed = @always_recompile || !File.exists?(compiled) || | ||
File.stat(compiled).mtime < File.stat(file).mtime | ||
if needed | ||
compile_file(file, compiled, print) | ||
else | ||
Rubinius::CodeLoader.new(compiled).load_compiled_file(compiled, 0) | ||
end | ||
end | ||
|
||
|
||
def self.compile_file(file, output = nil, print = Print.new) | ||
compiler = new :brainfuck_file, :compiled_file | ||
parser = compiler.parser | ||
|
||
parser.input file | ||
|
||
compiler.generator.root = Rubinius::AST::Script | ||
compiler.writer.name = output || compiled_filename(file) | ||
|
||
parser.print = print | ||
compiler.packager.print.bytecode = true if print.asm? | ||
|
||
begin | ||
compiler.run | ||
|
||
rescue Exception => e | ||
compiler_error "Error trying to compile brainfuck: #{file}", e | ||
end | ||
end | ||
|
||
def self.compile_for_eval(code, variable_scope, file = "(eval)", line = 0, print = Print.new) | ||
compiler = new :brainfuck_code, :compiled_method | ||
parser = compiler.parser | ||
|
||
parser.input code, file, line | ||
compiler.generator.root = Rubinius::AST::EvalExpression | ||
compiler.generator.variable_scope = variable_scope | ||
|
||
parser.print = print | ||
compiler.packager.print.bytecode = true if print.asm? | ||
|
||
begin | ||
compiler.run | ||
rescue Exception => e | ||
compiler_error "Error trying to compile brainfuck: #{file}", e | ||
end | ||
end | ||
|
||
class Print < Struct.new(:sexp, :ast, :asm) | ||
def sexp? | ||
@sexp | ||
end | ||
|
||
def ast? | ||
@ast | ||
end | ||
|
||
def asm? | ||
@asm | ||
end | ||
end | ||
|
||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
require 'brainfuck/version' | ||
|
||
module Brainfuck | ||
|
||
# Command line interface to Brainfuck. | ||
# | ||
# It should support the same command line options than the `brainfuck' | ||
# program. And additional options specific to Brainfuck and Rubinius. | ||
# | ||
# But currently we only take a brainfuck source name to compile and | ||
# run. | ||
# | ||
class Main | ||
|
||
def initialize | ||
@print = Compiler::Print.new | ||
@compile_only = false | ||
@evals = [] | ||
@rest = [] | ||
end | ||
|
||
def main(argv=ARGV) | ||
options(argv) | ||
# return repl if @rest.empty? && @evals.empty? && !@compile_only | ||
evals unless @evals.empty? | ||
script unless @rest.empty? | ||
compile if @compile_only | ||
end | ||
|
||
# Batch compile all brainfuck files given as arguments. | ||
def compile | ||
@rest.each do |py| | ||
begin | ||
Compiler.compile_file py, nil, @print | ||
rescue Compiler::Error => e | ||
e.show | ||
end | ||
end | ||
end | ||
|
||
# Evaluate code given on command line | ||
def evals | ||
bnd = Object.new | ||
def bnd.get; binding; end | ||
bnd = bnd.get | ||
mod = nil | ||
@evals.each do |code| | ||
CodeLoader.execute_code code, bnd, mod, @print | ||
end | ||
end | ||
|
||
# Run the given script if any | ||
def script | ||
CodeLoader.execute_file @rest.first, nil, @print | ||
end | ||
|
||
# # Run the Brainfuck REPL unless we were given an script | ||
# def repl | ||
# require 'brainfuck/repl' | ||
# ReadEvalPrintLoop.new(@print).main | ||
# end | ||
|
||
# Parse command line options | ||
def options(argv) | ||
options = Rubinius::Options.new "Usage: brainfuck [options] [program]", 20 | ||
options.doc "Brainfuck is a Brainfuck implementation for the Rubinius VM." | ||
options.doc "It is inteded to expose the same command line options as" | ||
options.doc "the `brainfuck` program and some Rubinius specific options." | ||
options.doc "" | ||
options.doc "OPTIONS:" | ||
|
||
options.on "-", "Read and evalute code from STDIN" do | ||
@evals << STDIN.read | ||
end | ||
|
||
options.on "--print-ast", "Print the Brainfuck AST" do | ||
@print.ast = true | ||
end | ||
|
||
options.on "--print-asm", "Print the Rubinius ASM" do | ||
@print.asm = true | ||
end | ||
|
||
options.on "--print-sexp", "Print the Brainfuck Sexp" do | ||
@print.sexp = true | ||
end | ||
|
||
options.on "--print-all", "Print Sexp, AST and Rubinius ASM" do | ||
@print.ast = @print.asm = @print.sexp = true | ||
end | ||
|
||
options.on "-C", "--compile", "Just batch compile dont execute." do | ||
@compile_only = true | ||
end | ||
|
||
options.on "-e", "CODE", "Execute CODE" do |e| | ||
@evals << e | ||
end | ||
|
||
options.on "-h", "--help", "Display this help" do | ||
puts options | ||
exit 0 | ||
end | ||
|
||
options.doc "" | ||
|
||
@rest = options.parse(argv) | ||
end | ||
|
||
end | ||
end |
Oops, something went wrong.