Usermode/libspiderscript - Fixing a multitude of bugs
[tpg/acess2.git] / Usermode / Libraries / libspiderscript.so_src / parse.c
1 /*
2  * Acess2 - SpiderScript
3  * - Parser
4  */
5 #include <string.h>
6 #include <stdlib.h>
7 #include <stdio.h>
8 #include <stdarg.h>
9 #include <spiderscript.h>
10 #define WANT_TOKEN_STRINGS      1
11 #include "tokens.h"
12 #include "ast.h"
13 #include "common.h"
14
15 #define DEBUG   0
16 #define SUPPORT_BREAK_TAGS      1
17
18 // === PROTOTYPES ===
19  int    Parse_Buffer(tSpiderScript *Script, const char *Buffer, const char *Filename);
20 void    *Parse_FunctionDefinition(tSpiderScript *Script, tParser *Parser, int Type);
21 tAST_Node       *Parse_DoCodeBlock(tParser *Parser);
22 tAST_Node       *Parse_DoBlockLine(tParser *Parser);
23 tAST_Node       *Parse_GetVarDef(tParser *Parser, int Type);
24
25 tAST_Node       *Parse_DoExpr0(tParser *Parser);        // Assignment
26 tAST_Node       *Parse_DoExpr1(tParser *Parser);        // Boolean Operators
27 tAST_Node       *Parse_DoExpr2(tParser *Parser);        // Comparison Operators
28 tAST_Node       *Parse_DoExpr3(tParser *Parser);        // Bitwise Operators
29 tAST_Node       *Parse_DoExpr4(tParser *Parser);        // Bit Shifts
30 tAST_Node       *Parse_DoExpr5(tParser *Parser);        // Arithmatic
31 tAST_Node       *Parse_DoExpr6(tParser *Parser);        // Mult & Div
32 tAST_Node       *Parse_DoExpr7(tParser *Parser);        // Right Unary Operations
33 tAST_Node       *Parse_DoExpr8(tParser *Parser);        // Left Unary Operations
34
35 tAST_Node       *Parse_DoParen(tParser *Parser);        // Parenthesis (Always Last)
36 tAST_Node       *Parse_DoValue(tParser *Parser);        // Values
37
38 tAST_Node       *Parse_GetString(tParser *Parser);
39 tAST_Node       *Parse_GetNumeric(tParser *Parser);
40 tAST_Node       *Parse_GetVariable(tParser *Parser);
41 tAST_Node       *Parse_GetIdent(tParser *Parser, int bObjectCreate);
42
43 void    SyntaxAssert(tParser *Parser, int Have, int Want);
44 void    SyntaxError(tParser *Parser, int bFatal, const char *Message, ...);
45
46 #define SyntaxAssert(_parser, _have, _want) do { \
47         int have = (_have), want = (_want); \
48         if( (have) != (want) ) { \
49                 SyntaxError(Parser, 1, "Unexpected %s(%i), expecting %s(%i)\n", \
50                         csaTOKEN_NAMES[have], have, csaTOKEN_NAMES[want], want); \
51                 return NULL; \
52         } \
53 }while(0)
54
55 #define TODO(Parser, message...) do {\
56         fprintf(stderr, "TODO: "message);\
57         longjmp(Parser->JmpTarget, -1);\
58 }while(0)
59
60 // === CODE ===
61 /**
62  * \brief Parse a buffer into a syntax tree
63  */
64 int Parse_Buffer(tSpiderScript *Script, const char *Buffer, const char *Filename)
65 {
66         tParser parser = {0};
67         tParser *Parser = &parser;      //< Keeps code consistent
68         tAST_Node       *mainCode, *node;
69          int    type;
70         tScript_Function        *fcn;
71         
72         #if DEBUG >= 2
73         printf("Parse_Buffer: (Variant=%p, Buffer=%p)\n", Variant, Buffer);
74         #endif
75         
76         // Initialise parser
77         parser.LastToken = -1;
78         parser.NextToken = -1;
79         parser.CurLine = 1;
80         parser.BufStart = Buffer;
81         parser.CurPos = Buffer;
82         // hackery to do reference counting
83         parser.Filename = malloc(sizeof(int)+strlen(Filename)+1);
84         strcpy(parser.Filename + sizeof(int), Filename);
85         *(int*)(parser.Filename) = 0;   // Set reference count
86         parser.Filename += sizeof(int); // Move filename
87         parser.ErrorHit = 0;
88         
89         mainCode = AST_NewCodeBlock(&parser);
90         
91         // Give us an error fallback
92         if( setjmp( parser.JmpTarget ) != 0 )
93         {
94                 AST_FreeNode( mainCode );
95                 
96                 for(fcn = Script->Functions; fcn; )
97                 {
98                         tScript_Function        *nextFcn;
99                         
100                         AST_FreeNode( fcn->ASTFcn );
101                         
102                         nextFcn = fcn->Next;
103                         free( fcn );
104                         fcn = nextFcn;
105                 }
106                 return -1;
107         }
108         
109         // Parse the file!
110         while(Parser->Token != TOK_EOF)
111         {
112                 switch( GetToken(Parser) )
113                 {
114                 case TOK_EOF:
115                         break;
116                 
117                 // Typed variables/functions
118                 case TOKEN_GROUP_TYPES:
119                         TOKEN_GET_DATATYPE(type, Parser->Token);
120                         
121                         switch(GetToken(Parser))
122                         {
123                         // Define a function (pass on to the other function definition code)
124                         case TOK_IDENT:
125                                 PutBack(Parser);
126                                 if( Parse_FunctionDefinition(Script, Parser, type) == NULL )
127                                         longjmp(Parser->JmpTarget, -1);
128                                 break ;
129                         // Define a variable
130                         case TOK_VARIABLE:
131                                 node = Parse_GetVarDef(Parser, type);
132                                 if(!node)       longjmp(Parser->JmpTarget, -1);
133                                 
134                                 AST_AppendNode( mainCode, node );
135                                 // Can't use SyntaxAssert because that returns
136                                 if(GetToken(Parser) != TOK_SEMICOLON) {
137                                         SyntaxError(Parser, 1, "Unexpected %s, expected TOK_SEMICOLON",
138                                                 csaTOKEN_NAMES[Parser->Token]);
139                                         longjmp(Parser->JmpTarget, -1);
140                                 }
141                                 break;
142                         default:
143                                 SyntaxError(Parser, 1, "Unexpected %s, expected TOK_IDENT or TOK_VARIABLE\n",
144                                         csaTOKEN_NAMES[Parser->Token]);
145                                 break;
146                         }
147                         break;
148                 
149                 // Define a function
150                 case TOK_RWD_FUNCTION:
151                         if( !Script->Variant->bDyamicTyped ) {
152                                 SyntaxError(Parser, 1, "Dynamic functions are invalid in static mode");
153                                 longjmp(Parser->JmpTarget, -1);
154                         }
155                         
156                         type = SS_DATATYPE_DYNAMIC;
157                 
158                         if( Parse_FunctionDefinition(Script, Parser, SS_DATATYPE_DYNAMIC) == NULL )
159                                 longjmp(Parser->JmpTarget, -1);
160                 
161                         break;
162                 
163                 // Ordinary Statement
164                 default:
165                         PutBack(Parser);
166                         node = Parse_DoBlockLine(Parser);
167                         if(!node)       longjmp(Parser->JmpTarget, -1);
168                         AST_AppendNode( mainCode, node );
169                         break;
170                 }
171                 
172                 // Jump to error handler on error
173                 if(Parser->ErrorHit)
174                         longjmp(Parser->JmpTarget, -1);
175         }
176         
177         AST_AppendFunction( Script, "", SS_DATATYPE_INTEGER, NULL, mainCode );
178         
179         //printf("---- %p parsed as SpiderScript ----\n", Buffer);
180         
181         return 0;
182 }
183
184 void *Parse_FunctionDefinition(tSpiderScript *Script, tParser *Parser, int Type)
185 {
186         char    *name;
187          int    rv;
188         tAST_Node       *first_arg, *last_arg, *code;
189         
190         last_arg = (void*)&first_arg;   // HACK
191         
192         SyntaxAssert(Parser, GetToken(Parser), TOK_IDENT );
193         
194         name = strndup( Parser->TokenStr, Parser->TokenLen );
195         #if DEBUG
196         printf("DefFCN %s\n", name);
197         #endif
198         
199         // Get arguments
200         SyntaxAssert(Parser, GetToken(Parser), TOK_PAREN_OPEN );
201         if( LookAhead(Parser) != TOK_PAREN_CLOSE )
202         {
203                 do {
204                          int    type = SS_DATATYPE_DYNAMIC;
205                         GetToken(Parser);
206                         // Non dynamic typed variants must use data types
207                         if( !Script->Variant->bDyamicTyped ) {
208                                 TOKEN_GET_DATATYPE(type, Parser->Token);
209                                 GetToken(Parser);
210                         }
211                         last_arg->NextSibling = Parse_GetVarDef(Parser, type);
212                         last_arg = last_arg->NextSibling;
213                         last_arg->NextSibling = NULL;
214                 }       while(GetToken(Parser) == TOK_COMMA);
215         }
216         else
217                 GetToken(Parser);
218         SyntaxAssert(Parser, Parser->Token, TOK_PAREN_CLOSE );
219
220         code = Parse_DoCodeBlock(Parser);
221
222         rv = AST_AppendFunction( Script, name, Type, first_arg, code );
223
224         // Clean up argument definition nodes
225         {
226                 tAST_Node       *nextarg;
227                 for( ; first_arg; first_arg = nextarg )
228                 {
229                         nextarg = first_arg->NextSibling;
230                         AST_FreeNode(first_arg);
231                 }
232         }
233
234         free(name);
235         
236         return rv == 0 ? (void*)1 : NULL;
237 }
238
239 /**
240  * \brief Parse a block of code surrounded by { }
241  */
242 tAST_Node *Parse_DoCodeBlock(tParser *Parser)
243 {
244         tAST_Node       *ret;
245         
246         // Check if we are being called for a one-liner
247         if( GetToken(Parser) != TOK_BRACE_OPEN ) {
248                 PutBack(Parser);
249                 return Parse_DoBlockLine(Parser);
250         }
251         
252         ret = AST_NewCodeBlock(Parser);
253         
254         while( LookAhead(Parser) != TOK_BRACE_CLOSE )
255         {
256                 tAST_Node       *node = Parse_DoBlockLine(Parser);
257                 if(!node) {
258                         AST_FreeNode(ret);
259                         return NULL;
260                 }
261                 AST_AppendNode( ret, node );
262         }
263         GetToken(Parser);       // Omnomnom
264         return ret;
265 }
266
267 /**
268  * \brief Parse a line in a block
269  */
270 tAST_Node *Parse_DoBlockLine(tParser *Parser)
271 {
272         tAST_Node       *ret;
273         
274         //printf("Parse_DoBlockLine: Line %i\n", Parser->CurLine);
275         
276         switch(LookAhead(Parser))
277         {
278         // New block
279         case TOK_BRACE_OPEN:
280                 return Parse_DoCodeBlock(Parser);
281         
282         // Empty statement
283         case TOK_SEMICOLON:
284                 GetToken(Parser);
285                 return NULL;
286         
287         // Return from a method
288         case TOK_RWD_RETURN:
289                 GetToken(Parser);
290                 ret = AST_NewUniOp(Parser, NODETYPE_RETURN, Parse_DoExpr0(Parser));
291                 break;
292         
293         // Break / Continue (end a loop / go to next iteration)
294         case TOK_RWD_CONTINUE:
295         case TOK_RWD_BREAK:
296                 {
297                  int    tok;
298                 char    *ident = NULL;
299                 tok = GetToken(Parser);
300                 // Get the number of nesting levels to break
301                 if(LookAhead(Parser) == TOK_IDENT)
302                 {
303                         GetToken(Parser);
304                         ident = strndup(Parser->TokenStr, Parser->TokenLen);
305                 }
306                 // Get the action
307                 switch(tok)
308                 {
309                 case TOK_RWD_BREAK:     ret = AST_NewBreakout(Parser, NODETYPE_BREAK, ident);   break;
310                 case TOK_RWD_CONTINUE:  ret = AST_NewBreakout(Parser, NODETYPE_CONTINUE, ident);        break;
311                 default:
312                         SyntaxError(Parser, 1, "BUG Unhandled break/continue (%s)",
313                                 csaTOKEN_NAMES[tok]);
314                         return NULL;
315                 }
316                 if(ident)       free(ident);
317                 }
318                 break;
319         
320         // Control Statements
321         case TOK_RWD_IF:
322                 {
323                 tAST_Node       *cond, *true, *false = NULL;
324                 GetToken(Parser);       // eat the if
325                 
326                 SyntaxAssert(Parser, GetToken(Parser), TOK_PAREN_OPEN);
327                 cond = Parse_DoExpr0(Parser);   // Get condition
328                 SyntaxAssert(Parser, GetToken(Parser), TOK_PAREN_CLOSE);
329                 true = Parse_DoCodeBlock(Parser);
330                 if( LookAhead(Parser) == TOK_RWD_ELSE ) {
331                         GetToken(Parser);
332                         false = Parse_DoCodeBlock(Parser);
333                 }
334                 else
335                         false = AST_NewNop(Parser);
336                 ret = AST_NewIf(Parser, cond, true, false);
337                 }
338                 return ret;
339         
340         case TOK_RWD_FOR:
341                 {
342                 char    *tag = NULL;
343                 tAST_Node       *init=NULL, *cond=NULL, *inc=NULL, *code;
344                 GetToken(Parser);       // Eat 'for'
345                 
346                 #if SUPPORT_BREAK_TAGS
347                 if(LookAhead(Parser) == TOK_LT)
348                 {
349                         GetToken(Parser);
350                         SyntaxAssert(Parser, GetToken(Parser), TOK_IDENT);
351                         tag = strndup(Parser->TokenStr, Parser->TokenLen);
352                         SyntaxAssert(Parser, GetToken(Parser), TOK_GT);
353                 }
354                 #endif
355                 
356                 SyntaxAssert(Parser, GetToken(Parser), TOK_PAREN_OPEN);
357                 
358                 if(LookAhead(Parser) != TOK_SEMICOLON)
359                         init = Parse_DoExpr0(Parser);
360                 
361                 SyntaxAssert(Parser, GetToken(Parser), TOK_SEMICOLON);
362                 
363                 if(LookAhead(Parser) != TOK_SEMICOLON)
364                         cond = Parse_DoExpr0(Parser);
365                 
366                 SyntaxAssert(Parser, GetToken(Parser), TOK_SEMICOLON);
367                 
368                 if(LookAhead(Parser) != TOK_PAREN_CLOSE)
369                         inc = Parse_DoExpr0(Parser);
370                 
371                 SyntaxAssert(Parser, GetToken(Parser), TOK_PAREN_CLOSE);
372                 
373                 code = Parse_DoCodeBlock(Parser);
374                 ret = AST_NewLoop(Parser, tag, init, 0, cond, inc, code);
375                 if(tag) free(tag);
376                 }
377                 return ret;
378         
379         case TOK_RWD_DO:
380                 {
381                 const char      *tag = "";
382                 tAST_Node       *code, *cond;
383                 GetToken(Parser);       // Eat 'do'
384                 
385                 #if SUPPORT_BREAK_TAGS
386                 if(LookAhead(Parser) == TOK_LT)
387                 {
388                         GetToken(Parser);
389                         SyntaxAssert(Parser, GetToken(Parser), TOK_IDENT);
390                         tag = strndup(Parser->TokenStr, Parser->TokenLen);
391                         SyntaxAssert(Parser, GetToken(Parser), TOK_GT);
392                 }
393                 #endif
394                 
395                 code = Parse_DoCodeBlock(Parser);
396                 SyntaxAssert( Parser, GetToken(Parser), TOK_RWD_WHILE );
397                 SyntaxAssert( Parser, GetToken(Parser), TOK_PAREN_OPEN );
398                 cond = Parse_DoExpr0(Parser);
399                 SyntaxAssert( Parser, GetToken(Parser), TOK_PAREN_CLOSE );
400                 ret = AST_NewLoop(Parser, tag, AST_NewNop(Parser), 1, cond, AST_NewNop(Parser), code);
401                 }
402                 break;
403         case TOK_RWD_WHILE:
404                 {
405                 const char      *tag = "";
406                 tAST_Node       *code, *cond;
407                 GetToken(Parser);       // Eat 'while'
408                 
409                 #if SUPPORT_BREAK_TAGS
410                 if(LookAhead(Parser) == TOK_LT)
411                 {
412                         GetToken(Parser);
413                         SyntaxAssert(Parser, GetToken(Parser), TOK_IDENT);
414                         tag = strndup(Parser->TokenStr, Parser->TokenLen);
415                         SyntaxAssert(Parser, GetToken(Parser), TOK_GT);
416                 }
417                 #endif
418                 
419                 SyntaxAssert( Parser, GetToken(Parser), TOK_PAREN_OPEN );
420                 cond = Parse_DoExpr0(Parser);
421                 SyntaxAssert( Parser, GetToken(Parser), TOK_PAREN_CLOSE );
422                 code = Parse_DoCodeBlock(Parser);
423                 ret = AST_NewLoop(Parser, tag, AST_NewNop(Parser), 0, cond, AST_NewNop(Parser), code);
424                 }
425                 return ret;
426         
427         // Define Variables
428         case TOKEN_GROUP_TYPES:
429                 {
430                          int    type;
431                         GetToken(Parser);
432                         TOKEN_GET_DATATYPE(type, Parser->Token);
433                         
434                         SyntaxAssert(Parser, GetToken(Parser), TOK_VARIABLE);
435                         
436                         ret = Parse_GetVarDef(Parser, type);
437                 }
438                 break;
439         
440         // Default
441         default:
442                 //printf("exp0\n");
443                 ret = Parse_DoExpr0(Parser);
444                 break;
445         }
446         
447         SyntaxAssert(Parser, GetToken(Parser), TOK_SEMICOLON );
448         return ret;
449 }
450
451 /**
452  * \brief Get a variable definition
453  */
454 tAST_Node *Parse_GetVarDef(tParser *Parser, int Type)
455 {
456         char    name[Parser->TokenLen];
457         tAST_Node       *ret;
458         
459         SyntaxAssert(Parser, Parser->Token, TOK_VARIABLE);
460         
461         // copy the name (trimming the $)
462         memcpy(name, Parser->TokenStr+1, Parser->TokenLen-1);
463         name[Parser->TokenLen-1] = 0;
464         // Define the variable
465         ret = AST_NewDefineVar(Parser, Type, name);
466         // Handle arrays
467         while( LookAhead(Parser) == TOK_SQUARE_OPEN )
468         {
469                 tAST_Node *node;
470                 GetToken(Parser);
471                 node = Parse_DoExpr0(Parser);
472                 if(!node) {
473                         AST_FreeNode(ret);
474                         return NULL;
475                 }
476                 AST_AppendNode(ret, node);
477                 SyntaxAssert(Parser, GetToken(Parser), TOK_SQUARE_CLOSE);
478         }
479         
480         if( LookAhead(Parser) == TOK_ASSIGN )
481         {
482                 GetToken(Parser);
483                 ret->DefVar.InitialValue = Parse_DoExpr0(Parser);
484                 if(!ret->DefVar.InitialValue) {
485                         AST_FreeNode(ret);
486                         return NULL;
487                 }
488         }
489         
490         return ret;
491 }
492
493 /**
494  * \brief Assignment Operations
495  */
496 tAST_Node *Parse_DoExpr0(tParser *Parser)
497 {
498         #define _next   Parse_DoExpr1
499         tAST_Node       *ret = _next(Parser);
500          int    cont = 1;
501
502         while( cont )
503         {
504                 // Check Assignment
505                 switch(GetToken(Parser))
506                 {
507                 case TOK_ASSIGN:
508                         ret = AST_NewAssign(Parser, NODETYPE_NOP, ret, _next(Parser));
509                         break;
510                 case TOK_ASSIGN_DIV:
511                         ret = AST_NewAssign(Parser, NODETYPE_DIVIDE, ret, _next(Parser));
512                         break;
513                 case TOK_ASSIGN_MUL:
514                         ret = AST_NewAssign(Parser, NODETYPE_MULTIPLY, ret, _next(Parser));
515                         break;
516                 case TOK_ASSIGN_PLUS:
517                         ret = AST_NewAssign(Parser, NODETYPE_ADD, ret, _next(Parser));
518                         break;
519                 case TOK_ASSIGN_MINUS:
520                         ret = AST_NewAssign(Parser, NODETYPE_SUBTRACT, ret, _next(Parser));
521                         break;
522                 default:
523                         #if DEBUG >= 2
524                         printf("Parse_DoExpr0: Parser->Token = %i\n", Parser->Token);
525                         #endif
526                         PutBack(Parser);
527                         cont = 0;
528                         break;
529                 }
530         }
531         return ret;
532         #undef _next
533 }
534
535 /**
536  * \brief Logical/Boolean Operators
537  */
538 tAST_Node *Parse_DoExpr1(tParser *Parser)
539 {
540         #define _next   Parse_DoExpr2
541         tAST_Node       *ret = _next(Parser);
542          int    cont = 1;
543
544         while( cont )
545         {
546                 switch(GetToken(Parser))
547                 {
548                 case TOK_LOGICAND:
549                         ret = AST_NewBinOp(Parser, NODETYPE_LOGICALAND, ret, _next(Parser));
550                         break;
551                 case TOK_LOGICOR:
552                         ret = AST_NewBinOp(Parser, NODETYPE_LOGICALOR, ret, _next(Parser));
553                         break;
554                 case TOK_LOGICXOR:
555                         ret = AST_NewBinOp(Parser, NODETYPE_LOGICALXOR, ret, _next(Parser));
556                         break;
557                 default:
558                         PutBack(Parser);
559                         cont = 0;
560                         break;
561                 }
562         }
563         return ret;
564         #undef _next
565 }
566
567 // --------------------
568 // Expression 2 - Comparison Operators
569 // --------------------
570 tAST_Node *Parse_DoExpr2(tParser *Parser)
571 {
572         #define _next   Parse_DoExpr3
573         tAST_Node       *ret = _next(Parser);
574          int    cont = 1;
575
576         while( cont )
577         {
578                 // Check token
579                 switch(GetToken(Parser))
580                 {
581                 case TOK_EQUALS:
582                         ret = AST_NewBinOp(Parser, NODETYPE_EQUALS, ret, _next(Parser));
583                         break;
584                 case TOK_NOTEQUALS:
585                         ret = AST_NewBinOp(Parser, NODETYPE_NOTEQUALS, ret, _next(Parser));
586                         break;
587                 case TOK_LT:
588                         ret = AST_NewBinOp(Parser, NODETYPE_LESSTHAN, ret, _next(Parser));
589                         break;
590                 case TOK_GT:
591                         ret = AST_NewBinOp(Parser, NODETYPE_GREATERTHAN, ret, _next(Parser));
592                         break;
593                 case TOK_LTE:
594                         ret = AST_NewBinOp(Parser, NODETYPE_LESSTHANEQUAL, ret, _next(Parser));
595                         break;
596                 case TOK_GTE:
597                         ret = AST_NewBinOp(Parser, NODETYPE_GREATERTHANEQUAL, ret, _next(Parser));
598                         break;
599                 default:
600                         PutBack(Parser);
601                         cont = 0;
602                         break;
603                 }
604         }
605         return ret;
606         #undef _next
607 }
608
609 /**
610  * \brief Bitwise Operations
611  */
612 tAST_Node *Parse_DoExpr3(tParser *Parser)
613 {
614         #define _next   Parse_DoExpr4
615         tAST_Node       *ret = _next(Parser);
616          int    cont = 1;
617
618         while( cont )
619         {
620                 // Check Token
621                 switch(GetToken(Parser))
622                 {
623                 case TOK_OR:
624                         ret = AST_NewBinOp(Parser, NODETYPE_BWOR, ret, _next(Parser));
625                         break;
626                 case TOK_AND:
627                         ret = AST_NewBinOp(Parser, NODETYPE_BWAND, ret, _next(Parser));
628                         break;
629                 case TOK_XOR:
630                         ret = AST_NewBinOp(Parser, NODETYPE_BWXOR, ret, _next(Parser));
631                         break;
632                 default:
633                         PutBack(Parser);
634                         cont = 0;
635                         break;
636                 }
637         }
638         return ret;
639         #undef _next
640 }
641
642 // --------------------
643 // Expression 4 - Shifts
644 // --------------------
645 tAST_Node *Parse_DoExpr4(tParser *Parser)
646 {
647         #define _next   Parse_DoExpr5
648         tAST_Node *ret = _next(Parser);
649          int    cont = 1;
650
651         while( cont )
652         {
653                 switch(GetToken(Parser))
654                 {
655                 case TOK_SHL:
656                         ret = AST_NewBinOp(Parser, NODETYPE_BITSHIFTLEFT, ret, _next(Parser));
657                         break;
658                 case TOK_SHR:
659                         ret = AST_NewBinOp(Parser, NODETYPE_BITSHIFTRIGHT, ret, _next(Parser));
660                         break;
661                 default:
662                         PutBack(Parser);
663                         cont = 0;
664                         break;
665                 }
666         }
667
668         return ret;
669         #undef _next
670 }
671
672 // --------------------
673 // Expression 5 - Arithmatic
674 // --------------------
675 tAST_Node *Parse_DoExpr5(tParser *Parser)
676 {
677         #define _next   Parse_DoExpr6
678         tAST_Node *ret = _next(Parser);
679          int    cont = 1;
680         
681         // While loop is added to ensure that the evaluation order ends up as
682         // right to left.
683         // E.g. a + b + c + d ends up as (((a + b) + c) + d) for casting
684         while( cont )
685         {
686                 switch(GetToken(Parser))
687                 {
688                 case TOK_PLUS:
689                         ret = AST_NewBinOp(Parser, NODETYPE_ADD, ret, _next(Parser));
690                         break;
691                 case TOK_MINUS:
692                         ret = AST_NewBinOp(Parser, NODETYPE_SUBTRACT, ret, _next(Parser));
693                         break;
694                 default:
695                         PutBack(Parser);
696                         cont = 0;
697                         break;
698                 }
699         }
700
701         return ret;
702         #undef _next
703 }
704
705 // --------------------
706 // Expression 6 - Multiplcation & Division
707 // --------------------
708 tAST_Node *Parse_DoExpr6(tParser *Parser)
709 {
710         #define _next   Parse_DoExpr7
711         tAST_Node *ret = _next(Parser);
712          int    cont = 1;
713
714         while( cont )
715         {
716                 switch(GetToken(Parser))
717                 {
718                 case TOK_MUL:
719                         ret = AST_NewBinOp(Parser, NODETYPE_MULTIPLY, ret, _next(Parser));
720                         break;
721                 case TOK_DIV:
722                         ret = AST_NewBinOp(Parser, NODETYPE_DIVIDE, ret, _next(Parser));
723                         break;
724                 default:
725                         PutBack(Parser);
726                         cont = 0;
727                         break;
728                 }
729         }
730
731         return ret;
732         #undef _next
733 }
734
735 // --------------------
736 // Expression 7 - Right Unary Operations
737 // --------------------
738 tAST_Node *Parse_DoExpr7(tParser *Parser)
739 {
740         tAST_Node *ret = Parse_DoExpr8(Parser);
741         
742         switch(GetToken(Parser))
743         {
744         case TOK_INCREMENT:
745                 ret = AST_NewUniOp(Parser, NODETYPE_POSTINC, ret);
746                 break;
747         case TOK_DECREMENT:
748                 ret = AST_NewUniOp(Parser, NODETYPE_POSTDEC, ret);
749                 break;
750         default:
751                 PutBack(Parser);
752                 break;
753         }
754         return ret;
755 }
756
757 // --------------------
758 // Expression 8 - Left Unary Operations
759 // --------------------
760 tAST_Node *Parse_DoExpr8(tParser *Parser)
761 {
762         switch(GetToken(Parser))
763         {
764         case TOK_INCREMENT:
765                 return AST_NewAssign(Parser, NODETYPE_ADD, Parse_DoExpr8(Parser), AST_NewInteger(Parser, 1));
766         case TOK_DECREMENT:
767                 return AST_NewAssign(Parser, NODETYPE_SUBTRACT, Parse_DoExpr8(Parser), AST_NewInteger(Parser, 1));
768         case TOK_MINUS:
769                 return AST_NewUniOp(Parser, NODETYPE_NEGATE, Parse_DoExpr8(Parser));
770         case TOK_LOGICNOT:
771                 return AST_NewUniOp(Parser, NODETYPE_LOGICALNOT, Parse_DoExpr8(Parser));
772         case TOK_BWNOT:
773                 return AST_NewUniOp(Parser, NODETYPE_BWNOT, Parse_DoExpr8(Parser));
774         default:
775                 PutBack(Parser);
776                 return Parse_DoParen(Parser);
777         }
778 }
779
780 // --------------------
781 // 2nd Last Expression - Parens
782 // --------------------
783 tAST_Node *Parse_DoParen(tParser *Parser)
784 {
785         #if DEBUG >= 2
786         printf("Parse_DoParen: (Parser=%p)\n", Parser);
787         #endif
788         if(LookAhead(Parser) == TOK_PAREN_OPEN)
789         {
790                 tAST_Node       *ret;
791                  int    type;
792                 GetToken(Parser);
793                 
794                 // TODO: Handle casts here
795                 switch(LookAhead(Parser))
796                 {
797                 case TOKEN_GROUP_TYPES:
798                         GetToken(Parser);
799                         TOKEN_GET_DATATYPE(type, Parser->Token);
800                         SyntaxAssert(Parser, GetToken(Parser), TOK_PAREN_CLOSE);
801                         ret = AST_NewCast(Parser, type, Parse_DoParen(Parser));
802                         break;
803                 default:                
804                         ret = Parse_DoExpr0(Parser);
805                         SyntaxAssert(Parser, GetToken(Parser), TOK_PAREN_CLOSE);
806                         break;
807                 }
808                 return ret;
809         }
810         else
811                 return Parse_DoValue(Parser);
812 }
813
814 // --------------------
815 // Last Expression - Value
816 // --------------------
817 tAST_Node *Parse_DoValue(tParser *Parser)
818 {
819          int    tok = LookAhead(Parser);
820
821         #if DEBUG >= 2
822         printf("Parse_DoValue: tok = %i\n", tok);
823         #endif
824
825         switch(tok)
826         {
827         case TOK_STR:
828                 return Parse_GetString(Parser);
829         case TOK_INTEGER:
830                 return Parse_GetNumeric(Parser);
831         
832         case TOK_REAL:
833                 GetToken(Parser);
834                 return AST_NewReal( Parser, atof(Parser->TokenStr) );
835         
836         case TOK_IDENT:
837                 return Parse_GetIdent(Parser, 0);
838         case TOK_VARIABLE:
839                 return Parse_GetVariable(Parser);
840         case TOK_RWD_NULL:
841                 GetToken(Parser);
842                 return AST_NewNop(Parser);      // NODETYPE_NOP returns NULL
843         case TOK_RWD_NEW:
844                 GetToken(Parser);
845                 return Parse_GetIdent(Parser, 1);
846
847         default:
848                 fprintf(stderr, "Syntax Error: Unexpected %s on line %i, Expected TOK_T_VALUE\n",
849                         csaTOKEN_NAMES[tok], Parser->CurLine);
850                 longjmp( Parser->JmpTarget, -1 );
851         }
852 }
853
854 /**
855  * \brief Get a string
856  */
857 tAST_Node *Parse_GetString(tParser *Parser)
858 {
859         tAST_Node       *ret;
860          int    i, j;
861         GetToken( Parser );
862         
863         {
864                 char    data[ Parser->TokenLen - 2 ];
865                 j = 0;
866                 
867                 for( i = 1; i < Parser->TokenLen - 1; i++ )
868                 {
869                         if( Parser->TokenStr[i] == '\\' ) {
870                                 i ++;
871                                 switch( Parser->TokenStr[i] )
872                                 {
873                                 case 'n':       data[j++] = '\n';       break;
874                                 case 'r':       data[j++] = '\r';       break;
875                                 default:
876                                         // TODO: Octal Codes
877                                         // TODO: Error/Warning?
878                                         break;
879                                 }
880                         }
881                         else {
882                                 data[j++] = Parser->TokenStr[i];
883                         }
884                 }
885                 
886                 // TODO: Parse Escape Codes
887                 ret = AST_NewString( Parser, data, j );
888         }
889         return ret;
890 }
891
892 /**
893  * \brief Get a numeric value
894  */
895 tAST_Node *Parse_GetNumeric(tParser *Parser)
896 {
897         uint64_t        value = 0;
898         const char      *pos;
899         SyntaxAssert( Parser, GetToken( Parser ), TOK_INTEGER );
900         pos = Parser->TokenStr;
901         //printf("pos = %p, *pos = %c\n", pos, *pos);
902                 
903         if( *pos == '0' )
904         {
905                 pos ++;
906                 if(*pos == 'x') {
907                         pos ++;
908                         for( ;; pos++)
909                         {
910                                 value *= 16;
911                                 if( '0' <= *pos && *pos <= '9' ) {
912                                         value += *pos - '0';
913                                         continue;
914                                 }
915                                 if( 'A' <= *pos && *pos <= 'F' ) {
916                                         value += *pos - 'A' + 10;
917                                         continue;
918                                 }
919                                 if( 'a' <= *pos && *pos <= 'f' ) {
920                                         value += *pos - 'a' + 10;
921                                         continue;
922                                 }
923                                 break;
924                         }
925                 }
926                 else {
927                         while( '0' <= *pos && *pos <= '7' ) {
928                                 value = value*8 + *pos - '0';
929                                 pos ++;
930                         }
931                 }
932         }
933         else {
934                 while( '0' <= *pos && *pos <= '9' ) {
935                         value = value*10 + *pos - '0';
936                         pos ++;
937                 }
938         }
939         
940         return AST_NewInteger( Parser, value );
941 }
942
943 /**
944  * \brief Get a variable
945  */
946 tAST_Node *Parse_GetVariable(tParser *Parser)
947 {
948         tAST_Node       *ret;
949         SyntaxAssert( Parser, GetToken(Parser), TOK_VARIABLE );
950         {
951                 char    name[Parser->TokenLen];
952                 memcpy(name, Parser->TokenStr+1, Parser->TokenLen-1);
953                 name[Parser->TokenLen-1] = 0;
954                 ret = AST_NewVariable( Parser, name );
955                 #if DEBUG >= 2
956                 printf("Parse_GetVariable: name = '%s'\n", name);
957                 #endif
958         }
959         for(;;)
960         {
961                 GetToken(Parser);
962                 if( Parser->Token == TOK_SQUARE_OPEN )
963                 {
964                         ret = AST_NewBinOp(Parser, NODETYPE_INDEX, ret, Parse_DoExpr0(Parser));
965                         SyntaxAssert(Parser, GetToken(Parser), TOK_SQUARE_CLOSE);
966                         continue ;
967                 }
968                 if( Parser->Token == TOK_ELEMENT )
969                 {
970                         SyntaxAssert(Parser, GetToken(Parser), TOK_IDENT);
971                         // Method Call
972                         if( LookAhead(Parser) == TOK_PAREN_OPEN )
973                         {
974                                 char    name[Parser->TokenLen+1];
975                                 memcpy(name, Parser->TokenStr, Parser->TokenLen);
976                                 name[Parser->TokenLen] = 0;
977                                 ret = AST_NewMethodCall(Parser, ret, name);
978                                 GetToken(Parser);       // Eat the '('
979                                 // Read arguments
980                                 if( GetToken(Parser) != TOK_PAREN_CLOSE )
981                                 {
982                                         PutBack(Parser);
983                                         do {
984                                                 AST_AppendFunctionCallArg( ret, Parse_DoExpr0(Parser) );
985                                         } while(GetToken(Parser) == TOK_COMMA);
986                                         SyntaxAssert( Parser, Parser->Token, TOK_PAREN_CLOSE );
987                                 }
988                                 
989                         }
990                         // Attribute
991                         else
992                         {
993                                 char    name[Parser->TokenLen];
994                                 memcpy(name, Parser->TokenStr+1, Parser->TokenLen-1);
995                                 name[Parser->TokenLen-1] = 0;
996                                 ret = AST_NewClassElement(Parser, ret, name);
997                         }
998                         continue ;
999                 }
1000                 
1001                 break ;
1002         }
1003         PutBack(Parser);
1004         return ret;
1005 }
1006
1007 /**
1008  * \brief Get an identifier (constant or function call)
1009  */
1010 tAST_Node *Parse_GetIdent(tParser *Parser, int bObjectCreate)
1011 {
1012         tAST_Node       *ret = NULL;
1013         char    *name;
1014         SyntaxAssert(Parser, GetToken(Parser), TOK_IDENT );
1015         name = strndup( Parser->TokenStr, Parser->TokenLen );
1016         
1017         #if USE_SCOPE_CHAR
1018         if( GetToken(Parser) == TOK_SCOPE )
1019         {
1020                 ret = AST_NewScopeDereference( Parser, name, Parse_GetIdent(Parser, bObjectCreate) );
1021                 free(name);
1022                 return ret;
1023         }
1024         PutBack(Parser);
1025         #endif
1026         
1027         if( GetToken(Parser) == TOK_PAREN_OPEN )
1028         {
1029                 #if DEBUG >= 2
1030                 printf("Parse_GetIdent: Calling '%s'\n", name);
1031                 #endif
1032                 // Function Call
1033                 if( bObjectCreate )
1034                         ret = AST_NewCreateObject( Parser, name );
1035                 else
1036                         ret = AST_NewFunctionCall( Parser, name );
1037                 // Read arguments
1038                 if( GetToken(Parser) != TOK_PAREN_CLOSE )
1039                 {
1040                         PutBack(Parser);
1041                         do {
1042                                 #if DEBUG >= 2
1043                                 printf(" Parse_GetIdent: Argument\n");
1044                                 #endif
1045                                 AST_AppendFunctionCallArg( ret, Parse_DoExpr0(Parser) );
1046                         } while(GetToken(Parser) == TOK_COMMA);
1047                         SyntaxAssert( Parser, Parser->Token, TOK_PAREN_CLOSE );
1048                         #if DEBUG >= 2
1049                         printf(" Parse_GetIdent: All arguments parsed\n");
1050                         #endif
1051                 }
1052         }
1053         else
1054         {
1055                 // Runtime Constant / Variable (When implemented)
1056                 #if DEBUG >= 2
1057                 printf("Parse_GetIdent: Referencing '%s'\n", name);
1058                 #endif
1059                 PutBack(Parser);
1060                 if( bObjectCreate )     // Void constructor (TODO: Should this be an error?)
1061                         ret = AST_NewCreateObject( Parser, name );
1062                 else
1063                         ret = AST_NewConstant( Parser, name );
1064         }
1065         
1066         free(name);
1067         return ret;
1068 }
1069
1070
1071 void SyntaxError(tParser *Parser, int bFatal, const char *Message, ...)
1072 {
1073         va_list args;
1074         va_start(args, Message);
1075         fprintf(stderr, "%s:%i: error: ", Parser->Filename, Parser->CurLine);
1076         vfprintf(stderr, Message, args);
1077         fprintf(stderr, "\n");
1078         va_end(args);
1079         
1080         if( bFatal ) {
1081                 //longjmp(Parser->JmpTarget, -1);
1082                 Parser->ErrorHit = 1;
1083         }
1084 }
1085

UCC git Repository :: git.ucc.asn.au