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

all_rules, #apply_typing_rule, #ast, #ast_env, #check, #check_all, check_init_class, #check_later, #error_found!, #error_group, find_rule_entry, #make_base_env, #proceed, rule

Methods included from Yadriggy

debug, debug=, define_syntax, reify

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
30
31
# File 'lib/yadriggy/c/codegen.rb', line 20

def initialize(printer, typechecker, public_methods)
  super()
  @printer = printer
  @typechecker = typechecker
  @func_counter = 0
  @func_names = {}
  @nerrors = 0
  @messages = []
  @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.



284
285
286
# File 'lib/yadriggy/c/codegen.rb', line 284

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.



307
308
309
# File 'lib/yadriggy/c/codegen.rb', line 307

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:



294
295
296
297
298
299
300
301
# File 'lib/yadriggy/c/codegen.rb', line 294

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:



386
387
388
# File 'lib/yadriggy/c/codegen.rb', line 386

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`.



395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
# File 'lib/yadriggy/c/codegen.rb', line 395

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



180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
# File 'lib/yadriggy/c/codegen.rb', line 180

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

#error_messagesObject

Gets an array of error messages.



41
42
43
# File 'lib/yadriggy/c/codegen.rb', line 41

def error_messages
  @messages
end

#errors?Boolean

Tests whether a type error was found.

Returns:

  • (Boolean)


35
36
37
# File 'lib/yadriggy/c/codegen.rb', line 35

def errors?
  @nerrors > 0
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_names (Array<Type>)

    the types of the original methods.

Returns:

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

    the names and types.



378
379
380
# File 'lib/yadriggy/c/codegen.rb', line 378

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

#headersvoid

This method returns an undefined value.

Prints ‘#include` derectives.



314
315
316
317
# File 'lib/yadriggy/c/codegen.rb', line 314

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.



321
322
323
324
325
326
327
# File 'lib/yadriggy/c/codegen.rb', line 321

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.



367
368
# File 'lib/yadriggy/c/codegen.rb', line 367

def preamble
end

#printerObject

Gets the printer given when object construction.



53
54
55
# File 'lib/yadriggy/c/codegen.rb', line 53

def printer
  @printer
end

#prototype(expr) ⇒ void

This method returns an undefined value.

Prints a function prototype.

Parameters:



346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
# File 'lib/yadriggy/c/codegen.rb', line 346

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.



47
48
49
# File 'lib/yadriggy/c/codegen.rb', line 47

def typechecker
  @typechecker
end

#variable_declarationsvoid

This method returns an undefined value.

Prints variable declarations.



331
332
333
334
335
336
337
338
339
340
# File 'lib/yadriggy/c/codegen.rb', line 331

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