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

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