Skip to content

Commit

Permalink
Merge branch 'master' into debug-flags-dev
Browse files Browse the repository at this point in the history
Conflicts:
	Interpreter.rb
	stack.rb
  • Loading branch information
1000000000 committed Jul 3, 2016
2 parents 4e7f7d5 + 2cf7e3e commit 0e607e1
Show file tree
Hide file tree
Showing 6 changed files with 165 additions and 22 deletions.
12 changes: 10 additions & 2 deletions Interpreter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ def step()
if ['()', '[]', '{}', '<>'].include? current_symbol
case current_symbol
when '()' then @current_value += 1
when '[]' then @current_value -= 1
when '[]' then @current_value += @active_stack.height
when '{}' then @current_value += @active_stack.pop
when '<>' then @active_stack = @active_stack == @left ? @right : @left
end
Expand All @@ -126,7 +126,7 @@ def step()

case current_symbol
when ')' then @active_stack.push(@current_value)
when ']' then puts @current_value
when ']' then @current_value *= -1
when '>' then @current_value = 0
when '}'
if @active_stack.peek != 0 then
Expand All @@ -135,11 +135,19 @@ def step()
end
end
@current_value += data[1]
else raise BrainFlakError.new("Invalid character '%s.'" % current_symbol, @index + 1)
end
@index += 1
end
if @index >= @source.length then
@running = false
end
end

