1
//=============================================================================
3
// File : KviKvsParser_expression.cpp
4
// Creation date : Mon 6 Oct 2003 01.31 CEST by Szymon Stefanek
6
// This file is part of the KVIrc irc client distribution
7
// Copyright (C) 2003-2010 Szymon Stefanek (pragma at kvirc dot net)
9
// This program is FREE software. You can redistribute it and/or
10
// modify it under the terms of the GNU General Public License
11
// as published by the Free Software Foundation; either version 2
12
// of the License, or (at your opinion) any later version.
14
// This program is distributed in the HOPE that it will be USEFUL,
15
// but WITHOUT ANY WARRANTY; without even the implied warranty of
16
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17
// See the GNU General Public License for more details.
19
// You should have received a copy of the GNU General Public License
20
// along with this program. If not, write to the Free Software Foundation,
21
// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
23
//=============================================================================
25
#include "KviKvsParser.h"
26
#include "KviKvsTreeNode.h"
27
#include "KviKvsReport.h"
28
#include "KviKvsKernel.h"
29
#include "KviKvsParserMacros.h"
30
#include "KviLocale.h"
33
//#warning "FIXME: expression eval doc!"
40
Expression evaluation identifier
46
Expression evaluation identifier
48
Evaluates <expression> and returns its result.[br]
49
If <expression> is a single string, array or hash, it is returned unmodified.[br]
50
In any other case the expression evaluation returns a numeric value, either real or integer.[br]
51
The expressions are really close to the C ones and have some minor extensions.[br]
52
The supported operators are +,-,*,/,|,&,^,||,&&,^^,>>,<<,<,>,<=,>=,==,!= and <> (synonim for !=).[br]
53
The following table describes their meaning.[br]
55
[tr][td][b]Operator[/b][/td][td][b]Description[/b][/td][/tr]
56
[tr][td]a + b[/td][td]Arithmetic sum: valid only for numeric operands[/td][/tr]
57
[tr][td]a - b[/td][td]Arithmetic subtraction: valid only for numeric operands[/td][/tr]
58
[tr][td]a / b[/td][td]Arithmetic division: valid only for numeric operands[/td][/tr]
59
[tr][td]a * b[/td][td]Arithmetic multiplication: valid only for numeric operands[/td][/tr]
60
[tr][td]a % b[/td][td]Arithmetic modulus: valid only for numeric operands[/td][/tr]
61
[tr][td]a || b[/td][td]Logical or: valid only for boolean operands[/td][/tr]
62
[tr][td]a && b[/td][td]Logical and: valid only for boolean operands[/td][/tr]
63
[tr][td]a ^^ b[/td][td]Logical xor: valid only for boolean operands[/td][/tr]
64
[tr][td]a >> b[/td][td]Bitwise shift right: valid only for integer operands[/td][/tr]
65
[tr][td]a << b[/td][td]Bitwise shift left: valid only for integer operands[/td][/tr]
66
[tr][td]a | b[/td][td]Bitwise or: valid only for integer operands[/td][/tr]
67
[tr][td]a & b[/td][td]Bitwise and: valid only for integer operands[/td][/tr]
68
[tr][td]a ^ b[/td][td]Bitwise xor: valid only for integer operands[/td][/tr]
69
[tr][td]a > b[/td][td]Greater than: valid for numeric or string operands. Case sensitive[/td][/tr]
70
[tr][td]a < b[/td][td]Lower than: valid for numeric or string operands. Case sensitive[/td][/tr]
71
[tr][td]a >= b[/td][td]Greater or equal to: valid for numeric or string operands. Case sensitive[/td][/tr]
72
[tr][td]a <= b[/td][td]Lower or equal to: valid for numeric or string operands. Case sensitive[/td][/tr]
73
[tr][td]a != b[/td][td]Not equal to: valid for numeric or string operands. Case sensitive[/td][/tr]
74
[tr][td]a == b[/td][td]Equal to: valid for numeric or string operands. Case sensitive[/td][/tr]
76
The expressions can contain integer, real or string constants and variable operands.[br]
77
The integer constants can be also specified as hexadecimal numbers by prefixing them by '0x'.[br]
78
The string constants should be enclosed in quotes.[br]
84
echo $(10.0 + 5 * 100)
86
echo $("hello" > "ciao")
94
echo $(-(10 + 20) * 3)
97
echo $(0xffff == 65535)
105
KviKvsTreeNodeExpressionBinaryOperator * KviKvsParser::parseExpressionBinaryOperator()
107
switch(KVSP_curCharUnicode)
111
if(KVSP_curCharUnicode == '=')
114
return new KviKvsTreeNodeExpressionBinaryOperatorEqualTo(KVSP_curCharPointer);
116
error(KVSP_curCharPointer,__tr2qs_ctx("Unknown binary operator '=%q': did you mean '==' ?","kvs"),KVSP_curCharPointer);
121
if(KVSP_curCharUnicode == '=')
124
return new KviKvsTreeNodeExpressionBinaryOperatorNotEqualTo(KVSP_curCharPointer);
129
return new KviKvsTreeNodeExpressionBinaryOperatorSum(KVSP_curCharPointer);
133
return new KviKvsTreeNodeExpressionBinaryOperatorSubtraction(KVSP_curCharPointer);
137
return new KviKvsTreeNodeExpressionBinaryOperatorDivision(KVSP_curCharPointer);
141
return new KviKvsTreeNodeExpressionBinaryOperatorModulus(KVSP_curCharPointer);
145
return new KviKvsTreeNodeExpressionBinaryOperatorMultiplication(KVSP_curCharPointer);
149
if(KVSP_curCharUnicode == '&')
152
return new KviKvsTreeNodeExpressionBinaryOperatorAnd(KVSP_curCharPointer);
154
return new KviKvsTreeNodeExpressionBinaryOperatorBitwiseAnd(KVSP_curCharPointer);
158
if(KVSP_curCharUnicode == '|')
161
return new KviKvsTreeNodeExpressionBinaryOperatorOr(KVSP_curCharPointer);
163
return new KviKvsTreeNodeExpressionBinaryOperatorBitwiseOr(KVSP_curCharPointer);
167
if(KVSP_curCharUnicode == '^')
170
return new KviKvsTreeNodeExpressionBinaryOperatorXor(KVSP_curCharPointer);
172
return new KviKvsTreeNodeExpressionBinaryOperatorBitwiseXor(KVSP_curCharPointer);
176
switch(KVSP_curCharUnicode)
180
return new KviKvsTreeNodeExpressionBinaryOperatorShiftRight(KVSP_curCharPointer);
184
return new KviKvsTreeNodeExpressionBinaryOperatorGreaterOrEqualTo(KVSP_curCharPointer);
187
return new KviKvsTreeNodeExpressionBinaryOperatorGreaterThan(KVSP_curCharPointer);
193
switch(KVSP_curCharUnicode)
197
return new KviKvsTreeNodeExpressionBinaryOperatorNotEqualTo(KVSP_curCharPointer);
201
return new KviKvsTreeNodeExpressionBinaryOperatorShiftLeft(KVSP_curCharPointer);
205
return new KviKvsTreeNodeExpressionBinaryOperatorLowerOrEqualTo(KVSP_curCharPointer);
208
return new KviKvsTreeNodeExpressionBinaryOperatorLowerThan(KVSP_curCharPointer);
214
error(KVSP_curCharPointer,__tr2qs_ctx("Unknown binary operator '%q'","kvs"),KVSP_curCharPointer);
219
static unsigned char binary_operator_initial_char[256]=
221
// 000 001 002 003 004 005 006 007 008 009 010 011 012 013 014 015
222
// NUL SOH STX ETX EOT ENQ ACK BEL BS HT LF VT FF CR SO SI
223
0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,
224
// 016 017 018 019 020 021 022 023 024 025 026 027 028 029 030 031
225
// DLE DC1 DC2 DC3 DC4 NAK SYN ETB CAN EM SUB ESC FS GS RS US
226
0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,
227
// 032 033 034 035 036 037 038 039 040 041 042 043 044 045 046 047
228
// ! " # $ % & ' ( ) * + , - . /
229
0 ,1 ,0 ,0 ,0 ,1 ,1 ,0 ,0 ,0 ,1 ,1 ,0 ,1 ,0 ,1 ,
230
// 048 049 050 051 052 053 054 055 056 057 058 059 060 061 062 063
231
// 0 1 2 3 4 5 6 7 8 9 : ; < = > ?
232
0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,1 ,1 ,1 ,0 ,
233
// 064 065 066 067 068 069 070 071 072 073 074 075 076 077 078 079
234
// @ A B C D E F G H I J K L M N O
235
0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,
236
// 080 081 082 083 084 085 086 087 088 089 090 091 092 093 094 095
237
// P Q R S T U V W X Y Z [ \ ] ^ _
238
0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,1 ,0 ,
239
// 096 097 098 099 100 101 102 103 104 105 106 107 108 109 110 111
240
// ` a b c d e f g h i j k l m n o
241
0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,
242
// 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
243
// p q r s t u v w x y z { | } ~
244
0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,1 ,0 ,0 ,0 ,
245
// 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
247
0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,
248
// 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
250
0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,
251
// 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
253
0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,
254
// 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191
256
0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,
257
// 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207
258
// � � � � � � � � � � � � � � � �
259
0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,
260
// 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223
261
// � � � � � � � � � � � � � � � �
262
0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,
263
// 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239
264
// � � � � � � � � � � � � � � � �
265
0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,
266
// 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255
268
0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0
272
bool KviKvsParser::parseExpressionMightPointToOperator()
274
if(KVSP_curCharUnicode == '%')
277
if(KVSP_curCharIsLetter || (KVSP_curCharUnicode == '_'))
279
// a variable, probably
286
if(KVSP_curCharUnicode > 255)return false;
287
return binary_operator_initial_char[KVSP_curCharUnicode] != 0;
291
KviKvsTreeNodeExpression * KviKvsParser::parseExpressionOperand(char terminator)
293
switch(KVSP_curCharUnicode)
298
error(KVSP_curCharPointer,__tr2qs_ctx("Unexpected end of script in expression","kvs"));
304
return parseExpression(')'); // sub expression
310
KviKvsTreeNodeExpression * d = parseExpressionOperand(terminator);
312
return new KviKvsTreeNodeExpressionUnaryOperatorNegate(d->location(),d);
319
KviKvsTreeNodeExpression * d = parseExpressionOperand(terminator);
321
return new KviKvsTreeNodeExpressionUnaryOperatorLogicalNot(d->location(),d);
328
KviKvsTreeNodeExpression * d = parseExpressionOperand(terminator);
330
return new KviKvsTreeNodeExpressionUnaryOperatorBitwiseNot(d->location(),d);
334
// anything else at this point is an operand core
335
return parseExpressionOperandCore(terminator);
346
KviKvsTreeNodeExpression * KviKvsParser::parseExpressionOperandCore(char terminator)
348
KviPointerList<KviKvsTreeNodeData> * pDataList = new KviPointerList<KviKvsTreeNodeData>;
349
pDataList->setAutoDelete(true);
351
static QString szStaticSingleSpace(" ");
353
const QChar * pOperandBegin = KVSP_curCharPointer;
355
bool bHaveVariable = false;
359
switch(KVSP_curCharUnicode)
364
error(KVSP_curCharPointer,__tr2qs_ctx("Unexpected end of script in expression","kvs"));
371
if((KVSP_curCharUnicode == terminator) || parseExpressionMightPointToOperator())goto postprocess_operand;
372
// separate by single spaces
373
pDataList->append(new KviKvsTreeNodeConstantData(KVSP_curCharPointer,new KviKvsVariant(szStaticSingleSpace)));
378
bHaveVariable = true;
379
KviKvsTreeNodeData * d = parseStringParameter();
385
pDataList->append(d);
392
bHaveVariable = true;
393
KviKvsTreeNodeData * d = parseParameterPercentOrDollar();
399
pDataList->append(d);
404
if(KVSP_curCharIsLetterOrNumber || (KVSP_curCharUnicode == '.') || (KVSP_curCharUnicode == '_'))
406
const QChar * pBegin = KVSP_curCharPointer;
407
while(KVSP_curCharIsLetterOrNumber || (KVSP_curCharUnicode == '.') || (KVSP_curCharUnicode == '_'))KVSP_skipChar;
408
QString tmp(pBegin,KVSP_curCharPointer - pBegin);
410
kvs_int_t iVal = tmp.toLong(&bOk);
413
pDataList->append(new KviKvsTreeNodeConstantData(pBegin,new KviKvsVariant(iVal)));
416
if(pBegin->unicode() == '0')
420
if((tmp[1] == 'x') || (tmp[1] == 'X'))
422
// hexadecimal constant ?
423
QString hex = tmp.right(tmp.length() - 2);
424
iVal = hex.toLong(&bOk,16);
427
pDataList->append(new KviKvsTreeNodeConstantData(pBegin,new KviKvsVariant(iVal)));
434
kvs_real_t dVal = tmp.toDouble(&bOk);
437
pDataList->append(new KviKvsTreeNodeConstantData(pBegin,new KviKvsVariant(dVal)));
439
pDataList->append(new KviKvsTreeNodeConstantData(pBegin,new KviKvsVariant(tmp)));
444
error(KVSP_curCharPointer,__tr2qs_ctx("Unexpected character %q (unicode %h) in expression. If it meant to be a string use the quotes.","kvs"),KVSP_curCharPointer,KVSP_curCharUnicode);
451
if((KVSP_curCharUnicode == terminator) || parseExpressionMightPointToOperator())break;
456
if(pDataList->count() == 0)
459
error(KVSP_curCharPointer,__tr2qs_ctx("Unexpected empty expression operand","kvs"));
463
if(pDataList->count() > 1)
464
return new KviKvsTreeNodeExpressionVariableOperand(pOperandBegin,new KviKvsTreeNodeCompositeData(pOperandBegin,pDataList));
466
KviKvsTreeNodeData * pUniqueData = pDataList->first();
470
pDataList->setAutoDelete(false);
472
return new KviKvsTreeNodeExpressionVariableOperand(pOperandBegin,pUniqueData);
475
// a single constant data element
476
KviKvsTreeNodeExpressionConstantOperand * op = new KviKvsTreeNodeExpressionConstantOperand(pOperandBegin,new KviKvsVariant(*(((KviKvsTreeNodeConstantData *)pUniqueData)->value())));
477
delete pDataList; // auto delete is true
482
KviKvsTreeNodeExpression * KviKvsParser::parseExpression(char terminator)
484
// we're inside the expression now
487
if(KVSP_curCharUnicode == terminator)
492
return new KviKvsTreeNodeExpressionConstantOperand(KVSP_curCharPointer,new KviKvsVariant((kvs_int_t)0));
495
KviKvsTreeNodeExpression * left = parseExpressionOperand(terminator);
498
left->contextDescription(sz);
502
if(KVSP_curCharUnicode == terminator)
508
// not a terminator... must be an operator (or an error, eventually)
510
KviKvsTreeNodeExpression * curTopOperator = parseExpressionBinaryOperator();
516
curTopOperator->contextDescription(sz);
518
curTopOperator->setLeft(left);
520
// ok.. parse the right side
522
// Now curTopOperator has the left subtree (one node) set
523
// and it points to the TOP (=ROOT) node
526
KviKvsTreeNodeExpression * operand;
527
KviKvsTreeNodeExpression * incompleteOperator = curTopOperator;
528
KviKvsTreeNodeExpression * auxOperator;
534
operand = parseExpressionOperand(terminator);
537
delete curTopOperator;
540
operand->contextDescription(sz);
544
if(KVSP_curCharUnicode == terminator)
547
incompleteOperator->setRight(operand);
548
return curTopOperator;
551
auxOperator = parseExpressionBinaryOperator();
554
delete curTopOperator;
559
auxOperator->contextDescription(sz);
562
//now compare operators...
563
if(incompleteOperator->precedence() > auxOperator->precedence())
565
// This in fact means that incomplete has LOWER precedence than
566
// aux and thus aux should be done first.
567
incompleteOperator->setRight(auxOperator);
568
auxOperator->setLeft(operand);
570
// incomplete has GREATER precedence than aux and thus aux should be done first
571
incompleteOperator->setRight(operand); //right tree complete
572
// go up until we find an operator with lower precedence than auxOperator (>=)
573
KviKvsTreeNodeExpression * tempOperator = incompleteOperator->parentWithPrecedenceLowerThan(auxOperator->precedence());
574
if(tempOperator == 0)
576
auxOperator->setLeft(curTopOperator);
577
curTopOperator = auxOperator;
579
KVSP_ASSERT(tempOperator->right());
580
auxOperator->setLeft(tempOperator->right());
581
tempOperator->setRight(auxOperator);
584
incompleteOperator = auxOperator;
585
KVSP_ASSERT(incompleteOperator->right() == 0);
590
return 0; //newer here
595
KviKvsTreeNodeExpression * right = parseExpression(terminator);
610
// now.. the left side is a single operand for sure
611
// the right side might be a single operand or a sequence of operations
612
if(right->isOperator())
614
// if the operator has lower precedence than op then
615
if(right->precedence() < op->precedence())
617
right->attachHighPrecedenceOperator(op);
623
// a single operand or a greater precedence operator