pratt_parser 0.0.1 → 0.0.2
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/CHANGELOG +4 -0
- data/examples/expression_evaluator.rb +3 -3
- data/examples/tree.rb +150 -0
- data/pratt_parser.gemspec +1 -1
- metadata +2 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ca11d04a7ae882b9277380b20a737f9da15d71ff
|
4
|
+
data.tar.gz: 73b065cfad311d5310d37ace99ddd4a78683c81c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8a2044d7296b0c958153481589955db1d2e8e40b5b31d937e72ec12175a51d6cbdaff5936e3e0739bfdcae78effe4652c037a474c237d6b9cfe121fb99631c3e
|
7
|
+
data.tar.gz: f576cb77ce8d32f23427dbab99faeaefab17ca438496684ef6732617516207b019bbdc2ca35312c86fa5872a19c89ae0773fba95f11adcae202a86bc409dbb8f
|
data/CHANGELOG
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
3
|
# Evaluate simple arithmetic expressions using a PrattParser.
|
4
|
-
# Supports +, -, *, /, ^ (with
|
5
|
-
# associativity, and parentheses. Also supports = to compare numbers
|
4
|
+
# Supports +, -, *, /, ^ (with customary precedence and
|
5
|
+
# associativity), and parentheses. Also supports = to compare numbers
|
6
6
|
# and booleans. Adding support for < and > would be a simple matter
|
7
7
|
# of adding some more tokens.
|
8
8
|
#
|
9
9
|
# Supporting whitespace needs a lexer that throws away whitespace.
|
10
10
|
#
|
11
11
|
# Numeric integer constants are supported using single-digit tokens
|
12
|
-
# which are left-
|
12
|
+
# which are left-associative.
|
13
13
|
|
14
14
|
require "pratt_parser"
|
15
15
|
|
data/examples/tree.rb
ADDED
@@ -0,0 +1,150 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# Parses simple arithmetic expressions using a PrattParser. Supports
|
4
|
+
# +, -, *, /, ^ (with customary precedence and associativity), and
|
5
|
+
# parentheses. The parse returns a tree of BinaryNode and NumberNode
|
6
|
+
# objects which is printed prefix-style ala Lisp.
|
7
|
+
#
|
8
|
+
# Numeric integer constants are supported using single-digit tokens
|
9
|
+
# which are left-associative.
|
10
|
+
|
11
|
+
require "pratt_parser"
|
12
|
+
|
13
|
+
class BinaryNode
|
14
|
+
def initialize(operator, left, right)
|
15
|
+
@operator = operator
|
16
|
+
@left = left
|
17
|
+
@right = right
|
18
|
+
end
|
19
|
+
|
20
|
+
def to_s
|
21
|
+
"(#{@operator} #{@left} #{@right})"
|
22
|
+
end
|
23
|
+
|
24
|
+
# Returns a pretty-print version of the expression ala Lisp.
|
25
|
+
|
26
|
+
def pp(indent = "")
|
27
|
+
newindent = indent + " "
|
28
|
+
"#{indent}(#{@operator}\n#{@left.pp(newindent)}\n#{@right.pp(newindent)})"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
class NumberNode
|
33
|
+
def initialize(number)
|
34
|
+
@number = number
|
35
|
+
end
|
36
|
+
|
37
|
+
def get_number
|
38
|
+
@number
|
39
|
+
end
|
40
|
+
|
41
|
+
def to_s
|
42
|
+
@number.to_s
|
43
|
+
end
|
44
|
+
|
45
|
+
# Returns a pretty-print version of the expression ala Lisp.
|
46
|
+
|
47
|
+
def pp(indent = "")
|
48
|
+
"#{indent}#{@number}"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
class TreeBuilder
|
53
|
+
def self.eval(expression)
|
54
|
+
PrattParser.new(Lexer.new(expression)).eval
|
55
|
+
end
|
56
|
+
|
57
|
+
class Lexer
|
58
|
+
# Note that new returns an Enumerator, not a Lexer.
|
59
|
+
|
60
|
+
def self.new(expression)
|
61
|
+
Enumerator.new do |y|
|
62
|
+
expression.each_char do |c|
|
63
|
+
# Discard spaces.
|
64
|
+
if c != " "
|
65
|
+
y << @@tokens[c]
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
class Token
|
72
|
+
def initialize(lbp)
|
73
|
+
@lbp = lbp
|
74
|
+
end
|
75
|
+
|
76
|
+
def lbp
|
77
|
+
@lbp
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
class InfixToken < Token
|
82
|
+
def initialize(operator, lbp, associates = :left)
|
83
|
+
super(lbp)
|
84
|
+
@operator = operator
|
85
|
+
@rbp = (associates == :left ? lbp : lbp - 1)
|
86
|
+
end
|
87
|
+
|
88
|
+
def led(parser, left)
|
89
|
+
right = parser.expression(@rbp)
|
90
|
+
BinaryNode.new(@operator, left, right)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
class DigitToken < Token
|
95
|
+
def initialize(lbp, value)
|
96
|
+
super(lbp)
|
97
|
+
@value = value
|
98
|
+
end
|
99
|
+
|
100
|
+
def nud(parser)
|
101
|
+
NumberNode.new(@value)
|
102
|
+
end
|
103
|
+
|
104
|
+
def led(parser, left)
|
105
|
+
NumberNode.new(left.number*10 + @value)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
class LeftParenToken < Token
|
110
|
+
def nud(parser)
|
111
|
+
parser.expression(lbp).tap do
|
112
|
+
parser.expect(RightParenToken)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
class RightParenToken < Token
|
118
|
+
end
|
119
|
+
|
120
|
+
@@tokens = {}
|
121
|
+
|
122
|
+
def self.token(char, t)
|
123
|
+
@@tokens[char] = t
|
124
|
+
end
|
125
|
+
|
126
|
+
def self.infix(char, lbp, associates = :left)
|
127
|
+
token(char, InfixToken.new(char, lbp, associates))
|
128
|
+
end
|
129
|
+
|
130
|
+
token("(", LeftParenToken.new(0))
|
131
|
+
token(")", RightParenToken.new(0))
|
132
|
+
|
133
|
+
infix("=", 10)
|
134
|
+
infix("+", 20)
|
135
|
+
infix("-", 20)
|
136
|
+
infix("*", 30)
|
137
|
+
infix("/", 30)
|
138
|
+
infix("^", 40, :right)
|
139
|
+
|
140
|
+
(0..9).each do |d|
|
141
|
+
token(d.to_s, DigitToken.new(100, d))
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
if __FILE__ == $0
|
147
|
+
tree = TreeBuilder.eval(ARGV[0])
|
148
|
+
puts tree.to_s
|
149
|
+
puts tree.pp
|
150
|
+
end
|
data/pratt_parser.gemspec
CHANGED
@@ -8,7 +8,7 @@ Gem::Specification.new do |gem|
|
|
8
8
|
gem.test_files = `git ls-files -- spec/*`.split("\n")
|
9
9
|
gem.name = "pratt_parser"
|
10
10
|
gem.require_paths = ["lib"]
|
11
|
-
gem.version = "0.0.
|
11
|
+
gem.version = "0.0.2"
|
12
12
|
gem.license = "MIT"
|
13
13
|
# gem.required_ruby_version = '>= 2.1.0'
|
14
14
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pratt_parser
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tom May
|
@@ -24,6 +24,7 @@ files:
|
|
24
24
|
- README.md
|
25
25
|
- Rakefile
|
26
26
|
- examples/expression_evaluator.rb
|
27
|
+
- examples/tree.rb
|
27
28
|
- lib/pratt_parser.rb
|
28
29
|
- pratt_parser.gemspec
|
29
30
|
homepage: https://github.com/tommay/pratt_parser
|