bibtex-ruby 1.2.1 → 1.3.0

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.

Potentially problematic release.


This version of bibtex-ruby might be problematic. Click here for more details.

Files changed (67) hide show
  1. data/Gemfile +6 -1
  2. data/Gemfile.lock +48 -5
  3. data/History.txt +16 -1
  4. data/Manifest +43 -19
  5. data/README.md +178 -167
  6. data/Rakefile +26 -5
  7. data/auto.watchr +6 -0
  8. data/bibtex-ruby.gemspec +8 -5
  9. data/examples/bib2html.rb +28 -18
  10. data/features/bibtex.feature +96 -0
  11. data/features/entries.feature +67 -0
  12. data/features/issues/slash_keys.feature +21 -0
  13. data/features/names.feature +72 -0
  14. data/features/preambles.feature +27 -0
  15. data/features/query.feature +56 -0
  16. data/features/replacement.feature +68 -0
  17. data/features/step_definitions/bibtex_steps.rb +74 -0
  18. data/features/step_definitions/name_steps.rb +13 -0
  19. data/features/strings.feature +52 -0
  20. data/features/support/env.rb +7 -0
  21. data/lib/bibtex.rb +5 -1
  22. data/lib/bibtex/bibliography.rb +218 -95
  23. data/lib/bibtex/bibtex.y +18 -15
  24. data/lib/bibtex/elements.rb +130 -136
  25. data/lib/bibtex/entry.rb +133 -69
  26. data/lib/bibtex/extensions.rb +0 -35
  27. data/lib/bibtex/lexer.rb +9 -9
  28. data/lib/bibtex/name_parser.output +464 -0
  29. data/lib/bibtex/name_parser.rb +490 -0
  30. data/lib/bibtex/names.rb +162 -0
  31. data/lib/bibtex/names.y +196 -0
  32. data/lib/bibtex/parser.output +5 -5
  33. data/lib/bibtex/parser.rb +19 -16
  34. data/lib/bibtex/replaceable.rb +52 -0
  35. data/lib/bibtex/utilities.rb +23 -5
  36. data/lib/bibtex/value.rb +201 -0
  37. data/lib/bibtex/version.rb +1 -1
  38. data/test/benchmark.rb +52 -0
  39. data/test/bibtex/test_bibliography.rb +141 -0
  40. data/test/bibtex/test_elements.rb +40 -0
  41. data/test/bibtex/test_entry.rb +99 -0
  42. data/test/bibtex/test_names.rb +23 -0
  43. data/test/bibtex/test_parser.rb +79 -0
  44. data/test/bibtex/test_string.rb +83 -0
  45. data/test/bibtex/test_utilities.rb +34 -0
  46. data/test/bibtex/test_value.rb +70 -0
  47. data/test/{bib/10_bibdesk.bib → fixtures/bibdesk.bib} +1 -1
  48. data/test/{bib/05_comment.bib → fixtures/comment.bib} +0 -0
  49. data/test/{bib/08_decoret.bib → fixtures/decoret.bib} +0 -0
  50. data/test/{bib/00_empty.bib → fixtures/empty.bib} +0 -0
  51. data/test/{bib/07_entry.bib → fixtures/entry.bib} +0 -0
  52. data/test/{bib/09_errors.bib → fixtures/errors.bib} +0 -0
  53. data/test/{bib/01_no_bibtex.bib → fixtures/no_bibtex.bib} +0 -0
  54. data/test/{bib/06_preamble.bib → fixtures/preamble.bib} +1 -1
  55. data/test/{bib/11_roundtrip.bib → fixtures/roundtrip.bib} +1 -1
  56. data/test/helper.rb +17 -2
  57. data/test/test_bibtex.rb +87 -93
  58. data/test/test_export.rb +18 -22
  59. metadata +85 -30
  60. data/test/bib/02_string.bib +0 -1
  61. data/test/bib/03_string.bib +0 -25
  62. data/test/bib/04_string_replacement.bib +0 -16
  63. data/test/test_comment.rb +0 -21
  64. data/test/test_entry.rb +0 -98
  65. data/test/test_preamble.rb +0 -39
  66. data/test/test_string.rb +0 -97
  67. data/test/test_utilities.rb +0 -36
@@ -1,6 +1,6 @@
1
1
  #--
2
2
  # BibTeX-Ruby
