Class: BibTeX::Lexer

Inherits:
Object
  • Object
show all
Extended by:
Forwardable
Defined in:
lib/bibtex/lexer.rb

Overview

The BibTeX::Lexer handles the lexical analysis of BibTeX bibliographies.

Constant Summary collapse

MODE =
Hash.new(:meta).merge({
  :bibtex  => :bibtex,  :entry    => :bibtex,
  :string  => :bibtex,  :preamble => :bibtex,
  :comment => :bibtex,  :meta     => :meta,
  :literal => :literal, :content  => :content
}).freeze

Class Attribute Summary collapse

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options = {}) ⇒ Lexer

Creates a new instance. Possible options and their respective default values are:

  • :include => [:errors] A list that may contain :meta_content, and :errors; depending on whether or not these are present, the respective tokens are included in the parse tree.

  • :strict => true In strict mode objects can start anywhere; therefore the ‘@’ symbol is not possible except inside literals or @comment objects; for a more lenient lexer set to false and objects are expected to start after a new line (leading white space is permitted).

  • :strip => true When enabled, newlines will be stripped from quoted string values.



65
66
67
68
# File 'lib/bibtex/lexer.rb', line 65

def initialize(options = {})
  @options = Lexer.defaults.merge(options)
  reset
end

Class Attribute Details

.defaultsObject

Returns the value of attribute defaults.



48
49
50
# File 'lib/bibtex/lexer.rb', line 48

def defaults
  @defaults
end

Instance Attribute Details

#modeObject

Returns the value of attribute mode.



29
30
31
# File 'lib/bibtex/lexer.rb', line 29

def mode
  @mode
end

#optionsObject (readonly)

Returns the value of attribute options.



29
30
31
# File 'lib/bibtex/lexer.rb', line 29

def options
  @options
end

#scannerObject (readonly)

Returns the value of attribute scanner.



29
30
31
# File 'lib/bibtex/lexer.rb', line 29

def scanner
  @scanner
end

#stackObject (readonly)

Returns the value of attribute stack.



29
30
31
# File 'lib/bibtex/lexer.rb', line 29

def stack
  @stack
end

Instance Method Details

#active?(object) ⇒ Boolean

Returns true if the lexer is currently parsing the given object type.

Returns:

  • (Boolean)


102
103
104
# File 'lib/bibtex/lexer.rb', line 102

def active?(object)
  @active_object == object
end

#analyse(string = nil) ⇒ Object

Start the lexical analysis.

Raises:



137
138
139
140
141
142
143
144
145
146
147
148
# File 'lib/bibtex/lexer.rb', line 137

def analyse(string = nil)
  raise(ArgumentError, 'Lexer: failed to start analysis: no source given!') unless
    string || @scanner    

  self.data = string || @scanner.string
  
  until @scanner.eos?
    send("parse_#{MODE[@mode]}")
  end

  push([false, '$end'])
end

#bibtex_mode?Boolean

Returns true if the lexer is currenty parsing a BibTeX object.

Returns:

  • (Boolean)


93
94
95
# File 'lib/bibtex/lexer.rb', line 93

def bibtex_mode?
  MODE[@mode] == :bibtex
end

#data=(data) ⇒ Object

Sets the source for the lexical analysis and resets the internal state.



82
83
84
85
# File 'lib/bibtex/lexer.rb', line 82

def data=(data)
  @scanner = StringScanner.new(data)
  reset
end

#next_tokenObject

Returns the next token from the parse stack.



90
# File 'lib/bibtex/lexer.rb', line 90

def next_token; @stack.shift; end

#push(value) ⇒ Object

Pushes a value onto the parse stack. Returns the Lexer.



114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
# File 'lib/bibtex/lexer.rb', line 114

def push(value)
  case value[0]
  when :CONTENT, :STRING_LITERAL
    value[1].gsub!(/\n\s*/, ' ') if strip_line_breaks?
    
    if !@stack.empty? && value[0] == @stack[-1][0]
      @stack[-1][1] << value[1]
    else
      @stack.push(value)
    end
  when :ERROR
    @stack.push(value) if @include_errors
    leave_object
  when :META_CONTENT        
    @stack.push(value) if @include_meta_content
  else
    @stack.push(value)
  end
        
  self
end

#resetObject



70
71
72
73
74
75
76
77
78
79
# File 'lib/bibtex/lexer.rb', line 70

def reset
  @stack, @brace_level, @mode, @active_object = [], 0, :meta, nil
  @scanner.reset if @scanner
  
  # cache options for speed
  @include_meta_content = @options[:include].include?(:meta_content)
  @include_errors = @options[:include].include?(:errors)
  
  self
end

#strict?Boolean

Returns true if the lexer is currently in strict mode.

Returns:

  • (Boolean)


107
# File 'lib/bibtex/lexer.rb', line 107

def strict?; !!(@options[:strict]); end

#strip_line_breaks?Boolean

Returns:

  • (Boolean)


109
110
111
# File 'lib/bibtex/lexer.rb', line 109

def strip_line_breaks?
  !!options[:strip] && !active?(:comment)
end

#symbolsObject



87
# File 'lib/bibtex/lexer.rb', line 87

def symbols; @stack.map(&:first); end