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