3
- # Copyright (C) 2010 Sylvester Keil <sylvester.keil.or.at>
3
+ # Copyright (C) 2010-2011 Sylvester Keil <sylvester.keil.or.at>
4
4
  #
5
5
  # This program is free software: you can redistribute it and/or modify
6
6
  # it under the terms of the GNU General Public License as published by
@@ -16,57 +16,80 @@
16
16
  # along with this program. If not, see <http://www.gnu.org/licenses/>.
17
17
  #++
18
18
 
19
+ require 'forwardable'
20
+
19
21
  module BibTeX
20
22
  #
21
23
  # Represents a regular BibTeX entry.
22
24
  #
23
25
  class Entry < Element
24
-
25
- attr_reader :key, :type, :fields
26
-
26
+ extend Forwardable
27
+ include Enumerable
28
+
27
29
  # Hash containing the required fields of the standard entry types
28
- @@RequiredFields = Hash.new([])
29
- @@RequiredFields.merge!({
30
- :article => [:author,:title,:journal,:year],
31
- :book => [[:author,:editor],:title,:publisher,:year],
32
- :booklet => [:title],
33
- :conference => [:author,:title,:booktitle,:year],
34
- :inbook => [[:author,:editor],:title,[:chapter,:pages],:publisher,:year],
35
- :incollection => [:author,:title,:booktitle,:publisher,:year],
30
+ REQUIRED_FIELDS = Hash.new([]).merge({
31
+ :article => [:author,:title,:journal,:year],
32
+ :book => [[:author,:editor],:title,:publisher,:year],
33
+ :booklet => [:title],
34
+ :conference => [:author,:title,:booktitle,:year],
35
+ :inbook => [[:author,:editor],:title,[:chapter,:pages],:publisher,:year],
36
+ :incollection => [:author,:title,:booktitle,:publisher,:year],
36
37
  :inproceedings => [:author,:title,:booktitle,:year],
37
- :manual => [:title],
38
+ :manual => [:title],
38
39
  :mastersthesis => [:author,:title,:school,:year],
39
- :misc => [],
40
- :phdthesis => [:author,:title,:school,:year],
41
- :proceedings => [:title,:year],
42
- :techreport => [:author,:title,:institution,:year],
43
- :unpublished => [:author,:title,:note]
44
- })
40
+ :misc => [],
41
+ :phdthesis => [:author,:title,:school,:year],
42
+ :proceedings => [:title,:year],
43
+ :techreport => [:author,:title,:institution,:year],
44
+ :unpublished => [:author,:title,:note]
45
+ }).freeze
46
+
47
+ NAME_FIELDS = [:author, :editor, :translator].freeze
48
+
49
+ attr_reader :type, :fields
50
+ def_delegators :@fields, :empty?, :each
45
51
 
46
52
  # Creates a new instance. If a hash is given, the entry is populated accordingly.
47
- def initialize(hash={})
53
+ def initialize(attributes = {})
48
54
  @fields = {}
49
55
 
50
- self.type = hash.delete(:type) if hash.has_key?(:type)
51
- self.key = hash.delete(:key) if hash.has_key?(:key)
52
-
53
- hash.each { |k, v| add(k.to_sym, v) }
56
+ self.type = attributes.delete(:type) if attributes.has_key?(:type)
57
+ self.key = attributes.delete(:key) if attributes.has_key?(:key)
58
+
59
+ add(attributes)
54
60
 
55
61
  yield self if block_given?
56
62
  end
57
63
 
58
64
  # Sets the key of the entry
59
65
  def key=(key)
60
- raise(ArgumentError, "BibTeX::Entry key must be of type String; was: #{key.class.name}.") unless key.is_a?(::String)
61
- @key = key
66
+ raise(ArgumentError, "keys must be convertible to Symbol; was: #{type.class.name}.") unless type.respond_to?(:to_sym)
67
+
68
+ unless @bibliography.nil?
69
+ @bibliography.entries.delete(@key)
70
+ @bibliography.entries[key] = self
71
+ end
72
+
73
+ @key = key.to_sym
74
+ end
75
+
76
+ def key
77
+ @key ||= default_key
62
78
  end
63
79
 
80
+ alias :id :key
81
+ alias :id= :key=
82
+
64
83
  # Sets the type of the entry.
65
84
  def type=(type)
