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.
@@ -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
 
@@ -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
 
@@ -195,7 +218,7 @@ def self.check_label_operand(str)
195
218
  return false if ("0".."9").to_a.include?(str[0])
196
219
 
197
220
  # 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 + ["_"]
221
+ allowed_chars = ("a".."z").to_a + ("A".."Z").to_a + ("0".."9").to_a + ["_", "."]
199
222
 
200
223
  is_each_char_allowed = str.each_char.map{|c| allowed_chars.include?(c)}
201
224
 
@@ -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 [" ", "\t"].include? line[i]
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 ["\"", "'"].include?(line[i])
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
- # If operand type doesn't not match, return false
328
- return false if operand[:type] != operand_description[:type]
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
@@ -366,10 +410,9 @@ end
366
410
 
367
411
  # Returns array of [status, operands]
368
412
  # 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)
413
+ def self.match_parsed_line_to_instruction(parsed_line, instruction)
372
414
 
415
+ keyword, operands = parsed_line
373
416
 
374
417
  # Check if the keyword matches
375
418
  if instruction[:keyword] != keyword
@@ -396,9 +439,12 @@ def self.check_instruction(line)
396
439
  instruction = nil
397
440
  operands = nil
398
441
 
442
+ parsed_line = Kompiler::Parsers.parse_instruction_line(line)
443
+
399
444
  Kompiler::Architecture.instructions.each do |curr_instruction|
400
445
  # If the instruction matches - break
401
- status, curr_operands = match_instruction(line, curr_instruction)
446
+
447
+ status, curr_operands = match_parsed_line_to_instruction(parsed_line, curr_instruction)
402
448
  if status == true
403
449
  instruction = curr_instruction
404
450
  operands = curr_operands
@@ -416,12 +462,20 @@ end
416
462
 
417
463
 
418
464
  def self.check_directive(line)
419
- status = parse_instruction_line(line)
420
-
421
- return [false, nil] if status == false
422
-
423
- keyword, operands = status
424
-
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
+
425
479
  if keyword[0] == "."
426
480
  keyword = keyword[1..]
427
481
  end
@@ -429,16 +483,35 @@ def self.check_directive(line)
429
483
  directive = nil
430
484
 
431
485
  Kompiler::Directives.directives.each do |curr_directive|
432
- if curr_directive[:keyword] == keyword
433
- directive = curr_directive
434
- break
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"
435
498
  end
436
499
  end
437
500
 
438
501
  if directive == nil
439
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
440
512
  else
441
- return [true, {directive: directive, operands: operands}]
513
+ # If operand collection isn't required, return the directive
514
+ return [true, {directive: directive, operands: []}]
442
515
  end
443
516
  end
444
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.2
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: 2024-12-23 00:00:00.000000000 Z
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