haxor 0.3.0 → 0.4.0

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.
@@ -4,7 +4,7 @@ require_relative '../lib/haxor'
4
4
  require 'optparse'
5
5
 
6
6
  parser = OptionParser.new do |opts|
7
- opts.banner = 'Usage: hcc [options] [file.hax]'
7
+ opts.banner = 'Usage: hc [options] [file.hax]'
8
8
 
9
9
  opts.on_tail('-h', '--help', 'Show this message') do
10
10
  puts opts
@@ -28,12 +28,4 @@ end
28
28
  source = File.absolute_path ARGV[0]
29
29
 
30
30
  compiler = Haxor::Compiler::Core.new
31
- compiler.register_unit Haxor::Compiler::Component::Arithmetic.new
32
- compiler.register_unit Haxor::Compiler::Component::Data.new
33
- compiler.register_unit Haxor::Compiler::Component::Jumps.new
34
- compiler.register_unit Haxor::Compiler::Component::Logical.new
35
- compiler.register_unit Haxor::Compiler::Component::Other.new
36
- compiler.register_unit Haxor::Compiler::Component::Transfer.new
37
- compiler.register_unit Haxor::Compiler::Component::Various.new
38
-
39
31
  compiler.compile source
data/bin/hvm CHANGED
@@ -26,11 +26,16 @@ if ARGV[0].nil?
26
26
  exit
27
27
  end
28
28
 
29
- vm = Haxor::Vm::Core.new
30
-
31
- filename = ARGV[0]
32
- # make life easier ;)
33
- filename += '.e' if filename.end_with? '.hax'
34
-
35
- vm.load_program filename
36
- vm.execute
29
+ begin
30
+ vm = Haxor::Vm::Core.new
31
+
32
+ filename = ARGV[0]
33
+ # make life easier ;)
34
+ filename += '.e' if filename.end_with? '.hax'
35
+
36
+ vm.load_program filename
37
+ vm.execute
38
+ rescue => e
39
+ puts "An error occurred: #{e}."
40
+ exit 1
41
+ end
@@ -5,6 +5,6 @@ set -e
5
5
 
6
6
  for program in *.hax ; do
7
7
  echo "Compiling example $program ..."
8
- ../bin/hcc $program
8
+ ../bin/hc $program
9
9
  ../bin/hld -o $program.e $program.u
10
10
  done
@@ -11,90 +11,79 @@ dw min, 1
11
11
  dw max, 1000
12
12
 
13
13
  section .bss
14
- dw number, 0
15
- dw answer, 0
16
- dw tries, 0
14
+ dw number
15
+ dw answer
16
+ dw tries
17
17
 
18
18
  section .text
19
- label bigger
20
- mov sc, 02h
21
- lea r01, bigger_msg
22
- push r01
23
- push 1
24
- syscall
25
- jmp question
26
19
 
27
- label smaller
28
- mov sc, 02h
29
- lea r01, smaller_msg
30
- push r01
31
- push 1
32
- syscall
33
- jmp question
20
+ bigger:
21
+ addi $sc, $0, 01h
22
+ pushi bigger_msg
23
+ pushi 1
24
+ syscall
25
+ j question
34
26
 
35
- label win
36
- mov sc, 02h
37
- push tries
38
- lea r01, win_msg
39
- push r01
40
- push 1
41
- syscall
42
- jmp exit
27
+ smaller:
28
+ addi $sc, $0, 01h
29
+ pushi smaller_msg
30
+ pushi 1
31
+ syscall
32
+ j question
43
33
 
44
- label invalid_number
45
- mov sc, 02h
46
- lea r01, invalid_msg
47
- push r01
48
- push 1
49
- syscall
50
- jmp question
34
+ win:
35
+ addi $sc, $0, 01h
36
+ pushm tries
37
+ pushi win_msg
38
+ push 1
39
+ syscall
40
+ exiti 0
51
41
 
52
- label main
42
+ invalid_number:
43
+ addi $sc, $0, 01h
44
+ pushi invalid_msg
45
+ push 1
46
+ syscall
47
+ j question
53
48
 
54
- label welcome
55
- mov sc, 02h
56
- lea r01, welcome_msg
57
- push r01
58
- push 1
59
- syscall
49
+ main:
50
+ addi $sc, $0, 01h
51
+ pushi welcome_msg
52
+ push 1
53
+ syscall
60
54
 
