new NXSL operator @
[public/netxms.git] / src / libnxsl / parser.y
1 %{
2
3 #pragma warning(disable : 4065 4102)
4
5 #define YYERROR_VERBOSE
6 #define YYINCLUDED_STDLIB_H
7 #define YYDEBUG 1
8
9 #include <nms_common.h>
10 #include "libnxsl.h"
11 #include "parser.tab.hpp"
12
13 void yyerror(yyscan_t scanner, NXSL_Lexer *pLexer, NXSL_Compiler *pCompiler,
14 NXSL_Program *pScript, const char *pszText);
15 int yylex(YYSTYPE *lvalp, yyscan_t scanner);
16
17 %}
18
19 %expect 1
20 %pure-parser
21 %lex-param {yyscan_t scanner}
22 %parse-param {yyscan_t scanner}
23 %parse-param {NXSL_Lexer *pLexer}
24 %parse-param {NXSL_Compiler *pCompiler}
25 %parse-param {NXSL_Program *pScript}
26
27 %union
28 {
29 LONG valInt32;
30 DWORD valUInt32;
31 INT64 valInt64;
32 QWORD valUInt64;
33 char *valStr;
34 double valReal;
35 NXSL_Value *pConstant;
36 NXSL_Instruction *pInstruction;
37 }
38
39 %token T_ARRAY
40 %token T_BREAK
41 %token T_CASE
42 %token T_CONTINUE
43 %token T_DEFAULT
44 %token T_DO
45 %token T_ELSE
46 %token T_EXIT
47 %token T_FALSE
48 %token T_FOR
49 %token T_FOREACH
50 %token T_GLOBAL
51 %token T_IF
52 %token T_NULL
53 %token T_PRINT
54 %token T_PRINTLN
55 %token T_RETURN
56 %token T_SUB
57 %token T_SWITCH
58 %token T_TRUE
59 %token T_TYPE_INT32
60 %token T_TYPE_INT64
61 %token T_TYPE_REAL
62 %token T_TYPE_STRING
63 %token T_TYPE_UINT32
64 %token T_TYPE_UINT64
65 %token T_USE
66 %token T_WHILE
67
68 %token <valStr> T_COMPOUND_IDENTIFIER
69 %token <valStr> T_IDENTIFIER
70 %token <valStr> T_STRING
71 %token <valInt32> T_INT32
72 %token <valUInt32> T_UINT32
73 %token <valInt64> T_INT64
74 %token <valUInt64> T_UINT64
75 %token <valReal> T_REAL
76
77 %right '=' T_ASSIGN_ADD T_ASSIGN_SUB T_ASSIGN_MUL T_ASSIGN_DIV T_ASSIGN_REM T_ASSIGN_CONCAT T_ASSIGN_AND T_ASSIGN_OR T_ASSIGN_XOR
78 %right ':'
79 %left '?'
80 %left '.'
81 %left T_OR
82 %left T_AND
83 %left '|'
84 %left '^'
85 %left '&'
86 %left T_NE T_EQ T_LIKE T_ILIKE T_MATCH T_IMATCH
87 %left '<' T_LE '>' T_GE
88 %left T_LSHIFT T_RSHIFT
89 %left '+' '-'
90 %left '*' '/' '%'
91 %right T_INC T_DEC '!' '~' NEGATE
92 %left T_REF '@'
93 %left T_POST_INC T_POST_DEC '[' ']'
94
95 %type <pConstant> Constant
96 %type <valStr> AnyIdentifier
97 %type <valStr> FunctionName
98 %type <valInt32> BuiltinType
99 %type <valInt32> ParameterList
100 %type <pInstruction> SimpleStatementKeyword
101
102 %start Script
103
104
105 %%
106
107 Script:
108 Module
109 {
110 char szErrorText[256];
111
112 // Add implicit main() function
113 if (!pScript->addFunction("$main", 0, szErrorText))
114 {
115 pCompiler->error(szErrorText);
116 pLexer->setErrorState();
117 }
118
119 // Implicit return
120 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_RET_NULL));
121 }
122 | Expression
123 {
124 char szErrorText[256];
125
126 // Add implicit return
127 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_RETURN));
128
129 // Add implicit main() function
130 if (!pScript->addFunction("$main", 0, szErrorText))
131 {
132 pCompiler->error(szErrorText);
133 pLexer->setErrorState();
134 }
135 }
136 |
137 {
138 char szErrorText[256];
139
140 // Add implicit return
141 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_RET_NULL));
142
143 // Add implicit main() function
144 if (!pScript->addFunction("$main", 0, szErrorText))
145 {
146 pCompiler->error(szErrorText);
147 pLexer->setErrorState();
148 }
149 }
150 ;
151
152 Module:
153 ModuleComponent Module
154 | ModuleComponent
155 ;
156
157 ModuleComponent:
158 Function
159 | StatementOrBlock
160 | UseStatement
161 ;
162
163 UseStatement:
164 T_USE AnyIdentifier ';'
165 {
166 pScript->addPreload($2);
167 }
168 ;
169
170 AnyIdentifier:
171 T_IDENTIFIER
172 | T_COMPOUND_IDENTIFIER
173 ;
174
175 Function:
176 T_SUB FunctionName
177 {
178 char szErrorText[256];
179
180 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_JMP, INVALID_ADDRESS));
181
182 if (!pScript->addFunction($2, INVALID_ADDRESS, szErrorText))
183 {
184 pCompiler->error(szErrorText);
185 pLexer->setErrorState();
186 }
187 free($2);
188 pCompiler->setIdentifierOperation(OPCODE_BIND);
189 }
190 ParameterDeclaration Block
191 {
192 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_RET_NULL));
193 pScript->resolveLastJump(OPCODE_JMP);
194 }
195 ;
196
197 ParameterDeclaration:
198 IdentifierList ')'
199 | ')'
200 ;
201
202 IdentifierList:
203 T_IDENTIFIER
204 {
205 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), pCompiler->getIdentifierOperation(), $1));
206 }
207 ',' IdentifierList
208 | T_IDENTIFIER
209 {
210 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), pCompiler->getIdentifierOperation(), $1));
211 }
212 ;
213
214 Block:
215 '{' StatementList '}'
216 ;
217
218 StatementList:
219 StatementOrBlock StatementList
220 |
221 ;
222
223 StatementOrBlock:
224 Statement
225 | Block
226 ;
227
228 Statement:
229 Expression ';'
230 {
231 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_POP, (int)1));
232 }
233 | BuiltinStatement
234 | ';'
235 {
236 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_NOP));
237 }
238 ;
239
240 Expression:
241 '(' Expression ')'
242 | T_IDENTIFIER '=' Expression
243 {
244 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_SET, $1));
245 }
246 | T_IDENTIFIER T_ASSIGN_ADD { pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_PUSH_VARIABLE, strdup($1))); } Expression
247 {
248 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_ADD));
249 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_SET, $1));
250 }
251 | T_IDENTIFIER T_ASSIGN_SUB { pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_PUSH_VARIABLE, strdup($1))); } Expression
252 {
253 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_SUB));
254 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_SET, $1));
255 }
256 | T_IDENTIFIER T_ASSIGN_MUL { pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_PUSH_VARIABLE, strdup($1))); } Expression
257 {
258 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_MUL));
259 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_SET, $1));
260 }
261 | T_IDENTIFIER T_ASSIGN_DIV { pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_PUSH_VARIABLE, strdup($1))); } Expression
262 {
263 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_DIV));
264 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_SET, $1));
265 }
266 | T_IDENTIFIER T_ASSIGN_REM { pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_PUSH_VARIABLE, strdup($1))); } Expression
267 {
268 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_REM));
269 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_SET, $1));
270 }
271 | T_IDENTIFIER T_ASSIGN_CONCAT { pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_PUSH_VARIABLE, strdup($1))); } Expression
272 {
273 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_CONCAT));
274 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_SET, $1));
275 }
276 | T_IDENTIFIER T_ASSIGN_AND { pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_PUSH_VARIABLE, strdup($1))); } Expression
277 {
278 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_BIT_AND));
279 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_SET, $1));
280 }
281 | T_IDENTIFIER T_ASSIGN_OR { pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_PUSH_VARIABLE, strdup($1))); } Expression
282 {
283 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_BIT_OR));
284 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_SET, $1));
285 }
286 | T_IDENTIFIER T_ASSIGN_XOR { pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_PUSH_VARIABLE, strdup($1))); } Expression
287 {
288 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_BIT_XOR));
289 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_SET, $1));
290 }
291 | Expression '[' Expression ']' '=' Expression
292 {
293 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_SET_ELEMENT));
294 }
295 | Expression '[' Expression ']'
296 {
297 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_GET_ELEMENT));
298 }
299 | Expression T_REF T_IDENTIFIER '=' Expression
300 {
301 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_SET_ATTRIBUTE, $3));
302 }
303 | Expression T_REF T_IDENTIFIER
304 {
305 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_GET_ATTRIBUTE, $3));
306 }
307 | T_IDENTIFIER '@' Expression
308 {
309 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_SAFE_GET_ATTR, $1));
310 }
311 | '-' Expression %prec NEGATE
312 {
313 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_NEG));
314 }
315 | '!' Expression
316 {
317 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_NOT));
318 }
319 | '~' Expression
320 {
321 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_BIT_NOT));
322 }
323 | T_INC T_IDENTIFIER
324 {
325 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_INCP, $2));
326 }
327 | T_DEC T_IDENTIFIER
328 {
329 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_DECP, $2));
330 }
331 | T_IDENTIFIER T_INC %prec T_POST_INC
332 {
333 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_INC, $1));
334 }
335 | T_IDENTIFIER T_DEC %prec T_POST_DEC
336 {
337 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_DEC, $1));
338 }
339 | Expression '+' Expression
340 {
341 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_ADD));
342 }
343 | Expression '-' Expression
344 {
345 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_SUB));
346 }
347 | Expression '*' Expression
348 {
349 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_MUL));
350 }
351 | Expression '/' Expression
352 {
353 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_DIV));
354 }
355 | Expression '%' Expression
356 {
357 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_REM));
358 }
359 | Expression T_LIKE Expression
360 {
361 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_LIKE));
362 }
363 | Expression T_ILIKE Expression
364 {
365 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_ILIKE));
366 }
367 | Expression T_MATCH Expression
368 {
369 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_MATCH));
370 }
371 | Expression T_IMATCH Expression
372 {
373 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_IMATCH));
374 }
375 | Expression T_EQ Expression
376 {
377 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_EQ));
378 }
379 | Expression T_NE Expression
380 {
381 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_NE));
382 }
383 | Expression '<' Expression
384 {
385 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_LT));
386 }
387 | Expression T_LE Expression
388 {
389 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_LE));
390 }
391 | Expression '>' Expression
392 {
393 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_GT));
394 }
395 | Expression T_GE Expression
396 {
397 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_GE));
398 }
399 | Expression '&' Expression
400 {
401 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_BIT_AND));
402 }
403 | Expression '|' Expression
404 {
405 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_BIT_OR));
406 }
407 | Expression '^' Expression
408 {
409 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_BIT_XOR));
410 }
411 | Expression T_AND { pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_JZ_PEEK, INVALID_ADDRESS)); } Expression
412 {
413 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_AND));
414 pScript->resolveLastJump(OPCODE_JZ_PEEK);
415 }
416 | Expression T_OR { pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_JNZ_PEEK, INVALID_ADDRESS)); } Expression
417 {
418 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_OR));
419 pScript->resolveLastJump(OPCODE_JNZ_PEEK);
420 }
421 | Expression T_LSHIFT Expression
422 {
423 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_LSHIFT));
424 }
425 | Expression T_RSHIFT Expression
426 {
427 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_RSHIFT));
428 }
429 | Expression '.' Expression
430 {
431 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_CONCAT));
432 }
433 | Expression '?'
434 {
435 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_JZ, INVALID_ADDRESS));
436 }
437 Expression ':'
438 {
439 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_JMP, INVALID_ADDRESS));
440 pScript->resolveLastJump(OPCODE_JZ);
441 }
442 Expression
443 {
444 pScript->resolveLastJump(OPCODE_JMP);
445 }
446 | Operand
447 ;
448
449 Operand:
450 FunctionCall
451 | TypeCast
452 | ArrayInitializer
453 | T_IDENTIFIER
454 {
455 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_PUSH_VARIABLE, $1));
456 }
457 | Constant
458 {
459 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_PUSH_CONSTANT, $1));
460 }
461 ;
462
463 TypeCast:
464 BuiltinType '(' Expression ')'
465 {
466 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_CAST, (int)$1));
467 }
468 ;
469
470 ArrayInitializer:
471 '%' '('
472 {
473 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_PUSH_CONSTANT, new NXSL_Value(new NXSL_Array)));
474 }
475 ArrayElements ')'
476 | '%' '(' ')'
477 {
478 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_PUSH_CONSTANT, new NXSL_Value(new NXSL_Array)));
479 }
480 ;
481
482 ArrayElements:
483 Expression
484 {
485 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_ADD_TO_ARRAY));
486 }
487 ',' ArrayElements
488 | Expression
489 {
490 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_ADD_TO_ARRAY));
491 }
492 ;
493
494 BuiltinType:
495 T_TYPE_INT32
496 {
497 $$ = NXSL_DT_INT32;
498 }
499 | T_TYPE_INT64
500 {
501 $$ = NXSL_DT_INT64;
502 }
503 | T_TYPE_UINT32
504 {
505 $$ = NXSL_DT_UINT32;
506 }
507 | T_TYPE_UINT64
508 {
509 $$ = NXSL_DT_UINT64;
510 }
511 | T_TYPE_REAL
512 {
513 $$ = NXSL_DT_REAL;
514 }
515 | T_TYPE_STRING
516 {
517 $$ = NXSL_DT_STRING;
518 }
519 ;
520
521 BuiltinStatement:
522 SimpleStatement ';'
523 | PrintlnStatement
524 | IfStatement
525 | DoStatement
526 | WhileStatement
527 | ForStatement
528 | ForEachStatement
529 | SwitchStatement
530 | ArrayStatement
531 | GlobalStatement
532 | T_BREAK ';'
533 {
534 if (pCompiler->canUseBreak())
535 {
536 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_NOP));
537 pCompiler->addBreakAddr(pScript->getCodeSize() - 1);
538 }
539 else
540 {
541 pCompiler->error("\"break\" statement can be used only within loops and \"switch\" statements");
542 pLexer->setErrorState();
543 }
544 }
545 | T_CONTINUE ';'
546 {
547 DWORD dwAddr = pCompiler->peekAddr();
548 if (dwAddr != INVALID_ADDRESS)
549 {
550 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_JMP, dwAddr));
551 }
552 else
553 {
554 pCompiler->error("\"continue\" statement can be used only within loops");
555 pLexer->setErrorState();
556 }
557 }
558 ;
559
560 SimpleStatement:
561 SimpleStatementKeyword Expression
562 {
563 pScript->addInstruction($1);
564 }
565 | SimpleStatementKeyword
566 {
567 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_PUSH_CONSTANT, new NXSL_Value));
568 pScript->addInstruction($1);
569 }
570 ;
571
572 SimpleStatementKeyword:
573 T_EXIT
574 {
575 $$ = new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_EXIT);
576 }
577 | T_RETURN
578 {
579 $$ = new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_RETURN);
580 }
581 | T_PRINT
582 {
583 $$ = new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_PRINT);
584 }
585 ;
586
587 PrintlnStatement:
588 T_PRINTLN Expression ';'
589 {
590 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_PUSH_CONSTANT, new NXSL_Value(_T("\n"))));
591 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_CONCAT));
592 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_PRINT));
593 }
594 | T_PRINTLN ';'
595 {
596 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_PUSH_CONSTANT, new NXSL_Value(_T("\n"))));
597 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_PRINT));
598 }
599 ;
600
601 IfStatement:
602 T_IF '(' Expression ')'
603 {
604 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_JZ, INVALID_ADDRESS));
605 }
606 IfBody
607 ;
608
609 IfBody:
610 StatementOrBlock
611 {
612 pScript->resolveLastJump(OPCODE_JZ);
613 }
614 | StatementOrBlock ElseStatement
615 {
616 pScript->resolveLastJump(OPCODE_JMP);
617 }
618 ;
619
620 ElseStatement:
621 T_ELSE
622 {
623 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_JMP, INVALID_ADDRESS));
624 pScript->resolveLastJump(OPCODE_JZ);
625 }
626 StatementOrBlock
627 ;
628
629 ForStatement:
630 T_FOR '(' Expression ';'
631 {
632 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_POP, (int)1));
633 pCompiler->pushAddr(pScript->getCodeSize());
634 }
635 Expression ';'
636 {
637 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_JZ, INVALID_ADDRESS));
638 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_JMP, INVALID_ADDRESS));
639 pCompiler->pushAddr(pScript->getCodeSize());
640 }
641 Expression ')'
642 {
643 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_POP, (int)1));
644 DWORD addrPart3 = pCompiler->popAddr();
645 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_JMP, pCompiler->popAddr()));
646 pCompiler->pushAddr(addrPart3);
647 pCompiler->newBreakLevel();
648 pScript->resolveLastJump(OPCODE_JMP);
649 }
650 StatementOrBlock
651 {
652 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_JMP, pCompiler->popAddr()));
653 pScript->resolveLastJump(OPCODE_JZ);
654 pCompiler->closeBreakLevel(pScript);
655 }
656 ;
657
658 ForEachStatement:
659 T_FOREACH '(' T_IDENTIFIER
660 {
661 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_PUSH_CONSTANT, new NXSL_Value($3)));
662 free($3);
663 }
664 ':' Expression ')'
665 {
666 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_FOREACH));
667 pCompiler->pushAddr(pScript->getCodeSize());
668 pCompiler->newBreakLevel();
669 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_NEXT));
670 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_JZ, INVALID_ADDRESS));
671 }
672 StatementOrBlock
673 {
674 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_JMP, pCompiler->popAddr()));
675 pScript->resolveLastJump(OPCODE_JZ);
676 pCompiler->closeBreakLevel(pScript);
677 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_POP, 1));
678 }
679 ;
680
681 WhileStatement:
682 T_WHILE
683 {
684 pCompiler->pushAddr(pScript->getCodeSize());
685 pCompiler->newBreakLevel();
686 }
687 '(' Expression ')'
688 {
689 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_JZ, INVALID_ADDRESS));
690 }
691 StatementOrBlock
692 {
693 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_JMP, pCompiler->popAddr()));
694 pScript->resolveLastJump(OPCODE_JZ);
695 pCompiler->closeBreakLevel(pScript);
696 }
697 ;
698
699 DoStatement:
700 T_DO
701 {
702 pCompiler->pushAddr(pScript->getCodeSize());
703 pCompiler->newBreakLevel();
704 }
705 StatementOrBlock T_WHILE '(' Expression ')' ';'
706 {
707 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(),
708 OPCODE_JNZ, pCompiler->popAddr()));
709 pCompiler->closeBreakLevel(pScript);
710 }
711 ;
712
713 SwitchStatement:
714 T_SWITCH
715 {
716 pCompiler->newBreakLevel();
717 }
718 '(' Expression ')' '{' CaseList Default '}'
719 {
720 pCompiler->closeBreakLevel(pScript);
721 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_POP, (int)1));
722 }
723 ;
724
725 CaseList:
726 Case
727 {
728 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_JMP, pScript->getCodeSize() + 3));
729 pScript->resolveLastJump(OPCODE_JZ);
730 }
731 CaseList
732 | Case
733 {
734 pScript->resolveLastJump(OPCODE_JZ);
735 }
736 ;
737
738 Case:
739 T_CASE Constant
740 {
741 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_CASE, $2));
742 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_JZ, INVALID_ADDRESS));
743 }
744 ':' StatementList
745 ;
746
747 Default:
748 T_DEFAULT ':' StatementList
749 |
750 ;
751
752 ArrayStatement:
753 T_ARRAY { pCompiler->setIdentifierOperation(OPCODE_ARRAY); } IdentifierList ';'
754 | T_GLOBAL T_ARRAY { pCompiler->setIdentifierOperation(OPCODE_GLOBAL_ARRAY); } IdentifierList ';'
755 ;
756
757 GlobalStatement:
758 T_GLOBAL GlobalVariableList ';'
759 ;
760
761 GlobalVariableList:
762 GlobalVariableDeclaration ',' GlobalVariableList
763 | GlobalVariableDeclaration
764 ;
765
766 GlobalVariableDeclaration:
767 T_IDENTIFIER
768 {
769 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_GLOBAL, $1, 0));
770 }
771 | T_IDENTIFIER '=' Expression
772 {
773 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_GLOBAL, $1, 1));
774 }
775 ;
776
777 FunctionCall:
778 FunctionName ParameterList ')'
779 {
780 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_CALL_EXTERNAL, $1, $2));
781 }
782 | FunctionName ')'
783 {
784 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_CALL_EXTERNAL, $1, 0));
785 }
786 ;
787
788 ParameterList:
789 Parameter ',' ParameterList { $$ = $3 + 1; }
790 | Parameter { $$ = 1; }
791 ;
792
793 Parameter:
794 Expression
795 | T_IDENTIFIER ':' Expression
796 {
797 pScript->addInstruction(new NXSL_Instruction(pLexer->getCurrLine(), OPCODE_NAME, $1));
798 }
799 ;
800
801 FunctionName:
802 T_IDENTIFIER '('
803 {
804 $$ = $1;
805 }
806 ;
807
808 Constant:
809 T_STRING
810 {
811 $$ = new NXSL_Value($1);
812 free($1);
813 }
814 | T_INT32
815 {
816 $$ = new NXSL_Value($1);
817 }
818 | T_UINT32
819 {
820 $$ = new NXSL_Value($1);
821 }
822 | T_INT64
823 {
824 $$ = new NXSL_Value($1);
825 }
826 | T_UINT64
827 {
828 $$ = new NXSL_Value($1);
829 }
830 | T_REAL
831 {
832 $$ = new NXSL_Value($1);
833 }
834 | T_TRUE
835 {
836 $$ = new NXSL_Value((LONG)1);
837 }
838 | T_FALSE
839 {
840 $$ = new NXSL_Value((LONG)0);
841 }
842 | T_NULL
843 {
844 $$ = new NXSL_Value;
845 }
846 ;