config: import latest kconfig
[carl9170fw.git] / config / expr.c
index 2b85ddf65aba4fb9119101aa8e58230161b36554..290ce41f8ba46fcee2d61b6d7f3bd157593f4b66 100644 (file)
@@ -7,15 +7,13 @@
 #include <stdlib.h>
 #include <string.h>
 
 #include <stdlib.h>
 #include <string.h>
 
-#define LKC_DIRECT_LINK
 #include "lkc.h"
 
 #define DEBUG_EXPR     0
 
 struct expr *expr_alloc_symbol(struct symbol *sym)
 {
 #include "lkc.h"
 
 #define DEBUG_EXPR     0
 
 struct expr *expr_alloc_symbol(struct symbol *sym)
 {
-       struct expr *e = malloc(sizeof(*e));
-       memset(e, 0, sizeof(*e));
+       struct expr *e = calloc(1, sizeof(*e));
        e->type = E_SYMBOL;
        e->left.sym = sym;
        return e;
        e->type = E_SYMBOL;
        e->left.sym = sym;
        return e;
@@ -23,8 +21,7 @@ struct expr *expr_alloc_symbol(struct symbol *sym)
 
 struct expr *expr_alloc_one(enum expr_type type, struct expr *ce)
 {
 
 struct expr *expr_alloc_one(enum expr_type type, struct expr *ce)
 {
-       struct expr *e = malloc(sizeof(*e));
-       memset(e, 0, sizeof(*e));
+       struct expr *e = calloc(1, sizeof(*e));
        e->type = type;
        e->left.expr = ce;
        return e;
        e->type = type;
        e->left.expr = ce;
        return e;
@@ -32,8 +29,7 @@ struct expr *expr_alloc_one(enum expr_type type, struct expr *ce)
 
 struct expr *expr_alloc_two(enum expr_type type, struct expr *e1, struct expr *e2)
 {
 
 struct expr *expr_alloc_two(enum expr_type type, struct expr *e1, struct expr *e2)
 {
-       struct expr *e = malloc(sizeof(*e));
-       memset(e, 0, sizeof(*e));
+       struct expr *e = calloc(1, sizeof(*e));
        e->type = type;
        e->left.expr = e1;
        e->right.expr = e2;
        e->type = type;
        e->left.expr = e1;
        e->right.expr = e2;
@@ -42,8 +38,7 @@ struct expr *expr_alloc_two(enum expr_type type, struct expr *e1, struct expr *e
 
 struct expr *expr_alloc_comp(enum expr_type type, struct symbol *s1, struct symbol *s2)
 {
 
 struct expr *expr_alloc_comp(enum expr_type type, struct symbol *s1, struct symbol *s2)
 {
-       struct expr *e = malloc(sizeof(*e));
-       memset(e, 0, sizeof(*e));
+       struct expr *e = calloc(1, sizeof(*e));
        e->type = type;
        e->left.sym = s1;
        e->right.sym = s2;
        e->type = type;
        e->left.sym = s1;
        e->right.sym = s2;
@@ -64,7 +59,7 @@ struct expr *expr_alloc_or(struct expr *e1, struct expr *e2)
        return e2 ? expr_alloc_two(E_OR, e1, e2) : e1;
 }
 
        return e2 ? expr_alloc_two(E_OR, e1, e2) : e1;
 }
 
-struct expr *expr_copy(struct expr *org)
+struct expr *expr_copy(const struct expr *org)
 {
        struct expr *e;
 
 {
        struct expr *e;
 
@@ -177,18 +172,13 @@ void expr_eliminate_eq(struct expr **ep1, struct expr **ep2)
        default:
                ;
        }
        default:
                ;
        }
-
-       if (e1->type != e2->type) {
-               switch (e2->type) {
-               case E_OR:
-               case E_AND:
-                       __expr_eliminate_eq(e2->type, ep1, ep2);
-               default:
-                       ;
-
-               }
+       if (e1->type != e2->type) switch (e2->type) {
+       case E_OR:
+       case E_AND:
+               __expr_eliminate_eq(e2->type, ep1, ep2);
+       default:
+               ;
        }
        }
-
        e1 = expr_eliminate_yn(e1);
        e2 = expr_eliminate_yn(e2);
 }
        e1 = expr_eliminate_yn(e1);
        e2 = expr_eliminate_yn(e2);
 }
@@ -242,10 +232,7 @@ struct expr *expr_eliminate_yn(struct expr *e)
 {
        struct expr *tmp;
 
 {
        struct expr *tmp;
 
-       if (!e)
-               return NULL;
-
-       switch (e->type) {
+       if (e) switch (e->type) {
        case E_AND:
                e->left.expr = expr_eliminate_yn(e->left.expr);
                e->right.expr = expr_eliminate_yn(e->right.expr);
        case E_AND:
                e->left.expr = expr_eliminate_yn(e->left.expr);
                e->right.expr = expr_eliminate_yn(e->right.expr);
@@ -265,7 +252,6 @@ struct expr *expr_eliminate_yn(struct expr *e)
                                return e;
                        }
                }
                                return e;
                        }
                }
-
                if (e->right.expr->type == E_SYMBOL) {
                        if (e->right.expr->left.sym == &symbol_no) {
                                expr_free(e->left.expr);
                if (e->right.expr->type == E_SYMBOL) {
                        if (e->right.expr->left.sym == &symbol_no) {
                                expr_free(e->left.expr);
@@ -283,7 +269,6 @@ struct expr *expr_eliminate_yn(struct expr *e)
                        }
                }
                break;
                        }
                }
                break;
-
        case E_OR:
                e->left.expr = expr_eliminate_yn(e->left.expr);
                e->right.expr = expr_eliminate_yn(e->right.expr);
        case E_OR:
                e->left.expr = expr_eliminate_yn(e->left.expr);
                e->right.expr = expr_eliminate_yn(e->right.expr);
@@ -303,7 +288,6 @@ struct expr *expr_eliminate_yn(struct expr *e)
                                return e;
                        }
                }
                                return e;
                        }
                }
-
                if (e->right.expr->type == E_SYMBOL) {
                        if (e->right.expr->left.sym == &symbol_no) {
                                free(e->right.expr);
                if (e->right.expr->type == E_SYMBOL) {
                        if (e->right.expr->left.sym == &symbol_no) {
                                free(e->right.expr);
@@ -322,7 +306,7 @@ struct expr *expr_eliminate_yn(struct expr *e)
                }
                break;
        default:
                }
                break;
        default:
-               break;
+               ;
        }
        return e;
 }
        }
        return e;
 }
