abnf-parser 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (33) hide show
  1. checksums.yaml +7 -0
  2. data/lib/abnf/compiler.rb +28 -0
  3. data/lib/abnf/compiler/ast.rb +67 -0
  4. data/lib/abnf/compiler/controls.rb +4 -0
  5. data/lib/abnf/compiler/controls/ast.rb +28 -0
  6. data/lib/abnf/compiler/controls/grammar.rb +32 -0
  7. data/lib/abnf/compiler/controls/rules.rb +44 -0
  8. data/lib/abnf/compiler/controls/text_stream.rb +15 -0
  9. data/lib/abnf/compiler/errors.rb +7 -0
  10. data/lib/abnf/compiler/grammar.rb +17 -0
  11. data/lib/abnf/compiler/grammar/alternative.rb +27 -0
  12. data/lib/abnf/compiler/grammar/char_val.rb +15 -0
  13. data/lib/abnf/compiler/grammar/compiler.rb +55 -0
  14. data/lib/abnf/compiler/grammar/concatenation.rb +21 -0
  15. data/lib/abnf/compiler/grammar/element.rb +57 -0
  16. data/lib/abnf/compiler/grammar/num_val.rb +72 -0
  17. data/lib/abnf/compiler/grammar/prose_val.rb +15 -0
  18. data/lib/abnf/compiler/grammar/repetition.rb +58 -0
  19. data/lib/abnf/compiler/grammar/rule.rb +31 -0
  20. data/lib/abnf/compiler/grammar/rulename.rb +15 -0
  21. data/lib/abnf/compiler/rule.rb +10 -0
  22. data/lib/abnf/compiler/rule/alternative.rb +43 -0
  23. data/lib/abnf/compiler/rule/concatenation.rb +29 -0
  24. data/lib/abnf/compiler/rule/none.rb +17 -0
  25. data/lib/abnf/compiler/rule/optional.rb +24 -0
  26. data/lib/abnf/compiler/rule/reference.rb +19 -0
  27. data/lib/abnf/compiler/rule/repetition.rb +41 -0
  28. data/lib/abnf/compiler/rule/terminal_value.rb +32 -0
  29. data/lib/abnf/compiler/rule/value_range.rb +33 -0
  30. data/lib/abnf/compiler/rule_list.rb +25 -0
  31. data/lib/abnf/compiler/rule_list/entry.rb +21 -0
  32. data/lib/abnf/compiler/text_stream.rb +67 -0
  33. metadata +75 -0
@@ -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,4 @@
1
+ require 'abnf/compiler/controls/ast'
2
+ require 'abnf/compiler/controls/grammar'
3
+ require 'abnf/compiler/controls/rules'
4
+ require 'abnf/compiler/controls/text_stream'
@@ -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,15 @@
1
+ module ABNF
2
+ module Compiler
3
+ module Controls
4
+ module TextStream
5
+ def self.example
6
+ Compiler::TextStream.new 'some-text'
7
+ end
8
+
9
+ def self.rule
10
+ Compiler::TextStream.new 'some-rule = "some-string"'
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,7 @@
1
+ module ABNF
2
+ module Compiler
3
+ Error = Class.new StandardError
4
+ ParsingError = Class.new Error
5
+ CompileError = Class.new Error
6
+ end
7
+ end
@@ -0,0 +1,17 @@
1
+ module ABNF
2
+ module Compiler
3
+ module Grammar
4
+ C_NL = %r{;[\t -~]*\r\n|\r\n}n
5
+
6
+ C_WSP = %r{\A
7
+ (?:
8
+ [[:blank:]]
9
+ |
10
+ #{C_NL}[[:blank:]]
11
+ )*
12
+ }xn
13
+
14
+ CRLF = %r{\r\n}
15
+ end
16
+ end
17
+ 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,15 @@
1
+ module ABNF
2
+ module Compiler
3
+ module Grammar
4
+ class CharVal
5
+ include Compiler
6
+
7
+ PATTERN = %r{\A"(?<string>[\x20-\x21\x23-\x7E]*)"}
8
+
9
+ def call
10
+ ABNF::Compiler::Rule::TerminalValue.new match_data['string']
11
+ end
12
+ end
13
+ end
14
+ end
15
+ 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,15 @@
1
+ module ABNF
2
+ module Compiler
3
+ module Grammar
4
+ class ProseVal
5
+ include Compiler
6
+
7
+ PATTERN = %r{\A<[\x20-\x3D\x3F-\x7E]*>\z}n
8
+
9
+ def call
10
+ ABNF::Compiler::Rule::None.instance
11
+ end
12
+ end
13
+ end
14
+ end
15
+ 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,10 @@
1
+ module ABNF
2
+ module Compiler
3
+ module Rule
4
+ def parse? text
5
+ stream = Compiler::TextStream(text)
6
+ if parse stream then true else false end
7
+ end
8
+ end
9
+ end
10
+ 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: []