Class: Yadriggy::C::CodeGen
- Inherits:
-
Yadriggy::Checker
- Object
- Yadriggy::Checker
- Yadriggy::C::CodeGen
- Defined in:
- lib/yadriggy/c/codegen.rb
Overview
C-code generator
Since Checker implements Visitor pattern, use it for code generation.
Direct Known Subclasses
Constant Summary
Constants included from Yadriggy
Class Method Summary collapse
-
.c_src_file(dir, lib_name) ⇒ String
Obtains the file name of the generated source code.
Instance Method Summary collapse
-
#build_cmd ⇒ String
Obtains compiler command.
-
#build_lib(lib_name, dir = './') ⇒ void
Runs a compiler.
-
#c_function(expr) ⇒ void
Prints a function implementation.
-
#c_function_name(expr) ⇒ String
Gets the function name in C after the translation from a Ruby method into a C function.
- #call_with_block(call_ast) ⇒ Object
-
#error_messages ⇒ Object
Gets an array of error messages.
-
#errors? ⇒ Boolean
Tests whether a type error was found.
-
#expand_functions(func_names, func_types) ⇒ Array<String>, Array<Type>
Appends implicitly generated functions.
-
#headers ⇒ void
Prints ‘#include` derectives.
-
#initialize(printer, typechecker, public_methods) ⇒ CodeGen
constructor
printer is a Printer object.
-
#name_global_variables ⇒ void
Gives a name to each global variable.
-
#preamble ⇒ Object
Prints a preamble.
-
#printer ⇒ Object
Gets the printer given when object construction.
-
#prototype(expr) ⇒ void
Prints a function prototype.
-
#typechecker ⇒ Object
Gets the type checker.
-
#variable_declarations ⇒ void
Prints variable declarations.
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.
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.
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_cmd ⇒ String
Obtains compiler command. A subclass can redefine this method.
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.
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.
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.
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_messages ⇒ Object
Gets an array of error messages.
41 42 43 |
# File 'lib/yadriggy/c/codegen.rb', line 41 def @messages end |
#errors? ⇒ Boolean
Tests whether a type error was found.
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.
378 379 380 |
# File 'lib/yadriggy/c/codegen.rb', line 378 def (func_names, func_types) return func_names, func_types end |
#headers ⇒ void
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_variables ⇒ void
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 |
#preamble ⇒ Object
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 |
#printer ⇒ Object
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.
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 |
#typechecker ⇒ Object
Gets the type checker.
47 48 49 |
# File 'lib/yadriggy/c/codegen.rb', line 47 def typechecker @typechecker end |
#variable_declarations ⇒ void
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 |