def finish
if @main_stack.length > 0
unmatched_brak = @main_stack[0]
raise BrainFlakError.new("Unclosed '%s' character." % unmatched_brak[0], unmatched_brak[2])
end
end
end
47 changes: 28 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,39 +8,41 @@ To get started with Brain-Flak, download the project from here, and run `ruby br

Brain-Flak has two stacks, known as 'left' and 'right'. The active stack starts at left. If an empty stack is popped, it will return 0. That's it. No other variables. When the program starts, each command line argument is pushed on to the active stack.

The only valid characters in a Brain-Flak program are `()[]{}<>`, and they must always be balanced. There are two types of functions: *Nilads* and *Monads*. A *nilad* is a function that takes 0 arguments. Here are all of the nilads:
The only valid characters in a Brain-Flak program are `()[()]{}<>`, and they must always be balanced. There are two types of functions: *Nilads* and *Monads*. A *nilad* is a function that takes 0 arguments. Here are all of the nilads:

- `()` +1.
- `[]` -1.
- `{}` Pop the active stack.
- `<>` Toggle the active stack.
- `()` Evaluates to one.
- `[]` Evaluates to the height of the current stack.
- `{}` Pop the active stack. Evaluates to the popped value.
- `<>` Toggle the active stack. Evaluates to zero.

These are concatenated together when they are evaluated. So if we had a '3' on top of the active stack, this snippet:

()(){}

would evaluate to `1 + 1 + active.pop()` which would evaluate to 5. `<>` evaluates to 0.
would evaluate to `1 + 1 + active.pop()` which would evaluate to 5.

The monads take one argument, a chunk of Brain-Flak code. Here are all of the monads:

- `(n)` Push 'n' on the active stack.
- `[n]` Print 'n'.
- `{foo}` While active.peek() != 0, do foo.
- `[n]` Evaluates to negative 'n'
- `{foo}` While zero is not on the top of the stack, do foo.
- `<foo>` Execute foo, but evaluate it as 0.

These functions will also return the value inside of them, so

(()()())

Will push 3 and
Will push 3 but

[()()()]
((()()()))

Will print 3 but
Will push 3 *twice*.

[(()()())]
The `{}` will evaluate to the sum of all runs. So if we had '3' and '4' on the top of the stack:

Will print **and** push 3.
{{}}

would evaluate as 7.

When the program is done executing, each value left on the active stack is printed, with a newline between. Values on the other stack are ignored.

Expand All @@ -56,21 +58,28 @@ Adding two numbers:

Subtracting two numbers:

{({}[]<({}[])>)}{}
([{}]{})

Multiplying two numbers (Positive only):

(<>)<>({}<>)<>{({}[])<>(({}))<>}{}<>{}({{}}{}<>)
({}<>)<>({<({}[()])><>({})<>}{})<>{}<>

Multiplying two numbers (Any):

(({})){{}(<>)<>(({}))(()){{}({}[]<({}()<(({}<>)<>)>)>)(({}<(({}))>))({}<({}<({}<>)<>>)<>({}<>)>)({}<(({})){{}{}(<(())>)}{}>)(({})){{}{}(<(())>)}{}({}{}[])}{}<>({{}})<>{{}<>{({}[]<([])>)}{}({{}})(<>)}{}{}{}(<>{}<{}><>)(<({}(<><>))>)}{}({}<{}>)
(({})){{}(<>)<>(({}))(()){{}({}[()]<({}()<(({}<>)<>)>)>)(({}<(({}))>))({}<({}<({}<>)<>>)<>({}<>)>)({}<(({})){{}{}(<(())>)}{}>)(({})){{}{}(<(())>)}{}({}{}[()])}{}<>({{}})<>{{}<>{({}[()]<([()])>)}{}({{}})(<>)}{}{}{}(<>{}<{}><>)(<({}(<><>))>)}{}({}<{}>)

Integer divide two numbers (Positive only):

({}<({}<>)<>>)<>(({}<>)){{}({}<({}<>)<>>)<>(({}<>))({}<({}<({}<>)<>>)<>({}<>)>[()]){({}[()]<({}[()])>)}{}((({}))){{}{}(<(())>)}{}(<>)<>{{}<>({}())<>({}<(({})<>)<>>)<>({}<>){({}[()]<({}[()])>)}{}((({}))){(()){{}({}[()]<({}())>)(({}<(({}))>))({}<({}<({}<>)<>>)<>({}<>)>)({}<(({})){(<{}{}(())>)}>{})(({})){{}{}(<(())>)}({}{}{}[()])}({}<{}(({})){{}{}(<(())>)}{}>)}{}}{}{}{}(<<>({}(<>))>)}{}({}<{}>)

Integer divide two numbers (Any):

Modulo two numbers:
({}<(({})<>)><>)<>(((({}<>)))){{}{}(<(())>)}{}(<>)<>{{}({}()<({}[()])>)<>({}())<>({}<(({})<>)><>)<>({}<>)({}<(({})<>)><>)<>(({}<>)){{}{}(<(())>)}{}({}<(({})){{}{}(<(())>)}{}>{}[()])}{}{}{}(<>{}<>)({}<(({})<>)><>)<>(((({}<>)))){{}{}(<(())>)}{}(<>)<>{{}({}()<({}[()])>)<>({}())<>({}<(({})<>)><>)<>({}<>)({}<(({})<>)><>)<>(({}<>)){{}{}(<(())>)}{}({}<(({})){{}{}(<(())>)}{}>{}[()])}{}{}{}(<>{}<>)({}<({}<(({})){(()){{}({}[()]<({}())>)(({}<(({}))>))({}<({}<({}<>)<>>)<>({}<>)>)({}<(({})){(<{}{}(())>)}>{})(({})){{}{}(<(())>)}({}{}{}[()])}({}<{}(({})){{}{}(<(())>)}{}>)}{}({}<(({})){(()){{}({}[()]<({}())>)(({}<(({}))>))({}<({}<({}<>)<>>)<>({}<>)>)({}<(({})){(<{}{}(())>)}>{})(({})){{}{}(<(())>)}({}{}{}[()])}({}<{}(({})){{}{}(<(())>)}{}>)}{}>)(({}{}[()])){{}{}(<(())>)}{}({}<(())>){{}{}((()[()]))}{}>)>)({}<({}<>)<>>)<>(({}<>)){{}({}<({}<>)<>>)<>(({}<><({}<>)><>)<<>({}<>)>[()]){({}[()]<({}[()])>)}{}((({}))){{}{}(<(())>)}{}(<>)<>{{}({}<(({})<>)<>>)<>({}<({}())><>){({}[()]<({}[()])>)}{}((({}))){(()){{}({}[()]<({}())>)(({}<(({}))>))({}<({}<({}<>)<>>)<>({}<>)>)({}<(({})){(<{}{}(())>)}>{})(({})){{}{}(<(())>)}({}{}{}[()])}({}<{}(({})){{}{}(<(())>)}{}>)}{}}{}{}{}(<<>({}(<>))>)}{}({}<{}({}<>)><>)<>({}<>){{}({}(()[()])){({}[()]<({}[()])>)}}{}

(<>)<>(({})){({}[])<>(())<>}{}({}<(({})){({}[])(<>)<>}{}>)(()){({}<(({})){({}[])<>{}<>}{}>)<>{<>({}[])(<>)}<>}({}<({}<{}>)>)<>{}{({}<>)({}{})<>}{}<>(({}<(({}))>))({}<({}<>)<>({}<><({}<>)>)>){({}[]<({}[])>)}{}(({})){{}{}(<><>)({}<({}<(())>)>)}{}({}<{}{}>)<>{}<>
Modulo two numbers (Positive only):

(<>)<>(({})){({}[()])<>(())<>}{}({}<(({})){({}[()])(<>)<>}{}>)(()){({}<(({})){({}[()])<>{}<>}{}>)<>{<>({}[()])(<>)}<>}({}<({}<{}>)>)<>{}{({}<>{})<>}{}<>(({}<(({}))>))({}<({}<>)<>({}<><({}<>)>)>){({}[()]<({}[()])>)}{}(({})){(<{}{}>)({}<({}<(())>)>)}{}({}<{}{}>)<>{}<>

Print the first *N* Fibonacci numbers:

<>((()))<>{({}[])<>({}<>)<>(({})<>({}<>))<>}<>{}{}
<>((()))<>{({}[()])<>({}<>)<>(({})<>({}<>))<>}<>{}{}
3 changes: 2 additions & 1 deletion brain_flak.rb
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,8 @@
interpreter.step
end

interpreter.finish
interpreter.active_stack.print
rescue BrainFlakError => e
puts e.message
STDERR.puts e.message
end
22 changes: 22 additions & 0 deletions compress.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import sys
import re

if __name__ == "__main__":
commandLineArgs = sys.argv
if len(commandLineArgs) != 3:
print "Please pass a input and output file."
print "(Example: python %s input.txt output.txt)" %commandLineArgs[0]
exit()
#Open first file replace whitespace and write to second file
#Open files
infile = open(commandLineArgs[1])
outfile = open(commandLineArgs[2],"w")

string = infile.read()
string = re.sub("[^\(\){}\[\]<>]",'',string)

outfile.write(string)

#Close all the files
outfile.close()
infile.close()
4 changes: 4 additions & 0 deletions stack.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ def talk
def inspect_array
return @data.inspect
end

def height
return @data.length
end
end

def is_opening_bracket?(b)
Expand Down
99 changes: 99 additions & 0 deletions unpack.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import sys
import re

def matching(brace1, brace2):
openers = "([{<"
closers = ")]}>"
if brace1 in openers and brace2 in closers:
return openers.index(brace1) == closers.index(brace2)
elif brace1 in closers and brace2 in openers:
return openers.index(brace2) == closers.index(brace1)
else:
return False

def indent(code, indenter):
return code.replace('\n','\n'+indenter)

'''
atomize will go through a code fragment and split up pieces that are not of the same scope
e.g.
(())<>{{}{}<>}
becomes
(())
<>
{{}{}<>}
'''
def atomize(fragment):
building = ""
currentScope = ""
for character in fragment:
building += character
currentScope += character
if len(currentScope) > 1 and matching(currentScope[-1],currentScope[-2]):
currentScope = currentScope[:-2]
building += '\n' if currentScope == "" else ''
if currentScope != "":
print "Broken fragment or uneven braces"
return building[:-1]

def unpack(code, indenter):
fragments = atomize(code).split('\n')
result = ""
#checkPattern tells us if it should be nested
checkPattern = re.compile(".*([{][^}].*[^{][}]|[<][^>].*[^<][>]).*")
for fragment in fragments:
if not checkPattern.match(fragment):
result += fragment+'\n'
continue
#Sub out the nilads
fragment = fragment.replace('{}','A').replace('<>','B')
recording = False
record = ""
currentScope = ""
for character in fragment:
if recording:
if character not in 'AB':
currentScope += character
if len(currentScope) > 1 and matching(currentScope[-1],currentScope[-2]):
currentScope = currentScope[:-2]
if currentScope == "":
result += '\n '
result += indent(unpack(record.replace('A','{}').replace('B','<>'),indenter)[:-1],indenter)
result += '\n'+character
recording = False
else:
record += character
else:
result += character
if character in "{<":
recording = True
record = ""
currentScope = character
result += '\n'
#Sub the nilads back in
result = result.replace('A','{}')
result = result.replace('B','<>')
return result

if __name__ == "__main__":
commandLineArgs = sys.argv
if len(commandLineArgs) != 3:
print "Please pass a input and output file."
print "(Example: python %s input.txt output.txt)" %commandLineArgs[0]
exit()
#Open files
infile = open(commandLineArgs[1])
outfile = open(commandLineArgs[2],"w")

string = infile.read()

#First we get rid of any formatting that may already exist
string = re.sub("[^\(\){}\[\]<>]",'',string)

string = unpack(string,' ')

outfile.write(string)

#Close all the files
outfile.close()
infile.close()

0 comments on commit 0e607e1

Please sign in to comment.