Skip to content

Instantly share code, notes, and snippets.

@kei-p
Created March 28, 2016 08:52
Show Gist options
  • Save kei-p/c10e06c4e5a4634c37dc to your computer and use it in GitHub Desktop.
Save kei-p/c10e06c4e5a4634c37dc to your computer and use it in GitHub Desktop.
Racc Samples
class JsonParser
options no_result_var
rule
json_text : ws object ws
{ val[1] }
| ws array ws
{ val[1] }
ws :
| ws SPACE
value : FALSE
| NULL
| TRUE
| object
| array
| number
| STRING
number : INTEGER
{ val[0].to_i }
| FLOAT
{ val[0].to_f }
object : '{' ws '}'
{ {} }
| '{' ws members ws '}'
{ val[2].to_h }
members : member
{ [ val[0] ] }
| members ws ',' ws member
{ val[0] << val[4] }
member : STRING ws ':' ws value
{ [ val[0], val[4] ] }
array : '[' ws ']'
{ [] }
| '[' ws values ws ']'
{ val[2] }
values : value
{ [ val[0] ] }
| values ws ',' ws value
{ val[0] << val[4] }
end
---- header
require 'strscan'
---- inner
R_SPACE = /\A[ \t\n\r]+/
R_RESERVED = /\A[\{\}\[\],:]/
R_INTEGER = /\A-?(?:0|[1-9]\d*)/
R_FLOAT = /\A-?(?:0|[1-9]\d*)(?:\.\d+)/
R_STRING = /\A"(?:\\["\\\/bfnrt]|\\u[\dA-Za-z]{4}|[^\\"])*"/
R_FALSE = /\Afalse/
R_NULL = /\Anull/
R_TRUE = /\Atrue/
def initialize(obj)
src = obj.is_a?(IO) ? obj.read : obj.to_s
@s = StringScanner.new(src)
end
def parse
piece = nil
@q = []
until @s.eos?
if (piece = @s.scan R_SPACE)
@q << [:SPACE, piece]
elsif (piece = @s.scan R_RESERVED)
@q << [piece, piece]
elsif (piece = @s.scan R_FLOAT)
@q << [:FLOAT, piece]
elsif (piece = @s.scan R_INTEGER)
@q << [:INTEGER, piece]
elsif (piece = @s.scan R_STRING)
@q << [:STRING, piece.gsub(/\A"(.*)"/, "\\1")]
elsif @s.scan R_FALSE
@q << [:FALSE, false]
elsif @s.scan R_NULL
@q << [:NULL, nil]
elsif @s.scan R_TRUE
@q << [:TRUE, true]
else
raise 'Error'
end
end
do_parse
end
def next_token
@q.shift
end
---- footer
if __FILE__ == $0
parser = JsonParser.new(ARGV[0])
begin
p parser.parse
rescue Racc::ParseError => e
$stderr.puts e
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment