2012/08/22(水)C言語でJSONパーサーをかく?

はてブ数 2012/08/23 01:13 プログラミング::チラ裏つーさ

ついったで、C言語によるJSONパーサーの話題をチラ見した。

  • C++だとpicojsonが便利いけど、C言語でJSON扱えるライブラリってそんなにないのか? 動的なメモリアロケーションがどうとか言うが、事前にchar[65536]確保して渡してそん中でごにょごにょするデザインにすりゃええんでろ? とか思って島 (20分前)
  • JSONパーサーは、パーサー書く練習のいい題材かもしれんのう。実際C#で書いた自前JSONパーサーが、もっとも多用してるライブラリやも。 (16分前)
  • struct json E_TYPE TYPE; size_t LENGTH; union { float NUMBER; char STRING[1]; ... } みたいなサイズ不定の構造体をchar[]の中に詰め込みながら先頭アドレスをメモってくのが好き。 (9分前)

静的に型付けされてる言語でJSONをどう扱うかっていうのが結構難しいよね。

とりあえずぱっと思いつくのはこういうモデル?

/* json parser */

#include <stdio.h>

typedef enum {
  E_JSON_TYPE_NULL,
  E_JSON_TYPE_BOOLEAN,
  E_JSON_TYPE_NUMBER,
  E_JSON_TYPE_STRING,
  E_JSON_TYPE_ARRAY,
  E_JSON_TYPE_OBJECT,
} e_json_type_t;

typedef struct t_json {
  e_json_type_t type;
  size_t length;
  union {
    char as_boolean;
    long long as_number;
    wchar_t as_string[1];
    size_t as_array;
    size_t as_object;
  };
} json_t;

inline int as_int(const json_t *o)
{
  assert(o->type == E_JSON_TYPE_NUMBER);
  return (int)o->as_number;
}

as_arrayとかas_objectのときは、そこに書いてあるsize_t分、後続のjson_tが格納されてると見なす、みたいな?

配列やオブジェクトのパースの時には事前に長さがわからないので、ランダムアクセスさせるデータ構造は作れないような気がする。
でも、上に書いたような線形リストっぽい実装しちゃうと、後からのトラバースでいちいち中見ないといけなくて面倒だよね。
obj[3][2] は、 obj->child->next->next->next->child->next->next って展開されるからアクセスも遅そうだし。

んー。メモリプールを二つに分けて、数値と文字列と真偽値みたいな葉をひたすらため込むプールとそこへのポインタをため込むプールにわける?
ポインタをため込むプールの方は1要素のサイズが固定できて添え字によるランダムアクセスしやすくなる。

案外奥が深いよね。

CでまともにTwitter Clientとか作ろうと思ったらめんどそう。