2 * Acess2 - SpiderScript
8 #include <spiderscript.h>
9 #define WANT_TOKEN_STRINGS 1
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);
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 tAST_Node *Parse_DoExpr7(tParser *Parser); // Right Unary Operations
29 tAST_Node *Parse_DoExpr8(tParser *Parser); // Left Unary Operations
31 tAST_Node *Parse_DoParen(tParser *Parser); // Parenthesis (Always Last)
32 tAST_Node *Parse_DoValue(tParser *Parser); // Values
34 tAST_Node *Parse_GetString(tParser *Parser);
35 tAST_Node *Parse_GetNumeric(tParser *Parser);
36 tAST_Node *Parse_GetVariable(tParser *Parser);
37 tAST_Node *Parse_GetIdent(tParser *Parser, int bObjectCreate);
39 void SyntaxAssert(tParser *Parser, int Have, int Want);
41 #define TODO(Parser, message...) do {\
42 fprintf(stderr, "TODO: "message);\
43 longjmp(Parser->JmpTarget, -1);\
48 * \brief Parse a buffer into a syntax tree
50 tAST_Script *Parse_Buffer(tSpiderVariant *Variant, char *Buffer)
53 tParser *Parser = &parser; //< Keeps code consistent
61 printf("Parse_Buffer: (Variant=%p, Buffer=%p)\n", Variant, Buffer);
65 parser.LastToken = -1;
66 parser.NextToken = -1;
68 parser.BufStart = Buffer;
69 parser.CurPos = Buffer;
71 ret = AST_NewScript();
72 mainCode = AST_NewCodeBlock(&parser);
74 // Give us an error fallback
75 if( setjmp( parser.JmpTarget ) != 0 )
77 AST_FreeNode( mainCode );
82 while(Parser->Token != TOK_EOF)
84 switch( GetToken(Parser) )
89 // Typed variables/functions
90 case TOKEN_GROUP_TYPES:
93 TOKEN_GET_DATATYPE(type, Parser->Token);
95 tok = GetToken(Parser);
96 // Define a function (pass on to the other function definition code)
97 if( tok == TOK_IDENT ) {
101 else if( tok == TOK_VARIABLE ) {
102 AST_AppendNode( mainCode, Parse_GetVarDef(Parser, type) );
103 SyntaxAssert(Parser, GetToken(Parser), TOK_SEMICOLON);
106 fprintf(stderr, "ERROR: Unexpected %s, expected TOK_IDENT or TOK_VARIABLE\n",
107 csaTOKEN_NAMES[tok]);
113 case TOK_RWD_FUNCTION:
114 if( !Variant->bDyamicTyped ) {
115 fprintf(stderr, "ERROR: Dynamic functions are invalid in static mode\n");
116 longjmp(Parser->JmpTarget, -1);
118 type = SS_DATATYPE_DYNAMIC;
119 SyntaxAssert(Parser, GetToken(Parser), TOK_IDENT );
121 name = strndup( Parser->TokenStr, Parser->TokenLen );
122 fcn = AST_AppendFunction( ret, name );
124 printf("DefFCN %s\n", name);
129 SyntaxAssert(Parser, GetToken(Parser), TOK_PAREN_OPEN );
130 if( LookAhead(Parser) != TOK_PAREN_CLOSE )
133 type = SS_DATATYPE_DYNAMIC;
135 // Non dynamic typed variants must use data types
136 if( !Variant->bDyamicTyped ) {
137 TOKEN_GET_DATATYPE(type, Parser->Token);
140 AST_AppendFunctionArg(fcn, Parse_GetVarDef(Parser, type));
141 } while(GetToken(Parser) == TOK_COMMA);
145 SyntaxAssert(Parser, Parser->Token, TOK_PAREN_CLOSE );
147 AST_SetFunctionCode( fcn, Parse_DoCodeBlock(Parser) );
152 AST_AppendNode( mainCode, Parse_DoBlockLine(Parser) );
157 fcn = AST_AppendFunction( ret, "" );
158 AST_SetFunctionCode( fcn, mainCode );
160 //printf("---- %p parsed as SpiderScript ----\n", Buffer);
166 * \brief Parse a block of code surrounded by { }
168 tAST_Node *Parse_DoCodeBlock(tParser *Parser)
172 // Check if we are being called for a one-liner
173 if( GetToken(Parser) != TOK_BRACE_OPEN ) {
175 return Parse_DoBlockLine(Parser);
178 ret = AST_NewCodeBlock(Parser);
180 while( LookAhead(Parser) != TOK_BRACE_CLOSE )
182 AST_AppendNode( ret, Parse_DoBlockLine(Parser) );
184 GetToken(Parser); // Omnomnom
189 * \brief Parse a line in a block
191 tAST_Node *Parse_DoBlockLine(tParser *Parser)
195 //printf("Parse_DoBlockLine: Line %i\n", Parser->CurLine);
197 switch(LookAhead(Parser))
201 return Parse_DoCodeBlock(Parser);
208 // Return from a method
211 ret = AST_NewUniOp(Parser, NODETYPE_RETURN, Parse_DoExpr0(Parser));
214 // Control Statements
217 tAST_Node *cond, *true, *false = NULL;
218 GetToken(Parser); // eat the if
219 SyntaxAssert(Parser, GetToken(Parser), TOK_PAREN_OPEN);
220 cond = Parse_DoExpr0(Parser); // Get condition
221 SyntaxAssert(Parser, GetToken(Parser), TOK_PAREN_CLOSE);
222 true = Parse_DoCodeBlock(Parser);
223 if( LookAhead(Parser) == TOK_RWD_ELSE ) {
225 false = Parse_DoCodeBlock(Parser);
228 false = AST_NewNop(Parser);
229 ret = AST_NewIf(Parser, cond, true, false);
235 tAST_Node *init=NULL, *cond=NULL, *inc=NULL, *code;
236 GetToken(Parser); // Eat 'for'
237 SyntaxAssert(Parser, GetToken(Parser), TOK_PAREN_OPEN);
239 if(LookAhead(Parser) != TOK_SEMICOLON)
240 init = Parse_DoExpr0(Parser);
242 SyntaxAssert(Parser, GetToken(Parser), TOK_SEMICOLON);
244 if(LookAhead(Parser) != TOK_SEMICOLON)
245 cond = Parse_DoExpr0(Parser);
247 SyntaxAssert(Parser, GetToken(Parser), TOK_SEMICOLON);
249 if(LookAhead(Parser) != TOK_PAREN_CLOSE)
250 inc = Parse_DoExpr0(Parser);
252 SyntaxAssert(Parser, GetToken(Parser), TOK_PAREN_CLOSE);
254 code = Parse_DoCodeBlock(Parser);
255 ret = AST_NewLoop(Parser, init, 0, cond, inc, code);
261 tAST_Node *code, *cond;
262 GetToken(Parser); // Eat 'do'
263 code = Parse_DoCodeBlock(Parser);
264 SyntaxAssert( Parser, GetToken(Parser), TOK_RWD_WHILE );
265 SyntaxAssert( Parser, GetToken(Parser), TOK_PAREN_OPEN );
266 cond = Parse_DoExpr0(Parser);
267 SyntaxAssert( Parser, GetToken(Parser), TOK_PAREN_CLOSE );
268 ret = AST_NewLoop(Parser, AST_NewNop(Parser), 1, cond, AST_NewNop(Parser), code);
273 tAST_Node *code, *cond;
274 GetToken(Parser); // Eat 'while'
275 SyntaxAssert( Parser, GetToken(Parser), TOK_PAREN_OPEN );
276 cond = Parse_DoExpr0(Parser);
277 SyntaxAssert( Parser, GetToken(Parser), TOK_PAREN_CLOSE );
278 code = Parse_DoCodeBlock(Parser);
279 ret = AST_NewLoop(Parser, AST_NewNop(Parser), 0, cond, AST_NewNop(Parser), code);
284 case TOKEN_GROUP_TYPES:
288 TOKEN_GET_DATATYPE(type, Parser->Token);
290 SyntaxAssert(Parser, GetToken(Parser), TOK_VARIABLE);
292 ret = Parse_GetVarDef(Parser, type);
299 ret = Parse_DoExpr0(Parser);
303 SyntaxAssert(Parser, GetToken(Parser), TOK_SEMICOLON );
308 * \brief Get a variable definition
310 tAST_Node *Parse_GetVarDef(tParser *Parser, int Type)
312 char name[Parser->TokenLen];
315 SyntaxAssert(Parser, Parser->Token, TOK_VARIABLE);
317 // copy the name (trimming the $)
318 memcpy(name, Parser->TokenStr+1, Parser->TokenLen-1);
319 name[Parser->TokenLen-1] = 0;
320 // Define the variable
321 ret = AST_NewDefineVar(Parser, Type, name);
323 while( LookAhead(Parser) == TOK_SQUARE_OPEN )
326 AST_AppendNode(ret, Parse_DoExpr0(Parser));
327 SyntaxAssert(Parser, GetToken(Parser), TOK_SQUARE_CLOSE);
330 if( LookAhead(Parser) == TOK_ASSIGN )
333 ret->DefVar.InitialValue = Parse_DoExpr0(Parser);
340 * \brief Assignment Operations
342 tAST_Node *Parse_DoExpr0(tParser *Parser)
344 tAST_Node *ret = Parse_DoExpr1(Parser);
347 switch(LookAhead(Parser))
350 GetToken(Parser); // Eat Token
351 ret = AST_NewAssign(Parser, NODETYPE_NOP, ret, Parse_DoExpr0(Parser));
354 GetToken(Parser); // Eat Token
355 ret = AST_NewAssign(Parser, NODETYPE_DIVIDE, ret, Parse_DoExpr0(Parser));
358 GetToken(Parser); // Eat Token
359 ret = AST_NewAssign(Parser, NODETYPE_MULTIPLY, ret, Parse_DoExpr0(Parser));
361 case TOK_ASSIGN_PLUS:
362 GetToken(Parser); // Eat Token
363 ret = AST_NewAssign(Parser, NODETYPE_ADD, ret, Parse_DoExpr0(Parser));
365 case TOK_ASSIGN_MINUS:
366 GetToken(Parser); // Eat Token
367 ret = AST_NewAssign(Parser, NODETYPE_SUBTRACT, ret, Parse_DoExpr0(Parser));
371 printf("Parse_DoExpr0: Parser->Token = %i\n", Parser->Token);
379 * \brief Logical/Boolean Operators
381 tAST_Node *Parse_DoExpr1(tParser *Parser)
383 tAST_Node *ret = Parse_DoExpr2(Parser);
385 switch(GetToken(Parser))
388 ret = AST_NewBinOp(Parser, NODETYPE_LOGICALAND, ret, Parse_DoExpr1(Parser));
391 ret = AST_NewBinOp(Parser, NODETYPE_LOGICALOR, ret, Parse_DoExpr1(Parser));
394 ret = AST_NewBinOp(Parser, NODETYPE_LOGICALXOR, ret, Parse_DoExpr1(Parser));
403 // --------------------
404 // Expression 2 - Comparison Operators
405 // --------------------
406 tAST_Node *Parse_DoExpr2(tParser *Parser)
408 tAST_Node *ret = Parse_DoExpr3(Parser);
411 switch(GetToken(Parser))
414 ret = AST_NewBinOp(Parser, NODETYPE_EQUALS, ret, Parse_DoExpr2(Parser));
417 ret = AST_NewBinOp(Parser, NODETYPE_LESSTHAN, ret, Parse_DoExpr2(Parser));
420 ret = AST_NewBinOp(Parser, NODETYPE_GREATERTHAN, ret, Parse_DoExpr2(Parser));
423 ret = AST_NewBinOp(Parser, NODETYPE_LESSTHANEQUAL, ret, Parse_DoExpr2(Parser));
426 ret = AST_NewBinOp(Parser, NODETYPE_GREATERTHANEQUAL, ret, Parse_DoExpr2(Parser));
436 * \brief Bitwise Operations
438 tAST_Node *Parse_DoExpr3(tParser *Parser)
440 tAST_Node *ret = Parse_DoExpr4(Parser);
443 switch(GetToken(Parser))
446 ret = AST_NewBinOp(Parser, NODETYPE_BWOR, ret, Parse_DoExpr3(Parser));
449 ret = AST_NewBinOp(Parser, NODETYPE_BWAND, ret, Parse_DoExpr3(Parser));
452 ret = AST_NewBinOp(Parser, NODETYPE_BWXOR, ret, Parse_DoExpr3(Parser));
461 // --------------------
462 // Expression 4 - Shifts
463 // --------------------
464 tAST_Node *Parse_DoExpr4(tParser *Parser)
466 tAST_Node *ret = Parse_DoExpr5(Parser);
468 switch(GetToken(Parser))
471 ret = AST_NewBinOp(Parser, NODETYPE_BITSHIFTLEFT, ret, Parse_DoExpr5(Parser));
474 ret = AST_NewBinOp(Parser, NODETYPE_BITSHIFTRIGHT, ret, Parse_DoExpr5(Parser));
484 // --------------------
485 // Expression 5 - Arithmatic
486 // --------------------
487 tAST_Node *Parse_DoExpr5(tParser *Parser)
489 tAST_Node *ret = Parse_DoExpr6(Parser);
491 switch(GetToken(Parser))
494 ret = AST_NewBinOp(Parser, NODETYPE_ADD, ret, Parse_DoExpr5(Parser));
497 ret = AST_NewBinOp(Parser, NODETYPE_SUBTRACT, ret, Parse_DoExpr5(Parser));
507 // --------------------
508 // Expression 6 - Multiplcation & Division
509 // --------------------
510 tAST_Node *Parse_DoExpr6(tParser *Parser)
512 tAST_Node *ret = Parse_DoExpr7(Parser);
514 switch(GetToken(Parser))
517 ret = AST_NewBinOp(Parser, NODETYPE_MULTIPLY, ret, Parse_DoExpr6(Parser));
520 ret = AST_NewBinOp(Parser, NODETYPE_DIVIDE, ret, Parse_DoExpr6(Parser));
530 // Right Unary Operations
531 tAST_Node *Parse_DoExpr7(tParser *Parser)
533 tAST_Node *ret = Parse_DoExpr8(Parser);
535 switch(GetToken(Parser))
538 ret = AST_NewUniOp(Parser, NODETYPE_POSTINC, ret);
541 ret = AST_NewUniOp(Parser, NODETYPE_POSTDEC, ret);
550 // Left Unary Operations
551 tAST_Node *Parse_DoExpr8(tParser *Parser)
553 switch(GetToken(Parser))
556 return AST_NewAssign(Parser, NODETYPE_ADD, Parse_DoExpr8(Parser), AST_NewInteger(Parser, 1));
558 return AST_NewAssign(Parser, NODETYPE_SUBTRACT, Parse_DoExpr8(Parser), AST_NewInteger(Parser, 1));
560 return AST_NewUniOp(Parser, NODETYPE_NEGATE, Parse_DoExpr8(Parser));
562 return AST_NewUniOp(Parser, NODETYPE_LOGICALNOT, Parse_DoExpr8(Parser));
564 return AST_NewUniOp(Parser, NODETYPE_BWNOT, Parse_DoExpr8(Parser));
567 return Parse_DoParen(Parser);
571 // --------------------
572 // 2nd Last Expression - Parens
573 // --------------------
574 tAST_Node *Parse_DoParen(tParser *Parser)
577 printf("Parse_DoParen: (Parser=%p)\n", Parser);
579 if(LookAhead(Parser) == TOK_PAREN_OPEN)
585 // TODO: Handle casts here
586 switch(LookAhead(Parser))
588 case TOKEN_GROUP_TYPES:
590 TOKEN_GET_DATATYPE(type, Parser->Token);
591 SyntaxAssert(Parser, GetToken(Parser), TOK_PAREN_CLOSE);
592 ret = AST_NewCast(Parser, type, Parse_DoParen(Parser));
595 ret = Parse_DoExpr0(Parser);
596 SyntaxAssert(Parser, GetToken(Parser), TOK_PAREN_CLOSE);
602 return Parse_DoValue(Parser);
605 // --------------------
606 // Last Expression - Value
607 // --------------------
608 tAST_Node *Parse_DoValue(tParser *Parser)
610 int tok = LookAhead(Parser);
613 printf("Parse_DoValue: tok = %i\n", tok);
619 return Parse_GetString(Parser);
621 return Parse_GetNumeric(Parser);
625 return AST_NewReal( Parser, atof(Parser->TokenStr) );
627 case TOK_IDENT: return Parse_GetIdent(Parser, 0);
628 case TOK_VARIABLE: return Parse_GetVariable(Parser);
630 GetToken(Parser); // Omnomnom
631 return Parse_GetIdent(Parser, 1);
634 fprintf(stderr, "Syntax Error: Unexpected %s on line %i, Expected TOK_T_VALUE\n",
635 csaTOKEN_NAMES[tok], Parser->CurLine);
636 longjmp( Parser->JmpTarget, -1 );
641 * \brief Get a string
643 tAST_Node *Parse_GetString(tParser *Parser)
650 char data[ Parser->TokenLen - 2 ];
653 for( i = 1; i < Parser->TokenLen - 1; i++ )
655 if( Parser->TokenStr[i] == '\\' ) {
657 switch( Parser->TokenStr[i] )
659 case 'n': data[j++] = '\n'; break;
660 case 'r': data[j++] = '\r'; break;
663 // TODO: Error/Warning?
668 data[j++] = Parser->TokenStr[i];
672 // TODO: Parse Escape Codes
673 ret = AST_NewString( Parser, data, j );
679 * \brief Get a numeric value
681 tAST_Node *Parse_GetNumeric(tParser *Parser)
685 SyntaxAssert( Parser, GetToken( Parser ), TOK_INTEGER );
686 pos = Parser->TokenStr;
687 //printf("pos = %p, *pos = %c\n", pos, *pos);
697 if( '0' <= *pos && *pos <= '9' ) {
701 if( 'A' <= *pos && *pos <= 'F' ) {
702 value += *pos - 'A' + 10;
705 if( 'a' <= *pos && *pos <= 'f' ) {
706 value += *pos - 'a' + 10;
713 while( '0' <= *pos && *pos <= '7' ) {
714 value = value*8 + *pos - '0';
720 while( '0' <= *pos && *pos <= '9' ) {
721 value = value*10 + *pos - '0';
726 return AST_NewInteger( Parser, value );
730 * \brief Get a variable
732 tAST_Node *Parse_GetVariable(tParser *Parser)
735 SyntaxAssert( Parser, GetToken(Parser), TOK_VARIABLE );
737 char name[Parser->TokenLen];
738 memcpy(name, Parser->TokenStr+1, Parser->TokenLen-1);
739 name[Parser->TokenLen-1] = 0;
740 ret = AST_NewVariable( Parser, name );
742 printf("Parse_GetVariable: name = '%s'\n", name);
748 if( Parser->Token == TOK_SQUARE_OPEN )
750 ret = AST_NewBinOp(Parser, NODETYPE_INDEX, ret, Parse_DoExpr0(Parser));
751 SyntaxAssert(Parser, GetToken(Parser), TOK_SQUARE_CLOSE);
754 if( Parser->Token == TOK_ELEMENT )
756 SyntaxAssert(Parser, GetToken(Parser), TOK_IDENT);
758 if( LookAhead(Parser) == TOK_PAREN_OPEN )
760 char name[Parser->TokenLen+1];
761 memcpy(name, Parser->TokenStr, Parser->TokenLen);
762 name[Parser->TokenLen] = 0;
763 ret = AST_NewMethodCall(Parser, ret, name);
764 GetToken(Parser); // Eat the '('
766 if( GetToken(Parser) != TOK_PAREN_CLOSE )
770 AST_AppendFunctionCallArg( ret, Parse_DoExpr0(Parser) );
771 } while(GetToken(Parser) == TOK_COMMA);
772 SyntaxAssert( Parser, Parser->Token, TOK_PAREN_CLOSE );
779 char name[Parser->TokenLen];
780 memcpy(name, Parser->TokenStr+1, Parser->TokenLen-1);
781 name[Parser->TokenLen-1] = 0;
782 ret = AST_NewClassElement(Parser, ret, name);
794 * \brief Get an identifier (constant or function call)
796 tAST_Node *Parse_GetIdent(tParser *Parser, int bObjectCreate)
798 tAST_Node *ret = NULL;
800 SyntaxAssert(Parser, GetToken(Parser), TOK_IDENT );
801 name = strndup( Parser->TokenStr, Parser->TokenLen );
804 if( GetToken(Parser) == TOK_SCOPE )
806 ret = AST_NewScopeDereference( Parser, Parse_GetIdent(Parser, bObjectCreate), name );
813 if( GetToken(Parser) == TOK_PAREN_OPEN )
816 printf("Parse_GetIdent: Calling '%s'\n", name);
820 ret = AST_NewCreateObject( Parser, name );
822 ret = AST_NewFunctionCall( Parser, name );
824 if( GetToken(Parser) != TOK_PAREN_CLOSE )
829 printf(" Parse_GetIdent: Argument\n");
831 AST_AppendFunctionCallArg( ret, Parse_DoExpr0(Parser) );
832 } while(GetToken(Parser) == TOK_COMMA);
833 SyntaxAssert( Parser, Parser->Token, TOK_PAREN_CLOSE );
835 printf(" Parse_GetIdent: All arguments parsed\n");
841 // Runtime Constant / Variable (When implemented)
843 printf("Parse_GetIdent: Referencing '%s'\n", name);
846 if( bObjectCreate ) // Void constructor (TODO: Should this be an error?)
847 ret = AST_NewCreateObject( Parser, name );
849 ret = AST_NewConstant( Parser, name );
857 * \brief Check for an error
859 void SyntaxAssert(tParser *Parser, int Have, int Want)
862 fprintf(stderr, "ERROR: SyntaxAssert Failed, Expected %s(%i), got %s(%i) on line %i\n",
863 csaTOKEN_NAMES[Want], Want, csaTOKEN_NAMES[Have], Have, Parser->CurLine);
864 longjmp(Parser->JmpTarget, -1);