license changed to LGPL for libnxcl, libnxsnmp, libnxlp, libnxsl, and libnxmap
[public/netxms.git] / src / libnxsl / compiler.cpp
1 /*
2 ** NetXMS - Network Management System
3 ** NetXMS Scripting Language Interpreter
4 ** Copyright (C) 2003-2010 Victor Kirhenshtein
5 **
6 ** This program is free software; you can redistribute it and/or modify
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
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 Lesser 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: compiler.cpp
21 **
22 **/
23
24 #include "libnxsl.h"
25
26
27 //
28 // Externals
29 //
30
31 int yyparse(yyscan_t scanner, NXSL_Lexer *, NXSL_Compiler *, NXSL_Program *);
32 extern int yydebug;
33 void yyset_extra(NXSL_Lexer *, yyscan_t);
34 int yylex_init(yyscan_t *);
35 int yylex_destroy(yyscan_t);
36
37
38 //
39 // Constructor
40 //
41
42 NXSL_Compiler::NXSL_Compiler()
43 {
44 m_pszErrorText = NULL;
45 m_pLexer = NULL;
46 m_pAddrStack = new NXSL_Stack;
47 m_pBreakStack = new NXSL_Stack;
48 }
49
50
51 //
52 // Destructor
53 //
54
55 NXSL_Compiler::~NXSL_Compiler()
56 {
57 safe_free(m_pszErrorText);
58 delete m_pLexer;
59 delete m_pAddrStack;
60 delete m_pBreakStack;
61 }
62
63
64 //
65 // Error handler
66 //
67
68 void NXSL_Compiler::error(const char *pszMsg)
69 {
70 char szText[1024];
71
72 if (m_pszErrorText == NULL)
73 {
74 snprintf(szText, 1024, "Error in line %d: %s", m_pLexer->getCurrLine(), pszMsg);
75 #ifdef UNICODE
76 nLen = strlen(szText) + 1;
77 m_pszErrorText = (WCHAR *)malloc(nLen * sizeof(WCHAR));
78 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, szText,
79 -1, m_pszErrorText, nLen, NULL, NULL);
80 #else
81 m_pszErrorText = strdup(szText);
82 #endif
83 }
84 }
85
86
87 //
88 // Compile source code
89 //
90
91 NXSL_Program *NXSL_Compiler::compile(const TCHAR *pszSourceCode)
92 {
93 NXSL_Program *pResult;
94 yyscan_t scanner;
95
96 m_pLexer = new NXSL_Lexer(this, pszSourceCode);
97 pResult = new NXSL_Program;
98 yylex_init(&scanner);
99 yyset_extra(m_pLexer, scanner);
100 //yydebug=1;
101 if (yyparse(scanner, m_pLexer, this, pResult) == 0)
102 {
103 pResult->resolveFunctions();
104 pResult->optimize();
105 }
106 else
107 {
108 delete pResult;
109 pResult = NULL;
110 }
111 yylex_destroy(scanner);
112 return pResult;
113 }
114
115
116 //
117 // yyerror() for parser
118 //
119
120 void yyerror(yyscan_t scanner, NXSL_Lexer *pLexer, NXSL_Compiler *pCompiler,
121 NXSL_Program *pScript, const char *pszText)
122 {
123 pCompiler->error(pszText);
124 }
125
126
127 //
128 // Pop address
129 //
130
131 DWORD NXSL_Compiler::popAddr()
132 {
133 void *pAddr;
134
135 pAddr = m_pAddrStack->pop();
136 return pAddr ? CAST_FROM_POINTER(pAddr, DWORD) : INVALID_ADDRESS;
137 }
138
139
140 //
141 // Peek address
142 //
143
144 DWORD NXSL_Compiler::peekAddr()
145 {
146 void *pAddr;
147
148 pAddr = m_pAddrStack->peek();
149 return pAddr ? CAST_FROM_POINTER(pAddr, DWORD) : INVALID_ADDRESS;
150 }
151
152
153 //
154 // Add "break" statement address
155 //
156
157 void NXSL_Compiler::addBreakAddr(DWORD dwAddr)
158 {
159 Queue *pQueue;
160
161 pQueue = (Queue *)m_pBreakStack->peek();
162 if (pQueue != NULL)
163 {
164 pQueue->Put(CAST_TO_POINTER(dwAddr, void *));
165 }
166 }
167
168
169 //
170 // Resolve all breal statements at current level
171 //
172
173 void NXSL_Compiler::closeBreakLevel(NXSL_Program *pScript)
174 {
175 Queue *pQueue;
176 void *pAddr;
177 DWORD dwAddr;
178
179 pQueue = (Queue *)m_pBreakStack->pop();
180 if (pQueue != NULL)
181 {
182 while((pAddr = pQueue->Get()) != NULL)
183 {
184 dwAddr = CAST_FROM_POINTER(pAddr, DWORD);
185 pScript->createJumpAt(dwAddr, pScript->getCodeSize());
186 }
187 delete pQueue;
188 }
189 }