@@ -334,7 +318,6 @@ struct expr *expr_trans_bool(struct expr *e)
 {
        if (!e)
                return NULL;
 {
        if (!e)
                return NULL;
-
        switch (e->type) {
        case E_AND:
        case E_OR:
        switch (e->type) {
        case E_AND:
        case E_OR:
@@ -343,7 +326,7 @@ struct expr *expr_trans_bool(struct expr *e)
                e->right.expr = expr_trans_bool(e->right.expr);
                break;
        case E_UNEQUAL:
                e->right.expr = expr_trans_bool(e->right.expr);
                break;
        case E_UNEQUAL:
-               /* FOO!=n -> FOO */
+               // FOO!=n -> FOO
                if (e->left.sym->type == S_TRISTATE) {
                        if (e->right.sym == &symbol_no) {
                                e->type = E_SYMBOL;
                if (e->left.sym->type == S_TRISTATE) {
                        if (e->right.sym == &symbol_no) {
                                e->type = E_SYMBOL;
@@ -392,19 +375,19 @@ static struct expr *expr_join_or(struct expr *e1, struct expr *e2)
                if (e1->type == E_EQUAL && e2->type == E_EQUAL &&
                    ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_mod) ||
                     (e1->right.sym == &symbol_mod && e2->right.sym == &symbol_yes))) {
                if (e1->type == E_EQUAL && e2->type == E_EQUAL &&
                    ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_mod) ||
                     (e1->right.sym == &symbol_mod && e2->right.sym == &symbol_yes))) {
-                       /* (a='y') || (a='m') -> (a!='n') */
+                       // (a='y') || (a='m') -> (a!='n')
                        return expr_alloc_comp(E_UNEQUAL, sym1, &symbol_no);
                }
                if (e1->type == E_EQUAL && e2->type == E_EQUAL &&
                    ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_no) ||
                     (e1->right.sym == &symbol_no && e2->right.sym == &symbol_yes))) {
                        return expr_alloc_comp(E_UNEQUAL, sym1, &symbol_no);
                }
                if (e1->type == E_EQUAL && e2->type == E_EQUAL &&
                    ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_no) ||
                     (e1->right.sym == &symbol_no && e2->right.sym == &symbol_yes))) {
-                       /* (a='y') || (a='n') -> (a!='m') */
+                       // (a='y') || (a='n') -> (a!='m')
                        return expr_alloc_comp(E_UNEQUAL, sym1, &symbol_mod);
                }
                if (e1->type == E_EQUAL && e2->type == E_EQUAL &&
                    ((e1->right.sym == &symbol_mod && e2->right.sym == &symbol_no) ||
                     (e1->right.sym == &symbol_no && e2->right.sym == &symbol_mod))) {
                        return expr_alloc_comp(E_UNEQUAL, sym1, &symbol_mod);
                }
                if (e1->type == E_EQUAL && e2->type == E_EQUAL &&
                    ((e1->right.sym == &symbol_mod && e2->right.sym == &symbol_no) ||
                     (e1->right.sym == &symbol_no && e2->right.sym == &symbol_mod))) {
-                       /* (a='m') || (a='n') -> (a!='y') */
+                       // (a='m') || (a='n') -> (a!='y')
                        return expr_alloc_comp(E_UNEQUAL, sym1, &symbol_yes);
                }
        }
                        return expr_alloc_comp(E_UNEQUAL, sym1, &symbol_yes);
                }
        }
