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

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