فهرست منبع

ncd: NCDValueParser: refactor to how NCDConfigParser is implemented, and avoid using the old NCDConfig
code

ambrop7 13 سال پیش
والد
کامیت
b1f6e3f1d6
6فایلهای تغییر یافته به همراه631 افزوده شده و 678 حذف شده
  1. 218 205
      generated/NCDValueParser_parse.c
  2. 7 7
      generated/NCDValueParser_parse.h
  3. 83 91
      generated/NCDValueParser_parse.out
  4. 131 102
      generated/NCDValueParser_parse.y
  5. 61 171
      ncd/NCDValueParser.c
  6. 131 102
      ncd/NCDValueParser_parse.y

+ 218 - 205
generated/NCDValueParser_parse.c

@@ -4,34 +4,6 @@
 /* First off, code is included that follows the "include" declaration
 ** in the input grammar file. */
 #include <stdio.h>
-#line 30 "NCDValueParser_parse.y"
-
-
-#include <string.h>
-#include <stddef.h>
-
-#include <misc/debug.h>
-#include <ncd/NCDConfig.h>
-
-#define AST_TYPE_NONE 0
-#define AST_TYPE_STRING 1
-#define AST_TYPE_LIST 2
-#define AST_TYPE_MAP 3
-
-struct parser_minor {
-    char *str;
-    size_t len;
-};
-
-struct parser_out {
-    int out_of_memory;
-    int syntax_error;
-    int ast_type;
-    struct parser_minor ast_string;
-    struct NCDConfig_list *ast_list;
-};
-
-#line 35 "NCDValueParser_parse.c"
 /* Next is all token values, in a form suitable for use by makeheaders.
 ** This section will be null unless lemon is run with the -m switch.
 */
@@ -84,21 +56,21 @@ struct parser_out {
 #define YYCODETYPE unsigned char
 #define YYNOCODE 16
 #define YYACTIONTYPE unsigned char
-#define ParseTOKENTYPE struct parser_minor
+#define ParseTOKENTYPE  struct token 
 typedef union {
   int yyinit;
   ParseTOKENTYPE yy0;
-  struct NCDConfig_list * yy14;
+  struct value yy1;
 } YYMINORTYPE;
 #ifndef YYSTACKDEPTH
 #define YYSTACKDEPTH 0
 #endif
-#define ParseARG_SDECL struct parser_out *parser_out;
-#define ParseARG_PDECL ,struct parser_out *parser_out
-#define ParseARG_FETCH struct parser_out *parser_out = yypParser->parser_out
-#define ParseARG_STORE yypParser->parser_out = parser_out
-#define YYNSTATE 23
-#define YYNRULE 14
+#define ParseARG_SDECL  struct parser_state *parser_out ;
+#define ParseARG_PDECL , struct parser_state *parser_out 
+#define ParseARG_FETCH  struct parser_state *parser_out  = yypParser->parser_out 
+#define ParseARG_STORE yypParser->parser_out  = parser_out 
+#define YYNSTATE 21
+#define YYNRULE 12
 #define YY_NO_ACTION      (YYNSTATE+YYNRULE+2)
 #define YY_ACCEPT_ACTION  (YYNSTATE+YYNRULE+1)
 #define YY_ERROR_ACTION   (YYNSTATE+YYNRULE)
@@ -168,34 +140,34 @@ static const YYMINORTYPE yyzerominor = { 0 };
 **  yy_default[]       Default action for each state.
 */
 static const YYACTIONTYPE yy_action[] = {
- /*     0 */    16,   23,   24,    1,   21,    2,   13,   17,   16,   18,
- /*    10 */     9,    1,   25,    2,   19,   17,   12,   18,   10,   14,
- /*    20 */    17,    3,   18,    9,   17,   15,   18,   10,    6,    5,
- /*    30 */     7,    1,    8,    2,   38,   16,   22,    4,    1,   17,
- /*    40 */     2,   18,   11,   20,
+ /*     0 */    15,   21,   16,    6,   34,    1,   19,    3,    2,   15,
+ /*    10 */    14,   16,    9,   11,   15,    5,   16,    7,   18,    1,
+ /*    20 */    35,   20,    2,   17,   14,   15,   10,   16,    8,   12,
+ /*    30 */    15,    4,   16,    7,   15,   13,   16,    8,    1,   35,
+ /*    40 */    35,    2,   35,   14,
 };
 static const YYCODETYPE yy_lookahead[] = {
- /*     0 */     1,    0,    0,    4,    5,    6,    9,   10,    1,   12,
- /*    10 */    13,    4,    0,    6,    7,   10,   11,   12,   13,    9,
- /*    20 */    10,    2,   12,   13,   10,   11,   12,   13,    1,    3,
- /*    30 */    10,    4,   12,    6,   14,    1,    5,    2,    4,   10,
- /*    40 */     6,   12,   13,    7,
+ /*     0 */    10,    0,   12,   13,   14,    2,    3,    1,    5,   10,
+ /*    10 */     7,   12,   13,    9,   10,    4,   12,   13,    6,    2,
+ /*    20 */    15,    3,    5,    6,    7,   10,   11,   12,   13,    9,
+ /*    30 */    10,    1,   12,   13,   10,   11,   12,   13,    2,   15,
+ /*    40 */    15,    5,   15,    7,
 };
-#define YY_SHIFT_USE_DFLT (-2)
-#define YY_SHIFT_MAX 13
+#define YY_SHIFT_USE_DFLT (-1)
+#define YY_SHIFT_MAX 11
 static const signed char yy_shift_ofst[] = {
- /*     0 */    27,   -1,    7,   34,   34,   34,    1,    2,   12,   19,
- /*    10 */    26,   35,   36,   31,
+ /*     0 */    36,    3,   17,   36,   36,   36,    1,    6,   11,   30,
+ /*    10 */    12,   18,
 };
-#define YY_REDUCE_USE_DFLT (-4)
+#define YY_REDUCE_USE_DFLT (-11)
 #define YY_REDUCE_MAX 5
 static const signed char yy_reduce_ofst[] = {
- /*     0 */    20,   -3,    5,   10,   14,   29,
+ /*     0 */   -10,    4,   15,   20,   24,   -1,
 };
 static const YYACTIONTYPE yy_default[] = {
- /*     0 */    37,   37,   37,   37,   37,   37,   37,   37,   37,   26,
- /*    10 */    37,   28,   37,   37,   27,   29,   34,   35,   36,   32,
- /*    20 */    33,   30,   31,
+ /*     0 */    33,   33,   33,   33,   33,   33,   33,   22,   33,   26,
+ /*    10 */    33,   33,   23,   27,   30,   31,   32,   28,   29,   24,
+ /*    20 */    25,
 };
 #define YY_SZ_ACTTAB (int)(sizeof(yy_action)/sizeof(yy_action[0]))
 
@@ -289,8 +261,8 @@ void ParseTrace(FILE *TraceFILE, char *zTracePrompt){
 /* For tracing shifts, the names of all terminals and nonterminals
 ** are required.  The following table supplies these names */
 static const char *const yyTokenName[] = { 
-  "$",             "STRING",        "COMMA",         "COLON",       
-  "CURLY_OPEN",    "CURLY_CLOSE",   "BRACKET_OPEN",  "BRACKET_CLOSE",
+  "$",             "COMMA",         "CURLY_OPEN",    "CURLY_CLOSE", 
+  "COLON",         "BRACKET_OPEN",  "BRACKET_CLOSE",  "STRING",      
   "error",         "list_contents",  "list",          "map_contents",
   "map",           "value",         "input",       
 };
@@ -300,20 +272,18 @@ static const char *const yyTokenName[] = {
 /* For tracing reduce actions, the names of all rules are required.
 */
 static const char *const yyRuleName[] = {
- /*   0 */ "input ::= STRING",
- /*   1 */ "input ::= list",
- /*   2 */ "input ::= map",
- /*   3 */ "list_contents ::= value",
- /*   4 */ "list_contents ::= value COMMA list_contents",
+ /*   0 */ "input ::= value",
+ /*   1 */ "list_contents ::= value",
+ /*   2 */ "list_contents ::= value COMMA list_contents",
+ /*   3 */ "list ::= CURLY_OPEN CURLY_CLOSE",
+ /*   4 */ "list ::= CURLY_OPEN list_contents CURLY_CLOSE",
  /*   5 */ "map_contents ::= value COLON value",
  /*   6 */ "map_contents ::= value COLON value COMMA map_contents",
- /*   7 */ "list ::= CURLY_OPEN CURLY_CLOSE",
- /*   8 */ "list ::= CURLY_OPEN list_contents CURLY_CLOSE",
- /*   9 */ "map ::= BRACKET_OPEN BRACKET_CLOSE",
- /*  10 */ "map ::= BRACKET_OPEN map_contents BRACKET_CLOSE",
- /*  11 */ "value ::= STRING",
- /*  12 */ "value ::= list",
- /*  13 */ "value ::= map",
+ /*   7 */ "map ::= BRACKET_OPEN BRACKET_CLOSE",
+ /*   8 */ "map ::= BRACKET_OPEN map_contents BRACKET_CLOSE",
+ /*   9 */ "value ::= STRING",
+ /*  10 */ "value ::= list",
+ /*  11 */ "value ::= map",
 };
 #endif /* NDEBUG */
 
@@ -393,17 +363,17 @@ static void yy_destructor(
     ** inside the C code.
     */
       /* TERMINAL Destructor */
-    case 1: /* STRING */
-    case 2: /* COMMA */
-    case 3: /* COLON */
-    case 4: /* CURLY_OPEN */
-    case 5: /* CURLY_CLOSE */
-    case 6: /* BRACKET_OPEN */
-    case 7: /* BRACKET_CLOSE */
+    case 1: /* COMMA */
+    case 2: /* CURLY_OPEN */
+    case 3: /* CURLY_CLOSE */
+    case 4: /* COLON */
+    case 5: /* BRACKET_OPEN */
+    case 6: /* BRACKET_CLOSE */
+    case 7: /* STRING */
 {
-#line 62 "NCDValueParser_parse.y"
- free((yypminor->yy0).str); 
-#line 407 "NCDValueParser_parse.c"
+#line 34 "NCDValueParser_parse.y"
+ free_token((yypminor->yy0)); 
+#line 377 "NCDValueParser_parse.c"
 }
       break;
     case 9: /* list_contents */
@@ -412,9 +382,9 @@ static void yy_destructor(
     case 12: /* map */
     case 13: /* value */
 {
-#line 70 "NCDValueParser_parse.y"
- NCDConfig_free_list((yypminor->yy14)); 
-#line 418 "NCDValueParser_parse.c"
+#line 42 "NCDValueParser_parse.y"
+ free_value((yypminor->yy1)); 
+#line 388 "NCDValueParser_parse.c"
 }
       break;
     default:  break;   /* If no destructor action specified: do nothing */
@@ -587,12 +557,12 @@ static void yyStackOverflow(yyParser *yypParser, YYMINORTYPE *yypMinor){
    while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
    /* Here code is inserted which will execute if the parser
    ** stack every overflows */
-#line 83 "NCDValueParser_parse.y"
+#line 55 "NCDValueParser_parse.y"
 
     if (yypMinor) {
-        free(yypMinor->yy0.str);
+        free_token(yypMinor->yy0);
     }
-#line 596 "NCDValueParser_parse.c"
+#line 566 "NCDValueParser_parse.c"
    ParseARG_STORE; /* Suppress warning about unused %extra_argument var */
 }
 
@@ -649,15 +619,13 @@ static const struct {
   YYCODETYPE lhs;         /* Symbol on the left-hand side of the rule */
   unsigned char nrhs;     /* Number of right-hand side symbols in the rule */
 } yyRuleInfo[] = {
-  { 14, 1 },
-  { 14, 1 },
   { 14, 1 },
   { 9, 1 },
   { 9, 3 },
-  { 11, 3 },
-  { 11, 5 },
   { 10, 2 },
   { 10, 3 },
+  { 11, 3 },
+  { 11, 5 },
   { 12, 2 },
   { 12, 3 },
   { 13, 1 },
@@ -717,159 +685,204 @@ static void yy_reduce(
   **  #line <lineno> <thisfile>
   **     break;
   */
-      case 0: /* input ::= STRING */
-#line 89 "NCDValueParser_parse.y"
+      case 0: /* input ::= value */
+#line 61 "NCDValueParser_parse.y"
 {
-    ASSERT(parser_out->ast_type == AST_TYPE_NONE)
-
-    parser_out->ast_string = yymsp[0].minor.yy0;
-    parser_out->ast_type = AST_TYPE_STRING;
+    if (!yymsp[0].minor.yy1.have || parser_out->have_value) {
+        free_value(yymsp[0].minor.yy1);
+    } else {
+        parser_out->have_value = 1;
+        parser_out->value = yymsp[0].minor.yy1.v;
+    }
 }
-#line 729 "NCDValueParser_parse.c"
+#line 699 "NCDValueParser_parse.c"
         break;
-      case 1: /* input ::= list */
-#line 96 "NCDValueParser_parse.y"
+      case 1: /* list_contents ::= value */
+#line 70 "NCDValueParser_parse.y"
 {
-    ASSERT(parser_out->ast_type == AST_TYPE_NONE)
+    if (!yymsp[0].minor.yy1.have) {
+        goto failL0;
+    }
+
+    NCDValue_InitList(&yygotominor.yy1.v);
+
+    if (!NCDValue_ListPrepend(&yygotominor.yy1.v, yymsp[0].minor.yy1.v)) {
+        goto failL1;
+    }
+    yymsp[0].minor.yy1.have = 0;
+
+    yygotominor.yy1.have = 1;
+    goto doneL;
 
-    parser_out->ast_list = yymsp[0].minor.yy14;
-    parser_out->ast_type = AST_TYPE_LIST;
+failL1:
+    NCDValue_Free(&yygotominor.yy1.v);
+failL0:
+    yygotominor.yy1.have = 0;
+    parser_out->out_of_memory = 1;
+doneL:
+    free_value(yymsp[0].minor.yy1);
 }
-#line 739 "NCDValueParser_parse.c"
+#line 726 "NCDValueParser_parse.c"
         break;
-      case 2: /* input ::= map */
-#line 103 "NCDValueParser_parse.y"
+      case 2: /* list_contents ::= value COMMA list_contents */
+#line 94 "NCDValueParser_parse.y"
 {
-    ASSERT(parser_out->ast_type == AST_TYPE_NONE)
+    if (!yymsp[-2].minor.yy1.have || !yymsp[0].minor.yy1.have) {
+        goto failM0;
+    }
+
+    if (!NCDValue_ListPrepend(&yymsp[0].minor.yy1.v, yymsp[-2].minor.yy1.v)) {
+        goto failM0;
+    }
+    yymsp[-2].minor.yy1.have = 0;
+
+    yygotominor.yy1.have = 1;
+    yygotominor.yy1.v = yymsp[0].minor.yy1.v;
+    yymsp[0].minor.yy1.have = 0;
+    goto doneM;
 
-    parser_out->ast_list = yymsp[0].minor.yy14;
-    parser_out->ast_type = AST_TYPE_MAP;
+failM0:
+    yygotominor.yy1.have = 0;
+    parser_out->out_of_memory = 1;
+doneM:
+    free_value(yymsp[-2].minor.yy1);
+    free_value(yymsp[0].minor.yy1);
+  yy_destructor(yypParser,1,&yymsp[-1].minor);
 }
-#line 749 "NCDValueParser_parse.c"
+#line 753 "NCDValueParser_parse.c"
         break;
-      case 3: /* list_contents ::= value */
-#line 110 "NCDValueParser_parse.y"
+      case 3: /* list ::= CURLY_OPEN CURLY_CLOSE */
+#line 117 "NCDValueParser_parse.y"
 {
-    yygotominor.yy14 = yymsp[0].minor.yy14;
+    yygotominor.yy1.have = 1;
+    NCDValue_InitList(&yygotominor.yy1.v);
+  yy_destructor(yypParser,2,&yymsp[-1].minor);
+  yy_destructor(yypParser,3,&yymsp[0].minor);
 }
-#line 756 "NCDValueParser_parse.c"
+#line 763 "NCDValueParser_parse.c"
         break;
-      case 4: /* list_contents ::= value COMMA list_contents */
-#line 114 "NCDValueParser_parse.y"
+      case 4: /* list ::= CURLY_OPEN list_contents CURLY_CLOSE */
+#line 122 "NCDValueParser_parse.y"
 {
-    if (!yymsp[-2].minor.yy14) {
-        NCDConfig_free_list(yymsp[0].minor.yy14);
-    } else {
-        ASSERT(!yymsp[-2].minor.yy14->next)
-        yymsp[-2].minor.yy14->next = yymsp[0].minor.yy14;
-    }
-    yygotominor.yy14 = yymsp[-2].minor.yy14;
-  yy_destructor(yypParser,2,&yymsp[-1].minor);
+    yygotominor.yy1 = yymsp[-1].minor.yy1;
+  yy_destructor(yypParser,2,&yymsp[-2].minor);
+  yy_destructor(yypParser,3,&yymsp[0].minor);
 }
-#line 770 "NCDValueParser_parse.c"
+#line 772 "NCDValueParser_parse.c"
         break;
       case 5: /* map_contents ::= value COLON value */
-#line 124 "NCDValueParser_parse.y"
+#line 126 "NCDValueParser_parse.y"
 {
-    if (!yymsp[-2].minor.yy14 || !yymsp[0].minor.yy14) {
-        NCDConfig_free_list(yymsp[-2].minor.yy14);
-        NCDConfig_free_list(yymsp[0].minor.yy14);
-        yygotominor.yy14 = NULL;
-    } else {
-        ASSERT(!yymsp[-2].minor.yy14->next)
-        ASSERT(!yymsp[0].minor.yy14->next)
-        yymsp[-2].minor.yy14->next = yymsp[0].minor.yy14;
-        yygotominor.yy14 = yymsp[-2].minor.yy14;
+    if (!yymsp[-2].minor.yy1.have || !yymsp[0].minor.yy1.have) {
+        goto failS0;
     }
-  yy_destructor(yypParser,3,&yymsp[-1].minor);
-}
-#line 787 "NCDValueParser_parse.c"
-        break;
-      case 6: /* map_contents ::= value COLON value COMMA map_contents */
-#line 137 "NCDValueParser_parse.y"
-{
-    if (!yymsp[-4].minor.yy14 || !yymsp[-2].minor.yy14) {
-        NCDConfig_free_list(yymsp[-4].minor.yy14);
-        NCDConfig_free_list(yymsp[-2].minor.yy14);
-        NCDConfig_free_list(yymsp[0].minor.yy14);
-        yygotominor.yy14 = NULL;
-    } else {
-        ASSERT(!yymsp[-4].minor.yy14->next)
-        ASSERT(!yymsp[-2].minor.yy14->next)
-        yymsp[-4].minor.yy14->next = yymsp[-2].minor.yy14;
-        yymsp[-2].minor.yy14->next = yymsp[0].minor.yy14;
-        yygotominor.yy14 = yymsp[-4].minor.yy14;
+
+    NCDValue_InitMap(&yygotominor.yy1.v);
+
+    if (!NCDValue_MapInsert(&yygotominor.yy1.v, yymsp[-2].minor.yy1.v, yymsp[0].minor.yy1.v)) {
+        goto failS1;
     }
-  yy_destructor(yypParser,3,&yymsp[-3].minor);
-  yy_destructor(yypParser,2,&yymsp[-1].minor);
-}
-#line 807 "NCDValueParser_parse.c"
-        break;
-      case 7: /* list ::= CURLY_OPEN CURLY_CLOSE */
-#line 152 "NCDValueParser_parse.y"
-{
-    yygotominor.yy14 = NULL;
+    yymsp[-2].minor.yy1.have = 0;
+    yymsp[0].minor.yy1.have = 0;
+
+    yygotominor.yy1.have = 1;
+    goto doneS;
+
+failS1:
+    NCDValue_Free(&yygotominor.yy1.v);
+failS0:
+    yygotominor.yy1.have = 0;
+    parser_out->out_of_memory = 1;
+doneS:
+    free_value(yymsp[-2].minor.yy1);
+    free_value(yymsp[0].minor.yy1);
   yy_destructor(yypParser,4,&yymsp[-1].minor);
-  yy_destructor(yypParser,5,&yymsp[0].minor);
-}
-#line 816 "NCDValueParser_parse.c"
-        break;
-      case 8: /* list ::= CURLY_OPEN list_contents CURLY_CLOSE */
-#line 156 "NCDValueParser_parse.y"
-{
-    yygotominor.yy14 = yymsp[-1].minor.yy14;
-  yy_destructor(yypParser,4,&yymsp[-2].minor);
-  yy_destructor(yypParser,5,&yymsp[0].minor);
 }
-#line 825 "NCDValueParser_parse.c"
+#line 802 "NCDValueParser_parse.c"
         break;
-      case 9: /* map ::= BRACKET_OPEN BRACKET_CLOSE */
-#line 160 "NCDValueParser_parse.y"
+      case 6: /* map_contents ::= value COLON value COMMA map_contents */
+#line 152 "NCDValueParser_parse.y"
 {
-    yygotominor.yy14 = NULL;
-  yy_destructor(yypParser,6,&yymsp[-1].minor);
-  yy_destructor(yypParser,7,&yymsp[0].minor);
+    if (!yymsp[-4].minor.yy1.have || !yymsp[-2].minor.yy1.have || !yymsp[0].minor.yy1.have) {
+        goto failT0;
+    }
+
+    if (NCDValue_MapFindKey(&yymsp[0].minor.yy1.v, &yymsp[-4].minor.yy1.v)) {
+        BLog(BLOG_ERROR, "duplicate key in map");
+        yygotominor.yy1.have = 0;
+        parser_out->syntax_error = 1;
+        goto doneT;
+    }
+
+    if (!NCDValue_MapInsert(&yymsp[0].minor.yy1.v, yymsp[-4].minor.yy1.v, yymsp[-2].minor.yy1.v)) {
+        goto failT0;
+    }
+    yymsp[-4].minor.yy1.have = 0;
+    yymsp[-2].minor.yy1.have = 0;
+
+    yygotominor.yy1.have = 1;
+    yygotominor.yy1.v = yymsp[0].minor.yy1.v;
+    yymsp[0].minor.yy1.have = 0;
+    goto doneT;
+
+failT0:
+    yygotominor.yy1.have = 0;
+    parser_out->out_of_memory = 1;
+doneT:
+    free_value(yymsp[-4].minor.yy1);
+    free_value(yymsp[-2].minor.yy1);
+    free_value(yymsp[0].minor.yy1);
+  yy_destructor(yypParser,4,&yymsp[-3].minor);
+  yy_destructor(yypParser,1,&yymsp[-1].minor);
 }
-#line 834 "NCDValueParser_parse.c"
+#line 839 "NCDValueParser_parse.c"
         break;
-      case 10: /* map ::= BRACKET_OPEN map_contents BRACKET_CLOSE */
-#line 164 "NCDValueParser_parse.y"
+      case 7: /* map ::= BRACKET_OPEN BRACKET_CLOSE */
+#line 184 "NCDValueParser_parse.y"
 {
-    yygotominor.yy14 = yymsp[-1].minor.yy14;
-  yy_destructor(yypParser,6,&yymsp[-2].minor);
-  yy_destructor(yypParser,7,&yymsp[0].minor);
+    yygotominor.yy1.have = 1;
+    NCDValue_InitMap(&yygotominor.yy1.v);
+  yy_destructor(yypParser,5,&yymsp[-1].minor);
+  yy_destructor(yypParser,6,&yymsp[0].minor);
 }
-#line 843 "NCDValueParser_parse.c"
+#line 849 "NCDValueParser_parse.c"
         break;
-      case 11: /* value ::= STRING */
-#line 168 "NCDValueParser_parse.y"
+      case 8: /* map ::= BRACKET_OPEN map_contents BRACKET_CLOSE */
+#line 189 "NCDValueParser_parse.y"
 {
-    yygotominor.yy14 = NCDConfig_make_list_string(yymsp[0].minor.yy0.str, yymsp[0].minor.yy0.len, NULL);
-    if (!yygotominor.yy14) {
-        parser_out->out_of_memory = 1;
-    }
+    yygotominor.yy1 = yymsp[-1].minor.yy1;
+  yy_destructor(yypParser,5,&yymsp[-2].minor);
+  yy_destructor(yypParser,6,&yymsp[0].minor);
 }
-#line 853 "NCDValueParser_parse.c"
+#line 858 "NCDValueParser_parse.c"
         break;
-      case 12: /* value ::= list */
-#line 175 "NCDValueParser_parse.y"
+      case 9: /* value ::= STRING */
+#line 193 "NCDValueParser_parse.y"
 {
-    yygotominor.yy14 = NCDConfig_make_list_list(yymsp[0].minor.yy14, NULL);
-    if (!yygotominor.yy14) {
-        parser_out->out_of_memory = 1;
+    ASSERT(yymsp[0].minor.yy0.str)
+
+    if (!NCDValue_InitStringBin(&yygotominor.yy1.v, (uint8_t *)yymsp[0].minor.yy0.str, yymsp[0].minor.yy0.len)) {
+        goto failU0;
     }
+
+    yygotominor.yy1.have = 1;
+    goto doneU;
+
+failU0:
+    yygotominor.yy1.have = 0;
+    parser_out->out_of_memory = 1;
+doneU:
+    free_token(yymsp[0].minor.yy0);
 }
-#line 863 "NCDValueParser_parse.c"
+#line 878 "NCDValueParser_parse.c"
         break;
-      case 13: /* value ::= map */
-#line 182 "NCDValueParser_parse.y"
+      case 10: /* value ::= list */
+      case 11: /* value ::= map */ yytestcase(yyruleno==11);
+#line 210 "NCDValueParser_parse.y"
 {
-    yygotominor.yy14 = NCDConfig_make_list_maplist(yymsp[0].minor.yy14, NULL);
-    if (!yygotominor.yy14) {
-        parser_out->out_of_memory = 1;
-    }
+    yygotominor.yy1 = yymsp[0].minor.yy1;
 }
-#line 873 "NCDValueParser_parse.c"
+#line 886 "NCDValueParser_parse.c"
         break;
       default:
         break;
@@ -931,10 +944,10 @@ static void yy_syntax_error(
 ){
   ParseARG_FETCH;
 #define TOKEN (yyminor.yy0)
-#line 78 "NCDValueParser_parse.y"
+#line 50 "NCDValueParser_parse.y"
 
     parser_out->syntax_error = 1;
-#line 938 "NCDValueParser_parse.c"
+#line 951 "NCDValueParser_parse.c"
   ParseARG_STORE; /* Suppress warning about unused %extra_argument variable */
 }
 

+ 7 - 7
generated/NCDValueParser_parse.h

@@ -1,7 +1,7 @@
-#define STRING                          1
-#define COMMA                           2
-#define COLON                           3
-#define CURLY_OPEN                      4
-#define CURLY_CLOSE                     5
-#define BRACKET_OPEN                    6
-#define BRACKET_CLOSE                   7
+#define COMMA                           1
+#define CURLY_OPEN                      2
+#define CURLY_CLOSE                     3
+#define COLON                           4
+#define BRACKET_OPEN                    5
+#define BRACKET_CLOSE                   6
+#define STRING                          7

+ 83 - 91
generated/NCDValueParser_parse.out

@@ -1,17 +1,19 @@
 State 0:
-          input ::= * STRING
-          input ::= * list
-          input ::= * map
+          input ::= * value
           list ::= * CURLY_OPEN CURLY_CLOSE
           list ::= * CURLY_OPEN list_contents CURLY_CLOSE
           map ::= * BRACKET_OPEN BRACKET_CLOSE
           map ::= * BRACKET_OPEN map_contents BRACKET_CLOSE
+          value ::= * STRING
+          value ::= * list
+          value ::= * map
 
-                        STRING shift  6
                     CURLY_OPEN shift  1
                   BRACKET_OPEN shift  2
-                          list shift  7
-                           map shift  8
+                        STRING shift  14
+                          list shift  15
+                           map shift  16
+                         value shift  6
                          input accept
 
 State 1:
@@ -27,20 +29,20 @@ State 1:
           value ::= * list
           value ::= * map
 
-                        STRING shift  16
                     CURLY_OPEN shift  1
-                   CURLY_CLOSE shift  21
+                   CURLY_CLOSE shift  19
                   BRACKET_OPEN shift  2
-                 list_contents shift  13
-                          list shift  17
-                           map shift  18
-                         value shift  9
+                        STRING shift  14
+                 list_contents shift  11
+                          list shift  15
+                           map shift  16
+                         value shift  7
 
 State 2:
-          map_contents ::= * value COLON value
-          map_contents ::= * value COLON value COMMA map_contents
           list ::= * CURLY_OPEN CURLY_CLOSE
           list ::= * CURLY_OPEN list_contents CURLY_CLOSE
+          map_contents ::= * value COLON value
+          map_contents ::= * value COLON value COMMA map_contents
           map ::= * BRACKET_OPEN BRACKET_CLOSE
           map ::= BRACKET_OPEN * BRACKET_CLOSE
           map ::= * BRACKET_OPEN map_contents BRACKET_CLOSE
@@ -49,14 +51,14 @@ State 2:
           value ::= * list
           value ::= * map
 
-                        STRING shift  16
                     CURLY_OPEN shift  1
                   BRACKET_OPEN shift  2
-                 BRACKET_CLOSE shift  19
-                          list shift  17
-                  map_contents shift  12
-                           map shift  18
-                         value shift  10
+                 BRACKET_CLOSE shift  17
+                        STRING shift  14
+                          list shift  15
+                  map_contents shift  10
+                           map shift  16
+                         value shift  8
 
 State 3:
           list_contents ::= * value
@@ -70,156 +72,146 @@ State 3:
           value ::= * list
           value ::= * map
 
-                        STRING shift  16
                     CURLY_OPEN shift  1
                   BRACKET_OPEN shift  2
-                 list_contents shift  14
-                          list shift  17
-                           map shift  18
-                         value shift  9
+                        STRING shift  14
+                 list_contents shift  12
+                          list shift  15
+                           map shift  16
+                         value shift  7
 
 State 4:
+          list ::= * CURLY_OPEN CURLY_CLOSE
+          list ::= * CURLY_OPEN list_contents CURLY_CLOSE
           map_contents ::= * value COLON value
           map_contents ::= * value COLON value COMMA map_contents
           map_contents ::= value COLON value COMMA * map_contents
-          list ::= * CURLY_OPEN CURLY_CLOSE
-          list ::= * CURLY_OPEN list_contents CURLY_CLOSE
           map ::= * BRACKET_OPEN BRACKET_CLOSE
           map ::= * BRACKET_OPEN map_contents BRACKET_CLOSE
           value ::= * STRING
           value ::= * list
           value ::= * map
 
-                        STRING shift  16
                     CURLY_OPEN shift  1
                   BRACKET_OPEN shift  2
-                          list shift  17
-                  map_contents shift  15
-                           map shift  18
-                         value shift  10
+                        STRING shift  14
+                          list shift  15
+                  map_contents shift  13
+                           map shift  16
+                         value shift  8
 
 State 5:
-          map_contents ::= value COLON * value
-          map_contents ::= value COLON * value COMMA map_contents
           list ::= * CURLY_OPEN CURLY_CLOSE
           list ::= * CURLY_OPEN list_contents CURLY_CLOSE
+          map_contents ::= value COLON * value
+          map_contents ::= value COLON * value COMMA map_contents
           map ::= * BRACKET_OPEN BRACKET_CLOSE
           map ::= * BRACKET_OPEN map_contents BRACKET_CLOSE
           value ::= * STRING
           value ::= * list
           value ::= * map
 
-                        STRING shift  16
                     CURLY_OPEN shift  1
                   BRACKET_OPEN shift  2
-                          list shift  17
-                           map shift  18
-                         value shift  11
+                        STRING shift  14
+                          list shift  15
+                           map shift  16
+                         value shift  9
 
 State 6:
-      (0) input ::= STRING *
+      (0) input ::= value *
 
                              $ reduce 0
 
 State 7:
-      (1) input ::= list *
-
-                             $ reduce 1
-
-State 8:
-      (2) input ::= map *
-
-                             $ reduce 2
-
-State 9:
-      (3) list_contents ::= value *
+      (1) list_contents ::= value *
           list_contents ::= value * COMMA list_contents
 
                          COMMA shift  3
-                     {default} reduce 3
+                     {default} reduce 1
 
-State 10:
+State 8:
           map_contents ::= value * COLON value
           map_contents ::= value * COLON value COMMA map_contents
 
                          COLON shift  5
 
-State 11:
+State 9:
       (5) map_contents ::= value COLON value *
           map_contents ::= value COLON value * COMMA map_contents
 
                          COMMA shift  4
                      {default} reduce 5
 
-State 12:
+State 10:
           map ::= BRACKET_OPEN map_contents * BRACKET_CLOSE
 
-                 BRACKET_CLOSE shift  20
+                 BRACKET_CLOSE shift  18
 
-State 13:
+State 11:
           list ::= CURLY_OPEN list_contents * CURLY_CLOSE
 
-                   CURLY_CLOSE shift  22
+                   CURLY_CLOSE shift  20
 
-State 14:
-      (4) list_contents ::= value COMMA list_contents *
+State 12:
+      (2) list_contents ::= value COMMA list_contents *
 
-                     {default} reduce 4
+                     {default} reduce 2
 
-State 15:
+State 13:
       (6) map_contents ::= value COLON value COMMA map_contents *
 
                      {default} reduce 6
 
+State 14:
+      (9) value ::= STRING *
+
+                     {default} reduce 9
+
+State 15:
+     (10) value ::= list *
+
+                     {default} reduce 10
+
 State 16:
-     (11) value ::= STRING *
+     (11) value ::= map *
 
                      {default} reduce 11
 
 State 17:
-     (12) value ::= list *
+      (7) map ::= BRACKET_OPEN BRACKET_CLOSE *
 
-                     {default} reduce 12
+                     {default} reduce 7
 
 State 18:
-     (13) value ::= map *
+      (8) map ::= BRACKET_OPEN map_contents BRACKET_CLOSE *
 
-                     {default} reduce 13
+                     {default} reduce 8
 
 State 19:
-      (9) map ::= BRACKET_OPEN BRACKET_CLOSE *
+      (3) list ::= CURLY_OPEN CURLY_CLOSE *
 
-                     {default} reduce 9
+                     {default} reduce 3
 
 State 20:
-     (10) map ::= BRACKET_OPEN map_contents BRACKET_CLOSE *
-
-                     {default} reduce 10
-
-State 21:
-      (7) list ::= CURLY_OPEN CURLY_CLOSE *
-
-                     {default} reduce 7
+      (4) list ::= CURLY_OPEN list_contents CURLY_CLOSE *
 
-State 22:
-      (8) list ::= CURLY_OPEN list_contents CURLY_CLOSE *
-
-                     {default} reduce 8
+                     {default} reduce 4
 
 ----------------------------------------------------
 Symbols:
     0: $:
-    1: STRING
-    2: COMMA
-    3: COLON
-    4: CURLY_OPEN
-    5: CURLY_CLOSE
-    6: BRACKET_OPEN
-    7: BRACKET_CLOSE
+    1: COMMA
+    2: CURLY_OPEN
+    3: CURLY_CLOSE
+    4: COLON
+    5: BRACKET_OPEN
+    6: BRACKET_CLOSE
+    7: STRING
     8: error:
-    9: list_contents: STRING CURLY_OPEN BRACKET_OPEN
+    9: list_contents: CURLY_OPEN BRACKET_OPEN STRING
    10: list: CURLY_OPEN
-   11: map_contents: STRING CURLY_OPEN BRACKET_OPEN
+   11: map_contents: CURLY_OPEN BRACKET_OPEN STRING
    12: map: BRACKET_OPEN
-   13: value: STRING CURLY_OPEN BRACKET_OPEN
-   14: input: STRING CURLY_OPEN BRACKET_OPEN
+   13: value: CURLY_OPEN BRACKET_OPEN STRING
+   14: input: CURLY_OPEN BRACKET_OPEN STRING

+ 131 - 102
generated/NCDValueParser_parse.y

@@ -27,51 +27,23 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-%include {
+%extra_argument { struct parser_state *parser_out }
 
-#include <string.h>
-#include <stddef.h>
+%token_type { struct token }
 
-#include <misc/debug.h>
-#include <ncd/NCDConfig.h>
+%token_destructor { free_token($$); }
 
-#define AST_TYPE_NONE 0
-#define AST_TYPE_STRING 1
-#define AST_TYPE_LIST 2
-#define AST_TYPE_MAP 3
+%type list_contents { struct value }
+%type list { struct value }
+%type map_contents { struct value }
+%type map  { struct value }
+%type value  { struct value }
 
-struct parser_minor {
-    char *str;
-    size_t len;
-};
-
-struct parser_out {
-    int out_of_memory;
-    int syntax_error;
-    int ast_type;
-    struct parser_minor ast_string;
-    struct NCDConfig_list *ast_list;
-};
-
-}
-
-%extra_argument {struct parser_out *parser_out}
-
-%token_type {struct parser_minor}
-
-%token_destructor { free($$.str); }
-
-%type list_contents {struct NCDConfig_list *}
-%type list {struct NCDConfig_list *}
-%type map_contents {struct NCDConfig_list *}
-%type map {struct NCDConfig_list *}
-%type value {struct NCDConfig_list *}
-
-%destructor list_contents { NCDConfig_free_list($$); }
-%destructor list { NCDConfig_free_list($$); }
-%destructor map_contents { NCDConfig_free_list($$); }
-%destructor map { NCDConfig_free_list($$); }
-%destructor value { NCDConfig_free_list($$); }
+%destructor list_contents { free_value($$); }
+%destructor list { free_value($$); }
+%destructor map_contents { free_value($$); }
+%destructor map { free_value($$); }
+%destructor value { free_value($$); }
 
 %stack_size 0
 
@@ -82,83 +54,136 @@ struct parser_out {
 // workaroud Lemon bug: if the stack overflows, the token that caused the overflow will be leaked
 %stack_overflow {
     if (yypMinor) {
-        free(yypMinor->yy0.str);
+        free_token(yypMinor->yy0);
     }
 }
 
-input ::= STRING(A). {
-    ASSERT(parser_out->ast_type == AST_TYPE_NONE)
-
-    parser_out->ast_string = A;
-    parser_out->ast_type = AST_TYPE_STRING;
+input ::= value(A). {
+    if (!A.have || parser_out->have_value) {
+        free_value(A);
+    } else {
+        parser_out->have_value = 1;
+        parser_out->value = A.v;
+    }
 }
 
-input ::= list(A). {
-    ASSERT(parser_out->ast_type == AST_TYPE_NONE)
+list_contents(R) ::= value(A). {
+    if (!A.have) {
+        goto failL0;
+    }
 
-    parser_out->ast_list = A;
-    parser_out->ast_type = AST_TYPE_LIST;
-}
+    NCDValue_InitList(&R.v);
 
-input ::= map(A). {
-    ASSERT(parser_out->ast_type == AST_TYPE_NONE)
+    if (!NCDValue_ListPrepend(&R.v, A.v)) {
+        goto failL1;
+    }
+    A.have = 0;
 
-    parser_out->ast_list = A;
-    parser_out->ast_type = AST_TYPE_MAP;
-}
+    R.have = 1;
+    goto doneL;
 
-list_contents(R) ::= value(A). {
-    R = A;
+failL1:
+    NCDValue_Free(&R.v);
+failL0:
+    R.have = 0;
+    parser_out->out_of_memory = 1;
+doneL:
+    free_value(A);
 }
 
 list_contents(R) ::= value(A) COMMA list_contents(N). {
-    if (!A) {
-        NCDConfig_free_list(N);
-    } else {
-        ASSERT(!A->next)
-        A->next = N;
+    if (!A.have || !N.have) {
+        goto failM0;
     }
+
+    if (!NCDValue_ListPrepend(&N.v, A.v)) {
+        goto failM0;
+    }
+    A.have = 0;
+
+    R.have = 1;
+    R.v = N.v;
+    N.have = 0;
+    goto doneM;
+
+failM0:
+    R.have = 0;
+    parser_out->out_of_memory = 1;
+doneM:
+    free_value(A);
+    free_value(N);
+}
+
+list(R) ::= CURLY_OPEN CURLY_CLOSE. {
+    R.have = 1;
+    NCDValue_InitList(&R.v);
+}
+
+list(R) ::= CURLY_OPEN list_contents(A) CURLY_CLOSE. {
     R = A;
 }
 
 map_contents(R) ::= value(A) COLON value(B). {
-    if (!A || !B) {
-        NCDConfig_free_list(A);
-        NCDConfig_free_list(B);
-        R = NULL;
-    } else {
-        ASSERT(!A->next)
-        ASSERT(!B->next)
-        A->next = B;
-        R = A;
+    if (!A.have || !B.have) {
+        goto failS0;
+    }
+
+    NCDValue_InitMap(&R.v);
+
+    if (!NCDValue_MapInsert(&R.v, A.v, B.v)) {
+        goto failS1;
     }
+    A.have = 0;
+    B.have = 0;
+
+    R.have = 1;
+    goto doneS;
+
+failS1:
+    NCDValue_Free(&R.v);
+failS0:
+    R.have = 0;
+    parser_out->out_of_memory = 1;
+doneS:
+    free_value(A);
+    free_value(B);
 }
 
 map_contents(R) ::= value(A) COLON value(B) COMMA map_contents(N). {
-    if (!A || !B) {
-        NCDConfig_free_list(A);
-        NCDConfig_free_list(B);
-        NCDConfig_free_list(N);
-        R = NULL;
-    } else {
-        ASSERT(!A->next)
-        ASSERT(!B->next)
-        A->next = B;
-        B->next = N;
-        R = A;
+    if (!A.have || !B.have || !N.have) {
+        goto failT0;
     }
-}
 
-list(R) ::= CURLY_OPEN CURLY_CLOSE. {
-    R = NULL;
-}
+    if (NCDValue_MapFindKey(&N.v, &A.v)) {
+        BLog(BLOG_ERROR, "duplicate key in map");
+        R.have = 0;
+        parser_out->syntax_error = 1;
+        goto doneT;
+    }
 
-list(R) ::= CURLY_OPEN list_contents(A) CURLY_CLOSE. {
-    R = A;
+    if (!NCDValue_MapInsert(&N.v, A.v, B.v)) {
+        goto failT0;
+    }
+    A.have = 0;
+    B.have = 0;
+
+    R.have = 1;
+    R.v = N.v;
+    N.have = 0;
+    goto doneT;
+
+failT0:
+    R.have = 0;
+    parser_out->out_of_memory = 1;
+doneT:
+    free_value(A);
+    free_value(B);
+    free_value(N);
 }
 
 map(R) ::= BRACKET_OPEN BRACKET_CLOSE. {
-    R = NULL;
+    R.have = 1;
+    NCDValue_InitMap(&R.v);
 }
 
 map(R) ::= BRACKET_OPEN map_contents(A) BRACKET_CLOSE. {
@@ -166,22 +191,26 @@ map(R) ::= BRACKET_OPEN map_contents(A) BRACKET_CLOSE. {
 }
 
 value(R) ::= STRING(A). {
-    R = NCDConfig_make_list_string(A.str, A.len, NULL);
-    if (!R) {
-        parser_out->out_of_memory = 1;
+    ASSERT(A.str)
+
+    if (!NCDValue_InitStringBin(&R.v, (uint8_t *)A.str, A.len)) {
+        goto failU0;
     }
+
+    R.have = 1;
+    goto doneU;
+
+failU0:
+    R.have = 0;
+    parser_out->out_of_memory = 1;
+doneU:
+    free_token(A);
 }
 
 value(R) ::= list(A). {
-    R = NCDConfig_make_list_list(A, NULL);
-    if (!R) {
-        parser_out->out_of_memory = 1;
-    }
+    R = A;
 }
 
 value(R) ::= map(A). {
-    R = NCDConfig_make_list_maplist(A, NULL);
-    if (!R) {
-        parser_out->out_of_memory = 1;
-    }
+    R = A;
 }

+ 61 - 171
ncd/NCDValueParser.c

@@ -31,7 +31,6 @@
 #include <stdlib.h>
 #include <string.h>
 
-#include <misc/debug.h>
 #include <base/BLog.h>
 #include <ncd/NCDConfigTokenizer.h>
 #include <ncd/NCDValCompat.h>
@@ -40,6 +39,37 @@
 
 #include <generated/blog_channel_NCDValueParser.h>
 
+struct token {
+    char *str;
+    size_t len;
+};
+
+struct value {
+    int have;
+    NCDValue v;
+};
+
+struct parser_state {
+    int have_value;
+    NCDValue value;
+    int out_of_memory;
+    int syntax_error;
+    int error;
+    void *parser;
+};
+
+static void free_token (struct token o)
+{
+    free(o.str);
+};
+
+static void free_value (struct value o)
+{
+    if (o.have) {
+        NCDValue_Free(&o.v);
+    }
+}
+
 // rename non-static functions defined by our Lemon parser
 // to avoid clashes with other Lemon parsers
 #define ParseTrace ParseTrace_NCDValueParser
@@ -50,22 +80,11 @@
 #include "../generated/NCDValueParser_parse.c"
 #include "../generated/NCDValueParser_parse.h"
 
-struct parser_state {
-    struct parser_out out;
-    int error;
-    void *parser;
-};
-
-static int tokenizer_output (void *user, int token, char *value, size_t value_len, size_t line, size_t line_char);
-static int build_value (struct NCDConfig_list *ast, NCDValue *out);
-static int build_list_value (struct NCDConfig_list *list, NCDValue *out);
-static int build_map_value (struct NCDConfig_list *list, NCDValue *out);
-
 static int tokenizer_output (void *user, int token, char *value, size_t value_len, size_t line, size_t line_char)
 {
     struct parser_state *state = user;
-    ASSERT(!state->out.out_of_memory)
-    ASSERT(!state->out.syntax_error)
+    ASSERT(!state->out_of_memory)
+    ASSERT(!state->syntax_error)
     ASSERT(!state->error)
     
     if (token == NCD_ERROR) {
@@ -73,55 +92,55 @@ static int tokenizer_output (void *user, int token, char *value, size_t value_le
         goto fail;
     }
     
-    struct parser_minor minor;
+    struct token minor;
     minor.str = value;
     minor.len = value_len;
     
     switch (token) {
         case NCD_EOF: {
-            Parse(state->parser, 0, minor, &state->out);
+            Parse(state->parser, 0, minor, state);
         } break;
         
         case NCD_TOKEN_CURLY_OPEN: {
-            Parse(state->parser, CURLY_OPEN, minor, &state->out);
+            Parse(state->parser, CURLY_OPEN, minor, state);
         } break;
         
         case NCD_TOKEN_CURLY_CLOSE: {
-            Parse(state->parser, CURLY_CLOSE, minor, &state->out);
+            Parse(state->parser, CURLY_CLOSE, minor, state);
         } break;
         
         case NCD_TOKEN_COMMA: {
-            Parse(state->parser, COMMA, minor, &state->out);
+            Parse(state->parser, COMMA, minor, state);
         } break;
         
         case NCD_TOKEN_STRING: {
-            Parse(state->parser, STRING, minor, &state->out);
+            Parse(state->parser, STRING, minor, state);
         } break;
         
         case NCD_TOKEN_COLON: {
-            Parse(state->parser, COLON, minor, &state->out);
+            Parse(state->parser, COLON, minor, state);
         } break;
         
         case NCD_TOKEN_BRACKET_OPEN: {
-            Parse(state->parser, BRACKET_OPEN, minor, &state->out);
+            Parse(state->parser, BRACKET_OPEN, minor, state);
         } break;
         
         case NCD_TOKEN_BRACKET_CLOSE: {
-            Parse(state->parser, BRACKET_CLOSE, minor, &state->out);
+            Parse(state->parser, BRACKET_CLOSE, minor, state);
         } break;
         
         default:
             BLog(BLOG_ERROR, "line %zu, character %zu: invalid token", line, line_char);
-            free(minor.str);
+            free_token(minor);
             goto fail;
     }
     
-    if (state->out.syntax_error) {
+    if (state->syntax_error) {
         BLog(BLOG_ERROR, "line %zu, character %zu: syntax error", line, line_char);
         goto fail;
     }
     
-    if (state->out.out_of_memory) {
+    if (state->out_of_memory) {
         BLog(BLOG_ERROR, "line %zu, character %zu: out of memory", line, line_char);
         goto fail;
     }
@@ -133,171 +152,42 @@ fail:
     return 0;
 }
 
-static int build_value (struct NCDConfig_list *ast, NCDValue *out)
-{
-    switch (ast->type) {
-        case NCDCONFIG_ARG_STRING: {
-            if (!NCDValue_InitStringBin(out, (uint8_t *)ast->string, ast->string_len)) {
-                BLog(BLOG_ERROR, "NCDValue_InitStringBin failed");
-                return 0;
-            }
-        } break;
-        
-        case NCDCONFIG_ARG_LIST: {
-            if (!build_list_value(ast->list, out)) {
-                return 0;
-            }
-        } break;
-        
-        case NCDCONFIG_ARG_MAPLIST: {
-            if (!build_map_value(ast->list, out)) {
-                return 0;
-            }
-        } break;
-        
-        default: ASSERT(0);
-    }
-    
-    return 1;
-}
-
-static int build_list_value (struct NCDConfig_list *list, NCDValue *out)
-{
-    NCDValue list_val;
-    NCDValue_InitList(&list_val);
-    
-    for (struct NCDConfig_list *elem = list; elem; elem = elem->next) {
-        NCDValue v;
-        
-        if (!build_value(elem, &v)) {
-            goto fail;
-        }
-        
-        if (!NCDValue_ListAppend(&list_val, v)) {
-            BLog(BLOG_ERROR, "NCDValue_ListAppend failed");
-            NCDValue_Free(&v);
-            goto fail;
-        }
-    }
-    
-    *out = list_val;
-    return 1;
-    
-fail:
-    NCDValue_Free(&list_val);
-    return 0;
-}
-
-static int build_map_value (struct NCDConfig_list *list, NCDValue *out)
-{
-    NCDValue map_val;
-    NCDValue_InitMap(&map_val);
-    
-    for (struct NCDConfig_list *elem = list; elem; elem = elem->next->next) {
-        ASSERT(elem->next)
-        
-        NCDValue key;
-        NCDValue val;
-        
-        if (!build_value(elem, &key)) {
-            goto fail;
-        }
-        
-        if (!build_value(elem->next, &val)) {
-            NCDValue_Free(&key);
-            goto fail;
-        }
-        
-        if (NCDValue_MapFindKey(&map_val, &key)) {
-            BLog(BLOG_ERROR, "duplicate map keys");
-            NCDValue_Free(&key);
-            NCDValue_Free(&val);
-            goto fail;
-        }
-        
-        if (!NCDValue_MapInsert(&map_val, key, val)) {
-            BLog(BLOG_ERROR, "NCDValue_MapInsert failed");
-            NCDValue_Free(&key);
-            NCDValue_Free(&val);
-            goto fail;
-        }
-    }
-    
-    *out = map_val;
-    return 1;
-    
-fail:
-    NCDValue_Free(&map_val);
-    return 0;
-}
-
 int NCDValueParser_Parse (const char *str, size_t str_len, NCDValue *out_value)
 {
-    int res = 0;
+    ASSERT(str_len == 0 || str)
+    ASSERT(out_value)
     
-    // init parse state
     struct parser_state state;
-    state.out.out_of_memory = 0;
-    state.out.syntax_error = 0;
-    state.out.ast_type = AST_TYPE_NONE;
-    state.out.ast_string.str = NULL;
-    state.out.ast_list = NULL;
+    state.have_value = 0;
+    state.out_of_memory = 0;
+    state.syntax_error = 0;
     state.error = 0;
     
-    // allocate parser
     if (!(state.parser = ParseAlloc(malloc))) {
         BLog(BLOG_ERROR, "ParseAlloc failed");
-        goto out;
+        return 0;
     }
     
-    // tokenize and parse
     NCDConfigTokenizer_Tokenize((char *)str, str_len, tokenizer_output, &state);
     
-    // check for errors
-    if (state.error) {
-        goto out;
-    }
-    
-    ASSERT(state.out.ast_type == AST_TYPE_STRING || state.out.ast_type == AST_TYPE_LIST ||
-           state.out.ast_type == AST_TYPE_MAP)
+    ParseFree(state.parser, free);
     
-    // convert AST to value
-    NCDValue val;
-    switch (state.out.ast_type) {
-        case AST_TYPE_STRING: {
-            if (!NCDValue_InitStringBin(&val, (uint8_t *)state.out.ast_string.str, state.out.ast_string.len)) {
-                BLog(BLOG_ERROR, "NCDValue_InitStringBin failed");
-                goto out;
-            }
-        } break;
-        
-        case AST_TYPE_LIST: {
-            if (!build_list_value(state.out.ast_list, &val)) {
-                goto out;
-            }
-        } break;
-        
-        case AST_TYPE_MAP: {
-            if (!build_map_value(state.out.ast_list, &val)) {
-                goto out;
-            }
-        } break;
+    if (state.error) {
+        if (state.have_value) {
+            NCDValue_Free(&state.value);
+        }
+        return 0;
     }
     
-    *out_value = val;
-    res = 1;
+    ASSERT(state.have_value)
     
-out:
-    if (state.parser) {
-        ParseFree(state.parser, free);
-    }
-    free(state.out.ast_string.str);
-    NCDConfig_free_list(state.out.ast_list);
-    return res;
+    *out_value = state.value;
+    return 1;
 }
 
 int NCDValParser_Parse (const char *str, size_t str_len, NCDValMem *mem, NCDValRef *out_value)
 {
+    ASSERT(str_len == 0 || str)
     ASSERT(mem)
     ASSERT(out_value)
     

+ 131 - 102
ncd/NCDValueParser_parse.y

@@ -27,51 +27,23 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-%include {
+%extra_argument { struct parser_state *parser_out }
 
-#include <string.h>
-#include <stddef.h>
+%token_type { struct token }
 
-#include <misc/debug.h>
-#include <ncd/NCDConfig.h>
+%token_destructor { free_token($$); }
 
-#define AST_TYPE_NONE 0
-#define AST_TYPE_STRING 1
-#define AST_TYPE_LIST 2
-#define AST_TYPE_MAP 3
+%type list_contents { struct value }
+%type list { struct value }
+%type map_contents { struct value }
+%type map  { struct value }
+%type value  { struct value }
 
-struct parser_minor {
-    char *str;
-    size_t len;
-};
-
-struct parser_out {
-    int out_of_memory;
-    int syntax_error;
-    int ast_type;
-    struct parser_minor ast_string;
-    struct NCDConfig_list *ast_list;
-};
-
-}
-
-%extra_argument {struct parser_out *parser_out}
-
-%token_type {struct parser_minor}
-
-%token_destructor { free($$.str); }
-
-%type list_contents {struct NCDConfig_list *}
-%type list {struct NCDConfig_list *}
-%type map_contents {struct NCDConfig_list *}
-%type map {struct NCDConfig_list *}
-%type value {struct NCDConfig_list *}
-
-%destructor list_contents { NCDConfig_free_list($$); }
-%destructor list { NCDConfig_free_list($$); }
-%destructor map_contents { NCDConfig_free_list($$); }
-%destructor map { NCDConfig_free_list($$); }
-%destructor value { NCDConfig_free_list($$); }
+%destructor list_contents { free_value($$); }
+%destructor list { free_value($$); }
+%destructor map_contents { free_value($$); }
+%destructor map { free_value($$); }
+%destructor value { free_value($$); }
 
 %stack_size 0
 
@@ -82,83 +54,136 @@ struct parser_out {
 // workaroud Lemon bug: if the stack overflows, the token that caused the overflow will be leaked
 %stack_overflow {
     if (yypMinor) {
-        free(yypMinor->yy0.str);
+        free_token(yypMinor->yy0);
     }
 }
 
-input ::= STRING(A). {
-    ASSERT(parser_out->ast_type == AST_TYPE_NONE)
-
-    parser_out->ast_string = A;
-    parser_out->ast_type = AST_TYPE_STRING;
+input ::= value(A). {
+    if (!A.have || parser_out->have_value) {
+        free_value(A);
+    } else {
+        parser_out->have_value = 1;
+        parser_out->value = A.v;
+    }
 }
 
-input ::= list(A). {
-    ASSERT(parser_out->ast_type == AST_TYPE_NONE)
+list_contents(R) ::= value(A). {
+    if (!A.have) {
+        goto failL0;
+    }
 
-    parser_out->ast_list = A;
-    parser_out->ast_type = AST_TYPE_LIST;
-}
+    NCDValue_InitList(&R.v);
 
-input ::= map(A). {
-    ASSERT(parser_out->ast_type == AST_TYPE_NONE)
+    if (!NCDValue_ListPrepend(&R.v, A.v)) {
+        goto failL1;
+    }
+    A.have = 0;
 
-    parser_out->ast_list = A;
-    parser_out->ast_type = AST_TYPE_MAP;
-}
+    R.have = 1;
+    goto doneL;
 
-list_contents(R) ::= value(A). {
-    R = A;
+failL1:
+    NCDValue_Free(&R.v);
+failL0:
+    R.have = 0;
+    parser_out->out_of_memory = 1;
+doneL:
+    free_value(A);
 }
 
 list_contents(R) ::= value(A) COMMA list_contents(N). {
-    if (!A) {
-        NCDConfig_free_list(N);
-    } else {
-        ASSERT(!A->next)
-        A->next = N;
+    if (!A.have || !N.have) {
+        goto failM0;
     }
+
+    if (!NCDValue_ListPrepend(&N.v, A.v)) {
+        goto failM0;
+    }
+    A.have = 0;
+
+    R.have = 1;
+    R.v = N.v;
+    N.have = 0;
+    goto doneM;
+
+failM0:
+    R.have = 0;
+    parser_out->out_of_memory = 1;
+doneM:
+    free_value(A);
+    free_value(N);
+}
+
+list(R) ::= CURLY_OPEN CURLY_CLOSE. {
+    R.have = 1;
+    NCDValue_InitList(&R.v);
+}
+
+list(R) ::= CURLY_OPEN list_contents(A) CURLY_CLOSE. {
     R = A;
 }
 
 map_contents(R) ::= value(A) COLON value(B). {
-    if (!A || !B) {
-        NCDConfig_free_list(A);
-        NCDConfig_free_list(B);
-        R = NULL;
-    } else {
-        ASSERT(!A->next)
-        ASSERT(!B->next)
-        A->next = B;
-        R = A;
+    if (!A.have || !B.have) {
+        goto failS0;
+    }
+
+    NCDValue_InitMap(&R.v);
+
+    if (!NCDValue_MapInsert(&R.v, A.v, B.v)) {
+        goto failS1;
     }
+    A.have = 0;
+    B.have = 0;
+
+    R.have = 1;
+    goto doneS;
+
+failS1:
+    NCDValue_Free(&R.v);
+failS0:
+    R.have = 0;
+    parser_out->out_of_memory = 1;
+doneS:
+    free_value(A);
+    free_value(B);
 }
 
 map_contents(R) ::= value(A) COLON value(B) COMMA map_contents(N). {
-    if (!A || !B) {
-        NCDConfig_free_list(A);
-        NCDConfig_free_list(B);
-        NCDConfig_free_list(N);
-        R = NULL;
-    } else {
-        ASSERT(!A->next)
-        ASSERT(!B->next)
-        A->next = B;
-        B->next = N;
-        R = A;
+    if (!A.have || !B.have || !N.have) {
+        goto failT0;
     }
-}
 
-list(R) ::= CURLY_OPEN CURLY_CLOSE. {
-    R = NULL;
-}
+    if (NCDValue_MapFindKey(&N.v, &A.v)) {
+        BLog(BLOG_ERROR, "duplicate key in map");
+        R.have = 0;
+        parser_out->syntax_error = 1;
+        goto doneT;
+    }
 
-list(R) ::= CURLY_OPEN list_contents(A) CURLY_CLOSE. {
-    R = A;
+    if (!NCDValue_MapInsert(&N.v, A.v, B.v)) {
+        goto failT0;
+    }
+    A.have = 0;
+    B.have = 0;
+
+    R.have = 1;
+    R.v = N.v;
+    N.have = 0;
+    goto doneT;
+
+failT0:
+    R.have = 0;
+    parser_out->out_of_memory = 1;
+doneT:
+    free_value(A);
+    free_value(B);
+    free_value(N);
 }
 
 map(R) ::= BRACKET_OPEN BRACKET_CLOSE. {
-    R = NULL;
+    R.have = 1;
+    NCDValue_InitMap(&R.v);
 }
 
 map(R) ::= BRACKET_OPEN map_contents(A) BRACKET_CLOSE. {
@@ -166,22 +191,26 @@ map(R) ::= BRACKET_OPEN map_contents(A) BRACKET_CLOSE. {
 }
 
 value(R) ::= STRING(A). {
-    R = NCDConfig_make_list_string(A.str, A.len, NULL);
-    if (!R) {
-        parser_out->out_of_memory = 1;
+    ASSERT(A.str)
+
+    if (!NCDValue_InitStringBin(&R.v, (uint8_t *)A.str, A.len)) {
+        goto failU0;
     }
+
+    R.have = 1;
+    goto doneU;
+
+failU0:
+    R.have = 0;
+    parser_out->out_of_memory = 1;
+doneU:
+    free_token(A);
 }
 
 value(R) ::= list(A). {
-    R = NCDConfig_make_list_list(A, NULL);
-    if (!R) {
-        parser_out->out_of_memory = 1;
-    }
+    R = A;
 }
 
 value(R) ::= map(A). {
-    R = NCDConfig_make_list_maplist(A, NULL);
-    if (!R) {
-        parser_out->out_of_memory = 1;
-    }
+    R = A;
 }