Skip to content

Instantly share code, notes, and snippets.

@lnznt
Created April 29, 2012 04:22
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lnznt/2533003 to your computer and use it in GitHub Desktop.
Save lnznt/2533003 to your computer and use it in GitHub Desktop.
sample: 'hello world' parser (Ruby/Racc)
# -*- coding : UTF-8 -*-
#
# to generate 'hello_parser.rb'
#
# $ racc -o hello_parser.rb hello_parser.ry
#
# to execute
#
# $ ruby hello_parser.rb <<EOT
# hello world #=> OK(1)
# EOT
#
# $ ruby hello_parser.rb <<EOT
# Hello, World #=> OK(2)
# EOT
#
# $ ruby hello_parser.rb <<EOT
# Hello: World # Racc::ParseError
# EOT
#
class HelloParser
rule
message : HELLO WORLD EOL { puts "OK(1)" ; result = val.join }
| HELLO ',' WORLD EOL { puts "OK(2)" ; result = val.join }
end
---- header
require 'strscan'
---- inner
attr_accessor :yydebug
def parse(text)
s = StringScanner.new text
tokens = []
case
when s.scan(/hello\b/i) ; tokens << [:HELLO, s.matched]
when s.scan(/world\b/i) ; tokens << [:WORLD, s.matched]
when s.scan(/\n/) ; tokens << [:EOL, s.matched]
when s.scan(/\s/) ; # ignore white space
when s.scan(/./m) ; tokens << [s.matched, s.matched]
end until s.eos?
define_singleton_method(:next_token) { tokens.shift }
do_parse
end
---- footer
if __FILE__ == $0
require 'optparse'
parser = HelloParser.new
ARGV.options do |opt|
opt.on('-d', '--debug') { parser.yydebug = true }
opt.parse!
end
parser.parse ARGF.read
end
# vi:set ts=2 sw=2 et:
# -*- coding : UTF-8 -*-
#
# to generate 'hello_parser2.rb'
#
# $ racc -o hello_parser2.rb hello_parser2.ry
#
# to execute
#
# $ ruby hello_parser2.rb <<EOT
# hello world #=> OK(1)
# EOT
#
# $ ruby hello_parser2.rb <<EOT
# Hello, World #=> OK(2)
# EOT
#
# $ ruby hello_parser2.rb <<EOT
# Hello: World # Racc::ParseError
# EOT
#
class HelloParser
rule
message :
| message helloworld { result = val.join }
helloworld : HELLO WORLD EOL { puts "OK(1)" ; result = val.join }
| HELLO ',' WORLD EOL { puts "OK(2)" ; result = val.join }
end
---- header
require 'strscan'
---- inner
attr_accessor :yydebug
def parse(text="", &source)
@source = source || proc {}
@s = StringScanner.new text
do_parse
end
class SkipToken < RuntimeError ; end
def next_token
@s << (@source.call or raise EOFError) if @s.eos?
case
when @s.scan(/hello\b/i) ; [:HELLO, @s.matched]
when @s.scan(/world\b/i) ; [:WORLD, @s.matched]
when @s.scan(/\n/) ; [:EOL, @s.matched]
when @s.scan(/\s/) ; raise SkipToken
when @s.scan(/./m) ; [@s.matched, @s.matched]
end
rescue SkipToken
retry
rescue EOFError
nil
end
---- footer
if __FILE__ == $0
require 'optparse'
parser = HelloParser.new
ARGV.options do |opt|
opt.on('-d', '--debug') { parser.yydebug = true }
opt.parse!
end
parser.parse { ARGF.gets }
end
# vi:set ts=2 sw=2 et:
#!/usr/bin/make -f
# -*- coding: UTF-8 -*-
#
# to generate 'foo.rb' from 'foo.ry'
#
# ex.1) $ make foo.rb
#
# ex.2) $ make FLAGS=-C foo.rb # syntax check only
#
# see also 'racc --help'
RACCFLAGS += --debug # -t
#RACCFLAGS += --verbose # -v
#RACCFLAGS += --log-file=filename # -Ofilename
#RACCFLAGS += --execute=ruby # -erubypath
#RACCFLAGS += --embedded # -E
#RACCFLAGS += --line-convert-all
#RACCFLAGS += --no-line-convert # -l
#RACCFLAGS += --no-omit-actions # -a
#RACCFLAGS += --superclass=CLASSNAME
#RACCFLAGS += --runtime=FEATURE
#RACCFLAGS += --check-only # -C
#RACCFLAGS += --output-status # -S
#RACCFLAGS += --output-status # -S
#RACCFLAGS += -P
RACCFLAGS += ${FLAGS}
%.rb: %.ry
racc ${RACCFLAGS} -o $@ $<
.PHONY : all
#
# to generate 'hello_parser.rb'
#
# ex.1) $ make
#
# ex.2) $ make FLAGS=-C # syntax check only
#
all : hello_parser.rb
# vi:set ts=4 sw=4:
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment