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.
- data/bin/voodooc +2 -2
- data/lib/voodoo/compiler.rb +7 -0
- data/lib/voodoo/config.rb +3 -3
- data/lib/voodoo/generators/amd64_nasm_generator.rb +1 -0
- data/lib/voodoo/generators/arm_gas_generator.rb +29 -10
- data/lib/voodoo/generators/common_code_generator.rb +15 -0
- data/lib/voodoo/generators/dummy_generator.rb +94 -2
- data/lib/voodoo/generators/mips_gas_generator.rb +1 -0
- data/lib/voodoo/generators/nasm_generator.rb +2 -0
- data/lib/voodoo/parser.rb +18 -2
- data/lib/voodoo/symbol_tracker.rb +35 -0
- metadata +3 -2
data/bin/voodooc
CHANGED
@@ -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
|
data/lib/voodoo/compiler.rb
CHANGED
@@ -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
|
data/lib/voodoo/config.rb
CHANGED
@@ -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.
|
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 = "
|
13
|
-
@nasm_command = ""
|
12
|
+
@gas_command = "as"
|
13
|
+
@nasm_command = "nasm"
|
14
14
|
end
|
15
15
|
|
16
16
|
attr_accessor :default_format,
|
@@ -49,15 +49,26 @@ module Voodoo
|
|
49
49
|
# saved r14
|
50
50
|
# saved r11
|
51
51
|
# :
|
52
|
-
# saved r4
|
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
|
60
|
-
#
|
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 - @
|
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.
|
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.
|
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
|
-
|
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
|
-
|
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
|
5
|
+
# Generator that does not generate code.
|
3
6
|
class DummyGenerator
|
4
|
-
def
|
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
|
@@ -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
|
data/lib/voodoo/parser.rb
CHANGED
@@ -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:
|
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.
|
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-
|
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:
|