61
- label generate
62
- mov sc, 02h
63
- push max
64
- push min
65
- lea r01, generate_msg
66
- push r01
67
- push 1
68
- syscall
69
- mov sc, 04h
70
- push max
71
- push min
72
- syscall
73
- pop number
55
+ generate:
56
+ addi $sc, $0, 01h
57
+ pushm max
58
+ pushm min
59
+ pushi generate_msg
60
+ pushi 1
61
+ syscall
62
+ addi $sc, $0, 03h
63
+ pushm max
64
+ pushm min
65
+ syscall
66
+ popm number
74
67
 
75
- label question
76
- mov sc, 02h
77
- lea r01, question_msg
78
- push r01
79
- push 1
80
- syscall
81
- mov sc, 03h
82
- lea r01, answer
83
- push r01
84
- lea r01, answer_fmt
85
- push r01
86
- push 0
87
- syscall
88
- cmp sc, -1
89
- je invalid_number
90
- inc tries
68
+ question:
69
+ addi $sc, $0, 01h
70
+ pushi question_msg
71
+ pushi 1
72
+ syscall
73
+ addi $sc, $0, 02h
74
+ pushi answer
75
+ pushi answer_fmt
76
+ pushi 0
77
+ syscall
91
78
 
92
- cmp number, answer
93
- je win
94
- jg bigger
95
- jl smaller
79
+ addi $5, $0, -1
80
+ beq $sc, $5, invalid_number
81
+ lw $6, $0, tries
82
+ addi $6, $6, 1
83
+ sw $0, tries, $6
96
84
 
97
- label exit
98
- mov sc, 01h
99
- push 0
100
- syscall
85
+ lw $7, $0, number
86
+ lw $8, $0, answer
87
+ beq $7, $8, win
88
+ bgt $7, $8, bigger
89
+ blt $7, $8, smaller
@@ -3,9 +3,11 @@ require 'json'
3
3
  require 'io/console'
4
4
  require 'scanf'
5
5
  require 'digest'
6
+ require 'ostruct'
6
7
 
7
8
  require_relative 'haxor/consts'
8
9
  require_relative 'haxor/header'
10
+ require_relative 'haxor/utils'
9
11
 
10
12
  # vm
11
13
  require_relative 'haxor/vm/core'
@@ -15,24 +17,10 @@ require_relative 'haxor/vm/stack'
15
17
  require_relative 'haxor/vm/os'
16
18
  require_relative 'haxor/vm/registers'
17
19
  require_relative 'haxor/vm/cpu/core'
18
- require_relative 'haxor/vm/cpu/unit/base'
19
- require_relative 'haxor/vm/cpu/unit/logical'
20
- require_relative 'haxor/vm/cpu/unit/arithmetic'
21
- require_relative 'haxor/vm/cpu/unit/jumps'
22
- require_relative 'haxor/vm/cpu/unit/various'
23
- require_relative 'haxor/vm/cpu/unit/transfer'
24
20
 
25
21
  # compiler
26
22
  require_relative 'haxor/compiler/unit'
27
23
  require_relative 'haxor/compiler/core'
28
- require_relative 'haxor/compiler/component/base'
29
- require_relative 'haxor/compiler/component/logical'
30
- require_relative 'haxor/compiler/component/arithmetic'
31
- require_relative 'haxor/compiler/component/jumps'
32
- require_relative 'haxor/compiler/component/various'
33
- require_relative 'haxor/compiler/component/transfer'
34
- require_relative 'haxor/compiler/component/data'
35
- require_relative 'haxor/compiler/component/other'
36
24
 
37
25
  # linker
38
26
  require_relative 'haxor/linker'
@@ -1,25 +1,85 @@
1
1
  module Haxor
2
2
  module Compiler
3
3
  class Core
4
+ REG_ALIASES = {
5
+ '$sp' => Vm::Cpu::Core::REG_STACK,
6
+ '$ret' => Vm::Cpu::Core::REG_RETURN,
7
+ '$sc' => Vm::Cpu::Core::REG_SYSCALL
8
+ }
9
+
4
10
  def initialize
5
11
  @units = []
6
- @cmds = {}
12
+ @cmds = []
7
13
  @autolabel = 0
8
14
  @prev_sections = []
9
15
 
10
- bind_cmd 'section', self, :cmd_section
16
+ init_cmds
11
17
  end
12
18
 
13
- def register_unit(unit)
14
- @units << unit
15
- unit.compiler = self
16
- unit.register
19
+ def init_cmds
20
+ bind_cmd 'section', [:any], :cmd_section
21
+ bind_cmd 'dw', [:wildcard], :cmd_dw
22
+ bind_cmd 'resw', [:any], :cmd_resw
23
+ bind_cmd '#', [:wildcard], :cmd_rem
24
+ bind_cmd 'push', [:reg], :cmd_push
25
+ bind_cmd 'pushi', [:imm], :cmd_pushi
26
+ bind_cmd 'pushm', [:imm], :cmd_pushm
27
+ bind_cmd 'pop', [:reg], :cmd_pop
28
+ bind_cmd 'popm', [:imm], :cmd_popm
29
+ bind_cmd 'move', [:reg, :reg], :cmd_move
30
+ bind_cmd 'clear', [:reg], :cmd_clear
31
+ bind_cmd 'not', [:reg, :reg], :cmd_not
32
+ bind_cmd 'ret', [], :cmd_ret
33
+
34
+ bind_cmd 'b', [:imm], :cmd_b
35
+ bind_cmd 'bal', [:imm], :cmd_bal
36
+ bind_cmd 'bgt', [:reg, :reg, :imm], :cmd_bgt
37
+ bind_cmd 'blt', [:reg, :reg, :imm], :cmd_blt
38
+ bind_cmd 'bge', [:reg, :reg, :imm], :cmd_bge
39
+ bind_cmd 'ble', [:reg, :reg, :imm], :cmd_ble
40
+ bind_cmd 'blez', [:reg, :imm], :cmd_blez
41
+ bind_cmd 'bgtz', [:reg, :imm], :cmd_bgtz
42
+ bind_cmd 'beqz', [:reg, :imm], :cmd_beqz
43
+
44
+ bind_cmd 'nop', [], Vm::Cpu::Core::OP_NOP
45
+ bind_cmd 'add', [:reg, :reg, :reg], Vm::Cpu::Core::OP_ADD
46
+ bind_cmd 'addi', [:reg, :reg, :imm], Vm::Cpu::Core::OP_ADDI
47
+ bind_cmd 'sub', [:reg, :reg, :reg], Vm::Cpu::Core::OP_SUB
48
+ bind_cmd 'mult', [:reg, :reg, :reg], Vm::Cpu::Core::OP_MULT
49
+ bind_cmd 'div', [:reg, :reg, :reg], Vm::Cpu::Core::OP_DIV
50
+ bind_cmd 'mod', [:reg, :reg, :reg], Vm::Cpu::Core::OP_MOD
51
+ bind_cmd 'lw', [:reg, :reg, :imm], Vm::Cpu::Core::OP_LW
52
+ bind_cmd 'sw', [:reg, :imm, :reg], Vm::Cpu::Core::OP_SW
53
+ bind_cmd 'lui', [:reg, :imm], Vm::Cpu::Core::OP_LUI
54
+ bind_cmd 'and', [:reg, :reg, :reg], Vm::Cpu::Core::OP_AND
55
+ bind_cmd 'andi', [:reg, :reg, :imm], Vm::Cpu::Core::OP_ANDI
56
+ bind_cmd 'or', [:reg, :reg, :reg], Vm::Cpu::Core::OP_OR
57
+ bind_cmd 'ori', [:reg, :reg, :imm], Vm::Cpu::Core::OP_ORI
58
+ bind_cmd 'xor', [:reg, :reg, :reg], Vm::Cpu::Core::OP_XOR
59
+ bind_cmd 'nor', [:reg, :reg, :reg], Vm::Cpu::Core::OP_NOR
60
+ bind_cmd 'slt', [:reg, :reg, :reg], Vm::Cpu::Core::OP_SLT
61
+ bind_cmd 'slti', [:reg, :reg, :imm], Vm::Cpu::Core::OP_SLTI
62
+ bind_cmd 'slli', [:reg, :reg, :imm], Vm::Cpu::Core::OP_SLLI
63
+ bind_cmd 'srli', [:reg, :reg, :imm], Vm::Cpu::Core::OP_SRLI
64
+ bind_cmd 'sll', [:reg, :reg, :reg], Vm::Cpu::Core::OP_SLL
65
+ bind_cmd 'srl', [:reg, :reg, :reg], Vm::Cpu::Core::OP_SRL
66
+ bind_cmd 'beq', [:reg, :reg, :imm], Vm::Cpu::Core::OP_BEQ, [:rel_imm, :x8]
67
+ bind_cmd 'beql', [:reg, :reg, :imm], Vm::Cpu::Core::OP_BEQL, [:rel_imm, :x8]
68
+ bind_cmd 'bne', [:reg, :reg, :imm], Vm::Cpu::Core::OP_BNE, [:rel_imm, :x8]
69
+ bind_cmd 'bnel', [:reg, :reg, :imm], Vm::Cpu::Core::OP_BNEL, [:rel_imm, :x8]
70
+ bind_cmd 'j', [:imm], Vm::Cpu::Core::OP_J, [:x8]
71
+ bind_cmd 'jr', [:reg], Vm::Cpu::Core::OP_JR
72
+ bind_cmd 'jal', [:imm], Vm::Cpu::Core::OP_JAL, [:x8]
73
+ bind_cmd 'exiti', [:imm], Vm::Cpu::Core::OP_EXITI
74
+ bind_cmd 'syscall', [], Vm::Cpu::Core::OP_SYSCALL
17
75
  end
18
76
 
19
- def bind_cmd(cmd, object, method)
20
- @cmds[cmd] = {
21
- object: object,
22
- method: method
77
+ def bind_cmd(cmd, args, opcode, opts = [])
78
+ @cmds << {
79
+ cmd: cmd,
80
+ args: args,
81
+ opcode: opcode,
82
+ opts: opts
23
83
  }
24
84
  end
25
85
 
@@ -27,6 +87,122 @@ module Haxor
27
87
  @unit.section = name[1..-1].to_sym
28
88
  end
29
89
 
90
+ def cmd_dw(*args)
91
+ add Token::Label.new(args[0])
92
+
93
+ if args.size == 1
94
+ add Token::Int64.new(0)
95
+ else
96
+ (1...args.size).each do |i|
97
+ begin
98
+ add Token::Int64.new(Integer(args[i]))
99
+ rescue
100
+ args[i][1...-1].each_char do |c|
101
+ add Token::Int64.new(c.ord)
102
+ end
103
+ end
104
+ end
105
+ end
106
+ end
107
+
108
+ def cmd_resw(*args)
109
+ (1..args[0].to_i).each do
110
+ add Token::Int64.new(0)
111
+ end
112
+ end
113
+
114
+ def cmd_rem(*)
115
+ end
116
+
117
+ def cmd_push(*args)
118
+ process_cmd 'addi', ['$sp', '$sp', '-' + Consts::WORD_SIZE.to_s]
119
+ process_cmd 'sw', ['$sp', '0', args[0]]
120
+ end
121
+
122
+ def cmd_pushi(*args)
123
+ process_cmd 'addi', ['$1', '$0', args[0]]
124
+ process_cmd 'addi', ['$sp', '$sp', '-' + Consts::WORD_SIZE.to_s]
125
+ process_cmd 'sw', ['$sp', '0', '$1']
126
+ end
127
+
128
+ def cmd_pushm(*args)
129
+ process_cmd 'lw', ['$1', '$0', args[0]]
130
+ process_cmd 'addi', ['$sp', '$sp', '-' + Consts::WORD_SIZE.to_s]
131
+ process_cmd 'sw', ['$sp', '0', '$1']
132
+ end
133
+
134
+ def cmd_pop(*args)
135
+ process_cmd 'lw', [args[0], '$sp', '0']
136
+ process_cmd 'addi', ['$sp', '$sp', Consts::WORD_SIZE.to_s]
137
+ end
138
+
139
+ def cmd_popm(*args)
140
+ process_cmd 'lw', ['$1', '$sp', '0']
141
+ process_cmd 'sw', ['$0', args[0], '$1']
142
+ process_cmd 'addi', ['$sp', '$sp', Consts::WORD_SIZE.to_s]
143
+ end
144
+
145
+ def cmd_move(*args)
146
+ process_cmd 'add', [args[0], args[1], '$0']
147
+ end
148
+
149
+ def cmd_clear(*args)
150
+ process_cmd 'add', [args[0], '$0', '$0']
151
+ end
152
+
153
+ def cmd_not(*args)
154
+ process_cmd 'nor', [args[0], args[1], '$0']
155
+ end
156
+
157
+ def cmd_ret(*_args)
158
+ process_cmd 'jr', ['$' + Vm::Cpu::Core::REG_RETURN.to_s]
159
+ end
160
+
161
+ def cmd_b(*args)
162
+ process_cmd 'beq', ['$0', '$0', args[0]]
163
+ end
164
+
165
+ def cmd_bal(*args)
166
+ process_cmd 'beql', ['$0', '$0', args[0]]
167
+ end
168
+
169
+ # branch is greater than
170
+ def cmd_bgt(*args)
171
+ process_cmd 'slt', ['$1', args[1], args[0]]
172
+ process_cmd 'bne', ['$1', '$0', args[2]]
173
+ end
174
+
175
+ # branch if less than
176
+ def cmd_blt(*args)
177
+ process_cmd 'slt', ['$1', args[0], args[1]]
178
+ process_cmd 'bne', ['$1', '$0', args[2]]
179
+ end
180
+
181
+ # branch is greater or equal
182
+ def cmd_bge(*args)
183
+ process_cmd 'slt', ['$1', args[0], args[1]]
184
+ process_cmd 'beq', ['$1', '$0', args[2]]
185
+ end
186
+
187
+ def cmd_ble(*args)
188
+ process_cmd 'slt', ['$1', args[1], args[0]]
189
+ process_cmd 'beq', ['$1', '$0', args[2]]
190
+ end
191
+
192
+ def cmd_blez(*args)
193
+ process_cmd 'slt', ['$1', '$0', args[0]]
194
+ process_cmd 'beq', ['$1', '$0', args[1]]
195
+ end
196
+
197
+ def cmd_bgtz(*args)
198
+ process_cmd 'slt', ['$1', '$0', args[0]]
199
+ process_cmd 'bne', ['$1', '$0', args[1]]
200
+ end
201
+
202
+ def cmd_beqz(*args)
203
+ process_cmd 'beq', [args[0], '$0', args[1]]
204
+ end
205
+
30
206
  # this is ugly and must be reworked
31
207
  def split_arguments(string)
32
208
  inside_quotes = false
@@ -52,6 +228,23 @@ module Haxor
52
228
  args.map!(&:strip).delete_if { |x| x.length == 0 }
53
229
  end
54
230
 
231
+ def process_cmd(cmd, args)
232
+ @cmds.each do |item|
233
+ next if item[:cmd] != cmd
234
+
235
+ if item[:opcode].is_a? Symbol
236
+ send(item[:opcode], *args)
237
+ return
238
+ end
239
+
240
+ add_cmd item, args
241
+ return
242
+ end
243
+
244
+ puts cmd
245
+ fail
246
+ end
247
+
55
248
  def compile(filename)
56
249
  input = File.read(filename, encoding: 'ASCII-8BIT')
57
250
 
@@ -64,9 +257,11 @@ module Haxor
64
257
  cmd = tmp[0]
65
258
  args = split_arguments(tmp[1] || '')
66
259
 
67
- fail "Unknown command #{cmd} in line #{index}." unless @cmds.key? cmd
68
-
69
- @cmds[cmd][:object].send(@cmds[cmd][:method], *args)
260
+ if cmd[-1] == ':'
261
+ add Token::Label.new(cmd[0...-1])
262
+ else
263
+ process_cmd(cmd, args)
264
+ end
70
265
  end
71
266
 
72
267
  @unit.save(filename + '.u')
@@ -76,11 +271,47 @@ module Haxor
76
271
  @unit.add token
77
272
  end
78
273
 
79
- def add_cmd(opcode, a = nil, b = nil)
80
- opcode |= offset_flags(a, b)
81
- add Token::Cmd.new(opcode)
82
- parse_value a unless a.nil?
83
- parse_value b unless b.nil?
274
+ # def resolve_arg(a, type)
275
+ # case type
276
+ # when :reg
277
+ # return a[1..-1].to_i
278
+ # when :imm
279
+ # return a.to_i
280
+ # else
281
+ # fail
282
+ # end
283
+ # end
284
+
285
+ def add_cmd(info, args = [])
286
+ registers = []
287
+ immediate = 0
288
+ info[:args].each_with_index do |type, index|
289
+ if type == :reg
290
+ if REG_ALIASES.key? args[index]
291
+ registers << REG_ALIASES[args[index]]
292
+ else
293
+ registers << args[index][1..-1].to_i
294
+ end
295
+ elsif type == :imm
296
+ begin
297
+ immediate = parse_number args[index]
298
+ rescue
299
+ immediate = args[index]
300
+ end
301
+ end
302
+ end
303
+
304
+ registers.fill 0, registers.size...3
305
+
306
+ token = Token::Cmd.new
307
+ token.cmd = info[:opcode]
308
+ token.reg1 = registers[0]
309
+ token.reg2 = registers[1]
310
+ token.reg3 = registers[2]
311
+ token.imm = immediate
312
+ token.opts = info[:opts]
313
+
314
+ add token
84
315
  end
85
316
 
86
317
  def parse_number(value)