very temporary work on the new generation of config parser.
[apps/madmutt.git] / rcparser.y
diff --git a/rcparser.y b/rcparser.y
new file mode 100644 (file)
index 0000000..b63ab9a
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+ *  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; either version 2 of the License, or (at
+ *  your option) any later version.
+ *
+ *  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 Street, Fifth Floor, Boston,
+ *  MA 02110-1301, USA.
+ *
+ *  Copyright © 2006 Pierre Habouzit
+ */
+
+%include {
+#   include "mutt.h"
+#   include "parse.h"
+
+    static buffer_t *buffer_merge(buffer_t *A, buffer_t **B)
+    {
+        buffer_addbuf(A, *B);
+        buffer_delete(B);
+        return A;
+    }
+
+    static inline int to_control(int c) {
+        return (toupper((unsigned char)c) - 'A' + 1) & 0x7f;
+    }
+
+    static buffer_t *buffer_escape(buffer_t *buf, const char *s, ssize_t len)
+    {
+        assert (len > 0);
+
+        switch (*s) {
+          case 'c': case 'C':
+            if (len < 2)
+                break;
+            buffer_addch(buf, to_control(s[1]));
+            buffer_add(buf, s + 2, len - 2);
+            return buf;
+
+          case 'x':
+            if (len >= 3) {
+                int i = (hexval(s[1]) << 4) | hexval(s[2]);
+                if (i >= 0) {
+                    buffer_addch(buf, i);
+                    buffer_add(buf, s + 3, len - 3);
+                    return buf;
+                }
+            }
+            break;
+
+          case '0': case '1': case '2': case '3':
+            if (len >= 3) {
+                int i = (octval(s[0]) << 6) | (octval(s[1]) << 3) | octval(s[2]);
+                if (i >= 0) {
+                    buffer_addch(buf, i);
+                    buffer_add(buf, s + 3, len - 3);
+                    return buf;
+                }
+            }
+            break;
+
+          case 'e': buffer_addch(buf, '\e'); return buf;
+          case 'f': buffer_addch(buf, '\f'); return buf;
+          case 'n': buffer_addch(buf, '\n'); return buf;
+          case 'r': buffer_addch(buf, '\r'); return buf;
+          case 't': buffer_addch(buf, '\t'); return buf;
+          case 'v': buffer_addch(buf, '\v'); return buf;
+
+          default:
+            break;
+        }
+
+        buffer_add(buf, s, len);
+        return buf;
+    }
+}
+
+%token_prefix RCTK_
+%token_type  { segment }
+%start_symbol rc
+
+/****************************************************************************/
+/* Often used                                                               */
+/****************************************************************************/
+
+spaces ::= SPACE .
+spaces ::= spaces SPACE .
+
+non_nl ::= ATOM|SPACE|BANG|BQUOTE|BSLASH|SHARP|DOLLAR|DQUOTE|EQUAL|LBRACE|PIPE|QUOTE|RBRACE|TILDE .
+non_nl_star ::= .
+non_nl_star ::= non_nl_star non_nl .
+
+to_eol ::= NL .
+to_eol ::= SHARP non_nl_star NL .
+to_eol ::= spaces SHARP non_nl_star NL .
+
+
+/****************************************************************************/
+/* Our macro tokens                                                         */
+/****************************************************************************/
+
+%type sqtok { buffer_t* }
+sqtok(C) ::= .                                 { C = buffer_new(); }
+sqtok(C) ::= sqtok(A) BSLASH BSLASH|QUOTE(B) . { buffer_addch(C = A, *B.s); }
+sqtok(C) ::= sqtok(A) BSLASH ATOM|SPACE|BANG|BQUOTE|SHARP|DOLLAR|DQUOTE|EQUAL|LBRACE|PIPE|RBRACE|TILDE(B) . {
+    buffer_addch(C = A, '\\');
+    buffer_add(C, B.s, B.len);
+}
+sqtok(C) ::= sqtok(A) ATOM|SPACE|BANG|BQUOTE|SHARP|DOLLAR|DQUOTE|EQUAL|LBRACE|PIPE|RBRACE|TILDE(B) . {
+    buffer_add(C = A, B.s, B.len);
+}
+
+%type dqtok { buffer_t* }
+dqtok(C) ::= .                           { C = buffer_new(); }
+dqtok(C) ::= dqtok(A) BSLASH non_nl(T) . { C = buffer_escape(A, T.s, T.len); }
+dqtok(C) ::= dqtok(A) ATOM|SPACE|BANG|SHARP|EQUAL|LBRACE|PIPE|RBRACE|TILDE(T)  . {
+    buffer_add(C = A, T.s, T.len);
+}
+
+%type tok   { buffer_t* }
+tok(R) ::= ATOM|BANG|EQUAL|PIPE|TILDE(T) . {
+    R = buffer_new();
+    buffer_add(R, T.s, T.len);
+}
+tok(R) ::= BSLASH non_nl(T) .          { R = buffer_new(); buffer_add(R, T.s, T.len); }
+tok(R) ::= QUOTE  sqtok(T) QUOTE .     { R = T; }
+tok(R) ::= DQUOTE dqtok(T) DQUOTE .    { R = T; }
+
+%type token_acc { buffer_t* }
+token_acc(A) ::= tok(T) . { A = T; }
+token_acc(C) ::= token_acc(A) tok(B) . { C = buffer_merge(A, &B); }
+
+%type token { buffer_t* }
+token(R) ::= spaces token_acc(T) . { R = T; }
+
+
+/****************************************************************************/
+/* list of tokens                                                           */
+/****************************************************************************/
+
+%type simple_list { string_list_t * }
+simple_list    ::= .
+simple_list(L) ::= simple_list(A) token(B) . {
+    string_list_t **last = string_list_last(&A);
+    *last = string_item_new();
+    (*last)->data = buffer_unwrap(&B);
+    L = A;
+}
+
+
+/****************************************************************************/
+/* Entry point : the rc lines                                               */
+/****************************************************************************/
+
+rc ::= rclines .
+rclines ::= .
+rclines ::= rclines rcline .
+
+rcline ::= to_eol .
+rcline ::= ALT_ORDER simple_list(L) to_eol . {
+    string_list_append(&AlternativeOrderList, L);
+}
+
+
+/* vim: set indentexpr= cin: */