license changed to LGPL for libnxcl, libnxsnmp, libnxlp, libnxsl, and libnxmap
[public/netxms.git] / src / libnxsl / program.cpp
CommitLineData
5039dede
AK
1/*
2** NetXMS - Network Management System
3** NetXMS Scripting Language Interpreter
65d2c384 4** Copyright (C) 2003-2010 Victor Kirhenshtein
5039dede
AK
5**
6** This program is free software; you can redistribute it and/or modify
65d2c384
VK
7** it under the terms of the GNU Lesser General Public License as published by
8** the Free Software Foundation; either version 3 of the License, or
5039dede
AK
9** (at your option) any later version.
10**
11** This program is distributed in the hope that it will be useful,
12** but WITHOUT ANY WARRANTY; without even the implied warranty of
13** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14** GNU General Public License for more details.
15**
65d2c384 16** You should have received a copy of the GNU Lesser General Public License
5039dede
AK
17** along with this program; if not, write to the Free Software
18** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19**
20** File: program.cpp
21**
22**/
23
24#include "libnxsl.h"
25#ifdef _WIN32
26#include <netxms-regex.h>
27#else
28#include <regex.h>
29#endif
30
31
32//
33// Constants
34//
35
c742e8c8 36#define MAX_ERROR_NUMBER 25
5039dede
AK
37#define CONTROL_STACK_LIMIT 32768
38
39
40//
41// Command mnemonics
42//
43
44static const char *m_szCommandMnemonic[] =
45{
46 "NOP", "RET", "JMP", "CALL", "CALL",
47 "PUSH", "PUSH", "EXIT", "POP", "SET",
48 "ADD", "SUB", "MUL", "DIV", "REM",
49 "EQ", "NE", "LT", "LE", "GT", "GE",
50 "BITAND", "BITOR", "BITXOR",
51 "AND", "OR", "LSHIFT", "RSHIFT",
52 "NRET", "JZ", "PRINT", "CONCAT",
53 "BIND", "INC", "DEC", "NEG", "NOT",
3a6047a2 54 "BITNOT", "CAST", "AGET", "INCP", "DECP",
5039dede 55 "JNZ", "LIKE", "ILIKE", "MATCH",
3a6047a2
VK
56 "IMATCH", "CASE", "ARRAY", "EGET",
57 "ESET", "ASET"
5039dede
AK
58};
59
60
61//
62// Error texts
63//
64
65static const TCHAR *m_szErrorMessage[MAX_ERROR_NUMBER] =
66{
67 _T("Data stack underflow"),
68 _T("Control stack underflow"),
69 _T("Condition value is not a number"),
70 _T("Bad arithmetic conversion"),
71 _T("Invalid operation with NULL value"),
72 _T("Internal error"),
73 _T("main() function not presented"),
74 _T("Control stack overflow"),
75 _T("Divide by zero"),
76 _T("Invalid operation with real numbers"),
77 _T("Function not found"),
78 _T("Invalid number of function's arguments"),
79 _T("Cannot do automatic type cast"),
80 _T("Left argument of -> must be a reference to object"),
81 _T("Unknown object's attribute"),
82 _T("Requested module not found or cannot be loaded"),
83 _T("Argument is not of string type and cannot be converted to string"),
84 _T("Invalid regular expression"),
85 _T("Function or operation argument is not a whole number"),
86 _T("Invalid operation on object"),
87 _T("Bad (or incompatible) object class"),
88 _T("Variable already exist"),
89 _T("Array index is not an integer"),
c742e8c8
VK
90 _T("Attempt to use array element access operation on non-array"),
91 _T("Cannot assign to a variable that is constant")
5039dede
AK
92};
93
94
95//
96// Determine operation data type
97//
98
99static int SelectResultType(int nType1, int nType2, int nOp)
100{
101 int nType;
102
103 if (nOp == OPCODE_DIV)
104 {
105 nType = NXSL_DT_REAL;
106 }
107 else
108 {
109 if ((nType1 == NXSL_DT_REAL) || (nType2 == NXSL_DT_REAL))
110 {
111 if ((nOp == OPCODE_REM) || (nOp == OPCODE_LSHIFT) ||
112 (nOp == OPCODE_RSHIFT) || (nOp == OPCODE_BIT_AND) ||
113 (nOp == OPCODE_BIT_OR) || (nOp == OPCODE_BIT_XOR))
114 {
115 nType = NXSL_DT_NULL; // Error
116 }
117 else
118 {
119 nType = NXSL_DT_REAL;
120 }
121 }
122 else
123 {
124 if (((nType1 >= NXSL_DT_UINT32) && (nType2 < NXSL_DT_UINT32)) ||
125 ((nType1 < NXSL_DT_UINT32) && (nType2 >= NXSL_DT_UINT32)))
126 {
127 // One operand signed, other unsigned, convert both to signed
128 if (nType1 >= NXSL_DT_UINT32)
129 nType1 -= 2;
130 else if (nType2 >= NXSL_DT_UINT32)
131 nType2 -= 2;
132 }
133 nType = max(nType1, nType2);
134 }
135 }
136 return nType;
137}
138
139
140//
141// Constructor
142//
143
bb5365ed 144NXSL_Program::NXSL_Program()
5039dede
AK
145{
146 m_ppInstructionSet = NULL;
147 m_dwCodeSize = 0;
148 m_dwCurrPos = INVALID_ADDRESS;
149 m_pDataStack = NULL;
150 m_pCodeStack = NULL;
151 m_nErrorCode = 0;
152 m_pszErrorText = NULL;
c742e8c8
VK
153 m_pConstants = new NXSL_VariableSystem(true);
154 m_pGlobals = new NXSL_VariableSystem(false);
5039dede
AK
155 m_pLocals = NULL;
156 m_dwNumFunctions = 0;
157 m_pFunctionList = NULL;
158 m_dwSubLevel = 0; // Level of current subroutine
159 m_pEnv = NULL;
160 m_pRetValue = NULL;
161 m_dwNumModules = 0;
162 m_pModuleList = NULL;
163 m_dwNumPreloads = 0;
164 m_ppszPreloadList = NULL;
165}
166
167
168//
169// Destructor
170//
171
bb5365ed 172NXSL_Program::~NXSL_Program()
5039dede
AK
173{
174 DWORD i;
175
176 for(i = 0; i < m_dwCodeSize; i++)
177 delete m_ppInstructionSet[i];
178 safe_free(m_ppInstructionSet);
179
180 delete m_pDataStack;
181 delete m_pCodeStack;
182
183 delete m_pConstants;
184 delete m_pGlobals;
185 delete m_pLocals;
186
187 delete m_pEnv;
188 delete m_pRetValue;
189
190 safe_free(m_pFunctionList);
191 safe_free(m_pModuleList);
192
193 for(i = 0; i < m_dwNumPreloads; i++)
194 safe_free(m_ppszPreloadList[i]);
195 safe_free(m_ppszPreloadList);
196
197 safe_free(m_pszErrorText);
198}
199
200
201//
202// Add new instruction to set
203//
204
bb5365ed 205void NXSL_Program::addInstruction(NXSL_Instruction *pInstruction)
5039dede
AK
206{
207 m_ppInstructionSet = (NXSL_Instruction **)realloc(m_ppInstructionSet,
208 sizeof(NXSL_Instruction *) * (m_dwCodeSize + 1));
209 m_ppInstructionSet[m_dwCodeSize++] = pInstruction;
210}
211
212
213//
214// Resolve last jump with INVALID_ADDRESS to current address
215//
216
bb5365ed 217void NXSL_Program::resolveLastJump(int nOpCode)
5039dede
AK
218{
219 DWORD i;
220
221 for(i = m_dwCodeSize; i > 0;)
222 {
223 i--;
224 if ((m_ppInstructionSet[i]->m_nOpCode == nOpCode) &&
225 (m_ppInstructionSet[i]->m_operand.m_dwAddr == INVALID_ADDRESS))
226 {
227 m_ppInstructionSet[i]->m_operand.m_dwAddr = m_dwCodeSize;
228 break;
229 }
230 }
231}
232
233
234//
235// Create jump at given address replacing another instruction (usually NOP)
236//
237
bb5365ed 238void NXSL_Program::createJumpAt(DWORD dwOpAddr, DWORD dwJumpAddr)
5039dede
AK
239{
240 int nLine;
241
242 if (dwOpAddr >= m_dwCodeSize)
243 return;
244
245 nLine = m_ppInstructionSet[dwOpAddr]->m_nSourceLine;
246 delete m_ppInstructionSet[dwOpAddr];
247 m_ppInstructionSet[dwOpAddr] = new NXSL_Instruction(nLine, OPCODE_JMP, dwJumpAddr);
248}
249
250
251//
252// Add new function to defined functions list
253// Will use first free address if dwAddr == INVALID_ADDRESS
254//
255
bb5365ed 256BOOL NXSL_Program::addFunction(const char *pszName, DWORD dwAddr, char *pszError)
5039dede
AK
257{
258 DWORD i;
259
260 // Check for duplicate function names
261 for(i = 0; i < m_dwNumFunctions; i++)
262 if (!strcmp(m_pFunctionList[i].m_szName, pszName))
263 {
264 sprintf(pszError, "Duplicate function name: \"%s\"", pszName);
265 return FALSE;
266 }
267 m_dwNumFunctions++;
268 m_pFunctionList = (NXSL_Function *)realloc(m_pFunctionList, sizeof(NXSL_Function) * m_dwNumFunctions);
269 nx_strncpy(m_pFunctionList[i].m_szName, pszName, MAX_FUNCTION_NAME);
270 m_pFunctionList[i].m_dwAddr = (dwAddr == INVALID_ADDRESS) ? m_dwCodeSize : dwAddr;
271 return TRUE;
272}
273
274
275//
276// Add preload information
277//
278
bb5365ed 279void NXSL_Program::addPreload(char *pszName)
5039dede
AK
280{
281 m_ppszPreloadList = (char **)realloc(m_ppszPreloadList, sizeof(char *) * (m_dwNumPreloads + 1));
282 m_ppszPreloadList[m_dwNumPreloads] = pszName;
283 m_dwNumPreloads++;
284}
285
286
287//
288// resolve local functions
289//
290
bb5365ed 291void NXSL_Program::resolveFunctions(void)
5039dede
AK
292{
293 DWORD i, j;
294
295 for(i = 0; i < m_dwCodeSize; i++)
296 {
297 if (m_ppInstructionSet[i]->m_nOpCode == OPCODE_CALL_EXTERNAL)
298 {
299 for(j = 0; j < m_dwNumFunctions; j++)
300 {
301 if (!strcmp(m_pFunctionList[j].m_szName,
302 m_ppInstructionSet[i]->m_operand.m_pszString))
303 {
304 free(m_ppInstructionSet[i]->m_operand.m_pszString);
305 m_ppInstructionSet[i]->m_operand.m_dwAddr = m_pFunctionList[j].m_dwAddr;
306 m_ppInstructionSet[i]->m_nOpCode = OPCODE_CALL;
307 break;
308 }
309 }
310 }
311 }
312}
313
314
315//
316// Dump program to file (as text)
317//
318
bb5365ed 319void NXSL_Program::dump(FILE *pFile)
5039dede
AK
320{
321 DWORD i;
322
323 for(i = 0; i < m_dwCodeSize; i++)
324 {
325 fprintf(pFile, "%04X %-6s ", i,
326 m_szCommandMnemonic[m_ppInstructionSet[i]->m_nOpCode]);
327 switch(m_ppInstructionSet[i]->m_nOpCode)
328 {
329 case OPCODE_CALL_EXTERNAL:
330 fprintf(pFile, "%s, %d\n", m_ppInstructionSet[i]->m_operand.m_pszString,
331 m_ppInstructionSet[i]->m_nStackItems);
332 break;
333 case OPCODE_CALL:
334 fprintf(pFile, "%04X, %d\n", m_ppInstructionSet[i]->m_operand.m_dwAddr,
335 m_ppInstructionSet[i]->m_nStackItems);
336 break;
337 case OPCODE_JMP:
338 case OPCODE_JZ:
339 case OPCODE_JNZ:
340 fprintf(pFile, "%04X\n", m_ppInstructionSet[i]->m_operand.m_dwAddr);
341 break;
342 case OPCODE_PUSH_VARIABLE:
343 case OPCODE_SET:
344 case OPCODE_BIND:
345 case OPCODE_ARRAY:
346 case OPCODE_INC:
347 case OPCODE_DEC:
348 case OPCODE_INCP:
349 case OPCODE_DECP:
3a6047a2
VK
350 case OPCODE_GET_ATTRIBUTE:
351 case OPCODE_SET_ATTRIBUTE:
5039dede
AK
352 fprintf(pFile, "%s\n", m_ppInstructionSet[i]->m_operand.m_pszString);
353 break;
354 case OPCODE_PUSH_CONSTANT:
355 case OPCODE_CASE:
bb5365ed 356 if (m_ppInstructionSet[i]->m_operand.m_pConstant->isNull())
5039dede
AK
357 fprintf(pFile, "<null>\n");
358 else
359 fprintf(pFile, "\"%s\"\n",
bb5365ed 360 m_ppInstructionSet[i]->m_operand.m_pConstant->getValueAsCString());
5039dede
AK
361 break;
362 case OPCODE_POP:
363 fprintf(pFile, "%d\n", m_ppInstructionSet[i]->m_nStackItems);
364 break;
365 case OPCODE_CAST:
366 fprintf(pFile, "[%s]\n", g_szTypeNames[m_ppInstructionSet[i]->m_nStackItems]);
367 break;
368 default:
369 fprintf(pFile, "\n");
370 break;
371 }
372 }
373}
374
375
376//
377// Report error
378//
379
bb5365ed 380void NXSL_Program::error(int nError)
5039dede
AK
381{
382 TCHAR szBuffer[1024];
383
384 safe_free(m_pszErrorText);
385 _sntprintf(szBuffer, 1024, _T("Error %d in line %d: %s"), nError,
386 (m_dwCurrPos == INVALID_ADDRESS) ? 0 : m_ppInstructionSet[m_dwCurrPos]->m_nSourceLine,
387 ((nError > 0) && (nError <= MAX_ERROR_NUMBER)) ? m_szErrorMessage[nError - 1] : _T("Unknown error code"));
388 m_pszErrorText = _tcsdup(szBuffer);
389 m_dwCurrPos = INVALID_ADDRESS;
390}
391
392
393//
394// Run program
395// Returns 0 on success and -1 on error
396//
397
bb5365ed 398int NXSL_Program::run(NXSL_Environment *pEnv, DWORD argc, NXSL_Value **argv,
c742e8c8
VK
399 NXSL_VariableSystem *pUserLocals, NXSL_VariableSystem **ppGlobals,
400 NXSL_VariableSystem *pConstants)
5039dede
AK
401{
402 DWORD i, dwOrigCodeSize, dwOrigNumFn;
c742e8c8 403 NXSL_VariableSystem *pSavedGlobals, *pSavedConstants = NULL;
5039dede
AK
404 NXSL_Value *pValue;
405 char szBuffer[32];
406
407 // Save original code size and number of functions
408 dwOrigCodeSize = m_dwCodeSize;
409 dwOrigNumFn = m_dwNumFunctions;
410
411 // Delete previous return value
ea84fc85 412 delete_and_null(m_pRetValue);
5039dede
AK
413
414 // Use provided environment or create default
415 if (pEnv != NULL)
416 m_pEnv = pEnv;
417 else
418 m_pEnv = new NXSL_Environment;
419
420 // Create stacks
421 m_pDataStack = new NXSL_Stack;
422 m_pCodeStack = new NXSL_Stack;
423
424 // Create local variable system for main() and bind arguments
425 m_pLocals = (pUserLocals == NULL) ? new NXSL_VariableSystem : pUserLocals;
426 for(i = 0; i < argc; i++)
427 {
428 sprintf(szBuffer, "$%d", i + 1);
bb5365ed 429 m_pLocals->create(szBuffer, argv[i]);
5039dede
AK
430 }
431
c742e8c8 432 // Preserve original global variables and constants
5039dede 433 pSavedGlobals = new NXSL_VariableSystem(m_pGlobals);
c742e8c8
VK
434 if (pConstants != NULL)
435 {
436 pSavedConstants = new NXSL_VariableSystem(m_pConstants);
437 m_pConstants->merge(pConstants);
438 }
5039dede
AK
439
440 // Preload modules
441 for(i = 0; i < m_dwNumPreloads; i++)
442 {
13ceb0fb 443 if (!m_pEnv->useModule(this, m_ppszPreloadList[i]))
5039dede 444 {
bb5365ed 445 error(NXSL_ERR_MODULE_NOT_FOUND);
5039dede
AK
446 break;
447 }
448 }
449
450 // Locate main() and run
451 if (i == m_dwNumPreloads)
452 {
453 for(i = 0; i < m_dwNumFunctions; i++)
454 if (!strcmp(m_pFunctionList[i].m_szName, "main"))
455 break;
456 if (i < m_dwNumFunctions)
457 {
458 m_dwCurrPos = m_pFunctionList[i].m_dwAddr;
459 while(m_dwCurrPos < m_dwCodeSize)
bb5365ed 460 execute();
5039dede 461 if (m_dwCurrPos != INVALID_ADDRESS)
bb5365ed 462 m_pRetValue = (NXSL_Value *)m_pDataStack->pop();
5039dede
AK
463 }
464 else
465 {
bb5365ed 466 error(NXSL_ERR_NO_MAIN);
5039dede
AK
467 }
468 }
469
470 // Restore global variables
471 if (ppGlobals == NULL)
472 delete m_pGlobals;
473 else
474 *ppGlobals = m_pGlobals;
475 m_pGlobals = pSavedGlobals;
476
c742e8c8
VK
477 // Restore constants
478 if (pSavedConstants != NULL)
479 {
480 delete m_pConstants;
481 m_pConstants = pSavedConstants;
482 }
483
5039dede 484 // Cleanup
bb5365ed 485 while((pValue = (NXSL_Value *)m_pDataStack->pop()) != NULL)
5039dede
AK
486 delete pValue;
487 while(m_dwSubLevel > 0)
488 {
489 m_dwSubLevel--;
bb5365ed
VK
490 delete (NXSL_VariableSystem *)m_pCodeStack->pop();
491 m_pCodeStack->pop();
5039dede
AK
492 }
493 delete_and_null(m_pEnv);
494 delete_and_null(m_pLocals);
495 delete_and_null(m_pDataStack);
496 delete_and_null(m_pCodeStack);
497 safe_free(m_pModuleList);
498 m_pModuleList = NULL;
499 m_dwNumModules = 0;
500
501 // Restore original code size and number of functions
502 for(i = dwOrigCodeSize; i < m_dwCodeSize; i++)
503 delete m_ppInstructionSet[i];
504 m_dwCodeSize = dwOrigCodeSize;
505 m_dwNumFunctions = dwOrigNumFn;
506
507 return (m_dwCurrPos == INVALID_ADDRESS) ? -1 : 0;
508}
509
510
511//
512// Set global variale
513//
514
bb5365ed 515void NXSL_Program::setGlobalVariable(const TCHAR *pszName, NXSL_Value *pValue)
5039dede
AK
516{
517 NXSL_Variable *pVar;
518
bb5365ed 519 pVar = m_pGlobals->find(pszName);
5039dede 520 if (pVar == NULL)
bb5365ed 521 pVar = m_pGlobals->create(pszName, pValue);
5039dede 522 else
bb5365ed 523 pVar->setValue(pValue);
5039dede
AK
524}
525
526
527//
528// Find variable or create if does not exist
529//
530
bb5365ed 531NXSL_Variable *NXSL_Program::findOrCreateVariable(TCHAR *pszName)
5039dede
AK
532{
533 NXSL_Variable *pVar;
534
bb5365ed 535 pVar = m_pConstants->find(pszName);
5039dede
AK
536 if (pVar == NULL)
537 {
bb5365ed 538 pVar = m_pGlobals->find(pszName);
5039dede
AK
539 if (pVar == NULL)
540 {
bb5365ed 541 pVar = m_pLocals->find(pszName);
5039dede
AK
542 if (pVar == NULL)
543 {
bb5365ed 544 pVar = m_pLocals->create(pszName);
5039dede
AK
545 }
546 }
547 }
548 return pVar;
549}
550
551
552//
553// Create variable if it does not exist, otherwise return NULL
554//
555
bb5365ed 556NXSL_Variable *NXSL_Program::createVariable(TCHAR *pszName)
5039dede
AK
557{
558 NXSL_Variable *pVar = NULL;
559
bb5365ed 560 if (m_pConstants->find(pszName) == NULL)
5039dede 561 {
bb5365ed 562 if (m_pGlobals->find(pszName) == NULL)
5039dede 563 {
bb5365ed 564 if (m_pLocals->find(pszName) == NULL)
5039dede 565 {
bb5365ed 566 pVar = m_pLocals->create(pszName);
5039dede
AK
567 }
568 }
569 }
570 return pVar;
571}
572
573
574//
575// Execute single instruction
576//
577
bb5365ed 578void NXSL_Program::execute()
5039dede
AK
579{
580 NXSL_Instruction *cp;
581 NXSL_Value *pValue;
582 NXSL_Variable *pVar;
583 NXSL_ExtFunction *pFunc;
584 DWORD dwNext = m_dwCurrPos + 1;
585 char szBuffer[256];
586 int i, nRet;
587
588 cp = m_ppInstructionSet[m_dwCurrPos];
589 switch(cp->m_nOpCode)
590 {
591 case OPCODE_PUSH_CONSTANT:
bb5365ed 592 m_pDataStack->push(new NXSL_Value(cp->m_operand.m_pConstant));
5039dede
AK
593 break;
594 case OPCODE_PUSH_VARIABLE:
bb5365ed
VK
595 pVar = findOrCreateVariable(cp->m_operand.m_pszString);
596 m_pDataStack->push(new NXSL_Value(pVar->getValue()));
5039dede
AK
597 break;
598 case OPCODE_SET:
bb5365ed 599 pVar = findOrCreateVariable(cp->m_operand.m_pszString);
c742e8c8
VK
600 if (!pVar->isConstant())
601 {
602 pValue = (NXSL_Value *)m_pDataStack->peek();
603 if (pValue != NULL)
5039dede 604 {
c742e8c8
VK
605 if (pValue->isArray())
606 {
607 pVar->setValue(new NXSL_Value(new NXSL_Array(pValue->getValueAsArray())));
608 }
609 else
610 {
611 pVar->setValue(new NXSL_Value(pValue));
612 }
5039dede
AK
613 }
614 else
615 {
c742e8c8 616 error(NXSL_ERR_DATA_STACK_UNDERFLOW);
5039dede 617 }
c742e8c8
VK
618 }
619 else
620 {
621 error(NXSL_ERR_ASSIGNMENT_TO_CONSTANT);
622 }
5039dede
AK
623 break;
624 case OPCODE_ARRAY:
bb5365ed 625 pVar = createVariable(cp->m_operand.m_pszString);
5039dede
AK
626 if (pVar != NULL)
627 {
bb5365ed 628 pVar->setValue(new NXSL_Value(new NXSL_Array));
5039dede
AK
629 }
630 else
631 {
bb5365ed 632 error(NXSL_ERR_VARIABLE_ALREADY_EXIST);
5039dede
AK
633 }
634 break;
635 case OPCODE_SET_ELEMENT: // Set array element; stack should contain: array index value (top)
bb5365ed 636 pValue = (NXSL_Value *)m_pDataStack->pop();
5039dede
AK
637 if (pValue != NULL)
638 {
639 NXSL_Value *array, *index;
640
bb5365ed
VK
641 index = (NXSL_Value *)m_pDataStack->pop();
642 array = (NXSL_Value *)m_pDataStack->pop();
5039dede
AK
643 if ((index != NULL) && (array != NULL))
644 {
bb5365ed 645 if (!index->isInteger())
5039dede 646 {
bb5365ed 647 error(NXSL_ERR_INDEX_NOT_INTEGER);
5039dede 648 }
bb5365ed 649 else if (!array->isArray())
5039dede 650 {
bb5365ed 651 error(NXSL_ERR_NOT_ARRAY);
5039dede
AK
652 }
653 else
654 {
bb5365ed 655 if (pValue->isArray())
3a6047a2 656 {
bb5365ed 657 array->getValueAsArray()->set(index->getValueAsInt32(), new NXSL_Value(new NXSL_Array(pValue->getValueAsArray())));
3a6047a2
VK
658 }
659 else
660 {
bb5365ed 661 array->getValueAsArray()->set(index->getValueAsInt32(), new NXSL_Value(pValue));
3a6047a2 662 }
bb5365ed 663 m_pDataStack->push(pValue);
3a6047a2 664 pValue = NULL; // Prevent deletion
5039dede
AK
665 }
666 }
667 else
668 {
bb5365ed 669 error(NXSL_ERR_DATA_STACK_UNDERFLOW);
5039dede
AK
670 }
671 delete index;
672 delete array;
3a6047a2 673 delete pValue;
5039dede
AK
674 }
675 else
676 {
bb5365ed 677 error(NXSL_ERR_DATA_STACK_UNDERFLOW);
5039dede
AK
678 }
679 break;
680 case OPCODE_GET_ELEMENT: // Get array element; stack should contain: array index (top)
bb5365ed 681 pValue = (NXSL_Value *)m_pDataStack->pop();
5039dede
AK
682 if (pValue != NULL)
683 {
684 NXSL_Value *array;
685
bb5365ed 686 array = (NXSL_Value *)m_pDataStack->pop();
5039dede
AK
687 if (array != NULL)
688 {
bb5365ed 689 if (array->isArray())
5039dede 690 {
bb5365ed 691 if (pValue->isInteger())
5039dede
AK
692 {
693 NXSL_Value *element;
694
bb5365ed
VK
695 element = array->getValueAsArray()->get(pValue->getValueAsInt32());
696 m_pDataStack->push((element != NULL) ? new NXSL_Value(element) : new NXSL_Value);
5039dede
AK
697 }
698 else
699 {
bb5365ed 700 error(NXSL_ERR_INDEX_NOT_INTEGER);
5039dede
AK
701 }
702 }
703 else
704 {
bb5365ed 705 error(NXSL_ERR_NOT_ARRAY);
5039dede
AK
706 }
707 delete array;
708 }
709 else
710 {
bb5365ed 711 error(NXSL_ERR_DATA_STACK_UNDERFLOW);
5039dede
AK
712 }
713 delete pValue;
714 }
715 else
716 {
bb5365ed 717 error(NXSL_ERR_DATA_STACK_UNDERFLOW);
5039dede
AK
718 }
719 break;
720 case OPCODE_CAST:
bb5365ed 721 pValue = (NXSL_Value *)m_pDataStack->peek();
5039dede
AK
722 if (pValue != NULL)
723 {
bb5365ed 724 if (!pValue->convert(cp->m_nStackItems))
5039dede 725 {
bb5365ed 726 error(NXSL_ERR_TYPE_CAST);
5039dede
AK
727 }
728 }
729 else
730 {
bb5365ed 731 error(NXSL_ERR_DATA_STACK_UNDERFLOW);
5039dede
AK
732 }
733 break;
734 case OPCODE_POP:
735 for(i = 0; i < cp->m_nStackItems; i++)
bb5365ed 736 delete (NXSL_Value *)m_pDataStack->pop();
5039dede
AK
737 break;
738 case OPCODE_JMP:
739 dwNext = cp->m_operand.m_dwAddr;
740 break;
741 case OPCODE_JZ:
742 case OPCODE_JNZ:
bb5365ed 743 pValue = (NXSL_Value *)m_pDataStack->pop();
5039dede
AK
744 if (pValue != NULL)
745 {
bb5365ed 746 if (pValue->isNumeric())
5039dede 747 {
bb5365ed 748 if (cp->m_nOpCode == OPCODE_JZ ? pValue->isZero() : pValue->isNonZero())
5039dede
AK
749 dwNext = cp->m_operand.m_dwAddr;
750 }
751 else
752 {
bb5365ed 753 error(3);
5039dede
AK
754 }
755 delete pValue;
756 }
757 else
758 {
bb5365ed 759 error(NXSL_ERR_DATA_STACK_UNDERFLOW);
5039dede
AK
760 }
761 break;
762 case OPCODE_CALL:
763 dwNext = cp->m_operand.m_dwAddr;
bb5365ed 764 callFunction(cp->m_nStackItems);
5039dede
AK
765 break;
766 case OPCODE_CALL_EXTERNAL:
bb5365ed 767 pFunc = m_pEnv->findFunction(cp->m_operand.m_pszString);
5039dede
AK
768 if (pFunc != NULL)
769 {
770 if ((cp->m_nStackItems == pFunc->m_iNumArgs) ||
771 (pFunc->m_iNumArgs == -1))
772 {
bb5365ed 773 if (m_pDataStack->getSize() >= cp->m_nStackItems)
5039dede
AK
774 {
775 nRet = pFunc->m_pfHandler(cp->m_nStackItems,
bb5365ed
VK
776 (NXSL_Value **)m_pDataStack->peekList(cp->m_nStackItems),
777 &pValue, this);
5039dede
AK
778 if (nRet == 0)
779 {
780 for(i = 0; i < cp->m_nStackItems; i++)
82b4f1b5 781 delete m_pDataStack->pop();
bb5365ed 782 m_pDataStack->push(pValue);
5039dede 783 }
ea84fc85
VK
784 else if (nRet == NXSL_STOP_SCRIPT_EXECUTION)
785 {
bb5365ed 786 m_pDataStack->push(pValue);
ea84fc85
VK
787 dwNext = m_dwCodeSize;
788 }
789 else
5039dede
AK
790 {
791 // Execution error inside function
bb5365ed 792 error(nRet);
5039dede
AK
793 }
794 }
795 else
796 {
bb5365ed 797 error(NXSL_ERR_DATA_STACK_UNDERFLOW);
5039dede
AK
798 }
799 }
800 else
801 {
bb5365ed 802 error(NXSL_ERR_INVALID_ARGUMENT_COUNT);
5039dede
AK
803 }
804 }
805 else
806 {
807 DWORD dwAddr;
808
bb5365ed 809 dwAddr = getFunctionAddress(cp->m_operand.m_pszString);
5039dede
AK
810 if (dwAddr != INVALID_ADDRESS)
811 {
812 dwNext = dwAddr;
bb5365ed 813 callFunction(cp->m_nStackItems);
5039dede
AK
814 }
815 else
816 {
bb5365ed 817 error(NXSL_ERR_NO_FUNCTION);
5039dede
AK
818 }
819 }
820 break;
821 case OPCODE_RET_NULL:
bb5365ed 822 m_pDataStack->push(new NXSL_Value);
5039dede
AK
823 case OPCODE_RETURN:
824 if (m_dwSubLevel > 0)
825 {
826 m_dwSubLevel--;
827 delete m_pLocals;
bb5365ed
VK
828 m_pLocals = (NXSL_VariableSystem *)m_pCodeStack->pop();
829 dwNext = CAST_FROM_POINTER(m_pCodeStack->pop(), DWORD);
5039dede
AK
830 }
831 else
832 {
833 // Return from main(), terminate program
834 dwNext = m_dwCodeSize;
835 }
836 break;
837 case OPCODE_BIND:
838 sprintf(szBuffer, "$%d", m_nBindPos++);
bb5365ed
VK
839 pVar = m_pLocals->find(szBuffer);
840 pValue = (pVar != NULL) ? new NXSL_Value(pVar->getValue()) : new NXSL_Value;
841 pVar = m_pLocals->find(cp->m_operand.m_pszString);
5039dede 842 if (pVar == NULL)
bb5365ed 843 m_pLocals->create(cp->m_operand.m_pszString, pValue);
5039dede 844 else
bb5365ed 845 pVar->setValue(pValue);
5039dede
AK
846 break;
847 case OPCODE_PRINT:
bb5365ed 848 pValue = (NXSL_Value *)m_pDataStack->pop();
5039dede
AK
849 if (pValue != NULL)
850 {
bb5365ed 851 const TCHAR *pszText;
5039dede
AK
852 DWORD dwLen;
853
bb5365ed 854 if (m_pEnv->getStdOut() != NULL)
5039dede 855 {
bb5365ed 856 pszText = pValue->getValueAsString(&dwLen);
5039dede 857 if (pszText != NULL)
bb5365ed 858 fwrite(pszText, dwLen, 1, m_pEnv->getStdOut());
5039dede 859 else
bb5365ed 860 fputs("(null)", m_pEnv->getStdOut());
5039dede
AK
861 }
862 delete pValue;
863 }
864 else
865 {
bb5365ed 866 error(NXSL_ERR_DATA_STACK_UNDERFLOW);
5039dede
AK
867 }
868 break;
869 case OPCODE_EXIT:
bb5365ed 870 if (m_pDataStack->getSize() > 0)
5039dede
AK
871 {
872 dwNext = m_dwCodeSize;
5039dede
AK
873 }
874 else
875 {
bb5365ed 876 error(NXSL_ERR_DATA_STACK_UNDERFLOW);
5039dede
AK
877 }
878 break;
879 case OPCODE_ADD:
880 case OPCODE_SUB:
881 case OPCODE_MUL:
882 case OPCODE_DIV:
883 case OPCODE_REM:
884 case OPCODE_CONCAT:
885 case OPCODE_LIKE:
886 case OPCODE_ILIKE:
887 case OPCODE_MATCH:
888 case OPCODE_IMATCH:
889 case OPCODE_EQ:
890 case OPCODE_NE:
891 case OPCODE_LT:
892 case OPCODE_LE:
893 case OPCODE_GT:
894 case OPCODE_GE:
895 case OPCODE_AND:
896 case OPCODE_OR:
897 case OPCODE_BIT_AND:
898 case OPCODE_BIT_OR:
899 case OPCODE_BIT_XOR:
900 case OPCODE_LSHIFT:
901 case OPCODE_RSHIFT:
902 case OPCODE_CASE:
bb5365ed 903 doBinaryOperation(cp->m_nOpCode);
5039dede
AK
904 break;
905 case OPCODE_NEG:
906 case OPCODE_NOT:
907 case OPCODE_BIT_NOT:
bb5365ed 908 doUnaryOperation(cp->m_nOpCode);
5039dede
AK
909 break;
910 case OPCODE_INC: // Post increment/decrement
911 case OPCODE_DEC:
bb5365ed
VK
912 pVar = findOrCreateVariable(cp->m_operand.m_pszString);
913 pValue = pVar->getValue();
914 if (pValue->isNumeric())
5039dede 915 {
bb5365ed 916 m_pDataStack->push(new NXSL_Value(pValue));
5039dede 917 if (cp->m_nOpCode == OPCODE_INC)
bb5365ed 918 pValue->increment();
5039dede 919 else
bb5365ed 920 pValue->decrement();
5039dede
AK
921 }
922 else
923 {
bb5365ed 924 error(NXSL_ERR_NOT_NUMBER);
5039dede
AK
925 }
926 break;
927 case OPCODE_INCP: // Pre increment/decrement
928 case OPCODE_DECP:
bb5365ed
VK
929 pVar = findOrCreateVariable(cp->m_operand.m_pszString);
930 pValue = pVar->getValue();
931 if (pValue->isNumeric())
5039dede
AK
932 {
933 if (cp->m_nOpCode == OPCODE_INC)
bb5365ed 934 pValue->increment();
5039dede 935 else
bb5365ed
VK
936 pValue->decrement();
937 m_pDataStack->push(new NXSL_Value(pValue));
5039dede
AK
938 }
939 else
940 {
bb5365ed 941 error(NXSL_ERR_NOT_NUMBER);
5039dede
AK
942 }
943 break;
3a6047a2 944 case OPCODE_GET_ATTRIBUTE:
bb5365ed 945 pValue = (NXSL_Value *)m_pDataStack->pop();
5039dede
AK
946 if (pValue != NULL)
947 {
bb5365ed 948 if (pValue->getDataType() == NXSL_DT_OBJECT)
5039dede
AK
949 {
950 NXSL_Object *pObj;
951 NXSL_Value *pAttr;
952
bb5365ed 953 pObj = pValue->getValueAsObject();
5039dede
AK
954 if (pObj != NULL)
955 {
bb5365ed 956 pAttr = pObj->getClass()->getAttr(pObj, cp->m_operand.m_pszString);
5039dede
AK
957 if (pAttr != NULL)
958 {
bb5365ed 959 m_pDataStack->push(pAttr);
5039dede
AK
960 }
961 else
962 {
bb5365ed 963 error(NXSL_ERR_NO_SUCH_ATTRIBUTE);
5039dede
AK
964 }
965 }
966 else
967 {
bb5365ed 968 error(NXSL_ERR_INTERNAL);
5039dede
AK
969 }
970 }
971 else
972 {
bb5365ed 973 error(NXSL_ERR_NOT_OBJECT);
5039dede
AK
974 }
975 delete pValue;
976 }
977 else
978 {
bb5365ed 979 error(NXSL_ERR_DATA_STACK_UNDERFLOW);
5039dede
AK
980 }
981 break;
3a6047a2 982 case OPCODE_SET_ATTRIBUTE:
bb5365ed 983 pValue = (NXSL_Value *)m_pDataStack->pop();
3a6047a2
VK
984 if (pValue != NULL)
985 {
bb5365ed 986 NXSL_Value *pReference = (NXSL_Value *)m_pDataStack->pop();
3a6047a2
VK
987 if (pReference != NULL)
988 {
bb5365ed 989 if (pReference->getDataType() == NXSL_DT_OBJECT)
3a6047a2
VK
990 {
991 NXSL_Object *pObj;
992
bb5365ed 993 pObj = pReference->getValueAsObject();
3a6047a2
VK
994 if (pObj != NULL)
995 {
bb5365ed 996 if (pObj->getClass()->setAttr(pObj, cp->m_operand.m_pszString, pValue))
3a6047a2 997 {
bb5365ed 998 m_pDataStack->push(pValue);
3a6047a2
VK
999 pValue = NULL;
1000 }
1001 else
1002 {
bb5365ed 1003 error(NXSL_ERR_NO_SUCH_ATTRIBUTE);
3a6047a2
VK
1004 }
1005 }
1006 else
1007 {
bb5365ed 1008 error(NXSL_ERR_INTERNAL);
3a6047a2
VK
1009 }
1010 }
1011 else
1012 {
bb5365ed 1013 error(NXSL_ERR_NOT_OBJECT);
3a6047a2
VK
1014 }
1015 delete pReference;
1016 }
1017 else
1018 {
bb5365ed 1019 error(NXSL_ERR_DATA_STACK_UNDERFLOW);
3a6047a2
VK
1020 }
1021 delete pValue;
1022 }
1023 else
1024 {
bb5365ed 1025 error(NXSL_ERR_DATA_STACK_UNDERFLOW);
3a6047a2
VK
1026 }
1027 break;
5039dede
AK
1028 default:
1029 break;
1030 }
1031
1032 if (m_dwCurrPos != INVALID_ADDRESS)
1033 m_dwCurrPos = dwNext;
1034}
1035
1036
1037//
1038// Perform binary operation on two operands from stack and push result to stack
1039//
1040
bb5365ed 1041void NXSL_Program::doBinaryOperation(int nOpCode)
5039dede
AK
1042{
1043 NXSL_Value *pVal1, *pVal2, *pRes = NULL;
bb5365ed 1044 const TCHAR *pszText1, *pszText2;
5039dede
AK
1045 DWORD dwLen1, dwLen2;
1046 int nType;
1047 LONG nResult;
1048
1049 if (nOpCode == OPCODE_CASE)
1050 {
1051 pVal1 = m_ppInstructionSet[m_dwCurrPos]->m_operand.m_pConstant;
bb5365ed 1052 pVal2 = (NXSL_Value *)m_pDataStack->peek();
5039dede
AK
1053 }
1054 else
1055 {
bb5365ed
VK
1056 pVal2 = (NXSL_Value *)m_pDataStack->pop();
1057 pVal1 = (NXSL_Value *)m_pDataStack->pop();
5039dede
AK
1058 }
1059
1060 if ((pVal1 != NULL) && (pVal2 != NULL))
1061 {
bb5365ed 1062 if ((!pVal1->isNull() && !pVal2->isNull()) ||
5039dede
AK
1063 (nOpCode == OPCODE_EQ) || (nOpCode == OPCODE_NE) || (nOpCode == OPCODE_CASE))
1064 {
bb5365ed 1065 if (pVal1->isNumeric() && pVal2->isNumeric() &&
5039dede
AK
1066 (nOpCode != OPCODE_CONCAT) && (nOpCode != OPCODE_LIKE))
1067 {
bb5365ed 1068 nType = SelectResultType(pVal1->getDataType(), pVal2->getDataType(), nOpCode);
5039dede
AK
1069 if (nType != NXSL_DT_NULL)
1070 {
bb5365ed 1071 if ((pVal1->convert(nType)) && (pVal2->convert(nType)))
5039dede
AK
1072 {
1073 switch(nOpCode)
1074 {
1075 case OPCODE_ADD:
1076 pRes = pVal1;
bb5365ed 1077 pRes->add(pVal2);
5039dede
AK
1078 delete pVal2;
1079 break;
1080 case OPCODE_SUB:
1081 pRes = pVal1;
bb5365ed 1082 pRes->sub(pVal2);
5039dede
AK
1083 delete pVal2;
1084 break;
1085 case OPCODE_MUL:
1086 pRes = pVal1;
bb5365ed 1087 pRes->mul(pVal2);
5039dede
AK
1088 delete pVal2;
1089 break;
1090 case OPCODE_DIV:
1091 pRes = pVal1;
bb5365ed 1092 pRes->div(pVal2);
5039dede
AK
1093 delete pVal2;
1094 break;
1095 case OPCODE_REM:
1096 pRes = pVal1;
bb5365ed 1097 pRes->rem(pVal2);
5039dede
AK
1098 delete pVal2;
1099 break;
1100 case OPCODE_EQ:
1101 case OPCODE_NE:
1102 nResult = pVal1->EQ(pVal2);
1103 delete pVal1;
1104 delete pVal2;
1105 pRes = new NXSL_Value((nOpCode == OPCODE_EQ) ? nResult : !nResult);
1106 break;
1107 case OPCODE_LT:
1108 nResult = pVal1->LT(pVal2);
1109 delete pVal1;
1110 delete pVal2;
1111 pRes = new NXSL_Value(nResult);
1112 break;
1113 case OPCODE_LE:
1114 nResult = pVal1->LE(pVal2);
1115 delete pVal1;
1116 delete pVal2;
1117 pRes = new NXSL_Value(nResult);
1118 break;
1119 case OPCODE_GT:
1120 nResult = pVal1->GT(pVal2);
1121 delete pVal1;
1122 delete pVal2;
1123 pRes = new NXSL_Value(nResult);
1124 break;
1125 case OPCODE_GE:
1126 nResult = pVal1->GE(pVal2);
1127 delete pVal1;
1128 delete pVal2;
1129 pRes = new NXSL_Value(nResult);
1130 break;
1131 case OPCODE_LSHIFT:
1132 pRes = pVal1;
bb5365ed 1133 pRes->lshift(pVal2->getValueAsInt32());
5039dede
AK
1134 delete pVal2;
1135 break;
1136 case OPCODE_RSHIFT:
1137 pRes = pVal1;
bb5365ed 1138 pRes->rshift(pVal2->getValueAsInt32());
5039dede
AK
1139 delete pVal2;
1140 break;
1141 case OPCODE_BIT_AND:
1142 pRes = pVal1;
bb5365ed 1143 pRes->bitAnd(pVal2);
5039dede
AK
1144 delete pVal2;
1145 break;
1146 case OPCODE_BIT_OR:
1147 pRes = pVal1;
bb5365ed 1148 pRes->bitOr(pVal2);
5039dede
AK
1149 delete pVal2;
1150 break;
1151 case OPCODE_BIT_XOR:
1152 pRes = pVal1;
bb5365ed 1153 pRes->bitXor(pVal2);
5039dede
AK
1154 delete pVal2;
1155 break;
1156 case OPCODE_AND:
bb5365ed 1157 nResult = (pVal1->isNonZero() && pVal2->isNonZero());
5039dede
AK
1158 delete pVal1;
1159 delete pVal2;
1160 pRes = new NXSL_Value(nResult);
1161 break;
1162 case OPCODE_OR:
bb5365ed 1163 nResult = (pVal1->isNonZero() || pVal2->isNonZero());
5039dede
AK
1164 delete pVal1;
1165 delete pVal2;
1166 pRes = new NXSL_Value(nResult);
1167 break;
1168 case OPCODE_CASE:
1169 pRes = new NXSL_Value((LONG)pVal1->EQ(pVal2));
1170 break;
1171 default:
bb5365ed 1172 error(NXSL_ERR_INTERNAL);
5039dede
AK
1173 break;
1174 }
1175 }
1176 else
1177 {
bb5365ed 1178 error(NXSL_ERR_TYPE_CAST);
5039dede
AK
1179 }
1180 }
1181 else
1182 {
bb5365ed 1183 error(NXSL_ERR_REAL_VALUE);
5039dede
AK
1184 }
1185 }
1186 else
1187 {
1188 switch(nOpCode)
1189 {
1190 case OPCODE_EQ:
1191 case OPCODE_NE:
1192 case OPCODE_CASE:
bb5365ed 1193 if (pVal1->isNull() && pVal2->isNull())
5039dede
AK
1194 {
1195 nResult = 1;
1196 }
bb5365ed 1197 else if (pVal1->isNull() || pVal2->isNull())
5039dede
AK
1198 {
1199 nResult = 0;
1200 }
1201 else
1202 {
bb5365ed
VK
1203 pszText1 = pVal1->getValueAsString(&dwLen1);
1204 pszText2 = pVal2->getValueAsString(&dwLen2);
5039dede
AK
1205 if (dwLen1 == dwLen2)
1206 nResult = !memcmp(pszText1, pszText2, dwLen1);
1207 else
1208 nResult = 0;
1209 }
1210 if (nOpCode != OPCODE_CASE)
1211 {
1212 delete pVal1;
1213 delete pVal2;
1214 }
1215 pRes = new NXSL_Value((nOpCode == OPCODE_NE) ? !nResult : nResult);
1216 break;
1217 case OPCODE_CONCAT:
bb5365ed 1218 if (pVal1->isNull() || pVal2->isNull())
5039dede 1219 {
bb5365ed 1220 error(NXSL_ERR_NULL_VALUE);
5039dede 1221 }
bb5365ed 1222 else if (pVal1->isObject() || pVal2->isObject())
5039dede 1223 {
bb5365ed 1224 error(NXSL_ERR_INVALID_OBJECT_OPERATION);
5039dede
AK
1225 }
1226 else
1227 {
1228 pRes = pVal1;
bb5365ed
VK
1229 pszText2 = pVal2->getValueAsString(&dwLen2);
1230 pRes->concatenate(pszText2, dwLen2);
5039dede
AK
1231 delete pVal2;
1232 }
1233 break;
1234 case OPCODE_LIKE:
1235 case OPCODE_ILIKE:
bb5365ed 1236 if (pVal1->isString() && pVal2->isString())
5039dede 1237 {
bb5365ed
VK
1238 pRes = new NXSL_Value((LONG)MatchString(pVal2->getValueAsCString(),
1239 pVal1->getValueAsCString(),
5039dede
AK
1240 nOpCode == OPCODE_LIKE));
1241 delete pVal1;
1242 delete pVal2;
1243 }
1244 else
1245 {
bb5365ed 1246 error(NXSL_ERR_NOT_STRING);
5039dede
AK
1247 }
1248 break;
1249 case OPCODE_MATCH:
1250 case OPCODE_IMATCH:
bb5365ed 1251 if (pVal1->isString() && pVal2->isString())
5039dede 1252 {
bb5365ed 1253 pRes = matchRegexp(pVal1, pVal2, nOpCode == OPCODE_IMATCH);
5039dede
AK
1254 delete pVal1;
1255 delete pVal2;
1256 }
1257 else
1258 {
bb5365ed 1259 error(NXSL_ERR_NOT_STRING);
5039dede
AK
1260 }
1261 break;
1262 case OPCODE_ADD:
1263 case OPCODE_SUB:
1264 case OPCODE_MUL:
1265 case OPCODE_DIV:
1266 case OPCODE_REM:
1267 case OPCODE_LT:
1268 case OPCODE_LE:
1269 case OPCODE_GT:
1270 case OPCODE_GE:
1271 case OPCODE_AND:
1272 case OPCODE_OR:
1273 case OPCODE_BIT_AND:
1274 case OPCODE_BIT_OR:
1275 case OPCODE_BIT_XOR:
1276 case OPCODE_LSHIFT:
1277 case OPCODE_RSHIFT:
bb5365ed 1278 error(NXSL_ERR_NOT_NUMBER);
5039dede
AK
1279 break;
1280 default:
bb5365ed 1281 error(NXSL_ERR_INTERNAL);
5039dede
AK
1282 break;
1283 }
1284 }
1285 }
1286 else
1287 {
bb5365ed 1288 error(NXSL_ERR_NULL_VALUE);
5039dede
AK
1289 }
1290 }
1291 else
1292 {
bb5365ed 1293 error(NXSL_ERR_DATA_STACK_UNDERFLOW);
5039dede
AK
1294 }
1295
1296 if (pRes != NULL)
bb5365ed 1297 m_pDataStack->push(pRes);
5039dede
AK
1298}
1299
1300
1301//
1302// Perform unary operation on operand from the stack and push result back to stack
1303//
1304
bb5365ed 1305void NXSL_Program::doUnaryOperation(int nOpCode)
5039dede
AK
1306{
1307 NXSL_Value *pVal;
1308
bb5365ed 1309 pVal = (NXSL_Value *)m_pDataStack->peek();
5039dede
AK
1310 if (pVal != NULL)
1311 {
bb5365ed 1312 if (pVal->isNumeric())
5039dede
AK
1313 {
1314 switch(nOpCode)
1315 {
1316 case OPCODE_NEG:
bb5365ed 1317 pVal->negate();
5039dede
AK
1318 break;
1319 case OPCODE_NOT:
bb5365ed 1320 if (!pVal->isReal())
5039dede 1321 {
bb5365ed 1322 pVal->set((LONG)pVal->isZero());
5039dede
AK
1323 }
1324 else
1325 {
bb5365ed 1326 error(NXSL_ERR_REAL_VALUE);
5039dede
AK
1327 }
1328 break;
1329 case OPCODE_BIT_NOT:
bb5365ed 1330 if (!pVal->isReal())
5039dede 1331 {
bb5365ed 1332 pVal->bitNot();
5039dede
AK
1333 }
1334 else
1335 {
bb5365ed 1336 error(NXSL_ERR_REAL_VALUE);
5039dede
AK
1337 }
1338 break;
1339 default:
bb5365ed 1340 error(NXSL_ERR_INTERNAL);
5039dede
AK
1341 break;
1342 }
1343 }
1344 else
1345 {
bb5365ed 1346 error(NXSL_ERR_NOT_NUMBER);
5039dede
AK
1347 }
1348 }
1349 else
1350 {
bb5365ed 1351 error(NXSL_ERR_DATA_STACK_UNDERFLOW);
5039dede
AK
1352 }
1353}
1354
1355
1356//
1357// Relocate code block
1358//
1359
bb5365ed 1360void NXSL_Program::relocateCode(DWORD dwStart, DWORD dwLen, DWORD dwShift)
5039dede
AK
1361{
1362 DWORD i, dwLast;
1363
1364 dwLast = min(dwStart + dwLen, m_dwCodeSize);
1365 for(i = dwStart; i < dwLast; i++)
1366 if ((m_ppInstructionSet[i]->m_nOpCode == OPCODE_JMP) ||
1367 (m_ppInstructionSet[i]->m_nOpCode == OPCODE_JZ) ||
1368 (m_ppInstructionSet[i]->m_nOpCode == OPCODE_JNZ) ||
1369 (m_ppInstructionSet[i]->m_nOpCode == OPCODE_CALL))
1370 {
1371 m_ppInstructionSet[i]->m_operand.m_dwAddr += dwShift;
1372 }
1373}
1374
1375
1376//
1377// Use external module
1378//
1379
bb5365ed 1380void NXSL_Program::useModule(NXSL_Program *pModule, const char *pszName)
5039dede
AK
1381{
1382 DWORD i, j, dwStart;
1383
1384 // Check if module already loaded
1385 for(i = 0; i < m_dwNumModules; i++)
1386 if (!stricmp(pszName, m_pModuleList[i].m_szName))
1387 return; // Already loaded
1388
1389 // Add code from module
1390 dwStart = m_dwCodeSize;
1391 m_dwCodeSize += pModule->m_dwCodeSize;
1392 m_ppInstructionSet = (NXSL_Instruction **)realloc(m_ppInstructionSet,
1393 sizeof(NXSL_Instruction *) * m_dwCodeSize);
1394 for(i = dwStart, j = 0; i < m_dwCodeSize; i++, j++)
1395 m_ppInstructionSet[i] = new NXSL_Instruction(pModule->m_ppInstructionSet[j]);
bb5365ed 1396 relocateCode(dwStart, pModule->m_dwCodeSize, dwStart);
5039dede
AK
1397
1398 // Add function names from module
1399 m_pFunctionList = (NXSL_Function *)realloc(m_pFunctionList,
1400 sizeof(NXSL_Function) * (m_dwNumFunctions + pModule->m_dwNumFunctions));
1401 memcpy(&m_pFunctionList[m_dwNumFunctions], pModule->m_pFunctionList,
1402 sizeof(NXSL_Function) * pModule->m_dwNumFunctions);
1403 for(i = m_dwNumFunctions, j = 0; j < pModule->m_dwNumFunctions; i++, j++)
1404 m_pFunctionList[i].m_dwAddr += dwStart;
1405
1406 // Register module as loaded
1407 m_pModuleList = (NXSL_Module *)malloc(sizeof(NXSL_Module) * (m_dwNumModules + 1));
1408 strncpy(m_pModuleList[m_dwNumModules].m_szName, pszName, MAX_PATH);
1409 m_pModuleList[m_dwNumModules].m_dwCodeStart = dwStart;
1410 m_pModuleList[m_dwNumModules].m_dwCodeSize = pModule->m_dwCodeSize;
1411 m_pModuleList[m_dwNumModules].m_dwFunctionStart = m_dwNumFunctions;
1412 m_pModuleList[m_dwNumModules].m_dwNumFunctions = pModule->m_dwNumFunctions;
1413 m_dwNumModules++;
1414
1415 m_dwNumFunctions += pModule->m_dwNumFunctions;
1416}
1417
1418
1419//
1420// Call function at given address
1421//
1422
bb5365ed 1423void NXSL_Program::callFunction(int nArgCount)
5039dede
AK
1424{
1425 int i;
1426 NXSL_Value *pValue;
1427 char szBuffer[32];
1428
1429 if (m_dwSubLevel < CONTROL_STACK_LIMIT)
1430 {
1431 m_dwSubLevel++;
bb5365ed
VK
1432 m_pCodeStack->push(CAST_TO_POINTER(m_dwCurrPos + 1, void *));
1433 m_pCodeStack->push(m_pLocals);
5039dede
AK
1434 m_pLocals = new NXSL_VariableSystem;
1435 m_nBindPos = 1;
1436
1437 // Bind arguments
1438 for(i = nArgCount; i > 0; i--)
1439 {
bb5365ed 1440 pValue = (NXSL_Value *)m_pDataStack->pop();
5039dede
AK
1441 if (pValue != NULL)
1442 {
1443 sprintf(szBuffer, "$%d", i);
bb5365ed 1444 m_pLocals->create(szBuffer, pValue);
5039dede
AK
1445 }
1446 else
1447 {
bb5365ed 1448 error(NXSL_ERR_DATA_STACK_UNDERFLOW);
5039dede
AK
1449 break;
1450 }
1451 }
1452 }
1453 else
1454 {
bb5365ed 1455 error(NXSL_ERR_CONTROL_STACK_OVERFLOW);
5039dede
AK
1456 }
1457}
1458
1459
1460//
1461// Find function address by name
1462//
1463
bb5365ed 1464DWORD NXSL_Program::getFunctionAddress(char *pszName)
5039dede
AK
1465{
1466 DWORD i;
1467
1468 for(i = 0; i < m_dwNumFunctions; i++)
1469 if (!strcmp(m_pFunctionList[i].m_szName, pszName))
1470 return m_pFunctionList[i].m_dwAddr;
1471 return INVALID_ADDRESS;
1472}
1473
1474
1475//
1476// Match regular expression
1477//
1478
bb5365ed 1479NXSL_Value *NXSL_Program::matchRegexp(NXSL_Value *pValue, NXSL_Value *pRegexp,
5039dede
AK
1480 BOOL bIgnoreCase)
1481{
1482 regex_t preg;
1483 regmatch_t fields[256];
1484 NXSL_Value *pResult;
1485 NXSL_Variable *pVar;
1486 TCHAR szName[16];
1487 int i;
1488
bb5365ed 1489 if (regcomp(&preg, pRegexp->getValueAsCString(),
5039dede
AK
1490 bIgnoreCase ? REG_EXTENDED | REG_ICASE : REG_EXTENDED) == 0)
1491 {
bb5365ed 1492 if (regexec(&preg, pValue->getValueAsCString(), 256, fields, 0) == 0)
5039dede
AK
1493 {
1494 pResult = new NXSL_Value((LONG)1);
1495 for(i = 1; (i < 256) && (fields[i].rm_so != -1); i++)
1496 {
1497 _stprintf(szName, _T("$%d"), i);
bb5365ed 1498 pVar = m_pLocals->find(szName);
5039dede 1499 if (pVar == NULL)
bb5365ed 1500 m_pLocals->create(szName, new NXSL_Value(pValue->getValueAsCString() + fields[i].rm_so, fields[i].rm_eo - fields[i].rm_so));
5039dede 1501 else
bb5365ed 1502 pVar->setValue(new NXSL_Value(pValue->getValueAsCString() + fields[i].rm_so, fields[i].rm_eo - fields[i].rm_so));
5039dede
AK
1503 }
1504 }
1505 else
1506 {
1507 pResult = new NXSL_Value((LONG)0);
1508 }
1509 regfree(&preg);
1510 }
1511 else
1512 {
bb5365ed 1513 error(NXSL_ERR_REGEXP_ERROR);
5039dede
AK
1514 pResult = NULL;
1515 }
1516 return pResult;
1517}
1518
1519
1520//
1521// Get final jump destination from a jump chain
1522//
1523
bb5365ed 1524DWORD NXSL_Program::getFinalJumpDestination(DWORD dwAddr)
5039dede 1525{
bb5365ed 1526 return (m_ppInstructionSet[dwAddr]->m_nOpCode == OPCODE_JMP) ? getFinalJumpDestination(m_ppInstructionSet[dwAddr]->m_operand.m_dwAddr) : dwAddr;
5039dede
AK
1527}
1528
1529
1530//
1531// Optimize compiled program
1532//
1533
bb5365ed 1534void NXSL_Program::optimize()
5039dede
AK
1535{
1536 DWORD i, j;
1537
1538 // Convert jump chains to single jump
1539 for(i = 0; i < m_dwCodeSize; i++)
1540 {
1541 if ((m_ppInstructionSet[i]->m_nOpCode == OPCODE_JMP) ||
1542 (m_ppInstructionSet[i]->m_nOpCode == OPCODE_JZ) ||
1543 (m_ppInstructionSet[i]->m_nOpCode == OPCODE_JNZ))
1544 {
bb5365ed 1545 m_ppInstructionSet[i]->m_operand.m_dwAddr = getFinalJumpDestination(m_ppInstructionSet[i]->m_operand.m_dwAddr);
5039dede
AK
1546 }
1547 }
1548
1549 // Remove jumps to next instruction
1550 for(i = 0; i < m_dwCodeSize; i++)
1551 {
1552 if (((m_ppInstructionSet[i]->m_nOpCode == OPCODE_JMP) ||
1553 (m_ppInstructionSet[i]->m_nOpCode == OPCODE_JZ) ||
1554 (m_ppInstructionSet[i]->m_nOpCode == OPCODE_JNZ)) &&
1555 (m_ppInstructionSet[i]->m_operand.m_dwAddr == i + 1))
1556 {
1557 delete m_ppInstructionSet[i];
1558 m_dwCodeSize--;
1559 memmove(&m_ppInstructionSet[i], &m_ppInstructionSet[i + 1], sizeof(NXSL_Instruction *) * (m_dwCodeSize - i));
1560
1561 // Change jump destination addresses
1562 for(j = 0; j < m_dwCodeSize; j++)
1563 {
1564 if (((m_ppInstructionSet[j]->m_nOpCode == OPCODE_JMP) ||
1565 (m_ppInstructionSet[j]->m_nOpCode == OPCODE_JZ) ||
1566 (m_ppInstructionSet[j]->m_nOpCode == OPCODE_JNZ) ||
1567 (m_ppInstructionSet[j]->m_nOpCode == OPCODE_CALL)) &&
1568 (m_ppInstructionSet[j]->m_operand.m_dwAddr > i))
1569 {
1570 m_ppInstructionSet[j]->m_operand.m_dwAddr--;
1571 }
1572 }
1573
1574 i--;
1575 }
1576 }
1577}
bb5365ed
VK
1578
1579
1580//
1581// Trace
1582//
1583
1584void NXSL_Program::trace(int level, const TCHAR *text)
1585{
1586 if (m_pEnv != NULL)
1587 m_pEnv->trace(level, text);
1588}