bibtex-ruby 1.2.1 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
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
|
+
|