66
- raise(ArgumentError, "BibTeX::Entry type must be convertible to Symbol; was: #{type.class.name}.") unless type.respond_to?(:to_sym)
85
+ raise(ArgumentError, "types must be convertible to Symbol; was: #{type.class.name}.") unless type.respond_to?(:to_sym)
67
86
  @type = type.to_sym
68
87
  end
69
88
 
89
+ def has_type?(type)
90
+ type.to_s.match(/^entry$/i) || @type == type.to_sym || super
91
+ end
92
+
70
93
  def method_missing(name, *args)
71
94
  return self[name] if @fields.has_key?(name)
72
95
  return self.send(:add, name.to_s.chop.to_sym, args[0]) if name.to_s.match(/=$/)
@@ -77,9 +100,23 @@ module BibTeX
77
100
  @fields.has_key?(method.to_sym) || method.to_s.match(/=$/) || super
78
101
  end
79
102
 
103
+ # Renames the given field names unless a field with the new name already
104
+ # exists.
105
+ def rename(*arguments)
106
+ Hash[*arguments.flatten].each_pair do |from,to|
107
+ if @field.has_key?(from) && !@field.has_key?(to)
108
+ @field[to] = @field[from]
109
+ @field.delete(from)
110
+ end
111
+ end
112
+ self
113
+ end
114
+
115
+ alias :rename_fields :rename
116
+
80
117
  # Returns the value of the field with the given name.
81
118
  def [](name)
82
- @fields[name.to_sym].to_s
119
+ @fields[name.to_sym]
83
120
  end
84
121
 
85
122
  # Adds a new field (name-value pair) to the entry.
@@ -88,13 +125,23 @@ module BibTeX
88
125
  add(name.to_sym, value)
89
126
  end
90
127
 
91
- # Adds a new field (name-value pair) to the entry.
92
- # Returns the new value.
93
- def add(name, value)
94
- raise(ArgumentError, "BibTeX::Entry field name must be of type Symbol; was: #{name.class.name}.") unless name.is_a?(Symbol)
95
- raise(ArgumentError, "BibTeX::Entry field value must be of type Array, Symbol, or String; was: #{value.class.name}.") unless [Array,::String,Symbol].map { |k| value.is_a?(k) }.inject { |sum,n| sum || n }
96
- @fields[name] = Extensions.string_replacement(value.is_a?(Array) ? value : [value])
128
+ # Adds a new field (name-value pair) or multiple fields to the entry.
129
+ # Returns the entry for chainability.
130
+ #
131
+ # call-seq:
132
+ # add(:author, "Edgar A. Poe")
133
+ # add(:author, "Edgar A. Poe", :title, "The Raven")
134
+ # add([:author, "Edgar A. Poe", :title, "The Raven"])
135
+ # add(:author => "Edgar A. Poe", :title => "The Raven")
136
+ #
137
+ def add(*arguments)
138
+ Hash[*arguments.flatten].each_pair do |name, value|
139
+ @fields[name.to_sym] = Value.new(value)
140
+ end
141
+ self
97
142
  end
143
+
144
+ alias :<< :add
98
145
 
99
146
  # Removes the field with a given name from the entry.
100
147
  # Returns the value of the deleted field; nil if the field was not set.
@@ -102,77 +149,94 @@ module BibTeX
102
149
  @fields.delete(name.to_sym)
103
150
  end
104
151
 
105
- # Adds all the fields contained in a given hash to the entry.
106
- def <<(fields)
107
- raise(ArgumentError, "BibTeX::Entry fields must be of type Hash; was: #{fields.class.name}.") unless fields.is_a?(Hash)
108
- fields.each { |n,v| add(n,v) }
109
- self
110
- end
111
-
112
- # Returns true if the entry currently contains no field.
113
- def empty?
114
- @fields.empty?
115
- end
116
-
117
152
  # Returns false if the entry is one of the standard entry types and does not have
118
153
  # definitions of all the required fields for that type.
119
154
  def valid?
120
- !@@RequiredFields[@type].map { |f|
155
+ REQUIRED_FIELDS[@type].all? do |f|
121
156
  f.is_a?(Array) ? !(f & @fields.keys).empty? : !@fields[f].nil?
122
- }.include?(false)
157
+ end
123
158
  end
124
159
 
125
160
  # Called when the element was added to a bibliography.
126
161
  def added_to_bibliography(bibliography)
127
- super(bibliography)
128
- bibliography.entries[@key] = self
162
+ super
163
+ bibliography.entries[key] = self
129
164
  self
130
165
  end
131
-
166
+
132
167
  # Called when the element was removed from a bibliography.
133
168
  def removed_from_bibliography(bibliography)
134
- super(bibliography)
135
- bibliography.entries[@key] = nil
169
+ super
170
+ bibliography.entries[key] = nil
136
171
  self
137
172
  end
138
173
 
139
- # Replaces all constants in this entry's field values which are defined in +hash+.
140
- def replace!(hash)
141
- @fields.keys.each { |k| @fields[k] = @fields[k].replace_strings(hash) }
174
+ def replace(*arguments)
175
+ arguments = bibliography.q('@string') if arguments.empty?
176
+ @fields.values.each { |v| v.replace(*arguments) }
177
+ self
142
178
  end
143
179
 
144
- def join!
145
- @fields.keys.each { |k| @fields[k] = @fields[k].join_strings }
180
+ def join
181
+ @fields.values.each(&:join)
182
+ self
146
183
  end
147
184
 
185
+ # Parses all name values of the entry. Tries to replace and join the
186
+ # value prior to parsing.
187
+ def parse_names
188
+ NAME_FIELDS.each do |key|
189
+ if name = @fields[key]
190
+ name.replace(bibliography.q('@string')) unless bibliography.nil?
191
+ name.join
192
+ name = name.to_name
193
+ @fields[key] = name
194
+ end
195
+ end
196
+ self
197
+ end
198
+
148
199
  # Returns a string of all the entry's fields.
149
- def content
150
- @fields.keys.map { |k| "#{k} = #{ @fields[k].to_s(:quotes => %w({ })) }" }.join(",\n")
200
+ def content(options = {})
201
+ @fields.map { |k,v| "#{k} = #{ @fields[k].to_s(options) }" }.join(",\n")
151
202
  end
152
203
 
153
204
  # Returns a string representation of the entry.
154
- def to_s
155
- ["@#{type}{#{key},",content.gsub(/^/,' '),"}\n"].join("\n")
205
+ def to_s(options = {})
206
+ options[:quotes] ||= %w({ })
207
+ ["@#{type}{#{key},", content(options).gsub(/^/,' '), "}\n"].join("\n")
156
208
  end
157
209
 
158
- def to_hash(options={})
210
+ def to_hash(options = {})
159
211
  options[:quotes] ||= %w({ })
160
- @fields.keys.map { |k| { k.to_s => @fields[k].to_s(options) } }.inject({ 'key' => @key, 'type' => @type.to_s }) { |sum,n| sum.merge(n) }
212
+ Hash[*([:key, key, :type, type] + @fields.map { |k,v| [k, v.to_s(options)] }.flatten)]
213
+ end
214
+
215
+ def to_citeproc(options = {})
216
+ to_hash(options)
161
217
  end
162
218
 
163
- def to_xml
164
- xml = REXML::Element.new(@type.to_s)
165
- xml.attributes['key'] = @key
219
+ def to_xml(options = {})
220
+ require 'rexml/document'
221
+
222
+ xml = REXML::Element.new(type)
223
+ xml.attributes['key'] = key
166
224
  @fields.each do |k,v|
167
225
  e = REXML::Element.new(k.to_s)
168
- e.text = v.to_s
226
+ e.text = v.to_s(options)
169
227
  xml.add_element(e)
170
228
  end
171
229
  xml
172
230
  end
173
231
 
174
232
  def <=>(other)
175
- self.type != other.type ? self.type <=> other.type : self.key != other.key ? self.key <=> other.key : self.to_s <=> other.to_s
233
+ type != other.type ? type <=> other.type : key != other.key ? key <=> other.key : to_s <=> other.to_s
234
+ end
235
+
236
+ protected
237
+
238
+ def default_key
239
+ object_id.to_s.to_sym
176
240
  end
177
241
 
178
242
  end
@@ -18,43 +18,8 @@
18
18
 
19
19
  module BibTeX
20
20
 
21
- # This module contains functions to manipulate BibTeX string literals.
22
- # It is intended to be injected in an Array that represents either the
23
- # content of a BibTeX @string or an rvalue of a field in a BibTeX entry.
24
21
  module Extensions
