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