kompiler 0.3.0.pre.2 → 0.3.0.pre.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0c7b411e21f2b93443cb22e7461437c8ab98df8acc4fd56538d64c8fc0d7c828
4
- data.tar.gz: 05747db808c1d5accc8b42ee6681b2a617feb89437bf244e389420740a3d4da0
3
+ metadata.gz: d37e70a65615ea1b7aece9de1a2ae544a30d9f3f9f1f44d233fac8ecde023b63
4
+ data.tar.gz: 533a6ac4a19a03c8ca483c63bf454d4cda802943462ea23bcbc1a59688e64d8d
5
5
  SHA512:
6
- metadata.gz: 0a302052eb6c01c1f6812e98b8492fc455077746effb6e6d6133a411eb179b157ecf3bc1a4bcd38e85e1a1dc2aea52dee4cfd7088b9212b73df6f0912ac9d1fc
7
- data.tar.gz: af2d6fb1f53eae49d7121fc90048d1bc5766316bc302fd910bc1702cf4dab3f43fd09ee01433fbb11f8ec4419de7191a0cc02fd64bb43f8c998173c78acc0237
6
+ metadata.gz: ad275ed1d7bbb7dad29409b3ca2f4e061c08f4534bf7c2104d2c20c235a1030e496ae6381322042fe1d1bdd699acc5e970ef82b521031853d4222792b6bf388f
7
+ data.tar.gz: 9132f9c232bc01ff2ebfac62bfa09527e79f644ce0d15a360de91ece0a854187da581b6e67c2bec78e6745845fb2257c759786d71e02d44f17fbf4919e7e106c
@@ -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)
@@ -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,7 +3,7 @@
3
3
 
4
4
  module Kompiler
5
5
 
6
- class CompilerFunctions
6
+ module CompilerFunctions
7
7
 
8
8
  def self.parse_includes(lines, loaded_files=[])
9
9
 
@@ -83,6 +83,113 @@ def self.parse_includes(lines, loaded_files=[])
83
83
  end
84
84
 
85
85
 
86
+ def self.parse_macros(lines)
87
+
88
+ macros = []
89
+
90
+ line_i = 0
91
+
92
+ loop do
93
+ break if line_i >= lines.size
94
+
95
+ line = lines[line_i]
96
+
97
+ keyword, operands = Kompiler::Parsers.parse_instruction_line line
98
+
99
+ keyword = keyword[1..] if keyword.start_with? "."
100
+
101
+ if keyword == 'macro'
102
+ raise "Macro definition error: Expected two operands to be provided, while #{operands.size} were given" if operands.size != 2
103
+ raise "Macro definition error: The macro name must either be a word or a string" if !["label", "string"].include?(operands[0][:type])
104
+
105
+ case operands[0][:type]
106
+ when "label"
107
+ macro_name = operands[0][:value]
108
+ when "string"
109
+ macro_name = operands[0][:value]
110
+ end
111
+
112
+ macro_definition = operands[1][:definition]
113
+
114
+ macros << {name: macro_name, definition: macro_definition}
115
+
116
+ lines.delete_at line_i
117
+ else
118
+ line_i += 1
119
+ end
120
+ end
121
+
122
+ # Apply the macros to all lines, and then the lines that were changed, and than again, and so on (iterative loop until none of the lines need to be checked)
123
+
124
+ lines_to_check = (0...lines.size).to_a
125
+
126
+ while lines_to_check.size != 0 # Repeat until no more lines to check
127
+
128
+ # Define restricted separators characters (characters that CAN'T separate a macro from everything else)
129
+ restricted_separator_chars = ("a".."z").to_a + ("A".."Z").to_a + ("0".."9").to_a + ["_", "."]
130
+
131
+ # Create an array for the lines to check once again
132
+ new_lines_to_check = []
133
+
134
+ lines_to_check.each do |line_i|
135
+ line = lines[line_i]
136
+
137
+ char_i = 0
138
+
139
+ # Create a variable to indicate if a macro was used on the current line
140
+ line_macro_used = false
141
+
142
+ loop do
143
+ break if char_i >= line.size
144
+
145
+ if ['"', "'"].include? line[char_i]
146
+ # If a string, skip it
147
+ str, parsed_length = Kompiler::Parsers.parse_str line[char_i..]
148
+ char_i += parsed_length
149
+ next
150
+ end
151
+
152
+ cut_line = line[char_i..]
153
+
154
+ # Create a variable to indicate if a macro was used in the current position
155
+ macro_used = false
156
+
157
+ macros.each do |macro|
158
+ macro_name = macro[:name]
159
+ macro_def = macro[:definition]
160
+ next if !cut_line.start_with?(macro_name) # Skip if doesn't begin with the macro's name
161
+ next if (cut_line.size > macro_name.size) && restricted_separator_chars.include?(cut_line[macro_name.size]) # Skip if there is a character after the macro name, and the character is not permitted
162
+ next if (char_i > 0) && restricted_separator_chars.include?(line[char_i - 1]) # Skip if there is a character before the checking sequence, and the character is not permitted
163
+
164
+ # Here if the macro is 'accepted'
165
+ line = line[...char_i] + macro_def + line[(char_i + macro_name.size)..]
166
+ # Indicate that a macro was used
167
+ macro_used = true
168
+ end
169
+
170
+ if macro_used
171
+ # If a macro was used, indicate that on line level
172
+ line_macro_used = true
173
+ else
174
+ # If a macro wasn't used, proceed to the next character
175
+ char_i += 1
176
+ end
177
+ end # line characters loop
178
+
179
+ if line_macro_used
180
+ # If a macro was used on the current line, update the lines array, and add the line to check for macros again
181
+ lines[line_i] = line
182
+ new_lines_to_check << line_i
183
+ end
184
+ end # lines_to_check.each loop
185
+
186
+ lines_to_check = new_lines_to_check # Update lines to check with the new ones
187
+
188
+ end # while lines_to_check.size != 0 loop
189
+
190
+ lines
191
+ end
192
+
86
193
 
