18
18
// You should have received a copy of the GNU General Public License
19
19
// along with this program. If not, write to the Free Software Foundation,
20
// Inc. ,59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20
// Inc, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22
// =============================================================================
23
24
#define _KVI_DEBUG_CHECK_RANGE_
25
#define _KVI_DEBUG_CLASS_NAME_ "KviExpression"
27
#include "kvi_command.h"
24
28
#include "kvi_debug.h"
27
#include "kvi_uparser.h"
28
#include "kvi_ircsocket.h"
29
#include "kvi_console.h"
30
#include "kvi_defines.h"
31
#include "kvi_frame.h"
32
#include "kvi_options.h"
33
29
#include "kvi_error.h"
30
#include "kvi_exprtree.h"
34
31
#include "kvi_locale.h"
35
#include "kvi_exprtree.h"
38
bool KviUserParser::evaluateExpr(KviCommand *c,long * result)
32
#include "kvi_userparser.h"
34
bool KviUserParser::evaluateExpr(KviCommand *cmd, long *result)
40
36
// This one evaluates an expression
41
KviExprTree * root = evaluateExpression(c);
42
if(!root)return false;
43
if(*(c->m_ptr) != ')'){
44
c->setError(KVI_ERROR_ParenthesisMismatch,_i18n_("EXPRESSION-END"),c->m_ptr);
37
KviExprTree *root = evaluateExpression(cmd);
38
if( !root ) return false;
40
if( *(cmd->m_ptr) != ')' ) {
41
cmd->setError(KVI_ERROR_ParenthesisMismatch, _i18n_("EXPRESSION-END"), cmd->m_ptr);
47
*result = root->calculate(c);
44
*result = root->calculate(cmd);
50
return (!c->hasError());
47
return (!cmd->hasError());
53
KviExprTree * KviUserParser::evaluateExpression(KviCommand *c)
50
KviExprTree *KviUserParser::evaluateExpression(KviCommand *cmd)
55
52
// This one evaluates the expression up to a (not matching) ')' or a \0
56
KviExprTree * op = evaluateOperand(c);
59
if((*(c->m_ptr) == ')')||(*(c->m_ptr) == '\0'))return op;//single operand
60
KviExprTree * curOper = evaluateOperator(c);
53
KviExprTree *op = evaluateOperand(cmd);
57
if( (*(cmd->m_ptr) == ')') || (*(cmd->m_ptr) == '\0') )
58
return op; // Single operand
59
KviExprTree *curOper = evaluateOperator(cmd);
65
64
curOper->setLeft(op);
66
return evaluateExpression_RightOperand(curOper,c);
65
return evaluateExpression_RightOperand(curOper, cmd);
69
KviExprTree * KviUserParser::evaluateOperand(KviCommand *c)
68
KviExprTree *KviUserParser::evaluateOperand(KviCommand *cmd)
71
// This one tries to extract a numeric operand from the data buffer
72
// Moves m_ptr to the character after the last char of the operand
73
// Returns a valid KviExprTreeNode of succesful
74
// otherwise returns 0 and sets c->m_err appropriately
70
// This one tries to extract a numeric operand from the data buffer.
71
// Moves m_ptr to the character after the last char of the operand.
72
// Returns a valid KviExprTreeNode of successful,
73
// otherwise returns 0 and sets cmd->m_err appropriately.
77
KviExprTree * pTop = 0;
78
KviExprTree * pCur = 0;
79
KviExprTree * pLast = 0;
76
KviExprTree *pTop = 0;
77
KviExprTree *pCur = 0;
78
KviExprTree *pLast = 0;
81
80
// Check for unary ops...
82
while(*(c->m_ptr) == '-' || *(c->m_ptr) == '~' || *(c->m_ptr) == '!'){
81
while( *(cmd->m_ptr) == '-' || *(cmd->m_ptr) == '~' || *(cmd->m_ptr) == '!' ) {
83
switch( *(cmd->m_ptr) ) {
86
pCur = new KviExprTree(KviExprTree::UnaryOperator,OP_NEGATE);
85
pCur = new KviExprTree(KviExprTree::UnaryOperator, OP_NEGATE);
89
pCur = new KviExprTree(KviExprTree::UnaryOperator,OP_BITNOT);
88
pCur = new KviExprTree(KviExprTree::UnaryOperator, OP_BITNOT);
92
pCur = new KviExprTree(KviExprTree::UnaryOperator,OP_NOT);
91
pCur = new KviExprTree(KviExprTree::UnaryOperator, OP_NOT);
95
94
// And we work with the child
96
if(pTop == 0)pTop = pCur;
97
else pLast->setLeft(pCur);
103
if(*(c->m_ptr) == '('){
106
pCur = evaluateExpression(c);
107
if(!pCur){ // failed somewhere in the call
104
if( *(cmd->m_ptr) == '(' ) {
107
pCur = evaluateExpression(cmd);
108
if( !pCur ) { // Failed somewhere in the call
111
if(*(c->m_ptr) != ')'){ // failed here
113
if( *(cmd->m_ptr) != ')' ) { // Failed here
114
c->setError(KVI_ERROR_ParenthesisMismatch,_i18n_("SUBEXPRESSION"));
117
cmd->setError(KVI_ERROR_ParenthesisMismatch, _i18n_("SUBEXPRESSION"));
119
// here *m_ptr may be something that is not a digit too!
120
pCur = evaluateSimpleOperand(c);
121
if(!pCur){ // failed somewere
122
// Here *m_ptr may be something that is not a digit too!
123
pCur = evaluateSimpleOperand(cmd);
124
if( !pCur ) { // Failed somewere
126
if(pTop)pLast->setLeft(pCur);
131
pLast->setLeft(pCur);
131
KviExprTree * KviUserParser::evaluateStringOperand(KviCommand *c)
137
KviExprTree *KviUserParser::evaluateStringOperand(KviCommand *cmd)
133
__range_valid(*(c->m_ptr) == '"');
134
KviExprTree * node = new KviExprTree(KviExprTree::StringOperand,0);
135
const char *aux_ptr = ++(c->m_ptr);
139
__range_valid(*(cmd->m_ptr) == '"');
140
KviExprTree *node = new KviExprTree(KviExprTree::StringOperand, 0);
141
const char *aux_ptr = ++(cmd->m_ptr);
138
// Now skip all the non interesting chars
139
while(*aux_ptr && (*aux_ptr != '\\') && (*aux_ptr != '\n') &&
140
(*aux_ptr != '"') && (*aux_ptr != '$') && (*aux_ptr != KVI_GLOBAL_VAR_CHAR))++aux_ptr;
144
// Now skip all the uninteresting chars
145
while( *aux_ptr && (*aux_ptr != '\\') &&
146
(*aux_ptr != '\n') && (*aux_ptr != '"') &&
147
(*aux_ptr != '$') && (*aux_ptr != KVI_GLOBAL_VAR_CHAR)
141
151
// Interesting char
144
case '\0': // end of command buffer...append the last block to the buffer and return
145
c->setError(KVI_ERROR_UnexpectedEndInString,_i18n_("EXPRESSION-STRING-OPERAND"));
154
case '\0': // End of command buffer... append the last block to the buffer and return
155
cmd->setError(KVI_ERROR_UnexpectedEndInString, _i18n_("EXPRESSION-STRING-OPERAND"));
149
case '"' : // append the last block to the buffer and return
150
node->m_string.append(c->m_ptr,aux_ptr - c->m_ptr);
151
c->m_ptr = ++aux_ptr; //don't forget to point to next char
159
case '"' : // Append the last block to the buffer and return
160
node->m_string.append(cmd->m_ptr, aux_ptr - cmd->m_ptr);
161
cmd->m_ptr = ++aux_ptr; // Do not forget to point to next char
154
case KVI_GLOBAL_VAR_CHAR: //variable: append the last block to the buffer and process the var
155
node->m_string.append(c->m_ptr,aux_ptr - c->m_ptr);
157
if(!processVariable(c,node->m_string)){
163
case '$': //system identifier: append the last block to the buffer and process the ident
164
node->m_string.append(c->m_ptr,aux_ptr - c->m_ptr);
166
if(!processIdentifier(c,node->m_string)){
172
case '\\': //escape character: append the last block to the processed buffer...
173
node->m_string.append(c->m_ptr,aux_ptr - c->m_ptr);
174
c->m_ptr = ++aux_ptr;
164
case KVI_GLOBAL_VAR_CHAR: // Variable: append the last block to the buffer and process the var
165
node->m_string.append(cmd->m_ptr, aux_ptr - cmd->m_ptr);
166
cmd->m_ptr = aux_ptr;
167
if( !processVariable(cmd, node->m_string) ) {
171
aux_ptr = cmd->m_ptr;
173
case '$': // System identifier: append the last block to the buffer and process the ident
174
node->m_string.append(cmd->m_ptr, aux_ptr - cmd->m_ptr);
175
cmd->m_ptr = aux_ptr;
176
if( !processIdentifier(cmd, node->m_string) ) {
180
aux_ptr = cmd->m_ptr;
182
case '\\': // Escape character: append the last block to the processed buffer...
183
node->m_string.append(cmd->m_ptr, aux_ptr - cmd->m_ptr);
184
cmd->m_ptr = ++aux_ptr;
177
c->setError(KVI_ERROR_UnexpectedEndInString,_i18n_("EXPRESSION-STRING-OPERAND"));
187
cmd->setError(KVI_ERROR_UnexpectedEndInString, _i18n_("EXPRESSION-STRING-OPERAND"));
181
case '\n': //escaped newline
182
c->m_ptr = ++aux_ptr; //skip it
183
c->skipSpace(); //skip leading spaces
184
aux_ptr = c->m_ptr; //continue
191
case '\n': // Escaped newline
192
cmd->m_ptr = ++aux_ptr; // Skip it
193
cmd->skipSpace(); // Skip leading spaces
194
aux_ptr = cmd->m_ptr; // Continue
186
196
default: // Must be copied to the buffer without modification
187
197
node->m_string.append(*aux_ptr);
188
c->m_ptr = ++aux_ptr;
198
cmd->m_ptr = ++aux_ptr;
194
return 0; //Newer here
197
KviExprTree * KviUserParser::evaluateSimpleOperand(KviCommand *c)
207
KviExprTree *KviUserParser::evaluateSimpleOperand(KviCommand *cmd)
199
209
// This one extracts a number from the data buffer
201
const char *aux = c->m_ptr;
203
case '%': if(!processVariable(c,tempNum))return 0; break;
204
case '$': if(!processIdentifier(c,tempNum))return 0; break;
205
case '"': return evaluateStringOperand(c); break;
211
const char *aux = cmd->m_ptr;
213
case '%': if( !processVariable(cmd, tempNum) ) return 0; break;
214
case '$': if( !processIdentifier(cmd, tempNum) ) return 0; break;
215
case '"': return evaluateStringOperand(cmd); break;
208
if(! ( isalpha(*(c->m_ptr)) || isxdigit(*(c->m_ptr)) ) )tempNum = "0";
218
if( !(isalpha(*(cmd->m_ptr)) || isxdigit(*(cmd->m_ptr))) )
211
if(isalpha(*(c->m_ptr))||isxdigit(*(c->m_ptr)))++(c->m_ptr);
212
while(isxdigit(*(c->m_ptr)))++(c->m_ptr);
213
tempNum.setStr(aux,(c->m_ptr) - aux);
222
if( isalpha(*(cmd->m_ptr)) || isxdigit(*(cmd->m_ptr)) )
224
while( isxdigit(*(cmd->m_ptr)) )
226
tempNum.setStr(aux, (cmd->m_ptr) - aux);
217
if(!isxdigit(*(c->m_ptr))){
218
c->setError(KVI_ERROR_UnexpectedCharacter,_i18n_("EXPRESSION-OPERAND"),c->m_ptr);
230
if( !isxdigit(*(cmd->m_ptr)) ) {
231
cmd->setError(KVI_ERROR_UnexpectedCharacter, _i18n_("EXPRESSION-OPERAND"), cmd->m_ptr);
221
while(isxdigit(*(c->m_ptr)))++(c->m_ptr);
222
tempNum.setStr(aux,(c->m_ptr) - aux);
234
while( isxdigit(*(cmd->m_ptr)) )
236
tempNum.setStr(aux, (cmd->m_ptr) - aux);
226
240
aux = tempNum.ptr();
230
switch(tolower(*aux)){
244
switch( tolower(*aux) ) {
231
245
case 'x': tempNum.cutLeft(2); base = 16; break;
232
246
case 'h': tempNum.cutLeft(2); base = 16; break;
234
case 'i': tempNum.cutLeft(2); base = 2; break; // can not use b because it is a hex digit
235
case 'j': tempNum.cutLeft(2); base = 3; break;
236
case 'k': tempNum.cutLeft(2); base = 4; break;
237
case 'l': tempNum.cutLeft(2); base = 5; break;
238
case 'm': tempNum.cutLeft(2); base = 6; break;
239
case 'n': tempNum.cutLeft(2); base = 7; break;
240
case 'o': tempNum.cutLeft(2); base = 8; break;
241
case 'p': tempNum.cutLeft(2); base = 9; break;
248
case 'i': tempNum.cutLeft(2); base = 2; break; // Cannot use b because it is a hex digit
249
case 'j': tempNum.cutLeft(2); base = 3; break;
250
case 'k': tempNum.cutLeft(2); base = 4; break;
251
case 'l': tempNum.cutLeft(2); base = 5; break;
252
case 'm': tempNum.cutLeft(2); base = 6; break;
253
case 'n': tempNum.cutLeft(2); base = 7; break;
254
case 'o': tempNum.cutLeft(2); base = 8; break;
255
case 'p': tempNum.cutLeft(2); base = 9; break;
242
256
case 'q': tempNum.cutLeft(2); base = 10; break;
243
257
case 'r': tempNum.cutLeft(2); base = 11; break;
244
258
case 's': tempNum.cutLeft(2); base = 12; break;
245
259
case 't': tempNum.cutLeft(2); base = 13; break;
246
260
case 'u': tempNum.cutLeft(2); base = 14; break;
247
261
case 'v': tempNum.cutLeft(2); base = 15; break;
248
default: break; // unknown ...maybe a single 0
262
default: break; // Unknown... maybe a single 0
252
long res = tempNum.toLongExt(&bOk,base);
254
c->setError(KVI_ERROR_UnexpectedCharacter,_i18n_("EXPRESSION-OPERAND"),tempNum.ptr());
266
long res = tempNum.toLongExt(&bOk, base);
268
cmd->setError(KVI_ERROR_UnexpectedCharacter, _i18n_("EXPRESSION-OPERAND"), tempNum.ptr());
257
return new KviExprTree(KviExprTree::NumericOperand,res);
271
return new KviExprTree(KviExprTree::NumericOperand, res);
260
KviExprTree * KviUserParser::evaluateExpression_RightOperand(KviExprTree * curTopOperator,KviCommand *c)
274
KviExprTree *KviUserParser::evaluateExpression_RightOperand(KviExprTree *curTopOperator, KviCommand *cmd)
262
276
__range_valid(curTopOperator);
263
277
// Now curTopOperator has the left subtree (one node) set
264
// and it points to the TOP (=ROOT) node
266
KviExprTree * operand;
267
KviExprTree * incompleteOperator = curTopOperator;
268
KviExprTree * auxOperator;
271
operand = evaluateOperand(c);
272
if(!operand){ delete curTopOperator; return 0; }
274
if(*(c->m_ptr) == ')' || *(c->m_ptr) == '\0'){ incompleteOperator->setRight(operand); return curTopOperator; }
276
auxOperator = evaluateOperator(c);
277
if(!auxOperator){ delete curTopOperator; delete operand; return 0; }
279
//now compare operators...
280
if(incompleteOperator->firstBinaryOperator() >= auxOperator->firstBinaryOperator()){
278
// and it points to the TOP (=ROOT) node.
279
// Evaluate the rest.
280
KviExprTree *operand;
281
KviExprTree *incompleteOperator = curTopOperator;
282
KviExprTree *auxOperator;
285
operand = evaluateOperand(cmd);
287
delete curTopOperator;
291
if( *(cmd->m_ptr) == ')' || *(cmd->m_ptr) == '\0' ) {
292
incompleteOperator->setRight(operand);
293
return curTopOperator;
296
auxOperator = evaluateOperator(cmd);
298
delete curTopOperator;
303
// Now compare operators...
304
if( incompleteOperator->firstBinaryOperator() >= auxOperator->firstBinaryOperator() ) {
281
305
incompleteOperator->setRight(auxOperator);
282
306
auxOperator->setLeft(operand);
284
// precedence of operators...
285
incompleteOperator->setRight(operand); //right tree complete
286
// go up until we find an operator with lower precedence than auxOperator (>=)
287
KviExprTree * tempOperator = incompleteOperator->parentWithPrecedenceLowerThan(auxOperator->m_value);
288
if(tempOperator == 0){ //reached the top
308
// Precedence of operators...
309
incompleteOperator->setRight(operand); // Right tree complete
310
// Go up until we find an operator with lower precedence than auxOperator (>=)
311
KviExprTree *tempOperator = incompleteOperator->parentWithPrecedenceLowerThan(auxOperator->m_value);
312
if( !tempOperator ) { // Reached the top
289
313
auxOperator->setLeft(curTopOperator);
290
314
curTopOperator = auxOperator;
297
321
incompleteOperator = auxOperator;
298
322
__range_valid(incompleteOperator->right() == 0);
300
return 0; //newer here
303
KviExprTree * KviUserParser::evaluateOperator(KviCommand *c)
327
KviExprTree *KviUserParser::evaluateOperator(KviCommand *cmd)
305
// This one extracts the first operator it finds
329
// This one extracts the first operator it finds
310
case '^': op = OP_POWER; ++(c->m_ptr); break;
311
case '*': op = OP_MUL; ++(c->m_ptr); break;
312
case '/': op = OP_DIV; ++(c->m_ptr); break;
313
case '%': op = OP_MOD; ++(c->m_ptr); break;
314
case '+': op = OP_ADD; ++(c->m_ptr); break;
315
case '-': op = OP_SUB; ++(c->m_ptr); break;
332
switch( *(cmd->m_ptr) ) {
334
case '^': op = OP_POWER; ++(cmd->m_ptr); break;
335
case '*': op = OP_MUL; ++(cmd->m_ptr); break;
336
case '/': op = OP_DIV; ++(cmd->m_ptr); break;
337
case '%': op = OP_MOD; ++(cmd->m_ptr); break;
338
case '+': op = OP_ADD; ++(cmd->m_ptr); break;
339
case '-': op = OP_SUB; ++(cmd->m_ptr); break;
318
if(*(c->m_ptr) == '=')op = OP_CSEQ , ++(c->m_ptr);
320
c->setError(KVI_ERROR_UnknownOperator,_i18n_("EXPRESSION-OPERATOR"),c->m_ptr);
342
if( *(cmd->m_ptr) == '=' ) {
346
cmd->setError(KVI_ERROR_UnknownOperator, _i18n_("EXPRESSION-OPERATOR"), cmd->m_ptr);
326
if(*(c->m_ptr) == '=')op = OP_EQ , ++(c->m_ptr);
328
c->setError(KVI_ERROR_UnknownOperator,_i18n_("EXPRESSION-OPERATOR"),c->m_ptr);
352
if( *(cmd->m_ptr) == '=' ) {
356
cmd->setError(KVI_ERROR_UnknownOperator, _i18n_("EXPRESSION-OPERATOR"), cmd->m_ptr);
334
if(*(c->m_ptr) == '=')op = OP_NE , ++(c->m_ptr);
336
c->setError(KVI_ERROR_UnknownOperator,_i18n_("EXPRESSION-OPERATOR"),c->m_ptr);
362
if( *(cmd->m_ptr) == '=' ) {
366
cmd->setError(KVI_ERROR_UnknownOperator, _i18n_("EXPRESSION-OPERATOR"), cmd->m_ptr);
342
if(*(c->m_ptr) == '=')op = OP_GE , ++(c->m_ptr);
343
else if(*(c->m_ptr) == '>')op = OP_SHR , ++(c->m_ptr);
372
if( *(cmd->m_ptr) == '=' ) {
375
} else if( *(cmd->m_ptr) == '>' ) {
348
if(*(c->m_ptr) == '=')op = OP_LE , ++(c->m_ptr);
349
else if(*(c->m_ptr) == '<')op = OP_SHL , ++(c->m_ptr);
382
if( *(cmd->m_ptr) == '=' ) {
385
} else if( *(cmd->m_ptr) == '<' ) {
354
if(*(c->m_ptr) == '&')op = OP_AND , ++(c->m_ptr);
392
if( *(cmd->m_ptr) == '&' ) {
395
} else op = OP_BITAND;
359
if(*(c->m_ptr) == '|')op = OP_OR , ++(c->m_ptr);
399
if( *(cmd->m_ptr) == '|' ) {
402
} else op = OP_BITOR;
363
c->setError(KVI_ERROR_UnknownOperator,_i18n_("EXPRESSION-OPERATOR"),c->m_ptr);
405
cmd->setError(KVI_ERROR_UnknownOperator, _i18n_("EXPRESSION-OPERATOR"), cmd->m_ptr);
368
return new KviExprTree(KviExprTree::BinaryOperator,op);
410
return new KviExprTree(KviExprTree::BinaryOperator, op);