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->ReturnType = ReturnType;
40 if(Script->LastFunction == NULL) {
41 Script->Functions = Script->LastFunction = ret;
44 Script->LastFunction->Next = ret;
45 Script->LastFunction = ret;
51 void AST_AppendFunctionArg(tAST_Function *Function, tAST_Node *Node)
53 if( !Function->Arguments ) {
54 Function->Arguments_Last = Function->Arguments = Node;
57 Function->Arguments_Last->NextSibling = Node;
58 Function->Arguments_Last = Node;
63 * \brief Set the code for a function
65 void AST_SetFunctionCode(tAST_Function *Function, tAST_Node *Root)
67 Function->Code = Root;
71 * \name Node Manipulation
74 #define WRITE_N(_buffer, _offset, _len, _dataptr) do { \
75 if(_buffer) memcpy((char*)_buffer + _offset, _dataptr, _len);\
79 #define WRITE_8(_buffer, _offset, _val) do {\
81 WRITE_N(_buffer, _offset, 1, &v);\
83 #define WRITE_16(_buffer, _offset, _val) do {\
85 WRITE_N(_buffer, _offset, 2, &v);\
87 #define WRITE_32(_buffer, _offset, _val) do {\
89 WRITE_N(_buffer, _offset, 4, &v);\
91 #define WRITE_64(_buffer, _offset, _val) do {\
93 WRITE_N(_buffer, _offset, 8, &v);\
95 #define WRITE_REAL(_buffer, _offset, _val) do {\
97 WRITE_N(_buffer, _offset, sizeof(double), &v);\
100 #define WRITE_STR(_buffer, _offset, _string) do {\
101 int len = strlen(_string);\
102 WRITE_16(_buffer, _offset, len);\
103 WRITE_N(_buffer, _offset, len, _string);\
104 if((_offset & 1) == 1)WRITE_8(_buffer, _offset, 0); \
105 if((_offset & 3) == 2)WRITE_16(_buffer, _offset, 0); \
107 #define WRITE_NODELIST(_buffer, _offset, _listHead) do {\
110 for(node=(_listHead); node; node = node->NextSibling) {\
112 _offset += AST_WriteNode(_buffer, _offset, node); \
113 WRITE_32(_buffer, ptr, ptr); \
115 if(ptr != -1){ptr -= 4; WRITE_32(_buffer, ptr, 0);} \
119 * \brief Writes a script dump to a buffer
120 * \return Size of encoded data
121 * \note If \a Buffer is NULL, no write is done, but the size is still returned
123 size_t AST_WriteScript(void *Buffer, tAST_Script *Script)
126 size_t ret = 0, ptr = 0;
128 for( fcn = Script->Functions; fcn; fcn = fcn->Next )
130 // printf("fcn = %p, fcn->Name = %p\n", fcn, fcn->Name);
132 WRITE_32(Buffer, ret, 0); // Next
133 WRITE_STR(Buffer, ret, fcn->Name);
134 WRITE_NODELIST(Buffer, ret, fcn->Arguments); // TODO: Cheaper way
135 ret += AST_WriteNode(Buffer, ret, fcn->Code);
136 WRITE_32(Buffer, ptr, ret); // Actually set next
141 WRITE_32(Buffer, ptr, 0); // Clear next for final
148 * \brief Write a node to a file
150 size_t AST_WriteNode(void *Buffer, size_t Offset, tAST_Node *Node)
152 size_t baseOfs = Offset;
155 //fprintf(stderr, "Possible Bug - NULL passed to AST_WriteNode\n");
156 WRITE_32(Buffer, Offset, 0);
157 WRITE_16(Buffer, Offset, NODETYPE_NOP);
158 WRITE_16(Buffer, Offset, 0); // Line (0)
162 WRITE_32(Buffer, Offset, 0); // Next
163 WRITE_16(Buffer, Offset, Node->Type);
164 // TODO: Scan the buffer for the location of the filename (with NULL byte)
165 // else, write the string at the end of the node
166 WRITE_16(Buffer, Offset, Node->Line); // Line
167 //WRITE_32(Buffer, Offset, 0); // File
173 WRITE_NODELIST(Buffer, Offset, Node->Block.FirstChild);
177 case NODETYPE_METHODCALL:
178 Offset += AST_WriteNode(Buffer, Offset, Node->FunctionCall.Object);
179 case NODETYPE_FUNCTIONCALL:
180 case NODETYPE_CREATEOBJECT:
181 // TODO: Search for the same function name and add a pointer
182 WRITE_STR(Buffer, Offset, Node->FunctionCall.Name);
183 WRITE_NODELIST(Buffer, Offset, Node->FunctionCall.FirstArg);
188 Offset += AST_WriteNode(Buffer, Offset, Node->If.Condition);
189 Offset += AST_WriteNode(Buffer, Offset, Node->If.True);
190 Offset += AST_WriteNode(Buffer, Offset, Node->If.False);
193 // Looping Construct (For loop node)
195 WRITE_8(Buffer, Offset, Node->For.bCheckAfter);
196 WRITE_STR(Buffer, Offset, Node->For.Tag);
197 Offset += AST_WriteNode(Buffer, Offset, Node->For.Init);
198 Offset += AST_WriteNode(Buffer, Offset, Node->For.Condition);
199 Offset += AST_WriteNode(Buffer, Offset, Node->For.Increment);
200 Offset += AST_WriteNode(Buffer, Offset, Node->For.Code);
204 case NODETYPE_ASSIGN:
205 WRITE_8(Buffer, Offset, Node->Assign.Operation);
206 Offset += AST_WriteNode(Buffer, Offset, Node->Assign.Dest);
207 Offset += AST_WriteNode(Buffer, Offset, Node->Assign.Value);
212 WRITE_8(Buffer, Offset, Node->Cast.DataType);
213 Offset += AST_WriteNode(Buffer, Offset, Node->Cast.Value);
217 case NODETYPE_DEFVAR:
218 WRITE_8(Buffer, Offset, Node->DefVar.DataType);
219 // TODO: Duplicate compress the strings
220 WRITE_STR(Buffer, Offset, Node->DefVar.Name);
222 WRITE_NODELIST(Buffer, Offset, Node->DefVar.LevelSizes);
223 Offset += AST_WriteNode(Buffer, Offset, Node->DefVar.InitialValue);
228 case NODETYPE_ELEMENT:
229 WRITE_STR(Buffer, Offset, Node->Scope.Name);
230 Offset += AST_WriteNode(Buffer, Offset, Node->UniOp.Value);
234 case NODETYPE_RETURN:
236 case NODETYPE_LOGICALNOT:
237 case NODETYPE_NEGATE:
238 case NODETYPE_POSTINC:
239 case NODETYPE_POSTDEC:
240 Offset += AST_WriteNode(Buffer, Offset, Node->UniOp.Value);
246 case NODETYPE_SUBTRACT:
247 case NODETYPE_MULTIPLY:
248 case NODETYPE_DIVIDE:
249 case NODETYPE_MODULO:
250 case NODETYPE_BITSHIFTLEFT:
251 case NODETYPE_BITSHIFTRIGHT:
252 case NODETYPE_BITROTATELEFT:
253 case NODETYPE_BWAND: case NODETYPE_LOGICALAND:
254 case NODETYPE_BWOR: case NODETYPE_LOGICALOR:
255 case NODETYPE_BWXOR: case NODETYPE_LOGICALXOR:
256 case NODETYPE_EQUALS:
257 case NODETYPE_LESSTHAN: case NODETYPE_LESSTHANEQUAL:
258 case NODETYPE_GREATERTHAN: case NODETYPE_GREATERTHANEQUAL:
259 Offset += AST_WriteNode(Buffer, Offset, Node->BinOp.Left);
260 Offset += AST_WriteNode(Buffer, Offset, Node->BinOp.Right);
263 // Node types with no children
266 case NODETYPE_VARIABLE:
267 case NODETYPE_CONSTANT:
269 case NODETYPE_CONTINUE:
270 // TODO: De-Duplicate the strings
271 WRITE_STR(Buffer, Offset, Node->Variable.Name);
273 case NODETYPE_STRING:
274 WRITE_32(Buffer, Offset, Node->Constant.String.Length);
275 WRITE_N(Buffer, Offset, Node->Constant.String.Length, Node->Constant.String.Data);
277 case NODETYPE_INTEGER:
278 WRITE_64(Buffer, Offset, Node->Constant.Integer);
281 WRITE_REAL(Buffer, Offset, Node->Constant.Real);
285 // fprintf(stderr, "AST_WriteNode: Unknown node type %i\n", Node->Type);
289 return Offset - baseOfs;
293 * \brief Free a node and all subnodes
295 void AST_FreeNode(tAST_Node *Node)
301 // Referenced counted file name
302 (*(int*)(Node->File - sizeof(int))) -= 1;
303 if( *(int*)(Node->File - sizeof(int)) == 0 )
304 free( (void*)(Node->File - sizeof(int)) );
310 for( node = Node->Block.FirstChild; node; )
312 tAST_Node *savedNext = node->NextSibling;
319 case NODETYPE_METHODCALL:
320 AST_FreeNode(Node->FunctionCall.Object);
321 case NODETYPE_FUNCTIONCALL:
322 case NODETYPE_CREATEOBJECT:
323 for( node = Node->FunctionCall.FirstArg; node; )
325 tAST_Node *savedNext = node->NextSibling;
333 AST_FreeNode(Node->If.Condition);
334 AST_FreeNode(Node->If.True);
335 AST_FreeNode(Node->If.False);
338 // Looping Construct (For loop node)
340 AST_FreeNode(Node->For.Init);
341 AST_FreeNode(Node->For.Condition);
342 AST_FreeNode(Node->For.Increment);
343 AST_FreeNode(Node->For.Code);
347 case NODETYPE_ASSIGN:
348 AST_FreeNode(Node->Assign.Dest);
349 AST_FreeNode(Node->Assign.Value);
354 AST_FreeNode(Node->Cast.Value);
358 case NODETYPE_ELEMENT:
359 AST_FreeNode(Node->Scope.Element);
363 case NODETYPE_DEFVAR:
364 for( node = Node->DefVar.LevelSizes; node; )
366 tAST_Node *savedNext = node->NextSibling;
370 AST_FreeNode(Node->DefVar.InitialValue);
374 case NODETYPE_RETURN:
376 case NODETYPE_LOGICALNOT:
377 case NODETYPE_NEGATE:
378 case NODETYPE_POSTINC:
379 case NODETYPE_POSTDEC:
380 AST_FreeNode(Node->UniOp.Value);
386 case NODETYPE_SUBTRACT:
387 case NODETYPE_MULTIPLY:
388 case NODETYPE_DIVIDE:
389 case NODETYPE_MODULO:
390 case NODETYPE_BITSHIFTLEFT:
391 case NODETYPE_BITSHIFTRIGHT:
392 case NODETYPE_BITROTATELEFT:
393 case NODETYPE_BWAND: case NODETYPE_LOGICALAND:
394 case NODETYPE_BWOR: case NODETYPE_LOGICALOR:
395 case NODETYPE_BWXOR: case NODETYPE_LOGICALXOR:
396 case NODETYPE_EQUALS:
397 case NODETYPE_LESSTHAN: case NODETYPE_LESSTHANEQUAL:
398 case NODETYPE_GREATERTHAN: case NODETYPE_GREATERTHANEQUAL:
399 AST_FreeNode( Node->BinOp.Left );
400 AST_FreeNode( Node->BinOp.Right );
403 // Node types with no children
404 case NODETYPE_NOP: break;
405 case NODETYPE_VARIABLE: break;
406 case NODETYPE_CONSTANT: break;
407 case NODETYPE_BREAK: break;
408 case NODETYPE_CONTINUE: break;
410 case NODETYPE_STRING:
411 case NODETYPE_INTEGER:
413 if( Node->ValueCache )
414 Object_Dereference(Node->ValueCache);
415 Node->ValueCache = NULL;
421 tAST_Node *AST_int_AllocateNode(tParser *Parser, int Type, int ExtraSize)
423 tAST_Node *ret = malloc( sizeof(tAST_Node) + ExtraSize );
424 ret->NextSibling = NULL;
425 ret->File = Parser->Filename; *(int*)(Parser->Filename - sizeof(int)) += 1;
426 ret->Line = Parser->CurLine;
430 ret->BlockState = NULL;
432 ret->ValueCache = NULL;
437 tAST_Node *AST_NewCodeBlock(tParser *Parser)
439 tAST_Node *ret = AST_int_AllocateNode(Parser, NODETYPE_BLOCK, 0 );
441 ret->Block.FirstChild = NULL;
442 ret->Block.LastChild = NULL;
447 void AST_AppendNode(tAST_Node *Parent, tAST_Node *Child)
449 // Ignore NULL children
450 if( !Child ) return ;
452 Child->NextSibling = NULL;
453 switch( Parent->Type )
456 if(Parent->Block.FirstChild == NULL) {
457 Parent->Block.FirstChild = Parent->Block.LastChild = Child;
460 Parent->Block.LastChild->NextSibling = Child;
461 Parent->Block.LastChild = Child;
464 case NODETYPE_DEFVAR:
465 if(Parent->DefVar.LevelSizes == NULL) {
466 Parent->DefVar.LevelSizes = Parent->DefVar.LevelSizes_Last = Child;
469 Parent->DefVar.LevelSizes_Last->NextSibling = Child;
470 Parent->DefVar.LevelSizes_Last = Child;
474 fprintf(stderr, "BUG REPORT: AST_AppendNode on an invalid node type (%i)\n", Parent->Type);
479 tAST_Node *AST_NewIf(tParser *Parser, tAST_Node *Condition, tAST_Node *True, tAST_Node *False)
481 tAST_Node *ret = AST_int_AllocateNode(Parser, NODETYPE_IF, 0);
482 ret->If.Condition = Condition;
484 ret->If.False = False;
488 tAST_Node *AST_NewLoop(tParser *Parser, const char *Tag, tAST_Node *Init, int bPostCheck, tAST_Node *Condition, tAST_Node *Increment, tAST_Node *Code)
490 tAST_Node *ret = AST_int_AllocateNode(Parser, NODETYPE_LOOP, strlen(Tag) + 1);
491 ret->For.Init = Init;
492 ret->For.bCheckAfter = !!bPostCheck;
493 ret->For.Condition = Condition;
494 ret->For.Increment = Increment;
495 ret->For.Code = Code;
496 strcpy(ret->For.Tag, Tag);
500 tAST_Node *AST_NewAssign(tParser *Parser, int Operation, tAST_Node *Dest, tAST_Node *Value)
502 tAST_Node *ret = AST_int_AllocateNode(Parser, NODETYPE_ASSIGN, 0);
504 if( Dest->Type != NODETYPE_VARIABLE && Dest->Type != NODETYPE_ELEMENT ) {
506 SyntaxError(Parser, 1, "Assign target is not a variable or attribute (instead %i)",
513 ret->Assign.Operation = Operation;
514 ret->Assign.Dest = Dest;
515 ret->Assign.Value = Value;
520 tAST_Node *AST_NewCast(tParser *Parser, int Target, tAST_Node *Value)
522 tAST_Node *ret = AST_int_AllocateNode(Parser, NODETYPE_CAST, 0);
524 ret->Cast.DataType = Target;
525 ret->Cast.Value = Value;
530 tAST_Node *AST_NewBinOp(tParser *Parser, int Operation, tAST_Node *Left, tAST_Node *Right)
532 tAST_Node *ret = AST_int_AllocateNode(Parser, Operation, 0);
534 ret->BinOp.Left = Left;
535 ret->BinOp.Right = Right;
542 tAST_Node *AST_NewUniOp(tParser *Parser, int Operation, tAST_Node *Value)
544 tAST_Node *ret = AST_int_AllocateNode(Parser, Operation, 0);
546 ret->UniOp.Value = Value;
551 tAST_Node *AST_NewBreakout(tParser *Parser, int Type, const char *DestTag)
553 int len = (DestTag ? strlen(DestTag) : 0);
554 tAST_Node *ret = AST_int_AllocateNode(Parser, Type, len + 1);
557 strcpy(ret->Variable.Name, DestTag);
559 ret->Variable.Name[0] = '\0';
564 tAST_Node *AST_NewNop(tParser *Parser)
566 tAST_Node *ret = AST_int_AllocateNode(Parser, NODETYPE_NOP, 0);
572 * \brief Create a new string node
574 tAST_Node *AST_NewString(tParser *Parser, const char *String, int Length)
576 tAST_Node *ret = AST_int_AllocateNode(Parser, NODETYPE_STRING, Length + 1);
578 ret->Constant.Type = SS_DATATYPE_STRING;
579 ret->Constant.ReferenceCount = 1;
580 ret->Constant.String.Length = Length;
581 memcpy(ret->Constant.String.Data, String, Length);
582 ret->Constant.String.Data[Length] = '\0';
588 * \brief Create a new integer node
590 tAST_Node *AST_NewInteger(tParser *Parser, int64_t Value)
592 tAST_Node *ret = AST_int_AllocateNode(Parser, NODETYPE_INTEGER, 0);
593 ret->Constant.Type = SS_DATATYPE_INTEGER;
594 ret->Constant.ReferenceCount = 1;
595 ret->Constant.Integer = Value;
600 * \brief Create a new real number node
602 tAST_Node *AST_NewReal(tParser *Parser, double Value)
604 tAST_Node *ret = AST_int_AllocateNode(Parser, NODETYPE_REAL, 0);
605 ret->Constant.Type = SS_DATATYPE_REAL;
606 ret->Constant.ReferenceCount = 1;
607 ret->Constant.Real = Value;
612 * \brief Create a new variable reference node
614 tAST_Node *AST_NewVariable(tParser *Parser, const char *Name)
616 tAST_Node *ret = AST_int_AllocateNode(Parser, NODETYPE_VARIABLE, strlen(Name) + 1 );
617 strcpy(ret->Variable.Name, Name);
622 * \brief Create a new variable definition node
624 tAST_Node *AST_NewDefineVar(tParser *Parser, int Type, const char *Name)
626 tAST_Node *ret = AST_int_AllocateNode(Parser, NODETYPE_DEFVAR, strlen(Name) + 1 );
628 ret->DefVar.DataType = Type;
629 ret->DefVar.LevelSizes = NULL;
630 ret->DefVar.LevelSizes_Last = NULL;
631 ret->DefVar.InitialValue = NULL;
632 strcpy(ret->DefVar.Name, Name);
638 * \brief Create a new runtime constant reference node
640 tAST_Node *AST_NewConstant(tParser *Parser, const char *Name)
642 tAST_Node *ret = AST_int_AllocateNode(Parser, NODETYPE_CONSTANT, strlen(Name) + 1 );
644 strcpy(ret->Variable.Name, Name);
650 * \brief Create a function call node
651 * \note Argument list is manipulated using AST_AppendFunctionCallArg
653 tAST_Node *AST_NewFunctionCall(tParser *Parser, const char *Name)
655 tAST_Node *ret = AST_int_AllocateNode(Parser, NODETYPE_FUNCTIONCALL, 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);
665 tAST_Node *AST_NewMethodCall(tParser *Parser, tAST_Node *Object, const char *Name)
667 tAST_Node *ret = AST_int_AllocateNode(Parser, NODETYPE_METHODCALL, strlen(Name) + 1 );
669 ret->FunctionCall.Object = Object;
670 ret->FunctionCall.FirstArg = NULL;
671 ret->FunctionCall.LastArg = NULL;
672 ret->FunctionCall.NumArgs = 0;
673 strcpy(ret->FunctionCall.Name, Name);
678 tAST_Node *AST_NewCreateObject(tParser *Parser, const char *Name)
680 tAST_Node *ret = AST_int_AllocateNode(Parser, NODETYPE_CREATEOBJECT, strlen(Name) + 1 );
682 ret->FunctionCall.Object = NULL;
683 ret->FunctionCall.FirstArg = NULL;
684 ret->FunctionCall.LastArg = NULL;
685 ret->FunctionCall.NumArgs = 0;
686 strcpy(ret->FunctionCall.Name, Name);
692 * \brief Append an argument to a function call
694 void AST_AppendFunctionCallArg(tAST_Node *Node, tAST_Node *Arg)
696 if( Node->Type != NODETYPE_FUNCTIONCALL
697 && Node->Type != NODETYPE_CREATEOBJECT
698 && Node->Type != NODETYPE_METHODCALL)
700 fprintf(stderr, "BUG REPORT: AST_AppendFunctionCallArg on an invalid node type (%i)\n", Node->Type);
704 if(Node->FunctionCall.LastArg) {
705 Node->FunctionCall.LastArg->NextSibling = Arg;
706 Node->FunctionCall.LastArg = Arg;
709 Node->FunctionCall.FirstArg = Arg;
710 Node->FunctionCall.LastArg = Arg;
712 Node->FunctionCall.NumArgs ++;
716 * \brief Add a scope node
718 tAST_Node *AST_NewScopeDereference(tParser *Parser, const char *Name, tAST_Node *Child)
720 tAST_Node *ret = AST_int_AllocateNode(Parser, NODETYPE_SCOPE, strlen(Name) + 1 );
721 ret->Scope.Element = Child;
722 strcpy(ret->Scope.Name, Name);
727 * \brief Add a scope node
729 tAST_Node *AST_NewClassElement(tParser *Parser, tAST_Node *Object, const char *Name)
731 tAST_Node *ret = AST_int_AllocateNode(Parser, NODETYPE_ELEMENT, strlen(Name) + 1 );
732 ret->Scope.Element = Object;
733 strcpy(ret->Scope.Name, Name);