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

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