87
194
  def self.parse_code(lines)
88
195
 
@@ -97,7 +204,7 @@ def self.parse_code(lines)
97
204
  if !is_char_whitespace.include?(false) # If only whitespace
98
205
  next # Skip
99
206
  end
100
-
207
+
101
208
  #
102
209
  # Label definitions are now a directive, so this isn't needed
103
210
  #
@@ -243,17 +350,19 @@ end
243
350
  def self.compile(code, included_files=[])
244
351
 
245
352
  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)
353
+
354
+ included_lines = parse_includes(lines, included_files.map{|fname| File.expand_path(fname)})
355
+
356
+ macroed_lines = parse_macros(included_lines)
357
+
358
+ parsed_lines = parse_code(macroed_lines)
250
359
 
251
360
  labels = get_labels(parsed_lines)
252
361
 
253
362
  # machine_code_bit_lines = construct_program_mc(parsed_lines, labels)
254
363
  #
255
364
  # machine_code_bytes = bit_lines_to_bytes(machine_code_bit_lines)
256
-
365
+
257
366
  machine_code_bytes = construct_program_mc(parsed_lines, labels)
258
367
  end
259
368
 
@@ -3,7 +3,7 @@
3
3
 
4
4
  module Kompiler
5
5
 
6
- class Parsers
6
+ module Parsers
7
7
 
8
8
  def self.parse_str(code)
9
9
 
@@ -195,7 +195,7 @@ def self.check_label_operand(str)
195
195
  return false if ("0".."9").to_a.include?(str[0])
196
196
 
197
197
  # Check if it's only made up of allowed characters
198
- allowed_chars = ("a".."z").to_a + ("A".."Z").to_a + ("0".."9").to_a + ["_"]
198
+ allowed_chars = ("a".."z").to_a + ("A".."Z").to_a + ("0".."9").to_a + ["_", "."]
199
199
 
200
200
  is_each_char_allowed = str.each_char.map{|c| allowed_chars.include?(c)}
201
201
 
@@ -366,10 +366,9 @@ end
366
366
 
367
367
  # Returns array of [status, operands]
368
368
  # If status = false, operands = nil; otherwise, status = true, operands = instruction operands
369
- def self.match_instruction(line, instruction)
370
-
371
- keyword, operands = parse_instruction_line(line)
369
+ def self.match_parsed_line_to_instruction(parsed_line, instruction)
372
370
 
371
+ keyword, operands = parsed_line
373
372
 
374
373
  # Check if the keyword matches
375
374
  if instruction[:keyword] != keyword
@@ -396,9 +395,12 @@ def self.check_instruction(line)
396
395
  instruction = nil
397
396
  operands = nil
398
397
 
398
+ parsed_line = Kompiler::Parsers.parse_instruction_line(line)
399
+
399
400
  Kompiler::Architecture.instructions.each do |curr_instruction|
400
401
  # If the instruction matches - break
401
- status, curr_operands = match_instruction(line, curr_instruction)
402
+
403
+ status, curr_operands = match_parsed_line_to_instruction(parsed_line, curr_instruction)
402
404
  if status == true
403
405
  instruction = curr_instruction
404
406
  operands = curr_operands
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kompiler
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0.pre.2
4
+ version: 0.3.0.pre.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kyryl Shyshko
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-12-23 00:00:00.000000000 Z
11
+ date: 2025-01-17 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: 'Kompiler is a low-level, modular and extendable compiler for any architecture.
14
14
  By default Kompiler supports ARMv8-a, but other architecture extensions can be downloaded