SpiderScript - Huge changes to introduce bytecode support
[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                 }
310                 break;
311         
312         // Control Statements
313         case TOK_RWD_IF:
314                 {
315                 tAST_Node       *cond, *true, *false = NULL;
316                 GetToken(Parser);       // eat the if
317                 
318                 SyntaxAssert(Parser, GetToken(Parser), TOK_PAREN_OPEN);
319                 cond = Parse_DoExpr0(Parser);   // Get condition
320                 SyntaxAssert(Parser, GetToken(Parser), TOK_PAREN_CLOSE);
321                 true = Parse_DoCodeBlock(Parser);
322                 if( LookAhead(Parser) == TOK_RWD_ELSE ) {
323                         GetToken(Parser);
324                         false = Parse_DoCodeBlock(Parser);
325                 }
326                 else
327                         false = AST_NewNop(Parser);
328                 ret = AST_NewIf(Parser, cond, true, false);
329                 }
330                 return ret;
331         
332         case TOK_RWD_FOR:
333                 {
334                 const char      *tag = "";
335                 tAST_Node       *init=NULL, *cond=NULL, *inc=NULL, *code;
336                 GetToken(Parser);       // Eat 'for'
337                 
338                 #if SUPPORT_BREAK_TAGS
339                 if(LookAhead(Parser) == TOK_LT)
340                 {
341                         GetToken(Parser);
342                         SyntaxAssert(Parser, GetToken(Parser), TOK_IDENT);
343                         tag = strndup(Parser->TokenStr, Parser->TokenLen);
344                         SyntaxAssert(Parser, GetToken(Parser), TOK_GT);
345                 }
346                 #endif
347                 
348                 SyntaxAssert(Parser, GetToken(Parser), TOK_PAREN_OPEN);
349                 
350                 if(LookAhead(Parser) != TOK_SEMICOLON)
351                         init = Parse_DoExpr0(Parser);
352                 
353                 SyntaxAssert(Parser, GetToken(Parser), TOK_SEMICOLON);
354                 
355                 if(LookAhead(Parser) != TOK_SEMICOLON)
356                         cond = Parse_DoExpr0(Parser);
357                 
358                 SyntaxAssert(Parser, GetToken(Parser), TOK_SEMICOLON);
359                 
360                 if(LookAhead(Parser) != TOK_PAREN_CLOSE)
361                         inc = Parse_DoExpr0(Parser);
362                 
363                 SyntaxAssert(Parser, GetToken(Parser), TOK_PAREN_CLOSE);
364                 
365                 code = Parse_DoCodeBlock(Parser);
366                 ret = AST_NewLoop(Parser, tag, init, 0, cond, inc, code);
367                 }
368                 return ret;
369         
370         case TOK_RWD_DO:
371                 {
372                 const char      *tag = "";
373                 tAST_Node       *code, *cond;
374                 GetToken(Parser);       // Eat 'do'
375                 
376                 #if SUPPORT_BREAK_TAGS
377                 if(LookAhead(Parser) == TOK_LT)
378                 {
379                         GetToken(Parser);
380                         SyntaxAssert(Parser, GetToken(Parser), TOK_IDENT);
381                         tag = strndup(Parser->TokenStr, Parser->TokenLen);
382                         SyntaxAssert(Parser, GetToken(Parser), TOK_GT);
383                 }
384                 #endif
385                 
386                 code = Parse_DoCodeBlock(Parser);
387                 SyntaxAssert( Parser, GetToken(Parser), TOK_RWD_WHILE );
388                 SyntaxAssert( Parser, GetToken(Parser), TOK_PAREN_OPEN );
389                 cond = Parse_DoExpr0(Parser);
390                 SyntaxAssert( Parser, GetToken(Parser), TOK_PAREN_CLOSE );
391                 ret = AST_NewLoop(Parser, tag, AST_NewNop(Parser), 1, cond, AST_NewNop(Parser), code);
392                 }
393                 break;
394         case TOK_RWD_WHILE:
395                 {
396                 const char      *tag = "";
397                 tAST_Node       *code, *cond;
398                 GetToken(Parser);       // Eat 'while'
399                 
400                 #if SUPPORT_BREAK_TAGS
401                 if(LookAhead(Parser) == TOK_LT)
402                 {
403                         GetToken(Parser);
404                         SyntaxAssert(Parser, GetToken(Parser), TOK_IDENT);
405                         tag = strndup(Parser->TokenStr, Parser->TokenLen);
406                         SyntaxAssert(Parser, GetToken(Parser), TOK_GT);
407                 }
408                 #endif
409                 
410                 SyntaxAssert( Parser, GetToken(Parser), TOK_PAREN_OPEN );
411                 cond = Parse_DoExpr0(Parser);
412                 SyntaxAssert( Parser, GetToken(Parser), TOK_PAREN_CLOSE );
413                 code = Parse_DoCodeBlock(Parser);
414                 ret = AST_NewLoop(Parser, tag, AST_NewNop(Parser), 0, cond, AST_NewNop(Parser), code);
415                 }
416                 return ret;
417         
418         // Define Variables
419         case TOKEN_GROUP_TYPES:
420                 {
421                          int    type;
422                         GetToken(Parser);
423                         TOKEN_GET_DATATYPE(type, Parser->Token);
424                         
425                         SyntaxAssert(Parser, GetToken(Parser), TOK_VARIABLE);
426                         
427                         ret = Parse_GetVarDef(Parser, type);
428                 }
429                 break;
430         
431         // Default
432         default:
433                 //printf("exp0\n");
434                 ret = Parse_DoExpr0(Parser);
435                 break;
436         }
437         
438         SyntaxAssert(Parser, GetToken(Parser), TOK_SEMICOLON );
439         return ret;
440 }
441
442 /**
443  * \brief Get a variable definition
444  */
445 tAST_Node *Parse_GetVarDef(tParser *Parser, int Type)
446 {
447         char    name[Parser->TokenLen];
448         tAST_Node       *ret;
449         
450         SyntaxAssert(Parser, Parser->Token, TOK_VARIABLE);
451         
452         // copy the name (trimming the $)
453         memcpy(name, Parser->TokenStr+1, Parser->TokenLen-1);
454         name[Parser->TokenLen-1] = 0;
455         // Define the variable
456         ret = AST_NewDefineVar(Parser, Type, name);
457         // Handle arrays
458         while( LookAhead(Parser) == TOK_SQUARE_OPEN )
459         {
460                 tAST_Node *node;
461                 GetToken(Parser);
462                 node = Parse_DoExpr0(Parser);
463                 if(!node) {
464                         AST_FreeNode(ret);
465                         return NULL;
466                 }
467                 AST_AppendNode(ret, node);
468                 SyntaxAssert(Parser, GetToken(Parser), TOK_SQUARE_CLOSE);
469         }
470         
471         if( LookAhead(Parser) == TOK_ASSIGN )
472         {
473                 GetToken(Parser);
474                 ret->DefVar.InitialValue = Parse_DoExpr0(Parser);
475                 if(!ret->DefVar.InitialValue) {
476                         AST_FreeNode(ret);
477                         return NULL;
478                 }
479         }
480         
481         return ret;
482 }
483
484 /**
485  * \brief Assignment Operations
486  */
487 tAST_Node *Parse_DoExpr0(tParser *Parser)
488 {
489         #define _next   Parse_DoExpr1
490         tAST_Node       *ret = _next(Parser);
491          int    cont = 1;
492
493         while( cont )
494         {
495                 // Check Assignment
496                 switch(GetToken(Parser))
497                 {
498                 case TOK_ASSIGN:
499                         ret = AST_NewAssign(Parser, NODETYPE_NOP, ret, _next(Parser));
500                         break;
501                 case TOK_ASSIGN_DIV:
502                         ret = AST_NewAssign(Parser, NODETYPE_DIVIDE, ret, _next(Parser));
503                         break;
504                 case TOK_ASSIGN_MUL:
505                         ret = AST_NewAssign(Parser, NODETYPE_MULTIPLY, ret, _next(Parser));
506                         break;
507                 case TOK_ASSIGN_PLUS:
508                         ret = AST_NewAssign(Parser, NODETYPE_ADD, ret, _next(Parser));
509                         break;
510                 case TOK_ASSIGN_MINUS:
511                         ret = AST_NewAssign(Parser, NODETYPE_SUBTRACT, ret, _next(Parser));
512                         break;
513                 default:
514                         #if DEBUG >= 2
515                         printf("Parse_DoExpr0: Parser->Token = %i\n", Parser->Token);
516                         #endif
517                         PutBack(Parser);
518                         cont = 0;
519                         break;
520                 }
521         }
522         return ret;
523         #undef _next
524 }
525
526 /**
527  * \brief Logical/Boolean Operators
528  */
529 tAST_Node *Parse_DoExpr1(tParser *Parser)
530 {
531         #define _next   Parse_DoExpr2
532         tAST_Node       *ret = _next(Parser);
533          int    cont = 1;
534
535         while( cont )
536         {
537                 switch(GetToken(Parser))
538                 {
539                 case TOK_LOGICAND:
540                         ret = AST_NewBinOp(Parser, NODETYPE_LOGICALAND, ret, _next(Parser));
541                         break;
542                 case TOK_LOGICOR:
543                         ret = AST_NewBinOp(Parser, NODETYPE_LOGICALOR, ret, _next(Parser));
544                         break;
545                 case TOK_LOGICXOR:
546                         ret = AST_NewBinOp(Parser, NODETYPE_LOGICALXOR, ret, _next(Parser));
547                         break;
548                 default:
549                         PutBack(Parser);
550                         cont = 0;
551                         break;
552                 }
553         }
554         return ret;
555         #undef _next
556 }
557
558 // --------------------
559 // Expression 2 - Comparison Operators
560 // --------------------
561 tAST_Node *Parse_DoExpr2(tParser *Parser)
562 {
563         #define _next   Parse_DoExpr3
564         tAST_Node       *ret = _next(Parser);
565          int    cont = 1;
566
567         while( cont )
568         {
569                 // Check token
570                 switch(GetToken(Parser))
571                 {
572                 case TOK_EQUALS:
573                         ret = AST_NewBinOp(Parser, NODETYPE_EQUALS, ret, _next(Parser));
574                         break;
575                 case TOK_LT:
576                         ret = AST_NewBinOp(Parser, NODETYPE_LESSTHAN, ret, _next(Parser));
577                         break;
578                 case TOK_GT:
579                         ret = AST_NewBinOp(Parser, NODETYPE_GREATERTHAN, ret, _next(Parser));
580                         break;
581                 case TOK_LTE:
582                         ret = AST_NewBinOp(Parser, NODETYPE_LESSTHANEQUAL, ret, _next(Parser));
583                         break;
584                 case TOK_GTE:
585                         ret = AST_NewBinOp(Parser, NODETYPE_GREATERTHANEQUAL, ret, _next(Parser));
586                         break;
587                 default:
588                         PutBack(Parser);
589                         cont = 0;
590                         break;
591                 }
592         }
593         return ret;
594         #undef _next
595 }
596
597 /**
598  * \brief Bitwise Operations
599  */
600 tAST_Node *Parse_DoExpr3(tParser *Parser)
601 {
602         #define _next   Parse_DoExpr4
603         tAST_Node       *ret = _next(Parser);
604          int    cont = 1;
605
606         while( cont )
607         {
608                 // Check Token
609                 switch(GetToken(Parser))
610                 {
611                 case TOK_OR:
612                         ret = AST_NewBinOp(Parser, NODETYPE_BWOR, ret, _next(Parser));
613                         break;
614                 case TOK_AND:
615                         ret = AST_NewBinOp(Parser, NODETYPE_BWAND, ret, _next(Parser));
616                         break;
617                 case TOK_XOR:
618                         ret = AST_NewBinOp(Parser, NODETYPE_BWXOR, ret, _next(Parser));
619                         break;
620                 default:
621                         PutBack(Parser);
622                         cont = 0;
623                         break;
624                 }
625         }
626         return ret;
627         #undef _next
628 }
629
630 // --------------------
631 // Expression 4 - Shifts
632 // --------------------
633 tAST_Node *Parse_DoExpr4(tParser *Parser)
634 {
635         #define _next   Parse_DoExpr5
636         tAST_Node *ret = _next(Parser);
637          int    cont = 1;
638
639         while( cont )
640         {
641                 switch(GetToken(Parser))
642                 {
643                 case TOK_SHL:
644                         ret = AST_NewBinOp(Parser, NODETYPE_BITSHIFTLEFT, ret, _next(Parser));
645                         break;
646                 case TOK_SHR:
647                         ret = AST_NewBinOp(Parser, NODETYPE_BITSHIFTRIGHT, ret, _next(Parser));
648                         break;
649                 default:
650                         PutBack(Parser);
651                         cont = 0;
652                         break;
653                 }
654         }
655
656         return ret;
657         #undef _next
658 }
659
660 // --------------------
661 // Expression 5 - Arithmatic
662 // --------------------
663 tAST_Node *Parse_DoExpr5(tParser *Parser)
664 {
665         #define _next   Parse_DoExpr6
666         tAST_Node *ret = _next(Parser);
667          int    cont = 1;
668         
669         // While loop is added to ensure that the evaluation order ends up as
670         // right to left.
671         // E.g. a + b + c + d ends up as (((a + b) + c) + d) for casting
672         while( cont )
673         {
674                 switch(GetToken(Parser))
675                 {
676                 case TOK_PLUS:
677                         ret = AST_NewBinOp(Parser, NODETYPE_ADD, ret, _next(Parser));
678                         break;
679                 case TOK_MINUS:
680                         ret = AST_NewBinOp(Parser, NODETYPE_SUBTRACT, ret, _next(Parser));
681                         break;
682                 default:
683                         PutBack(Parser);
684                         cont = 0;
685                         break;
686                 }
687         }
688
689         return ret;
690         #undef _next
691 }
692
693 // --------------------
694 // Expression 6 - Multiplcation & Division
695 // --------------------
696 tAST_Node *Parse_DoExpr6(tParser *Parser)
697 {
698         #define _next   Parse_DoExpr7
699         tAST_Node *ret = _next(Parser);
700          int    cont = 1;
701
702         while( cont )
703         {
704                 switch(GetToken(Parser))
705                 {
706                 case TOK_MUL:
707                         ret = AST_NewBinOp(Parser, NODETYPE_MULTIPLY, ret, _next(Parser));
708                         break;
709                 case TOK_DIV:
710                         ret = AST_NewBinOp(Parser, NODETYPE_DIVIDE, ret, _next(Parser));
711                         break;
712                 default:
713                         PutBack(Parser);
714                         cont = 0;
715                         break;
716                 }
717         }
718
719         return ret;
720         #undef _next
721 }
722
723 // --------------------
724 // Expression 7 - Right Unary Operations
725 // --------------------
726 tAST_Node *Parse_DoExpr7(tParser *Parser)
727 {
728         tAST_Node *ret = Parse_DoExpr8(Parser);
729         
730         switch(GetToken(Parser))
731         {
732         case TOK_INCREMENT:
733                 ret = AST_NewUniOp(Parser, NODETYPE_POSTINC, ret);
734                 break;
735         case TOK_DECREMENT:
736                 ret = AST_NewUniOp(Parser, NODETYPE_POSTDEC, ret);
737                 break;
738         default:
739                 PutBack(Parser);
740                 break;
741         }
742         return ret;
743 }
744
745 // --------------------
746 // Expression 8 - Left Unary Operations
747 // --------------------
748 tAST_Node *Parse_DoExpr8(tParser *Parser)
749 {
750         switch(GetToken(Parser))
751         {
752         case TOK_INCREMENT:
753                 return AST_NewAssign(Parser, NODETYPE_ADD, Parse_DoExpr8(Parser), AST_NewInteger(Parser, 1));
754         case TOK_DECREMENT:
755                 return AST_NewAssign(Parser, NODETYPE_SUBTRACT, Parse_DoExpr8(Parser), AST_NewInteger(Parser, 1));
756         case TOK_MINUS:
757                 return AST_NewUniOp(Parser, NODETYPE_NEGATE, Parse_DoExpr8(Parser));
758         case TOK_LOGICNOT:
759                 return AST_NewUniOp(Parser, NODETYPE_LOGICALNOT, Parse_DoExpr8(Parser));
760         case TOK_BWNOT:
761                 return AST_NewUniOp(Parser, NODETYPE_BWNOT, Parse_DoExpr8(Parser));
762         default:
763                 PutBack(Parser);
764                 return Parse_DoParen(Parser);
765         }
766 }
767
768 // --------------------
769 // 2nd Last Expression - Parens
770 // --------------------
771 tAST_Node *Parse_DoParen(tParser *Parser)
772 {
773         #if DEBUG >= 2
774         printf("Parse_DoParen: (Parser=%p)\n", Parser);
775         #endif
776         if(LookAhead(Parser) == TOK_PAREN_OPEN)
777         {
778                 tAST_Node       *ret;
779                  int    type;
780                 GetToken(Parser);
781                 
782                 // TODO: Handle casts here
783                 switch(LookAhead(Parser))
784                 {
785                 case TOKEN_GROUP_TYPES:
786                         GetToken(Parser);
787                         TOKEN_GET_DATATYPE(type, Parser->Token);
788                         SyntaxAssert(Parser, GetToken(Parser), TOK_PAREN_CLOSE);
789                         ret = AST_NewCast(Parser, type, Parse_DoParen(Parser));
790                         break;
791                 default:                
792                         ret = Parse_DoExpr0(Parser);
793                         SyntaxAssert(Parser, GetToken(Parser), TOK_PAREN_CLOSE);
794                         break;
795                 }
796                 return ret;
797         }
798         else
799                 return Parse_DoValue(Parser);
800 }
801
802 // --------------------
803 // Last Expression - Value
804 // --------------------
805 tAST_Node *Parse_DoValue(tParser *Parser)
806 {
807          int    tok = LookAhead(Parser);
808
809         #if DEBUG >= 2
810         printf("Parse_DoValue: tok = %i\n", tok);
811         #endif
812
813         switch(tok)
814         {
815         case TOK_STR:
816                 return Parse_GetString(Parser);
817         case TOK_INTEGER:
818                 return Parse_GetNumeric(Parser);
819         
820         case TOK_REAL:
821                 GetToken(Parser);
822                 return AST_NewReal( Parser, atof(Parser->TokenStr) );
823         
824         case TOK_IDENT:
825                 return Parse_GetIdent(Parser, 0);
826         case TOK_VARIABLE:
827                 return Parse_GetVariable(Parser);
828         case TOK_RWD_NULL:
829                 GetToken(Parser);
830                 return AST_NewNop(Parser);      // NODETYPE_NOP returns NULL
831         case TOK_RWD_NEW:
832                 GetToken(Parser);
833                 return Parse_GetIdent(Parser, 1);
834
835         default:
836                 fprintf(stderr, "Syntax Error: Unexpected %s on line %i, Expected TOK_T_VALUE\n",
837                         csaTOKEN_NAMES[tok], Parser->CurLine);
838                 longjmp( Parser->JmpTarget, -1 );
839         }
840 }
841
842 /**
843  * \brief Get a string
844  */
845 tAST_Node *Parse_GetString(tParser *Parser)
846 {
847         tAST_Node       *ret;
848          int    i, j;
849         GetToken( Parser );
850         
851         {
852                 char    data[ Parser->TokenLen - 2 ];
853                 j = 0;
854                 
855                 for( i = 1; i < Parser->TokenLen - 1; i++ )
856                 {
857                         if( Parser->TokenStr[i] == '\\' ) {
858                                 i ++;
859                                 switch( Parser->TokenStr[i] )
860                                 {
861                                 case 'n':       data[j++] = '\n';       break;
862                                 case 'r':       data[j++] = '\r';       break;
863                                 default:
864                                         // TODO: Octal Codes
865                                         // TODO: Error/Warning?
866                                         break;
867                                 }
868                         }
869                         else {
870                                 data[j++] = Parser->TokenStr[i];
871                         }
872                 }
873                 
874                 // TODO: Parse Escape Codes
875                 ret = AST_NewString( Parser, data, j );
876         }
877         return ret;
878 }
879
880 /**
881  * \brief Get a numeric value
882  */
883 tAST_Node *Parse_GetNumeric(tParser *Parser)
884 {
885         uint64_t        value = 0;
886         const char      *pos;
887         SyntaxAssert( Parser, GetToken( Parser ), TOK_INTEGER );
888         pos = Parser->TokenStr;
889         //printf("pos = %p, *pos = %c\n", pos, *pos);
890                 
891         if( *pos == '0' )
892         {
893                 pos ++;
894                 if(*pos == 'x') {
895                         pos ++;
896                         for( ;; pos++)
897                         {
898                                 value *= 16;
899                                 if( '0' <= *pos && *pos <= '9' ) {
900                                         value += *pos - '0';
901                                         continue;
902                                 }
903                                 if( 'A' <= *pos && *pos <= 'F' ) {
904                                         value += *pos - 'A' + 10;
905                                         continue;
906                                 }
907                                 if( 'a' <= *pos && *pos <= 'f' ) {
908                                         value += *pos - 'a' + 10;
909                                         continue;
910                                 }
911                                 break;
912                         }
913                 }
914                 else {
915                         while( '0' <= *pos && *pos <= '7' ) {
916                                 value = value*8 + *pos - '0';
917                                 pos ++;
918                         }
919                 }
920         }
921         else {
922                 while( '0' <= *pos && *pos <= '9' ) {
923                         value = value*10 + *pos - '0';
924                         pos ++;
925                 }
926         }
927         
928         return AST_NewInteger( Parser, value );
929 }
930
931 /**
932  * \brief Get a variable
933  */
934 tAST_Node *Parse_GetVariable(tParser *Parser)
935 {
936         tAST_Node       *ret;
937         SyntaxAssert( Parser, GetToken(Parser), TOK_VARIABLE );
938         {
939                 char    name[Parser->TokenLen];
940                 memcpy(name, Parser->TokenStr+1, Parser->TokenLen-1);
941                 name[Parser->TokenLen-1] = 0;
942                 ret = AST_NewVariable( Parser, name );
943                 #if DEBUG >= 2
944                 printf("Parse_GetVariable: name = '%s'\n", name);
945                 #endif
946         }
947         for(;;)
948         {
949                 GetToken(Parser);
950                 if( Parser->Token == TOK_SQUARE_OPEN )
951                 {
952                         ret = AST_NewBinOp(Parser, NODETYPE_INDEX, ret, Parse_DoExpr0(Parser));
953                         SyntaxAssert(Parser, GetToken(Parser), TOK_SQUARE_CLOSE);
954                         continue ;
955                 }
956                 if( Parser->Token == TOK_ELEMENT )
957                 {
958                         SyntaxAssert(Parser, GetToken(Parser), TOK_IDENT);
959                         // Method Call
960                         if( LookAhead(Parser) == TOK_PAREN_OPEN )
961                         {
962                                 char    name[Parser->TokenLen+1];
963                                 memcpy(name, Parser->TokenStr, Parser->TokenLen);
964                                 name[Parser->TokenLen] = 0;
965                                 ret = AST_NewMethodCall(Parser, ret, name);
966                                 GetToken(Parser);       // Eat the '('
967                                 // Read arguments
968                                 if( GetToken(Parser) != TOK_PAREN_CLOSE )
969                                 {
970                                         PutBack(Parser);
971                                         do {
972                                                 AST_AppendFunctionCallArg( ret, Parse_DoExpr0(Parser) );
973                                         } while(GetToken(Parser) == TOK_COMMA);
974                                         SyntaxAssert( Parser, Parser->Token, TOK_PAREN_CLOSE );
975                                 }
976                                 
977                         }
978                         // Attribute
979                         else
980                         {
981                                 char    name[Parser->TokenLen];
982                                 memcpy(name, Parser->TokenStr+1, Parser->TokenLen-1);
983                                 name[Parser->TokenLen-1] = 0;
984                                 ret = AST_NewClassElement(Parser, ret, name);
985                         }
986                         continue ;
987                 }
988                 
989                 break ;
990         }
991         PutBack(Parser);
992         return ret;
993 }
994
995 /**
996  * \brief Get an identifier (constant or function call)
997  */
998 tAST_Node *Parse_GetIdent(tParser *Parser, int bObjectCreate)
999 {
1000         tAST_Node       *ret = NULL;
1001         char    *name;
1002         SyntaxAssert(Parser, GetToken(Parser), TOK_IDENT );
1003         name = strndup( Parser->TokenStr, Parser->TokenLen );
1004         
1005         #if USE_SCOPE_CHAR
1006         if( GetToken(Parser) == TOK_SCOPE )
1007         {
1008                 ret = AST_NewScopeDereference( Parser, name, Parse_GetIdent(Parser, bObjectCreate) );
1009                 free(name);
1010                 return ret;
1011         }
1012         PutBack(Parser);
1013         #endif
1014         
1015         if( GetToken(Parser) == TOK_PAREN_OPEN )
1016         {
1017                 #if DEBUG >= 2
1018                 printf("Parse_GetIdent: Calling '%s'\n", name);
1019                 #endif
1020                 // Function Call
1021                 if( bObjectCreate )
1022                         ret = AST_NewCreateObject( Parser, name );
1023                 else
1024                         ret = AST_NewFunctionCall( Parser, name );
1025                 // Read arguments
1026                 if( GetToken(Parser) != TOK_PAREN_CLOSE )
1027                 {
1028                         PutBack(Parser);
1029                         do {
1030                                 #if DEBUG >= 2
1031                                 printf(" Parse_GetIdent: Argument\n");
1032                                 #endif
1033                                 AST_AppendFunctionCallArg( ret, Parse_DoExpr0(Parser) );
1034                         } while(GetToken(Parser) == TOK_COMMA);
1035                         SyntaxAssert( Parser, Parser->Token, TOK_PAREN_CLOSE );
1036                         #if DEBUG >= 2
1037                         printf(" Parse_GetIdent: All arguments parsed\n");
1038                         #endif
1039                 }
1040         }
1041         else
1042         {
1043                 // Runtime Constant / Variable (When implemented)
1044                 #if DEBUG >= 2
1045                 printf("Parse_GetIdent: Referencing '%s'\n", name);
1046                 #endif
1047                 PutBack(Parser);
1048                 if( bObjectCreate )     // Void constructor (TODO: Should this be an error?)
1049                         ret = AST_NewCreateObject( Parser, name );
1050                 else
1051                         ret = AST_NewConstant( Parser, name );
1052         }
1053         
1054         free(name);
1055         return ret;
1056 }
1057
1058
1059 void SyntaxError(tParser *Parser, int bFatal, const char *Message, ...)
1060 {
1061         va_list args;
1062         va_start(args, Message);
1063         fprintf(stderr, "%s:%i: error: ", Parser->Filename, Parser->CurLine);
1064         vfprintf(stderr, Message, args);
1065         fprintf(stderr, "\n");
1066         va_end(args);
1067         
1068         if( bFatal ) {
1069                 //longjmp(Parser->JmpTarget, -1);
1070                 Parser->ErrorHit = 1;
1071         }
1072 }
1073

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