voodoo 1.1.1 → 1.1.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: