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.
- data/Gemfile +6 -1
- data/Gemfile.lock +48 -5
- data/History.txt +16 -1
- data/Manifest +43 -19
- data/README.md +178 -167
- data/Rakefile +26 -5
- data/auto.watchr +6 -0
- data/bibtex-ruby.gemspec +8 -5
- data/examples/bib2html.rb +28 -18
- data/features/bibtex.feature +96 -0
- data/features/entries.feature +67 -0
- data/features/issues/slash_keys.feature +21 -0
- data/features/names.feature +72 -0
- data/features/preambles.feature +27 -0
- data/features/query.feature +56 -0
- data/features/replacement.feature +68 -0
- data/features/step_definitions/bibtex_steps.rb +74 -0
- data/features/step_definitions/name_steps.rb +13 -0
- data/features/strings.feature +52 -0
- data/features/support/env.rb +7 -0
- data/lib/bibtex.rb +5 -1
- data/lib/bibtex/bibliography.rb +218 -95
- data/lib/bibtex/bibtex.y +18 -15
- data/lib/bibtex/elements.rb +130 -136
- data/lib/bibtex/entry.rb +133 -69
- data/lib/bibtex/extensions.rb +0 -35
- data/lib/bibtex/lexer.rb +9 -9
- data/lib/bibtex/name_parser.output +464 -0
- data/lib/bibtex/name_parser.rb +490 -0
- data/lib/bibtex/names.rb +162 -0
- data/lib/bibtex/names.y +196 -0
- data/lib/bibtex/parser.output +5 -5
- data/lib/bibtex/parser.rb +19 -16
- data/lib/bibtex/replaceable.rb +52 -0
- data/lib/bibtex/utilities.rb +23 -5
- data/lib/bibtex/value.rb +201 -0
- data/lib/bibtex/version.rb +1 -1
- data/test/benchmark.rb +52 -0
- data/test/bibtex/test_bibliography.rb +141 -0
- data/test/bibtex/test_elements.rb +40 -0
- data/test/bibtex/test_entry.rb +99 -0
- data/test/bibtex/test_names.rb +23 -0
- data/test/bibtex/test_parser.rb +79 -0
- data/test/bibtex/test_string.rb +83 -0
- data/test/bibtex/test_utilities.rb +34 -0
- data/test/bibtex/test_value.rb +70 -0
- data/test/{bib/10_bibdesk.bib → fixtures/bibdesk.bib} +1 -1
- data/test/{bib/05_comment.bib → fixtures/comment.bib} +0 -0
- data/test/{bib/08_decoret.bib → fixtures/decoret.bib} +0 -0
- data/test/{bib/00_empty.bib → fixtures/empty.bib} +0 -0
- data/test/{bib/07_entry.bib → fixtures/entry.bib} +0 -0
- data/test/{bib/09_errors.bib → fixtures/errors.bib} +0 -0
- data/test/{bib/01_no_bibtex.bib → fixtures/no_bibtex.bib} +0 -0
- data/test/{bib/06_preamble.bib → fixtures/preamble.bib} +1 -1
- data/test/{bib/11_roundtrip.bib → fixtures/roundtrip.bib} +1 -1
- data/test/helper.rb +17 -2
- data/test/test_bibtex.rb +87 -93
- data/test/test_export.rb +18 -22
- metadata +85 -30
- data/test/bib/02_string.bib +0 -1
- data/test/bib/03_string.bib +0 -25
- data/test/bib/04_string_replacement.bib +0 -16
- data/test/test_comment.rb +0 -21
- data/test/test_entry.rb +0 -98
- data/test/test_preamble.rb +0 -39
- data/test/test_string.rb +0 -97
- data/test/test_utilities.rb +0 -36
data/lib/bibtex/entry.rb
CHANGED
@@ -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
|
-
|
26
|
-
|
26
|
+
extend Forwardable
|
27
|
+
include Enumerable
|
28
|
+
|
27
29
|
# Hash containing the required fields of the standard entry types
|
28
|
-
|
29
|
-
|
30
|
-
:
|
31
|
-
:
|
32
|
-
:
|
33
|
-
:
|
34
|
-
:
|
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
|
38
|
+
:manual => [:title],
|
38
39
|
:mastersthesis => [:author,:title,:school,:year],
|
39
|
-
:misc
|
40
|
-
:phdthesis
|
41
|
-
:proceedings
|
42
|
-
:techreport
|
43
|
-
:unpublished
|
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(
|
53
|
+
def initialize(attributes = {})
|
48
54
|
@fields = {}
|
49
55
|
|
50
|
-
self.type =
|
51
|
-
self.key =
|
52
|
-
|
53
|
-
|
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, "
|
61
|
-
|
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, "
|
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]
|
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
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
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
|
-
|
155
|
+
REQUIRED_FIELDS[@type].all? do |f|
|
121
156
|
f.is_a?(Array) ? !(f & @fields.keys).empty? : !@fields[f].nil?
|
122
|
-
|
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
|
128
|
-
bibliography.entries[
|
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
|
135
|
-
bibliography.entries[
|
169
|
+
super
|
170
|
+
bibliography.entries[key] = nil
|
136
171
|
self
|
137
172
|
end
|
138
173
|
|
139
|
-
|
140
|
-
|
141
|
-
@fields.
|
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.
|
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.
|
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
|
-
|
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
|
-
|
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
|
-
|
165
|
-
|
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
|
-
|
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
|
data/lib/bibtex/extensions.rb
CHANGED
@@ -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
|
data/lib/bibtex/lexer.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
#--
|
2
2
|
# BibTeX-Ruby
|
3
|
-
# Copyright (C) 2010
|
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 :
|
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
|
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] == :
|
123
|
-
if @options[:include].include?(:
|
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 [:
|
197
|
+
push [:META_CONTENT, match.chop]
|
198
198
|
enter_object
|
199
199
|
else
|
200
|
-
push [:
|
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,:
|
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
|
+
|