rltk 2.2.0 → 2.2.1

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -312,28 +312,29 @@ Calls to {RLTK::Parser.parse} may raise one of four exceptions:
312
312
 
313
313
  **Warning: this is the lest tested feature of RLTK. If you encounter any problems while using it, please let me know so I can fix any bugs as soon as possible.**
314
314
 
315
- When an RLTK parser encounters a token for which there are no more valid actions (and it is on the last parse stack / possible parse-tree path) it will enter error handling mode. In this mode the parser pops states and input off of the parse stack (the parser is a pushdown automaton after all) until it finds a state that has a shift action for the `ERROR` terminal. A dummy `ERROR` terminal is then placed onto the parse stack and the shift action is taken. This error token will have the position information of the token that caused the parser to enter error handling mode.
315
+ When an RLTK parser encounters a token for which there are no more valid actions (and it is on the last parse stack / possible parse-tree path) it will enter error handling mode. In this mode the parser pops states and input off of the parse stack (the parser is a pushdown automaton after all) until it finds a state that has a shift action for the `ERROR` terminal. A dummy `ERROR` terminal is then placed onto the parse stack and the shift action is taken. This error token will have the position information of the token that caused the parser to enter error handling mode. Additional tokens may have been discarded after this token.
316
316
 
317
- If the input (including the `ERROR` token) can be reduced immediately the associated error handling proc is evaluated and we continue parsing. If the parser can't immediately reduce it will begin shifting tokens onto the input stack. This may cause the parser to enter a state in which it again has no valid actions for an input. When this happens it enters error handling mode again and pops states and input off of the stack until it reaches an error state again. In this way it searches for the first substring after the error occurred for which it can resume parsing.
317
+ If the input (including the `ERROR` token) can be reduced immediately the associated error handling proc is evaluated and we continue parsing. If no shift or reduce action is available the parser will being shifting tokens off of the input stack until a token appears with a valid action in the current state, in which case parsing resumes as normal.
318
318
 
319
- The example below for the unit tests shows a very basic usage of error productions:
319
+ The value of an `ERROR` non-terminal will be an array containing all of the tokens that were discarded while the parser was searching for a valid action.
320
320
 
321
- class AfterPlsError < StandardError; end
322
- class AfterSubError < StandardError; end
321
+ The example below, based on one of the unit tests, shows a very basic usage of error productions:
323
322
 
324
323
  class ErrorCalc < RLTK::Parser
324
+ left :ERROR
325
+ right :PLS, :SUB, :MUL, :DIV, :NUM
326
+
325
327
  production(:e) do
326
- clause('NUM') { |n| n }
327
-
328
+ clause('NUM') {|n| n}
329
+
328
330
  clause('e PLS e') { |e0, _, e1| e0 + e1 }
329
331
  clause('e SUB e') { |e0, _, e1| e0 - e1 }
330
332
  clause('e MUL e') { |e0, _, e1| e0 * e1 }
331
333
  clause('e DIV e') { |e0, _, e1| e0 / e1 }
332
-
333
- clause('e PLS ERROR') { |_, _, _| raise AfterPlsError }
334
- clause('e SUB ERROR') { |_, _, _| raise AfterSubError }
335
- end
336
334
 
335
+ clause('e PLS ERROR e') { |e0, _, err, e1| error("#{err.len} tokens skipped."); e0 + e1 }
336
+ end
337
+
337
338
  finalize
338
339
  end
339
340
 
@@ -835,6 +835,13 @@ module RLTK # :nodoc:
835
835
  # If we are already in error mode and there
836
836
  # are no actions we skip this token.
837
837
  if error_mode
838
+ v.puts("Discarding token: #{token.type}#{if token.value then "(#{token.value})" end}") if v
839
+
840
+ # Add the current token to the array
841
+ # that corresponds to the output value
842
+ # for the ERROR token.
843
+ stack.output_stack.last << token
844
+
838
845
  moving_on << stack
839
846
  next
840
847
  end
@@ -842,6 +849,16 @@ module RLTK # :nodoc:
842
849
  # We would be dropping the last stack so we
843
850
  # are going to go into error mode.
844
851
  if accepted.empty? and moving_on.empty? and processing.empty?
852
+
853
+ if v
854
+ v.puts
855
+ v.puts('Current stack:')
856
+ v.puts("\tID: #{stack.id}")
857
+ v.puts("\tState stack:\t#{stack.state_stack.inspect}")
858
+ v.puts("\tOutput Stack:\t#{stack.output_stack.inspect}")
859
+ v.puts
860
+ end
861
+
845
862
  # Try and find a valid error state.
846
863
  while stack.state
847
864
  if (actions = @states[stack.state].on?(:ERROR)).empty?
@@ -850,7 +867,7 @@ module RLTK # :nodoc:
850
867
  stack.pop
851
868
  else
852
869
  # Enter the found error state.
853
- stack.push(actions.first.id, nil, :ERROR, token.position)
870
+ stack.push(actions.first.id, [token], :ERROR, token.position)
854
871
 
855
872
  break
856
873
  end
@@ -860,9 +877,12 @@ module RLTK # :nodoc:
860
877
  # We found a valid error state.
861
878
  error_mode = reduction_guard = true
862
879
  opts[:env].he = true
863
- processing << stack
880
+ moving_on << stack
864
881
 
865
- v.puts('Invalid input encountered. Entering error handling mode.') if v
882
+ if v
883
+ v.puts('Invalid input encountered. Entering error handling mode.')
884
+ v.puts("Discarding token: #{token.type}#{if token.value then "(#{token.value})" end}")
885
+ end
866
886
  else
867
887
  # No valid error states could be
868
888
  # found. Time to print a message
@@ -5,7 +5,7 @@
5
5
 
6
6
  module RLTK # :nodoc:
7
7
  # The version number of the RLTK library.
8
- VERSION = '2.2.0'
8
+ VERSION = '2.2.1'
9
9
  # The version of LLVM targeted by RLTK.
10
10
  LLVM_TARGET_VERSION = '3.0'
11
11
  end
@@ -127,6 +127,9 @@ class ParserTester < Test::Unit::TestCase
127
127
  class DummyError2 < StandardError; end
128
128
 
129
129
  class ErrorCalc < RLTK::Parser
130
+ left :ERROR
131
+ right :PLS, :SUB, :MUL, :DIV, :NUM
132
+
130
133
  production(:e) do
131
134
  clause('NUM') {|n| n}
132
135
 
@@ -135,8 +138,7 @@ class ParserTester < Test::Unit::TestCase
135
138
  clause('e MUL e') { |e0, _, e1| e0 * e1 }
136
139
  clause('e DIV e') { |e0, _, e1| e0 / e1 }
137
140
 
138
- clause('e PLS ERROR') { |_, _, _| raise DummyError1 }
139
- clause('e SUB ERROR') { |_, _, _| raise DummyError2 }
141
+ clause('e PLS ERROR e') { |e0, _, ts, e1| error(ts); e0 + e1 }
140
142
  end
141
143
 
142
144
  finalize
@@ -159,7 +161,7 @@ class ParserTester < Test::Unit::TestCase
159
161
  clause('NEWLINE') { |_| nil }
160
162
 
161
163
  clause('WORD+ SEMI NEWLINE') { |w, _, _| w }
162
- clause('WORD+ ERROR NEWLINE') { |w, e, _| error(pos(1).line_number); w }
164
+ clause('WORD+ ERROR') { |w, e| error(pos(1).line_number); w }
163
165
  end
164
166
 
165
167
  finalize
@@ -277,8 +279,8 @@ class ParserTester < Test::Unit::TestCase
277
279
  end
278
280
 
279
281
  def test_error_productions
280
- assert_raise(DummyError1) { ErrorCalc.parse(RLTK::Lexers::Calculator.lex('1 + +')) }
281
- assert_raise(DummyError2) { ErrorCalc.parse(RLTK::Lexers::Calculator.lex('1 - +')) }
282
+
283
+ # Test to see if error reporting is working correctly.
282
284
 
283
285
  test_string = "first line;\n"
284
286
  test_string += "second line\n"
@@ -289,8 +291,30 @@ class ParserTester < Test::Unit::TestCase
289
291
 
290
292
  begin
291
293
  ErrorLine.parse(ELLexer.lex(test_string))
294
+
295
+ rescue RLTK::HandledError => e
296
+ assert_equal([2,4], e.errors)
297
+ end
298
+
299
+ # Test to see if we can continue parsing after errors are encounterd.
300
+
301
+ begin
302
+ ErrorCalc.parse(RLTK::Lexers::Calculator.lex('1 + + 1'))
303
+
304
+ rescue RLTK::HandledError => e
305
+ assert_equal(1, e.errors.first.length)
306
+ assert_equal(2, e.result)
307
+ end
308
+
309
+ # Test to see if we pop tokens correctly after an error is
310
+ # encountered.
311
+
312
+ begin
313
+ ErrorCalc.parse(RLTK::Lexers::Calculator.lex('1 + + + + + + 1'))
314
+
292
315
  rescue RLTK::HandledError => e
293
- assert_equal(e.errors, [2,4])
316
+ assert_equal(5, e.errors.first.length)
317
+ assert_equal(2, e.result)
294
318
  end
295
319
  end
296
320
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rltk
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.2.0
4
+ version: 2.2.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-08-09 00:00:00.000000000 Z
12
+ date: 2012-09-01 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: ffi