25
-
26
- def self.string_replacement(obj)
27
- raise(ArgumentError, "StringReplacement should only be injected into instances of Array, not #{obj.class}.") unless obj.is_a?(::Array)
28
- class << obj; include ::BibTeX::Extensions::StringReplacement end
29
- obj
30
- end
31
-
32
- module StringReplacement
33
- # Returns a string representation of the literal.
34
- def to_s(options={})
35
- return '' if self.empty?
36
-
37
- options[:quotes] ||= [nil,nil]
38
-
39
- if self.length == 1 && !self[0].is_a?(::Symbol)
40
- [options[:quotes][0], self[0], options[:quotes][1]].join
41
- else
42
- self.map { |s| s.is_a?(::Symbol) ? s.to_s : %Q("#{ s }") }.join(' # ')
43
- end
44
- end
45
22
 
46
- # Replaces all string constants which are defined in +hash+.
47
- def replace_strings(hash)
48
- Extensions.string_replacement(self.map { |s| s.is_a?(::Symbol) && hash.has_key?(s) ? hash[s] : s }.flatten)
49
- end
50
-
51
- # Joins consecutive strings separated by '#'.
52
- def join_strings
53
- Extensions.string_replacement(self.inject([]) { |a,b|
54
- a << (a.last.is_a?(::String) && b.is_a?(::String) ? (a.pop + b) : b )
55
- })
56
- end
57
- end
58
23
  end
59
24
 
60
25
  end
@@ -1,6 +1,6 @@
1
1
  #--
2
2
  # BibTeX-Ruby
3
- # Copyright (C) 2010 Sylvester Keil <http://sylvester.keil.or.at>
3
+ # Copyright (C) 2010-2011 Sylvester Keil <http://sylvester.keil.or.at>
4
4
  #
5
5
  # This program is free software: you can redistribute it and/or modify
6
6
  # it under the terms of the GNU General Public License as published by
@@ -32,7 +32,7 @@ module BibTeX
32
32
  # Creates a new instance. Possible options and their respective
33
33
  # default values are:
34
34
  #
35
- # - :include => [:errors] A list that may contain :meta_comments, and
35
+ # - :include => [:errors] A list that may contain :meta_content, and
36
36
  # :errors; depending on whether or not these are present, the respective
37
37
  # tokens are included in the parse tree.
38
38
  # - :strict => true In strict mode objects can start anywhere; therefore
@@ -40,7 +40,7 @@ module BibTeX
40
40
  # objects; for a more lenient lexer set to false and objects are
41
41
  # expected to start after a new line (leading white space is permitted).
42
42
  #
43
- def initialize(options={})
43
+ def initialize(options = {})
44
44
  @options = options
45
45
  @options[:include] ||= [:errors]
46
46
  @options[:strict] = true unless @options.has_key?(:strict)
@@ -90,7 +90,7 @@ module BibTeX
90
90
  [:bibtex,:comment,:string,:preamble,:entry].include?(self.mode)
91
91
  end
92
92
 
93
- # Returns true if the lexer is currently parsing meta comments.
93
+ # Returns true if the lexer is currently parsing meta content.
94
94
  def meta_mode?
95
95
  self.mode == :meta
96
96
  end
@@ -119,8 +119,8 @@ module BibTeX
119
119
  when value[0] == :ERROR
120
120
  @stack.push(value) if @options[:include].include?(:errors)
121
121
  leave_object
122
- when value[0] == :META_COMMENT
123
- if @options[:include].include?(:meta_comments)
122
+ when value[0] == :META_CONTENT
123
+ if @options[:include].include?(:meta_content)
124
124
  value[1] = [value[1], line_number_at(@src.pos)]
125
125
  @stack.push(value)
126
126
  end
@@ -194,10 +194,10 @@ module BibTeX
194
194
  def parse_meta
195
195
  match = self.src.scan_until(@options[:strict] ? /@[\t ]*/o : /(^|\n)[\t ]*@[\t ]*/o)
196
196
  unless self.src.matched.nil?
197
- push [:META_COMMENT, match.chop]
197
+ push [:META_CONTENT, match.chop]
198
198
  enter_object
199
199
  else
200
- push [:META_COMMENT,self.src.rest]
200
+ push [:META_CONTENT,self.src.rest]
201
201
  self.src.terminate
202
202
  end
203
203
  end
@@ -318,7 +318,7 @@ module BibTeX
318
318
 
319
319
  def backtrace(error)
320
320
  trace = []
