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 );
33 strcpy(ret->Name, Name);
35 ret->Arguments = NULL;
36 ret->ReturnType = ReturnType;
38 if(Script->LastFunction == NULL) {
39 Script->Functions = Script->LastFunction = ret;
42 Script->LastFunction->Next = ret;
43 Script->LastFunction = ret;
49 void AST_AppendFunctionArg(tAST_Function *Function, tAST_Node *Node)
51 if( !Function->Arguments ) {
52 Function->Arguments_Last = Function->Arguments = Node;
55 Function->Arguments_Last->NextSibling = Node;
56 Function->Arguments_Last = Node;
61 * \brief Set the code for a function
63 void AST_SetFunctionCode(tAST_Function *Function, tAST_Node *Root)
65 Function->Code = Root;
69 * \name Node Manipulation
72 #define WRITE_N(_buffer, _offset, _len, _dataptr) do { \
73 if(_buffer) memcpy((char*)_buffer + _offset, _dataptr, _len);\
77 #define WRITE_8(_buffer, _offset, _val) do {\
79 WRITE_N(_buffer, _offset, 1, &v);\
81 #define WRITE_16(_buffer, _offset, _val) do {\
83 WRITE_N(_buffer, _offset, 2, &v);\
85 #define WRITE_32(_buffer, _offset, _val) do {\
87 WRITE_N(_buffer, _offset, 4, &v);\
89 #define WRITE_64(_buffer, _offset, _val) do {\
91 WRITE_N(_buffer, _offset, 8, &v);\
93 #define WRITE_REAL(_buffer, _offset, _val) do {\
95 WRITE_N(_buffer, _offset, sizeof(double), &v);\
98 #define WRITE_STR(_buffer, _offset, _string) do {\
99 int len = strlen(_string);\
100 WRITE_16(_buffer, _offset, len);\
101 WRITE_N(_buffer, _offset, len, _string);\
102 if((_offset & 1) == 1)WRITE_8(_buffer, _offset, 0); \
103 if((_offset & 3) == 2)WRITE_16(_buffer, _offset, 0); \
105 #define WRITE_NODELIST(_buffer, _offset, _listHead) do {\
108 for(node=(_listHead); node; node = node->NextSibling) {\
110 _offset += AST_WriteNode(_buffer, _offset, node); \
111 WRITE_32(_buffer, ptr, ptr); \
113 if(ptr != -1){ptr -= 4; WRITE_32(_buffer, ptr, 0);} \
117 * \brief Writes a script dump to a buffer
118 * \return Size of encoded data
119 * \note If \a Buffer is NULL, no write is done, but the size is still returned
121 size_t AST_WriteScript(void *Buffer, tAST_Script *Script)
124 size_t ret = 0, ptr = 0;
126 for( fcn = Script->Functions; fcn; fcn = fcn->Next )
128 // printf("fcn = %p, fcn->Name = %p\n", fcn, fcn->Name);
130 WRITE_32(Buffer, ret, 0); // Next
131 WRITE_STR(Buffer, ret, fcn->Name);
132 WRITE_NODELIST(Buffer, ret, fcn->Arguments); // TODO: Cheaper way
133 ret += AST_WriteNode(Buffer, ret, fcn->Code);
134 WRITE_32(Buffer, ptr, ret); // Actually set next
139 WRITE_32(Buffer, ptr, 0); // Clear next for final
146 * \brief Write a node to a file
148 size_t AST_WriteNode(void *Buffer, size_t Offset, tAST_Node *Node)
150 size_t baseOfs = Offset;
153 //fprintf(stderr, "Possible Bug - NULL passed to AST_WriteNode\n");
154 WRITE_32(Buffer, Offset, 0);
155 WRITE_16(Buffer, Offset, NODETYPE_NOP);
156 WRITE_16(Buffer, Offset, 0); // Line (0)
160 WRITE_32(Buffer, Offset, 0); // Next
161 WRITE_16(Buffer, Offset, Node->Type);
162 // TODO: Scan the buffer for the location of the filename (with NULL byte)
163 // else, write the string at the end of the node
164 WRITE_16(Buffer, Offset, Node->Line); // Line
165 //WRITE_32(Buffer, Offset, 0); // File
171 WRITE_NODELIST(Buffer, Offset, Node->Block.FirstChild);
175 case NODETYPE_METHODCALL:
176 Offset += AST_WriteNode(Buffer, Offset, Node->FunctionCall.Object);
177 case NODETYPE_FUNCTIONCALL:
178 case NODETYPE_CREATEOBJECT:
179 // TODO: Search for the same function name and add a pointer
180 WRITE_STR(Buffer, Offset, Node->FunctionCall.Name);
181 WRITE_NODELIST(Buffer, Offset, Node->FunctionCall.FirstArg);
186 Offset += AST_WriteNode(Buffer, Offset, Node->If.Condition);
187 Offset += AST_WriteNode(Buffer, Offset, Node->If.True);
188 Offset += AST_WriteNode(Buffer, Offset, Node->If.False);
191 // Looping Construct (For loop node)
193 WRITE_8(Buffer, Offset, Node->For.bCheckAfter);
195 Offset += AST_WriteNode(Buffer, Offset, Node->For.Init);
196 Offset += AST_WriteNode(Buffer, Offset, Node->For.Condition);
197 Offset += AST_WriteNode(Buffer, Offset, Node->For.Increment);
198 Offset += AST_WriteNode(Buffer, Offset, Node->For.Code);
202 case NODETYPE_ASSIGN:
203 WRITE_8(Buffer, Offset, Node->Assign.Operation);
204 Offset += AST_WriteNode(Buffer, Offset, Node->Assign.Dest);
205 Offset += AST_WriteNode(Buffer, Offset, Node->Assign.Value);
210 WRITE_8(Buffer, Offset, Node->Cast.DataType);
211 Offset += AST_WriteNode(Buffer, Offset, Node->Cast.Value);
215 case NODETYPE_DEFVAR:
216 WRITE_8(Buffer, Offset, Node->DefVar.DataType);
217 // TODO: Duplicate compress the strings
218 WRITE_STR(Buffer, Offset, Node->DefVar.Name);
220 WRITE_NODELIST(Buffer, Offset, Node->DefVar.LevelSizes);
221 Offset += AST_WriteNode(Buffer, Offset, Node->DefVar.InitialValue);
226 case NODETYPE_ELEMENT:
227 WRITE_STR(Buffer, Offset, Node->Scope.Name);
228 Offset += AST_WriteNode(Buffer, Offset, Node->UniOp.Value);
232 case NODETYPE_RETURN:
234 case NODETYPE_LOGICALNOT:
235 case NODETYPE_NEGATE:
236 case NODETYPE_POSTINC:
237 case NODETYPE_POSTDEC:
238 Offset += AST_WriteNode(Buffer, Offset, Node->UniOp.Value);
244 case NODETYPE_SUBTRACT:
245 case NODETYPE_MULTIPLY:
246 case NODETYPE_DIVIDE:
247 case NODETYPE_MODULO:
248 case NODETYPE_BITSHIFTLEFT:
249 case NODETYPE_BITSHIFTRIGHT:
250 case NODETYPE_BITROTATELEFT:
251 case NODETYPE_BWAND: case NODETYPE_LOGICALAND:
252 case NODETYPE_BWOR: case NODETYPE_LOGICALOR:
253 case NODETYPE_BWXOR: case NODETYPE_LOGICALXOR:
254 case NODETYPE_EQUALS:
255 case NODETYPE_LESSTHAN: case NODETYPE_LESSTHANEQUAL:
256 case NODETYPE_GREATERTHAN: case NODETYPE_GREATERTHANEQUAL:
257 Offset += AST_WriteNode(Buffer, Offset, Node->BinOp.Left);
258 Offset += AST_WriteNode(Buffer, Offset, Node->BinOp.Right);
261 // Node types with no children
264 case NODETYPE_VARIABLE:
265 case NODETYPE_CONSTANT:
266 // TODO: De-Duplicate the strings
267 WRITE_STR(Buffer, Offset, Node->Variable.Name);
269 case NODETYPE_STRING:
270 WRITE_32(Buffer, Offset, Node->Constant.String.Length);
271 WRITE_N(Buffer, Offset, Node->Constant.String.Length, Node->Constant.String.Data);
273 case NODETYPE_INTEGER:
274 WRITE_64(Buffer, Offset, Node->Constant.Integer);
277 WRITE_REAL(Buffer, Offset, Node->Constant.Real);
281 // fprintf(stderr, "AST_WriteNode: Unknown node type %i\n", Node->Type);
285 return Offset - baseOfs;
289 * \brief Free a node and all subnodes
291 void AST_FreeNode(tAST_Node *Node)
301 for( node = Node->Block.FirstChild; node; )
303 tAST_Node *savedNext = node->NextSibling;
310 case NODETYPE_METHODCALL:
311 AST_FreeNode(Node->FunctionCall.Object);
312 case NODETYPE_FUNCTIONCALL:
313 case NODETYPE_CREATEOBJECT:
314 for( node = Node->FunctionCall.FirstArg; node; )
316 tAST_Node *savedNext = node->NextSibling;
324 AST_FreeNode(Node->If.Condition);
325 AST_FreeNode(Node->If.True);
326 AST_FreeNode(Node->If.False);
329 // Looping Construct (For loop node)
331 AST_FreeNode(Node->For.Init);
332 AST_FreeNode(Node->For.Condition);
333 AST_FreeNode(Node->For.Increment);
334 AST_FreeNode(Node->For.Code);
338 case NODETYPE_ASSIGN:
339 AST_FreeNode(Node->Assign.Dest);
340 AST_FreeNode(Node->Assign.Value);
345 AST_FreeNode(Node->Cast.Value);
349 case NODETYPE_ELEMENT:
350 AST_FreeNode(Node->Scope.Element);
354 case NODETYPE_DEFVAR:
355 for( node = Node->DefVar.LevelSizes; node; )
357 tAST_Node *savedNext = node->NextSibling;
361 AST_FreeNode(Node->DefVar.InitialValue);
365 case NODETYPE_RETURN:
367 case NODETYPE_LOGICALNOT:
368 case NODETYPE_NEGATE:
369 case NODETYPE_POSTINC:
370 case NODETYPE_POSTDEC:
371 AST_FreeNode(Node->UniOp.Value);
377 case NODETYPE_SUBTRACT:
378 case NODETYPE_MULTIPLY:
379 case NODETYPE_DIVIDE:
380 case NODETYPE_MODULO:
381 case NODETYPE_BITSHIFTLEFT:
382 case NODETYPE_BITSHIFTRIGHT:
383 case NODETYPE_BITROTATELEFT:
384 case NODETYPE_BWAND: case NODETYPE_LOGICALAND:
385 case NODETYPE_BWOR: case NODETYPE_LOGICALOR:
386 case NODETYPE_BWXOR: case NODETYPE_LOGICALXOR:
387 case NODETYPE_EQUALS:
388 case NODETYPE_LESSTHAN: case NODETYPE_LESSTHANEQUAL:
389 case NODETYPE_GREATERTHAN: case NODETYPE_GREATERTHANEQUAL:
390 AST_FreeNode( Node->BinOp.Left );
391 AST_FreeNode( Node->BinOp.Right );
394 // Node types with no children
395 case NODETYPE_NOP: break;
396 case NODETYPE_VARIABLE: break;
397 case NODETYPE_CONSTANT: break;
399 case NODETYPE_STRING:
400 case NODETYPE_INTEGER:
402 if( Node->ValueCache )
403 Object_Dereference(Node->ValueCache);
404 Node->ValueCache = NULL;
410 tAST_Node *AST_int_AllocateNode(tParser *Parser, int Type, int ExtraSize)
412 tAST_Node *ret = malloc( sizeof(tAST_Node) + ExtraSize );
413 ret->NextSibling = NULL;
415 ret->Line = Parser->CurLine;
419 ret->BlockState = NULL;
421 ret->ValueCache = NULL;
426 tAST_Node *AST_NewCodeBlock(tParser *Parser)
428 tAST_Node *ret = AST_int_AllocateNode(Parser, NODETYPE_BLOCK, 0 );
430 ret->Block.FirstChild = NULL;
431 ret->Block.LastChild = NULL;
436 void AST_AppendNode(tAST_Node *Parent, tAST_Node *Child)
438 // Ignore NULL children
439 if( !Child ) return ;
441 Child->NextSibling = NULL;
442 switch( Parent->Type )
445 if(Parent->Block.FirstChild == NULL) {
446 Parent->Block.FirstChild = Parent->Block.LastChild = Child;
449 Parent->Block.LastChild->NextSibling = Child;
450 Parent->Block.LastChild = Child;
453 case NODETYPE_DEFVAR:
454 if(Parent->DefVar.LevelSizes == NULL) {
455 Parent->DefVar.LevelSizes = Parent->DefVar.LevelSizes_Last = Child;
458 Parent->DefVar.LevelSizes_Last->NextSibling = Child;
459 Parent->DefVar.LevelSizes_Last = Child;
463 fprintf(stderr, "BUG REPORT: AST_AppendNode on an invalid node type (%i)\n", Parent->Type);
468 tAST_Node *AST_NewIf(tParser *Parser, tAST_Node *Condition, tAST_Node *True, tAST_Node *False)
470 tAST_Node *ret = AST_int_AllocateNode(Parser, NODETYPE_IF, 0);
471 ret->If.Condition = Condition;
473 ret->If.False = False;
477 tAST_Node *AST_NewLoop(tParser *Parser, tAST_Node *Init, int bPostCheck, tAST_Node *Condition, tAST_Node *Increment, tAST_Node *Code)
479 tAST_Node *ret = AST_int_AllocateNode(Parser, NODETYPE_LOOP, 0);
480 ret->For.Init = Init;
481 ret->For.bCheckAfter = !!bPostCheck;
482 ret->For.Condition = Condition;
483 ret->For.Increment = Increment;
484 ret->For.Code = Code;
488 tAST_Node *AST_NewAssign(tParser *Parser, int Operation, tAST_Node *Dest, tAST_Node *Value)
490 tAST_Node *ret = AST_int_AllocateNode(Parser, NODETYPE_ASSIGN, 0);
492 if( Dest->Type != NODETYPE_VARIABLE && Dest->Type != NODETYPE_ELEMENT ) {
494 SyntaxError(Parser, 1, "Assign target is not a variable or attribute (instead %i)",
501 ret->Assign.Operation = Operation;
502 ret->Assign.Dest = Dest;
503 ret->Assign.Value = Value;
508 tAST_Node *AST_NewCast(tParser *Parser, int Target, tAST_Node *Value)
510 tAST_Node *ret = AST_int_AllocateNode(Parser, NODETYPE_CAST, 0);
512 ret->Cast.DataType = Target;
513 ret->Cast.Value = Value;
518 tAST_Node *AST_NewBinOp(tParser *Parser, int Operation, tAST_Node *Left, tAST_Node *Right)
520 tAST_Node *ret = AST_int_AllocateNode(Parser, Operation, 0);
522 ret->BinOp.Left = Left;
523 ret->BinOp.Right = Right;
530 tAST_Node *AST_NewUniOp(tParser *Parser, int Operation, tAST_Node *Value)
532 tAST_Node *ret = AST_int_AllocateNode(Parser, Operation, 0);
534 ret->UniOp.Value = Value;
539 tAST_Node *AST_NewNop(tParser *Parser)
541 tAST_Node *ret = AST_int_AllocateNode(Parser, NODETYPE_NOP, 0);
547 * \brief Create a new string node
549 tAST_Node *AST_NewString(tParser *Parser, const char *String, int Length)
551 tAST_Node *ret = AST_int_AllocateNode(Parser, NODETYPE_STRING, Length + 1);
553 ret->Constant.Type = SS_DATATYPE_STRING;
554 ret->Constant.ReferenceCount = 1;
555 ret->Constant.String.Length = Length;
556 memcpy(ret->Constant.String.Data, String, Length);
557 ret->Constant.String.Data[Length] = '\0';
563 * \brief Create a new integer node
565 tAST_Node *AST_NewInteger(tParser *Parser, int64_t Value)
567 tAST_Node *ret = AST_int_AllocateNode(Parser, NODETYPE_INTEGER, 0);
568 ret->Constant.Type = SS_DATATYPE_INTEGER;
569 ret->Constant.ReferenceCount = 1;
570 ret->Constant.Integer = Value;
575 * \brief Create a new real number node
577 tAST_Node *AST_NewReal(tParser *Parser, double Value)
579 tAST_Node *ret = AST_int_AllocateNode(Parser, NODETYPE_REAL, 0);
580 ret->Constant.Type = SS_DATATYPE_REAL;
581 ret->Constant.ReferenceCount = 1;
582 ret->Constant.Real = Value;
587 * \brief Create a new variable reference node
589 tAST_Node *AST_NewVariable(tParser *Parser, const char *Name)
591 tAST_Node *ret = AST_int_AllocateNode(Parser, NODETYPE_VARIABLE, strlen(Name) + 1 );
592 strcpy(ret->Variable.Name, Name);
597 * \brief Create a new variable definition node
599 tAST_Node *AST_NewDefineVar(tParser *Parser, int Type, const char *Name)
601 tAST_Node *ret = AST_int_AllocateNode(Parser, NODETYPE_DEFVAR, strlen(Name) + 1 );
603 ret->DefVar.DataType = Type;
604 ret->DefVar.LevelSizes = NULL;
605 ret->DefVar.LevelSizes_Last = NULL;
606 ret->DefVar.InitialValue = NULL;
607 strcpy(ret->DefVar.Name, Name);
613 * \brief Create a new runtime constant reference node
615 tAST_Node *AST_NewConstant(tParser *Parser, const char *Name)
617 tAST_Node *ret = AST_int_AllocateNode(Parser, NODETYPE_CONSTANT, strlen(Name) + 1 );
619 strcpy(ret->Variable.Name, Name);
625 * \brief Create a function call node
626 * \note Argument list is manipulated using AST_AppendFunctionCallArg
628 tAST_Node *AST_NewFunctionCall(tParser *Parser, const char *Name)
630 tAST_Node *ret = AST_int_AllocateNode(Parser, NODETYPE_FUNCTIONCALL, strlen(Name) + 1 );
632 ret->FunctionCall.Object = NULL;
633 ret->FunctionCall.FirstArg = NULL;
634 ret->FunctionCall.LastArg = NULL;
635 ret->FunctionCall.NumArgs = 0;
636 strcpy(ret->FunctionCall.Name, Name);
640 tAST_Node *AST_NewMethodCall(tParser *Parser, tAST_Node *Object, const char *Name)
642 tAST_Node *ret = AST_int_AllocateNode(Parser, NODETYPE_METHODCALL, strlen(Name) + 1 );
644 ret->FunctionCall.Object = Object;
645 ret->FunctionCall.FirstArg = NULL;
646 ret->FunctionCall.LastArg = NULL;
647 ret->FunctionCall.NumArgs = 0;
648 strcpy(ret->FunctionCall.Name, Name);
653 tAST_Node *AST_NewCreateObject(tParser *Parser, const char *Name)
655 tAST_Node *ret = AST_int_AllocateNode(Parser, NODETYPE_CREATEOBJECT, strlen(Name) + 1 );
657 ret->FunctionCall.Object = NULL;
658 ret->FunctionCall.FirstArg = NULL;
659 ret->FunctionCall.LastArg = NULL;
660 ret->FunctionCall.NumArgs = 0;
661 strcpy(ret->FunctionCall.Name, Name);
667 * \brief Append an argument to a function call
669 void AST_AppendFunctionCallArg(tAST_Node *Node, tAST_Node *Arg)
671 if( Node->Type != NODETYPE_FUNCTIONCALL
672 && Node->Type != NODETYPE_CREATEOBJECT
673 && Node->Type != NODETYPE_METHODCALL)
675 fprintf(stderr, "BUG REPORT: AST_AppendFunctionCallArg on an invalid node type (%i)\n", Node->Type);
679 if(Node->FunctionCall.LastArg) {
680 Node->FunctionCall.LastArg->NextSibling = Arg;
681 Node->FunctionCall.LastArg = Arg;
684 Node->FunctionCall.FirstArg = Arg;
685 Node->FunctionCall.LastArg = Arg;
687 Node->FunctionCall.NumArgs ++;
691 * \brief Add a scope node
693 tAST_Node *AST_NewScopeDereference(tParser *Parser, const char *Name, tAST_Node *Child)
695 tAST_Node *ret = AST_int_AllocateNode(Parser, NODETYPE_SCOPE, strlen(Name) + 1 );
696 ret->Scope.Element = Child;
697 strcpy(ret->Scope.Name, Name);
702 * \brief Add a scope node
704 tAST_Node *AST_NewClassElement(tParser *Parser, tAST_Node *Object, const char *Name)
706 tAST_Node *ret = AST_int_AllocateNode(Parser, NODETYPE_ELEMENT, strlen(Name) + 1 );
707 ret->Scope.Element = Object;
708 strcpy(ret->Scope.Name, Name);