Class: Yadriggy::C::CodeGen

Inherits:
Yadriggy::Checker show all
Defined in:
lib/yadriggy/c/codegen.rb

Overview

C-code generator

Since Checker implements Visitor pattern, use it for code generation.

Direct Known Subclasses

OclCodeGen

Constant Summary

Constants included from Yadriggy

DynType, Undef, VERSION, Void

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Yadriggy::Checker

#ast, #ast_env, #check, #check_all, #check_later, #error!, #error_found!, #error_messages, #errors?, #last_error, #make_base_env, #proceed, rule

Methods included from Yadriggy

debug, debug=, define_syntax, reify, reset_pry

Constructor Details

#initialize(printer, typechecker, public_methods) ⇒ CodeGen

printer is a Printer object. Only main_method is converted into an extern function. Other methods are converted into static functions.

Parameters:

  • public_methods (Array<ASTree>)

    publicly exported methods.



20
21
22
23
24
25
26
27
28
29
# File 'lib/yadriggy/c/codegen.rb', line 20

def initialize(printer, typechecker, public_methods)
  super()
  @printer = printer
  @typechecker = typechecker
  @func_counter = 0
  @func_names = {}
  @public_methods = {}
  public_methods.each {|m| @public_methods[m.tree] = m.tree }
  @gvariables = {}
end

Class Method Details

.c_src_file(dir, lib_name) ⇒ String

Obtains the file name of the generated source code. A subclass can redefine this method.

Parameters:

  • dir (String)

    a directory name.

  • lib_name (String)

    a library name.

Returns:

  • (String)

    a source file name.



270
271
272
# File 'lib/yadriggy/c/codegen.rb', line 270

def self.c_src_file(dir, lib_name)
  "#{dir}#{lib_name}.c"
end

Instance Method Details

#build_cmdString

Obtains compiler command. A subclass can redefine this method.

Returns:

  • (String)

    command.



293
294
295
# File 'lib/yadriggy/c/codegen.rb', line 293

def build_cmd
  Config::Compiler
end

#build_lib(lib_name, dir = './') ⇒ void

This method returns an undefined value.

Runs a compiler. A subclass can redefine this method.

Parameters:

  • lib_name (String)

    a library name.

  • dir (String) (defaults to: './')

    a directory name.

Raises:



280
281
282
283
284
285
286
287
# File 'lib/yadriggy/c/codegen.rb', line 280

def build_lib(lib_name, dir='./')
  file_name = self.class.c_src_file(dir, lib_name)
  lib_file_name = "#{dir}lib#{lib_name}#{Config::LibExtension}"
  cmd = "#{build_cmd} #{Config::CoptOutput}#{lib_file_name} #{file_name}"
  system(cmd)
  status = $?.exitstatus
  raise BuildError.new(["exit #{status}"]) if status > 0
end

#c_function(expr) ⇒ void

This method returns an undefined value.

Prints a function implementation.

Parameters:



372
373
374
# File 'lib/yadriggy/c/codegen.rb', line 372

def c_function(expr)
  check(expr)
end

#c_function_name(expr) ⇒ String

Gets the function name in C after the translation from a Ruby method into a C function.

Parameters:

Returns:

  • (String)

    the function name for expr.



381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
# File 'lib/yadriggy/c/codegen.rb', line 381

def c_function_name(expr)
  return expr.name.name if expr.is_a?(Def) &&
                           @public_methods.include?(expr)

  fname_str = @func_names[expr]
  if fname_str.nil?
    @func_counter += 1
    fname_str = if expr.is_a?(Block)
                  "yadriggy_blk#{@func_counter}"
                else
                  "#{expr.name.name}_#{@func_counter}"
                end
    @func_names[expr] = fname_str
  end
  fname_str
end

#call_with_block(call_ast) ⇒ Object



166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
# File 'lib/yadriggy/c/codegen.rb', line 166

def call_with_block(call_ast)
  loop_param = call_ast.block.params[0]
  @printer << 'for (' << c_type(RubyClass::Integer) << ' '
  check(loop_param)
  @printer << ' = ('
  check(ast.receiver)
  @printer << ') - 1; '
  check(loop_param)
  @printer << ' >= 0; '
  check(loop_param)
  @printer << '--) {'
  @printer.down
  local_var_declarations(ast.block)
  check(ast.block.body)
  @printer << ';' unless ast.block.body.is_a?(Exprs)
  @printer.up
  @printer << '}' << :nl
end

#expand_functions(func_names, func_types) ⇒ Array<String>, Array<Type>

Appends implicitly generated functions. A subclass can override this method. The original implementation does not append any.

Parameters:

  • func_names (Array<String>)

    the names of the generated functions.

  • func_types (Array<Type>)

    the types of the original methods.

Returns:

  • (Array<String>, Array<Type>)

    the names and types.



364
365
366
# File 'lib/yadriggy/c/codegen.rb', line 364

def expand_functions(func_names, func_types)
  return func_names, func_types
end

#headersvoid

This method returns an undefined value.

Prints #include derectives.



300
301
302
303
# File 'lib/yadriggy/c/codegen.rb', line 300

def headers()
  Config::Headers.each {|h| @printer << h << :nl }
  @printer << :nl
end

#name_global_variablesvoid

This method returns an undefined value.

Gives a name to each global variable.



307
308
309
310
311
312
313
# File 'lib/yadriggy/c/codegen.rb', line 307

def name_global_variables()
  id = 0
  @typechecker.instance_variables.each do |obj|
    @gvariables[obj] = "_gvar_#{id}_"
    id += 1
  end
end

#preambleObject

Prints a preamble. This method is invoked right after printing function prototypes. A subclass can override this method. The original implementation does not print anything.



353
354
# File 'lib/yadriggy/c/codegen.rb', line 353

def preamble
end

#printerObject

Gets the printer given when object construction.



39
40
41
# File 'lib/yadriggy/c/codegen.rb', line 39

def printer
  @printer
end

#prototype(expr) ⇒ void

This method returns an undefined value.

Prints a function prototype.

Parameters:



332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
# File 'lib/yadriggy/c/codegen.rb', line 332

def prototype(expr)
  t = @typechecker.type(expr)
  return if ForeignMethodType.role(t)

  @printer << 'static ' if @public_methods[expr].nil?

  fname_str = c_function_name(expr)
  mt = MethodType.role(t)
  if mt
    parameters(expr, fname_str, mt)
    @printer << ';' << :nl
  else
    error!(expr, "bad method #{fname_str}")
  end
  self
end

#typecheckerObject

Gets the type checker.



33
34
35
# File 'lib/yadriggy/c/codegen.rb', line 33

def typechecker
  @typechecker
end

#variable_declarationsvoid

This method returns an undefined value.

Prints variable declarations.



317
318
319
320
321
322
323
324
325
326
# File 'lib/yadriggy/c/codegen.rb', line 317

def variable_declarations()
  @gvariables.each do |obj, name|
    if obj.is_a?(CType::CArray)
      @printer << 'static ' << c_type(obj.type) << ' ' << name
      obj.sizes.each {|s| @printer << '[' << s << ']' }
      @printer << ';' << :nl
    end
  end
  @printer << :nl
end