简体   繁体   中英

Distribution of NOT token in bison

Given an input of an if condition (only the conditions part) written in C++, I want to distribute the "nots" by the laws of De Morgan. The problem is that according to my rules, the recursion does not allow me to get immediately the expressions within parentheses when I find a symbol "!", Then I can distribute. Let me explain with an example:

input: (!(a&&(b&&!(c&&d))))

output (In the time that each token is found.): c AND d ) ( b AND NOT b ) ( a AND ) ( ) ( NOT

The output is disordered by the recursion, but in this conditions, how can I apply De Morgan's laws?, in the case of this input, I want to get:

(!(a&&(b&&!(c&&d))))->(!a&&!(b&&!(c&&d)))->(!a&&b&&(c||d))

Note that every time that I found a ! token, is immediately used distributing in the next parentheses. If I get (!a&&b) , I dont have to use it, only when I found ! and ( as the next symbol.

So, the problem is: I can't distribute the ! token in the next group of the condition, because I'm getting all the tokens in disorder.

This is possible?, how can I define my rules to do this?

main.cpp:

#include <iostream>
#include <string>
#include "lex.yy.c"

using namespace std;

typedef yy_buffer_state *YY_BUFFER_STATE;
extern int yyparse();
extern YY_BUFFER_STATE yy_scan_buffer(char *, size_t);

int main(int argc, char** argv) {

    char condition[] = "(!(a&&(b&&!(c&&d)))) \0\0";

    yy_scan_buffer(condition, sizeof(condition));

    yyparse();

    return 0;
}

scanner.l:

%option noyywrap
%{
    #include <iostream>
    #include "parser.tab.c"
    using namespace std;
%}

%%

[a-zA-Z0-9<>=]+  {
    yylval = strdup(yytext);
    return SYMBOL;
}

"&&" {
    return AND;
}

"||" {
    return OR;
}

"!" {
    return NOT;
}

[ \0\0] {
    return END;
}

"("     {
    return LEFT_PAR;
}

")"     {
    return RIGHT_PAR;
}

%%

bison.y:

%{
    #include <iostream>
    #include <string>

    using namespace std;

    int yylex(void);
    void yyerror(char *);

    #define YYSTYPE string
%}

%token  LEFT_PAR
        RIGHT_PAR
        SYMBOL
        END
        NOT

%left
        AND
        OR

%start input

%%

input:

    |   input terms
;

terms:
        LEFT_PAR terms close_terms        {  
            cout << " ( ";
        }
    |   LEFT_PAR condition close_terms       {  
            cout << " ( ";
        }
    |   LEFT_PAR NOT condition close_terms   {
            cout << " ( NOT ";
        }
    |   LEFT_PAR NOT terms close_terms    {
            cout << " ( NOT ";
        }
;

close_terms:
    RIGHT_PAR { 
        cout << " ) ";
    }
;

binary_condition:
        terms AND terms   { 
            cout << " AND ";
        }
    |   SYMBOL AND terms    {
            cout << $1 << " AND ";
        }
    |   SYMBOL AND NOT terms {
            cout << $1 << " AND NOT " << $3;
        }
    |   terms AND SYMBOL    {
            cout << " AND " << $3;
        }
    |   SYMBOL AND SYMBOL     {
            cout << $1 << " AND " << $3;
        }
    |   SYMBOL AND NOT SYMBOL {
            cout << $1 << " AND NOT " << $4;
        }



    |   terms OR terms    { 
            cout << " OR ";
        }
    |   SYMBOL OR terms     {
            cout << $1 << " OR ";
        }
    |   SYMBOL OR NOT terms {
            cout << $1 << " OR NOT ";
        }
    |   terms OR SYMBOL     {
            cout << " OR " << $3;
        }
    |   SYMBOL OR SYMBOL      {
            cout << $1 << " OR " << $3;
        }
    |   SYMBOL OR NOT SYMBOL {
            cout << $1 << " OR NOT " << $4;
        }
;


condition:
        SYMBOL                         {
            cout << $1;
        }          
    |   binary_condition
    |   binary_condition AND condition  
    |   binary_condition OR condition
;

%%

void yyerror(char *s) {

}

Thanks!

It usually makes the most sense to make your grammar as simple as possible for what you wish to parse, and then think of any transformations you want to make as transformations on the parse tree, rather than trying to change the grammar in some way. In your case, you have a very confused grammar -- you've made AND and OR right recursive and equal in precedence (despite the %left declaration, which has no effect as there are no conflicts for it to resolve.)

So you start with the simple grammar for expressions:

%left '|'
%left '&'   /* & and | are left recursive, with & having higher precedence */
%%

input: /* empty */ | input expr '\n' ;

expr: SYMBOL | '(' expr ')' | '!' expr | expr '&' expr | expr '|' expr

Then you add rules to build expression tree data structures and transform them:

input: /* empty */ | input expr '\n' { PrintExpr(ConvertToNormalForm($2)); }
expr: SYMBOL { $$ = CreateSymbolNode($1); }
    | '(' expr ')' { $$ = $2; }
    | '!' expr { $$ = CreateUnaryNode('!', $2); }
    | expr '&' expr { $$ = CreateBinaryNode('&', $1, $3); }
    | expr '|' expr { $$ = CreateBinaryNode('|', $1, $3); }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM