3 * - Script AST Manipulator
11 tAST_Script *AST_NewScript(void)
13 tAST_Script *ret = malloc( sizeof(tAST_Script) );
15 ret->Functions = NULL;
16 ret->LastFunction = NULL;
22 * \brief Append a function to a script
24 tAST_Function *AST_AppendFunction(tAST_Script *Script, const char *Name)
28 ret = malloc( sizeof(tAST_Function) + strlen(Name) + 1 );
30 strcpy(ret->Name, Name);
32 ret->Arguments = NULL;
34 if(Script->LastFunction == NULL) {
35 Script->Functions = Script->LastFunction = ret;
38 Script->LastFunction->Next = ret;
39 Script->LastFunction = ret;
45 void AST_AppendFunctionArg(tAST_Function *Function, tAST_Node *Node)
47 if( !Function->Arguments ) {
48 Function->Arguments_Last = Function->Arguments = Node;
51 Function->Arguments_Last->NextSibling = Node;
52 Function->Arguments_Last = Node;
57 * \brief Set the code for a function
59 void AST_SetFunctionCode(tAST_Function *Function, tAST_Node *Root)
61 Function->Code = Root;
65 * \name Node Manipulation
68 #define WRITE_N(_buffer, _offset, _len, _dataptr) do { \
69 if(_buffer) memcpy((char*)_buffer + _offset, _dataptr, _len);\
73 #define WRITE_8(_buffer, _offset, _val) do {\
75 WRITE_N(_buffer, _offset, 1, &v);\
77 #define WRITE_16(_buffer, _offset, _val) do {\
79 WRITE_N(_buffer, _offset, 2, &v);\
81 #define WRITE_32(_buffer, _offset, _val) do {\
83 WRITE_N(_buffer, _offset, 4, &v);\
85 #define WRITE_64(_buffer, _offset, _val) do {\
87 WRITE_N(_buffer, _offset, 8, &v);\
89 #define WRITE_REAL(_buffer, _offset, _val) do {\
91 WRITE_N(_buffer, _offset, sizeof(double), &v);\
94 #define WRITE_STR(_buffer, _offset, _string) do {\
95 int len = strlen(_string);\
96 WRITE_16(_buffer, _offset, len);\
97 WRITE_N(_buffer, _offset, len, _string);\
98 if((_offset & 1) == 1)WRITE_8(_buffer, _offset, 0); \
99 if((_offset & 3) == 2)WRITE_16(_buffer, _offset, 0); \
101 #define WRITE_NODELIST(_buffer, _offset, _listHead) do {\
104 for(node=(_listHead); node; node = node->NextSibling) {\
106 _offset += AST_WriteNode(_buffer, _offset, node); \
107 WRITE_32(_buffer, ptr, ptr); \
109 if(ptr != -1){ptr -= 4; WRITE_32(_buffer, ptr, 0);} \
113 * \brief Writes a script dump to a buffer
114 * \return Size of encoded data
115 * \note If \a Buffer is NULL, no write is done, but the size is still returned
117 size_t AST_WriteScript(void *Buffer, tAST_Script *Script)
120 size_t ret = 0, ptr = 0;
122 for( fcn = Script->Functions; fcn; fcn = fcn->Next )
124 // printf("fcn = %p, fcn->Name = %p\n", fcn, fcn->Name);
126 WRITE_32(Buffer, ret, 0); // Next
127 WRITE_STR(Buffer, ret, fcn->Name);
128 WRITE_NODELIST(Buffer, ret, fcn->Arguments); // TODO: Cheaper way
129 ret += AST_WriteNode(Buffer, ret, fcn->Code);
130 WRITE_32(Buffer, ptr, ret); // Actually set next
135 WRITE_32(Buffer, ptr, 0); // Clear next for final
142 * \brief Write a node to a file
144 size_t AST_WriteNode(void *Buffer, size_t Offset, tAST_Node *Node)
146 size_t baseOfs = Offset;
149 //fprintf(stderr, "Possible Bug - NULL passed to AST_WriteNode\n");
150 WRITE_32(Buffer, Offset, 0);
151 WRITE_16(Buffer, Offset, NODETYPE_NOP);
152 WRITE_16(Buffer, Offset, 0); // Line (0)
156 WRITE_32(Buffer, Offset, 0); // Next
157 WRITE_16(Buffer, Offset, Node->Type);
158 // TODO: Scan the buffer for the location of the filename (with NULL byte)
159 // else, write the string at the end of the node
160 WRITE_16(Buffer, Offset, Node->Line); // Line
161 //WRITE_32(Buffer, Offset, 0); // File
167 WRITE_NODELIST(Buffer, Offset, Node->Block.FirstChild);
171 case NODETYPE_METHODCALL:
172 Offset += AST_WriteNode(Buffer, Offset, Node->FunctionCall.Object);
173 case NODETYPE_FUNCTIONCALL:
174 case NODETYPE_CREATEOBJECT:
175 // TODO: Search for the same function name and add a pointer
176 WRITE_STR(Buffer, Offset, Node->FunctionCall.Name);
177 WRITE_NODELIST(Buffer, Offset, Node->FunctionCall.FirstArg);
182 Offset += AST_WriteNode(Buffer, Offset, Node->If.Condition);
183 Offset += AST_WriteNode(Buffer, Offset, Node->If.True);
184 Offset += AST_WriteNode(Buffer, Offset, Node->If.False);
187 // Looping Construct (For loop node)
189 WRITE_8(Buffer, Offset, Node->For.bCheckAfter);
191 Offset += AST_WriteNode(Buffer, Offset, Node->For.Init);
192 Offset += AST_WriteNode(Buffer, Offset, Node->For.Condition);
193 Offset += AST_WriteNode(Buffer, Offset, Node->For.Increment);
194 Offset += AST_WriteNode(Buffer, Offset, Node->For.Code);
198 case NODETYPE_ASSIGN:
199 WRITE_8(Buffer, Offset, Node->Assign.Operation);
200 Offset += AST_WriteNode(Buffer, Offset, Node->Assign.Dest);
201 Offset += AST_WriteNode(Buffer, Offset, Node->Assign.Value);
206 WRITE_8(Buffer, Offset, Node->Cast.DataType);
207 Offset += AST_WriteNode(Buffer, Offset, Node->Cast.Value);
211 case NODETYPE_DEFVAR:
212 WRITE_8(Buffer, Offset, Node->DefVar.DataType);
213 // TODO: Duplicate compress the strings
214 WRITE_STR(Buffer, Offset, Node->DefVar.Name);
216 WRITE_NODELIST(Buffer, Offset, Node->DefVar.LevelSizes);
217 Offset += AST_WriteNode(Buffer, Offset, Node->DefVar.InitialValue);
222 case NODETYPE_ELEMENT:
223 WRITE_STR(Buffer, Offset, Node->Scope.Name);
224 Offset += AST_WriteNode(Buffer, Offset, Node->UniOp.Value);
228 case NODETYPE_RETURN:
230 case NODETYPE_LOGICALNOT:
231 case NODETYPE_NEGATE:
232 case NODETYPE_POSTINC:
233 case NODETYPE_POSTDEC:
234 Offset += AST_WriteNode(Buffer, Offset, Node->UniOp.Value);
240 case NODETYPE_SUBTRACT:
241 case NODETYPE_MULTIPLY:
242 case NODETYPE_DIVIDE:
243 case NODETYPE_MODULO:
244 case NODETYPE_BITSHIFTLEFT:
245 case NODETYPE_BITSHIFTRIGHT:
246 case NODETYPE_BITROTATELEFT:
247 case NODETYPE_BWAND: case NODETYPE_LOGICALAND:
248 case NODETYPE_BWOR: case NODETYPE_LOGICALOR:
249 case NODETYPE_BWXOR: case NODETYPE_LOGICALXOR:
250 case NODETYPE_EQUALS:
251 case NODETYPE_LESSTHAN: case NODETYPE_LESSTHANEQUAL:
252 case NODETYPE_GREATERTHAN: case NODETYPE_GREATERTHANEQUAL:
253 Offset += AST_WriteNode(Buffer, Offset, Node->BinOp.Left);
254 Offset += AST_WriteNode(Buffer, Offset, Node->BinOp.Right);
257 // Node types with no children
260 case NODETYPE_VARIABLE:
261 case NODETYPE_CONSTANT:
262 // TODO: De-Duplicate the strings
263 WRITE_STR(Buffer, Offset, Node->Variable.Name);
265 case NODETYPE_STRING:
266 WRITE_32(Buffer, Offset, Node->Constant.String.Length);
267 WRITE_N(Buffer, Offset, Node->Constant.String.Length, Node->Constant.String.Data);
269 case NODETYPE_INTEGER:
270 WRITE_64(Buffer, Offset, Node->Constant.Integer);
273 WRITE_REAL(Buffer, Offset, Node->Constant.Real);
277 // fprintf(stderr, "AST_WriteNode: Unknown node type %i\n", Node->Type);
281 return Offset - baseOfs;
285 * \brief Free a node and all subnodes
287 void AST_FreeNode(tAST_Node *Node)
297 for( node = Node->Block.FirstChild; node; )
299 tAST_Node *savedNext = node->NextSibling;
306 case NODETYPE_METHODCALL:
307 AST_FreeNode(Node->FunctionCall.Object);
308 case NODETYPE_FUNCTIONCALL:
309 case NODETYPE_CREATEOBJECT:
310 for( node = Node->FunctionCall.FirstArg; node; )
312 tAST_Node *savedNext = node->NextSibling;
320 AST_FreeNode(Node->If.Condition);
321 AST_FreeNode(Node->If.True);
322 AST_FreeNode(Node->If.False);
325 // Looping Construct (For loop node)
327 AST_FreeNode(Node->For.Init);
328 AST_FreeNode(Node->For.Condition);
329 AST_FreeNode(Node->For.Increment);
330 AST_FreeNode(Node->For.Code);
334 case NODETYPE_ASSIGN:
335 AST_FreeNode(Node->Assign.Dest);
336 AST_FreeNode(Node->Assign.Value);
341 AST_FreeNode(Node->Cast.Value);
345 case NODETYPE_ELEMENT:
346 AST_FreeNode(Node->Scope.Element);
350 case NODETYPE_DEFVAR:
351 for( node = Node->DefVar.LevelSizes; node; )
353 tAST_Node *savedNext = node->NextSibling;
357 AST_FreeNode(Node->DefVar.InitialValue);
361 case NODETYPE_RETURN:
363 case NODETYPE_LOGICALNOT:
364 case NODETYPE_NEGATE:
365 case NODETYPE_POSTINC:
366 case NODETYPE_POSTDEC:
367 AST_FreeNode(Node->UniOp.Value);
373 case NODETYPE_SUBTRACT:
374 case NODETYPE_MULTIPLY:
375 case NODETYPE_DIVIDE:
376 case NODETYPE_MODULO:
377 case NODETYPE_BITSHIFTLEFT:
378 case NODETYPE_BITSHIFTRIGHT:
379 case NODETYPE_BITROTATELEFT:
380 case NODETYPE_BWAND: case NODETYPE_LOGICALAND:
381 case NODETYPE_BWOR: case NODETYPE_LOGICALOR:
382 case NODETYPE_BWXOR: case NODETYPE_LOGICALXOR:
383 case NODETYPE_EQUALS:
384 case NODETYPE_LESSTHAN: case NODETYPE_LESSTHANEQUAL:
385 case NODETYPE_GREATERTHAN: case NODETYPE_GREATERTHANEQUAL:
386 AST_FreeNode( Node->BinOp.Left );
387 AST_FreeNode( Node->BinOp.Right );
390 // Node types with no children
391 case NODETYPE_NOP: break;
392 case NODETYPE_VARIABLE: break;
393 case NODETYPE_CONSTANT: break;
395 case NODETYPE_STRING:
396 case NODETYPE_INTEGER:
398 if( Node->ValueCache )
399 Object_Dereference(Node->ValueCache);
400 Node->ValueCache = NULL;
406 tAST_Node *AST_int_AllocateNode(tParser *Parser, int Type, int ExtraSize)
408 tAST_Node *ret = malloc( sizeof(tAST_Node) + ExtraSize );
409 ret->NextSibling = NULL;
411 ret->Line = Parser->CurLine;
415 ret->BlockState = NULL;
417 ret->ValueCache = NULL;
422 tAST_Node *AST_NewCodeBlock(tParser *Parser)
424 tAST_Node *ret = AST_int_AllocateNode(Parser, NODETYPE_BLOCK, 0 );
426 ret->Block.FirstChild = NULL;
427 ret->Block.LastChild = NULL;
432 void AST_AppendNode(tAST_Node *Parent, tAST_Node *Child)
434 Child->NextSibling = NULL;
435 switch( Parent->Type )
438 if(Parent->Block.FirstChild == NULL) {
439 Parent->Block.FirstChild = Parent->Block.LastChild = Child;
442 Parent->Block.LastChild->NextSibling = Child;
443 Parent->Block.LastChild = Child;
446 case NODETYPE_DEFVAR:
447 if(Parent->DefVar.LevelSizes == NULL) {
448 Parent->DefVar.LevelSizes = Parent->DefVar.LevelSizes_Last = Child;
451 Parent->DefVar.LevelSizes_Last->NextSibling = Child;
452 Parent->DefVar.LevelSizes_Last = Child;
456 fprintf(stderr, "BUG REPORT: AST_AppendNode on an invalid node type (%i)\n", Parent->Type);
461 tAST_Node *AST_NewIf(tParser *Parser, tAST_Node *Condition, tAST_Node *True, tAST_Node *False)
463 tAST_Node *ret = AST_int_AllocateNode(Parser, NODETYPE_IF, 0);
464 ret->If.Condition = Condition;
466 ret->If.False = False;
470 tAST_Node *AST_NewLoop(tParser *Parser, tAST_Node *Init, int bPostCheck, tAST_Node *Condition, tAST_Node *Increment, tAST_Node *Code)
472 tAST_Node *ret = AST_int_AllocateNode(Parser, NODETYPE_LOOP, 0);
473 ret->For.Init = Init;
474 ret->For.bCheckAfter = !!bPostCheck;
475 ret->For.Condition = Condition;
476 ret->For.Increment = Increment;
477 ret->For.Code = Code;
481 tAST_Node *AST_NewAssign(tParser *Parser, int Operation, tAST_Node *Dest, tAST_Node *Value)
483 tAST_Node *ret = AST_int_AllocateNode(Parser, NODETYPE_ASSIGN, 0);
485 ret->Assign.Operation = Operation;
486 ret->Assign.Dest = Dest;
487 ret->Assign.Value = Value;
492 tAST_Node *AST_NewCast(tParser *Parser, int Target, tAST_Node *Value)
494 tAST_Node *ret = AST_int_AllocateNode(Parser, NODETYPE_CAST, 0);
496 ret->Cast.DataType = Target;
497 ret->Cast.Value = Value;
502 tAST_Node *AST_NewBinOp(tParser *Parser, int Operation, tAST_Node *Left, tAST_Node *Right)
504 tAST_Node *ret = AST_int_AllocateNode(Parser, Operation, 0);
506 ret->BinOp.Left = Left;
507 ret->BinOp.Right = Right;
514 tAST_Node *AST_NewUniOp(tParser *Parser, int Operation, tAST_Node *Value)
516 tAST_Node *ret = AST_int_AllocateNode(Parser, Operation, 0);
518 ret->UniOp.Value = Value;
523 tAST_Node *AST_NewNop(tParser *Parser)
525 tAST_Node *ret = AST_int_AllocateNode(Parser, NODETYPE_NOP, 0);
531 * \brief Create a new string node
533 tAST_Node *AST_NewString(tParser *Parser, const char *String, int Length)
535 tAST_Node *ret = AST_int_AllocateNode(Parser, NODETYPE_STRING, Length + 1);
537 ret->Constant.Type = SS_DATATYPE_STRING;
538 ret->Constant.ReferenceCount = 1;
539 ret->Constant.String.Length = Length;
540 memcpy(ret->Constant.String.Data, String, Length);
541 ret->Constant.String.Data[Length] = '\0';
547 * \brief Create a new integer node
549 tAST_Node *AST_NewInteger(tParser *Parser, int64_t Value)
551 tAST_Node *ret = AST_int_AllocateNode(Parser, NODETYPE_INTEGER, 0);
552 ret->Constant.Type = SS_DATATYPE_INTEGER;
553 ret->Constant.ReferenceCount = 1;
554 ret->Constant.Integer = Value;
559 * \brief Create a new real number node
561 tAST_Node *AST_NewReal(tParser *Parser, double Value)
563 tAST_Node *ret = AST_int_AllocateNode(Parser, NODETYPE_REAL, 0);
564 ret->Constant.Type = SS_DATATYPE_REAL;
565 ret->Constant.ReferenceCount = 1;
566 ret->Constant.Real = Value;
571 * \brief Create a new variable reference node
573 tAST_Node *AST_NewVariable(tParser *Parser, const char *Name)
575 tAST_Node *ret = AST_int_AllocateNode(Parser, NODETYPE_VARIABLE, strlen(Name) + 1 );
576 strcpy(ret->Variable.Name, Name);
581 * \brief Create a new variable definition node
583 tAST_Node *AST_NewDefineVar(tParser *Parser, int Type, const char *Name)
585 tAST_Node *ret = AST_int_AllocateNode(Parser, NODETYPE_DEFVAR, strlen(Name) + 1 );
587 ret->DefVar.DataType = Type;
588 ret->DefVar.LevelSizes = NULL;
589 ret->DefVar.LevelSizes_Last = NULL;
590 ret->DefVar.InitialValue = NULL;
591 strcpy(ret->DefVar.Name, Name);
597 * \brief Create a new runtime constant reference node
599 tAST_Node *AST_NewConstant(tParser *Parser, const char *Name)
601 tAST_Node *ret = AST_int_AllocateNode(Parser, NODETYPE_CONSTANT, strlen(Name) + 1 );
603 strcpy(ret->Variable.Name, Name);
609 * \brief Create a function call node
610 * \note Argument list is manipulated using AST_AppendFunctionCallArg
612 tAST_Node *AST_NewFunctionCall(tParser *Parser, const char *Name)
614 tAST_Node *ret = AST_int_AllocateNode(Parser, NODETYPE_FUNCTIONCALL, strlen(Name) + 1 );
616 ret->FunctionCall.Object = NULL;
617 ret->FunctionCall.FirstArg = NULL;
618 ret->FunctionCall.LastArg = NULL;
619 ret->FunctionCall.NumArgs = 0;
620 strcpy(ret->FunctionCall.Name, Name);
624 tAST_Node *AST_NewMethodCall(tParser *Parser, tAST_Node *Object, const char *Name)
626 tAST_Node *ret = AST_int_AllocateNode(Parser, NODETYPE_METHODCALL, strlen(Name) + 1 );
628 ret->FunctionCall.Object = Object;
629 ret->FunctionCall.FirstArg = NULL;
630 ret->FunctionCall.LastArg = NULL;
631 ret->FunctionCall.NumArgs = 0;
632 strcpy(ret->FunctionCall.Name, Name);
637 tAST_Node *AST_NewCreateObject(tParser *Parser, const char *Name)
639 tAST_Node *ret = AST_int_AllocateNode(Parser, NODETYPE_CREATEOBJECT, strlen(Name) + 1 );
641 ret->FunctionCall.Object = NULL;
642 ret->FunctionCall.FirstArg = NULL;
643 ret->FunctionCall.LastArg = NULL;
644 ret->FunctionCall.NumArgs = 0;
645 strcpy(ret->FunctionCall.Name, Name);
651 * \brief Append an argument to a function call
653 void AST_AppendFunctionCallArg(tAST_Node *Node, tAST_Node *Arg)
655 if( Node->Type != NODETYPE_FUNCTIONCALL
656 && Node->Type != NODETYPE_CREATEOBJECT
657 && Node->Type != NODETYPE_METHODCALL)
659 fprintf(stderr, "BUG REPORT: AST_AppendFunctionCallArg on an invalid node type (%i)\n", Node->Type);
663 if(Node->FunctionCall.LastArg) {
664 Node->FunctionCall.LastArg->NextSibling = Arg;
665 Node->FunctionCall.LastArg = Arg;
668 Node->FunctionCall.FirstArg = Arg;
669 Node->FunctionCall.LastArg = Arg;
671 Node->FunctionCall.NumArgs ++;
675 * \brief Add a scope node
677 tAST_Node *AST_NewScopeDereference(tParser *Parser, const char *Name, tAST_Node *Child)
679 tAST_Node *ret = AST_int_AllocateNode(Parser, NODETYPE_SCOPE, strlen(Name) + 1 );
680 ret->Scope.Element = Child;
681 strcpy(ret->Scope.Name, Name);
686 * \brief Add a scope node
688 tAST_Node *AST_NewClassElement(tParser *Parser, tAST_Node *Object, const char *Name)
690 tAST_Node *ret = AST_int_AllocateNode(Parser, NODETYPE_ELEMENT, strlen(Name) + 1 );
691 ret->Scope.Element = Object;
692 strcpy(ret->Scope.Name, Name);