kompiler 0.3.0.pre.2 → 0.3.0.pre.3
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/architectures/armv8a/instructions.rb +12 -0
- data/lib/kompiler/compiler_functions.rb +116 -7
- data/lib/kompiler/parsers.rb +8 -6
- metadata +2 -2
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: d37e70a65615ea1b7aece9de1a2ae544a30d9f3f9f1f44d233fac8ecde023b63
         | 
| 4 | 
            +
              data.tar.gz: 533a6ac4a19a03c8ca483c63bf454d4cda802943462ea23bcbc1a59688e64d8d
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: ad275ed1d7bbb7dad29409b3ca2f4e061c08f4534bf7c2104d2c20c235a1030e496ae6381322042fe1d1bdd699acc5e970ef82b521031853d4222792b6bf388f
         | 
| 7 | 
            +
              data.tar.gz: 9132f9c232bc01ff2ebfac62bfa09527e79f644ce0d15a360de91ece0a854187da581b6e67c2bec78e6745845fb2257c759786d71e02d44f17fbf4919e7e106c
         | 
| @@ -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 | 
            -
             | 
| 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 | 
            -
            	 | 
| 248 | 
            -
             | 
| 249 | 
            -
            	 | 
| 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 |  | 
    
        data/lib/kompiler/parsers.rb
    CHANGED
    
    | @@ -3,7 +3,7 @@ | |
| 3 3 |  | 
| 4 4 | 
             
            module Kompiler
         | 
| 5 5 |  | 
| 6 | 
            -
             | 
| 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. | 
| 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 | 
            -
            		 | 
| 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. | 
| 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:  | 
| 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
         |