3 * - Script AST Manipulator
11 extern void SyntaxError(tParser *Parser, int bFatal, const char *Message, ...);
14 tAST_Script *AST_NewScript(void)
16 tAST_Script *ret = malloc( sizeof(tAST_Script) );
18 ret->Functions = NULL;
19 ret->LastFunction = NULL;
25 * \brief Append a function to a script
27 tAST_Function *AST_AppendFunction(tAST_Script *Script, const char *Name, int ReturnType)
31 ret = malloc( sizeof(tAST_Function) + strlen(Name) + 1 );
35 strcpy(ret->Name, Name);
37 ret->Arguments = NULL;
38 ret->ArgumentCount = 0;
39 ret->ReturnType = ReturnType;
41 if(Script->LastFunction == NULL) {
42 Script->Functions = Script->LastFunction = ret;
45 Script->LastFunction->Next = ret;
46 Script->LastFunction = ret;
52 void AST_AppendFunctionArg(tAST_Function *Function, tAST_Node *Node)
54 if( !Function->Arguments ) {
55 Function->Arguments_Last = Function->Arguments = Node;
58 Function->Arguments_Last->NextSibling = Node;
59 Function->Arguments_Last = Node;
61 Function->ArgumentCount ++;
65 * \brief Set the code for a function
67 void AST_SetFunctionCode(tAST_Function *Function, tAST_Node *Root)
69 Function->Code = Root;
73 * \name Node Manipulation
76 #define WRITE_N(_buffer, _offset, _len, _dataptr) do { \
77 if(_buffer) memcpy((char*)_buffer + _offset, _dataptr, _len);\
81 #define WRITE_8(_buffer, _offset, _val) do {\
83 WRITE_N(_buffer, _offset, 1, &v);\
85 #define WRITE_16(_buffer, _offset, _val) do {\
87 WRITE_N(_buffer, _offset, 2, &v);\
89 #define WRITE_32(_buffer, _offset, _val) do {\
91 WRITE_N(_buffer, _offset, 4, &v);\
93 #define WRITE_64(_buffer, _offset, _val) do {\
95 WRITE_N(_buffer, _offset, 8, &v);\
97 #define WRITE_REAL(_buffer, _offset, _val) do {\
99 WRITE_N(_buffer, _offset, sizeof(double), &v);\
102 #define WRITE_STR(_buffer, _offset, _string) do {\
103 int len = strlen(_string);\
104 WRITE_16(_buffer, _offset, len);\
105 WRITE_N(_buffer, _offset, len, _string);\
106 if((_offset & 1) == 1)WRITE_8(_buffer, _offset, 0); \
107 if((_offset & 3) == 2)WRITE_16(_buffer, _offset, 0); \
109 #define WRITE_NODELIST(_buffer, _offset, _listHead) do {\
112 for(node=(_listHead); node; node = node->NextSibling) {\
114 _offset += AST_WriteNode(_buffer, _offset, node); \
115 WRITE_32(_buffer, ptr, ptr); \
117 if(ptr != -1){ptr -= 4; WRITE_32(_buffer, ptr, 0);} \
121 * \brief Writes a script dump to a buffer
122 * \return Size of encoded data
123 * \note If \a Buffer is NULL, no write is done, but the size is still returned
125 size_t AST_WriteScript(void *Buffer, tAST_Script *Script)
128 size_t ret = 0, ptr = 0;
130 for( fcn = Script->Functions; fcn; fcn = fcn->Next )
132 // printf("fcn = %p, fcn->Name = %p\n", fcn, fcn->Name);
134 WRITE_32(Buffer, ret, 0); // Next
135 WRITE_STR(Buffer, ret, fcn->Name);
136 WRITE_NODELIST(Buffer, ret, fcn->Arguments); // TODO: Cheaper way
137 ret += AST_WriteNode(Buffer, ret, fcn->Code);
138 WRITE_32(Buffer, ptr, ret); // Actually set next
143 WRITE_32(Buffer, ptr, 0); // Clear next for final
150 * \brief Write a node to a file
152 size_t AST_WriteNode(void *Buffer, size_t Offset, tAST_Node *Node)
154 size_t baseOfs = Offset;
157 //fprintf(stderr, "Possible Bug - NULL passed to AST_WriteNode\n");
158 WRITE_32(Buffer, Offset, 0);
159 WRITE_16(Buffer, Offset, NODETYPE_NOP);
160 WRITE_16(Buffer, Offset, 0); // Line (0)
164 WRITE_32(Buffer, Offset, 0); // Next
165 WRITE_16(Buffer, Offset, Node->Type);
166 // TODO: Scan the buffer for the location of the filename (with NULL byte)
167 // else, write the string at the end of the node
168 WRITE_16(Buffer, Offset, Node->Line); // Line
169 //WRITE_32(Buffer, Offset, 0); // File
175 WRITE_NODELIST(Buffer, Offset, Node->Block.FirstChild);
179 case NODETYPE_METHODCALL:
180 Offset += AST_WriteNode(Buffer, Offset, Node->FunctionCall.Object);
181 case NODETYPE_FUNCTIONCALL:
182 case NODETYPE_CREATEOBJECT:
183 // TODO: Search for the same function name and add a pointer
184 WRITE_STR(Buffer, Offset, Node->FunctionCall.Name);
185 WRITE_NODELIST(Buffer, Offset, Node->FunctionCall.FirstArg);
190 Offset += AST_WriteNode(Buffer, Offset, Node->If.Condition);
191 Offset += AST_WriteNode(Buffer, Offset, Node->If.True);
192 Offset += AST_WriteNode(Buffer, Offset, Node->If.False);
195 // Looping Construct (For loop node)
197 WRITE_8(Buffer, Offset, Node->For.bCheckAfter);
198 // printf("Node %p, Loop Tag %p\n", Node, Node->For.Tag);
199 WRITE_STR(Buffer, Offset, Node->For.Tag);
200 Offset += AST_WriteNode(Buffer, Offset, Node->For.Init);
201 Offset += AST_WriteNode(Buffer, Offset, Node->For.Condition);
202 Offset += AST_WriteNode(Buffer, Offset, Node->For.Increment);
203 Offset += AST_WriteNode(Buffer, Offset, Node->For.Code);
207 case NODETYPE_ASSIGN:
208 WRITE_8(Buffer, Offset, Node->Assign.Operation);
209 Offset += AST_WriteNode(Buffer, Offset, Node->Assign.Dest);
210 Offset += AST_WriteNode(Buffer, Offset, Node->Assign.Value);
215 WRITE_8(Buffer, Offset, Node->Cast.DataType);
216 Offset += AST_WriteNode(Buffer, Offset, Node->Cast.Value);
220 case NODETYPE_DEFVAR:
221 WRITE_8(Buffer, Offset, Node->DefVar.DataType);
222 // TODO: Duplicate compress the strings
223 WRITE_STR(Buffer, Offset, Node->DefVar.Name);
225 WRITE_NODELIST(Buffer, Offset, Node->DefVar.LevelSizes);
226 Offset += AST_WriteNode(Buffer, Offset, Node->DefVar.InitialValue);
231 case NODETYPE_ELEMENT:
232 WRITE_STR(Buffer, Offset, Node->Scope.Name);
233 Offset += AST_WriteNode(Buffer, Offset, Node->UniOp.Value);
237 case NODETYPE_RETURN:
239 case NODETYPE_LOGICALNOT:
240 case NODETYPE_NEGATE:
241 case NODETYPE_POSTINC:
242 case NODETYPE_POSTDEC:
243 Offset += AST_WriteNode(Buffer, Offset, Node->UniOp.Value);
249 case NODETYPE_SUBTRACT:
250 case NODETYPE_MULTIPLY:
251 case NODETYPE_DIVIDE:
252 case NODETYPE_MODULO:
253 case NODETYPE_BITSHIFTLEFT:
254 case NODETYPE_BITSHIFTRIGHT:
255 case NODETYPE_BITROTATELEFT:
256 case NODETYPE_BWAND: case NODETYPE_LOGICALAND:
257 case NODETYPE_BWOR: case NODETYPE_LOGICALOR:
258 case NODETYPE_BWXOR: case NODETYPE_LOGICALXOR:
259 case NODETYPE_EQUALS:
260 case NODETYPE_LESSTHAN: case NODETYPE_LESSTHANEQUAL:
261 case NODETYPE_GREATERTHAN: case NODETYPE_GREATERTHANEQUAL:
262 Offset += AST_WriteNode(Buffer, Offset, Node->BinOp.Left);
263 Offset += AST_WriteNode(Buffer, Offset, Node->BinOp.Right);
266 // Node types with no children
269 case NODETYPE_VARIABLE:
270 case NODETYPE_CONSTANT:
272 case NODETYPE_CONTINUE:
273 // TODO: De-Duplicate the strings
274 WRITE_STR(Buffer, Offset, Node->Variable.Name);
276 case NODETYPE_STRING:
277 WRITE_32(Buffer, Offset, Node->Constant.String.Length);
278 WRITE_N(Buffer, Offset, Node->Constant.String.Length, Node->Constant.String.Data);
280 case NODETYPE_INTEGER:
281 WRITE_64(Buffer, Offset, Node->Constant.Integer);
284 WRITE_REAL(Buffer, Offset, Node->Constant.Real);
288 // fprintf(stderr, "AST_WriteNode: Unknown node type %i\n", Node->Type);
292 return Offset - baseOfs;
296 * \brief Free a node and all subnodes
298 void AST_FreeNode(tAST_Node *Node)
304 // Referenced counted file name
305 (*(int*)(Node->File - sizeof(int))) -= 1;
306 if( *(int*)(Node->File - sizeof(int)) == 0 )
307 free( (void*)(Node->File - sizeof(int)) );
313 for( node = Node->Block.FirstChild; node; )
315 tAST_Node *savedNext = node->NextSibling;
322 case NODETYPE_METHODCALL:
323 AST_FreeNode(Node->FunctionCall.Object);
324 case NODETYPE_FUNCTIONCALL:
325 case NODETYPE_CREATEOBJECT:
326 for( node = Node->FunctionCall.FirstArg; node; )
328 tAST_Node *savedNext = node->NextSibling;
336 AST_FreeNode(Node->If.Condition);
337 AST_FreeNode(Node->If.True);
338 AST_FreeNode(Node->If.False);
341 // Looping Construct (For loop node)
343 AST_FreeNode(Node->For.Init);
344 AST_FreeNode(Node->For.Condition);
345 AST_FreeNode(Node->For.Increment);
346 AST_FreeNode(Node->For.Code);
350 case NODETYPE_ASSIGN:
351 AST_FreeNode(Node->Assign.Dest);
352 AST_FreeNode(Node->Assign.Value);
357 AST_FreeNode(Node->Cast.Value);
361 case NODETYPE_ELEMENT:
362 AST_FreeNode(Node->Scope.Element);
366 case NODETYPE_DEFVAR:
367 for( node = Node->DefVar.LevelSizes; node; )
369 tAST_Node *savedNext = node->NextSibling;
373 AST_FreeNode(Node->DefVar.InitialValue);
377 case NODETYPE_RETURN:
379 case NODETYPE_LOGICALNOT:
380 case NODETYPE_NEGATE:
381 case NODETYPE_POSTINC:
382 case NODETYPE_POSTDEC:
383 AST_FreeNode(Node->UniOp.Value);
389 case NODETYPE_SUBTRACT:
390 case NODETYPE_MULTIPLY:
391 case NODETYPE_DIVIDE:
392 case NODETYPE_MODULO:
393 case NODETYPE_BITSHIFTLEFT:
394 case NODETYPE_BITSHIFTRIGHT:
395 case NODETYPE_BITROTATELEFT:
396 case NODETYPE_BWAND: case NODETYPE_LOGICALAND:
397 case NODETYPE_BWOR: case NODETYPE_LOGICALOR:
398 case NODETYPE_BWXOR: case NODETYPE_LOGICALXOR:
399 case NODETYPE_EQUALS:
400 case NODETYPE_LESSTHAN: case NODETYPE_LESSTHANEQUAL:
401 case NODETYPE_GREATERTHAN: case NODETYPE_GREATERTHANEQUAL:
402 AST_FreeNode( Node->BinOp.Left );
403 AST_FreeNode( Node->BinOp.Right );
406 // Node types with no children
407 case NODETYPE_NOP: break;
408 case NODETYPE_VARIABLE: break;
409 case NODETYPE_CONSTANT: break;
411 case NODETYPE_CONTINUE: break;
413 case NODETYPE_STRING:
414 case NODETYPE_INTEGER:
416 if( Node->ValueCache )
417 SpiderScript_DereferenceValue(Node->ValueCache);
418 Node->ValueCache = NULL;
424 tAST_Node *AST_int_AllocateNode(tParser *Parser, int Type, int ExtraSize)
426 tAST_Node *ret = malloc( sizeof(tAST_Node) + ExtraSize );
427 ret->NextSibling = NULL;
428 ret->File = Parser->Filename; *(int*)(Parser->Filename - sizeof(int)) += 1;
429 ret->Line = Parser->CurLine;
433 ret->BlockState = NULL;
435 ret->ValueCache = NULL;
440 tAST_Node *AST_NewCodeBlock(tParser *Parser)
442 tAST_Node *ret = AST_int_AllocateNode(Parser, NODETYPE_BLOCK, 0 );
444 ret->Block.FirstChild = NULL;
445 ret->Block.LastChild = NULL;
450 void AST_AppendNode(tAST_Node *Parent, tAST_Node *Child)
452 // Ignore NULL children
453 if( !Child ) return ;
455 Child->NextSibling = NULL;
456 switch( Parent->Type )
459 if(Parent->Block.FirstChild == NULL) {
460 Parent->Block.FirstChild = Parent->Block.LastChild = Child;
463 Parent->Block.LastChild->NextSibling = Child;
464 Parent->Block.LastChild = Child;
467 case NODETYPE_DEFVAR:
468 if(Parent->DefVar.LevelSizes == NULL) {
469 Parent->DefVar.LevelSizes = Parent->DefVar.LevelSizes_Last = Child;
472 Parent->DefVar.LevelSizes_Last->NextSibling = Child;
473 Parent->DefVar.LevelSizes_Last = Child;
477 fprintf(stderr, "BUG REPORT: AST_AppendNode on an invalid node type (%i)\n", Parent->Type);
482 tAST_Node *AST_NewIf(tParser *Parser, tAST_Node *Condition, tAST_Node *True, tAST_Node *False)
484 tAST_Node *ret = AST_int_AllocateNode(Parser, NODETYPE_IF, 0);
485 ret->If.Condition = Condition;
487 ret->If.False = False;
491 tAST_Node *AST_NewLoop(tParser *Parser, const char *Tag, tAST_Node *Init, int bPostCheck, tAST_Node *Condition, tAST_Node *Increment, tAST_Node *Code)
495 ret = AST_int_AllocateNode(Parser, NODETYPE_LOOP, strlen(Tag) + 1);
496 ret->For.Init = Init;
497 ret->For.bCheckAfter = !!bPostCheck;
498 ret->For.Condition = Condition;
499 ret->For.Increment = Increment;
500 ret->For.Code = Code;
501 strcpy(ret->For.Tag, Tag);
505 tAST_Node *AST_NewAssign(tParser *Parser, int Operation, tAST_Node *Dest, tAST_Node *Value)
507 tAST_Node *ret = AST_int_AllocateNode(Parser, NODETYPE_ASSIGN, 0);
509 if( Dest->Type != NODETYPE_VARIABLE && Dest->Type != NODETYPE_ELEMENT ) {
511 SyntaxError(Parser, 1, "Assign target is not a variable or attribute (instead %i)",
518 ret->Assign.Operation = Operation;
519 ret->Assign.Dest = Dest;
520 ret->Assign.Value = Value;
525 tAST_Node *AST_NewCast(tParser *Parser, int Target, tAST_Node *Value)
527 tAST_Node *ret = AST_int_AllocateNode(Parser, NODETYPE_CAST, 0);
529 ret->Cast.DataType = Target;
530 ret->Cast.Value = Value;
535 tAST_Node *AST_NewBinOp(tParser *Parser, int Operation, tAST_Node *Left, tAST_Node *Right)
537 tAST_Node *ret = AST_int_AllocateNode(Parser, Operation, 0);
539 ret->BinOp.Left = Left;
540 ret->BinOp.Right = Right;
547 tAST_Node *AST_NewUniOp(tParser *Parser, int Operation, tAST_Node *Value)
549 tAST_Node *ret = AST_int_AllocateNode(Parser, Operation, 0);
551 ret->UniOp.Value = Value;
556 tAST_Node *AST_NewBreakout(tParser *Parser, int Type, const char *DestTag)
558 int len = (DestTag ? strlen(DestTag) : 0);
559 tAST_Node *ret = AST_int_AllocateNode(Parser, Type, len + 1);
562 strcpy(ret->Variable.Name, DestTag);
564 ret->Variable.Name[0] = '\0';
569 tAST_Node *AST_NewNop(tParser *Parser)
571 tAST_Node *ret = AST_int_AllocateNode(Parser, NODETYPE_NOP, 0);
577 * \brief Create a new string node
579 tAST_Node *AST_NewString(tParser *Parser, const char *String, int Length)
581 tAST_Node *ret = AST_int_AllocateNode(Parser, NODETYPE_STRING, Length + 1);
583 ret->Constant.Type = SS_DATATYPE_STRING;
584 ret->Constant.ReferenceCount = 1;
585 ret->Constant.String.Length = Length;
586 memcpy(ret->Constant.String.Data, String, Length);
587 ret->Constant.String.Data[Length] = '\0';
593 * \brief Create a new integer node
595 tAST_Node *AST_NewInteger(tParser *Parser, int64_t Value)
597 tAST_Node *ret = AST_int_AllocateNode(Parser, NODETYPE_INTEGER, 0);
598 ret->Constant.Type = SS_DATATYPE_INTEGER;
599 ret->Constant.ReferenceCount = 1;
600 ret->Constant.Integer = Value;
605 * \brief Create a new real number node
607 tAST_Node *AST_NewReal(tParser *Parser, double Value)
609 tAST_Node *ret = AST_int_AllocateNode(Parser, NODETYPE_REAL, 0);
610 ret->Constant.Type = SS_DATATYPE_REAL;
611 ret->Constant.ReferenceCount = 1;
612 ret->Constant.Real = Value;
617 * \brief Create a new variable reference node
619 tAST_Node *AST_NewVariable(tParser *Parser, const char *Name)
621 tAST_Node *ret = AST_int_AllocateNode(Parser, NODETYPE_VARIABLE, strlen(Name) + 1 );
622 strcpy(ret->Variable.Name, Name);
627 * \brief Create a new variable definition node
629 tAST_Node *AST_NewDefineVar(tParser *Parser, int Type, const char *Name)
631 tAST_Node *ret = AST_int_AllocateNode(Parser, NODETYPE_DEFVAR, strlen(Name) + 1 );
633 ret->DefVar.DataType = Type;
634 ret->DefVar.LevelSizes = NULL;
635 ret->DefVar.LevelSizes_Last = NULL;
636 ret->DefVar.InitialValue = NULL;
637 strcpy(ret->DefVar.Name, Name);
643 * \brief Create a new runtime constant reference node
645 tAST_Node *AST_NewConstant(tParser *Parser, const char *Name)
647 tAST_Node *ret = AST_int_AllocateNode(Parser, NODETYPE_CONSTANT, strlen(Name) + 1 );
649 strcpy(ret->Variable.Name, Name);
655 * \brief Create a function call node
656 * \note Argument list is manipulated using AST_AppendFunctionCallArg
658 tAST_Node *AST_NewFunctionCall(tParser *Parser, const char *Name)
660 tAST_Node *ret = AST_int_AllocateNode(Parser, NODETYPE_FUNCTIONCALL, strlen(Name) + 1 );
662 ret->FunctionCall.Object = NULL;
663 ret->FunctionCall.FirstArg = NULL;
664 ret->FunctionCall.LastArg = NULL;
665 ret->FunctionCall.NumArgs = 0;
666 strcpy(ret->FunctionCall.Name, Name);
670 tAST_Node *AST_NewMethodCall(tParser *Parser, tAST_Node *Object, const char *Name)
672 tAST_Node *ret = AST_int_AllocateNode(Parser, NODETYPE_METHODCALL, strlen(Name) + 1 );
674 ret->FunctionCall.Object = Object;
675 ret->FunctionCall.FirstArg = NULL;
676 ret->FunctionCall.LastArg = NULL;
677 ret->FunctionCall.NumArgs = 0;
678 strcpy(ret->FunctionCall.Name, Name);
683 tAST_Node *AST_NewCreateObject(tParser *Parser, const char *Name)
685 tAST_Node *ret = AST_int_AllocateNode(Parser, NODETYPE_CREATEOBJECT, strlen(Name) + 1 );
687 ret->FunctionCall.Object = NULL;
688 ret->FunctionCall.FirstArg = NULL;
689 ret->FunctionCall.LastArg = NULL;
690 ret->FunctionCall.NumArgs = 0;
691 strcpy(ret->FunctionCall.Name, Name);
697 * \brief Append an argument to a function call
699 void AST_AppendFunctionCallArg(tAST_Node *Node, tAST_Node *Arg)
701 if( Node->Type != NODETYPE_FUNCTIONCALL
702 && Node->Type != NODETYPE_CREATEOBJECT
703 && Node->Type != NODETYPE_METHODCALL)
705 fprintf(stderr, "BUG REPORT: AST_AppendFunctionCallArg on an invalid node type (%i)\n", Node->Type);
709 if(Node->FunctionCall.LastArg) {
710 Node->FunctionCall.LastArg->NextSibling = Arg;
711 Node->FunctionCall.LastArg = Arg;
714 Node->FunctionCall.FirstArg = Arg;
715 Node->FunctionCall.LastArg = Arg;
717 Node->FunctionCall.NumArgs ++;
721 * \brief Add a scope node
723 tAST_Node *AST_NewScopeDereference(tParser *Parser, const char *Name, tAST_Node *Child)
725 tAST_Node *ret = AST_int_AllocateNode(Parser, NODETYPE_SCOPE, strlen(Name) + 1 );
726 ret->Scope.Element = Child;
727 strcpy(ret->Scope.Name, Name);
732 * \brief Add a scope node
734 tAST_Node *AST_NewClassElement(tParser *Parser, tAST_Node *Object, const char *Name)
736 tAST_Node *ret = AST_int_AllocateNode(Parser, NODETYPE_ELEMENT, strlen(Name) + 1 );
737 ret->Scope.Element = Object;
738 strcpy(ret->Scope.Name, Name);