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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0c7b411e21f2b93443cb22e7461437c8ab98df8acc4fd56538d64c8fc0d7c828
4
- data.tar.gz: 05747db808c1d5accc8b42ee6681b2a617feb89437bf244e389420740a3d4da0
3
+ metadata.gz: b00e5940820b7f2798ede46f7014a87ab43d7ade0ca171c223eae550668673c0
4
+ data.tar.gz: dcd9d7bd8d170a37206d51a6b427c48217d115f048620404b045a8f6005eb6e0
5
5
  SHA512:
6
- metadata.gz: 0a302052eb6c01c1f6812e98b8492fc455077746effb6e6d6133a411eb179b157ecf3bc1a4bcd38e85e1a1dc2aea52dee4cfd7088b9212b73df6f0912ac9d1fc
7
- data.tar.gz: af2d6fb1f53eae49d7121fc90048d1bc5766316bc302fd910bc1702cf4dab3f43fd09ee01433fbb11f8ec4419de7191a0cc02fd64bb43f8c998173c78acc0237
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
- class ArchManager
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
- Dir[File.join(__dir__, 'arch_entries', '*.rb')].each { |file| require file }
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
- class CompilerFunctions
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
- lines.each_with_index do |line, line_i|
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| [" ", "\t"].include? 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(operands, state)
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
- labels = get_labels(parsed_lines)
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