kompiler 0.3.0.pre.2 → 0.3.0.pre.4
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.
- checksums.yaml +4 -4
- data/lib/kompiler/arch_manager.rb +2 -2
- data/lib/kompiler/architectures/armv8a/instructions.rb +12 -0
- data/lib/kompiler/compiler_functions.rb +110 -106
- data/lib/kompiler/config.rb +29 -0
- data/lib/kompiler/directives.rb +354 -4
- data/lib/kompiler/math_ast.rb +665 -0
- data/lib/kompiler/parsers.rb +124 -51
- data/lib/kompiler.rb +3 -1
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b00e5940820b7f2798ede46f7014a87ab43d7ade0ca171c223eae550668673c0
|
4
|
+
data.tar.gz: dcd9d7bd8d170a37206d51a6b427c48217d115f048620404b045a8f6005eb6e0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 023ae20fa5229d793e71ebea06bc46dea243170129e12eaf5c099c16dabdabcecb6302f0893ef17cbf0128c30a8d7d9f0b77841ecfa6ddb871d18e0c517373d4
|
7
|
+
data.tar.gz: ae856004b38f75b46b4b62c7455c5f94cbeb2f21dd34e54443ff776f4fbb23432eb42f389bd706f3d649c8b2d69bee3a3e2d2cf7095d24178c32e50f32b47149
|
@@ -4,7 +4,7 @@
|
|
4
4
|
module Kompiler
|
5
5
|
|
6
6
|
# Object for managing architecture entries / available architectures
|
7
|
-
|
7
|
+
module ArchManager
|
8
8
|
@arch_entries = []
|
9
9
|
|
10
10
|
def self.add_arch(arch_name, include_path)
|
@@ -20,7 +20,7 @@ module Kompiler
|
|
20
20
|
end
|
21
21
|
|
22
22
|
def self.load_all_entries
|
23
|
-
|
23
|
+
Gem.find_files("kompiler/arch_entries/*").each { |file| require file }
|
24
24
|
end
|
25
25
|
end
|
26
26
|
|
@@ -954,6 +954,18 @@ end
|
|
954
954
|
],
|
955
955
|
bitsize: 32
|
956
956
|
},
|
957
|
+
{
|
958
|
+
keyword: "svc",
|
959
|
+
name: "Supervisor Call",
|
960
|
+
description: "Triggers a synchronous exception taken to EL1, passing an immediate value to the ESR_ELx system register.",
|
961
|
+
operands: [{type: "immediate", name: "Immediate"}],
|
962
|
+
mc_constructor: [
|
963
|
+
["bits", 1,0, 0,0,0],
|
964
|
+
["get_bits", ["get_operand", 0], 0, 16],
|
965
|
+
["bits", 0,0,0, 0,0,1,0,1,0,1,1],
|
966
|
+
],
|
967
|
+
bitsize: 32
|
968
|
+
},
|
957
969
|
|
958
970
|
|
959
971
|
#
|
@@ -3,86 +3,7 @@
|
|
3
3
|
|
4
4
|
module Kompiler
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
def self.parse_includes(lines, loaded_files=[])
|
9
|
-
|
10
|
-
final_lines = lines.dup
|
11
|
-
|
12
|
-
line_i = 0
|
13
|
-
|
14
|
-
loop do
|
15
|
-
break if line_i >= final_lines.size
|
16
|
-
|
17
|
-
line = final_lines[line_i]
|
18
|
-
|
19
|
-
keyword, operands = Kompiler::Parsers.parse_instruction_line(line)
|
20
|
-
|
21
|
-
if keyword == false
|
22
|
-
line_i += 1
|
23
|
-
next
|
24
|
-
end
|
25
|
-
|
26
|
-
if keyword.start_with? "."
|
27
|
-
keyword = keyword[1..]
|
28
|
-
end
|
29
|
-
|
30
|
-
if !["load", "include", "load_end", "include_end"].include?(keyword)
|
31
|
-
line_i += 1
|
32
|
-
next
|
33
|
-
end
|
34
|
-
|
35
|
-
raise "Incorrect use of the \"#{keyword}\" directive: requires a filename in a string." if operands.size != 1 || (operands.size == 1 && operands[0][:type] != "string")
|
36
|
-
|
37
|
-
load_file_name_selector = operands[0][:string]
|
38
|
-
|
39
|
-
|
40
|
-
# Remove the include code line from the lines array
|
41
|
-
final_lines.delete_at line_i
|
42
|
-
|
43
|
-
# If ends with _end, that means that the file contents should be appended at the end of the current lines
|
44
|
-
if keyword.end_with? "_end"
|
45
|
-
next_i_insert = final_lines.size
|
46
|
-
else
|
47
|
-
# If doesn't end with _end, files should be loaded in-place of the current line
|
48
|
-
next_i_insert = line_i
|
49
|
-
end
|
50
|
-
|
51
|
-
|
52
|
-
Dir[load_file_name_selector].each do |load_file_name|
|
53
|
-
# Get the absolute path filename
|
54
|
-
full_file_name = File.expand_path(load_file_name)
|
55
|
-
|
56
|
-
raise "#{keyword} \"#{load_file_name}\": File not found." if !File.exist?(full_file_name)
|
57
|
-
|
58
|
-
# Check if the file was already loaded (stop recursive loading)
|
59
|
-
if loaded_files.include?(full_file_name)
|
60
|
-
next
|
61
|
-
end
|
62
|
-
|
63
|
-
# Read the file to load
|
64
|
-
include_code = File.read(full_file_name)
|
65
|
-
|
66
|
-
# Separate the lines inside it
|
67
|
-
include_code_lines = Kompiler::Parsers.get_code_lines(include_code)
|
68
|
-
|
69
|
-
# Add the lines from the load file to the lines array at the line_i index, effectively replacing the load command with the content of the load file
|
70
|
-
final_lines.insert next_i_insert, *include_code_lines
|
71
|
-
|
72
|
-
next_i_insert += include_code_lines.size
|
73
|
-
|
74
|
-
# Add the filename (absolute path) to the list of included files
|
75
|
-
loaded_files << full_file_name
|
76
|
-
end
|
77
|
-
|
78
|
-
# Don't increment line_i, since the new loop will now start include-parsing the newly loaded file in the same program
|
79
|
-
end
|
80
|
-
|
81
|
-
final_lines
|
82
|
-
|
83
|
-
end
|
84
|
-
|
85
|
-
|
6
|
+
module CompilerFunctions
|
86
7
|
|
87
8
|
def self.parse_code(lines)
|
88
9
|
|
@@ -90,30 +11,29 @@ def self.parse_code(lines)
|
|
90
11
|
|
91
12
|
instr_adr = 0
|
92
13
|
|
93
|
-
|
14
|
+
line_i = 0
|
15
|
+
|
16
|
+
extra_state = Hash.new
|
17
|
+
|
18
|
+
add_later_directives = []
|
19
|
+
|
20
|
+
while line_i < lines.size
|
21
|
+
line = lines[line_i]
|
94
22
|
|
95
23
|
# Check if line is not just whitespace
|
96
|
-
is_char_whitespace = line.each_char.map{|c|
|
24
|
+
is_char_whitespace = line.each_char.map{|c| Kompiler::Config.whitespace_chars.include? c}
|
97
25
|
if !is_char_whitespace.include?(false) # If only whitespace
|
26
|
+
line_i += 1
|
98
27
|
next # Skip
|
99
28
|
end
|
100
|
-
|
101
|
-
#
|
102
|
-
# Label definitions are now a directive, so this isn't needed
|
103
|
-
#
|
104
29
|
|
105
|
-
# is_label, label_name = check_label(line)
|
106
|
-
# if is_label
|
107
|
-
# # labels[label_name] = instr_adr
|
108
|
-
# parsed_lines << {type: "label", label_name: label_name, label_address: instr_adr, address: instr_adr}
|
109
|
-
# next
|
110
|
-
# end
|
111
|
-
|
112
30
|
is_instruction, exec_instruction = Kompiler::Parsers.check_instruction(line)
|
113
31
|
if is_instruction
|
114
32
|
parsed_lines << {type: "instruction", instruction: exec_instruction[:instruction], operands: exec_instruction[:operands], address: instr_adr}
|
115
33
|
instr_adr += exec_instruction[:instruction][:bitsize] / 8
|
116
|
-
|
34
|
+
|
35
|
+
line_i += 1
|
36
|
+
|
117
37
|
next # Go to the next line
|
118
38
|
end
|
119
39
|
|
@@ -123,12 +43,59 @@ def self.parse_code(lines)
|
|
123
43
|
directive = directive_hash[:directive]
|
124
44
|
operands = directive_hash[:operands]
|
125
45
|
|
126
|
-
state = {current_address: instr_adr, parsed_lines: parsed_lines}
|
46
|
+
state = {current_address: instr_adr, parsed_lines: parsed_lines, lines: lines, line_i: line_i, extra_state: extra_state}
|
47
|
+
|
48
|
+
add_later_directive = false
|
49
|
+
|
50
|
+
if directive.keys.include?(:add_later_directive) && directive[:add_later_directive] == true
|
51
|
+
add_later_directive = true
|
52
|
+
end
|
53
|
+
|
54
|
+
new_operands = operands.map do |op|
|
55
|
+
if op[:type] == "run_block"
|
56
|
+
begin
|
57
|
+
block_state = state.dup
|
58
|
+
block_state[:block_args] = op[:block_args]
|
59
|
+
block_state[:labels] = self.get_labels(parsed_lines)
|
60
|
+
op = op[:block].call(block_state)
|
61
|
+
rescue
|
62
|
+
add_later_directive = true
|
63
|
+
op = {type: "immediate", value: 0, def_type: "kompiler_test_value", definition: "0"}
|
64
|
+
end
|
65
|
+
end
|
66
|
+
op
|
67
|
+
end
|
68
|
+
|
69
|
+
|
70
|
+
if add_later_directive
|
71
|
+
|
72
|
+
try_state = {current_address: instr_adr, parsed_lines: parsed_lines.dup, lines: lines.dup, line_i: line_i, extra_state: extra_state.dup}
|
73
|
+
|
74
|
+
try_state = directive[:func].call(new_operands, try_state)
|
75
|
+
|
76
|
+
|
77
|
+
instr_adr = try_state[:current_address]
|
78
|
+
line_i = try_state[:line_i]
|
79
|
+
|
80
|
+
raise "Directive error 1.1" if !(lines == try_state[:lines])
|
81
|
+
raise "Directive error 1.2" if !(extra_state == try_state[:extra_state])
|
82
|
+
raise "Directive error 1.3" if !(parsed_lines == try_state[:parsed_lines][...parsed_lines.size]) # Check that the previous parsed lines were not changed by the directive
|
83
|
+
|
84
|
+
state.delete :parsed_lines
|
85
|
+
state.delete :lines
|
86
|
+
|
87
|
+
add_later_directives << {directive_hash: directive_hash, insert_i: parsed_lines.size, run_state: state, return_line_i: line_i, return_current_address: instr_adr}
|
88
|
+
|
89
|
+
next
|
90
|
+
end
|
127
91
|
|
128
|
-
state = directive[:func].call(
|
92
|
+
state = directive[:func].call(new_operands, state)
|
129
93
|
|
130
94
|
instr_adr = state[:current_address]
|
131
95
|
parsed_lines = state[:parsed_lines]
|
96
|
+
lines = state[:lines]
|
97
|
+
line_i = state[:line_i]
|
98
|
+
extra_state = state[:extra_state]
|
132
99
|
|
133
100
|
next # Skip to the next lime
|
134
101
|
end
|
@@ -139,6 +106,37 @@ def self.parse_code(lines)
|
|
139
106
|
|
140
107
|
raise "\"#{line}\" - Unknown syntax: Program build not possible"
|
141
108
|
|
109
|
+
end
|
110
|
+
|
111
|
+
add_later_directives.sort_by{|hash| hash[:insert_i]}.reverse.each do |add_later_directive|
|
112
|
+
directive_hash = add_later_directive[:directive_hash]
|
113
|
+
insert_i = add_later_directive[:insert_i]
|
114
|
+
state = add_later_directive[:run_state]
|
115
|
+
|
116
|
+
state[:parsed_lines] = parsed_lines[...insert_i]
|
117
|
+
state[:lines] = lines
|
118
|
+
|
119
|
+
directive = directive_hash[:directive]
|
120
|
+
operands = directive_hash[:operands]
|
121
|
+
|
122
|
+
new_operands = operands.map do |op|
|
123
|
+
if op[:type] == "run_block"
|
124
|
+
block_state = state.dup
|
125
|
+
block_state[:block_args] = op[:block_args]
|
126
|
+
block_state[:labels] = self.get_labels(parsed_lines)
|
127
|
+
op = op[:block].call(block_state)
|
128
|
+
end
|
129
|
+
op
|
130
|
+
end
|
131
|
+
|
132
|
+
state = directive[:func].call(new_operands, state)
|
133
|
+
|
134
|
+
|
135
|
+
raise "Directive error 2.1" if add_later_directive[:return_current_address] != state[:current_address]
|
136
|
+
raise "Directive error 2.2" if add_later_directive[:return_line_i] != state[:line_i]
|
137
|
+
|
138
|
+
|
139
|
+
parsed_lines = state[:parsed_lines] + parsed_lines[insert_i..]
|
142
140
|
end
|
143
141
|
|
144
142
|
parsed_lines
|
@@ -173,9 +171,21 @@ def self.construct_program_mc(parsed_lines, labels)
|
|
173
171
|
parsed_lines.each do |line|
|
174
172
|
case line[:type]
|
175
173
|
when "instruction"
|
176
|
-
program_state[:operands] = line[:operands]
|
177
174
|
program_state[:current_address] = line[:address]
|
178
175
|
|
176
|
+
operands = line[:operands]
|
177
|
+
operands.map! do |op|
|
178
|
+
if op[:type] == "run_block"
|
179
|
+
state = program_state.dup
|
180
|
+
state[:block_args] = op[:block_args]
|
181
|
+
op = op[:block].call(state)
|
182
|
+
end
|
183
|
+
op
|
184
|
+
end
|
185
|
+
|
186
|
+
program_state[:operands] = operands
|
187
|
+
|
188
|
+
|
179
189
|
mc_constructor = line[:instruction][:mc_constructor]
|
180
190
|
|
181
191
|
instr_bits = Kompiler::MachineCode_AST.build_mc(mc_constructor, program_state)
|
@@ -243,17 +253,11 @@ end
|
|
243
253
|
def self.compile(code, included_files=[])
|
244
254
|
|
245
255
|
lines = Kompiler::Parsers.get_code_lines(code)
|
246
|
-
|
247
|
-
final_lines = parse_includes(lines, included_files.map{|fname| File.expand_path(fname)})
|
248
|
-
|
249
|
-
parsed_lines = parse_code(final_lines)
|
250
256
|
|
251
|
-
|
257
|
+
parsed_lines = parse_code(lines)
|
258
|
+
|
259
|
+
labels = get_labels(parsed_lines)
|
252
260
|
|
253
|
-
# machine_code_bit_lines = construct_program_mc(parsed_lines, labels)
|
254
|
-
#
|
255
|
-
# machine_code_bytes = bit_lines_to_bytes(machine_code_bit_lines)
|
256
|
-
|
257
261
|
machine_code_bytes = construct_program_mc(parsed_lines, labels)
|
258
262
|
end
|
259
263
|
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Kompiler
|
2
|
+
|
3
|
+
module Config
|
4
|
+
|
5
|
+
@keyword_chars = ("a".."z").to_a + ("A".."Z").to_a + ("0".."9").to_a + ["_", "."]
|
6
|
+
@label_chars = ("a".."z").to_a + ("A".."Z").to_a + ("0".."9").to_a + ["_", "."]
|
7
|
+
@whitespace_chars = [" ", "\t"]
|
8
|
+
@string_delimiters = ['"', "'"]
|
9
|
+
|
10
|
+
# Returns the permittable keyword characters
|
11
|
+
def self.keyword_chars
|
12
|
+
@keyword_chars
|
13
|
+
end
|
14
|
+
|
15
|
+
# Returns the permittable label characters
|
16
|
+
def self.label_chars
|
17
|
+
@label_chars
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.whitespace_chars
|
21
|
+
@whitespace_chars
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.string_delimiters
|
25
|
+
@string_delimiters
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|