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

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