babel_bridge 0.3.0 → 0.3.1
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.
- data/examples/test.rb +31 -0
- data/examples/turing/examples.turing +33 -0
- data/examples/turing/notes.rb +111 -0
- data/examples/turing/turing.rb +13 -6
- data/examples/turing/turing00.rb +7 -0
- data/examples/turing/turing01.rb +8 -0
- data/examples/turing/turing02.rb +10 -0
- data/examples/turing/turing03.rb +19 -0
- data/examples/turing/turing04.rb +19 -0
- data/examples/turing/turing05.rb +18 -0
- data/examples/turing/turing06.rb +20 -0
- data/examples/turing/turing07.rb +21 -0
- data/examples/turing/turing08.rb +26 -0
- data/examples/turing/turing09.rb +37 -0
- data/examples/turing/turing10.rb +53 -0
- data/examples/turing/turing11.rb +63 -0
- data/examples/turing/turing12.rb +71 -0
- data/examples/turing/turing_demo.rb +71 -0
- data/lib/nodes/many_node.rb +3 -1
- data/lib/nodes/node.rb +7 -0
- data/lib/parser.rb +51 -32
- data/lib/pattern_element.rb +10 -1
- data/lib/rule_variant.rb +1 -7
- data/lib/shell.rb +13 -6
- data/lib/string.rb +4 -1
- data/lib/tools.rb +27 -8
- data/lib/version.rb +1 -1
- data/test/test_bb.rb +17 -2
- metadata +18 -2
- data/examples/turing/test.rb +0 -28
data/examples/test.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__),"..","lib","babel_bridge")
|
2
|
+
|
3
|
+
class TestParser < BabelBridge::Parser
|
4
|
+
|
5
|
+
rule :expr, :bin_op do
|
6
|
+
def evaluate
|
7
|
+
output = bin_op.evaluate
|
8
|
+
input = to_s
|
9
|
+
puts "bbtest: #{output} = #{eval output}"
|
10
|
+
puts "ruby: #{input} = #{eval input}"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
#rule :bin_op, :operand, "+", :operand do
|
15
|
+
#rule :bin_op, many(:operand,"+") do
|
16
|
+
#rule :bin_op, :operand, /([-+\/*])|(\*\*)/, :bin_op do
|
17
|
+
#rule :bin_op, many(:operand,/([-+\/*])|(\*\*)/) do
|
18
|
+
binary_operators_rule :bin_op, :operand, ["**", [:/, :*], [:+, "-"]], :right_operators => ["**"] do
|
19
|
+
def evaluate
|
20
|
+
"(#{left.evaluate}#{operator}#{right.evaluate})"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
rule :operand, "(", :bin_op, ")"
|
25
|
+
|
26
|
+
rule :operand, /[-]?[0-9]+/ do
|
27
|
+
def evaluate; to_s; end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
BabelBridge::Shell.new(TestParser.new).start
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# this language doesn't support comments, should copy-paste the examples between
|
2
|
+
# the comments
|
3
|
+
|
4
|
+
# calculate 2^[0]
|
5
|
+
[0]=10;[1]=1;while [0]>0 do [0]=[0]-1;[1]=[1]*2 end;[1]
|
6
|
+
|
7
|
+
# return the [0]th number in the fibonancci sequence:
|
8
|
+
# [0] == fib number to output
|
9
|
+
# [1] == current fib number
|
10
|
+
# [2] == fib[[1]]
|
11
|
+
# [3] == fib[[1]-1]
|
12
|
+
# [4] == temp
|
13
|
+
[0]=5;[1]=2;[2]=[3]=1;while [1]<[0] do [4]=[2]+[3];[2]=[3];[3]=[4];[1]=[1]+1 end;[3]
|
14
|
+
|
15
|
+
# simulate a turing machine
|
16
|
+
# [0] == current state
|
17
|
+
# [1] == head position
|
18
|
+
# [2] == number of symbols this machine recognizes
|
19
|
+
# [3] == current state + read value offset
|
20
|
+
# [state*[2]*3+10] == write at the current head position(nil or any number)
|
21
|
+
# [state*[2]*3+11] == move head amount (-1, 0, 1)
|
22
|
+
# [state*[2]*3+12] == next-state (states starting from 0)
|
23
|
+
# [10000+] == tape - pick a large enough constant that the turing machine doesn't corrupt your states
|
24
|
+
# -1 is the stop-state
|
25
|
+
# Assumes you initalized your turing program for all your states.
|
26
|
+
[0]=-1;
|
27
|
+
[1]=10000;
|
28
|
+
while [0]>=0 do
|
29
|
+
[3] = 10 + ([0]*[2]+[[1]]) * 3;
|
30
|
+
[[1]] = [[3]];
|
31
|
+
[1] = [1] + [[3]+1];
|
32
|
+
[0] = [[3]+2];
|
33
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
turing0: #babel-bridge setup
|
2
|
+
turing1: #introducing rules -> show interactive shell in action
|
3
|
+
rule :int, /[-]?[0-9]+/
|
4
|
+
|
5
|
+
turing2: #the "add" rule (with 2 variants to support recursive matching)
|
6
|
+
rule :add, :int, "+", :add
|
7
|
+
rule :add, :int
|
8
|
+
|
9
|
+
turing3: #add evaluate methods
|
10
|
+
rule :add, :int, "+", :add do
|
11
|
+
def evaluate
|
12
|
+
int.evaluate + add.evaluate
|
13
|
+
end
|
14
|
+
end
|
15
|
+
rule :add, :int
|
16
|
+
|
17
|
+
rule :int, /[-]?[0-9]+/ do
|
18
|
+
def evaluate
|
19
|
+
to_s.to_i
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
turing4: #multiple operators, but "3*10+2" or "2+10*3" breaks!
|
24
|
+
# add :operator rule, update evaluate
|
25
|
+
rule :add, :int, /[-+\/*]/, :add do
|
26
|
+
def evaluate
|
27
|
+
int.evaluate.send match[1].to_s.to_sym, add.evaluate
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
turing5: # binary_operators_rule
|
32
|
+
# replace all but the int rule with:
|
33
|
+
binary_operators_rule :statement, :int, [[:/, :*], [:+, :-]] do
|
34
|
+
def evaluate
|
35
|
+
left.evaluate.send operator, right.evaluate
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
turing6: # add parenthesis
|
40
|
+
# rename :int to :operand
|
41
|
+
rule :operand, "(", :statement, ")"
|
42
|
+
|
43
|
+
turing7: # show "5 + 2" fails -> ignore_whitespace
|
44
|
+
ignore_whitespace
|
45
|
+
|
46
|
+
turing8: # add comparators
|
47
|
+
binary_operators_rule :statement, :operand, [[:/, :*], [:+, :-],
|
48
|
+
[:<, :<=, :>, :>=, :==]] do
|
49
|
+
def evaluate
|
50
|
+
case operator
|
51
|
+
when :<, :<=, :>, :>=, :==
|
52
|
+
(left.evaluate.send operator, right.evaluate) ? 1 : nil
|
53
|
+
else
|
54
|
+
left.evaluate.send operator, right.evaluate
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
turing9: # add if
|
60
|
+
rule :statement, "if", :statement, "then", :statement, :else_clause?, "end" do
|
61
|
+
def evaluate
|
62
|
+
if matches[1].evaluate
|
63
|
+
matches[3].evaluate
|
64
|
+
else
|
65
|
+
else_clause.evaluate if else_clause
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
rule :else_clause, "else", :statement
|
70
|
+
|
71
|
+
turing10: #add store
|
72
|
+
|
73
|
+
def store
|
74
|
+
@store||=[]
|
75
|
+
end
|
76
|
+
|
77
|
+
rule :operand, "[", :statement, "]", "=", :statement do
|
78
|
+
def evaluate
|
79
|
+
parser.store[statement[0].evaluate] = statement[1].evaluate
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
rule :operand, "[", :statement, "]" do
|
84
|
+
def evaluate
|
85
|
+
parser.store[statement.evaluate]
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
turing11: #statements
|
90
|
+
# update "if" bodies to have statements
|
91
|
+
|
92
|
+
rule :statements, many(:statement,";"), match?(";") do
|
93
|
+
def evaluate
|
94
|
+
ret = nil
|
95
|
+
statement.each do |s|
|
96
|
+
ret = s.evaluate
|
97
|
+
end
|
98
|
+
ret
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
turing12: # while
|
103
|
+
|
104
|
+
rule :statement, "while", :statement, "do", :statements, "end" do
|
105
|
+
def evaluate
|
106
|
+
while statement.evaluate
|
107
|
+
statements.evaluate
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
data/examples/turing/turing.rb
CHANGED
@@ -1,7 +1,14 @@
|
|
1
1
|
require File.join(File.dirname(__FILE__),"..","..","lib","babel_bridge")
|
2
|
+
# A turing complete programming language
|
3
|
+
# Example program that computes the power of two of the value stored in the [0] register:
|
4
|
+
# => [0]=32;[1]=1;while [0]>0 do [1] = [1] * 2; [0] = [0]-1; end;[1]
|
5
|
+
|
6
|
+
# TODO: add variables and functions
|
2
7
|
|
3
8
|
class TuringParser < BabelBridge::Parser
|
4
9
|
ignore_whitespace
|
10
|
+
# TODO: add "whole_words" option to convert all literal matching patterns that are words into /word\b/
|
11
|
+
|
5
12
|
|
6
13
|
def store
|
7
14
|
@store||=[]
|
@@ -17,18 +24,18 @@ class TuringParser < BabelBridge::Parser
|
|
17
24
|
end
|
18
25
|
end
|
19
26
|
|
20
|
-
rule :statement,
|
27
|
+
rule :statement, "if", :statement, "then", :statements, :else_clause?, "end" do
|
21
28
|
def evaluate
|
22
|
-
if statement
|
23
|
-
|
29
|
+
if statement.evaluate
|
30
|
+
statements.evaluate
|
24
31
|
else
|
25
32
|
else_clause.evaluate if else_clause
|
26
33
|
end
|
27
34
|
end
|
28
35
|
end
|
29
|
-
rule :else_clause,
|
36
|
+
rule :else_clause, "else", :statements
|
30
37
|
|
31
|
-
rule :statement,
|
38
|
+
rule :statement, "while", :statement, "do", :statements, "end" do
|
32
39
|
def evaluate
|
33
40
|
while statement.evaluate
|
34
41
|
statements.evaluate
|
@@ -36,7 +43,7 @@ class TuringParser < BabelBridge::Parser
|
|
36
43
|
end
|
37
44
|
end
|
38
45
|
|
39
|
-
binary_operators_rule :statement, :operand, [[
|
46
|
+
binary_operators_rule :statement, :operand, [[:/, :*], [:+, :-], [:<, :<=, :>, :>=, :==]] do
|
40
47
|
def evaluate
|
41
48
|
case operator
|
42
49
|
when :<, :<=, :>, :>=, :==
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__),"..","..","lib","babel_bridge")
|
2
|
+
|
3
|
+
class TuringParser < BabelBridge::Parser
|
4
|
+
|
5
|
+
rule :add, :int, "+", :add do
|
6
|
+
def evaluate
|
7
|
+
int.evaluate + add.evaluate
|
8
|
+
end
|
9
|
+
end
|
10
|
+
rule :add, :int
|
11
|
+
|
12
|
+
rule :int, /[-]?[0-9]+/ do
|
13
|
+
def evaluate
|
14
|
+
to_s.to_i
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
BabelBridge::Shell.new(TuringParser.new).start
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__),"..","..","lib","babel_bridge")
|
2
|
+
|
3
|
+
class TuringParser < BabelBridge::Parser
|
4
|
+
|
5
|
+
rule :add, :int, /[-+\/*]/, :add do
|
6
|
+
def evaluate
|
7
|
+
int.evaluate.send matches[1].to_s.to_sym, add.evaluate
|
8
|
+
end
|
9
|
+
end
|
10
|
+
rule :add, :int
|
11
|
+
|
12
|
+
rule :int, /[-]?[0-9]+/ do
|
13
|
+
def evaluate
|
14
|
+
to_s.to_i
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
BabelBridge::Shell.new(TuringParser.new).start
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__),"..","..","lib","babel_bridge")
|
2
|
+
|
3
|
+
class TuringParser < BabelBridge::Parser
|
4
|
+
|
5
|
+
binary_operators_rule :statement, :int, [[:/, :*], [:+, :-]] do
|
6
|
+
def evaluate
|
7
|
+
left.evaluate.send operator, right.evaluate
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
rule :int, /[-]?[0-9]+/ do
|
12
|
+
def evaluate
|
13
|
+
to_s.to_i
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
BabelBridge::Shell.new(TuringParser.new).start
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__),"..","..","lib","babel_bridge")
|
2
|
+
|
3
|
+
class TuringParser < BabelBridge::Parser
|
4
|
+
|
5
|
+
binary_operators_rule :statement, :operand, [[:/, :*], [:+, :-]] do
|
6
|
+
def evaluate
|
7
|
+
left.evaluate.send operator, right.evaluate
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
rule :operand, "(", :statement, ")"
|
12
|
+
|
13
|
+
rule :operand, /[-]?[0-9]+/ do
|
14
|
+
def evaluate
|
15
|
+
to_s.to_i
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
BabelBridge::Shell.new(TuringParser.new).start
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__),"..","..","lib","babel_bridge")
|
2
|
+
|
3
|
+
class TuringParser < BabelBridge::Parser
|
4
|
+
ignore_whitespace
|
5
|
+
|
6
|
+
binary_operators_rule :statement, :operand, [[:/, :*], [:+, :-]] do
|
7
|
+
def evaluate
|
8
|
+
left.evaluate.send operator, right.evaluate
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
rule :operand, "(", :statement, ")"
|
13
|
+
|
14
|
+
rule :operand, /[-]?[0-9]+/ do
|
15
|
+
def evaluate
|
16
|
+
to_s.to_i
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
BabelBridge::Shell.new(TuringParser.new).start
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__),"..","..","lib","babel_bridge")
|
2
|
+
|
3
|
+
class TuringParser < BabelBridge::Parser
|
4
|
+
ignore_whitespace
|
5
|
+
|
6
|
+
binary_operators_rule :statement, :operand, [[:/, :*], [:+, :-], [:<, :<=, :>, :>=, :==]] do
|
7
|
+
def evaluate
|
8
|
+
case operator
|
9
|
+
when :<, :<=, :>, :>=, :==
|
10
|
+
(left.evaluate.send operator, right.evaluate) ? 1 : nil
|
11
|
+
else
|
12
|
+
left.evaluate.send operator, right.evaluate
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
rule :operand, "(", :statement, ")"
|
18
|
+
|
19
|
+
rule :operand, /[-]?[0-9]+/ do
|
20
|
+
def evaluate
|
21
|
+
to_s.to_i
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
BabelBridge::Shell.new(TuringParser.new).start
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__),"..","..","lib","babel_bridge")
|
2
|
+
|
3
|
+
class TuringParser < BabelBridge::Parser
|
4
|
+
ignore_whitespace
|
5
|
+
|
6
|
+
rule :statement, "if", :statement, "then", :statement, :else_clause?, "end" do
|
7
|
+
def evaluate
|
8
|
+
if matches[1].evaluate
|
9
|
+
matches[3].evaluate
|
10
|
+
else
|
11
|
+
else_clause.evaluate if else_clause
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
rule :else_clause, "else", :statement
|
16
|
+
|
17
|
+
binary_operators_rule :statement, :operand, [[:/, :*], [:+, :-], [:<, :<=, :>, :>=, :==]] do
|
18
|
+
def evaluate
|
19
|
+
case operator
|
20
|
+
when :<, :<=, :>, :>=, :==
|
21
|
+
(left.evaluate.send operator, right.evaluate) ? 1 : nil
|
22
|
+
else
|
23
|
+
left.evaluate.send operator, right.evaluate
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
rule :operand, "(", :statement, ")"
|
29
|
+
|
30
|
+
rule :operand, /[-]?[0-9]+/ do
|
31
|
+
def evaluate
|
32
|
+
to_s.to_i
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
BabelBridge::Shell.new(TuringParser.new).start
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__),"..","..","lib","babel_bridge")
|
2
|
+
|
3
|
+
class TuringParser < BabelBridge::Parser
|
4
|
+
ignore_whitespace
|
5
|
+
|
6
|
+
def store
|
7
|
+
@store||=[]
|
8
|
+
end
|
9
|
+
|
10
|
+
rule :statement, "if", :statement, "then", :statement, :else_clause?, "end" do
|
11
|
+
def evaluate
|
12
|
+
if statement[0].evaluate
|
13
|
+
statement[1].evaluate
|
14
|
+
else
|
15
|
+
else_clause.evaluate if else_clause
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
rule :else_clause, "else", :statement
|
20
|
+
|
21
|
+
binary_operators_rule :statement, :operand, [[:/, :*], [:+, :-], [:<, :<=, :>, :>=, :==]] do
|
22
|
+
def evaluate
|
23
|
+
case operator
|
24
|
+
when :<, :<=, :>, :>=, :==
|
25
|
+
(left.evaluate.send operator, right.evaluate) ? 1 : nil
|
26
|
+
else
|
27
|
+
left.evaluate.send operator, right.evaluate
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
rule :operand, "(", :statement, ")"
|
33
|
+
|
34
|
+
rule :operand, "[", :statement, "]", "=", :statement do
|
35
|
+
def evaluate
|
36
|
+
parser.store[statement[0].evaluate] = statement[1].evaluate
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
rule :operand, "[", :statement, "]" do
|
41
|
+
def evaluate
|
42
|
+
parser.store[statement.evaluate]
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
rule :operand, /[-]?[0-9]+/ do
|
47
|
+
def evaluate
|
48
|
+
to_s.to_i
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
BabelBridge::Shell.new(TuringParser.new).start
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__),"..","..","lib","babel_bridge")
|
2
|
+
|
3
|
+
class TuringParser < BabelBridge::Parser
|
4
|
+
ignore_whitespace
|
5
|
+
|
6
|
+
def store
|
7
|
+
@store||=[]
|
8
|
+
end
|
9
|
+
|
10
|
+
rule :statements, many(:statement,";"), match?(";") do
|
11
|
+
def evaluate
|
12
|
+
ret = nil
|
13
|
+
statement.each do |s|
|
14
|
+
ret = s.evaluate
|
15
|
+
end
|
16
|
+
ret
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
rule :statement, "if", :statement, "then", :statements, :else_clause?, "end" do
|
21
|
+
def evaluate
|
22
|
+
if statement.evaluate
|
23
|
+
statements.evaluate
|
24
|
+
else
|
25
|
+
else_clause.evaluate if else_clause
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
rule :else_clause, "else", :statements
|
30
|
+
|
31
|
+
binary_operators_rule :statement, :operand, [[:/, :*], [:+, :-], [:<, :<=, :>, :>=, :==]] do
|
32
|
+
def evaluate
|
33
|
+
case operator
|
34
|
+
when :<, :<=, :>, :>=, :==
|
35
|
+
(left.evaluate.send operator, right.evaluate) ? 1 : nil
|
36
|
+
else
|
37
|
+
left.evaluate.send operator, right.evaluate
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
rule :operand, "(", :statement, ")"
|
43
|
+
|
44
|
+
rule :operand, "[", :statement, "]", "=", :statement do
|
45
|
+
def evaluate
|
46
|
+
parser.store[statement[0].evaluate] = statement[1].evaluate
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
rule :operand, "[", :statement, "]" do
|
51
|
+
def evaluate
|
52
|
+
parser.store[statement.evaluate]
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
rule :operand, /[-]?[0-9]+/ do
|
57
|
+
def evaluate
|
58
|
+
to_s.to_i
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
BabelBridge::Shell.new(TuringParser.new).start
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__),"..","..","lib","babel_bridge")
|
2
|
+
|
3
|
+
class TuringParser < BabelBridge::Parser
|
4
|
+
ignore_whitespace
|
5
|
+
|
6
|
+
def store
|
7
|
+
@store||=[]
|
8
|
+
end
|
9
|
+
|
10
|
+
rule :statements, many(:statement,";"), match?(";") do
|
11
|
+
def evaluate
|
12
|
+
ret = nil
|
13
|
+
statement.each do |s|
|
14
|
+
ret = s.evaluate
|
15
|
+
end
|
16
|
+
ret
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
rule :statement, "if", :statement, "then", :statements, :else_clause?, "end" do
|
21
|
+
def evaluate
|
22
|
+
if statement.evaluate
|
23
|
+
statements.evaluate
|
24
|
+
else
|
25
|
+
else_clause.evaluate if else_clause
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
rule :else_clause, "else", :statements
|
30
|
+
|
31
|
+
rule :statement, "while", :statement, "do", :statements, "end" do
|
32
|
+
def evaluate
|
33
|
+
while statement.evaluate
|
34
|
+
statements.evaluate
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
binary_operators_rule :statement, :operand, [[:/, :*], [:+, :-], [:<, :<=, :>, :>=, :==]] do
|
40
|
+
def evaluate
|
41
|
+
case operator
|
42
|
+
when :<, :<=, :>, :>=, :==
|
43
|
+
(left.evaluate.send operator, right.evaluate) ? 1 : nil
|
44
|
+
else
|
45
|
+
left.evaluate.send operator, right.evaluate
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
rule :operand, "(", :statement, ")"
|
51
|
+
|
52
|
+
rule :operand, "[", :statement, "]", "=", :statement do
|
53
|
+
def evaluate
|
54
|
+
parser.store[statement[0].evaluate] = statement[1].evaluate
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
rule :operand, "[", :statement, "]" do
|
59
|
+
def evaluate
|
60
|
+
parser.store[statement.evaluate]
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
rule :operand, /[-]?[0-9]+/ do
|
65
|
+
def evaluate
|
66
|
+
to_s.to_i
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
BabelBridge::Shell.new(TuringParser.new).start
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__),"..","..","lib","babel_bridge")
|
2
|
+
|
3
|
+
class TuringParser < BabelBridge::Parser
|
4
|
+
ignore_whitespace
|
5
|
+
|
6
|
+
def store
|
7
|
+
@store||=[]
|
8
|
+
end
|
9
|
+
|
10
|
+
rule :statements, many(:statement,";"), match?(";") do
|
11
|
+
def evaluate
|
12
|
+
ret = nil
|
13
|
+
statement.each do |s|
|
14
|
+
puts "class is: "+s.class
|
15
|
+
ret = s.evaluate
|
16
|
+
end
|
17
|
+
ret
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
binary_operators_rule :statement, :operand, [[:/, :*], [:+, :-], [:<, :<=, :>, :>=, :==]] do
|
22
|
+
def evaluate
|
23
|
+
case operator
|
24
|
+
when :<, :<=, :>, :>=, :==
|
25
|
+
(left.evaluate.send operator, right.evaluate) ? 1 : nil
|
26
|
+
else
|
27
|
+
left.evaluate.send operator, right.evaluate
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
rule :statement, "if", :statement, "then", :statements, :else_clause?, "end" do
|
33
|
+
def evaluate
|
34
|
+
if statement[0].evaluate
|
35
|
+
statement[1].evaluate
|
36
|
+
else
|
37
|
+
else_clause.evaluate if else_clause
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
rule :else_clause, "else", :statement
|
42
|
+
|
43
|
+
rule :statement, "while", :statement, "do", :statements, "end" do
|
44
|
+
def evaluate
|
45
|
+
while statement.evaluate
|
46
|
+
statements.evaluate
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
rule :operand, "[", :statement, "]", "=", :statement do
|
52
|
+
def evaluate
|
53
|
+
parser.store[statement[0].evaluate] = statement[1].evaluate
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
rule :operand, "[", :statement, "]" do
|
58
|
+
def evaluate
|
59
|
+
parser.store[statement.evaluate]
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
rule :operand, "(", :statement, ")"
|
64
|
+
rule :operand, /-?[0-9]+/ do
|
65
|
+
def evaluate
|
66
|
+
to_s.to_i
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
BabelBridge::Shell.new(TuringParser.new).start
|
data/lib/nodes/many_node.rb
CHANGED
@@ -36,7 +36,9 @@ module BabelBridge
|
|
36
36
|
ret=list.collect {|a|a.inspect(options)}.compact
|
37
37
|
ret= if ret.length==0 then simple ? nil : "[]"
|
38
38
|
elsif ret.length==1 && !ret[0]["\n"] then (simple ? ret[0] : "[#{ret[0]}]")
|
39
|
-
else
|
39
|
+
else
|
40
|
+
ret = ret.collect {|a| " "+a.gsub("\n","\n ")}
|
41
|
+
(simple ? ret : ["[",ret,"]"]).flatten.join("\n") #.gsub("\n","\n ")
|
40
42
|
end
|
41
43
|
ret
|
42
44
|
end
|
data/lib/nodes/node.rb
CHANGED
@@ -41,6 +41,13 @@ class Node
|
|
41
41
|
self
|
42
42
|
end
|
43
43
|
|
44
|
+
# Returns a human-readable representation of the parse tree
|
45
|
+
# options
|
46
|
+
# :simple => output a simplified representation of the parse tree
|
47
|
+
def inspect(options={})
|
48
|
+
"(TODO: def #{self.class}#inspect(options={}))"
|
49
|
+
end
|
50
|
+
|
44
51
|
#********************
|
45
52
|
# info methods
|
46
53
|
#********************
|
data/lib/parser.rb
CHANGED
@@ -160,6 +160,7 @@ class Parser
|
|
160
160
|
attr_accessor :expecting_list
|
161
161
|
attr_accessor :src
|
162
162
|
attr_accessor :parse_cache
|
163
|
+
attr_accessor :failed_parse # gets set if the entire input was not matched
|
163
164
|
|
164
165
|
def initialize
|
165
166
|
reset_parser_tracking
|
@@ -209,6 +210,7 @@ class Parser
|
|
209
210
|
if ret.next<src.length # parse only succeeds if the whole input is matched
|
210
211
|
@parsing_did_not_match_entire_input=true
|
211
212
|
@failure_index=ret.next
|
213
|
+
@failed_parse = ret
|
212
214
|
ret=nil
|
213
215
|
else
|
214
216
|
reset_parser_tracking
|
@@ -235,51 +237,68 @@ class Parser
|
|
235
237
|
node_list && node_list[common_root.length..-1].map{|p|"#{p.class}(#{p.offset})"}.join(" > ")
|
236
238
|
end
|
237
239
|
|
238
|
-
def
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
Source:
|
246
|
-
...
|
247
|
-
#{(failure_index==0 ? "" : src[0..(failure_index-1)]).last_lines(bracketing_lines)}<HERE>#{src[(failure_index)..-1].first_lines(bracketing_lines)}
|
248
|
-
...
|
249
|
-
ENDTXT
|
240
|
+
def nodes_interesting_parse_path(node)
|
241
|
+
path = node.parent_list
|
242
|
+
path << node
|
243
|
+
path.pop while path[-1] && !path[-1].kind_of?(NonTerminalNode)
|
244
|
+
path
|
245
|
+
end
|
250
246
|
|
251
|
-
if @parsing_did_not_match_entire_input
|
252
|
-
ret+="\nParser did not match entire input."
|
253
|
-
else
|
254
247
|
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
common_root=node.parent_list
|
248
|
+
def expecting_output
|
249
|
+
return "" if expecting_list.length==0
|
250
|
+
common_root=nil
|
251
|
+
expecting_list.values.each do |e|
|
252
|
+
node=e[:node]
|
253
|
+
pl=nodes_interesting_parse_path(node)
|
254
|
+
pl.pop # ignore the node itself
|
255
|
+
if common_root
|
256
|
+
common_root.each_index do |i|
|
257
|
+
if pl[i]!=common_root[i]
|
258
|
+
common_root=common_root[0..i-1]
|
259
|
+
break
|
268
260
|
end
|
269
261
|
end
|
270
|
-
|
262
|
+
else
|
263
|
+
common_root=pl
|
264
|
+
end
|
265
|
+
end
|
266
|
+
<<ENDTXT
|
271
267
|
|
272
|
-
|
268
|
+
Parse path at failure:
|
273
269
|
#{node_list_string(common_root)}
|
274
270
|
|
275
271
|
Expecting#{expecting_list.length>1 ? ' one of' : ''}:
|
276
272
|
#{expecting_list.values.collect do |a|
|
277
|
-
list=node_list_string(a[:node]
|
273
|
+
list=node_list_string(nodes_interesting_parse_path(a[:node]),common_root)
|
278
274
|
[list,"#{a[:pattern].inspect} (#{list})"]
|
279
275
|
end.sort.map{|i|i[1]}.join("\n ")}
|
280
276
|
ENDTXT
|
277
|
+
end
|
278
|
+
|
279
|
+
#option: :verbose => true
|
280
|
+
def parser_failure_info(options={})
|
281
|
+
return unless src
|
282
|
+
verbose = options[:verbose]
|
283
|
+
bracketing_lines=5
|
284
|
+
line,col=src.line_col(failure_index)
|
285
|
+
ret=<<-ENDTXT
|
286
|
+
Parsing error at line #{line} column #{col} offset #{failure_index}
|
287
|
+
|
288
|
+
Source:
|
289
|
+
...
|
290
|
+
#{(failure_index==0 ? "" : src[0..(failure_index-1)]).last_lines(bracketing_lines)}<HERE>#{src[(failure_index)..-1].first_lines(bracketing_lines)}
|
291
|
+
...
|
292
|
+
ENDTXT
|
293
|
+
|
294
|
+
if @parsing_did_not_match_entire_input
|
295
|
+
ret+="\nParser did not match entire input.\n"
|
296
|
+
if verbose
|
297
|
+
ret+="\nParsed:\n#{Tools::indent failed_parse.inspect}\n"
|
298
|
+
end
|
281
299
|
end
|
282
|
-
|
300
|
+
|
301
|
+
ret+expecting_output
|
283
302
|
end
|
284
303
|
end
|
285
304
|
end
|
data/lib/pattern_element.rb
CHANGED
@@ -32,6 +32,10 @@ class PatternElement
|
|
32
32
|
raise "pattern element cannot be both :dont and :optional" if negative && optional
|
33
33
|
end
|
34
34
|
|
35
|
+
def inspect
|
36
|
+
"<PatternElement rule_variant=#{rule_variant.variant_node_class} match=#{match.inspect}>"
|
37
|
+
end
|
38
|
+
|
35
39
|
def to_s
|
36
40
|
match.inspect
|
37
41
|
end
|
@@ -50,6 +54,11 @@ class PatternElement
|
|
50
54
|
# Could-match patterns (PEG: &element)
|
51
55
|
match.match_length=0 if match && could_match
|
52
56
|
|
57
|
+
if !match && terminal
|
58
|
+
# log failures on Terminal patterns for debug output if overall parse fails
|
59
|
+
parent_node.parser.log_parsing_failure(parent_node.next,:pattern=>self.match,:node=>parent_node)
|
60
|
+
end
|
61
|
+
|
53
62
|
# return match
|
54
63
|
match
|
55
64
|
end
|
@@ -139,7 +148,7 @@ class PatternElement
|
|
139
148
|
|
140
149
|
# generate delimiter_pattern_element
|
141
150
|
delimiter_pattern_element= hash[:delimiter] && PatternElement.new(hash[:delimiter],rule_variant)
|
142
|
-
|
151
|
+
|
143
152
|
# generate post_delimiter_element
|
144
153
|
post_delimiter_element=hash[:post_delimiter] && case hash[:post_delimiter]
|
145
154
|
when TrueClass then delimiter_pattern_element
|
data/lib/rule_variant.rb
CHANGED
@@ -25,13 +25,7 @@ class RuleVariant
|
|
25
25
|
match=pe.parse(node)
|
26
26
|
|
27
27
|
# if parse failed
|
28
|
-
if !match
|
29
|
-
if pe.terminal
|
30
|
-
# log failures on Terminal patterns for debug output if overall parse fails
|
31
|
-
node.parser.log_parsing_failure(node.next,:pattern=>pe.match,:node=>node)
|
32
|
-
end
|
33
|
-
return nil
|
34
|
-
end
|
28
|
+
return if !match
|
35
29
|
|
36
30
|
# parse succeeded, add to node and continue
|
37
31
|
node.add_match(match,pe.name)
|
data/lib/shell.rb
CHANGED
@@ -8,9 +8,14 @@ class Shell
|
|
8
8
|
end
|
9
9
|
|
10
10
|
def evaluate(parse_tree_node)
|
11
|
-
parse_tree_node.evaluate
|
11
|
+
if parse_tree_node.respond_to? :evaluate
|
12
|
+
" => "+parse_tree_node.evaluate.inspect
|
13
|
+
else
|
14
|
+
"\nParse tree:\n "+
|
15
|
+
parse_tree_node.inspect.gsub("\n","\n ")+"\n\n"
|
16
|
+
end
|
12
17
|
rescue Exception => e
|
13
|
-
@stderr.puts "Error evaluating parse tree: #{e}\n "+e.backtrace.join("\n ")
|
18
|
+
@stderr.puts "Error evaluating parse tree: #{e}\n "+e.backtrace.join("\n ")+"\nParse Tree:\n"+parse_tree_node.inspect
|
14
19
|
end
|
15
20
|
|
16
21
|
# if block is provided, successful parsers are yield to block
|
@@ -19,16 +24,18 @@ class Shell
|
|
19
24
|
@stdout = options[:stdout] || $stdout
|
20
25
|
@stderr = options[:stdout] || @stdout
|
21
26
|
@stdin = options[:stdin] || $stdin
|
22
|
-
while line = @stdin == $stdin ? Readline.readline("> ", true) : @stdin.gets
|
23
|
-
|
27
|
+
while line = @stdin == $stdin ? Readline.readline("> ", true) : @stdin.gets
|
28
|
+
line.strip!
|
29
|
+
next if line.length==0
|
30
|
+
ret = parser.parse line
|
24
31
|
if ret
|
25
32
|
if block
|
26
33
|
yield ret
|
27
34
|
else
|
28
|
-
@stdout.puts
|
35
|
+
@stdout.puts evaluate(ret)
|
29
36
|
end
|
30
37
|
else
|
31
|
-
@stderr.puts parser.parser_failure_info
|
38
|
+
@stderr.puts parser.parser_failure_info :verbose => true
|
32
39
|
end
|
33
40
|
end
|
34
41
|
end
|
data/lib/string.rb
CHANGED
@@ -14,8 +14,11 @@ module BabelBridge
|
|
14
14
|
lines.length<=n ? self : lines[-n..-1].join("\n")
|
15
15
|
end
|
16
16
|
|
17
|
+
# return the line and column of a given offset into this string
|
18
|
+
# line and column are 1-based
|
17
19
|
def line_col(offset)
|
18
|
-
|
20
|
+
return 1,1 if length==0 || offset==0
|
21
|
+
lines=(self[0..offset-1]+" ").split("\n")
|
19
22
|
return lines.length, lines[-1].length
|
20
23
|
end
|
21
24
|
end
|
data/lib/tools.rb
CHANGED
@@ -2,15 +2,33 @@ module BabelBridge
|
|
2
2
|
class Tools
|
3
3
|
class << self
|
4
4
|
|
5
|
+
def indent(string,indent=" ")
|
6
|
+
indent + string.gsub("\n", "\n#{indent}")
|
7
|
+
end
|
8
|
+
|
9
|
+
def symbols_to_strings(array)
|
10
|
+
array.collect {|op| op.kind_of?(Symbol) ? op.to_s : op}
|
11
|
+
end
|
12
|
+
|
13
|
+
def regexp_and_strings_to_regexpstrings(array)
|
14
|
+
array.collect {|op| op.kind_of?(Regexp) ? op.source : Regexp.escape(op)}
|
15
|
+
end
|
16
|
+
|
17
|
+
# sort strings first, regexp second
|
18
|
+
# sort strings by lenght, longest first
|
19
|
+
# will then match first to last
|
20
|
+
def sort_operator_patterns(array)
|
21
|
+
array.sort_by {|a| a.kind_of?(Regexp) ? 0 : -a.length}
|
22
|
+
end
|
23
|
+
|
5
24
|
# Takes an array of Strings and Regexp and generates a new Regexp
|
6
25
|
# that matches the or ("|") of all strings and Regexp
|
7
26
|
def array_to_or_regexp_string(array)
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
end.sort{|a|a.length}.join('|')
|
27
|
+
array = symbols_to_strings array.flatten
|
28
|
+
array = sort_operator_patterns array
|
29
|
+
array = regexp_and_strings_to_regexpstrings array
|
30
|
+
|
31
|
+
array.collect {|op| "(#{op})"}.join('|') #.tap {|a| puts "array_to_or_regexp_string(#{array.inspect}) -> /#{a}/"}
|
14
32
|
end
|
15
33
|
|
16
34
|
def array_to_anchored_or_regexp(array)
|
@@ -33,9 +51,10 @@ class BinaryOperatorProcessor
|
|
33
51
|
|
34
52
|
operator_precedence.each_with_index do |op_level,i|
|
35
53
|
(op_level.kind_of?(Array) ? op_level : [op_level]).each do |op|
|
54
|
+
precedence = operator_precedence.length - i
|
36
55
|
case op
|
37
|
-
when String, Symbol then @exact_operator_precedence[op.to_s] =
|
38
|
-
when Regexp then @regexp_operator_precedence << [op,
|
56
|
+
when String, Symbol then @exact_operator_precedence[op.to_s] = precedence
|
57
|
+
when Regexp then @regexp_operator_precedence << [op,precedence]
|
39
58
|
end
|
40
59
|
end
|
41
60
|
end
|
data/lib/version.rb
CHANGED
data/test/test_bb.rb
CHANGED
@@ -394,7 +394,7 @@ class BBTests < TestHelper
|
|
394
394
|
|
395
395
|
def test_binary_operator_rule
|
396
396
|
parser=new_parser do
|
397
|
-
binary_operators_rule :bin_op, :int, [
|
397
|
+
binary_operators_rule :bin_op, :int, ["**", [:/, :*], [:+, "-"]], :right_operators => ["**"] do
|
398
398
|
def evaluate
|
399
399
|
"(#{left.evaluate}#{operator}#{right.evaluate})"
|
400
400
|
end
|
@@ -408,11 +408,26 @@ class BBTests < TestHelper
|
|
408
408
|
assert_equal "((1+2)+3)", parser.parse("1+2+3").evaluate
|
409
409
|
assert_equal "(1+(2*3))", parser.parse("1+2*3").evaluate
|
410
410
|
assert_equal "((1*2)+3)", parser.parse("1*2+3").evaluate
|
411
|
-
assert_equal "(5**6)",
|
411
|
+
assert_equal "(5**6)", parser.parse("5**6").evaluate
|
412
412
|
assert_equal "((1-2)+((3*4)/(5**6)))", parser.parse("1-2+3*4/5**6").evaluate
|
413
413
|
assert_equal "(5**(6**7))", parser.parse("5**6**7").evaluate
|
414
414
|
end
|
415
415
|
|
416
|
+
def test_line_col
|
417
|
+
assert_equal [1,1], "".line_col(0)
|
418
|
+
assert_equal [1,1], " ".line_col(0)
|
419
|
+
assert_equal [1,1], "a\nbb\nccc".line_col(0)
|
420
|
+
assert_equal [1,2], "a\nbb\nccc".line_col(1)
|
421
|
+
assert_equal [2,1], "a\nbb\nccc".line_col(2)
|
422
|
+
assert_equal [2,2], "a\nbb\nccc".line_col(3)
|
423
|
+
assert_equal [2,3], "a\nbb\nccc".line_col(4)
|
424
|
+
assert_equal [3,1], "a\nbb\nccc".line_col(5)
|
425
|
+
assert_equal [3,2], "a\nbb\nccc".line_col(6)
|
426
|
+
assert_equal [3,3], "a\nbb\nccc".line_col(7)
|
427
|
+
assert_equal [3,4], "a\nbb\nccc".line_col(8)
|
428
|
+
assert_equal [3,4], "a\nbb\nccc".line_col(9)
|
429
|
+
end
|
430
|
+
|
416
431
|
def disabled_test_recursive_block
|
417
432
|
# PEG does have this problem, so this isn't really an error
|
418
433
|
# But maybe in the future we'll handle it better.
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: babel_bridge
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -40,8 +40,24 @@ files:
|
|
40
40
|
- lib/version.rb
|
41
41
|
- examples/indention_grouping.rb
|
42
42
|
- examples/indention_grouping_test.txt
|
43
|
-
- examples/
|
43
|
+
- examples/test.rb
|
44
|
+
- examples/turing/examples.turing
|
45
|
+
- examples/turing/notes.rb
|
44
46
|
- examples/turing/turing.rb
|
47
|
+
- examples/turing/turing00.rb
|
48
|
+
- examples/turing/turing01.rb
|
49
|
+
- examples/turing/turing02.rb
|
50
|
+
- examples/turing/turing03.rb
|
51
|
+
- examples/turing/turing04.rb
|
52
|
+
- examples/turing/turing05.rb
|
53
|
+
- examples/turing/turing06.rb
|
54
|
+
- examples/turing/turing07.rb
|
55
|
+
- examples/turing/turing08.rb
|
56
|
+
- examples/turing/turing09.rb
|
57
|
+
- examples/turing/turing10.rb
|
58
|
+
- examples/turing/turing11.rb
|
59
|
+
- examples/turing/turing12.rb
|
60
|
+
- examples/turing/turing_demo.rb
|
45
61
|
homepage: http://babel-bridge.rubyforge.org
|
46
62
|
licenses: []
|
47
63
|
post_install_message:
|
data/examples/turing/test.rb
DELETED
@@ -1,28 +0,0 @@
|
|
1
|
-
require File.join(File.dirname(__FILE__),"..","..","lib","babel_bridge")
|
2
|
-
|
3
|
-
class TestParser < BabelBridge::Parser
|
4
|
-
|
5
|
-
rule :expr, :bin_op do
|
6
|
-
def evaluate
|
7
|
-
output = bin_op.evaluate
|
8
|
-
input = to_s
|
9
|
-
puts "bbtest: #{output} = #{eval output}"
|
10
|
-
puts "ruby: #{input} = #{eval input}"
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
#rule :bin_op, many(:int,/[-+\/*]/) do
|
15
|
-
binary_operators_rule :bin_op, :operand, [[:+, "-"], [:/, :*], "**"], :right_operators => ["**"] do
|
16
|
-
def evaluate
|
17
|
-
"(#{left.evaluate}#{operator}#{right.evaluate})"
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
rule :operand, "(", :bin_op, ")"
|
22
|
-
|
23
|
-
rule :operand, /[-]?[0-9]+/ do
|
24
|
-
def evaluate; to_s; end
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
BabelBridge::Shell.new(TestParser.new).start
|