class Rucc::Engine

Public Class Methods

new(argv, input = nil) click to toggle source

When io is specified, io is used as input source. When io is not specified, ARGV is considered as sourcde file.

@param [<String>] argv @param [IO, NilClass] input

# File lib/rucc/engine.rb, line 13
def initialize(argv, input = nil)
  @option = Option.new
  @option.parse!(argv)

  if input
    @filename = "-"
  else
    @filename = argv.first
    input = File.open(@filename)
  end

  # Setup lexer
  @lexer = Lexer.new(input, @filename)

  # Setup parser
  label_gen = LabelGen.new
  @parser = Parser.new(@lexer, label_gen)
  @lexer.expr_reader = -> { @parser.read_expr }

  # Setup gen
  @out = StringIO.new
  @gen = Gen.new(@out, label_gen)

  init_environment!
end

Public Instance Methods

gen() click to toggle source
# File lib/rucc/engine.rb, line 52
def gen
  parse.each do |toplevel_ast|
    @gen.emit_toplevel(toplevel_ast)
  end
  @out.rewind
  @out.read
end
lex() click to toggle source

NOTE: Used only for debug

# File lib/rucc/engine.rb, line 40
def lex
  r = []
  while (tok = @lexer.lex).kind != T::EOF
    r.push(tok)
  end
  r
end
parse() click to toggle source
# File lib/rucc/engine.rb, line 48
def parse
  @parser.read_toplevels
end
run!() click to toggle source
# File lib/rucc/engine.rb, line 60
def run!
  asm = gen

  if @option.dumpasm
    File.write(outfile('s'), asm)
    return
  end

  File.write(tmpfile('s'), asm)
  assemble!(src: tmpfile('s'), dst: tmpfile('o'))

  if @option.dontlink
    FileUtils.copy(tmpfile('o'), outfile('o'))
    return
  end

  link!(src: tmpfile('o'), dst: (@option.outfile || "a.out"))
end

Private Instance Methods

assemble!(src:, dst:) click to toggle source
# File lib/rucc/engine.rb, line 93
def assemble!(src:, dst:)
  # TODO(south37) Check status code
  `as -o #{dst} -c #{src}`
end
init_environment!() click to toggle source
# File lib/rucc/engine.rb, line 103
def init_environment!
  pre_difined_include_path.each do |path|
    @lexer.append_include_path(path)
  end

  @option.include_path.each do |path|
    @lexer.append_include_path(path)
  end

  read_from_string("#include <#{::Rucc.root}/include/rucc.h>")
end
outfile(ext) click to toggle source
# File lib/rucc/engine.rb, line 85
def outfile(ext)
  if @option.outfile
    @option.outfile
  else
    @filename.gsub(/\.c$/, ".#{ext}")
  end
end
pre_difined_include_path() click to toggle source
# File lib/rucc/engine.rb, line 115
def pre_difined_include_path
  [
    "#{::Rucc.root}/include",
    "/usr/local/lib/rucc/include",
    "/usr/local/include",
    "/usr/include",
    "/usr/include/linux",
    "/usr/include/x86_64-linux-gnu",
  ]
end
read_from_string(buf) click to toggle source

Reads from a string as if the string is a content of input file. Convenient for evaluating small string snippet contaiing preprocessor macros.

@param [String] buf

# File lib/rucc/engine.rb, line 130
def read_from_string(buf)
  @lexer.stream_stash([FileIO.new(StringIO.new(buf), "-")])
  parse.each do |toplevel_ast|
    @gen.emit_toplevel(toplevel_ast)
  end
  @lexer.stream_unstash
end
tmpfile(ext) click to toggle source
# File lib/rucc/engine.rb, line 81
def tmpfile(ext)
  "/tmp/ruccXXXXXX.#{ext}"
end