2018-12-18 15:13:35 +03:00
// SPDX-License-Identifier: GPL-2.0
2005-04-17 02:20:36 +04:00
/*
* Copyright ( C ) 2002 Roman Zippel < zippel @ linux - m68k . org >
*/
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include "lkc.h"
# define DEBUG_EXPR 0
2015-02-24 18:37:13 +03:00
static int expr_eq ( struct expr * e1 , struct expr * e2 ) ;
static struct expr * expr_eliminate_yn ( struct expr * e ) ;
2005-04-17 02:20:36 +04:00
struct expr * expr_alloc_symbol ( struct symbol * sym )
{
2012-11-06 18:32:08 +04:00
struct expr * e = xcalloc ( 1 , sizeof ( * e ) ) ;
2005-04-17 02:20:36 +04:00
e - > type = E_SYMBOL ;
e - > left . sym = sym ;
return e ;
}
struct expr * expr_alloc_one ( enum expr_type type , struct expr * ce )
{
2012-11-06 18:32:08 +04:00
struct expr * e = xcalloc ( 1 , sizeof ( * e ) ) ;
2005-04-17 02:20:36 +04:00
e - > type = type ;
e - > left . expr = ce ;
return e ;
}
struct expr * expr_alloc_two ( enum expr_type type , struct expr * e1 , struct expr * e2 )
{
2012-11-06 18:32:08 +04:00
struct expr * e = xcalloc ( 1 , sizeof ( * e ) ) ;
2005-04-17 02:20:36 +04:00
e - > type = type ;
e - > left . expr = e1 ;
e - > right . expr = e2 ;
return e ;
}
struct expr * expr_alloc_comp ( enum expr_type type , struct symbol * s1 , struct symbol * s2 )
{
2012-11-06 18:32:08 +04:00
struct expr * e = xcalloc ( 1 , sizeof ( * e ) ) ;
2005-04-17 02:20:36 +04:00
e - > type = type ;
e - > left . sym = s1 ;
e - > right . sym = s2 ;
return e ;
}
struct expr * expr_alloc_and ( struct expr * e1 , struct expr * e2 )
{
if ( ! e1 )
return e2 ;
return e2 ? expr_alloc_two ( E_AND , e1 , e2 ) : e1 ;
}
struct expr * expr_alloc_or ( struct expr * e1 , struct expr * e2 )
{
if ( ! e1 )
return e2 ;
return e2 ? expr_alloc_two ( E_OR , e1 , e2 ) : e1 ;
}
2010-12-20 18:06:44 +03:00
struct expr * expr_copy ( const struct expr * org )
2005-04-17 02:20:36 +04:00
{
struct expr * e ;
if ( ! org )
return NULL ;
2012-11-06 18:32:08 +04:00
e = xmalloc ( sizeof ( * org ) ) ;
2005-04-17 02:20:36 +04:00
memcpy ( e , org , sizeof ( * org ) ) ;
switch ( org - > type ) {
case E_SYMBOL :
e - > left = org - > left ;
break ;
case E_NOT :
e - > left . expr = expr_copy ( org - > left . expr ) ;
break ;
case E_EQUAL :
2015-06-15 15:00:21 +03:00
case E_GEQ :
case E_GTH :
case E_LEQ :
case E_LTH :
2005-04-17 02:20:36 +04:00
case E_UNEQUAL :
e - > left . sym = org - > left . sym ;
e - > right . sym = org - > right . sym ;
break ;
case E_AND :
case E_OR :
2008-01-14 06:50:23 +03:00
case E_LIST :
2005-04-17 02:20:36 +04:00
e - > left . expr = expr_copy ( org - > left . expr ) ;
e - > right . expr = expr_copy ( org - > right . expr ) ;
break ;
default :
2018-02-06 03:34:41 +03:00
fprintf ( stderr , " can't copy type %d \n " , e - > type ) ;
2005-04-17 02:20:36 +04:00
free ( e ) ;
e = NULL ;
break ;
}
return e ;
}
void expr_free ( struct expr * e )
{
if ( ! e )
return ;
switch ( e - > type ) {
case E_SYMBOL :
break ;
case E_NOT :
expr_free ( e - > left . expr ) ;
2017-10-08 20:35:45 +03:00
break ;
2005-04-17 02:20:36 +04:00
case E_EQUAL :
2015-06-15 15:00:21 +03:00
case E_GEQ :
case E_GTH :
case E_LEQ :
case E_LTH :
2005-04-17 02:20:36 +04:00
case E_UNEQUAL :
break ;
case E_OR :
case E_AND :
expr_free ( e - > left . expr ) ;
expr_free ( e - > right . expr ) ;
break ;
default :
2018-02-06 03:34:41 +03:00
fprintf ( stderr , " how to free type %d? \n " , e - > type ) ;
2005-04-17 02:20:36 +04:00
break ;
}
free ( e ) ;
}
static int trans_count ;
# define e1 (*ep1)
# define e2 (*ep2)
2017-10-08 20:50:55 +03:00
/*
* expr_eliminate_eq ( ) helper .
*
* Walks the two expression trees given in ' ep1 ' and ' ep2 ' . Any node that does
* not have type ' type ' ( E_OR / E_AND ) is considered a leaf , and is compared
* against all other leaves . Two equal leaves are both replaced with either ' y '
* or ' n ' as appropriate for ' type ' , to be eliminated later .
*/
2005-04-17 02:20:36 +04:00
static void __expr_eliminate_eq ( enum expr_type type , struct expr * * ep1 , struct expr * * ep2 )
{
2017-10-08 20:50:55 +03:00
/* Recurse down to leaves */
2005-04-17 02:20:36 +04:00
if ( e1 - > type = = type ) {
__expr_eliminate_eq ( type , & e1 - > left . expr , & e2 ) ;
__expr_eliminate_eq ( type , & e1 - > right . expr , & e2 ) ;
return ;
}
if ( e2 - > type = = type ) {
__expr_eliminate_eq ( type , & e1 , & e2 - > left . expr ) ;
__expr_eliminate_eq ( type , & e1 , & e2 - > right . expr ) ;
return ;
}
2017-10-08 20:50:55 +03:00
/* e1 and e2 are leaves. Compare them. */
2005-04-17 02:20:36 +04:00
if ( e1 - > type = = E_SYMBOL & & e2 - > type = = E_SYMBOL & &
2006-06-09 09:12:40 +04:00
e1 - > left . sym = = e2 - > left . sym & &
( e1 - > left . sym = = & symbol_yes | | e1 - > left . sym = = & symbol_no ) )
2005-04-17 02:20:36 +04:00
return ;
if ( ! expr_eq ( e1 , e2 ) )
return ;
2017-10-08 20:50:55 +03:00
/* e1 and e2 are equal leaves. Prepare them for elimination. */
2005-04-17 02:20:36 +04:00
trans_count + + ;
expr_free ( e1 ) ; expr_free ( e2 ) ;
switch ( type ) {
case E_OR :
e1 = expr_alloc_symbol ( & symbol_no ) ;
e2 = expr_alloc_symbol ( & symbol_no ) ;
break ;
case E_AND :
e1 = expr_alloc_symbol ( & symbol_yes ) ;
e2 = expr_alloc_symbol ( & symbol_yes ) ;
break ;
default :
;
}
}
2017-10-08 20:50:55 +03:00
/*
* Rewrites the expressions ' ep1 ' and ' ep2 ' to remove operands common to both .
* Example reductions :
*
* ep1 : A & & B - > ep1 : y
* ep2 : A & & B & & C - > ep2 : C
*
* ep1 : A | | B - > ep1 : n
* ep2 : A | | B | | C - > ep2 : C
*
* ep1 : A & & ( B & & FOO ) - > ep1 : FOO
* ep2 : ( BAR & & B ) & & A - > ep2 : BAR
*
* ep1 : A & & ( B | | C ) - > ep1 : y
* ep2 : ( C | | B ) & & A - > ep2 : y
*
* Comparisons are done between all operands at the same " level " of & & or | | .
* For example , in the expression ' e1 & & ( e2 | | e3 ) & & ( e4 | | e5 ) ' , the
* following operands will be compared :
*
* - ' e1 ' , ' e2 | | e3 ' , and ' e4 | | e5 ' , against each other
* - e2 against e3
* - e4 against e5
*
* Parentheses are irrelevant within a single level . ' e1 & & ( e2 & & e3 ) ' and
* ' ( e1 & & e2 ) & & e3 ' are both a single level .
*
* See __expr_eliminate_eq ( ) as well .
*/
2005-04-17 02:20:36 +04:00
void expr_eliminate_eq ( struct expr * * ep1 , struct expr * * ep2 )
{
if ( ! e1 | | ! e2 )
return ;
switch ( e1 - > type ) {
case E_OR :
case E_AND :
__expr_eliminate_eq ( e1 - > 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 ) ;
}
# undef e1
# undef e2
2017-10-08 20:50:55 +03:00
/*
* Returns true if ' e1 ' and ' e2 ' are equal , after minor simplification . Two
* & & / | | expressions are considered equal if every operand in one expression
* equals some operand in the other ( operands do not need to appear in the same
* order ) , recursively .
*/
2015-02-24 18:37:13 +03:00
static int expr_eq ( struct expr * e1 , struct expr * e2 )
2005-04-17 02:20:36 +04:00
{
int res , old_count ;
if ( e1 - > type ! = e2 - > type )
return 0 ;
switch ( e1 - > type ) {
case E_EQUAL :
2015-06-15 15:00:21 +03:00
case E_GEQ :
case E_GTH :
case E_LEQ :
case E_LTH :
2005-04-17 02:20:36 +04:00
case E_UNEQUAL :
return e1 - > left . sym = = e2 - > left . sym & & e1 - > right . sym = = e2 - > right . sym ;
case E_SYMBOL :
return e1 - > left . sym = = e2 - > left . sym ;
case E_NOT :
return expr_eq ( e1 - > left . expr , e2 - > left . expr ) ;
case E_AND :
case E_OR :
e1 = expr_copy ( e1 ) ;
e2 = expr_copy ( e2 ) ;
old_count = trans_count ;
expr_eliminate_eq ( & e1 , & e2 ) ;
res = ( e1 - > type = = E_SYMBOL & & e2 - > type = = E_SYMBOL & &
e1 - > left . sym = = e2 - > left . sym ) ;
expr_free ( e1 ) ;
expr_free ( e2 ) ;
trans_count = old_count ;
return res ;
2008-01-14 06:50:23 +03:00
case E_LIST :
2005-04-17 02:20:36 +04:00
case E_RANGE :
case E_NONE :
/* panic */ ;
}
if ( DEBUG_EXPR ) {
expr_fprint ( e1 , stdout ) ;
printf ( " = " ) ;
expr_fprint ( e2 , stdout ) ;
printf ( " ? \n " ) ;
}
return 0 ;
}
2017-10-08 20:50:55 +03:00
/*
* Recursively performs the following simplifications in - place ( as well as the
* corresponding simplifications with swapped operands ) :
*
* expr & & n - > n
* expr & & y - > expr
* expr | | n - > expr
* expr | | y - > y
*
* Returns the optimized expression .
*/
2015-02-24 18:37:13 +03:00
static struct expr * expr_eliminate_yn ( struct expr * e )
2005-04-17 02:20:36 +04:00
{
struct expr * tmp ;
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 ) ;
if ( e - > left . expr - > type = = E_SYMBOL ) {
if ( e - > left . expr - > left . sym = = & symbol_no ) {
expr_free ( e - > left . expr ) ;
expr_free ( e - > right . expr ) ;
e - > type = E_SYMBOL ;
e - > left . sym = & symbol_no ;
e - > right . expr = NULL ;
return e ;
} else if ( e - > left . expr - > left . sym = = & symbol_yes ) {
free ( e - > left . expr ) ;
tmp = e - > right . expr ;
* e = * ( e - > right . expr ) ;
free ( tmp ) ;
return e ;
}
}
if ( e - > right . expr - > type = = E_SYMBOL ) {
if ( e - > right . expr - > left . sym = = & symbol_no ) {
expr_free ( e - > left . expr ) ;
expr_free ( e - > right . expr ) ;
e - > type = E_SYMBOL ;
e - > left . sym = & symbol_no ;
e - > right . expr = NULL ;
return e ;
} else if ( e - > right . expr - > left . sym = = & symbol_yes ) {
free ( e - > right . expr ) ;
tmp = e - > left . expr ;
* e = * ( e - > left . expr ) ;
free ( tmp ) ;
return e ;
}
}
break ;
case E_OR :
e - > left . expr = expr_eliminate_yn ( e - > left . expr ) ;
e - > right . expr = expr_eliminate_yn ( e - > right . expr ) ;
if ( e - > left . expr - > type = = E_SYMBOL ) {
if ( e - > left . expr - > left . sym = = & symbol_no ) {
free ( e - > left . expr ) ;
tmp = e - > right . expr ;
* e = * ( e - > right . expr ) ;
free ( tmp ) ;
return e ;
} else if ( e - > left . expr - > left . sym = = & symbol_yes ) {
expr_free ( e - > left . expr ) ;
expr_free ( e - > right . expr ) ;
e - > type = E_SYMBOL ;
e - > left . sym = & symbol_yes ;
e - > right . expr = NULL ;
return e ;
}
}
if ( e - > right . expr - > type = = E_SYMBOL ) {
if ( e - > right . expr - > left . sym = = & symbol_no ) {
free ( e - > right . expr ) ;
tmp = e - > left . expr ;
* e = * ( e - > left . expr ) ;
free ( tmp ) ;
return e ;
} else if ( e - > right . expr - > left . sym = = & symbol_yes ) {
expr_free ( e - > left . expr ) ;
expr_free ( e - > right . expr ) ;
e - > type = E_SYMBOL ;
e - > left . sym = & symbol_yes ;
e - > right . expr = NULL ;
return e ;
}
}
break ;
default :
;
}
return e ;
}
/*
* bool FOO ! = n = > FOO
*/
struct expr * expr_trans_bool ( struct expr * e )
{
if ( ! e )
return NULL ;
switch ( e - > type ) {
case E_AND :
case E_OR :
case E_NOT :
e - > left . expr = expr_trans_bool ( e - > left . expr ) ;
e - > right . expr = expr_trans_bool ( e - > right . expr ) ;
break ;
case E_UNEQUAL :
// FOO!=n -> FOO
if ( e - > left . sym - > type = = S_TRISTATE ) {
if ( e - > right . sym = = & symbol_no ) {
e - > type = E_SYMBOL ;
e - > right . sym = NULL ;
}
}
break ;
default :
;
}
return e ;
}
/*
* e1 | | e2 - > ?
*/
2009-09-18 23:49:23 +04:00
static struct expr * expr_join_or ( struct expr * e1 , struct expr * e2 )
2005-04-17 02:20:36 +04:00
{
struct expr * tmp ;
struct symbol * sym1 , * sym2 ;
if ( expr_eq ( e1 , e2 ) )
return expr_copy ( e1 ) ;
if ( e1 - > type ! = E_EQUAL & & e1 - > type ! = E_UNEQUAL & & e1 - > type ! = E_SYMBOL & & e1 - > type ! = E_NOT )
return NULL ;
if ( e2 - > type ! = E_EQUAL & & e2 - > type ! = E_UNEQUAL & & e2 - > type ! = E_SYMBOL & & e2 - > type ! = E_NOT )
return NULL ;
if ( e1 - > type = = E_NOT ) {
tmp = e1 - > left . expr ;
if ( tmp - > type ! = E_EQUAL & & tmp - > type ! = E_UNEQUAL & & tmp - > type ! = E_SYMBOL )
return NULL ;
sym1 = tmp - > left . sym ;
} else
sym1 = e1 - > left . sym ;
if ( e2 - > type = = E_NOT ) {
if ( e2 - > left . expr - > type ! = E_SYMBOL )
return NULL ;
sym2 = e2 - > left . expr - > left . sym ;
} else
sym2 = e2 - > left . sym ;
if ( sym1 ! = sym2 )
return NULL ;
if ( sym1 - > type ! = S_BOOLEAN & & sym1 - > type ! = S_TRISTATE )
return NULL ;
if ( sym1 - > type = = S_TRISTATE ) {
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')
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')
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')
return expr_alloc_comp ( E_UNEQUAL , sym1 , & symbol_yes ) ;
}
}
if ( sym1 - > type = = S_BOOLEAN & & sym1 = = sym2 ) {
if ( ( e1 - > type = = E_NOT & & e1 - > left . expr - > type = = E_SYMBOL & & e2 - > type = = E_SYMBOL ) | |
( e2 - > type = = E_NOT & & e2 - > left . expr - > type = = E_SYMBOL & & e1 - > type = = E_SYMBOL ) )
return expr_alloc_symbol ( & symbol_yes ) ;
}
if ( DEBUG_EXPR ) {
printf ( " optimize ( " ) ;
expr_fprint ( e1 , stdout ) ;
printf ( " ) || ( " ) ;
expr_fprint ( e2 , stdout ) ;
printf ( " )? \n " ) ;
}
return NULL ;
}
2009-09-18 23:49:23 +04:00
static struct expr * expr_join_and ( struct expr * e1 , struct expr * e2 )
2005-04-17 02:20:36 +04:00
{
struct expr * tmp ;
struct symbol * sym1 , * sym2 ;
if ( expr_eq ( e1 , e2 ) )
return expr_copy ( e1 ) ;
if ( e1 - > type ! = E_EQUAL & & e1 - > type ! = E_UNEQUAL & & e1 - > type ! = E_SYMBOL & & e1 - > type ! = E_NOT )
return NULL ;
if ( e2 - > type ! = E_EQUAL & & e2 - > type ! = E_UNEQUAL & & e2 - > type ! = E_SYMBOL & & e2 - > type ! = E_NOT )
return NULL ;
if ( e1 - > type = = E_NOT ) {
tmp = e1 - > left . expr ;
if ( tmp - > type ! = E_EQUAL & & tmp - > type ! = E_UNEQUAL & & tmp - > type ! = E_SYMBOL )
return NULL ;
sym1 = tmp - > left . sym ;
} else
sym1 = e1 - > left . sym ;
if ( e2 - > type = = E_NOT ) {
if ( e2 - > left . expr - > type ! = E_SYMBOL )
return NULL ;
sym2 = e2 - > left . expr - > left . sym ;
} else
sym2 = e2 - > left . sym ;
if ( sym1 ! = sym2 )
return NULL ;
if ( sym1 - > type ! = S_BOOLEAN & & sym1 - > type ! = S_TRISTATE )
return NULL ;
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')
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)
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')
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'
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'
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 )
: expr_alloc_symbol ( & symbol_no ) ;
}
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')
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')
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')
return expr_alloc_comp ( E_EQUAL , sym1 , & symbol_yes ) ;
if ( ( e1 - > type = = E_SYMBOL & & e2 - > type = = E_EQUAL & & e2 - > right . sym = = & symbol_mod ) | |
( e2 - > type = = E_SYMBOL & & e1 - > type = = E_EQUAL & & e1 - > right . sym = = & symbol_mod ) | |
( e1 - > type = = E_SYMBOL & & e2 - > type = = E_UNEQUAL & & e2 - > right . sym = = & symbol_yes ) | |
( e2 - > type = = E_SYMBOL & & e1 - > type = = E_UNEQUAL & & e1 - > right . sym = = & symbol_yes ) )
return NULL ;
}
if ( DEBUG_EXPR ) {
printf ( " optimize ( " ) ;
expr_fprint ( e1 , stdout ) ;
printf ( " ) && ( " ) ;
expr_fprint ( e2 , stdout ) ;
printf ( " )? \n " ) ;
}
return NULL ;
}
2017-10-08 20:50:55 +03:00
/*
* expr_eliminate_dups ( ) helper .
*
* Walks the two expression trees given in ' ep1 ' and ' ep2 ' . Any node that does
* not have type ' type ' ( E_OR / E_AND ) is considered a leaf , and is compared
* against all other leaves to look for simplifications .
*/
2005-04-17 02:20:36 +04:00
static void expr_eliminate_dups1 ( enum expr_type type , struct expr * * ep1 , struct expr * * ep2 )
{
# define e1 (*ep1)
# define e2 (*ep2)
struct expr * tmp ;
2017-10-08 20:50:55 +03:00
/* Recurse down to leaves */
2005-04-17 02:20:36 +04:00
if ( e1 - > type = = type ) {
expr_eliminate_dups1 ( type , & e1 - > left . expr , & e2 ) ;
expr_eliminate_dups1 ( type , & e1 - > right . expr , & e2 ) ;
return ;
}
if ( e2 - > type = = type ) {
expr_eliminate_dups1 ( type , & e1 , & e2 - > left . expr ) ;
expr_eliminate_dups1 ( type , & e1 , & e2 - > right . expr ) ;
return ;
}
2017-10-08 20:50:55 +03:00
/* e1 and e2 are leaves. Compare and process them. */
2005-04-17 02:20:36 +04:00
if ( e1 = = e2 )
return ;
switch ( e1 - > type ) {
case E_OR : case E_AND :
expr_eliminate_dups1 ( e1 - > type , & e1 , & e1 ) ;
default :
;
}
switch ( type ) {
case E_OR :
tmp = expr_join_or ( e1 , e2 ) ;
if ( tmp ) {
expr_free ( e1 ) ; expr_free ( e2 ) ;
e1 = expr_alloc_symbol ( & symbol_no ) ;
e2 = tmp ;
trans_count + + ;
}
break ;
case E_AND :
tmp = expr_join_and ( e1 , e2 ) ;
if ( tmp ) {
expr_free ( e1 ) ; expr_free ( e2 ) ;
e1 = expr_alloc_symbol ( & symbol_yes ) ;
e2 = tmp ;
trans_count + + ;
}
break ;
default :
;
}
# undef e1
# undef e2
}
2017-10-08 20:50:55 +03:00
/*
* Rewrites ' e ' in - place to remove ( " join " ) duplicate and other redundant
* operands .
*
* Example simplifications :
*
* A | | B | | A - > A | | B
* A & & B & & A = y - > A = y & & B
*
* Returns the deduplicated expression .
*/
2005-04-17 02:20:36 +04:00
struct expr * expr_eliminate_dups ( struct expr * e )
{
int oldcount ;
if ( ! e )
return e ;
oldcount = trans_count ;
while ( 1 ) {
trans_count = 0 ;
switch ( e - > type ) {
case E_OR : case E_AND :
expr_eliminate_dups1 ( e - > type , & e , & e ) ;
default :
;
}
if ( ! trans_count )
2017-10-08 20:50:55 +03:00
/* No simplifications done in this pass. We're done */
2005-04-17 02:20:36 +04:00
break ;
e = expr_eliminate_yn ( e ) ;
}
trans_count = oldcount ;
return e ;
}
2017-10-08 20:50:55 +03:00
/*
* Performs various simplifications involving logical operators and
* comparisons .
*
* Allocates and returns a new expression .
*/
2005-04-17 02:20:36 +04:00
struct expr * expr_transform ( struct expr * e )
{
struct expr * tmp ;
if ( ! e )
return NULL ;
switch ( e - > type ) {
case E_EQUAL :
2015-06-15 15:00:21 +03:00
case E_GEQ :
case E_GTH :
case E_LEQ :
case E_LTH :
2005-04-17 02:20:36 +04:00
case E_UNEQUAL :
case E_SYMBOL :
2008-01-14 06:50:23 +03:00
case E_LIST :
2005-04-17 02:20:36 +04:00
break ;
default :
e - > left . expr = expr_transform ( e - > left . expr ) ;
e - > right . expr = expr_transform ( e - > right . expr ) ;
}
switch ( e - > type ) {
case E_EQUAL :
if ( e - > left . sym - > type ! = S_BOOLEAN )
break ;
if ( e - > right . sym = = & symbol_no ) {
e - > type = E_NOT ;
e - > left . expr = expr_alloc_symbol ( e - > left . sym ) ;
e - > right . sym = NULL ;
break ;
}
if ( e - > right . sym = = & symbol_mod ) {
printf ( " boolean symbol %s tested for 'm'? test forced to 'n' \n " , e - > left . sym - > name ) ;
e - > type = E_SYMBOL ;
e - > left . sym = & symbol_no ;
e - > right . sym = NULL ;
break ;
}
if ( e - > right . sym = = & symbol_yes ) {
e - > type = E_SYMBOL ;
e - > right . sym = NULL ;
break ;
}
break ;
case E_UNEQUAL :
if ( e - > left . sym - > type ! = S_BOOLEAN )
break ;
if ( e - > right . sym = = & symbol_no ) {
e - > type = E_SYMBOL ;
e - > right . sym = NULL ;
break ;
}
if ( e - > right . sym = = & symbol_mod ) {
printf ( " boolean symbol %s tested for 'm'? test forced to 'y' \n " , e - > left . sym - > name ) ;
e - > type = E_SYMBOL ;
e - > left . sym = & symbol_yes ;
e - > right . sym = NULL ;
break ;
}
if ( e - > right . sym = = & symbol_yes ) {
e - > type = E_NOT ;
e - > left . expr = expr_alloc_symbol ( e - > left . sym ) ;
e - > right . sym = NULL ;
break ;
}
break ;
case E_NOT :
switch ( e - > left . expr - > type ) {
case E_NOT :
// !!a -> a
tmp = e - > left . expr - > left . expr ;
free ( e - > left . expr ) ;
free ( e ) ;
e = tmp ;
e = expr_transform ( e ) ;
break ;
case E_EQUAL :
case E_UNEQUAL :
// !a='x' -> a!='x'
tmp = e - > left . expr ;
free ( e ) ;
e = tmp ;
e - > type = e - > type = = E_EQUAL ? E_UNEQUAL : E_EQUAL ;
break ;
2015-06-15 15:00:21 +03:00
case E_LEQ :
case E_GEQ :
// !a<='x' -> a>'x'
tmp = e - > left . expr ;
free ( e ) ;
e = tmp ;
e - > type = e - > type = = E_LEQ ? E_GTH : E_LTH ;
break ;
case E_LTH :
case E_GTH :
// !a<'x' -> a>='x'
tmp = e - > left . expr ;
free ( e ) ;
e = tmp ;
e - > type = e - > type = = E_LTH ? E_GEQ : E_LEQ ;
break ;
2005-04-17 02:20:36 +04:00
case E_OR :
// !(a || b) -> !a && !b
tmp = e - > left . expr ;
e - > type = E_AND ;
e - > right . expr = expr_alloc_one ( E_NOT , tmp - > right . expr ) ;
tmp - > type = E_NOT ;
tmp - > right . expr = NULL ;
e = expr_transform ( e ) ;
break ;
case E_AND :
// !(a && b) -> !a || !b
tmp = e - > left . expr ;
e - > type = E_OR ;
e - > right . expr = expr_alloc_one ( E_NOT , tmp - > right . expr ) ;
tmp - > type = E_NOT ;
tmp - > right . expr = NULL ;
e = expr_transform ( e ) ;
break ;
case E_SYMBOL :
if ( e - > left . expr - > left . sym = = & symbol_yes ) {
// !'y' -> 'n'
tmp = e - > left . expr ;
free ( e ) ;
e = tmp ;
e - > type = E_SYMBOL ;
e - > left . sym = & symbol_no ;
break ;
}
if ( e - > left . expr - > left . sym = = & symbol_mod ) {
// !'m' -> 'm'
tmp = e - > left . expr ;
free ( e ) ;
e = tmp ;
e - > type = E_SYMBOL ;
e - > left . sym = & symbol_mod ;
break ;
}
if ( e - > left . expr - > left . sym = = & symbol_no ) {
// !'n' -> 'y'
tmp = e - > left . expr ;
free ( e ) ;
e = tmp ;
e - > type = E_SYMBOL ;
e - > left . sym = & symbol_yes ;
break ;
}
break ;
default :
;
}
break ;
default :
;
}
return e ;
}
int expr_contains_symbol ( struct expr * dep , struct symbol * sym )
{
if ( ! dep )
return 0 ;
switch ( dep - > type ) {
case E_AND :
case E_OR :
return expr_contains_symbol ( dep - > left . expr , sym ) | |
expr_contains_symbol ( dep - > right . expr , sym ) ;
case E_SYMBOL :
return dep - > left . sym = = sym ;
case E_EQUAL :
2015-06-15 15:00:21 +03:00
case E_GEQ :
case E_GTH :
case E_LEQ :
case E_LTH :
2005-04-17 02:20:36 +04:00
case E_UNEQUAL :
return dep - > left . sym = = sym | |
dep - > right . sym = = sym ;
case E_NOT :
return expr_contains_symbol ( dep - > left . expr , sym ) ;
default :
;
}
return 0 ;
}
bool expr_depends_symbol ( struct expr * dep , struct symbol * sym )
{
if ( ! dep )
return false ;
switch ( dep - > type ) {
case E_AND :
return expr_depends_symbol ( dep - > left . expr , sym ) | |
expr_depends_symbol ( dep - > right . expr , sym ) ;
case E_SYMBOL :
return dep - > left . sym = = sym ;
case E_EQUAL :
if ( dep - > left . sym = = sym ) {
if ( dep - > right . sym = = & symbol_yes | | dep - > right . sym = = & symbol_mod )
return true ;
}
break ;
case E_UNEQUAL :
if ( dep - > left . sym = = sym ) {
if ( dep - > right . sym = = & symbol_no )
return true ;
}
break ;
default :
;
}
return false ;
}
2017-10-08 20:50:55 +03:00
/*
* Inserts explicit comparisons of type ' type ' to symbol ' sym ' into the
* expression ' e ' .
*
* Examples transformations for type = = E_UNEQUAL , sym = = & symbol_no :
*
* A - > A ! = n
* ! A - > A = n
* A & & B - > ! ( A = n | | B = n )
* A | | B - > ! ( A = n & & B = n )
* A & & ( B | | C ) - > ! ( A = n | | ( B = n & & C = n ) )
*
* Allocates and returns a new expression .
*/
2005-04-17 02:20:36 +04:00
struct expr * expr_trans_compare ( struct expr * e , enum expr_type type , struct symbol * sym )
{
struct expr * e1 , * e2 ;
if ( ! e ) {
e = expr_alloc_symbol ( sym ) ;
if ( type = = E_UNEQUAL )
e = expr_alloc_one ( E_NOT , e ) ;
return e ;
}
switch ( e - > type ) {
case E_AND :
e1 = expr_trans_compare ( e - > left . expr , E_EQUAL , sym ) ;
e2 = expr_trans_compare ( e - > right . expr , E_EQUAL , sym ) ;
if ( sym = = & symbol_yes )
e = expr_alloc_two ( E_AND , e1 , e2 ) ;
if ( sym = = & symbol_no )
e = expr_alloc_two ( E_OR , e1 , e2 ) ;
if ( type = = E_UNEQUAL )
e = expr_alloc_one ( E_NOT , e ) ;
return e ;
case E_OR :
e1 = expr_trans_compare ( e - > left . expr , E_EQUAL , sym ) ;
e2 = expr_trans_compare ( e - > right . expr , E_EQUAL , sym ) ;
if ( sym = = & symbol_yes )
e = expr_alloc_two ( E_OR , e1 , e2 ) ;
if ( sym = = & symbol_no )
e = expr_alloc_two ( E_AND , e1 , e2 ) ;
if ( type = = E_UNEQUAL )
e = expr_alloc_one ( E_NOT , e ) ;
return e ;
case E_NOT :
return expr_trans_compare ( e - > left . expr , type = = E_EQUAL ? E_UNEQUAL : E_EQUAL , sym ) ;
case E_UNEQUAL :
2015-06-15 15:00:21 +03:00
case E_LTH :
case E_LEQ :
case E_GTH :
case E_GEQ :
2005-04-17 02:20:36 +04:00
case E_EQUAL :
if ( type = = E_EQUAL ) {
if ( sym = = & symbol_yes )
return expr_copy ( e ) ;
if ( sym = = & symbol_mod )
return expr_alloc_symbol ( & symbol_no ) ;
if ( sym = = & symbol_no )
return expr_alloc_one ( E_NOT , expr_copy ( e ) ) ;
} else {
if ( sym = = & symbol_yes )
return expr_alloc_one ( E_NOT , expr_copy ( e ) ) ;
if ( sym = = & symbol_mod )
return expr_alloc_symbol ( & symbol_yes ) ;
if ( sym = = & symbol_no )
return expr_copy ( e ) ;
}
break ;
case E_SYMBOL :
return expr_alloc_comp ( type , e - > left . sym , sym ) ;
2008-01-14 06:50:23 +03:00
case E_LIST :
2005-04-17 02:20:36 +04:00
case E_RANGE :
case E_NONE :
/* panic */ ;
}
return NULL ;
}
2015-06-15 15:00:21 +03:00
enum string_value_kind {
k_string ,
k_signed ,
k_unsigned ,
} ;
union string_value {
unsigned long long u ;
signed long long s ;
} ;
static enum string_value_kind expr_parse_string ( const char * str ,
enum symbol_type type ,
union string_value * val )
{
char * tail ;
enum string_value_kind kind ;
errno = 0 ;
switch ( type ) {
case S_BOOLEAN :
case S_TRISTATE :
2017-11-17 04:06:39 +03:00
val - > s = ! strcmp ( str , " n " ) ? 0 :
! strcmp ( str , " m " ) ? 1 :
! strcmp ( str , " y " ) ? 2 : - 1 ;
return k_signed ;
2015-06-15 15:00:21 +03:00
case S_INT :
val - > s = strtoll ( str , & tail , 10 ) ;
kind = k_signed ;
break ;
case S_HEX :
val - > u = strtoull ( str , & tail , 16 ) ;
kind = k_unsigned ;
break ;
2018-11-30 12:15:52 +03:00
default :
2015-06-15 15:00:21 +03:00
val - > s = strtoll ( str , & tail , 0 ) ;
kind = k_signed ;
break ;
}
return ! errno & & ! * tail & & tail > str & & isxdigit ( tail [ - 1 ] )
? kind : k_string ;
}
2005-04-17 02:20:36 +04:00
tristate expr_calc_value ( struct expr * e )
{
tristate val1 , val2 ;
const char * str1 , * str2 ;
2015-06-15 15:00:21 +03:00
enum string_value_kind k1 = k_string , k2 = k_string ;
union string_value lval = { } , rval = { } ;
int res ;
2005-04-17 02:20:36 +04:00
if ( ! e )
return yes ;
switch ( e - > type ) {
case E_SYMBOL :
sym_calc_value ( e - > left . sym ) ;
return e - > left . sym - > curr . tri ;
case E_AND :
val1 = expr_calc_value ( e - > left . expr ) ;
val2 = expr_calc_value ( e - > right . expr ) ;
2008-01-07 23:09:55 +03:00
return EXPR_AND ( val1 , val2 ) ;
2005-04-17 02:20:36 +04:00
case E_OR :
val1 = expr_calc_value ( e - > left . expr ) ;
val2 = expr_calc_value ( e - > right . expr ) ;
2008-01-07 23:09:55 +03:00
return EXPR_OR ( val1 , val2 ) ;
2005-04-17 02:20:36 +04:00
case E_NOT :
val1 = expr_calc_value ( e - > left . expr ) ;
2008-01-07 23:09:55 +03:00
return EXPR_NOT ( val1 ) ;
2005-04-17 02:20:36 +04:00
case E_EQUAL :
2015-06-15 15:00:21 +03:00
case E_GEQ :
case E_GTH :
case E_LEQ :
case E_LTH :
2005-04-17 02:20:36 +04:00
case E_UNEQUAL :
2015-06-15 15:00:21 +03:00
break ;
2005-04-17 02:20:36 +04:00
default :
printf ( " expr_calc_value: %d? \n " , e - > type ) ;
return no ;
}
2015-06-15 15:00:21 +03:00
sym_calc_value ( e - > left . sym ) ;
sym_calc_value ( e - > right . sym ) ;
str1 = sym_get_string_value ( e - > left . sym ) ;
str2 = sym_get_string_value ( e - > right . sym ) ;
if ( e - > left . sym - > type ! = S_STRING | | e - > right . sym - > type ! = S_STRING ) {
k1 = expr_parse_string ( str1 , e - > left . sym - > type , & lval ) ;
k2 = expr_parse_string ( str2 , e - > right . sym - > type , & rval ) ;
}
if ( k1 = = k_string | | k2 = = k_string )
res = strcmp ( str1 , str2 ) ;
2018-11-30 12:15:52 +03:00
else if ( k1 = = k_unsigned | | k2 = = k_unsigned )
2015-06-15 15:00:21 +03:00
res = ( lval . u > rval . u ) - ( lval . u < rval . u ) ;
else /* if (k1 == k_signed && k2 == k_signed) */
res = ( lval . s > rval . s ) - ( lval . s < rval . s ) ;
switch ( e - > type ) {
case E_EQUAL :
return res ? no : yes ;
case E_GEQ :
return res > = 0 ? yes : no ;
case E_GTH :
return res > 0 ? yes : no ;
case E_LEQ :
return res < = 0 ? yes : no ;
case E_LTH :
return res < 0 ? yes : no ;
case E_UNEQUAL :
return res ? yes : no ;
default :
printf ( " expr_calc_value: relation %d? \n " , e - > type ) ;
return no ;
}
2005-04-17 02:20:36 +04:00
}
2015-02-24 18:37:13 +03:00
static int expr_compare_type ( enum expr_type t1 , enum expr_type t2 )
2005-04-17 02:20:36 +04:00
{
if ( t1 = = t2 )
return 0 ;
switch ( t1 ) {
2015-06-15 15:00:21 +03:00
case E_LEQ :
case E_LTH :
case E_GEQ :
case E_GTH :
if ( t2 = = E_EQUAL | | t2 = = E_UNEQUAL )
return 1 ;
2005-04-17 02:20:36 +04:00
case E_EQUAL :
case E_UNEQUAL :
if ( t2 = = E_NOT )
return 1 ;
case E_NOT :
if ( t2 = = E_AND )
return 1 ;
case E_AND :
if ( t2 = = E_OR )
return 1 ;
case E_OR :
2008-01-14 06:50:23 +03:00
if ( t2 = = E_LIST )
2005-04-17 02:20:36 +04:00
return 1 ;
2008-01-14 06:50:23 +03:00
case E_LIST :
2005-04-17 02:20:36 +04:00
if ( t2 = = 0 )
return 1 ;
default :
return - 1 ;
}
printf ( " [%dgt%d?] " , t1 , t2 ) ;
return 0 ;
}
2018-02-20 11:18:47 +03:00
void expr_print ( struct expr * e ,
void ( * fn ) ( void * , struct symbol * , const char * ) ,
void * data , int prevtoken )
2005-04-17 02:20:36 +04:00
{
if ( ! e ) {
2006-06-09 09:12:47 +04:00
fn ( data , NULL , " y " ) ;
2005-04-17 02:20:36 +04:00
return ;
}
if ( expr_compare_type ( prevtoken , e - > type ) > 0 )
2006-06-09 09:12:47 +04:00
fn ( data , NULL , " ( " ) ;
2005-04-17 02:20:36 +04:00
switch ( e - > type ) {
case E_SYMBOL :
if ( e - > left . sym - > name )
2006-06-09 09:12:47 +04:00
fn ( data , e - > left . sym , e - > left . sym - > name ) ;
2005-04-17 02:20:36 +04:00
else
2006-06-09 09:12:47 +04:00
fn ( data , NULL , " <choice> " ) ;
2005-04-17 02:20:36 +04:00
break ;
case E_NOT :
2006-06-09 09:12:47 +04:00
fn ( data , NULL , " ! " ) ;
2005-04-17 02:20:36 +04:00
expr_print ( e - > left . expr , fn , data , E_NOT ) ;
break ;
case E_EQUAL :
2008-01-24 14:54:23 +03:00
if ( e - > left . sym - > name )
fn ( data , e - > left . sym , e - > left . sym - > name ) ;
else
fn ( data , NULL , " <choice> " ) ;
2006-06-09 09:12:47 +04:00
fn ( data , NULL , " = " ) ;
fn ( data , e - > right . sym , e - > right . sym - > name ) ;
2015-06-15 15:00:21 +03:00
break ;
case E_LEQ :
case E_LTH :
if ( e - > left . sym - > name )
fn ( data , e - > left . sym , e - > left . sym - > name ) ;
else
fn ( data , NULL , " <choice> " ) ;
fn ( data , NULL , e - > type = = E_LEQ ? " <= " : " < " ) ;
fn ( data , e - > right . sym , e - > right . sym - > name ) ;
break ;
case E_GEQ :
case E_GTH :
if ( e - > left . sym - > name )
fn ( data , e - > left . sym , e - > left . sym - > name ) ;
else
fn ( data , NULL , " <choice> " ) ;
2015-10-19 17:51:02 +03:00
fn ( data , NULL , e - > type = = E_GEQ ? " >= " : " > " ) ;
2015-06-15 15:00:21 +03:00
fn ( data , e - > right . sym , e - > right . sym - > name ) ;
2005-04-17 02:20:36 +04:00
break ;
case E_UNEQUAL :
2008-01-24 14:54:23 +03:00
if ( e - > left . sym - > name )
fn ( data , e - > left . sym , e - > left . sym - > name ) ;
else
fn ( data , NULL , " <choice> " ) ;
2006-06-09 09:12:47 +04:00
fn ( data , NULL , " != " ) ;
fn ( data , e - > right . sym , e - > right . sym - > name ) ;
2005-04-17 02:20:36 +04:00
break ;
case E_OR :
2018-02-20 11:18:47 +03:00
expr_print ( e - > left . expr , fn , data , E_OR ) ;
fn ( data , NULL , " || " ) ;
expr_print ( e - > right . expr , fn , data , E_OR ) ;
2005-04-17 02:20:36 +04:00
break ;
case E_AND :
expr_print ( e - > left . expr , fn , data , E_AND ) ;
2006-06-09 09:12:47 +04:00
fn ( data , NULL , " && " ) ;
2005-04-17 02:20:36 +04:00
expr_print ( e - > right . expr , fn , data , E_AND ) ;
break ;
2008-01-14 06:50:23 +03:00
case E_LIST :
2006-06-09 09:12:47 +04:00
fn ( data , e - > right . sym , e - > right . sym - > name ) ;
2005-04-17 02:20:36 +04:00
if ( e - > left . expr ) {
2006-06-09 09:12:47 +04:00
fn ( data , NULL , " ^ " ) ;
2008-01-14 06:50:23 +03:00
expr_print ( e - > left . expr , fn , data , E_LIST ) ;
2005-04-17 02:20:36 +04:00
}
break ;
case E_RANGE :
2006-06-09 09:12:47 +04:00
fn ( data , NULL , " [ " ) ;
fn ( data , e - > left . sym , e - > left . sym - > name ) ;
fn ( data , NULL , " " ) ;
fn ( data , e - > right . sym , e - > right . sym - > name ) ;
fn ( data , NULL , " ] " ) ;
2005-04-17 02:20:36 +04:00
break ;
default :
{
char buf [ 32 ] ;
sprintf ( buf , " <unknown type %d> " , e - > type ) ;
2006-06-09 09:12:47 +04:00
fn ( data , NULL , buf ) ;
2005-04-17 02:20:36 +04:00
break ;
}
}
if ( expr_compare_type ( prevtoken , e - > type ) > 0 )
2006-06-09 09:12:47 +04:00
fn ( data , NULL , " ) " ) ;
2005-04-17 02:20:36 +04:00
}
2006-06-09 09:12:47 +04:00
static void expr_print_file_helper ( void * data , struct symbol * sym , const char * str )
2005-04-17 02:20:36 +04:00
{
2010-08-05 02:01:02 +04:00
xfwrite ( str , strlen ( str ) , 1 , data ) ;
2005-04-17 02:20:36 +04:00
}
void expr_fprint ( struct expr * e , FILE * out )
{
expr_print ( e , expr_print_file_helper , out , E_NONE ) ;
}
2006-06-09 09:12:47 +04:00
static void expr_print_gstr_helper ( void * data , struct symbol * sym , const char * str )
2005-04-17 02:20:36 +04:00
{
2009-12-20 11:29:49 +03:00
struct gstr * gs = ( struct gstr * ) data ;
const char * sym_str = NULL ;
if ( 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 ) ;
2010-05-07 09:56:50 +04:00
if ( sym & & sym - > type ! = S_UNKNOWN )
2009-12-20 11:29:49 +03:00
str_printf ( gs , " [=%s] " , sym_str ) ;
2005-04-17 02:20:36 +04:00
}
void expr_gstr_print ( struct expr * e , struct gstr * gs )
{
expr_print ( e , expr_print_gstr_helper , gs , E_NONE ) ;
}
2018-01-25 12:46:35 +03:00
/*
* Transform the top level " || " tokens into newlines and prepend each
* line with a minus . This makes expressions much easier to read .
* Suitable for reverse dependency expressions .
*/
2018-02-20 11:18:47 +03:00
static void expr_print_revdep ( struct expr * e ,
void ( * fn ) ( void * , struct symbol * , const char * ) ,
2018-02-24 18:24:18 +03:00
void * data , tristate pr_type , const char * * title )
2018-02-20 11:18:47 +03:00
{
if ( e - > type = = E_OR ) {
2018-02-24 18:24:18 +03:00
expr_print_revdep ( e - > left . expr , fn , data , pr_type , title ) ;
expr_print_revdep ( e - > right . expr , fn , data , pr_type , title ) ;
} else if ( expr_calc_value ( e ) = = pr_type ) {
if ( * title ) {
fn ( data , NULL , * title ) ;
* title = NULL ;
}
2018-02-20 11:18:47 +03:00
fn ( data , NULL , " - " ) ;
expr_print ( e , fn , data , E_NONE ) ;
fn ( data , NULL , " \n " ) ;
}
}
2018-02-24 18:24:18 +03:00
void expr_gstr_print_revdep ( struct expr * e , struct gstr * gs ,
tristate pr_type , const char * title )
2018-01-25 12:46:35 +03:00
{
2018-02-24 18:24:18 +03:00
expr_print_revdep ( e , expr_print_gstr_helper , gs , pr_type , & title ) ;
2018-01-25 12:46:35 +03:00
}