SpiderScript: String Casts, Escape Codes, Size for Opaque data types
[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 <spiderscript.h>
9 #define WANT_TOKEN_STRINGS      1
10 #include "tokens.h"
11 #include "ast.h"
12
13 #define DEBUG   0
14
15 // === PROTOTYPES ===
16 tAST_Script     *Parse_Buffer(tSpiderVariant *Variant, char *Buffer);
17 tAST_Node       *Parse_DoCodeBlock(tParser *Parser);
18 tAST_Node       *Parse_DoBlockLine(tParser *Parser);
19 tAST_Node       *Parse_GetVarDef(tParser *Parser, int Type);
20
21 tAST_Node       *Parse_DoExpr0(tParser *Parser);        // Assignment
22 tAST_Node       *Parse_DoExpr1(tParser *Parser);        // Boolean Operators
23 tAST_Node       *Parse_DoExpr2(tParser *Parser);        // Comparison Operators
24 tAST_Node       *Parse_DoExpr3(tParser *Parser);        // Bitwise Operators
25 tAST_Node       *Parse_DoExpr4(tParser *Parser);        // Bit Shifts
26 tAST_Node       *Parse_DoExpr5(tParser *Parser);        // Arithmatic
27 tAST_Node       *Parse_DoExpr6(tParser *Parser);        // Mult & Div
28
29 tAST_Node       *Parse_DoParen(tParser *Parser);        // Parenthesis (Always Last)
30 tAST_Node       *Parse_DoValue(tParser *Parser);        // Values
31
32 tAST_Node       *Parse_GetString(tParser *Parser);
33 tAST_Node       *Parse_GetNumeric(tParser *Parser);
34 tAST_Node       *Parse_GetVariable(tParser *Parser);
35 tAST_Node       *Parse_GetIdent(tParser *Parser);
36
37 void    SyntaxAssert(tParser *Parser, int Have, int Want);
38
39 #define TODO(Parser, message...) do {\
40         fprintf(stderr, "TODO: "message);\
41         longjmp(Parser->JmpTarget, -1);\
42 }while(0)
43
44 // === CODE ===
45 /**
46  * \brief Parse a buffer into a syntax tree
47  */
48 tAST_Script     *Parse_Buffer(tSpiderVariant *Variant, char *Buffer)
49 {
50         tParser parser = {0};
51         tParser *Parser = &parser;      //< Keeps code consitent
52         tAST_Script     *ret;
53         tAST_Node       *mainCode;
54         char    *name;
55         tAST_Function   *fcn;
56          int    type;
57         
58         #if DEBUG >= 2
59         printf("Parse_Buffer: (Variant=%p, Buffer=%p)\n", Variant, Buffer);
60         #endif
61         
62         // Initialise parser
63         parser.LastToken = -1;
64         parser.NextToken = -1;
65         parser.CurLine = 1;
66         parser.BufStart = Buffer;
67         parser.CurPos = Buffer;
68         
69         ret = AST_NewScript();
70         mainCode = AST_NewCodeBlock();
71         
72         // Give us an error fallback
73         if( setjmp( parser.JmpTarget ) != 0 )
74         {
75                 AST_FreeNode( mainCode );
76                 return NULL;
77         }
78         
79         // Parse the file!
80         while(Parser->Token != TOK_EOF)
81         {
82                 switch( GetToken(Parser) )
83                 {
84                 case TOK_EOF:
85                         break;
86                 
87                 // Typed variables/functions
88                 case TOKEN_GROUP_TYPES:
89                         {
90                          int    tok, type;
91                         TOKEN_GET_DATATYPE(type, Parser->Token);
92                         
93                         tok = GetToken(Parser);
94                         // Define a function (pass on to the other function definition code)
95                         if( tok == TOK_IDENT ) {
96                                 goto defFcn;
97                         }
98                         // Define a variable
99                         else if( tok == TOK_VARIABLE ) {
100                                 AST_AppendNode( mainCode, Parse_GetVarDef(Parser, type) );
101                                 SyntaxAssert(Parser, GetToken(Parser), TOK_SEMICOLON);
102                         }
103                         else {
104                                 fprintf(stderr, "ERROR: Unexpected %s, expected TOK_IDENT or TOK_VARIABLE\n",
105                                         csaTOKEN_NAMES[tok]);
106                         }
107                         }
108                         break;
109                 
110                 // Define a function
111                 case TOK_RWD_FUNCTION:
112                         if( !Variant->bDyamicTyped ) {
113                                 fprintf(stderr, "ERROR: Attempt to create a dynamic function\n");
114                                 longjmp(Parser->JmpTarget, -1);
115                         }
116                         type = SS_DATATYPE_DYNAMIC;
117                         SyntaxAssert(Parser, GetToken(Parser), TOK_IDENT );
118                 defFcn:
119                         name = strndup( Parser->TokenStr, Parser->TokenLen );
120                         fcn = AST_AppendFunction( ret, name );
121                         #if DEBUG
122                         printf("DefFCN %s\n", name);
123                         #endif
124                         free(name);
125                         
126                         // Get arguments
127                         SyntaxAssert(Parser, GetToken(Parser), TOK_PAREN_OPEN );
128                         if( LookAhead(Parser) != TOK_PAREN_CLOSE )
129                         {
130                                 do {
131                                         type = SS_DATATYPE_DYNAMIC;
132                                         GetToken(Parser);
133                                         // Non dynamic typed variants must use data types
134                                         if( !Variant->bDyamicTyped ) {
135                                                 TOKEN_GET_DATATYPE(type, Parser->Token);
136                                                 GetToken(Parser);
137                                         }
138                                         AST_AppendFunctionArg(fcn, Parse_GetVarDef(Parser, type)); 
139                                 }       while(GetToken(Parser) == TOK_COMMA);
140                         }
141                         else
142                                 GetToken(Parser);
143                         SyntaxAssert(Parser, Parser->Token, TOK_PAREN_CLOSE );
144                         
145                         AST_SetFunctionCode( fcn, Parse_DoCodeBlock(Parser) );
146                         break;
147                 
148                 default:
149                         PutBack(Parser);
150                         AST_AppendNode( mainCode, Parse_DoBlockLine(Parser) );
151                         break;
152                 }
153         }
154         
155         fcn = AST_AppendFunction( ret, "" );
156         AST_SetFunctionCode( fcn, mainCode );
157         
158         printf("---- %p parsed as SpiderScript ----\n", Buffer);
159         
160         return ret;
161 }
162
163 /**
164  * \brief Parse a block of code surrounded by { }
165  */
166 tAST_Node *Parse_DoCodeBlock(tParser *Parser)
167 {
168         tAST_Node       *ret;
169         
170         // Check if we are being called for a one-liner
171         if( GetToken(Parser) != TOK_BRACE_OPEN ) {
172                 PutBack(Parser);
173                 return Parse_DoBlockLine(Parser);
174         }
175         
176         ret = AST_NewCodeBlock();
177         
178         while( LookAhead(Parser) != TOK_BRACE_CLOSE )
179         {
180                 AST_AppendNode( ret, Parse_DoBlockLine(Parser) );
181         }
182         GetToken(Parser);       // Omnomnom
183         return ret;
184 }
185
186 /**
187  * \brief Parse a line in a block
188  */
189 tAST_Node *Parse_DoBlockLine(tParser *Parser)
190 {
191         tAST_Node       *ret;
192         
193         //printf("Parse_DoBlockLine: Line %i\n", Parser->CurLine);
194         
195         switch(LookAhead(Parser))
196         {
197         
198         // Return from a method
199         case TOK_RWD_RETURN:
200                 //printf("return\n");
201                 GetToken(Parser);
202                 ret = AST_NewUniOp(NODETYPE_RETURN, Parse_DoExpr0(Parser));
203                 break;
204         
205         // Control Statements
206         case TOK_RWD_IF:
207                 {
208                 tAST_Node       *cond, *true, *false = NULL;
209                 GetToken(Parser);       // eat the if
210                 SyntaxAssert(Parser, GetToken(Parser), TOK_PAREN_OPEN);
211                 cond = Parse_DoExpr0(Parser);   // Get condition
212                 SyntaxAssert(Parser, GetToken(Parser), TOK_PAREN_CLOSE);
213                 true = Parse_DoCodeBlock(Parser);
214                 if( LookAhead(Parser) == TOK_RWD_ELSE ) {
215                         GetToken(Parser);
216                         false = Parse_DoCodeBlock(Parser);
217                 }
218                 ret = AST_NewIf(cond, true, false);
219                 }
220                 return ret;
221         case TOK_RWD_FOR:
222         case TOK_RWD_DO:
223         case TOK_RWD_WHILE:
224                 TODO(Parser, "Implement if, for, do and while\n");
225                 break;
226         
227         // Define Variables
228         case TOKEN_GROUP_TYPES:
229                 {
230                          int    type;
231                         
232                         switch(GetToken(Parser))
233                         {
234                         case TOK_RWD_INTEGER:   type = SS_DATATYPE_INTEGER;     break;
235                         case TOK_RWD_OBJECT:    type = SS_DATATYPE_OBJECT;      break;
236                         case TOK_RWD_REAL:      type = SS_DATATYPE_REAL;        break;
237                         case TOK_RWD_STRING:    type = SS_DATATYPE_STRING;      break;
238                         }
239                         
240                         SyntaxAssert(Parser, GetToken(Parser), TOK_VARIABLE);
241                         
242                         ret = Parse_GetVarDef(Parser, type);
243                 }
244                 break;
245         
246         // Default
247         default:
248                 //printf("exp0\n");
249                 ret = Parse_DoExpr0(Parser);
250                 break;
251         }
252         
253         SyntaxAssert(Parser, GetToken(Parser), TOK_SEMICOLON );
254         return ret;
255 }
256
257 /**
258  * \brief Get a variable definition
259  */
260 tAST_Node *Parse_GetVarDef(tParser *Parser, int Type)
261 {
262         char    name[Parser->TokenLen];
263         tAST_Node       *ret;
264         
265         SyntaxAssert(Parser, Parser->Token, TOK_VARIABLE);
266         
267         // copy the name (trimming the $)
268         memcpy(name, Parser->TokenStr+1, Parser->TokenLen-1);
269         name[Parser->TokenLen-1] = 0;
270         // Define the variable
271         ret = AST_NewDefineVar(Type, name);
272         // Handle arrays
273         while( LookAhead(Parser) == TOK_SQUARE_OPEN )
274         {
275                 GetToken(Parser);
276                 AST_AppendNode(ret, Parse_DoExpr0(Parser));
277                 SyntaxAssert(Parser, GetToken(Parser), TOK_SQUARE_CLOSE);
278         }
279         return ret;
280 }
281
282 /**
283  * \brief Assignment Operations
284  */
285 tAST_Node *Parse_DoExpr0(tParser *Parser)
286 {
287         tAST_Node       *ret = Parse_DoExpr1(Parser);
288
289         // Check Assignment
290         switch(LookAhead(Parser))
291         {
292         case TOK_ASSIGN:
293                 GetToken(Parser);               // Eat Token
294                 ret = AST_NewAssign(NODETYPE_NOP, ret, Parse_DoExpr0(Parser));
295                 break;
296         #if 0
297         case TOK_DIV_EQU:
298                 GetToken(Parser);               // Eat Token
299                 ret = AST_NewAssign(NODETYPE_DIVIDE, ret, Parse_DoExpr0(Parser));
300                 break;
301         case TOK_MULT_EQU:
302                 GetToken(Parser);               // Eat Token
303                 ret = AST_NewAssign(NODETYPE_MULTIPLY, ret, Parse_DoExpr0(Parser));
304                 break;
305         #endif
306         default:
307                 #if DEBUG >= 2
308                 printf("Parse_DoExpr0: Parser->Token = %i\n", Parser->Token);
309                 #endif
310                 break;
311         }
312         return ret;
313 }
314
315 /**
316  * \brief Logical/Boolean Operators
317  */
318 tAST_Node *Parse_DoExpr1(tParser *Parser)
319 {
320         tAST_Node       *ret = Parse_DoExpr2(Parser);
321         
322         switch(GetToken(Parser))
323         {
324         case TOK_LOGICAND:
325                 ret = AST_NewBinOp(NODETYPE_LOGICALAND, ret, Parse_DoExpr1(Parser));
326                 break;
327         case TOK_LOGICOR:
328                 ret = AST_NewBinOp(NODETYPE_LOGICALOR, ret, Parse_DoExpr1(Parser));
329                 break;
330         case TOK_LOGICXOR:
331                 ret = AST_NewBinOp(NODETYPE_LOGICALXOR, ret, Parse_DoExpr1(Parser));
332                 break;
333         default:
334                 PutBack(Parser);
335                 break;
336         }
337         return ret;
338 }
339
340 // --------------------
341 // Expression 2 - Comparison Operators
342 // --------------------
343 tAST_Node *Parse_DoExpr2(tParser *Parser)
344 {
345         tAST_Node       *ret = Parse_DoExpr3(Parser);
346
347         // Check token
348         switch(GetToken(Parser))
349         {
350         case TOK_EQUALS:
351                 ret = AST_NewBinOp(NODETYPE_EQUALS, ret, Parse_DoExpr2(Parser));
352                 break;
353         case TOK_LT:
354                 ret = AST_NewBinOp(NODETYPE_LESSTHAN, ret, Parse_DoExpr2(Parser));
355                 break;
356         case TOK_GT:
357                 ret = AST_NewBinOp(NODETYPE_GREATERTHAN, ret, Parse_DoExpr2(Parser));
358                 break;
359         default:
360                 PutBack(Parser);
361                 break;
362         }
363         return ret;
364 }
365
366 /**
367  * \brief Bitwise Operations
368  */
369 tAST_Node *Parse_DoExpr3(tParser *Parser)
370 {
371         tAST_Node       *ret = Parse_DoExpr4(Parser);
372
373         // Check Token
374         switch(GetToken(Parser))
375         {
376         case TOK_OR:
377                 ret = AST_NewBinOp(NODETYPE_BWOR, ret, Parse_DoExpr3(Parser));
378                 break;
379         case TOK_AND:
380                 ret = AST_NewBinOp(NODETYPE_BWAND, ret, Parse_DoExpr3(Parser));
381                 break;
382         case TOK_XOR:
383                 ret = AST_NewBinOp(NODETYPE_BWXOR, ret, Parse_DoExpr3(Parser));
384                 break;
385         default:
386                 PutBack(Parser);
387                 break;
388         }
389         return ret;
390 }
391
392 // --------------------
393 // Expression 4 - Shifts
394 // --------------------
395 tAST_Node *Parse_DoExpr4(tParser *Parser)
396 {
397         tAST_Node *ret = Parse_DoExpr5(Parser);
398
399         switch(GetToken(Parser))
400         {
401         case TOK_SHL:
402                 ret = AST_NewBinOp(NODETYPE_BITSHIFTLEFT, ret, Parse_DoExpr5(Parser));
403                 break;
404         case TOK_SHR:
405                 ret = AST_NewBinOp(NODETYPE_BITSHIFTRIGHT, ret, Parse_DoExpr5(Parser));
406                 break;
407         default:
408                 PutBack(Parser);
409                 break;
410         }
411
412         return ret;
413 }
414
415 // --------------------
416 // Expression 5 - Arithmatic
417 // --------------------
418 tAST_Node *Parse_DoExpr5(tParser *Parser)
419 {
420         tAST_Node *ret = Parse_DoExpr6(Parser);
421
422         switch(GetToken(Parser))
423         {
424         case TOK_PLUS:
425                 ret = AST_NewBinOp(NODETYPE_ADD, ret, Parse_DoExpr5(Parser));
426                 break;
427         case TOK_MINUS:
428                 ret = AST_NewBinOp(NODETYPE_SUBTRACT, ret, Parse_DoExpr5(Parser));
429                 break;
430         default:
431                 PutBack(Parser);
432                 break;
433         }
434
435         return ret;
436 }
437
438 // --------------------
439 // Expression 6 - Multiplcation & Division
440 // --------------------
441 tAST_Node *Parse_DoExpr6(tParser *Parser)
442 {
443         tAST_Node *ret = Parse_DoParen(Parser);
444
445         switch(GetToken(Parser))
446         {
447         case TOK_MUL:
448                 ret = AST_NewBinOp(NODETYPE_MULTIPLY, ret, Parse_DoExpr6(Parser));
449                 break;
450         case TOK_DIV:
451                 ret = AST_NewBinOp(NODETYPE_DIVIDE, ret, Parse_DoExpr6(Parser));
452                 break;
453         default:
454                 PutBack(Parser);
455                 break;
456         }
457
458         return ret;
459 }
460
461
462 // --------------------
463 // 2nd Last Expression - Parens
464 // --------------------
465 tAST_Node *Parse_DoParen(tParser *Parser)
466 {
467         #if DEBUG >= 2
468         printf("Parse_DoParen: (Parser=%p)\n", Parser);
469         #endif
470         if(LookAhead(Parser) == TOK_PAREN_OPEN)
471         {
472                 tAST_Node       *ret;
473                  int    type;
474                 GetToken(Parser);
475                 
476                 // TODO: Handle casts here
477                 switch(LookAhead(Parser))
478                 {
479                 case TOKEN_GROUP_TYPES:
480                         GetToken(Parser);
481                         TOKEN_GET_DATATYPE(type, Parser->Token);
482                         SyntaxAssert(Parser, GetToken(Parser), TOK_PAREN_CLOSE);
483                         ret = AST_NewCast(type, Parse_DoParen(Parser));
484                         break;
485                 default:                
486                         ret = Parse_DoExpr0(Parser);
487                         SyntaxAssert(Parser, GetToken(Parser), TOK_PAREN_CLOSE);
488                         break;
489                 }
490                 return ret;
491         }
492         else
493                 return Parse_DoValue(Parser);
494 }
495
496 // --------------------
497 // Last Expression - Value
498 // --------------------
499 tAST_Node *Parse_DoValue(tParser *Parser)
500 {
501          int    tok = LookAhead(Parser);
502
503         #if DEBUG >= 2
504         printf("Parse_DoValue: tok = %i\n", tok);
505         #endif
506
507         switch(tok)
508         {
509         case TOK_STR:   return Parse_GetString(Parser);
510         case TOK_INTEGER:       return Parse_GetNumeric(Parser);
511         case TOK_IDENT: return Parse_GetIdent(Parser);
512         case TOK_VARIABLE:      return Parse_GetVariable(Parser);
513
514         default:
515                 fprintf(stderr, "Syntax Error: Unexpected %s on line %i, Expected TOK_T_VALUE\n",
516                         csaTOKEN_NAMES[tok], Parser->CurLine);
517                 longjmp( Parser->JmpTarget, -1 );
518         }
519 }
520
521 /**
522  * \brief Get a string
523  */
524 tAST_Node *Parse_GetString(tParser *Parser)
525 {
526         tAST_Node       *ret;
527          int    i, j;
528         GetToken( Parser );
529         
530         {
531                 char    data[ Parser->TokenLen - 2 ];
532                 j = 0;
533                 
534                 for( i = 1; i < Parser->TokenLen - 1; i++ )
535                 {
536                         if( Parser->TokenStr[i] == '\\' ) {
537                                 i ++;
538                                 switch( Parser->TokenStr[i] )
539                                 {
540                                 case 'n':       data[j++] = '\n';       break;
541                                 case 'r':       data[j++] = '\r';       break;
542                                 default:
543                                         // TODO: Octal Codes
544                                         // TODO: Error/Warning?
545                                         break;
546                                 }
547                         }
548                         else {
549                                 data[j++] = Parser->TokenStr[i];
550                         }
551                 }
552                 
553                 // TODO: Parse Escape Codes
554                 ret = AST_NewString( data, j );
555         }
556         return ret;
557 }
558
559 /**
560  * \brief Get a numeric value
561  */
562 tAST_Node *Parse_GetNumeric(tParser *Parser)
563 {
564         uint64_t        value;
565         GetToken( Parser );
566         value = atoi( Parser->TokenStr );
567         return AST_NewInteger( value );
568 }
569
570 /**
571  * \brief Get a variable
572  */
573 tAST_Node *Parse_GetVariable(tParser *Parser)
574 {
575         tAST_Node       *ret;
576         SyntaxAssert( Parser, GetToken(Parser), TOK_VARIABLE );
577         {
578                 char    name[Parser->TokenLen];
579                 memcpy(name, Parser->TokenStr+1, Parser->TokenLen-1);
580                 name[Parser->TokenLen-1] = 0;
581                 ret = AST_NewVariable( name );
582                 #if DEBUG >= 2
583                 printf("Parse_GetVariable: name = '%s'\n", name);
584                 #endif
585         }
586         // Handle array references
587         while( LookAhead(Parser) == TOK_SQUARE_OPEN )
588         {
589                 GetToken(Parser);
590                 ret = AST_NewBinOp(NODETYPE_INDEX, ret, Parse_DoExpr0(Parser));
591                 SyntaxAssert(Parser, GetToken(Parser), TOK_SQUARE_CLOSE);
592         }
593         return ret;
594 }
595
596 /**
597  * \brief Get an identifier (constand or function call)
598  */
599 tAST_Node *Parse_GetIdent(tParser *Parser)
600 {
601         tAST_Node       *ret;
602         char    *name;
603         SyntaxAssert(Parser, GetToken(Parser), TOK_IDENT );
604         name = strndup( Parser->TokenStr, Parser->TokenLen );
605         
606         #if 0
607         while( GetToken(Parser) == TOK_SCOPE )
608         {
609                 ret = AST_New
610         }
611         PutBack(Parser);
612         #endif
613         
614         if( GetToken(Parser) == TOK_PAREN_OPEN )
615         {
616                 #if DEBUG >= 2
617                 printf("Parse_GetIdent: Calling '%s'\n", name);
618                 #endif
619                 // Function Call
620                 ret = AST_NewFunctionCall( name );
621                 // Read arguments
622                 if( GetToken(Parser) != TOK_PAREN_CLOSE )
623                 {
624                         PutBack(Parser);
625                         do {
626                                 #if DEBUG >= 2
627                                 printf(" Parse_GetIdent: Argument\n");
628                                 #endif
629                                 AST_AppendFunctionCallArg( ret, Parse_DoExpr0(Parser) );
630                         } while(GetToken(Parser) == TOK_COMMA);
631                         SyntaxAssert( Parser, Parser->Token, TOK_PAREN_CLOSE );
632                         #if DEBUG >= 2
633                         printf(" Parse_GetIdent: All arguments parsed\n");
634                         #endif
635                 }
636         }
637         else {
638                 // Runtime Constant
639                 #if DEBUG >= 2
640                 printf("Parse_GetIdent: Referencing '%s'\n", name);
641                 #endif
642                 PutBack(Parser);
643                 ret = AST_NewConstant( name );
644         }
645         
646         free(name);
647         return ret;
648 }
649
650 /**
651  * \brief Check for an error
652  */
653 void SyntaxAssert(tParser *Parser, int Have, int Want)
654 {
655         if(Have != Want) {
656                 fprintf(stderr, "ERROR: SyntaxAssert Failed, Expected %s(%i), got %s(%i) on line %i\n",
657                         csaTOKEN_NAMES[Want], Want, csaTOKEN_NAMES[Have], Have, Parser->CurLine);
658                 longjmp(Parser->JmpTarget, -1);
659         }
660 }
661

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