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.
@@ -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 [" ", "\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
@@ -418,12 +462,20 @@ end
418
462
 
419
463
 
420
464
  def self.check_directive(line)
421
- status = parse_instruction_line(line)
422
-
423
- return [false, nil] if status == false
424
-
425
- keyword, operands = status
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] == keyword
435
- directive = curr_directive
436
- 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"
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
- return [true, {directive: directive, operands: operands}]
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.3
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-01-17 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