Skip to content

Instantly share code, notes, and snippets.

@spundun
Last active August 29, 2015 14:07
Show Gist options
  • Save spundun/92ce4524c9fae95a944e to your computer and use it in GitHub Desktop.
Save spundun/92ce4524c9fae95a944e to your computer and use it in GitHub Desktop.
Ruby Treetop gem Parser Rules: Potential Bug

Trying to follow the tutorial from http://thingsaaronmade.com/blog/a-quick-intro-to-writing-a-parser-using-treetop.html

I get the following error.

spundun$ bundle exec pry
[1] pry(main)> require './parser'
=> true
[2] pry(main)> Parser.parse('(this "is" a test( 1 2.0 3))')
Exception: Parse error at offset: 0
from /Users/spundun/Documents/code_samples/s_expression_parser/parser.rb:35:in `parse'
[3] pry(main)> 

The error goes away if I move the body rule in sexp_parser.treetop from the bottom to the top. (Making it the first rule).

spundun$ bundle exec pry
[1] pry(main)> require './parser'
=> true
[2] pry(main)> Parser.parse('(this "is" a test( 1 2.0 3))')
=> [[:this, "is", :a, :test, [1, 2.0, 3]]]
[3] pry(main)> quit

gem 'treetop'
gem 'pry'
GEM
specs:
coderay (1.1.0)
method_source (0.8.2)
polyglot (0.3.5)
pry (0.10.1)
coderay (~> 1.1.0)
method_source (~> 0.8.1)
slop (~> 3.4)
slop (3.6.0)
treetop (1.5.3)
polyglot (~> 0.3)
PLATFORMS
ruby
DEPENDENCIES
pry
treetop
# In file node_extensions.rb
module Sexp
class IntegerLiteral < Treetop::Runtime::SyntaxNode
def to_array
return self.text_value.to_i
end
end
class StringLiteral < Treetop::Runtime::SyntaxNode
def to_array
return eval self.text_value
end
end
class FloatLiteral < Treetop::Runtime::SyntaxNode
def to_array
return self.text_value.to_f
end
end
class Identifier < Treetop::Runtime::SyntaxNode
def to_array
return self.text_value.to_sym
end
end
class Expression < Treetop::Runtime::SyntaxNode
def to_array
return self.elements[0].to_array
end
end
class Body < Treetop::Runtime::SyntaxNode
def to_array
return self.elements.map {|x| x.to_array}
end
end
end
# In file parser.rb
require 'treetop'
# Find out what our base path is
base_path = File.expand_path(File.dirname(__FILE__))
# Load our custom syntax node classes so the parser can use them
require File.join(base_path, 'node_extensions.rb')
class Parser
# Load the Treetop grammar from the 'sexp_parser' file, and
# create a new instance of that parser as a class variable
# so we don't have to re-create it every time we need to
# parse a string
# Spundun: Had to add the following line. It seems like the base_path
# variable initialized above goes out of scope here, I wonder why
# This error was there in the code I pasted from
# http://thingsaaronmade.com/blog/a-quick-intro-to-writing-a-parser-using-treetop.html
# Maybe ruby version issue?
# Find out what our base path is
base_path = File.expand_path(File.dirname(__FILE__))
Treetop.load(File.join(base_path, 'sexp_parser.treetop'))
@@parser = SexpParser.new
def self.parse(data)
# Pass the data over to the parser instance
tree = @@parser.parse(data)
# If the AST is nil then there was an error during parsing
# we need to report a simple error message to help the user
if(tree.nil?)
raise Exception, "Parse error at offset: #{@@parser.index}"
end
self.clean_tree(tree)
return tree.to_array
end
private
def self.clean_tree(root_node)
return if(root_node.elements.nil?)
root_node.elements.delete_if{|node| node.class.name == "Treetop::Runtime::SyntaxNode" }
root_node.elements.each {|node| self.clean_tree(node) }
end
end
# In file sexp_extensions.rb
grammar Sexp
rule integer
('+' / '-')? [0-9]+ <IntegerLiteral>
end
rule float
('+' / '-')? [0-9]+ (('.' [0-9]+) / ('e' [0-9]+)) <FloatLiteral>
end
rule string
'"' ([^"\\] / "\\" . )* '"' <StringLiteral>
end
rule identifier
[a-zA-Z\=\*] [a-zA-Z0-9_\=\*]* <Identifier>
end
rule space
[\s]+
end
rule expression
space? '(' body ')' space? <Expression>
end
rule body
(expression / identifier / float / integer / string / space )* <Body>
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment