kompiler 0.3.0.pre.3 → 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 +1 -1
- data/lib/kompiler/compiler_functions.rb +107 -212
- 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 +116 -45
- data/lib/kompiler.rb +3 -1
- metadata +4 -2
data/lib/kompiler/parsers.rb
CHANGED
@@ -171,6 +171,29 @@ def self.check_char_operand(str)
|
|
171
171
|
end
|
172
172
|
|
173
173
|
|
174
|
+
def self.check_expression_operand(str)
|
175
|
+
begin
|
176
|
+
|
177
|
+
ast = Kompiler::Parsers::SymAST.parse str
|
178
|
+
|
179
|
+
run_block = lambda do |state|
|
180
|
+
state[:labels]["here"] = state[:current_address]
|
181
|
+
|
182
|
+
ast_result = Kompiler::Parsers::SymAST.run_ast state[:block_args][:ast], state[:labels], []
|
183
|
+
|
184
|
+
return {type: "immediate", value: ast_result, def_type: "sym_ast", definition: state[:block_args][:definition]}
|
185
|
+
end
|
186
|
+
|
187
|
+
return [true, {type: "run_block", block: run_block, block_args: {ast: ast, definition: str}, block_output_type: "immediate"}]
|
188
|
+
|
189
|
+
rescue RuntimeError => e
|
190
|
+
p e
|
191
|
+
# If an error was caused, return false
|
192
|
+
return [false, nil]
|
193
|
+
end
|
194
|
+
|
195
|
+
end
|
196
|
+
|
174
197
|
|
175
198
|
def self.check_immediate_operand(operand_str)
|
176
199
|
|
@@ -231,45 +254,22 @@ def self.parse_operand_str(operand_str)
|
|
231
254
|
return {type: "label", value: operand_str, definition: operand_str} if is_label
|
232
255
|
|
233
256
|
|
257
|
+
is_expr, expr_operand = check_expression_operand(operand_str)
|
258
|
+
return expr_operand if is_expr
|
259
|
+
|
234
260
|
# If no checks succeeded, return false
|
235
261
|
return false
|
236
262
|
end
|
237
263
|
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
def self.parse_instruction_line(line)
|
242
|
-
keyword = ""
|
264
|
+
# Extract operand strings from the structure "op1, op2, op3, ..."
|
265
|
+
# Returns an array of the operand strings
|
266
|
+
def self.extract_instruction_operands(line)
|
243
267
|
i = 0
|
244
|
-
|
245
|
-
# Loop until a non-whitespace character
|
246
|
-
while i < line.size
|
247
|
-
break if ![" ", "\t"].include?(line[i])
|
248
|
-
i += 1
|
249
|
-
end
|
250
|
-
|
251
|
-
# Loop to get the keyword
|
252
|
-
loop do
|
253
|
-
# Exit out of the loop if the character is a whitespace
|
254
|
-
break if [" ", "\t"].include?(line[i]) || i >= line.size
|
255
|
-
# Add the character if not a whitespace
|
256
|
-
keyword << line[i]
|
257
|
-
# Proceed to the next character
|
258
|
-
i += 1
|
259
|
-
end
|
260
|
-
|
261
268
|
operand_strings = []
|
262
269
|
|
263
|
-
# Loop for operands
|
264
270
|
loop do
|
265
271
|
break if i >= line.size
|
266
|
-
|
267
|
-
# # Whitespace - skip
|
268
|
-
# if [" ", "\t"].include? line[i]
|
269
|
-
# i += 1
|
270
|
-
# next
|
271
|
-
# end
|
272
|
-
|
272
|
+
|
273
273
|
operand_content = ""
|
274
274
|
|
275
275
|
# Collect the operand's content until a comma or end of line
|
@@ -283,13 +283,13 @@ def self.parse_instruction_line(line)
|
|
283
283
|
end
|
284
284
|
|
285
285
|
# Skip whitespace
|
286
|
-
if
|
286
|
+
if Kompiler::Config.whitespace_chars.include? line[i]
|
287
287
|
i += 1
|
288
288
|
next
|
289
289
|
end
|
290
290
|
|
291
291
|
# If a string definition, parse to the end of the string
|
292
|
-
if
|
292
|
+
if Kompiler::Config.string_delimiters.include?(line[i])
|
293
293
|
str_content, parsed_size = parse_str(line[i..])
|
294
294
|
operand_content += line[i] + str_content + line[i]
|
295
295
|
i += parsed_size
|
@@ -305,7 +305,45 @@ def self.parse_instruction_line(line)
|
|
305
305
|
|
306
306
|
# After operand content was collected, add it to the list of operands if the content isn't empty
|
307
307
|
operand_strings << operand_content if operand_content.size != 0
|
308
|
-
end
|
308
|
+
end
|
309
|
+
|
310
|
+
operand_strings
|
311
|
+
end
|
312
|
+
|
313
|
+
|
314
|
+
def self.extract_instruction_parts(line)
|
315
|
+
|
316
|
+
keyword = ""
|
317
|
+
i = 0
|
318
|
+
|
319
|
+
# Loop until a non-whitespace character
|
320
|
+
while i < line.size
|
321
|
+
break if !Kompiler::Config.whitespace_chars.include?(line[i])
|
322
|
+
i += 1
|
323
|
+
end
|
324
|
+
|
325
|
+
# Loop to get the keyword
|
326
|
+
loop do
|
327
|
+
# Exit out of the loop if the character is a whitespace
|
328
|
+
break if Kompiler::Config.whitespace_chars.include?(line[i]) || i >= line.size
|
329
|
+
# Add the character if not a whitespace
|
330
|
+
keyword << line[i]
|
331
|
+
# Proceed to the next character
|
332
|
+
i += 1
|
333
|
+
end
|
334
|
+
|
335
|
+
operand_strings = extract_instruction_operands(line[i..])
|
336
|
+
|
337
|
+
# Loop for operands
|
338
|
+
|
339
|
+
return keyword, operand_strings
|
340
|
+
end
|
341
|
+
|
342
|
+
|
343
|
+
|
344
|
+
def self.parse_instruction_line(line)
|
345
|
+
|
346
|
+
keyword, operand_strings = extract_instruction_parts(line)
|
309
347
|
|
310
348
|
# Parse operand strings into operand types and values
|
311
349
|
|
@@ -324,8 +362,12 @@ end
|
|
324
362
|
|
325
363
|
def self.check_operand_match(operand_description, operand)
|
326
364
|
|
327
|
-
#
|
328
|
-
|
365
|
+
if operand[:type] == "run_block" # A special check for a run block
|
366
|
+
return false if operand[:block_output_type] != operand_description[:type]
|
367
|
+
else
|
368
|
+
# If operand type doesn't not match, return false
|
369
|
+
return false if operand[:type] != operand_description[:type]
|
370
|
+
end
|
329
371
|
|
330
372
|
# Get the restrictions
|
331
373
|
operand_restrictions = operand_description[:restrictions]
|
@@ -337,6 +379,8 @@ def self.check_operand_match(operand_description, operand)
|
|
337
379
|
operand_encoding = operand[:value]
|
338
380
|
when "immediate"
|
339
381
|
operand_encoding = operand[:value]
|
382
|
+
when "run_block"
|
383
|
+
operand_encoding = Hash.new
|
340
384
|
when "string"
|
341
385
|
operand_encoding = Hash.new
|
342
386
|
end
|
@@ -418,12 +462,20 @@ end
|
|
418
462
|
|
419
463
|
|
420
464
|
def self.check_directive(line)
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
465
|
+
# Skip whitespace
|
466
|
+
char_i = 0
|
467
|
+
while char_i < line.size && Kompiler::Config.whitespace_chars.include?(line[char_i])
|
468
|
+
char_i += 1
|
469
|
+
end
|
470
|
+
|
471
|
+
# Collect the keyword
|
472
|
+
keyword = ""
|
473
|
+
|
474
|
+
while char_i < line.size && Kompiler::Config.keyword_chars.include?(line[char_i])
|
475
|
+
keyword << line[char_i]
|
476
|
+
char_i += 1
|
477
|
+
end
|
478
|
+
|
427
479
|
if keyword[0] == "."
|
428
480
|
keyword = keyword[1..]
|
429
481
|
end
|
@@ -431,16 +483,35 @@ def self.check_directive(line)
|
|
431
483
|
directive = nil
|
432
484
|
|
433
485
|
Kompiler::Directives.directives.each do |curr_directive|
|
434
|
-
if curr_directive[:keyword]
|
435
|
-
|
436
|
-
|
486
|
+
if curr_directive[:keyword].is_a? String
|
487
|
+
if curr_directive[:keyword] == keyword
|
488
|
+
directive = curr_directive
|
489
|
+
break
|
490
|
+
end
|
491
|
+
elsif curr_directive[:keyword].is_a? Array
|
492
|
+
if curr_directive[:keyword].include? keyword
|
493
|
+
directive = curr_directive
|
494
|
+
break
|
495
|
+
end
|
496
|
+
else
|
497
|
+
raise "Directive name error"
|
437
498
|
end
|
438
499
|
end
|
439
500
|
|
440
501
|
if directive == nil
|
441
502
|
return [false, nil]
|
503
|
+
end
|
504
|
+
|
505
|
+
# Check if the directive requires pre-collected operands (with the :collect_operands key that is true by default)
|
506
|
+
if !directive.keys.include?([:collect_operands]) || directive[:collect_operands] == true
|
507
|
+
parse_status, operands = parse_instruction_line(line)
|
508
|
+
|
509
|
+
return [false, nil] if parse_status == false # Return negative if operands can't be parsed
|
510
|
+
|
511
|
+
return [true, {directive: directive, operands: operands}] # Otherwise, return the directive
|
442
512
|
else
|
443
|
-
|
513
|
+
# If operand collection isn't required, return the directive
|
514
|
+
return [true, {directive: directive, operands: []}]
|
444
515
|
end
|
445
516
|
end
|
446
517
|
|
data/lib/kompiler.rb
CHANGED
@@ -12,9 +12,11 @@
|
|
12
12
|
# See the License for the specific language governing permissions and
|
13
13
|
# limitations under the License.
|
14
14
|
|
15
|
+
require 'kompiler/config.rb'
|
15
16
|
require 'kompiler/mc_builder.rb'
|
16
17
|
require 'kompiler/parsers.rb'
|
17
18
|
require 'kompiler/compiler_functions.rb'
|
18
19
|
require 'kompiler/architecture.rb'
|
19
20
|
require 'kompiler/directives.rb'
|
20
|
-
require 'kompiler/arch_manager.rb'
|
21
|
+
require 'kompiler/arch_manager.rb'
|
22
|
+
require 'kompiler/math_ast.rb'
|
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.
|
4
|
+
version: 0.3.0.pre.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kyryl Shyshko
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-
|
11
|
+
date: 2025-02-28 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
|
@@ -33,7 +33,9 @@ files:
|
|
33
33
|
- lib/kompiler/architectures/armv8a/sys_instructions.rb
|
34
34
|
- lib/kompiler/architectures/armv8a/sys_registers.rb
|
35
35
|
- lib/kompiler/compiler_functions.rb
|
36
|
+
- lib/kompiler/config.rb
|
36
37
|
- lib/kompiler/directives.rb
|
38
|
+
- lib/kompiler/math_ast.rb
|
37
39
|
- lib/kompiler/mc_builder.rb
|
38
40
|
- lib/kompiler/parsers.rb
|
39
41
|
homepage: https://github.com/kyryloshy/kompiler
|