321
- trace.unshift(@stack.pop) until @stack.empty? || (!trace.empty? && [:AT,:META_COMMENT].include?(trace[0][0]))
321
+ trace.unshift(@stack.pop) until @stack.empty? || (!trace.empty? && [:AT,:META_CONTENT].include?(trace[0][0]))
322
322
  trace << error
323
323
  push [:ERROR,trace]
324
324
  end
@@ -0,0 +1,464 @@
1
+
2
+
3
+ -------- Grammar --------
4
+
5
+ rule 1 result:
6
+ rule 2 result: names
7
+ rule 3 names: name
8
+ rule 4 names: names AND name
9
+ rule 5 name: last
10
+ rule 6 name: u_words last
11
+ rule 7 name: sort COMMA first
12
+ rule 8 sort: u_words
13
+ rule 9 sort: LWORD
14
+ rule 10 sort: von LWORD
15
+ rule 11 sort: von u_words
16
+ rule 12 last: word
17
+ rule 13 last: von LWORD
18
+ rule 14 last: von u_words
19
+ rule 15 first: opt_words
20
+ rule 16 first: opt_words COMMA opt_words
21
+ rule 17 u_words: u_word
22
+ rule 18 u_words: u_words u_word
23
+ rule 19 u_word: UWORD
24
+ rule 20 u_word: PWORD
25
+ rule 21 von: LWORD
26
+ rule 22 von: von u_words LWORD
27
+ rule 23 von: von LWORD
28
+ rule 24 words: word
29
+ rule 25 words: words word
30
+ rule 26 opt_words:
31
+ rule 27 opt_words: words
32
+ rule 28 word: LWORD
33
+ rule 29 word: UWORD
34
+ rule 30 word: PWORD
35
+
36
+ ------- Symbols -------
37
+
38
+ **Nonterminals, with rules where they appear
39
+
40
+ $start (8)
41
+ on right:
42
+ on left :
43
+ result (9)
44
+ on right:
45
+ on left : 1 2
46
+ names (10)
47
+ on right: 2 4
48
+ on left : 3 4
49
+ name (11)
50
+ on right: 3 4
51
+ on left : 5 6 7
52
+ last (12)
53
+ on right: 5 6
54
+ on left : 12 13 14
55
+ u_words (13)
56
+ on right: 6 8 11 14 18 22
57
+ on left : 17 18
58
+ sort (14)
59
+ on right: 7
60
+ on left : 8 9 10 11
61
+ first (15)
62
+ on right: 7
63
+ on left : 15 16
64
+ von (16)
65
+ on right: 10 11 13 14 22 23
66
+ on left : 21 22 23
67
+ word (17)
68
+ on right: 12 24 25
69
+ on left : 28 29 30
70
+ opt_words (18)
71
+ on right: 15 16
72
+ on left : 26 27
73
+ u_word (19)
74
+ on right: 17 18
75
+ on left : 19 20
76
+ words (20)
77
+ on right: 25 27
78
+ on left : 24 25
79
+
80
+ **Terminals, with rules where they appear
81
+
82
+ $end (0)
83
+ error (1)
84
+ COMMA (2) 7 16
85
+ UWORD (3) 19 29
86
+ LWORD (4) 9 10 13 21 22 23 28
87
+ PWORD (5) 20 30
88
+ AND (6) 4
89
+ ERROR (7)
90
+
91
+ --------- State ---------
92
+
93
+ state 0
94
+
95
+
96
+ UWORD shift, and go to state 11
97
+ LWORD shift, and go to state 7
98
+ PWORD shift, and go to state 12
99
+ $default reduce using rule 1 (result)
100
+
101
+ result go to state 1
102
+ names go to state 2
103
+ name go to state 3
104
+ last go to state 4
105
+ u_words go to state 5
106
+ sort go to state 6
107
+ von go to state 8
108
+ word go to state 9
109
+ u_word go to state 10
110
+
111
+ state 1
112
+
113
+
114
+ $end shift, and go to state 13
115
+
116
+
117
+ state 2
118
+
119
+ 2) result : names _
120
+ 4) names : names _ AND name
121
+
122
+ AND shift, and go to state 14
123
+ $default reduce using rule 2 (result)
124
+
125
+
126
+ state 3
127
+
128
+ 3) names : name _
129
+
130
+ $default reduce using rule 3 (names)
131
+
132
+
133
+ state 4
134
+
135
+ 5) name : last _
136
+
137
+ $default reduce using rule 5 (name)
138
+
139
+
140
+ state 5
141
+
142
+ 6) name : u_words _ last
143
+ 8) sort : u_words _
144
+ 18) u_words : u_words _ u_word
145
+
146
+ UWORD shift, and go to state 11
147
+ LWORD shift, and go to state 18
148
+ PWORD shift, and go to state 12
149
+ $default reduce using rule 8 (sort)
150
+
151
+ last go to state 15
152
+ word go to state 9
153
+ von go to state 16
154
+ u_word go to state 17
155
+
156
+ state 6
157
+
158
+ 7) name : sort _ COMMA first
159
+
160
+ COMMA shift, and go to state 19
161
+
162
+
163
+ state 7
164
+
165
+ 9) sort : LWORD _
166
+ 21) von : LWORD _
167
+ 28) word : LWORD _
168
+
169
+ $end reduce using rule 28 (word)
170
+ COMMA reduce using rule 9 (sort)
171
+ AND reduce using rule 28 (word)
172
+ $default reduce using rule 21 (von)
173
+
174
+
175
+ state 8
176
+
177
+ 10) sort : von _ LWORD
178
+ 11) sort : von _ u_words
179
+ 13) last : von _ LWORD
180
+ 14) last : von _ u_words
181
+ 22) von : von _ u_words LWORD
182
+ 23) von : von _ LWORD
183
+
184
+ UWORD shift, and go to state 22
185
+ LWORD shift, and go to state 20
186
+ PWORD shift, and go to state 23
187
+
188
+ u_words go to state 21
189
+ u_word go to state 10
190
+
191
+ state 9
192
+
193
+ 12) last : word _
194
+
195
+ $default reduce using rule 12 (last)
196
+
197
+
198
+ state 10
199
+
200
+ 17) u_words : u_word _
201
+
202
+ $default reduce using rule 17 (u_words)
203
+
204
+
205
+ state 11
206
+
207
+ 19) u_word : UWORD _
208
+ 29) word : UWORD _
209
+
210
+ $end reduce using rule 29 (word)
211
+ AND reduce using rule 29 (word)
212
+ $default reduce using rule 19 (u_word)
213
+
214
+
215
+ state 12
216
+
217
+ 20) u_word : PWORD _
218
+ 30) word : PWORD _
219
+
220
+ $end reduce using rule 30 (word)
221
+ AND reduce using rule 30 (word)
222
+ $default reduce using rule 20 (u_word)
223
+
224
+
225
+ state 13
226
+
227
+
228
+ $end shift, and go to state 24
229
+
230
+
231
+ state 14
232
+
233
+ 4) names : names AND _ name
234
+
235
+ UWORD shift, and go to state 11
236
+ LWORD shift, and go to state 7
237
+ PWORD shift, and go to state 12
238
+
239
+ name go to state 25
240
+ last go to state 4
241
+ u_words go to state 5
242
+ sort go to state 6
243
+ von go to state 8
244
+ word go to state 9
245
+ u_word go to state 10
246
+
247
+ state 15
248
+
249
+ 6) name : u_words last _
250
+
251
+ $default reduce using rule 6 (name)
252
+
253
+
254
+ state 16
255
+
256
+ 13) last : von _ LWORD
257
+ 14) last : von _ u_words
258
+ 22) von : von _ u_words LWORD
259
+ 23) von : von _ LWORD
260
+
261
+ UWORD shift, and go to state 22
262
+ LWORD shift, and go to state 26
263
+ PWORD shift, and go to state 23
264
+
265
+ u_words go to state 27
266
+ u_word go to state 10
267
+
268
+ state 17
269
+
270
+ 18) u_words : u_words u_word _
271
+
272
+ $default reduce using rule 18 (u_words)
273
+
274
+
275
+ state 18
276
+
277
+ 21) von : LWORD _
278
+ 28) word : LWORD _
279
+
280
+ $end reduce using rule 28 (word)
281
+ AND reduce using rule 28 (word)
282
+ $default reduce using rule 21 (von)
283
+
284
+
285
+ state 19
286
+
287
+ 7) name : sort COMMA _ first
288
+
289
+ UWORD shift, and go to state 33
290
+ LWORD shift, and go to state 32
291
+ PWORD shift, and go to state 34
292
+ $default reduce using rule 26 (opt_words)
293
+
294
+ first go to state 28
295
+ opt_words go to state 29
296
+ word go to state 30
297
+ words go to state 31
298
+
299
+ state 20
300
+
301
+ 10) sort : von LWORD _
302
+ 13) last : von LWORD _
303
+ 23) von : von LWORD _
304
+
305
+ $end reduce using rule 13 (last)
306
+ COMMA reduce using rule 10 (sort)
307
+ AND reduce using rule 13 (last)
308
+ $default reduce using rule 23 (von)
309
+
310
+
311
+ state 21
312
+
313
+ 11) sort : von u_words _
314
+ 14) last : von u_words _
315
+ 18) u_words : u_words _ u_word
316
+ 22) von : von u_words _ LWORD
317
+
318
+ UWORD shift, and go to state 22
319
+ LWORD shift, and go to state 35
320
+ PWORD shift, and go to state 23
321
+ COMMA reduce using rule 11 (sort)
322
+ $default reduce using rule 14 (last)
323
+
324
+ u_word go to state 17
325
+
326
+ state 22
327
+
328
+ 19) u_word : UWORD _
329
+
330
+ $default reduce using rule 19 (u_word)
331
+
332
+
333
+ state 23
334
+
335
+ 20) u_word : PWORD _
336
+
337
+ $default reduce using rule 20 (u_word)
338
+
339
+
340
+ state 24
341
+
342
+
343
+ $default accept
344
+
345
+
346
+ state 25
347
+
348
+ 4) names : names AND name _
349
+
350
+ $default reduce using rule 4 (names)
351
+
352
+
353
+ state 26
354
+
355
+ 13) last : von LWORD _
356
+ 23) von : von LWORD _
357
+
358
+ $end reduce using rule 13 (last)
359
+ AND reduce using rule 13 (last)
360
+ $default reduce using rule 23 (von)
361
+
362
+
363
+ state 27
364
+
365
+ 14) last : von u_words _
366
+ 18) u_words : u_words _ u_word
367
+ 22) von : von u_words _ LWORD
368
+
369
+ UWORD shift, and go to state 22
370
+ LWORD shift, and go to state 35
371
+ PWORD shift, and go to state 23
372
+ $default reduce using rule 14 (last)
373
+
374
+ u_word go to state 17
375
+
376
+ state 28
377
+
378
+ 7) name : sort COMMA first _
379
+
380
+ $default reduce using rule 7 (name)
381
+
382
+
383
+ state 29
384
+
385
+ 15) first : opt_words _
386
+ 16) first : opt_words _ COMMA opt_words
387
+
388
+ COMMA shift, and go to state 36
389
+ $default reduce using rule 15 (first)
390
+
391
+
392
+ state 30
393
+
394
+ 24) words : word _
395
+
396
+ $default reduce using rule 24 (words)
397
+
398
+
399
+ state 31
400
+
401
+ 25) words : words _ word
402
+ 27) opt_words : words _
403
+
404
+ UWORD shift, and go to state 33
405
+ LWORD shift, and go to state 32
406
+ PWORD shift, and go to state 34
407
+ $default reduce using rule 27 (opt_words)
408
+
409
+ word go to state 37
410
+
411
+ state 32
412
+
413
+ 28) word : LWORD _
414
+
415
+ $default reduce using rule 28 (word)
416
+
417
+
418
+ state 33
419
+
420
+ 29) word : UWORD _
421
+
422
+ $default reduce using rule 29 (word)
423
+
424
+
425
+ state 34
426
+
427
+ 30) word : PWORD _
428
+
429
+ $default reduce using rule 30 (word)
430
+
431
+
432
+ state 35
433
+
434
+ 22) von : von u_words LWORD _
435
+
436
+ $default reduce using rule 22 (von)
437
+
438
+
439
+ state 36
440
+
441
+ 16) first : opt_words COMMA _ opt_words
442
+
443
+ UWORD shift, and go to state 33
444
+ LWORD shift, and go to state 32
445
+ PWORD shift, and go to state 34
446
+ $default reduce using rule 26 (opt_words)
447
+
448
+ opt_words go to state 38
449
+ word go to state 30
450
+ words go to state 31
451
+
452
+ state 37
453
+
454
+ 25) words : words word _
455
+
456
+ $default reduce using rule 25 (words)
457
+
458
+
459
+ state 38
460
+
461
+ 16) first : opt_words COMMA opt_words _
462
+
463
+ $default reduce using rule 16 (first)
464
+