I have implemented shunting-yard algorithm to parse arithmetic string-expressions from infix to postfix-notation.
I now also want to parse expressions with relational operators and Ternary conditional. Considering C++ Operator Precedence i added those operators with the lowest precedence and right-associativity for ? and : and the second-lowest and left-associativity for > and <.
When i now parse an expression like: A>B?C:D (where A, B, C and D can be any valid arithmetic expression) i would expect: A B > C D : ?, but i get A B C D : ? <. When i use Parentheses to evaluate the Condition first (A>B)?C:D it works. A mixed expression like (1+2<3+4)?C:D gives me 1 2 + 3 4 + < C D : ? which seems also legit to me. (A<B)?5+6:C gives me A B < 5 6 : + ? which again is messed up. Again, (A<B)?(5+6):C would fix that.
As stated in the comments, evaluating conditions first and the proceed with the left arithmetic expression would also be fine. But i really did not stumble upon an algorithm for evaluating expressions with relational and ternary operators in my research yet. Any help, even if pointing out an algorithm would be very appreciated
Here is the implementation of shunting-yard:
QQueue<QString> ShuntingYard::infixToPostfixWithConditionals(const QString& expression)
{
QStack<QString> stack;
QQueue<QString> queue;
QString token;
QStringList tokens = splitExpression(expression);
Q_FOREACH(QString token, tokens)
{
if (isDefineOrNumber(token))
queue.enqueue(token);
if (isFunction(token))
stack.push(token);
if (isOperator(token))
{
while (!stack.isEmpty() && isOperator(stack.top()) && isLeftAssociativeOperator(token) && !hasHigherPrecedence(token, stack.top()))
queue.enqueue(stack.pop());
stack.push(token);
}
if (isLeftParenthese(token))
stack.push(token);
else if (isRightParenthese(token))
{
while (!isLeftParenthese(stack.top()))
{
if (stack.isEmpty())
break;
if (isOperator(stack.top()))
queue.enqueue(stack.pop());
}
stack.pop();
if (isFunction(stack.top()))
queue.enqueue(stack.pop());
}
}
while (!stack.isEmpty())
{
if (isLeftParenthese(stack.top()))
break;
queue.enqueue(stack.pop());
}
return queue;
}
EDIT: made code and description more concise for readabilility
Another EDIT: Treating ?: as left-associative gave me the expected output
Now, regarding this question about the associativity of ternary conditionals. If i input a<b?a:b?c:d i get a b < a b c d : ? : ?, where a < b will be evaluated first, which is correct, due to its higher precedence, but then b ? c : d will be evaluated first, which is the correct right-to-left order. Confusing.
Related
Does spaces have any meaning in these expressions:
assume:
int a = 1;
int b = 2;
1)
int c = a++ +b;
Or,
2)
int c = a+ ++b;
When I run these two in visual studio, I get different results. Is that the correct behavior, and what does the spec says?
In general, what should be evaluated first, post-increment or pre-increment?
Edit: I should say that
c =a+++b;
Does not compile on visual studio. But I think it should. The postfix++ seems to be evaluated first.
Is that the correct behavior
Yes, it is.
Postfix ++ first returns the current value, then increments it. so int c = a++ +b means compute the value of c as the sum between current a(take the current a value, and only after taking it, increment a) and b;
Prefix ++ first increments the current value, then returns the value already incremented, so in this case, int c = a+ ++b means compute c as the sum between a and the return of the next expression, ++b, which means b is first incremented, then returned.
In general, what should be evaluated first, post-increment or
pre-increment?
In this example, it is not about which gets evaluated first, it is about what each does - postfix first returns the value, then increments it; prefix first increments the value, then returns it.
Hth
Maybe it helps to understand the general architecture of how programs are parsed.
In a nutshell, there are two stages to parsing a program (C++ or others): lexer and parser.
The lexer takes the text input and maps it to a sequence of symbols. This is when spaces are handled because they tell where the symbols are. Spaces really matter at some places (like between int and c, to not confuse with the symbol intc) but not others (like between a and ++ because there is no ambiguity to separate them).
The first example:
int c = a++ +b;
gives the following symbols, each on its own row (implementations may do this in slightly different ways of course):
int
c
=
a
++
+
b
;
While in the other case:
int c = a+ ++b;
the symbols are instead:
int
c
=
a
+
++
b
;
The parser then builds a tree (Abstract Syntax Tree, AST) out of the symbols and according to some grammar. In particular, according to the C++ grammar, + as an addition has a lower precedence than the unary ++ operator (regardless of postfix or prefix). This means that the first example is semantically the same as (a++) + b while the second is like a+ (++b).
For your examples, the ASTs will be different, because the spaces already lead to a different output at the lexer phase.
Note that spaces are not required between ++ and +, so a+++b would theoretically be fine, but this is not recommended for readability. So, some spaces are important for technical reasons while others are important for us users to read the code.
Yes they should be different; the behaviour is correct.
There are a few possible sources for your confusion.
This question is not about "spaces in operators". You have different operators. If you were to remove the space, you would have a different question. See What is i+++ increment in c++
It's also not about "what should be evaluated first, post-increment or pre-increment". It's about understanding the difference between post-increment and pre-increment.
Both increment the variable to which they apply.
But the post-increment expression returns the value from before the increment.
Whereas the pre-increment expression returns the value after the increment.
I.e.
//Given:
int a = 1;
int b = 2;
//Post-increment
int c = a++ +b; =>
1 + 2; (and a == 2) =>
3;
//Pre-increment
int c = a+ ++b; =>
1 + 3; (and b == 3) =>
4;
Another thing that might be causing confusion. You wrote: a++ +b;. And you may be assuming that +b is the unary + operator. This would be an incorrect assumption because you have both left and right operands making that + a binary additive operator (as in x + y).
Final possible confusion. You may be wondering why:
in a++ +b the ++ is a post-increment operator applied to a.
whereas in a+ ++b it's a pre-increment operator applied to b.
The reason is that ++ has higher precedence than the binary additive +. And in both cases it would be impossible to apply ++ to +.
int x = 5,y = 10;
bool boolean = 0;
int k = (boolean ? ++x, ++y : --x, --y);
cout<<k;
When boolean is 0,it outputs 9, however when it is 1 it outputs 10.I know this is happening because of precedence but cannot exactly figure out how is it happening, please help me understand this.
NOTE:I know I can get the expected output if I use parenthesis,or better write a clean code,I am just using this to understand how compiler would evaluate expressions like these according to precedence.
, has lower precedence than ?:. Which means that the full parenthesising is:
int k = ((boolean ? (++x, ++y) : --x), --y);
As you can see, k is always initialised to the value of --y. It's just that if boolean is true, ++y happens before that.
When looking for the full parenthesis form of an expression, think of it as constructing the expression tree (where the lowest-precedence operator is at the root).
Find the lowest-precedence operator in an expression, and parenthesise its left-hand side argument and its right-hand side argument. Repeat recursively within the sub-expressions just parenthesised.
Due to the comma operator having the lowest operator precedence, your statement is actually equal to
k = (boolean ? (++x, ++y) : --x), --y;
That means when boolean is true you both increase and decrease y. The result of the ternary expression is thrown away in both cases and k is only assigned the result of --y.
It should be noted that this is not undefined behavior, as the comma operator introduces a sequence point.
To get the result you expect, you need to do
k = boolean ? (++x, ++y) : (--x, --y);
Note that the parentheses around ++x, ++y is strictly not needed, but it does make the expression clearer.
Given the above excellent answers, one should write instead:
if (boolean) {
++x;
++y;
} else {
--x;
--y;
}
int k = y;
Because then the code is more readable and clear in its intent. This will help anyone who has to maintain the code (including the original author!) without anyone having to waste time by asking SO questions or worrying about the precedence of , or ?: or what the logistics of assignment to such a complex expression are. Any modern compiler will optimize both this and the above to the same resulting code
This question already has answers here:
What does the question mark character ('?') mean in C++?
(8 answers)
Closed 7 years ago.
Consider this function
template<class T> inline bool cx(T &a, T b) {return a < b ? a = b, 1 : 0;}
Can anyone explain what exactly this is doing? It seems different from the typical condition ? true : false format.
We could make it more clear like so:
return a < b ? (a = b, 1) : 0;
The parenthesized bit means "assign b to a, then use 1 as our value".
Comma-separated lists of values in C and C++ generally mean "evaluate all of these, but use the last one as the expression's value".
This combination is a little tricky, because it combines a comma operator with the conditional expression. It parses as follows:
a < b is the condition,
a = b, 1 is the "when true" expression
0 is the "when false" expression
The result of the comma operator is its last component, i.e. 1. The goal of employing the comma operator in the first place is to cause the side effect of assigning b to a.
You can execute several expression using ,
In this case if a < b, then assign b to a and return 1. According C++ grammar:
conditional-expression:
logical-or-expression
| logical-or-expression ? expression : assignment-expression
where
expression:
assignment-expression
| expression , assignment-expression
assignment-expression:
conditional-expression
| logical-or-expression assignment-operator initializer-clause
| throw-expression
The , operator just evaluates all the expressions, left to right, and evaluates to the value of the rightmost expression.
Your code is the same as...
if (a < b)
{
a = b;
return 1;
}
else
{
return 0;
}
Read it as:
if ( a < b )
{
a = b;
return ( 1 );
}
else
{
return ( 0 );
}
a < b ? a = b, 1 : 0 is parsed as (a < b) ? (a = b, 1) : 0, a normal conditional operator. When a < b is true, a = b, 1 is evaluated by assigning b to a and then "returning" 1. The net effect of cx(a,b) is thus to assign the larger value to a and to return 1 if a changed, 0 otherwise.
In the following code,
int main() {
int a =1, b = 2, c = 3;
if(((a++) == 5) && ((b++) == 5) && ((c++) == 5)) {
cout<<"inside if"<< endl; // prints !!!Hello World!!!
}
cout<<a<<b<<c<<endl;
return 0;
}
all increment operation should be done before doing logical operation. But execution skips increment b and c. Why logical && precede over ()? By the way, result of this code is 223.
Because of short circuiting: when the left hand side of && is false, the right-hand side is not evaluated. The precedence, on the other hand, is the way you think it should be (and, as AnT says, it's unrelated to the behavior you're seeing): () has precedence over &&.
(Similarly, when the left hand side of || is true, the right-hand side is not evaluated.)
all increment operation should be done before doing logical operation
This is simply not true. There's no reason why increment operation should be done before doing logical operation and () does not change that in any way. As it has been stated many times before, operator precedence does not have anything to do with order of evaluation. These are two completely unrelated concepts.
At the top level, your expression has the following structure
<term1> && <term2> && <term3> && ... && <termN>
Such expressions are always evaluated in strictly sequenced left-to-right order from <term1> to <termN> (with possibly short-circuited evaluation). It is completely irrelevant what you have inside those terms: nothing inside <term2> will ever be evaluated before <term1>.
I just saw the code and I am unable to understand how the logical and behaves with "cout" here:
int userInput = 9; // Suppose user input is 9.
int remainder = 9 % 2;
(remainder & 1 && std::cout<<"odd" )|| cout<<"even";
std::cout<<"odd" is an expression that will return std::cout (which is why you can do std::cout << a << b << c). When evaluated in boolean context, it simply returns true if the fail bit isn't set. So if the output operation succeeds then it will evaluate as true.
However, the intent of this code isn't to test that value, rather it is a clever (and not very readable)1 way to express this:
if (remainder & 1) {
std::cout << "odd";
} else {
std::cout << "even";
}
It takes advantage of the short-circuiting nature of the && and || operators:
In a && b, if a is false then it evaluates as a (b is not evaluated!) otherwise it evaluates as b.
In a || b, if a is true then it evaluates as a (b is not evaluated!) otherwise it evaluates as b.
So if remainder & 1 evaluates as false (zero in this case) then std::cout << "odd" is not evaluated because the && expression short-circuits, returning false. This is the left operand to the outer || expression, which causes its b (std::cout << "even") to be evaluated, writing "even" to the output.
If remainder & 1 evaluates as true (non-zero in this case) then the right operand for && is evaluated, displaying "odd". Assuming that this operation succeeds, the left operand for the || operation will be true, which causes it to short-circuit and not evaluate the right operand.
1 Experienced programmers are likely to know exactly what is going on here, but as you have found this technique is not the most readable. It's better (IMO) to be straightforward about the intent of code, so I would just use an if conditional -- or, at the very least, use the ternary operator: std::cout << (remainder & 1 ? "odd" : "even").
In other languages (JavaScript comes to mind) (ab)using the short-circuiting operators is a very common technique. I usually don't see them used this way in C++ and I would strongly discourage such use.
The line in question:
(remainder & 1 && std::cout<<"odd" ) || cout<<"even";
Is the same as the following when you take operator precedence and operator overloads into account:
((remainder & 1) && (operator<<(std::cout, "odd").operator bool())) || (operator<<(std::cout, "even").operator bool());
std::cout (more generically, std::basic_ostream) has operator<<() and operator bool() operators defined. The first operator returns a std::basic_ostream& reference, ie a reference to the stream itself (useful for chaining operations together). The second operator returns whether the stream is in a failure state or not.
See the following documentation for more details:
C++ operator precedence
operator overloading
std::basic_ostream::operator<<
std::basic_ios::operator bool