@@ -455,29 +438,29 @@ static struct expr *expr_join_and(struct expr *e1, struct expr *e2)
 
        if ((e1->type == E_SYMBOL && e2->type == E_EQUAL && e2->right.sym == &symbol_yes) ||
            (e2->type == E_SYMBOL && e1->type == E_EQUAL && e1->right.sym == &symbol_yes))
 
        if ((e1->type == E_SYMBOL && e2->type == E_EQUAL && e2->right.sym == &symbol_yes) ||
            (e2->type == E_SYMBOL && e1->type == E_EQUAL && e1->right.sym == &symbol_yes))
-               /* (a) && (a='y') -> (a='y') */
+               // (a) && (a='y') -> (a='y')
                return expr_alloc_comp(E_EQUAL, sym1, &symbol_yes);
 
        if ((e1->type == E_SYMBOL && e2->type == E_UNEQUAL && e2->right.sym == &symbol_no) ||
            (e2->type == E_SYMBOL && e1->type == E_UNEQUAL && e1->right.sym == &symbol_no))
                return expr_alloc_comp(E_EQUAL, sym1, &symbol_yes);
 
        if ((e1->type == E_SYMBOL && e2->type == E_UNEQUAL && e2->right.sym == &symbol_no) ||
            (e2->type == E_SYMBOL && e1->type == E_UNEQUAL && e1->right.sym == &symbol_no))
-               /* (a) && (a!='n') -> (a) */
+               // (a) && (a!='n') -> (a)
                return expr_alloc_symbol(sym1);
 
        if ((e1->type == E_SYMBOL && e2->type == E_UNEQUAL && e2->right.sym == &symbol_mod) ||
            (e2->type == E_SYMBOL && e1->type == E_UNEQUAL && e1->right.sym == &symbol_mod))
                return expr_alloc_symbol(sym1);
 
        if ((e1->type == E_SYMBOL && e2->type == E_UNEQUAL && e2->right.sym == &symbol_mod) ||
            (e2->type == E_SYMBOL && e1->type == E_UNEQUAL && e1->right.sym == &symbol_mod))
-               /* (a) && (a!='m') -> (a='y') */
+               // (a) && (a!='m') -> (a='y')
                return expr_alloc_comp(E_EQUAL, sym1, &symbol_yes);
 
        if (sym1->type == S_TRISTATE) {
                if (e1->type == E_EQUAL && e2->type == E_UNEQUAL) {
                return expr_alloc_comp(E_EQUAL, sym1, &symbol_yes);
 
        if (sym1->type == S_TRISTATE) {
                if (e1->type == E_EQUAL && e2->type == E_UNEQUAL) {
-                       /* (a='b') && (a!='c') -> 'b'='c' ? 'n' : a='b' */
+                       // (a='b') && (a!='c') -> 'b'='c' ? 'n' : a='b'
                        sym2 = e1->right.sym;
                        if ((e2->right.sym->flags & SYMBOL_CONST) && (sym2->flags & SYMBOL_CONST))
                                return sym2 != e2->right.sym ? expr_alloc_comp(E_EQUAL, sym1, sym2)
                                                             : expr_alloc_symbol(&symbol_no);
                }
                if (e1->type == E_UNEQUAL && e2->type == E_EQUAL) {
                        sym2 = e1->right.sym;
                        if ((e2->right.sym->flags & SYMBOL_CONST) && (sym2->flags & SYMBOL_CONST))
                                return sym2 != e2->right.sym ? expr_alloc_comp(E_EQUAL, sym1, sym2)
                                                             : expr_alloc_symbol(&symbol_no);
                }
                if (e1->type == E_UNEQUAL && e2->type == E_EQUAL) {
-                       /* (a='b') && (a!='c') -> 'b'='c' ? 'n' : a='b' */
+                       // (a='b') && (a!='c') -> 'b'='c' ? 'n' : a='b'
                        sym2 = e2->right.sym;
                        if ((e1->right.sym->flags & SYMBOL_CONST) && (sym2->flags & SYMBOL_CONST))
                                return sym2 != e1->right.sym ? expr_alloc_comp(E_EQUAL, sym1, sym2)
                        sym2 = e2->right.sym;
                        if ((e1->right.sym->flags & SYMBOL_CONST) && (sym2->flags & SYMBOL_CONST))
                                return sym2 != e1->right.sym ? expr_alloc_comp(E_EQUAL, sym1, sym2)
@@ -486,19 +469,19 @@ static struct expr *expr_join_and(struct expr *e1, struct expr *e2)
                if (e1->type == E_UNEQUAL && e2->type == E_UNEQUAL &&
                           ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_no) ||
                            (e1->right.sym == &symbol_no && e2->right.sym == &symbol_yes)))
                if (e1->type == E_UNEQUAL && e2->type == E_UNEQUAL &&
                           ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_no) ||
                            (e1->right.sym == &symbol_no && e2->right.sym == &symbol_yes)))
-                       /* (a!='y') && (a!='n') -> (a='m') */
+                       // (a!='y') && (a!='n') -> (a='m')
                        return expr_alloc_comp(E_EQUAL, sym1, &symbol_mod);
 
                if (e1->type == E_UNEQUAL && e2->type == E_UNEQUAL &&
                           ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_mod) ||
                            (e1->right.sym == &symbol_mod && e2->right.sym == &symbol_yes)))
                        return expr_alloc_comp(E_EQUAL, sym1, &symbol_mod);
 
                if (e1->type == E_UNEQUAL && e2->type == E_UNEQUAL &&
                           ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_mod) ||
                            (e1->right.sym == &symbol_mod && e2->right.sym == &symbol_yes)))
-                       /* (a!='y') && (a!='m') -> (a='n') */
+                       // (a!='y') && (a!='m') -> (a='n')
                        return expr_alloc_comp(E_EQUAL, sym1, &symbol_no);
 
                if (e1->type == E_UNEQUAL && e2->type == E_UNEQUAL &&
                           ((e1->right.sym == &symbol_mod && e2->right.sym == &symbol_no) ||
                            (e1->right.sym == &symbol_no && e2->right.sym == &symbol_mod)))
                        return expr_alloc_comp(E_EQUAL, sym1, &symbol_no);
 
                if (e1->type == E_UNEQUAL && e2->type == E_UNEQUAL &&
                           ((e1->right.sym == &symbol_mod && e2->right.sym == &symbol_no) ||
                            (e1->right.sym == &symbol_no && e2->right.sym == &symbol_mod)))
-                       /* (a!='m') && (a!='n') -> (a='m') */
+                       // (a!='m') && (a!='n') -> (a='m')
                        return expr_alloc_comp(E_EQUAL, sym1, &symbol_yes);
 
                if ((e1->type == E_SYMBOL && e2->type == E_EQUAL && e2->right.sym == &symbol_mod) ||
                        return expr_alloc_comp(E_EQUAL, sym1, &symbol_yes);
 
                if ((e1->type == E_SYMBOL && e2->type == E_EQUAL && e2->right.sym == &symbol_mod) ||
@@ -591,7 +574,7 @@ static void expr_eliminate_dups2(enum expr_type type, struct expr **ep1, struct
        switch (e1->type) {
        case E_OR:
                expr_eliminate_dups2(e1->type, &e1, &e1);
        switch (e1->type) {
        case E_OR:
                expr_eliminate_dups2(e1->type, &e1, &e1);
-               /* (FOO || BAR) && (!FOO && !BAR) -> n */
+               // (FOO || BAR) && (!FOO && !BAR) -> n
                tmp1 = expr_transform(expr_alloc_one(E_NOT, expr_copy(e1)));
                tmp2 = expr_copy(e2);
                tmp = expr_extract_eq_and(&tmp1, &tmp2);
                tmp1 = expr_transform(expr_alloc_one(E_NOT, expr_copy(e1)));
                tmp2 = expr_copy(e2);
                tmp = expr_extract_eq_and(&tmp1, &tmp2);
@@ -606,7 +589,7 @@ static void expr_eliminate_dups2(enum expr_type type, struct expr **ep1, struct
                break;
        case E_AND:
                expr_eliminate_dups2(e1->type, &e1, &e1);
                break;
        case E_AND:
                expr_eliminate_dups2(e1->type, &e1, &e1);
-               /* (FOO && BAR) || (!FOO || !BAR) -> y */
+               // (FOO && BAR) || (!FOO || !BAR) -> y
                tmp1 = expr_transform(expr_alloc_one(E_NOT, expr_copy(e1)));
                tmp2 = expr_copy(e2);
                tmp = expr_extract_eq_or(&tmp1, &tmp2);
                tmp1 = expr_transform(expr_alloc_one(E_NOT, expr_copy(e1)));
                tmp2 = expr_copy(e2);
                tmp = expr_extract_eq_or(&tmp1, &tmp2);
@@ -715,7 +698,7 @@ struct expr *expr_transform(struct expr *e)
        case E_NOT:
                switch (e->left.expr->type) {
                case E_NOT:
        case E_NOT:
                switch (e->left.expr->type) {
                case E_NOT:
-                       /* !!a -> a */
+                       // !!a -> a
                        tmp = e->left.expr->left.expr;
                        free(e->left.expr);
                        free(e);
                        tmp = e->left.expr->left.expr;
                        free(e->left.expr);
                        free(e);
@@ -724,14 +707,14 @@ struct expr *expr_transform(struct expr *e)
                        break;
                case E_EQUAL:
                case E_UNEQUAL:
                        break;
                case E_EQUAL:
                case E_UNEQUAL:
-                       /* !a='x' -> a!='x' */
+                       // !a='x' -> a!='x'
                        tmp = e->left.expr;
                        free(e);
                        e = tmp;
                        e->type = e->type == E_EQUAL ? E_UNEQUAL : E_EQUAL;
                        break;
                case E_OR:
                        tmp = e->left.expr;
                        free(e);
                        e = tmp;
                        e->type = e->type == E_EQUAL ? E_UNEQUAL : E_EQUAL;
                        break;
                case E_OR:
-                       /* !(a || b) -> !a && !b */
+                       // !(a || b) -> !a && !b
                        tmp = e->left.expr;
                        e->type = E_AND;
                        e->right.expr = expr_alloc_one(E_NOT, tmp->right.expr);
                        tmp = e->left.expr;
                        e->type = E_AND;
                        e->right.expr = expr_alloc_one(E_NOT, tmp->right.expr);
@@ -740,7 +723,7 @@ struct expr *expr_transform(struct expr *e)
                        e = expr_transform(e);
                        break;
                case E_AND:
                        e = expr_transform(e);
                        break;
                case E_AND:
-                       /* !(a && b) -> !a || !b */
+                       // !(a && b) -> !a || !b
                        tmp = e->left.expr;
                        e->type = E_OR;
                        e->right.expr = expr_alloc_one(E_NOT, tmp->right.expr);
                        tmp = e->left.expr;
                        e->type = E_OR;
                        e->right.expr = expr_alloc_one(E_NOT, tmp->right.expr);
@@ -750,7 +733,7 @@ struct expr *expr_transform(struct expr *e)
                        break;
                case E_SYMBOL:
                        if (e->left.expr->left.sym == &symbol_yes) {
                        break;
                case E_SYMBOL:
                        if (e->left.expr->left.sym == &symbol_yes) {
-                               /* !'y' -> 'n' */
+                               // !'y' -> 'n'
                                tmp = e->left.expr;
                                free(e);
                                e = tmp;
                                tmp = e->left.expr;
                                free(e);
                                e = tmp;
@@ -759,7 +742,7 @@ struct expr *expr_transform(struct expr *e)
                                break;
                        }
                        if (e->left.expr->left.sym == &symbol_mod) {
                                break;
                        }
                        if (e->left.expr->left.sym == &symbol_mod) {
-                               /* !'m' -> 'm' */
+                               // !'m' -> 'm'
                                tmp = e->left.expr;
                                free(e);
                                e = tmp;
                                tmp = e->left.expr;
                                free(e);
                                e = tmp;
@@ -768,7 +751,7 @@ struct expr *expr_transform(struct expr *e)
                                break;
                        }
                        if (e->left.expr->left.sym == &symbol_no) {
                                break;
                        }
                        if (e->left.expr->left.sym == &symbol_no) {
-                               /* !'n' -> 'y' */
+                               // !'n' -> 'y'
                                tmp = e->left.expr;
                                free(e);
                                e = tmp;
                                tmp = e->left.expr;
                                free(e);
                                e = tmp;
@@ -837,7 +820,7 @@ bool expr_depends_symbol(struct expr *dep, struct symbol *sym)
        default:
                ;
        }
        default:
                ;
        }
-       return false;
+       return false;
 }
 
 struct expr *expr_extract_eq_and(struct expr **ep1, struct expr **ep2)
 }
 
 struct expr *expr_extract_eq_and(struct expr **ep1, struct expr **ep2)
@@ -1025,6 +1008,48 @@ int expr_compare_type(enum expr_type t1, enum expr_type t2)
 #endif
 }
 
 #endif
 }
 
+static inline struct expr *
+expr_get_leftmost_symbol(const struct expr *e)
+{
+
+       if (e == NULL)
+               return NULL;
+
+       while (e->type != E_SYMBOL)
+               e = e->left.expr;
+
+       return expr_copy(e);
+}
+
+/*
+ * Given expression `e1' and `e2', returns the leaf of the longest
+ * sub-expression of `e1' not containing 'e2.
+ */
+struct expr *expr_simplify_unmet_dep(struct expr *e1, struct expr *e2)
+{
+       struct expr *ret;
+
+       switch (e1->type) {
+       case E_OR:
+               return expr_alloc_and(
+                   expr_simplify_unmet_dep(e1->left.expr, e2),
+                   expr_simplify_unmet_dep(e1->right.expr, e2));
+       case E_AND: {
+               struct expr *e;
+               e = expr_alloc_and(expr_copy(e1), expr_copy(e2));
+               e = expr_eliminate_dups(e);
+               ret = (!expr_eq(e, e1)) ? e1 : NULL;
+               expr_free(e);
+               break;
+               }
+       default:
+               ret = e1;
+               break;
+       }
+
+       return expr_get_leftmost_symbol(ret);
+}
+
 void expr_print(struct expr *e, void (*fn)(void *, struct symbol *, const char *), void *data, int prevtoken)
 {
        if (!e) {
 void expr_print(struct expr *e, void (*fn)(void *, struct symbol *, const char *), void *data, int prevtoken)
 {
        if (!e) {
@@ -1099,7 +1124,7 @@ void expr_print(struct expr *e, void (*fn)(void *, struct symbol *, const char *
 
 static void expr_print_file_helper(void *data, struct symbol *sym, const char *str)
 {
 
 static void expr_print_file_helper(void *data, struct symbol *sym, const char *str)
 {
-       fwrite(str, strlen(str), 1, data);
+       xfwrite(str, strlen(str), 1, data);
 }
 
 void expr_fprint(struct expr *e, FILE *out)
 }
 
 void expr_fprint(struct expr *e, FILE *out)
@@ -1109,9 +1134,32 @@ void expr_fprint(struct expr *e, FILE *out)
 
 static void expr_print_gstr_helper(void *data, struct symbol *sym, const char *str)
 {
 
 static void expr_print_gstr_helper(void *data, struct symbol *sym, const char *str)
 {
-       str_append((struct gstr *)data, str);
+       struct gstr *gs = (struct gstr*)data;
+       const char *sym_str = NULL;
+
        if (sym)
        if (sym)
-               str_printf((struct gstr *)data, " [=%s]", sym_get_string_value(sym));
+               sym_str = sym_get_string_value(sym);
+
+       if (gs->max_width) {
+               unsigned extra_length = strlen(str);
+               const char *last_cr = strrchr(gs->s, '\n');
+               unsigned last_line_length;
+
+               if (sym_str)
+                       extra_length += 4 + strlen(sym_str);
+
+               if (!last_cr)
+                       last_cr = gs->s;
+
+               last_line_length = strlen(gs->s) - (last_cr - gs->s);
+
+               if ((last_line_length + extra_length) > gs->max_width)
+                       str_append(gs, "\\\n");
+       }
+
+       str_append(gs, str);
+       if (sym && sym->type != S_UNKNOWN)
+               str_printf(gs, " [=%s]", sym_str);
 }
 
 void expr_gstr_print(struct expr *e, struct gstr *gs)
 }
 
 void expr_gstr_print(struct expr *e, struct gstr *gs)