Advertisement
avp210159

spjson.c

Feb 2nd, 2014
135
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 13.32 KB | None | 0 0
  1. /*
  2. Это мой spj.h
  3.  
  4. Вставил заодно вместе с набросками .c
  5. */
  6. #ifndef _SPJ_H
  7. #define _SPJ_H
  8.  
  9. #include <stdlib.h>
  10.  
  11. struct jval;
  12. #ifdef USE_OBJ_DICT
  13. struct htab; // will be implemented sometime
  14. #endif
  15.  
  16. typedef enum jValue_type {
  17.   Unknown = 0,
  18.   Object,
  19.   Array,
  20.   String,
  21.   Number,
  22.   Bool,
  23.   Null
  24. } jValue_type;
  25.  
  26. typedef struct jObject {
  27.   struct jval *data; // array
  28.   int size;
  29. #ifdef USE_OBJ_DICT
  30.   struct htab *hash;
  31. #endif
  32. } jObject;
  33.  
  34. typedef struct jArray {
  35.   struct jval *data; // array
  36.   int size;
  37. } jArray;
  38.  
  39. typedef struct jString {
  40.   char *data; // nil terminating
  41.   int size;
  42. } jString;
  43.  
  44. union value {
  45.   struct jObject obj;
  46.   struct jArray arr;
  47.   struct jString str;
  48.   double number;  // Bool, Null, integer and real (all in one)
  49. };
  50.  
  51. typedef struct jval {
  52.   jValue_type type;    // try to do it without flags
  53.   struct jval *parent; // calculated AFTER the filling of the PARENT's container
  54.   char *name;          // name pairs (valid only for members of the object)
  55.   union value value;
  56. } jValue;
  57.  
  58.  
  59. typedef enum jtoken {
  60.   Jeof,
  61.   Jnumber,
  62.   Jstring,
  63.   Jbool,     // true false
  64.   Jnull,     // null
  65.   Jobjstart, // {
  66.   Jarrstart, // [
  67.   Jobjend,   // }
  68.   Jarrend,   // ]
  69.   Jcolon,    // : =
  70.   Jcomma,    // ,
  71.   Jname,     // extension for name : value (unquoted name)
  72.   Jerror,
  73.   Janymember,
  74.   Jnomem = -1
  75. } jToken;
  76.  
  77. typedef struct spjiter {
  78.   const char *data;
  79.   size_t dsize, curpos;
  80. } jIter;
  81.  
  82. typedef struct jlexer {
  83.   jIter it;
  84.   jToken tok;
  85.   int charin, charpos;
  86.   char *errmsg;
  87.   union value lv;
  88. } jLexer;
  89.  
  90. jToken spj_getoken (jLexer *lex);
  91. #endif
  92.  
  93. /*
  94.   spj.c
  95.  
  96.    Это просто наброски кода лексера и двух функций парсера
  97.    (парсер нужно рассматривать в качестве псевдокода)
  98.  
  99.    Станислав, я не стал класть сюда некоторые функции,
  100.    возмжно самому будет интересно их написать (4/2/2014 я их длбавил сюда).
  101.    Только у меня некоторые структуры немного другие.
  102. */
  103.  
  104. // функции для get_jutf8str и еще несколько для сообщений об ошибке
  105.  
  106. // эти .h я использую тут
  107. #include <stdio.h>
  108. #include <string.h>
  109. #include <stdint.h>
  110. #include <ctype.h>
  111. #include <errno.h>
  112. #include <stdarg.h>
  113.  
  114. // эта кладет в buf[] размером bs текст из исходного json, вызвавший ошибку при распознавании true,false,null
  115. //   например, для tru или trueeee
  116. static  char *
  117. stsubstr (const char *src, const char *end, char buf[], int bs)
  118. {
  119.   int l = end - src;
  120.  
  121.   if (l > bs - 1) {
  122.     strncpy(buf, src, bs - 4);
  123.     strcpy(buf + bs - 4, "...");
  124.   } else {
  125.     strncpy(buf, src, l);
  126.     buf[l] = 0;
  127.   }
  128.   return buf;
  129. }
  130.  
  131. // like sprintf to dynamic string in jLexer
  132. static jToken
  133. spj_eprintf (jLexer *lex, jToken curtok, const char *fmt, ...)
  134. {
  135.   lex->errtok = curtok;
  136.   int retl;
  137.   jToken rc = Jnomem;
  138.   va_list ap;
  139.  
  140.   va_start(ap, fmt);
  141.   retl = vsnprintf(lex->errmsg, 0, fmt, ap);
  142.   va_end(ap);
  143.   if (lex->errmsg = (char *)malloc(retl + 1)) {
  144.     va_start(ap, fmt);
  145.     vsnprintf(lex->errmsg, retl + 1, fmt, ap);
  146.     va_end(ap);
  147.     rc = Jerror;
  148.   }
  149.  
  150.   return rc;
  151. }
  152.  
  153. // like sprintf to concat string with lex->errmsg
  154. static jToken
  155. spj_emsgcat (jLexer *lex, const char *fmt, ...)
  156. {
  157.   int retl, lemsg = lex->errmsg ? strlen(lex->errmsg) : 0;
  158.   char *t = lex->errmsg;
  159.   jToken rc = Jnomem;
  160.   va_list ap;
  161.  
  162.   va_start(ap, fmt);
  163.   retl = vsnprintf(t, 0, fmt, ap);
  164.   va_end(ap);
  165.   if (lex->errmsg = (char *)realloc(lex->errmsg, retl + lemsg + 1)) {
  166.     va_start(ap, fmt);
  167.     vsnprintf(lex->errmsg + lemsg, retl, fmt, ap);
  168.     va_end(ap);
  169.     rc = Jerror;
  170.   } else {
  171.     lex->errmsg = t;
  172.   }
  173.  
  174.   return rc;
  175. }
  176.  
  177. // check true,false,null
  178. static int
  179. check_tfn (jLexer *lex, const char *w)
  180. {
  181.   int c;
  182.   const char *cw = w;
  183.  
  184.   while ((c = spj_getc(&lex->it)) && *w == c)
  185.     w++;
  186.  
  187.   if (c && *w == 0)
  188.     if (isspace(c) || strchr("]},", c)) {
  189.       spj_seek(&lex->it, -1);
  190.       return 1;
  191.     }
  192.   char buf[10];
  193.   if (c) {
  194.     spj_eprintf (lex, lex->charin == 'n' ? Jnull : Jbool,
  195.          "unexpected '%c%s%c...' instead of '%c%s' at pos: %d\n",
  196.          lex->charin, stsubstr(cw, w, buf, sizeof(buf)), c,
  197.          lex->charin, cw, lex->charpos);
  198.     spj_seek(&lex->it, -1);
  199.   } else {
  200.     spj_eprintf (lex, lex->charin == 'n' ? Jnull : Jbool,
  201.          "unexpected EOF instead of '%c%s' at pos: %d\n",
  202.          lex->charin, cw, lex->charpos);
  203.   }
  204.   return 0;
  205. }
  206.  
  207. // Call it only for VALID c !!!
  208. static inline int
  209. hexdigit (int c)
  210. {
  211.   if (c <= '9')
  212.     return c-'0';
  213.   if (c <= 'F')
  214.     return c-'A'+10;
  215.   return c-'a'+10;
  216. }
  217.  
  218. // returns 0 if surrogate pair is not valid
  219. int
  220. surpair_to_ucs (int sp[2])
  221. {
  222.   int ucs = 0;
  223.  
  224.   if ((sp[0] & 0xFFFFFC00) == 0xD800 && (sp[1] & 0xFFFFFC00) == 0xDC00)
  225.     ucs = ((sp[0] & 0x3FF) << 10) | (sp[1] & 0x3FF);
  226.   return ucs;
  227. }
  228.  
  229. /*
  230.   For a given UCS puts in memory bytes in UTF-8
  231.   Returns the number of bytes, or 0 on error (UCS <0)
  232.  */
  233. int
  234. ucs_to_utf8 (int uc, char *b)
  235. {
  236.   if (uc < 0)
  237.     return 0;
  238.   u_int ucs = uc;
  239.   if (ucs < 128) {
  240.     b[0] = ucs;
  241.     return 1;
  242.   }
  243.  
  244.   int n = 6, i;
  245.   if (ucs < 0x800)
  246.     n = 2;
  247.   else if (ucs < 0x10000)
  248.     n = 3;
  249.   else if (ucs < 0x200000)
  250.     n = 4;
  251.   else if (ucs < 0x4000000)
  252.     n = 5;
  253.  
  254.   char *u = b+n-1;
  255.   static u_int
  256.     mask1[7] = { 0x0, 0x0, 0x1f, 0x0f, 0x07, 0x03, 0x01},
  257.     mask2[7] = { 0x0, 0x0, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc};
  258.  
  259.   for (i = 0; i < n-1; i++, u--, ucs >>= 6)
  260.     *u = (ucs & 0x3f) | 0x80;
  261.   *u = (ucs & mask1[n]) | mask2[n];
  262.  
  263.   return n;
  264. }
  265.  
  266. // 4 hex digits to integer (returns -1 on error)
  267. static int
  268. spj_gethex4 (jLexer *lex)
  269. {
  270.   int i, ucs = 0, c;
  271.  
  272.   for (i = 0; i < 4; i++) {
  273.     if (isxdigit(c = spj_getc(&lex->it)))
  274.       ucs = (ucs << 4) | hexdigit(c);
  275.     else {
  276.       spj_eprintf (lex, Jstring,
  277.            "invalid '%c' (0x02x) character in \\uHHHH in Jstring before pos: %d\n",
  278.            c, c, lex->it.curpos);
  279.       return -1;
  280.     }
  281.   }
  282.   return ucs;
  283. }
  284.  
  285.  
  286. // json String encoded utf-8
  287. jToken
  288. get_jutf8str (jLexer *lex)
  289. {
  290.   jToken rc = Jeof;
  291.   int ucs32, c, lutf8, lstr = 0, capacity, incr = JSTR_INIT_INCREMENT;
  292.   char utf8[8], *str = (char *)malloc(capacity = JSTR_INIT_SIZE);
  293.   if (!str)
  294.     return Jnomem;
  295.  
  296.   while (c = spj_getc(&lex->it)) {
  297.     ucs32 = -1;
  298.     if (c == '"') { // return result
  299.       lex->lv.str.size = lstr;
  300.       str[lstr++] = 0;
  301.       lex->lv.str.data = (char *)realloc(str, lstr); // free unused bytes
  302.       return Jstring;
  303.     }
  304.     if (c == '\\') {
  305.       // c == 0 after switch() means any error is found
  306.       switch (c = spj_getc(&lex->it)) {
  307.       case 0: break;
  308.       case 't': c = '\t'; break;
  309.       case 'r': c = '\r'; break;
  310.       case 'n': c = '\n'; break;
  311.       case 'f': c = '\f'; break;
  312.       case 'b': c = '\b'; break;
  313.       case '\\': c = '\\'; break;
  314.       case '/': c = '/'; break;
  315.       case '"': c = '"'; break;
  316.       case 'u':
  317.     {
  318.       int sp[2]; // assume the appearance of a surrogate pair
  319.       if ((ucs32 = sp[0] = spj_gethex4(lex)) == -1) {
  320.         rc = Jerror; c = 0; // c == 0 error flag
  321.             break;
  322.       }
  323.       if ((ucs32 & 0xFC00) == 0xd800) { // surrogate pair
  324.         if ((c = spj_getc(&lex->it)) == '\\' &&
  325.         (c = spj_getc(&lex->it)) == 'u') {
  326.           if (!(sp[1] = spj_gethex4(lex))) {
  327.         rc = Jerror; c = 0; break;
  328.           }
  329.           if (!(ucs32 = surpair_to_ucs(sp))) {
  330.         fprintf (stderr, "invalid surrogate pair in Jstring before pos: %ld\n",
  331.              lex->it.curpos);
  332.             rc = Jerror; c = 0; break;
  333.           }
  334.         } else {
  335.           fprintf (stderr, "unexpected character '\\%c' (0x%02x) in Jstring at pos: %ld\n",
  336.                c, c, lex->it.curpos);
  337.           rc = Jerror; c = 0; break;
  338.         }
  339.       }
  340.     }
  341.     break;
  342.       default:
  343.     rc = Jerror;
  344.     fprintf (stderr, "invalid escape sequence '\\%c' (0x%02x) in Jstring at pos: %ld\n",
  345.          c, c, lex->it.curpos);
  346.     c = 0;
  347.       }
  348.       if (!c)
  349.     break; // break while () loop, free mem, returns error
  350.     }
  351.     /*
  352.       We assume that JSON encoded UTF-8.
  353.       Therefore, all symbols except encoded by \uHHHH
  354.       copied into the result
  355.     */
  356.     if (ucs32 != -1) { // utf-8 value of \uHHHH is in utf8[]
  357.       if (!(lutf8 = ucs_to_utf8(ucs32, utf8))) {
  358.     rc = Jerror;
  359.     fprintf (stderr, "invalid ucs to utf8 conversion near pos: %ld\n",
  360.          lex->it.curpos);
  361.     break;
  362.       }
  363.     } else {
  364.       lutf8 = 1;
  365.       utf8[0] = c;
  366.     }
  367.     if (lutf8 + 1 + lstr > capacity) {
  368.       char *t = (char *)realloc(str, capacity += (lutf8 + incr));
  369.       if (!t) {
  370.     rc = Jnomem;
  371.     break;
  372.       }
  373.       str = t;
  374.       if ((incr <<= 1) > JSTR_MAX_INCREMENT)
  375.     incr = JSTR_MAX_INCREMENT;
  376.     }
  377.     memcpy(str + lstr, utf8, lutf8);
  378.     lstr += lutf8;
  379.   }
  380.  
  381.   free(str);
  382.   return rc;
  383. }
  384.  
  385. jToken
  386. spj_getoken (jLexer *lex)
  387. {
  388.   int c, i;
  389.  
  390.   while (isspace(c = spj_getc(&lex->it)));
  391.  
  392.   lex->charin = c;
  393.   lex->charpos = spj_seek(&lex->it, 0); // one position more !!!
  394.  
  395.   switch (c) {
  396.   case 0:
  397.     return lex->tok = Jeof;
  398.   case '{':  return lex->tok = Jobjstart;
  399.   case '}':  return lex->tok = Jobjend;
  400.   case '[':  return lex->tok = Jarrstart;
  401.   case ']':  return lex->tok = Jarrend;
  402.   case ':':  case '=': return lex->tok = Jcolon;
  403.   case ',':  return lex->tok = Jcomma;
  404.   case 't': case 'f': case 'n':
  405.     lex->lv.number = (c == 't'); // false, null = 0
  406.     {
  407.       const char *w = "rue";
  408.       if (c == 'f')
  409.     w = "alse";
  410.       else if (c == 'n')
  411.     w = "ull";
  412.       return !check_tfn(lex, w) ? lex->tok = Jerror :
  413.     (c == 'n') ? (lex->tok = Jnull) : (lex->tok = Jbool);
  414.     }
  415.   case '"':
  416.     return lex->tok = get_jutf8str(lex);
  417.   default :
  418.     if (isdigit(c) || c == '-') {
  419.       char *t, s[22];
  420.       s[0] = c;
  421.       for (i = 1;
  422.        (isdigit(c = spj_getc(&lex->it)) || strchr("eE+-.", c)) && i < 20;
  423.        i++)
  424.     s[i] = c;
  425.       s[i++] = c;
  426.       s[i] = 0;
  427.       errno = 0;
  428.       lex->lv.number = strtod(s, &t);
  429.       if (errno || s == t ||
  430.       !(isspace(*t) || *t == ',' || *t == '}' || *t == ']')) {
  431.     fprintf (stderr, "invalid number '%s' at pos: %ld\n",
  432.          s, lex->it.curpos);
  433.     return lex->tok = Jerror;
  434.       }
  435.       spj_seek(&lex->it, -1);
  436.       return lex->tok = Jnumber;
  437.     }
  438.     fprintf (stderr, "unexpected character  '%c' (0x%02x) at pos: %ld\n",
  439.          c, c, lex->it.curpos);
  440.     return lex->tok = Jerror;
  441.   }
  442.  
  443.   fprintf (stderr, "interror: spj_getoken() notreached\n");
  444.   return lex->tok = Jerror;
  445. }
  446.  
  447. /*
  448.   это чисто заглушки, чтобы компилились spj_parse_object() и spj_parse_array()
  449. */
  450. static void complete_obj (jValue *obj) {
  451.  
  452. }
  453.  
  454. static void delete_member (jValue *obj) {
  455.  
  456. }
  457.  
  458. static void complete_arr (jValue *arr) {
  459.  
  460. }
  461.  
  462. static void add_arrmember (jValue *arr, jValue *member, int n) {
  463.  
  464. }
  465.  
  466. static void put_objmember (jValue *obj, jValue *member) {
  467.  
  468. }
  469.  
  470. static jToken struct_error (jToken rc, jToken expected, jLexer *lex, jValue *obj) {
  471.  
  472. }
  473.  
  474. static jValue_type do_jtype (jToken rc) {
  475.  
  476. }
  477.  
  478. jToken spj_parse_array (jLexer *lex, jValue *obj);
  479.  
  480. jToken
  481. spj_parse_object (jLexer *lex, jValue *obj)
  482. {
  483.   obj->type = Object;
  484.   char *name;
  485.   jToken rc;
  486.   int n;
  487.  
  488.   for (n = 0;;n++) {
  489.     if ((rc = spj_getoken(lex)) == Jobjend && n == 0)
  490.       break;
  491.     if (rc != Jstring)
  492.       return struct_error(rc, Jstring, lex, obj);
  493.     name = lex->lv.str.data;
  494.  
  495.     if ((rc = spj_getoken(lex)) != Jcolon)
  496.       return struct_error(rc, Jcolon, lex, obj);
  497.  
  498.     jValue member = {0};
  499.     member.name = name;
  500.     switch (rc = spj_getoken(lex)) {
  501.     case Jnumber: case Jstring: case Jbool: case Jnull:
  502.       member.value = lex->lv;
  503.       member.type = do_jtype(rc);
  504.       break;
  505.     case Jobjstart:
  506.       if ((rc = spj_parse_object(lex, &member)) == Jobjend)
  507.     break; // OK
  508.       delete_member(&member);
  509.       return rc;
  510.     case Jarrstart:
  511.       if ((rc = spj_parse_array(lex, &member)) == Jarrend)
  512.     break; // OK
  513.       delete_member(&member);
  514.       return rc;
  515.     default:
  516.       return struct_error(rc, Janymember, lex, obj);
  517.     }
  518.     put_objmember(obj, &member);
  519.  
  520.     if ((rc = spj_getoken(lex)) == Jobjend)
  521.       break;
  522.     if (rc != Jcomma)
  523.       return struct_error(rc, Jcomma, lex, obj);
  524.   }
  525.  
  526.   complete_obj(obj);
  527.   return rc;
  528. }
  529.  
  530. jToken
  531. spj_parse_array (jLexer *lex, jValue *obj)
  532. {
  533.   obj->type = Array;
  534.   jToken rc;
  535.   int n;
  536.  
  537.   for (n = 0;;n++) {
  538.     if ((rc = spj_getoken(lex)) == Jarrend && n == 0)
  539.       break;
  540.     jValue member = {0};
  541.  
  542.     switch (rc) {
  543.     case Jnumber: case Jstring: case Jbool: case Jnull:
  544.       member.value = lex->lv;
  545.       member.type = do_jtype(rc);
  546.       break;
  547.     case Jobjstart:
  548.       if ((rc = spj_parse_object(lex, &member)) == Jobjend)
  549.     break; // OK
  550.       delete_member(&member);
  551.       return rc;
  552.     case Jarrstart:
  553.       if ((rc = spj_parse_array(lex, &member)) == Jarrend)
  554.     break; // OK
  555.       delete_member(&member);
  556.       return rc;
  557.     default:
  558.       return struct_error(rc, Janymember, lex, obj);
  559.     }
  560.     add_arrmember(obj, &member, n);
  561.  
  562.     if ((rc = spj_getoken(lex)) == Jarrend)
  563.       break;
  564.     if (rc != Jcomma)
  565.       return struct_error(rc, Jcomma, lex, obj);
  566.   }
  567.  
  568.   complete_arr(obj);
  569.   return rc;
  570. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement