braingasm 0.1.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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 803b75a915a22087c3ff27c5b5960381bd05b36e
4
+ data.tar.gz: 0321e68035610e58a2fd83e795d6c1588b700bcd
5
+ SHA512:
6
+ metadata.gz: 352c4a0c18097b93024223b10193a37cfc160639104d1592dd1b2fc7240b83231e5afcc19cb620eb3e3fbd79def8988724f899a5a786f8e1aa91ada5e5267d87
7
+ data.tar.gz: 0233ac17008cbb6f894a9eafb3496cb83ea197b552b56b19a3c61e2d329eedefbf4c274a9d1f945cc7b14aa2dea22488e7618d54f3c13c36af7c67cf9e66986f
data/.gitignore ADDED
@@ -0,0 +1,12 @@
1
+ .*.swp
2
+ .*.swo
3
+
4
+ /.bundle/
5
+ /.yardoc
6
+ /Gemfile.lock
7
+ /_yardoc/
8
+ /coverage/
9
+ /doc/
10
+ /pkg/
11
+ /spec/reports/
12
+ /tmp/
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.3.0
5
+ before_install: gem install bundler -v 1.12.5
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in braingasm.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2016 Daniel Rødskog
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,64 @@
1
+ # Braingasm
2
+
3
+ Braingasm is a super-set of [brainfuck](https://esolangs.org/wiki/brainfuck),
4
+ and extends the 8 original instructions with the concept of *prefixes* and
5
+ *registers*.
6
+
7
+ The original idea for the language was to combine brainfuck and assembly code
8
+ (asm), hence the name.
9
+
10
+ ### Prefixes
11
+ A prefix may alter the effect of an instruction in different ways. The simplest
12
+ kind of prefix is a numeric literal, which makes the succeeding instruction
13
+ repeat a certain number of times:
14
+
15
+ * `5+` increases the value of the current cell by 5.
16
+ * `7[X]` Runs the loop, containing some code `X`, exactly 7 times.
17
+
18
+ ### Registers
19
+ Registers can also be used as prefixes. Registers are typically updated when
20
+ other instructions are executed:
21
+
22
+ * The `z` register holds the value `1` if the previous update of a cell caused
23
+ it the reach the value 0. Otherwise the `z` register holds the value `0`.
24
+ * The `#` register holds the current position in the data tape. `#>` will move
25
+ to cell 12 if the current cell is 6.
26
+
27
+ More information about the different prefixes and registers will come.
28
+
29
+ ## Installation
30
+
31
+ Add this line to your application's Gemfile:
32
+
33
+ ```ruby
34
+ gem 'braingasm'
35
+ ```
36
+
37
+ And then execute:
38
+
39
+ $ bundle
40
+
41
+ Or install it yourself as:
42
+
43
+ $ gem install braingasm
44
+
45
+ ## Usage
46
+
47
+ $ braingasm my_program.bg
48
+
49
+ ## Development
50
+
51
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
52
+
53
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
54
+
55
+ ## Contributing
56
+
57
+ Bug reports and pull requests are welcome on GitHub at
58
+ https://github.com/daniero/braingasm.
59
+
60
+
61
+ ## License
62
+
63
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
64
+
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "braingasm"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
data/braingasm.gemspec ADDED
@@ -0,0 +1,25 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'braingasm/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "braingasm"
8
+ spec.version = Braingasm::VERSION
9
+ spec.author = "Daniel Rødskog"
10
+ spec.email = "danielmero@gmail.com"
11
+
12
+ spec.summary = %q{It's liek brainfuck and assembly in one!}
13
+ spec.description = %q{braingasm combines the readability of brainfuck with the high-level functionality of assembly}
14
+ spec.homepage = "https://github.com/daniero/braingasm"
15
+ spec.license = "MIT"
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
18
+ spec.bindir = "exe"
19
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
20
+ spec.require_paths = ["lib"]
21
+
22
+ spec.add_development_dependency "bundler", "~> 1.12"
23
+ spec.add_development_dependency "rake", "~> 11.2"
24
+ spec.add_development_dependency "rspec", "~> 3.0"
25
+ end
data/exe/braingasm ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'braingasm'
4
+ require 'braingasm/errors'
5
+
6
+ input = IO.read(ARGV.shift)
7
+
8
+ begin
9
+ machine = Braingasm.initialize_machine(input)
10
+ machine.run
11
+ rescue Braingasm::BraingasmError => e
12
+ $stderr.puts "#{e.type}: #{e.message}"
13
+ exit 1
14
+ end
@@ -0,0 +1,22 @@
1
+ module Braingasm
2
+ class BraingasmError < RuntimeError
3
+ def type
4
+ self.class.to_s
5
+ end
6
+ end
7
+
8
+ class ParsingError < BraingasmError
9
+ attr_reader :line, :column
10
+ def initialize(line=nil, column=nil)
11
+ @line = line
12
+ @column = column
13
+ end
14
+
15
+ def type
16
+ "#{super} [line #@line, col #@column]"
17
+ end
18
+ end
19
+
20
+ class VMError < BraingasmError
21
+ end
22
+ end
@@ -0,0 +1,83 @@
1
+ require "braingasm/errors"
2
+
3
+ module Braingasm
4
+
5
+ # A Machine keeps the state of a running program, and exposes various
6
+ # operations to modify this state
7
+ class Machine
8
+ attr_accessor :tape, :dp, :program, :ip
9
+
10
+ def initialize
11
+ @tape = Array.new(10) { 0 }
12
+ @dp = 0 # data pointer
13
+ @ip = 0 # instruction pointer
14
+ end
15
+
16
+ def run
17
+ return if @program.empty?
18
+
19
+ loop do
20
+ continue = step
21
+ break unless continue && @ip < @program.size
22
+ end
23
+ end
24
+
25
+ def step
26
+ move = @program[@ip].call(self)
27
+ @ip = move
28
+ end
29
+
30
+ def inst_right(n=1)
31
+ new_dp = @dp + n
32
+ no_cells = @tape.length
33
+
34
+ if new_dp >= no_cells
35
+ grow = new_dp * 3 / 2
36
+ @tape.fill(0, no_cells..grow)
37
+ end
38
+
39
+ @dp = new_dp
40
+ @ip + 1
41
+ end
42
+
43
+ def inst_left(n=1)
44
+ @dp -= 1
45
+ raise VMError, "Moved outside the tape" if @dp < 0
46
+ @ip + 1
47
+ end
48
+
49
+ def inst_print_tape
50
+ p @tape
51
+ @ip + 1
52
+ end
53
+
54
+ def inst_inc(n=1)
55
+ @tape[@dp] += n
56
+ @ip + 1
57
+ end
58
+
59
+ def inst_dec(n=1)
60
+ @tape[@dp] -= n
61
+ @ip + 1
62
+ end
63
+
64
+ def inst_jump(to)
65
+ to
66
+ end
67
+
68
+ def inst_jump_if_zero(to)
69
+ @tape[@dp] == 0 ? to : @ip + 1
70
+ end
71
+
72
+ def inst_print_cell
73
+ print @tape[@dp].chr
74
+ @ip + 1
75
+ end
76
+
77
+ def inst_read_byte
78
+ @tape[@dp] = ARGF.getbyte || 0
79
+ @ip + 1
80
+ end
81
+
82
+ end
83
+ end
@@ -0,0 +1,100 @@
1
+ require "braingasm/errors"
2
+
3
+ module Braingasm
4
+
5
+ # Takes some input code and generates the program
6
+ class Parser
7
+ attr_accessor :program, :loop_stack
8
+
9
+ def initialize(input)
10
+ @input = input
11
+ @program = []
12
+ @loop_stack = []
13
+ end
14
+
15
+ def parse_program
16
+ loop do
17
+ push_instruction parse_next(@input)
18
+ end
19
+
20
+ raise_parsing_error("Unmatched `[`") unless @loop_stack.empty?
21
+ @program
22
+ end
23
+
24
+ def parse_next(tokens)
25
+ case tokens.next
26
+ when :right
27
+ right()
28
+ when :left
29
+ left()
30
+ when :plus
31
+ inc()
32
+ when :minus
33
+ dec()
34
+ when :period
35
+ print()
36
+ when :comma
37
+ read()
38
+ when :loop_start
39
+ new_loop = Loop.new
40
+ @loop_stack.push(new_loop)
41
+ new_loop.start_index = @program.size
42
+ new_loop
43
+ when :loop_end
44
+ current_loop = @loop_stack.pop
45
+ raise_parsing_error("Unmatched `]`") unless current_loop
46
+ instruction = jump(current_loop.start_index)
47
+ index = @program.size
48
+ current_loop.stop_index = index
49
+ instruction
50
+ end
51
+ end
52
+
53
+ def push_instruction(instruction)
54
+ return unless instruction
55
+ @program.push instruction
56
+ @program.size - 1
57
+ end
58
+
59
+ def right(n=1)
60
+ -> m { m.inst_right(n) }
61
+ end
62
+
63
+ def left(n=1)
64
+ -> m { m.inst_left(n) }
65
+ end
66
+
67
+ def inc(n=1)
68
+ -> m { m.inst_inc(n) }
69
+ end
70
+
71
+ def dec(n=1)
72
+ -> m { m.inst_dec(n) }
73
+ end
74
+
75
+ def print()
76
+ -> m { m.inst_print_cell }
77
+ end
78
+
79
+ def read()
80
+ -> m { m.inst_read_byte }
81
+ end
82
+
83
+ def jump(to)
84
+ -> m { m.inst_jump(to) }
85
+ end
86
+
87
+ class Loop
88
+ attr_accessor :start_index, :stop_index
89
+
90
+ def call(machine)
91
+ machine.inst_jump_if_zero(stop_index + 1)
92
+ end
93
+
94
+ end
95
+
96
+ def raise_parsing_error(message)
97
+ raise ParsingError.new(@input.line_numer, @input.column_number), message
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,51 @@
1
+ require 'strscan'
2
+
3
+ module Braingasm
4
+ class Tokenizer < Enumerator
5
+ attr_accessor :input
6
+ attr_reader :line_numer, :column_number
7
+
8
+ def initialize(input)
9
+ @line_numer = 1
10
+ @column_number = 0
11
+
12
+ scanner = StringScanner.new(input)
13
+
14
+ super() do |y|
15
+ loop do
16
+ line_numer, column_number = @line_numer, @column_number
17
+
18
+ while scanner.skip(/\s/)
19
+ if scanner.beginning_of_line?
20
+ line_numer += 1
21
+ column_number = 0
22
+ else
23
+ column_number += 1
24
+ end
25
+ end
26
+
27
+ break if scanner.eos?
28
+
29
+ column_number += 1
30
+ @line_numer, @column_number = line_numer, column_number
31
+ y << read_token(scanner)
32
+ end
33
+ end
34
+ end
35
+
36
+ private
37
+ def read_token(scanner)
38
+ tokens = { '+' => :plus,
39
+ '-' => :minus,
40
+ '<' => :left,
41
+ '>' => :right,
42
+ '.' => :period,
43
+ ',' => :comma,
44
+ '[' => :loop_start,
45
+ ']' => :loop_end }
46
+ tokens[scanner.scan(/\S/)] || :unknown
47
+ end
48
+
49
+ end
50
+ end
51
+
@@ -0,0 +1,3 @@
1
+ module Braingasm
2
+ VERSION = "0.1.0"
3
+ end
data/lib/braingasm.rb ADDED
@@ -0,0 +1,12 @@
1
+ require "braingasm/tokenizer"
2
+ require "braingasm/parser"
3
+ require "braingasm/machine"
4
+
5
+ module Braingasm
6
+ def self.initialize_machine(code)
7
+ machine = Machine.new
8
+ tokenizer = Tokenizer.new(code)
9
+ machine.program = Parser.new(tokenizer).parse_program
10
+ machine
11
+ end
12
+ end
metadata ADDED
@@ -0,0 +1,104 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: braingasm
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Daniel Rødskog
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2016-08-10 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.12'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.12'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '11.2'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '11.2'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.0'
55
+ description: braingasm combines the readability of brainfuck with the high-level functionality
56
+ of assembly
57
+ email: danielmero@gmail.com
58
+ executables:
59
+ - braingasm
60
+ extensions: []
61
+ extra_rdoc_files: []
62
+ files:
63
+ - ".gitignore"
64
+ - ".rspec"
65
+ - ".travis.yml"
66
+ - Gemfile
67
+ - LICENSE.txt
68
+ - README.md
69
+ - Rakefile
70
+ - bin/console
71
+ - bin/setup
72
+ - braingasm.gemspec
73
+ - exe/braingasm
74
+ - lib/braingasm.rb
75
+ - lib/braingasm/errors.rb
76
+ - lib/braingasm/machine.rb
77
+ - lib/braingasm/parser.rb
78
+ - lib/braingasm/tokenizer.rb
79
+ - lib/braingasm/version.rb
80
+ homepage: https://github.com/daniero/braingasm
81
+ licenses:
82
+ - MIT
83
+ metadata: {}
84
+ post_install_message:
85
+ rdoc_options: []
86
+ require_paths:
87
+ - lib
88
+ required_ruby_version: !ruby/object:Gem::Requirement
89
+ requirements:
90
+ - - ">="
91
+ - !ruby/object:Gem::Version
92
+ version: '0'
93
+ required_rubygems_version: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - ">="
96
+ - !ruby/object:Gem::Version
97
+ version: '0'
98
+ requirements: []
99
+ rubyforge_project:
100
+ rubygems_version: 2.5.1
101
+ signing_key:
102
+ specification_version: 4
103
+ summary: It's liek brainfuck and assembly in one!
104
+ test_files: []