Adjustments of the language, added copyright notice and license information, ...
[liboconfig.git] / src / parser.y
index 911363c..6d1de2d 100644 (file)
@@ -1,32 +1,35 @@
+/**
+ * oconfig - src/parser.y
+ * Copyright (C) 2007  Florian octo Forster <octo at verplant.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; only version 2 of the License is applicable.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
 %{
 #include <stdlib.h>
 #include <string.h>
 #include "oconfig.h"
+#include "aux_types.h"
 
-static oconfig_item_t *ci_root;
-static oconfig_item_t *ci_current;
-
-static oconfig_item_t  *statement_list;
-static int              statement_list_num;
-
-static oconfig_value_t *argument_list;
-static int              argument_list_num;
-
-struct statement_list_s
-{
-       oconfig_item_t *statement;
-       int             statement_num;
-};
-typedef struct statement_list_s statement_list_t;
+static char *unquote (const char *orig);
+static int yyerror (const char *s);
 
-struct argument_list_s
-{
-       oconfig_value_t *argument;
-       int              argument_num;
-};
-typedef struct argument_list_s argument_list_t;
+/* Lexer variables */
+extern int yylineno;
+extern char *yytext;
 
-static void dump_ci (oconfig_item_t *ci, int shift);
+extern oconfig_item_t *ci_root;
 %}
 
 %start entire_file
@@ -36,7 +39,6 @@ static void dump_ci (oconfig_item_t *ci, int shift);
        int     boolean;
        char   *string;
        oconfig_value_t  cv;
-       oconfig_value_t *cvp;
        oconfig_item_t   ci;
        argument_list_t  al;
        statement_list_t sl;
@@ -49,19 +51,23 @@ static void dump_ci (oconfig_item_t *ci, int shift);
 
 %type <string> string
 %type <string> identifier
-%type <string> block_end
+/* arguments */
 %type <cv> argument
 %type <al> argument_list
+/* blocks */
 %type <ci> block_begin
 %type <ci> block
+%type <string> block_end
+/* statements */
 %type <ci> option
 %type <ci> statement
 %type <sl> statement_list
+%type <ci> entire_file
 
 %%
 string:
-       QUOTED_STRING           {$$ = $1;}
-       | UNQUOTED_STRING       {$$ = $1;}
+       QUOTED_STRING           {$$ = unquote ($1);}
+       | UNQUOTED_STRING       {$$ = strdup ($1);}
        ;
 
 argument:
@@ -76,19 +82,19 @@ argument_list:
        {
         $$ = $1;
         $$.argument_num++;
-        $$.argument = realloc ($$.argument, $$.argument_num * sizeof (argument_list_t));
+        $$.argument = realloc ($$.argument, $$.argument_num * sizeof (oconfig_value_t));
         $$.argument[$$.argument_num-1] = $2;
        }
        | argument
        {
-        $$.argument = malloc (sizeof (argument_list_t));
+        $$.argument = malloc (sizeof (oconfig_value_t));
         $$.argument[0] = $1;
         $$.argument_num = 1;
        }
        ;
 
 identifier:
-       UNQUOTED_STRING                 {$$ = $1;}
+       UNQUOTED_STRING                 {$$ = strdup ($1);}
        ;
 
 option:
@@ -98,7 +104,6 @@ option:
         $$.key = $1;
         $$.values = $2.argument;
         $$.values_num = $2.argument_num;
-        printf ("Option `%s' has %i arguments\n", $$.key, $$.values_num);
        }
        ;
 
@@ -109,100 +114,107 @@ block_begin:
         $$.key = $2;
         $$.values = $3.argument;
         $$.values_num = $3.argument_num;
-        printf ("Begin block `%s'\n", $2);
        }
        ;
 
 block_end:
-       OPENBRAC SLASH identifier CLOSEBRAC EOL {$$ = $3; printf ("End block `%s'\n", $3);}
+       OPENBRAC SLASH identifier CLOSEBRAC EOL
+       {
+        $$ = $3;
+       }
        ;
 
 block:
        block_begin statement_list block_end
        {
         if (strcmp ($1.key, $3) != 0)
-               yyerror ("Block %s not closed..\n", $1);
+        {
+               printf ("block_begin = %s; block_end = %s;\n", $1.key, $3);
+               yyerror ("Block not closed..\n");
+               exit (1);
+        }
         $$ = $1;
         $$.children = $2.statement;
+        $$.children_num = $2.statement_num;
        }
        ;
 
 statement:
        option          {$$ = $1;}
        | block         {$$ = $1;}
-       | EOL           {/* ignore */}
+       | EOL           {$$.values_num = 0;}
        ;
 
 statement_list:
        statement_list statement
        {
         $$ = $1;
-        $$.statement_num++;
-        $$.statement = realloc ($$.statement, $$.statement_num * sizeof (statement_list_t));
-        $$.statement[$$.statement_num-1] = $2;
-        printf ("statement_list: length = %i\n", $$.statement_num);
+        if ($2.values_num > 0)
+        {
+                $$.statement_num++;
+                $$.statement = realloc ($$.statement, $$.statement_num * sizeof (oconfig_item_t));
+                $$.statement[$$.statement_num-1] = $2;
+        }
        }
        | statement
        {
-        $$.statement = malloc (sizeof (statement_list_t));
-        $$.statement[0] = $1;
-        $$.statement_num = 1;
+        if ($1.values_num > 0)
+        {
+                $$.statement = malloc (sizeof (oconfig_item_t));
+                $$.statement[0] = $1;
+                $$.statement_num = 1;
+        }
+        else
+        {
+               $$.statement = NULL;
+               $$.statement_num = 0;
+        }
        }
        ;
 
 entire_file:
        statement_list
        {
-        int i;
-        for (i = 0; i < $1.statement_num; i++)
-               dump_ci ($1.statement + i, 0);
+        ci_root = malloc (sizeof (oconfig_item_t));
+        memset (ci_root, '\0', sizeof (oconfig_item_t));
+        ci_root->children = $1.statement;
+        ci_root->children_num = $1.statement_num;
        }
        ;
 
 %%
-#include "lex.yy.c"
-
-/*
-void yyerror (char *s)
+static int yyerror (const char *s)
 {
-       fprintf (stderr, "%s\n", s);
-}
+       fprintf (stderr, "Error in line %i near `%s': %s\n", yylineno, yytext, s);
+       return (-1);
+} /* int yyerror */
 
-int yylex (void)
+static char *unquote (const char *orig)
 {
-       return (getc (stdin));
-}
-*/
+       char *ret = strdup (orig);
+       int len;
+       int i;
 
-int main (int argc, char **argv)
-{
-       yyparse ();
-       return (0);
-}
+       if (ret == NULL)
+               return (NULL);
 
-static void dump_ci (oconfig_item_t *ci, int shift)
-{
-       int i;
+       len = strlen (ret);
 
-       if (shift > 0)
-               printf ("%*s", "", shift);
+       if ((len < 2) || (ret[0] != '"') || (ret[len - 1] != '"'))
+               return (ret);
 
-       printf ("%s", ci->key);
-       for (i = 0; i < ci->values_num; i++)
+       ret++;
+       len -= 2;
+       ret[len] = '\0';
+
+       for (i = 0; i < len; i++)
        {
-               oconfig_value_t cv = ci->values[i];
-
-               if (cv.type == OCONFIG_TYPE_STRING)
-                       printf (" `%s'", cv.value.string);
-               else if (cv.type == OCONFIG_TYPE_NUMBER)
-                       printf (" %lf", cv.value.number);
-               else if (cv.type == OCONFIG_TYPE_BOOLEAN)
-                       printf (" %s", cv.value.boolean ? "true" : "false");
-               else
-                       printf ("<unknown type %i>", cv.type);
+               if (ret[i] == '\\')
+               {
+                       memmove (ret + i, ret + (i + 1), len - i);
+                       len--;
+               }
        }
-       printf ("\n");
 
-       for (i = 0; i < ci->children_num; i++)
-               dump_ci (ci->children + i, shift + 1);
-}
+       return (ret);
+} /* char *unquote */