Results 1 to 2 of 2

Thread: Suggestions for logical expression syntax?

  1. #1
    Join Date
    Aug 2009
    Posts
    56
    Thanks
    14
    Thanked 1 Time in 1 Post

    Default Suggestions for logical expression syntax?

    I want the user to be able to do something like this

    (column1 has changed AND column2 has not changed) OR (column 3 has changed)

    A couple of ideas I had to let the user express this:

    C Style:
    (column1(CHANGED) AND column2(NOT_CHANGED)) OR (column3(CHANGED)

    Postfix:

    OR, AND, CHANGED, column1, NOT_CHANGED, column2, column 3

    Let the user connect nodes in a graph view. Two or more links means OR, one link means AND.

    -------- -----------------------
    |Start|---->| column1 (Changed |-----> (etc)
    ______ -------------------------

    However, these are a lot of work. I was wondering if anyone had any suggestions. Maybe there is a library or built-in feature for something like this already?

  2. #2
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: Suggestions for logical expression syntax?

    Usually you'd use predicates and either prefix or infix operators:

    (column1 has changed AND column2 has not changed) OR (column 3 has changed)

    "( changed(column1) AND NOT changed(column2) ) OR changed(column3)"

    It's just a couple of minutes of work to implement a parser and interpreter for such a language. You may use parser generators (like qlalr for Qt) if you want but if you haven't used one before, it'll be faster to implement the parser manually.

    Just for completeness a full grammar of the language in EBNF:

    ebnf Code:
    1. Expression ::== LogicalValue | OrExpression | AndExpression | NotExpression | ParenthesisExpression ;
    2. OrExpression ::== Expression 'OR' Expression ;
    3. AndExpression ::== Expression 'AND' Expression ;
    4. NotExpression ::== 'NOT' Expression ;
    5. ParenthesisExpression ::== '(' Expression ')' ;
    6. LogicalValue :: == 'TRUE' | 'FALSE' | Predicate ;
    7. Predicate ::== AlNumString '(' AlNumString ')' ;
    8. AlNumString ::== (A..Z|a..z)(A..Z|a..z|0..9)* ;
    To copy to clipboard, switch view to plain text mode 

    And a skeletal implementation for OrExpression:

    Qt Code:
    1. class Node {
    2. public:
    3. virtual bool Interprete() = 0;
    4. };
    5. class OrNode : public Node {
    6. public:
    7. OrNode(Node *left, Node *right){ m_left = left; m_right = right; }
    8. bool Interprete() { return (left->Interprete() || right->Interprete()); }
    9. private:
    10. Node *m_left, *m_right;
    11. };
    To copy to clipboard, switch view to plain text mode 
    The parsing code has to first do a lexical analysis by dividing the input into tokens and then start matching tokens to ones you expect. For instance at top level you can either encounter one of the following tokens: TRUE, FALSE, AlNumString, NOT, '('. First three correspond to LogicalValue, the fourth one to a NotExpression and the last one to ParenthesisExpression. Then you can call an appropriate subroutine that will return a node and information about where it stopped parsing. If you encounter an OR token, you call a subroutine to parse the right part (the left one is already parsed) and then you create an OrNode and assign the two obtained nodes to it. At some point you'll either encounter a parse error (unexpected token) or end of input. At that point the last node will be the root of your abstract syntax tree. You can call Interprete() on it to get the boolean value of the whole expression.

    This is really simple and not as much work as you'd think.

    Qt Code:
    1. Node *parseExpression(QList<Token> &tokens){
    2. Token t = tokens.first();
    3. if(t.type == T_TRUE || t.type == T_FALSE || t.type == T_IDENT) return parseLogicalValue(tokens);
    4. else if(t.type == T_NOT) return parseNotExpression(tokens);
    5. else if(t.type == T_LPAREN) return parseParenthesisExpression(tokens);
    6. else return 0; // parse error
    7. }
    8.  
    9. Node *parseNotExpression(QList<Token> &tokens){
    10. Token t = tokens.first();
    11. if(t.type != T_NOT) return 0; // parse error
    12. tokens.takeFirst(); // removes T_NOT from input
    13. Node *subNode = parseExpression(tokens);
    14. if(!subNode) return 0; // propagate parse error
    15. return new NotNode(subNode);
    16. }
    To copy to clipboard, switch view to plain text mode 
    etc.
    Last edited by wysota; 19th September 2009 at 20:31.
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  3. The following 2 users say thank you to wysota for this useful post:

    drhex (19th September 2009), rakkar (19th September 2009)

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Digia, Qt and their respective logos are trademarks of Digia Plc in Finland and/or other countries worldwide.