abnf-parser 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/lib/abnf/compiler.rb +28 -0
- data/lib/abnf/compiler/ast.rb +67 -0
- data/lib/abnf/compiler/controls.rb +4 -0
- data/lib/abnf/compiler/controls/ast.rb +28 -0
- data/lib/abnf/compiler/controls/grammar.rb +32 -0
- data/lib/abnf/compiler/controls/rules.rb +44 -0
- data/lib/abnf/compiler/controls/text_stream.rb +15 -0
- data/lib/abnf/compiler/errors.rb +7 -0
- data/lib/abnf/compiler/grammar.rb +17 -0
- data/lib/abnf/compiler/grammar/alternative.rb +27 -0
- data/lib/abnf/compiler/grammar/char_val.rb +15 -0
- data/lib/abnf/compiler/grammar/compiler.rb +55 -0
- data/lib/abnf/compiler/grammar/concatenation.rb +21 -0
- data/lib/abnf/compiler/grammar/element.rb +57 -0
- data/lib/abnf/compiler/grammar/num_val.rb +72 -0
- data/lib/abnf/compiler/grammar/prose_val.rb +15 -0
- data/lib/abnf/compiler/grammar/repetition.rb +58 -0
- data/lib/abnf/compiler/grammar/rule.rb +31 -0
- data/lib/abnf/compiler/grammar/rulename.rb +15 -0
- data/lib/abnf/compiler/rule.rb +10 -0
- data/lib/abnf/compiler/rule/alternative.rb +43 -0
- data/lib/abnf/compiler/rule/concatenation.rb +29 -0
- data/lib/abnf/compiler/rule/none.rb +17 -0
- data/lib/abnf/compiler/rule/optional.rb +24 -0
- data/lib/abnf/compiler/rule/reference.rb +19 -0
- data/lib/abnf/compiler/rule/repetition.rb +41 -0
- data/lib/abnf/compiler/rule/terminal_value.rb +32 -0
- data/lib/abnf/compiler/rule/value_range.rb +33 -0
- data/lib/abnf/compiler/rule_list.rb +25 -0
- data/lib/abnf/compiler/rule_list/entry.rb +21 -0
- data/lib/abnf/compiler/text_stream.rb +67 -0
- metadata +75 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: f9345bd72e56a26df453cb85fe51c3dac095f90c
|
4
|
+
data.tar.gz: 9caae3be175e985e45e9be3fa75d7293e28d13fe
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: fce4984fcd8c8f28cbfa5b1cadb1721fcb43f08b9c5754c5d2aa42c1b2a335f33b1efd18c6d58ad785bccf4bb4fe3113929c09afa6c9ac04bd2dce5e59799f60
|
7
|
+
data.tar.gz: e8ddbfa79408449743b00d809006dd897544ee10bd966d26bc09d186cc55624f269f01bf28721d10b541644b08062cf53e4405242f951bed9748c77e6d34c721
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'abnf/compiler/ast'
|
2
|
+
require 'abnf/compiler/errors'
|
3
|
+
require 'abnf/compiler/text_stream'
|
4
|
+
|
5
|
+
require 'abnf/compiler/grammar'
|
6
|
+
require 'abnf/compiler/grammar/compiler'
|
7
|
+
require 'abnf/compiler/grammar/alternative'
|
8
|
+
require 'abnf/compiler/grammar/char_val'
|
9
|
+
require 'abnf/compiler/grammar/concatenation'
|
10
|
+
require 'abnf/compiler/grammar/element'
|
11
|
+
require 'abnf/compiler/grammar/num_val'
|
12
|
+
require 'abnf/compiler/grammar/prose_val'
|
13
|
+
require 'abnf/compiler/grammar/repetition'
|
14
|
+
require 'abnf/compiler/grammar/rule'
|
15
|
+
require 'abnf/compiler/grammar/rulename'
|
16
|
+
|
17
|
+
require 'abnf/compiler/rule'
|
18
|
+
require 'abnf/compiler/rule/alternative'
|
19
|
+
require 'abnf/compiler/rule/concatenation'
|
20
|
+
require 'abnf/compiler/rule/none'
|
21
|
+
require 'abnf/compiler/rule/optional'
|
22
|
+
require 'abnf/compiler/rule/reference'
|
23
|
+
require 'abnf/compiler/rule/repetition'
|
24
|
+
require 'abnf/compiler/rule/terminal_value'
|
25
|
+
require 'abnf/compiler/rule/value_range'
|
26
|
+
|
27
|
+
require 'abnf/compiler/rule_list'
|
28
|
+
require 'abnf/compiler/rule_list/entry'
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module ABNF
|
2
|
+
module Compiler
|
3
|
+
module AST
|
4
|
+
def self.leaf *arguments
|
5
|
+
Leaf.new *arguments
|
6
|
+
end
|
7
|
+
|
8
|
+
class Leaf
|
9
|
+
attr_reader :text
|
10
|
+
|
11
|
+
def initialize text
|
12
|
+
@text = text
|
13
|
+
end
|
14
|
+
|
15
|
+
def == other_node
|
16
|
+
other_node.respond_to? :text and text == other_node.text
|
17
|
+
end
|
18
|
+
|
19
|
+
def inner_text
|
20
|
+
text
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.repetition *arguments
|
25
|
+
Repetition.new *arguments
|
26
|
+
end
|
27
|
+
|
28
|
+
class Repetition
|
29
|
+
attr_reader :nodes
|
30
|
+
|
31
|
+
def initialize *nodes
|
32
|
+
@nodes = nodes
|
33
|
+
end
|
34
|
+
|
35
|
+
def == other_node
|
36
|
+
other_node.respond_to? :nodes and nodes == other_node.nodes
|
37
|
+
end
|
38
|
+
|
39
|
+
def inner_text
|
40
|
+
strings = nodes.map &:inner_text
|
41
|
+
strings.join
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.sequence *arguments
|
46
|
+
Sequence.new *arguments
|
47
|
+
end
|
48
|
+
|
49
|
+
class Sequence
|
50
|
+
attr_reader :nodes
|
51
|
+
|
52
|
+
def initialize *nodes
|
53
|
+
@nodes = nodes
|
54
|
+
end
|
55
|
+
|
56
|
+
def == other_node
|
57
|
+
other_node.respond_to? :nodes and nodes == other_node.nodes
|
58
|
+
end
|
59
|
+
|
60
|
+
def inner_text
|
61
|
+
strings = nodes.map &:inner_text
|
62
|
+
strings.join
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module ABNF
|
2
|
+
module Compiler
|
3
|
+
module Controls
|
4
|
+
module AST
|
5
|
+
extend self
|
6
|
+
|
7
|
+
def leaf text = nil
|
8
|
+
text ||= 'some-string'
|
9
|
+
Compiler::AST.leaf text
|
10
|
+
end
|
11
|
+
|
12
|
+
def repetition
|
13
|
+
Compiler::AST.repetition(
|
14
|
+
leaf('some-string'),
|
15
|
+
leaf('other-string'),
|
16
|
+
)
|
17
|
+
end
|
18
|
+
|
19
|
+
def sequence
|
20
|
+
Compiler::AST.sequence(
|
21
|
+
leaf('some-string'),
|
22
|
+
leaf('other-string'),
|
23
|
+
)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module ABNF
|
2
|
+
module Compiler
|
3
|
+
module Controls
|
4
|
+
module Grammar
|
5
|
+
class Example
|
6
|
+
attr_reader :abnf
|
7
|
+
attr_reader :type
|
8
|
+
|
9
|
+
def initialize abnf, type
|
10
|
+
@abnf = abnf
|
11
|
+
@type = type
|
12
|
+
end
|
13
|
+
|
14
|
+
def rule
|
15
|
+
@rule ||= type.compile abnf
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
Alternative = Example.new '1*%x30-39 / *%x30-39 "*" *%x30-39', Compiler::Grammar::Alternative
|
20
|
+
CharVal = Example.new '"some-string"', Compiler::Grammar::CharVal
|
21
|
+
Concatenation = Example.new '"some-string" " " "some-string"', Compiler::Grammar::Concatenation
|
22
|
+
Group = Example.new '( "foo" / "bar" )', Compiler::Grammar::Element
|
23
|
+
NumVal = Example.new '%x41.42.43', Compiler::Grammar::NumVal
|
24
|
+
Option = Example.new '[ "some-string" ]', Compiler::Grammar::Element
|
25
|
+
Repetition = Example.new '1*2"some-element"', Compiler::Grammar::Repetition
|
26
|
+
Rulename = Example.new 'some-rule', Compiler::Grammar::Rulename
|
27
|
+
Rule = Example.new "some-rule = \"some-string\"\r\n", Compiler::Grammar::Rule
|
28
|
+
ProseVal = Example.new '<Some Prose>', Compiler::Grammar::ProseVal
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module ABNF
|
2
|
+
module Compiler
|
3
|
+
module Controls
|
4
|
+
module Rules
|
5
|
+
extend self
|
6
|
+
|
7
|
+
def alternative
|
8
|
+
Compiler::Rule::Alternative.new terminal_value, value_range
|
9
|
+
end
|
10
|
+
|
11
|
+
def concatenation
|
12
|
+
Compiler::Rule::Concatenation.new terminal_value, reference
|
13
|
+
end
|
14
|
+
|
15
|
+
def optional
|
16
|
+
Compiler::Rule::Optional.new terminal_value
|
17
|
+
end
|
18
|
+
|
19
|
+
def reference
|
20
|
+
Compiler::Rule::Reference.new 'some-rule'
|
21
|
+
end
|
22
|
+
|
23
|
+
def repetition range = nil
|
24
|
+
range ||= (1..2)
|
25
|
+
element = Rules.terminal_value
|
26
|
+
|
27
|
+
Compiler::Rule::Repetition.new range, element
|
28
|
+
end
|
29
|
+
|
30
|
+
def space
|
31
|
+
Compiler::Rule::TerminalValue.new ' '
|
32
|
+
end
|
33
|
+
|
34
|
+
def terminal_value case_sensitive = false
|
35
|
+
Compiler::Rule::TerminalValue.new 'some-string', case_sensitive
|
36
|
+
end
|
37
|
+
|
38
|
+
def value_range
|
39
|
+
Compiler::Rule::ValueRange.new 'A', 'Z'
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module ABNF
|
2
|
+
module Compiler
|
3
|
+
module Grammar
|
4
|
+
class Alternative
|
5
|
+
include Compiler
|
6
|
+
|
7
|
+
DELIMITER = %r{/}
|
8
|
+
|
9
|
+
def call
|
10
|
+
concatenations = []
|
11
|
+
|
12
|
+
begin
|
13
|
+
concatenation = Concatenation.compile stream
|
14
|
+
break unless concatenation
|
15
|
+
concatenations << concatenation
|
16
|
+
end while match? stream
|
17
|
+
|
18
|
+
ABNF::Compiler::Rule::Alternative.new *concatenations
|
19
|
+
end
|
20
|
+
|
21
|
+
def match? stream
|
22
|
+
stream.match C_WSP and stream.match DELIMITER and stream.match C_WSP
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module ABNF
|
2
|
+
module Compiler
|
3
|
+
module Grammar
|
4
|
+
module Compiler
|
5
|
+
def self.included cls
|
6
|
+
cls.extend BuildMethod
|
7
|
+
cls.extend CompileMethod
|
8
|
+
cls.extend PatternMethod
|
9
|
+
end
|
10
|
+
|
11
|
+
module CompileMethod
|
12
|
+
def compile? stream
|
13
|
+
if compile stream then true else false end
|
14
|
+
end
|
15
|
+
|
16
|
+
def compile stream
|
17
|
+
stream = ABNF::Compiler::TextStream(stream)
|
18
|
+
pattern = self.pattern
|
19
|
+
match_data = stream.match pattern
|
20
|
+
|
21
|
+
return unless match_data
|
22
|
+
|
23
|
+
instance = build stream, match_data
|
24
|
+
instance.()
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
module BuildMethod
|
29
|
+
def build stream, match_data
|
30
|
+
instance = new stream, match_data
|
31
|
+
instance
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
module PatternMethod
|
36
|
+
def pattern
|
37
|
+
if const_defined? :PATTERN
|
38
|
+
const_get :PATTERN
|
39
|
+
else
|
40
|
+
@null_pattern ||= %r{}
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
attr_reader :match_data
|
46
|
+
attr_reader :stream
|
47
|
+
|
48
|
+
def initialize stream, match_data = nil
|
49
|
+
@match_data = match_data
|
50
|
+
@stream = stream
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module ABNF
|
2
|
+
module Compiler
|
3
|
+
module Grammar
|
4
|
+
class Concatenation
|
5
|
+
include Compiler
|
6
|
+
|
7
|
+
def call
|
8
|
+
repetitions = []
|
9
|
+
|
10
|
+
begin
|
11
|
+
repetition = Repetition.compile stream
|
12
|
+
break unless repetition
|
13
|
+
repetitions << repetition
|
14
|
+
end while stream.match C_WSP
|
15
|
+
|
16
|
+
ABNF::Compiler::Rule::Concatenation.new *repetitions
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module ABNF
|
2
|
+
module Compiler
|
3
|
+
module Grammar
|
4
|
+
class Element
|
5
|
+
include Compiler
|
6
|
+
|
7
|
+
GROUP_START = %r{\(}
|
8
|
+
GROUP_STOP = %r{\)}
|
9
|
+
OPTION_START = %r{\[}
|
10
|
+
OPTION_STOP = %r{\]}
|
11
|
+
|
12
|
+
def call
|
13
|
+
if stream.next_character == '['.freeze
|
14
|
+
option
|
15
|
+
elsif stream.next_character == '('.freeze
|
16
|
+
group
|
17
|
+
else
|
18
|
+
terminal
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def group
|
23
|
+
stream.match GROUP_START
|
24
|
+
stream.match C_WSP
|
25
|
+
|
26
|
+
alternative = Alternative.compile stream
|
27
|
+
|
28
|
+
stream.match C_WSP
|
29
|
+
stream.match GROUP_STOP
|
30
|
+
|
31
|
+
alternative
|
32
|
+
end
|
33
|
+
|
34
|
+
def option
|
35
|
+
stream.match OPTION_START
|
36
|
+
stream.match C_WSP
|
37
|
+
|
38
|
+
alternative = Alternative.compile stream
|
39
|
+
option = ABNF::Compiler::Rule::Optional.new alternative
|
40
|
+
|
41
|
+
stream.match C_WSP
|
42
|
+
stream.match OPTION_STOP
|
43
|
+
|
44
|
+
option
|
45
|
+
end
|
46
|
+
|
47
|
+
def terminal
|
48
|
+
[Rulename, CharVal, NumVal, ProseVal].each do |type|
|
49
|
+
output = type.compile stream
|
50
|
+
return output if output
|
51
|
+
end
|
52
|
+
nil
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
module ABNF
|
2
|
+
module Compiler
|
3
|
+
module Grammar
|
4
|
+
class NumVal
|
5
|
+
include Compiler
|
6
|
+
|
7
|
+
PATTERN = %r{\A%
|
8
|
+
(?:
|
9
|
+
(?<base_code>x)(?<first_character>[[:xdigit:]]+)
|
10
|
+
(?:(?:-(?<range_end>[[:xdigit:]]+))|(?<sequence>(?:\.[[:xdigit:]]+)+))?
|
11
|
+
|
|
12
|
+
(?<base_code>d)(?<first_character>[[:digit:]]+)
|
13
|
+
(?:(?:-(?<range_end>[[:digit:]]+))|(?<sequence>(?:\.[[:digit:]]+)+))?
|
14
|
+
|
|
15
|
+
(?<base_code>b)(?<first_character>[01]+)
|
16
|
+
(?:(?:-(?<range_end>[01]+))|(?<sequence>(?:\.[01]+)+))?
|
17
|
+
)
|
18
|
+
}nx
|
19
|
+
|
20
|
+
def base
|
21
|
+
base_code = match_data['base_code'.freeze]
|
22
|
+
|
23
|
+
{
|
24
|
+
'b'.freeze => 2,
|
25
|
+
'd'.freeze => 10,
|
26
|
+
'x'.freeze => 16,
|
27
|
+
}[base_code]
|
28
|
+
end
|
29
|
+
|
30
|
+
def build_string
|
31
|
+
*characters = sequence.to_s.split '.'
|
32
|
+
|
33
|
+
[first_character, *characters].reduce String.new do |string, character|
|
34
|
+
octet = convert_hex_character character
|
35
|
+
string << octet
|
36
|
+
string
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def call
|
41
|
+
if range_end
|
42
|
+
first_octet = convert_hex_character first_character
|
43
|
+
last_octet = convert_hex_character range_end
|
44
|
+
return ABNF::Compiler::Rule::ValueRange.new first_octet, last_octet
|
45
|
+
end
|
46
|
+
|
47
|
+
ABNF::Compiler::Rule::TerminalValue.new build_string, true
|
48
|
+
end
|
49
|
+
|
50
|
+
def convert_hex_character hex
|
51
|
+
character = hex.to_i base
|
52
|
+
octet = character.chr
|
53
|
+
octet
|
54
|
+
end
|
55
|
+
|
56
|
+
def first_character
|
57
|
+
match_data['first_character'.freeze]
|
58
|
+
end
|
59
|
+
|
60
|
+
def range_end
|
61
|
+
match_data['range_end'.freeze]
|
62
|
+
end
|
63
|
+
|
64
|
+
def sequence
|
65
|
+
sequence = match_data['sequence'.freeze]
|
66
|
+
sequence.slice! 0, 1 if sequence
|
67
|
+
sequence
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module ABNF
|
2
|
+
module Compiler
|
3
|
+
module Grammar
|
4
|
+
class Repetition
|
5
|
+
include Compiler
|
6
|
+
|
7
|
+
PATTERN = %r{\A
|
8
|
+
(?:
|
9
|
+
(?<range>(?<minimum>[[:digit:]]*)\*(?<maximum>[[:digit:]]*))
|
10
|
+
|
|
11
|
+
(?<fixed_number>[[:digit:]]+)
|
12
|
+
)?
|
13
|
+
}nx
|
14
|
+
|
15
|
+
def call
|
16
|
+
element = Element.compile stream
|
17
|
+
return unless element
|
18
|
+
|
19
|
+
if no_repeat?
|
20
|
+
min = 1
|
21
|
+
max = 1
|
22
|
+
elsif fixed_number
|
23
|
+
min = fixed_number.to_i
|
24
|
+
max = min
|
25
|
+
else
|
26
|
+
min = minimum.to_i
|
27
|
+
max = if maximum.empty? then Float::INFINITY else maximum.to_i end
|
28
|
+
end
|
29
|
+
|
30
|
+
return element if min == 1 and max == 1
|
31
|
+
return if min > max
|
32
|
+
|
33
|
+
ABNF::Compiler::Rule::Repetition.new min..max, element
|
34
|
+
end
|
35
|
+
|
36
|
+
def fixed_number
|
37
|
+
match_data['fixed_number'.freeze]
|
38
|
+
end
|
39
|
+
|
40
|
+
def maximum
|
41
|
+
match_data['maximum'.freeze]
|
42
|
+
end
|
43
|
+
|
44
|
+
def minimum
|
45
|
+
match_data['minimum'.freeze]
|
46
|
+
end
|
47
|
+
|
48
|
+
def no_repeat?
|
49
|
+
not fixed_number and not range?
|
50
|
+
end
|
51
|
+
|
52
|
+
def range?
|
53
|
+
match_data['range'.freeze]
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module ABNF
|
2
|
+
module Compiler
|
3
|
+
module Grammar
|
4
|
+
class Rule
|
5
|
+
include Compiler
|
6
|
+
|
7
|
+
DELIMITER = %r{=/?}n
|
8
|
+
|
9
|
+
def call
|
10
|
+
reference = Rulename.compile stream
|
11
|
+
return unless reference
|
12
|
+
|
13
|
+
rulename = reference.rulename
|
14
|
+
stream.match C_WSP
|
15
|
+
alternative_form = extract_delimiter
|
16
|
+
stream.match C_WSP
|
17
|
+
alternative = Alternative.compile stream
|
18
|
+
stream.match C_NL
|
19
|
+
|
20
|
+
RuleList::Entry.new rulename, alternative, alternative_form
|
21
|
+
end
|
22
|
+
|
23
|
+
def extract_delimiter
|
24
|
+
match_data = stream.match DELIMITER
|
25
|
+
return unless match_data
|
26
|
+
match_data.to_s == '=/'.freeze
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module ABNF
|
2
|
+
module Compiler
|
3
|
+
module Grammar
|
4
|
+
class Rulename
|
5
|
+
include Compiler
|
6
|
+
|
7
|
+
PATTERN = %r{\A(?<string>[[:alpha:]][-[:alpha:][:digit:]]*)}n
|
8
|
+
|
9
|
+
def call
|
10
|
+
ABNF::Compiler::Rule::Reference.new match_data['string']
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module ABNF
|
2
|
+
module Compiler
|
3
|
+
module Rule
|
4
|
+
class Alternative
|
5
|
+
include Rule
|
6
|
+
|
7
|
+
attr_reader :rules
|
8
|
+
|
9
|
+
def initialize *rules
|
10
|
+
@rules = rules
|
11
|
+
end
|
12
|
+
|
13
|
+
def find_match stream
|
14
|
+
matches = []
|
15
|
+
|
16
|
+
rules.each do |rule|
|
17
|
+
stream.branch do
|
18
|
+
node = rule.parse stream
|
19
|
+
matches.<< Match.new node, stream.position if node
|
20
|
+
false
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
matches.sort!
|
25
|
+
matches.pop
|
26
|
+
end
|
27
|
+
|
28
|
+
def parse stream
|
29
|
+
match = find_match stream
|
30
|
+
return unless match
|
31
|
+
stream.seek match.stream_position
|
32
|
+
match.node
|
33
|
+
end
|
34
|
+
|
35
|
+
Match = Struct.new :node, :stream_position do
|
36
|
+
def <=> match
|
37
|
+
stream_position <=> match.stream_position
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module ABNF
|
2
|
+
module Compiler
|
3
|
+
module Rule
|
4
|
+
class Concatenation
|
5
|
+
include Rule
|
6
|
+
|
7
|
+
attr_reader :rules
|
8
|
+
|
9
|
+
def initialize *rules
|
10
|
+
@rules = rules
|
11
|
+
end
|
12
|
+
|
13
|
+
def parse stream
|
14
|
+
nodes = []
|
15
|
+
|
16
|
+
stream.branch do
|
17
|
+
rules.all? do |rule|
|
18
|
+
node = rule.parse stream
|
19
|
+
nodes << node if node
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
return unless nodes.size == rules.size
|
24
|
+
AST.sequence *nodes
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module ABNF
|
2
|
+
module Compiler
|
3
|
+
module Rule
|
4
|
+
class None
|
5
|
+
include Rule
|
6
|
+
|
7
|
+
def self.instance
|
8
|
+
@instance ||= new
|
9
|
+
end
|
10
|
+
|
11
|
+
def parse *;
|
12
|
+
raise ParsingError, 'Prose in ABNF source material must be overridden'
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module ABNF
|
2
|
+
module Compiler
|
3
|
+
module Rule
|
4
|
+
class Optional
|
5
|
+
include Rule
|
6
|
+
|
7
|
+
attr_reader :rule
|
8
|
+
|
9
|
+
def initialize rule
|
10
|
+
@rule = rule
|
11
|
+
end
|
12
|
+
|
13
|
+
def parse stream
|
14
|
+
node = nil
|
15
|
+
stream.branch do
|
16
|
+
node = rule.parse stream
|
17
|
+
end
|
18
|
+
node ||= AST.leaf ''
|
19
|
+
node
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module ABNF
|
2
|
+
module Compiler
|
3
|
+
module Rule
|
4
|
+
class Reference
|
5
|
+
include Rule
|
6
|
+
|
7
|
+
attr_reader :rulename
|
8
|
+
|
9
|
+
def initialize rulename
|
10
|
+
@rulename = rulename
|
11
|
+
end
|
12
|
+
|
13
|
+
def parse *;
|
14
|
+
raise ParsingError, "Rule not found: #{rulename.inspect}"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module ABNF
|
2
|
+
module Compiler
|
3
|
+
module Rule
|
4
|
+
class Repetition
|
5
|
+
include Rule
|
6
|
+
|
7
|
+
attr_reader :element
|
8
|
+
attr_reader :range
|
9
|
+
|
10
|
+
def initialize range, element
|
11
|
+
@element = element
|
12
|
+
@range = range
|
13
|
+
end
|
14
|
+
|
15
|
+
def maximum
|
16
|
+
range.last
|
17
|
+
end
|
18
|
+
|
19
|
+
def minimum
|
20
|
+
range.first
|
21
|
+
end
|
22
|
+
|
23
|
+
def parse stream
|
24
|
+
matches = false
|
25
|
+
nodes = []
|
26
|
+
|
27
|
+
stream.branch do
|
28
|
+
until nodes.size == maximum
|
29
|
+
node = element.parse stream
|
30
|
+
break unless node
|
31
|
+
nodes << node
|
32
|
+
end
|
33
|
+
matches = true if nodes.size >= minimum
|
34
|
+
end
|
35
|
+
|
36
|
+
AST.repetition *nodes if matches
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module ABNF
|
2
|
+
module Compiler
|
3
|
+
module Rule
|
4
|
+
class TerminalValue
|
5
|
+
include Rule
|
6
|
+
|
7
|
+
attr_reader :case_sensitive
|
8
|
+
attr_reader :string
|
9
|
+
|
10
|
+
def initialize string, case_sensitive = false
|
11
|
+
@string = string
|
12
|
+
@case_sensitive = case_sensitive
|
13
|
+
end
|
14
|
+
|
15
|
+
def parse stream
|
16
|
+
match_data = stream.match regexp
|
17
|
+
return unless match_data
|
18
|
+
AST.leaf match_data.to_s
|
19
|
+
end
|
20
|
+
|
21
|
+
def regexp
|
22
|
+
@regexp ||=
|
23
|
+
begin
|
24
|
+
escaped_string = Regexp.escape string
|
25
|
+
case_insensitive = !case_sensitive
|
26
|
+
Regexp.new escaped_string, case_insensitive, 'n'.freeze
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module ABNF
|
2
|
+
module Compiler
|
3
|
+
module Rule
|
4
|
+
class ValueRange
|
5
|
+
include Rule
|
6
|
+
|
7
|
+
attr_reader :start_character
|
8
|
+
attr_reader :end_character
|
9
|
+
|
10
|
+
def initialize start_character, end_character
|
11
|
+
@start_character = start_character
|
12
|
+
@end_character = end_character
|
13
|
+
end
|
14
|
+
|
15
|
+
def parse stream
|
16
|
+
match_data = stream.match regexp
|
17
|
+
return unless match_data
|
18
|
+
AST.leaf match_data.to_s
|
19
|
+
end
|
20
|
+
|
21
|
+
def regexp
|
22
|
+
@regexp ||=
|
23
|
+
begin
|
24
|
+
start_char = Regexp.escape start_character
|
25
|
+
end_char = Regexp.escape end_character
|
26
|
+
|
27
|
+
Regexp.new "[#{start_char}-#{end_char}]", false, 'n'.freeze
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module ABNF
|
2
|
+
module Compiler
|
3
|
+
class RuleList
|
4
|
+
attr_reader :rules
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
@rules = {}
|
8
|
+
end
|
9
|
+
|
10
|
+
def compile abnf
|
11
|
+
stream = Compiler::TextStream(abnf)
|
12
|
+
|
13
|
+
until stream.eof?
|
14
|
+
stream.match Grammar::C_WSP
|
15
|
+
stream.match Grammar::C_NL
|
16
|
+
|
17
|
+
rule = Grammar::Rule.compile stream
|
18
|
+
next unless rule
|
19
|
+
|
20
|
+
rules[rule.name] = rule
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module ABNF
|
2
|
+
module Compiler
|
3
|
+
class RuleList
|
4
|
+
class Entry
|
5
|
+
attr_reader :alternative_form
|
6
|
+
attr_reader :name
|
7
|
+
attr_reader :rule
|
8
|
+
|
9
|
+
def initialize name, rule, alternative_form
|
10
|
+
@alternative_form = alternative_form
|
11
|
+
@name = name
|
12
|
+
@rule = rule
|
13
|
+
end
|
14
|
+
|
15
|
+
def alternative_form?
|
16
|
+
alternative_form
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module ABNF
|
2
|
+
module Compiler
|
3
|
+
class TextStream
|
4
|
+
attr_reader :stack
|
5
|
+
attr_reader :text
|
6
|
+
|
7
|
+
def initialize text
|
8
|
+
@text = text
|
9
|
+
@stack = [0]
|
10
|
+
end
|
11
|
+
|
12
|
+
def == other_stream
|
13
|
+
return unless other_stream.is_a? self.class
|
14
|
+
text == other_stream.text and stack == other_stream.stack
|
15
|
+
end
|
16
|
+
|
17
|
+
def branch &block
|
18
|
+
next_position = position
|
19
|
+
|
20
|
+
stack << position
|
21
|
+
if block.()
|
22
|
+
next_position = position
|
23
|
+
end
|
24
|
+
stack.pop
|
25
|
+
|
26
|
+
self.position = next_position
|
27
|
+
end
|
28
|
+
|
29
|
+
def eof?
|
30
|
+
position == text.size
|
31
|
+
end
|
32
|
+
|
33
|
+
def match regexp
|
34
|
+
match_data = regexp.match rest
|
35
|
+
return unless match_data
|
36
|
+
return unless match_data.pre_match.empty?
|
37
|
+
self.position += match_data.to_s.size
|
38
|
+
match_data
|
39
|
+
end
|
40
|
+
|
41
|
+
def next_character
|
42
|
+
text[position]
|
43
|
+
end
|
44
|
+
|
45
|
+
def position= new_position
|
46
|
+
stack[-1] = new_position
|
47
|
+
end
|
48
|
+
alias_method :seek, :position=
|
49
|
+
|
50
|
+
def position
|
51
|
+
stack[-1]
|
52
|
+
end
|
53
|
+
|
54
|
+
def rest
|
55
|
+
text[position..-1]
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.TextStream string_or_stream
|
60
|
+
case string_or_stream
|
61
|
+
when String then TextStream.new string_or_stream
|
62
|
+
when TextStream then string_or_stream
|
63
|
+
else raise TypeError, "Invalid value for TextStream(): #{string_or_stream.inspect}"
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
metadata
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: abnf-parser
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.8.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Nathan Ladd
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-11-13 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: abnf-parser allows you to compile ABNF into rule lists that can be used
|
14
|
+
to parse text.
|
15
|
+
email: nathanladd+github@gmail.com
|
16
|
+
executables: []
|
17
|
+
extensions: []
|
18
|
+
extra_rdoc_files: []
|
19
|
+
files:
|
20
|
+
- lib/abnf/compiler.rb
|
21
|
+
- lib/abnf/compiler/ast.rb
|
22
|
+
- lib/abnf/compiler/controls.rb
|
23
|
+
- lib/abnf/compiler/controls/ast.rb
|
24
|
+
- lib/abnf/compiler/controls/grammar.rb
|
25
|
+
- lib/abnf/compiler/controls/rules.rb
|
26
|
+
- lib/abnf/compiler/controls/text_stream.rb
|
27
|
+
- lib/abnf/compiler/errors.rb
|
28
|
+
- lib/abnf/compiler/grammar.rb
|
29
|
+
- lib/abnf/compiler/grammar/alternative.rb
|
30
|
+
- lib/abnf/compiler/grammar/char_val.rb
|
31
|
+
- lib/abnf/compiler/grammar/compiler.rb
|
32
|
+
- lib/abnf/compiler/grammar/concatenation.rb
|
33
|
+
- lib/abnf/compiler/grammar/element.rb
|
34
|
+
- lib/abnf/compiler/grammar/num_val.rb
|
35
|
+
- lib/abnf/compiler/grammar/prose_val.rb
|
36
|
+
- lib/abnf/compiler/grammar/repetition.rb
|
37
|
+
- lib/abnf/compiler/grammar/rule.rb
|
38
|
+
- lib/abnf/compiler/grammar/rulename.rb
|
39
|
+
- lib/abnf/compiler/rule.rb
|
40
|
+
- lib/abnf/compiler/rule/alternative.rb
|
41
|
+
- lib/abnf/compiler/rule/concatenation.rb
|
42
|
+
- lib/abnf/compiler/rule/none.rb
|
43
|
+
- lib/abnf/compiler/rule/optional.rb
|
44
|
+
- lib/abnf/compiler/rule/reference.rb
|
45
|
+
- lib/abnf/compiler/rule/repetition.rb
|
46
|
+
- lib/abnf/compiler/rule/terminal_value.rb
|
47
|
+
- lib/abnf/compiler/rule/value_range.rb
|
48
|
+
- lib/abnf/compiler/rule_list.rb
|
49
|
+
- lib/abnf/compiler/rule_list/entry.rb
|
50
|
+
- lib/abnf/compiler/text_stream.rb
|
51
|
+
homepage: https://github.com/ntl/abnf-parser
|
52
|
+
licenses:
|
53
|
+
- MIT
|
54
|
+
metadata: {}
|
55
|
+
post_install_message:
|
56
|
+
rdoc_options: []
|
57
|
+
require_paths:
|
58
|
+
- lib
|
59
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - ">="
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: '0'
|
64
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
requirements: []
|
70
|
+
rubyforge_project:
|
71
|
+
rubygems_version: 2.4.5.1
|
72
|
+
signing_key:
|
73
|
+
specification_version: 4
|
74
|
+
summary: ABNF Compiler & Parsing Library
|
75
|
+
test_files: []
|