Skip to content

Instantly share code, notes, and snippets.

@shomah4a
Created January 12, 2011 16:02
Show Gist options
  • Save shomah4a/776350 to your computer and use it in GitHub Desktop.
Save shomah4a/776350 to your computer and use it in GitHub Desktop.
Erlang で JSON をパースしてみました
%% -*- coding:utf-8 -*-
-module(json).
-export([parseJson/1]).
%% 空白飛ばし
skipSpace([]) ->
[];
skipSpace([X|XS]) when (X == $ ) or (X == $\n) or (X == $\r) or (X == $\t) ->
skipSpace(XS);
skipSpace(XS) ->
XS.
%% トークン
parseToken([X|XS], Result) when (X == $_) or
((X >= $0) and (X =< $9)) or
((X >= $A) and (X =< $Z)) or
((X >= $a) and (X =< $z)) ->
parseToken(XS, [X|Result]);
parseToken(XS, Result) ->
checkToken(XS, lists:reverse(Result)).
checkToken(XS, "null") ->
{ok, {null, XS}};
checkToken(_, Result) ->
{error, "Invalid Token " ++ Result}.
%% 使わないけど取りあえず
parseString([$'|XS]) ->
parseString($', XS);
parseString([$"|XS]) ->
parseString($", XS);
parseString([X|XS]) ->
{error, {"Invalid String " ++ [X]}}.
%% 文字列パースエントリポイント
parseString(T, XS) ->
{ok, {Result, Left}} = parseString(T, XS, []),
{ok, {lists:reverse(Result), Left}}.
%% 文字列パース
parseString(_, [], _) ->
{error, "Unterminated string"};
parseString(T, [T|XS], [$\\|Result]) ->
parseString(T, XS, [T, $\\|Result]);
parseString(T, [T|XS], Result) ->
{ok, {Result, XS}};
parseString(T, [X|XS], Result) ->
parseString(T, XS, [X|Result]).
%% 数値パース
parseNumber(XS) ->
{Sign, Num} = parseSign(XS),
parseNumber(Num, [Sign]).
parseNumber([], []) ->
{error, "Invalid number"};
parseNumber([], Result) ->
{ok, {list_to_integer(lists:reverse(Result)), []}};
parseNumber([$.|XS], Result) ->
parseFloat(XS, [$.|Result]);
parseNumber([X|XS], Result) when (X >= $0) and (X =< $9) ->
parseNumber(XS, [X|Result]);
parseNumber(XS, Result) ->
{ok, {list_to_integer(lists:reverse(Result)), XS}}.
parseFloat([X|XS], Result) when (X >= $0) and (X =< $9) ->
parseFloat(XS, [X|Result]);
parseFloat(XS, Result) ->
{ok, {list_to_float(lists:reverse([$0|Result])), XS}}.
parseSign([$-|XS]) ->
{$-, XS};
parseSign([$+|XS]) ->
{$+, XS};
parseSign(XS) ->
{$+, XS}.
%% 配列
parseArray(XS) ->
{ok, {Result, Left}} = parseArray(skipSpace(XS), []),
{ok, {lists:reverse(Result), Left}}.
parseArray([], _) ->
{error, "Invalid array"};
parseArray([$]|XS], Result) ->
{ok, {Result, XS}};
parseArray(XS, Result) ->
{ok, {Object, Left}} = parseJson(XS),
parseArrayCont(skipSpace(Left), [Object|Result]).
%% 続ける?
parseArrayCont([$,|XS], Result) ->
parseArray(XS, Result);
parseArrayCont([$]|XS], Result) ->
{ok, {Result, XS}};
parseArrayCont([X|XS], _) ->
{error, "Invalid Charactor Array"}.
%% オブジェクトとか
parseObject(XS) ->
{ok, {Result, Left}} = parseObject(XS, []),
{ok, {lists:reverse(Result), Left}}.
parseObject([], _) ->
{error, "Invalid Object"};
parseObject([$}|XS], Result) ->
{ok, {Result, XS}};
parseObject(XS, Result) ->
{ok, {Key, KeyLeft}} = parseString(skipSpace(XS)),
[$:|BeforeValue] = skipSpace(KeyLeft),
{ok, {Value, ValueLeft}} = parseJson(skipSpace(BeforeValue)),
parseObjectCont(skipSpace(ValueLeft), [{Key, Value}|Result]).
parseObjectCont([$,|XS], Result) ->
parseObject(XS, Result);
parseObjectCont([$}|XS], Result) ->
{ok, {Result, XS}};
parseObjectCont([X|XS], _) ->
{error, "Invalid Charactor Array"}.
parseStart([$[|XS]) ->
parseArray(XS);
parseStart([${|XS]) ->
parseObject(XS);
parseStart([X|XS]) when (X =:= $') or (X =:= $") ->
parseString(X, XS);
parseStart([X|XS]) when ((X >= $0) and (X =< $9)) or (X == $+) or (X == $-) ->
parseNumber([X|XS]);
parseStart([X|XS]) when (X == $_) or
((X >= $A) and (X =< $Z)) or
((X >= $a) and (X =< $z)) ->
parseToken(XS, [X]).
parseJson(XS) ->
parseStart(skipSpace(XS)).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment