voodoo 1.1.1 → 1.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -81,7 +81,7 @@ def handle_error error
81
81
  if error.kind_of? Voodoo::Compiler::Error
82
82
  error.errors.each do |e|
83
83
  message = ''
84
- if e.start_line != nil
84
+ if e.respond_to?(:start_line) && e.start_line != nil
85
85
  message << "#{e.start_line}: "
86
86
  if e.input_name != nil
87
87
  message = "#{e.input_name}:#{message}"
@@ -91,7 +91,7 @@ def handle_error error
91
91
  end
92
92
  message << e.message
93
93
  $stderr.puts message
94
- if e.text != nil
94
+ if e.respond_to?(:text) && e.text != nil
95
95
  $stderr.print "\n #{e.text.gsub("\n", "\n ")}\n"
96
96
  end
97
97
  end
@@ -67,6 +67,13 @@ module Voodoo
67
67
  end
68
68
  end
69
69
 
70
+ undefined_symbols = @generator.undefined_symbols
71
+ unless undefined_symbols.empty?
72
+ msg = "The following symbols are used, but have not been defined" +
73
+ " or imported:\n" + undefined_symbols.to_a.sort!.join(" ")
74
+ errors << RuntimeError.new(msg)
75
+ end
76
+
70
77
  if errors.empty?
71
78
  @generator.write @output
72
79
  else
@@ -2,15 +2,15 @@ module Voodoo
2
2
  # Methods to get and set configuration parameters
3
3
  module Config
4
4
  IMPLEMENTATION_NAME = 'Voodoo Compiler'
5
- IMPLEMENTATION_VERSION = '1.1.1'
5
+ IMPLEMENTATION_VERSION = '1.1.2'
6
6
 
7
7
  # Class that holds configuration parameters
8
8
  class Configuration
9
9
  def initialize
10
10
  @default_architecture = :auto
11
11
  @default_format = :elf
12
- @gas_command = "/usr/bin/as"
13
- @nasm_command = ""
12
+ @gas_command = "as"
13
+ @nasm_command = "nasm"
14
14
  end
15
15
 
16
16
  attr_accessor :default_format,
@@ -166,6 +166,7 @@ module Voodoo
166
166
  emit "xor rax, rax\n"
167
167
  # If value_ref is a symbol, use PLT-relative addressing
168
168
  if global?(func)
169
+ @symbol_tracker.use func
169
170
  emit "call #{value_ref} wrt ..plt\n"
170
171
  else
171
172
  emit "call #{value_ref}\n"
@@ -49,15 +49,26 @@ module Voodoo
49
49
  # saved r14
50
50
  # saved r11
51
51
  # :
52
- # saved r4 <-- r13 points here
52
+ # saved r4
53
+ # local6
54
+ # :
55
+ # localn <-- r13 points here
53
56
  #
54
57
  # == Register Usage
55
58
  #
56
59
  # Inside a function, registers r4..r8 and r10 are used for local variables
57
60
  # and function arguments, whereas r11 is used as a frame pointer.
58
61
  #
59
- # r12 is used as a temporary, and r3 is used when another temporary
60
- # is needed.
62
+ # r12 is used as a temporary, and r3, r2 and r1 are used when more
63
+ # temporaries are needed.
64
+ #
65
+ # == Local Variables
66
+ #
67
+ # Local variables are used to store both the first 4 function arguments
68
+ # and any variables declared inside the function (arguments beyond the 4th
69
+ # are stored on the stack, as per the calling convention). Local variables
70
+ # beyond the 6th are stored on the stack, starting below the saved registers
71
+ # and counting down.
61
72
  #
62
73
  class ARMGasGenerator < CommonCodeGenerator
63
74
  def initialize params
@@ -88,9 +99,10 @@ module Voodoo
88
99
  @frame_offset = 0
89
100
  @frame_size = 0
90
101
  @function_end_label = nil
91
- @imports = {}
102
+ @imports = Set.new
92
103
  @if_labels = []
93
104
  @saved_registers = [] # registers we've saved in the current frame
105
+ @saved_size = 0 # bytes dedicated to saved registers
94
106
  super params
95
107
  @output_file_suffix = '.s'
96
108
  @features.merge! \
@@ -222,6 +234,7 @@ module Voodoo
222
234
 
223
235
  # Call function
224
236
  if global? func
237
+ @symbol_tracker.use func
225
238
  emit "bl #{func}\n"
226
239
  else
227
240
  with_temporary do |temporary|
@@ -254,6 +267,7 @@ module Voodoo
254
267
  clobbered << @FP
255
268
  clobbered << :lr if save_lr
256
269
  @saved_registers = clobbered
270
+ @saved_size = @saved_registers.length * @WORDSIZE
257
271
  emit "stmfd sp!, {#{clobbered.join ', '}}\n"
258
272
  emit "add #{@FP}, sp, \##{clobbered.length * @WORDSIZE}\n"
259
273
 
@@ -378,7 +392,7 @@ module Voodoo
378
392
  # If we are returning to top level, restore stack pointer
379
393
  # and saved registers.
380
394
  if @environment.parent == @top_level
381
- offset = @frame_size - @saved_registers.length * @WORDSIZE
395
+ offset = @frame_size - @saved_size
382
396
  if offset > 0
383
397
  emit "add sp, sp, \##{offset}\n"
384
398
  end
@@ -386,6 +400,7 @@ module Voodoo
386
400
  @frame_size = 0
387
401
  @frame_offset = 0
388
402
  @saved_registers = []
403
+ @saved_size = 0
389
404
 
390
405
  # If we need to emit constants, do so now
391
406
  unless @constants.empty?
@@ -411,6 +426,7 @@ module Voodoo
411
426
  @frame_size = 0
412
427
  @frame_offset = 0
413
428
  @saved_registers = []
429
+ @saved_size = 0
414
430
  @environment = @top_level
415
431
  end
416
432
 
@@ -427,13 +443,13 @@ module Voodoo
427
443
  case op
428
444
  when :div
429
445
  func = :"__aeabi_idiv"
430
- import func unless @imports.has_key? func
446
+ import func unless @imports.member? func
431
447
  call func, expr[1], expr[2]
432
448
  emit "cpy #{register}, r0\n" if register != :r0
433
449
  return
434
450
  when :mod
435
451
  func = :"__aeabi_idivmod"
436
- import func unless @imports.has_key? func
452
+ import func unless @imports.member? func
437
453
  call func, expr[1], expr[2]
438
454
  emit "cpy #{register}, r1\n" if register != :r1
439
455
  return
@@ -642,8 +658,9 @@ module Voodoo
642
658
 
643
659
  # Import labels into the current section
644
660
  def import *symbols
645
- # Record imported labels in @imports
646
- symbols.each { |sym| @imports[sym] = sym }
661
+ # Record imported labels in @imports and @symbol_tracker
662
+ @imports.merge symbols
663
+ @symbol_tracker.define *symbols
647
664
  end
648
665
 
649
666
  # Introduce a new local variable
@@ -703,7 +720,8 @@ module Voodoo
703
720
 
704
721
  # Returns the fp-relative reference for the nth (0-based) local.
705
722
  def local_offset n
706
- -@INITIAL_FRAME_SIZE - ((n + number_of_register_arguments) * @WORDSIZE)
723
+ nstack_locals = n + number_of_register_arguments - @NREGISTER_LOCALS
724
+ -(nstack_locals + 1) * @WORDSIZE - @saved_size
707
725
  end
708
726
 
709
727
  # Given an offset, returns an fp-relative reference.
@@ -935,6 +953,7 @@ module Voodoo
935
953
  return register
936
954
  else
937
955
  # Assume global
956
+ @symbol_tracker.use x
938
957
  lbl = add_constant x
939
958
  emit "ldr #{register}, #{lbl}\n"
940
959
  return register
@@ -1,4 +1,5 @@
1
1
  require 'set'
2
+ require 'voodoo/symbol_tracker'
2
3
 
3
4
  module Voodoo
4
5
  # Common base class for code generators.
@@ -48,6 +49,7 @@ module Voodoo
48
49
  @output_file_suffix = '.o'
49
50
  @open_labels = [] # Labels for which we must emit size annotations
50
51
  @relocated_symbols = Set.new
52
+ @symbol_tracker = SymbolTracker.new
51
53
  @features = {
52
54
  :voodoo => "1.1" # Voodoo language version
53
55
  }
@@ -309,6 +311,7 @@ module Voodoo
309
311
  if real_section_name(section) == ".data"
310
312
  @relocated_symbols.merge symbols
311
313
  end
314
+ @symbol_tracker.use *symbols
312
315
  emit_export *symbols
313
316
  end
314
317
 
@@ -332,6 +335,7 @@ module Voodoo
332
335
  if real_section_name(section) == ".data"
333
336
  @relocated_symbols.merge symbols
334
337
  end
338
+ @symbol_tracker.define *symbols
335
339
  emit_import *symbols
336
340
  end
337
341
 
@@ -368,6 +372,7 @@ module Voodoo
368
372
  emit_label_type name, type
369
373
  @open_labels << name
370
374
  end
375
+ @symbol_tracker.define name
371
376
  emit_label name
372
377
  end
373
378
 
@@ -565,6 +570,11 @@ module Voodoo
565
570
  [:add, :and, :mul, :or, :xor].member? op
566
571
  end
567
572
 
573
+ # Returns a set of symbols that have been used, but not defined.
574
+ def undefined_symbols
575
+ @symbol_tracker.used_but_undefined_symbols
576
+ end
577
+
568
578
  # Executes a block of code, passing the block the name of +n+
569
579
  # unused temporary registers.
570
580
  #
@@ -698,6 +708,11 @@ module Voodoo
698
708
  def count_locals_helper statements, count, max
699
709
  statements.each do |statement|
700
710
  case statement[0]
711
+ when :ifeq, :ifge, :ifgt, :ifle, :iflt, :ifne
712
+ max = count_locals_helper statement[2], count, max
713
+ if statement.length > 3
714
+ max = count_locals_helper statement[3], count, max
715
+ end
701
716
  when :block
702
717
  max = count_locals_helper statement[1..-1], count, max
703
718
  when :let
@@ -1,10 +1,102 @@
1
+ require 'set'
2
+ require 'voodoo/symbol_tracker'
3
+
1
4
  module Voodoo
2
- # Generator that does nothing.
5
+ # Generator that does not generate code.
3
6
  class DummyGenerator
4
- def add *args
7
+ def initialize *params
8
+ @locals = Set.new
9
+ @symbol_tracker = SymbolTracker.new
10
+ end
11
+
12
+ def add section, *code
13
+ analyze code
14
+ end
15
+
16
+ # Returns a set of symbols that have been used, but not defined.
17
+ def undefined_symbols
18
+ @symbol_tracker.used_but_undefined_symbols
5
19
  end
6
20
 
7
21
  def write *args
8
22
  end
23
+
24
+ private
25
+
26
+ def analyze statements
27
+ statements.each { |code| analyze_statement code }
28
+ end
29
+
30
+ def analyze_statement code
31
+ case code[0]
32
+ when :block
33
+ old_locals = @locals
34
+ @locals = Set.new @locals
35
+ begin
36
+ analyze code[1..-1]
37
+ ensure
38
+ @locals = old_locals
39
+ end
40
+ when :export
41
+ use *code[1..-1]
42
+ when :function
43
+ old_locals = @locals
44
+ @locals = Set.new @locals
45
+ @locals.merge code[1]
46
+ begin
47
+ analyze code[2..-1]
48
+ ensure
49
+ @locals = old_locals
50
+ end
51
+ when :import
52
+ define *code[1..-1]
53
+ when :label
54
+ define code[1]
55
+ when :let
56
+ define code[1]
57
+ analyze_expr code[2..-1]
58
+ when :return
59
+ analyze_expr code[1..-1]
60
+ when :set
61
+ analyze_values [code[1]]
62
+ analyze_expr code[2..-1]
63
+ else
64
+ if code[0].to_s[0...2] == "if"
65
+ analyze_values code[1]
66
+ analyze code[2]
67
+ analyze code[3] if code.length > 3
68
+ else
69
+ analyze_values code[1..-1]
70
+ end
71
+ end
72
+ end
73
+
74
+ def analyze_expr code
75
+ if code.length == 1
76
+ analyze_values code
77
+ else
78
+ analyze_values code[1..-1]
79
+ end
80
+ end
81
+
82
+ def analyze_values values
83
+ values.each do |x|
84
+ if x.kind_of? Symbol
85
+ use x
86
+ elsif x.respond_to?(:[]) && x[0] == :'@'
87
+ analyze_values x[1]
88
+ end
89
+ end
90
+ end
91
+
92
+ def define *symbols
93
+ @symbol_tracker.define *symbols
94
+ end
95
+
96
+ def use *symbols
97
+ syms = Set.new symbols
98
+ nonlocals = syms - @locals
99
+ @symbol_tracker.use *nonlocals
100
+ end
9
101
  end
10
102
  end
@@ -281,6 +281,7 @@ module Voodoo
281
281
 
282
282
  # Load function address
283
283
  if global? func
284
+ @symbol_tracker.use func
284
285
  if @imports.has_key? func
285
286
  # Load address from global offset table
286
287
  emit "lw #{@FUNCTION}, %call16(#{func})(#{@GOT})\n"
@@ -55,6 +55,7 @@ module Voodoo
55
55
 
56
56
  # Import labels into the current section
57
57
  def import *symbols
58
+ @symbol_tracker.define *symbols
58
59
  if real_section_name(section) != ".text"
59
60
  @relocated_symbols.merge symbols
60
61
  end
@@ -351,6 +352,7 @@ module Voodoo
351
352
  offset_reference x
352
353
  else
353
354
  # Assume global
355
+ @symbol_tracker.use symbol
354
356
  if @relocated_symbols.include? symbol
355
357
  load_symbol_from_got symbol, reg
356
358
  else
@@ -320,8 +320,13 @@ module Voodoo
320
320
  # This method should be called while the lookahead is the first
321
321
  # character of the symbol name.
322
322
  def parse_symbol
323
+ parse_symbol1 ''
324
+ end
325
+
326
+ # Continues parsing a symbol.
327
+ # +name+ the part of the symbol that has already been parsed.
328
+ def parse_symbol1 name
323
329
  wrap_exceptions do
324
- name = ''
325
330
  while lookahead != :eof
326
331
  case lookahead
327
332
  when "\\"
@@ -547,9 +552,20 @@ module Voodoo
547
552
  when NUMBER_STARTER
548
553
  # Digit; parse number
549
554
  parse_number
555
+ when "\\"
556
+ # Check if this is the line continuation escape or some other escape.
557
+ decoded = parse_escape
558
+ if decoded == ''
559
+ # Line continuation. Now that we've parsed that, try again.
560
+ try_parse_token
561
+ else
562
+ # Some other escape. That means it's a symbol.
563
+ parse_symbol1 decoded
564
+ end
550
565
  when SYMBOL_STARTER
551
566
  # Letter, underscore, or backslash; parse symbol
552
- # Note: \w matches digits, too, so keep this case after \d
567
+ # Note: SYMBOL_STARTER matches digits and backslashes, too, so
568
+ # keep it after the cases that match those.
553
569
  parse_symbol
554
570
  when STRING_STARTER
555
571
  # Double quote; parse string
@@ -0,0 +1,35 @@
1
+ require 'set'
2
+
3
+ module Voodoo
4
+ # Class to keep track of defined and used symbols.
5
+ class SymbolTracker
6
+ def initialize
7
+ @defined = Set.new
8
+ @used = Set.new
9
+ end
10
+
11
+ def define *symbols
12
+ @defined.merge symbols
13
+ end
14
+
15
+ def use *symbols
16
+ @used.merge symbols
17
+ end
18
+
19
+ def defined_but_unused_symbols
20
+ @defined - @used
21
+ end
22
+
23
+ def defined_symbols
24
+ @defined
25
+ end
26
+
27
+ def used_symbols
28
+ @used
29
+ end
30
+
31
+ def used_but_undefined_symbols
32
+ @used - @defined
33
+ end
34
+ end
35
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: voodoo
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.1
4
+ version: 1.1.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-07-15 00:00:00.000000000 Z
12
+ date: 2013-10-21 00:00:00.000000000 Z
13
13
  dependencies: []
14
14
  description: ! 'The Voodoo compiler is an implementation of the Voodoo programming
15
15
 
@@ -50,6 +50,7 @@ files:
50
50
  - lib/voodoo/compiler.rb
51
51
  - lib/voodoo/validator.rb
52
52
  - lib/voodoo/config.rb
53
+ - lib/voodoo/symbol_tracker.rb
53
54
  homepage: http://inglorion.net/software/voodoo/
54
55
  licenses: []
55
56
  post_install_message: