Created
June 15, 2017 23:50
-
-
Save iliabylich/a2c484609577bac419565b5e3c0deb1a to your computer and use it in GitHub Desktop.
json parser
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# racc json_parser.rb -o out.rb -v -g && ruby -rpry -rstrscan out.rb | |
class JsonParser | |
token tDOT tQUOTE | |
tLCURLY tRCURLY | |
tLBRACK tRBRACK | |
tCOMMA tCOLON | |
tSTRING tNUMBER | |
kTRUE kFALSE kNULL | |
rule | |
object : tLCURLY tRCURLY | |
{ | |
result = {} | |
} | |
| tLCURLY kv_pairs tRCURLY | |
{ | |
result = val[1] | |
} | |
kv_pairs : kv_pair | |
| kv_pair tCOMMA kv_pairs | |
{ | |
result = val[0].merge(val[2]) | |
} | |
kv_pair : key tCOLON value | |
{ | |
result = { val[0] => val[2] } | |
} | |
key : string | |
value : string | |
| integer | |
| float | |
| object | |
| array | |
| true | |
| false | |
| null | |
string : tSTRING | |
integer : tNUMBER | |
{ | |
result = val[0].to_i | |
} | |
float : tNUMBER tDOT tNUMBER | |
{ | |
result = val.join.to_f | |
} | |
array : tLBRACK tRBRACK | |
{ | |
result = [] | |
} | |
| tLBRACK array_items tRBRACK | |
{ | |
result = val[1] | |
} | |
array_items : array_item | |
{ | |
result = val | |
} | |
| array_item tCOMMA array_items | |
{ | |
result = [val[0]] + val[2] | |
} | |
array_item : value | |
true : kTRUE | |
{ | |
result = true | |
} | |
false : kFALSE | |
{ | |
result = false | |
} | |
null : kNULL | |
{ | |
result = nil | |
} | |
end | |
---- inner | |
def initialize(raw_json) | |
@raw_json = raw_json | |
@yydebug = true | |
end | |
def parse | |
@tokens = JsonLexer.new(@raw_json).tokens | |
do_parse | |
end | |
def next_token | |
@tokens.shift | |
end | |
class JsonLexer | |
TOKENS = { | |
/\./ => :tDOT, | |
/\{/ => :tLCURLY, | |
/\}/ => :tRCURLY, | |
/\[/ => :tLBRACK, | |
/\]/ => :tRBRACK, | |
/,/ => :tCOMMA, | |
/:/ => :tCOLON, | |
/true/ => :kTRUE, | |
/false/ => :kFALSE, | |
/null/ => :kNULL, | |
/\d+/ => :tNUMBER | |
}.freeze | |
attr_reader :source | |
def initialize(source) | |
@source = StringScanner.new(source) | |
@result = [] | |
end | |
def tokens | |
while (@source.skip(/\s+/); !@source.empty?) do | |
# string is a special case | |
if str = @source.scan(/"(.*?)"/) | |
@result << [:tSTRING, str[1..-2]] | |
else | |
found = false | |
TOKENS.each do |regexp, token| | |
if value = @source.scan(regexp) | |
@result << [token, value] | |
found = true | |
end | |
end | |
unless found | |
raise "Lex error : " + @source.inspect | |
end | |
end | |
end | |
@result | |
end | |
end | |
---- footer | |
p JsonParser.new(DATA.read).parse | |
__END__ | |
{ | |
"number": 123, | |
"float": 2.3, | |
"string": "str", | |
"array": [4, 5.6, "str", [7], {"8": "9"}], | |
"true": true, | |
"false": false, | |
"null": null | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment