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

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