pratt_parser 0.0.0 → 0.0.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.
- checksums.yaml +4 -4
- data/CHANGELOG +8 -0
- data/README.md +12 -5
- data/examples/expression_evaluator.rb +104 -0
- data/pratt_parser.gemspec +3 -3
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f8429fe8f5e629ccb6048fdc5766a278bbd5f5ae
|
4
|
+
data.tar.gz: 03df74e2cb12a8403dd4025c5a4597d3da067a0f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b215b84b04fde6efdbce9c5244ece12be8b9cb9d9e268056cd2699eb63e30f253c93e17e8cfd1287de0fc1702514a26c5b3e4154fa11a21712b248e1019685a9
|
7
|
+
data.tar.gz: e27d791be91a17b96ca7907f32a53274a6ade2a7ab2d88c6cbbfc3d1c77e05f0fc313c560228a6085af4514cf9072d99303e2a31a5c3e8831e768bdce446d9d8
|
data/CHANGELOG
ADDED
data/README.md
CHANGED
@@ -1,19 +1,26 @@
|
|
1
1
|
Pratt Parser
|
2
2
|
============
|
3
3
|
|
4
|
-
A Pratt Parser.
|
5
|
-
|
4
|
+
A Pratt Parser. Just a simple parsing framework.
|
5
|
+
|
6
|
+
Define tokens that describe your language and combine terms. Write a
|
7
|
+
Lexer (an Enumerator) that produces a stream of tokens. Instantiate a
|
8
|
+
PrattParser and call #eval to parse the stream and return whatever
|
9
|
+
your tokens want.
|
6
10
|
|
7
11
|
Pratt parsers are like recursive descent parsers but instead of having
|
8
12
|
to code a function for each production you just code up some token
|
9
|
-
objects which define their own prededence and associativity
|
10
|
-
|
11
|
-
|
13
|
+
objects which define their own prededence and associativity and how
|
14
|
+
subexpressions to the left and/or right are combined. So it's simple
|
15
|
+
to add new language features/tokens without having to rewrite a bunch
|
16
|
+
of recursive descent functions.
|
12
17
|
|
13
18
|
Pratt parsers are also more efficient than recursive descent parsers
|
14
19
|
since they don't need to recurse all the way down to the bottom level
|
15
20
|
to figure out what to do.
|
16
21
|
|
22
|
+
Read more:
|
23
|
+
|
17
24
|
http://javascript.crockford.com/tdop/tdop.html
|
18
25
|
|
19
26
|
http://effbot.org/zone/simple-top-down-parsing.htm
|
@@ -0,0 +1,104 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# Evaluate simple arithmetic expressions using a PrattParser.
|
4
|
+
# Supports +, -, *, /, ^ (with ustomarycorrect precedence and
|
5
|
+
# associativity, and parentheses. Also supports = to compare numbers
|
6
|
+
# and booleans. Adding support for < and > would be a simple matter
|
7
|
+
# of adding some more tokens.
|
8
|
+
#
|
9
|
+
# Supporting whitespace needs a lexer that throws away whitespace.
|
10
|
+
#
|
11
|
+
# Numeric integer constants are supported using single-digit tokens
|
12
|
+
# which are left-associatiuve.
|
13
|
+
|
14
|
+
require "pratt_parser"
|
15
|
+
|
16
|
+
class PrattEvaluator
|
17
|
+
def self.eval(expression)
|
18
|
+
PrattParser.new(Lexer.new(expression)).eval
|
19
|
+
end
|
20
|
+
|
21
|
+
class Lexer
|
22
|
+
# Note that new returns an Enumerator, not a Lexer.
|
23
|
+
|
24
|
+
def self.new(expression)
|
25
|
+
expression.each_char.lazy.map{|c|@@tokens[c]}
|
26
|
+
end
|
27
|
+
|
28
|
+
class Token
|
29
|
+
def initialize(lbp)
|
30
|
+
@lbp = lbp
|
31
|
+
end
|
32
|
+
|
33
|
+
def lbp
|
34
|
+
@lbp
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
class InfixToken < Token
|
39
|
+
def initialize(lbp, associates = :left, &block)
|
40
|
+
super(lbp)
|
41
|
+
@block = block
|
42
|
+
@rbp = (associates == :left ? lbp : lbp - 1)
|
43
|
+
end
|
44
|
+
|
45
|
+
def led(parser, left)
|
46
|
+
@block.call(left, parser.expression(@rbp))
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
class DigitToken < Token
|
51
|
+
def initialize(lbp, value)
|
52
|
+
super(lbp)
|
53
|
+
@value = value
|
54
|
+
end
|
55
|
+
|
56
|
+
def nud(parser)
|
57
|
+
@value
|
58
|
+
end
|
59
|
+
|
60
|
+
def led(parser, left)
|
61
|
+
left*10 + @value
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
class LeftParenToken < Token
|
66
|
+
def nud(parser)
|
67
|
+
parser.expression(lbp).tap do
|
68
|
+
parser.expect(RightParenToken)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
class RightParenToken < Token
|
74
|
+
end
|
75
|
+
|
76
|
+
@@tokens = {}
|
77
|
+
|
78
|
+
def self.token(char, t)
|
79
|
+
@@tokens[char] = t
|
80
|
+
end
|
81
|
+
|
82
|
+
def self.infix(char, lbp, associates = :left, &block)
|
83
|
+
token(char, InfixToken.new(lbp, associates, &block))
|
84
|
+
end
|
85
|
+
|
86
|
+
token("(", LeftParenToken.new(0))
|
87
|
+
token(")", RightParenToken.new(0))
|
88
|
+
|
89
|
+
infix("=", 10, &:==)
|
90
|
+
infix("+", 20, &:+)
|
91
|
+
infix("-", 20, &:-)
|
92
|
+
infix("*", 30, &:*)
|
93
|
+
infix("/", 30, &:/)
|
94
|
+
infix("^", 40, :right, &:**)
|
95
|
+
|
96
|
+
(0..9).each do |d|
|
97
|
+
token(d.to_s, DigitToken.new(100, d.to_f))
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
if __FILE__ == $0
|
103
|
+
puts PrattEvaluator.eval(ARGV[0])
|
104
|
+
end
|
data/pratt_parser.gemspec
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
Gem::Specification.new do |gem|
|
2
|
-
gem.description = "A Pratt parser. Create token objects to define your language."
|
2
|
+
gem.description = "A Pratt parser. Create token objects to define your language. Create a lexer to return tokens. Call the parser to grok the language."
|
3
3
|
gem.summary = "A Pratt parser."
|
4
4
|
gem.authors = ["Tom May"]
|
5
5
|
gem.email = ["tom@tommay.net"]
|
6
6
|
gem.homepage = "https://github.com/tommay/pratt_parser"
|
7
|
-
gem.files = `git ls-files
|
7
|
+
gem.files = `git ls-files`.split("\n")
|
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.1"
|
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.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tom May
|
@@ -10,7 +10,8 @@ bindir: bin
|
|
10
10
|
cert_chain: []
|
11
11
|
date: 2015-02-26 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
|
-
description: A Pratt parser. Create token objects to define your language.
|
13
|
+
description: A Pratt parser. Create token objects to define your language. Create
|
14
|
+
a lexer to return tokens. Call the parser to grok the language.
|
14
15
|
email:
|
15
16
|
- tom@tommay.net
|
16
17
|
executables: []
|
@@ -18,9 +19,11 @@ extensions: []
|
|
18
19
|
extra_rdoc_files: []
|
19
20
|
files:
|
20
21
|
- ".gitignore"
|
22
|
+
- CHANGELOG
|
21
23
|
- LICENSE.md
|
22
24
|
- README.md
|
23
25
|
- Rakefile
|
26
|
+
- examples/expression_evaluator.rb
|
24
27
|
- lib/pratt_parser.rb
|
25
28
|
- pratt_parser.gemspec
|
26
29
|
homepage: https://github.com/tommay/pratt_parser
|