* \name Node Manipulation
* \{
*/
+/**
+ * \brief Get the in-memory size of a node
+ */
+size_t AST_GetNodeSize(tAST_Node *Node)
+{
+ size_t ret;
+ tAST_Node *node;
+
+ if(!Node)
+ return 0;
+
+ ret = sizeof(tAST_Node*) + sizeof(tAST_NodeType)
+ + sizeof(const char *) + sizeof(int);
+
+ switch(Node->Type)
+ {
+ // Block of code
+ case NODETYPE_BLOCK:
+ ret += sizeof(Node->Block);
+ for( node = Node->Block.FirstChild; node; )
+ {
+ ret += AST_GetNodeSize(node);
+ node = node->NextSibling;
+ }
+ break;
+
+ // Function Call
+ case NODETYPE_FUNCTIONCALL:
+ ret += sizeof(Node->FunctionCall) + strlen(Node->FunctionCall.Name) + 1;
+ for( node = Node->FunctionCall.FirstArg; node; )
+ {
+ ret += AST_GetNodeSize(node);
+ node = node->NextSibling;
+ }
+ break;
+
+ // If node
+ case NODETYPE_IF:
+ ret += sizeof(Node->If);
+ ret += AST_GetNodeSize(Node->If.Condition);
+ ret += AST_GetNodeSize(Node->If.True);
+ ret += AST_GetNodeSize(Node->If.False);
+ break;
+
+ // Looping Construct (For loop node)
+ case NODETYPE_LOOP:
+ ret += sizeof(Node->For);
+ ret += AST_GetNodeSize(Node->For.Init);
+ ret += AST_GetNodeSize(Node->For.Condition);
+ ret += AST_GetNodeSize(Node->For.Increment);
+ ret += AST_GetNodeSize(Node->For.Code);
+ break;
+
+ // Asignment
+ case NODETYPE_ASSIGN:
+ ret += sizeof(Node->Assign);
+ ret += AST_GetNodeSize(Node->Assign.Dest);
+ ret += AST_GetNodeSize(Node->Assign.Value);
+ break;
+
+ // Casting
+ case NODETYPE_CAST:
+ ret += sizeof(Node->Cast);
+ ret += AST_GetNodeSize(Node->Cast.Value);
+ break;
+
+ // Define a variable
+ case NODETYPE_DEFVAR:
+ ret += sizeof(Node->DefVar) + strlen(Node->DefVar.Name) + 1;
+ for( node = Node->DefVar.LevelSizes; node; )
+ {
+ ret += AST_GetNodeSize(node);
+ node = node->NextSibling;
+ }
+ break;
+
+ // Unary Operations
+ case NODETYPE_RETURN:
+ ret += sizeof(Node->UniOp);
+ ret += AST_GetNodeSize(Node->UniOp.Value);
+ break;
+
+ // Binary Operations
+ case NODETYPE_INDEX:
+ case NODETYPE_ADD:
+ case NODETYPE_SUBTRACT:
+ case NODETYPE_MULTIPLY:
+ case NODETYPE_DIVIDE:
+ case NODETYPE_MODULO:
+ case NODETYPE_BITSHIFTLEFT:
+ case NODETYPE_BITSHIFTRIGHT:
+ case NODETYPE_BITROTATELEFT:
+ case NODETYPE_BWAND: case NODETYPE_LOGICALAND:
+ case NODETYPE_BWOR: case NODETYPE_LOGICALOR:
+ case NODETYPE_BWXOR: case NODETYPE_LOGICALXOR:
+ case NODETYPE_EQUALS:
+ case NODETYPE_LESSTHAN:
+ case NODETYPE_GREATERTHAN:
+ ret += sizeof(Node->BinOp);
+ ret += AST_GetNodeSize( Node->BinOp.Left );
+ ret += AST_GetNodeSize( Node->BinOp.Right );
+ break;
+
+ // Node types with no children
+ case NODETYPE_NOP:
+ break;
+ case NODETYPE_VARIABLE:
+ case NODETYPE_CONSTANT:
+ ret += sizeof(Node->Variable) + strlen(Node->Variable.Name) + 1;
+ break;
+ case NODETYPE_STRING:
+ ret += sizeof(Node->String) + Node->String.Length;
+ break;
+ case NODETYPE_INTEGER:
+ ret += sizeof(Node->Integer);
+ break;
+ case NODETYPE_REAL:
+ ret += sizeof(Node->Real);
+ break;
+ }
+ return ret;
+}
+
+#if 1
+
+#define WRITE_N(_buffer, _offset, _len, _dataptr) do { \
+ if(_buffer) memcpy((char*)_buffer + _offset, _dataptr, _len);\
+ _offset += _len; \
+} while(0)
+
+#define WRITE_8(_buffer, _offset, _val) do {\
+ uint8_t v = (_val);\
+ WRITE_N(_buffer, _offset, 1, &v);\
+} while(0)
+#define WRITE_16(_buffer, _offset, _val) do {\
+ uint16_t v = (_val);\
+ WRITE_N(_buffer, _offset, 2, &v);\
+} while(0)
+#define WRITE_32(_buffer, _offset, _val) do {\
+ uint32_t v = (_val);\
+ WRITE_N(_buffer, _offset, 4, &v);\
+} while(0)
+#define WRITE_64(_buffer, _offset, _val) do {\
+ uint64_t v = (_val);\
+ WRITE_N(_buffer, _offset, 8, &v);\
+} while(0)
+#define WRITE_REAL(_buffer, _offset, _val) do {\
+ double v = (_val);\
+ WRITE_N(_buffer, _offset, sizeof(double), &v);\
+} while(0)
+
+#define WRITE_STR(_buffer, _offset, _string) do {\
+ int len = strlen(_string);\
+ WRITE_16(_buffer, _offset, len);\
+ WRITE_N(_buffer, _offset, len, _string);\
+} while(0)
+#define WRITE_NODELIST(_buffer, _offset, _listHead) do {\
+ tAST_Node *node; \
+ size_t ptr = -1;\
+ for(node=(_listHead); node; node = node->NextSibling) {\
+ ptr = _offset;\
+ _offset += AST_WriteNode(_buffer, _offset, node); \
+ WRITE_32(_buffer, ptr, ptr); \
+ } \
+ if(ptr != -1){ptr -= 4; WRITE_32(_buffer, ptr, 0);} \
+} while(0)
+
+/**
+ * \brief Writes a script dump to a buffer
+ * \return Size of encoded data
+ * \note If \a Buffer is NULL, no write is done, but the size is still returned
+ */
+size_t AST_WriteScript(void *Buffer, tAST_Script *Script)
+{
+ tAST_Function *fcn;
+ size_t ret = 0, ptr;
+
+ for( fcn = Script->Functions; fcn; fcn = fcn->Next )
+ {
+ ptr = ret;
+ WRITE_32(Buffer, ret, 0); // Next
+ WRITE_STR(Buffer, ret, fcn->Name);
+ WRITE_NODELIST(Buffer, ret, fcn->Arguments); // TODO: Cheaper way
+ ret += AST_WriteNode(Buffer, ret, fcn->Code);
+ WRITE_32(Buffer, ptr, ret); // Actually set next
+ }
+ ptr -= 4;
+ WRITE_32(Buffer, ptr, 0); // Clear next for final
+
+ return ret;
+}
+
+/**
+ * \brief Write a node to a file
+ */
+size_t AST_WriteNode(void *Buffer, size_t Offset, tAST_Node *Node)
+{
+ off_t ptr;
+ typeof(Offset) baseOfs = Offset;
+
+ if(!Node) {
+ fprintf(stderr, "Possible Bug - NULL passed to AST_WriteNode\n");
+ return 0;
+ }
+
+ WRITE_32(Buffer, Offset, 0); // Next
+ WRITE_8(Buffer, Offset, Node->Type);
+ //WRITE_32(Buffer, Offset, 0); // File
+ WRITE_16(Buffer, Offset, Node->Line); // Line
+
+ switch(Node->Type)
+ {
+ // Block of code
+ case NODETYPE_BLOCK:
+ WRITE_NODELIST(Buffer, Offset, Node->Block.FirstChild);
+ break;
+
+ // Function Call
+ case NODETYPE_FUNCTIONCALL:
+ WRITE_STR(Buffer, Offset, Node->FunctionCall.Name);
+ WRITE_NODELIST(Buffer, Offset, Node->FunctionCall.FirstArg);
+ break;
+
+ // If node
+ case NODETYPE_IF:
+ ptr = Offset;
+ WRITE_32(Buffer, Offset, 0); // Condition
+ WRITE_32(Buffer, Offset, 0); // True
+ WRITE_32(Buffer, Offset, 0); // False
+
+ Offset += AST_WriteNode(Buffer, Offset, Node->If.Condition);
+ WRITE_32(Buffer, ptr, Offset);
+ Offset += AST_WriteNode(Buffer, Offset, Node->If.True);
+ WRITE_32(Buffer, ptr, Offset);
+ Offset += AST_WriteNode(Buffer, Offset, Node->If.False);
+ WRITE_32(Buffer, ptr, Offset);
+ break;
+
+ // Looping Construct (For loop node)
+ case NODETYPE_LOOP:
+ WRITE_8(Buffer, Offset, Node->For.bCheckAfter);
+ ptr = Offset;
+ WRITE_32(Buffer, Offset, 0); // Init
+ WRITE_32(Buffer, Offset, 0); // Condition
+ WRITE_32(Buffer, Offset, 0); // Increment
+ WRITE_32(Buffer, Offset, 0); // Code
+
+ Offset += AST_WriteNode(Buffer, Offset, Node->For.Init);
+ WRITE_32(Buffer, ptr, Offset);
+ Offset += AST_WriteNode(Buffer, Offset, Node->For.Condition);
+ WRITE_32(Buffer, ptr, Offset);
+ Offset += AST_WriteNode(Buffer, Offset, Node->For.Increment);
+ WRITE_32(Buffer, ptr, Offset);
+ Offset += AST_WriteNode(Buffer, Offset, Node->For.Code);
+ WRITE_32(Buffer, ptr, Offset);
+ break;
+
+ // Asignment
+ case NODETYPE_ASSIGN:
+ WRITE_8(Buffer, Offset, Node->Assign.Operation);
+ ptr = Offset;
+ WRITE_32(Buffer, Offset, 0); // Dest
+ WRITE_32(Buffer, Offset, 0); // Value
+
+ Offset += AST_WriteNode(Buffer, Offset, Node->Assign.Dest);
+ WRITE_32(Buffer, ptr, Offset);
+ Offset += AST_WriteNode(Buffer, Offset, Node->Assign.Value);
+ WRITE_32(Buffer, ptr, Offset);
+ break;
+
+ // Casting
+ case NODETYPE_CAST:
+ WRITE_8(Buffer, Offset, Node->Cast.DataType);
+ ptr = Offset;
+ WRITE_32(Buffer, Offset, 0);
+
+ Offset += AST_WriteNode(Buffer, Offset, Node->Cast.Value);
+ WRITE_32(Buffer, ptr, Offset);
+ break;
+
+ // Define a variable
+ case NODETYPE_DEFVAR:
+ WRITE_8(Buffer, Offset, Node->DefVar.DataType);
+ WRITE_8(Buffer, Offset, Node->DefVar.Depth);
+ WRITE_STR(Buffer, Offset, Node->DefVar.Name);
+
+ WRITE_NODELIST(Buffer, Offset, Node->DefVar.LevelSizes);
+ break;
+
+ // Unary Operations
+ case NODETYPE_RETURN:
+ ptr = Offset;
+ WRITE_32(Buffer, Offset, 0);
+ Offset += AST_WriteNode(Buffer, Offset, Node->UniOp.Value);
+ WRITE_32(Buffer, ptr, Offset);
+ break;
+
+ // Binary Operations
+ case NODETYPE_INDEX:
+ case NODETYPE_ADD:
+ case NODETYPE_SUBTRACT:
+ case NODETYPE_MULTIPLY:
+ case NODETYPE_DIVIDE:
+ case NODETYPE_MODULO:
+ case NODETYPE_BITSHIFTLEFT:
+ case NODETYPE_BITSHIFTRIGHT:
+ case NODETYPE_BITROTATELEFT:
+ case NODETYPE_BWAND: case NODETYPE_LOGICALAND:
+ case NODETYPE_BWOR: case NODETYPE_LOGICALOR:
+ case NODETYPE_BWXOR: case NODETYPE_LOGICALXOR:
+ case NODETYPE_EQUALS:
+ case NODETYPE_LESSTHAN:
+ case NODETYPE_GREATERTHAN:
+ ptr = Offset;
+ WRITE_32(Buffer, Offset, 0); // Left
+ WRITE_32(Buffer, Offset, 0); // Right
+ Offset += AST_WriteNode(Buffer, Offset, Node->BinOp.Left);
+ WRITE_32(Buffer, ptr, Offset);
+ Offset += AST_WriteNode(Buffer, Offset, Node->BinOp.Right);
+ WRITE_32(Buffer, ptr, Offset);
+ break;
+
+ // Node types with no children
+ case NODETYPE_NOP:
+ break;
+ case NODETYPE_VARIABLE:
+ case NODETYPE_CONSTANT:
+ WRITE_STR(Buffer, Offset, Node->Variable.Name);
+ break;
+ case NODETYPE_STRING:
+ WRITE_32(Buffer, Offset, Node->String.Length);
+ WRITE_N(Buffer, Offset, Node->String.Length, Node->String.Data);
+ break;
+ case NODETYPE_INTEGER:
+ WRITE_64(Buffer, Offset, Node->Integer);
+ break;
+ case NODETYPE_REAL:
+ WRITE_REAL(Buffer, Offset, Node->Real);
+ break;
+
+ default:
+ fprintf(stderr, "AST_WriteNode: Unknown node type %i\n", Node->Type);
+ break;
+ }
+
+ return Offset - baseOfs;
+}
+#elif 0
+/**
+ * \brief Write a node to a file
+ */
+void AST_WriteNode(FILE *FP, tAST_Node *Node)
+{
+ tAST_Node *node;
+ intptr_t ptr;
+ int ret;
+
+ if(!Node) return ;
+
+ ptr = ftell(FP) + AST_GetNodeSize(Node);
+ fwrite(&ptr, sizeof(ptr), 1, FP);
+ fwrite(&Node->Type, sizeof(Node->Type), 1, FP);
+ ptr = 0; fwrite(&ptr, sizeof(ptr), 1, FP); // File
+ fwrite(&Node->Line, sizeof(Node->Line), 1, FP);
+
+ ret = sizeof(tAST_Node*) + sizeof(tAST_NodeType)
+ + sizeof(const char *) + sizeof(int);
+
+ switch(Node->Type)
+ {
+ // Block of code
+ case NODETYPE_BLOCK:
+ ret += sizeof(Node->Block);
+ for( node = Node->Block.FirstChild; node; )
+ {
+ ret += AST_GetNodeSize(node);
+ node = node->NextSibling;
+ }
+ break;
+
+ // Function Call
+ case NODETYPE_FUNCTIONCALL:
+ ret += sizeof(Node->FunctionCall) + strlen(Node->FunctionCall.Name) + 1;
+ for( node = Node->FunctionCall.FirstArg; node; )
+ {
+ ret += AST_GetNodeSize(node);
+ node = node->NextSibling;
+ }
+ break;
+
+ // If node
+ case NODETYPE_IF:
+ ret += sizeof(Node->If);
+ ret += AST_GetNodeSize(Node->If.Condition);
+ ret += AST_GetNodeSize(Node->If.True);
+ ret += AST_GetNodeSize(Node->If.False);
+ break;
+
+ // Looping Construct (For loop node)
+ case NODETYPE_LOOP:
+ ret += sizeof(Node->For);
+ ret += AST_GetNodeSize(Node->For.Init);
+ ret += AST_GetNodeSize(Node->For.Condition);
+ ret += AST_GetNodeSize(Node->For.Increment);
+ ret += AST_GetNodeSize(Node->For.Code);
+ break;
+
+ // Asignment
+ case NODETYPE_ASSIGN:
+ ret += sizeof(Node->Assign);
+ ret += AST_GetNodeSize(Node->Assign.Dest);
+ ret += AST_GetNodeSize(Node->Assign.Value);
+ break;
+
+ // Casting
+ case NODETYPE_CAST:
+ ret += sizeof(Node->Cast);
+ ret += AST_GetNodeSize(Node->Cast.Value);
+ break;
+
+ // Define a variable
+ case NODETYPE_DEFVAR:
+ ret += sizeof(Node->DefVar) + strlen(Node->DefVar.Name) + 1;
+ for( node = Node->DefVar.LevelSizes; node; )
+ {
+ ret += AST_GetNodeSize(node);
+ node = node->NextSibling;
+ }
+ break;
+
+ // Unary Operations
+ case NODETYPE_RETURN:
+ ret += sizeof(Node->UniOp);
+ ret += AST_GetNodeSize(Node->UniOp.Value);
+ break;
+
+ // Binary Operations
+ case NODETYPE_INDEX:
+ case NODETYPE_ADD:
+ case NODETYPE_SUBTRACT:
+ case NODETYPE_MULTIPLY:
+ case NODETYPE_DIVIDE:
+ case NODETYPE_MODULO:
+ case NODETYPE_BITSHIFTLEFT:
+ case NODETYPE_BITSHIFTRIGHT:
+ case NODETYPE_BITROTATELEFT:
+ case NODETYPE_BWAND: case NODETYPE_LOGICALAND:
+ case NODETYPE_BWOR: case NODETYPE_LOGICALOR:
+ case NODETYPE_BWXOR: case NODETYPE_LOGICALXOR:
+ case NODETYPE_EQUALS:
+ case NODETYPE_LESSTHAN:
+ case NODETYPE_GREATERTHAN:
+ ret += sizeof(Node->BinOp);
+ ret += AST_GetNodeSize( Node->BinOp.Left );
+ ret += AST_GetNodeSize( Node->BinOp.Right );
+ break;
+
+ // Node types with no children
+ case NODETYPE_NOP:
+ break;
+ case NODETYPE_VARIABLE:
+ case NODETYPE_CONSTANT:
+ ret += sizeof(Node->Variable) + strlen(Node->Variable.Name) + 1;
+ break;
+ case NODETYPE_STRING:
+ ret += sizeof(Node->String) + Node->String.Length;
+ break;
+ case NODETYPE_INTEGER:
+ ret += sizeof(Node->Integer);
+ break;
+ case NODETYPE_REAL:
+ ret += sizeof(Node->Real);
+ break;
+ }
+ return ret;
+}
+#endif
+
/**
* \brief Free a node and all subnodes
*/
tAST_Node *ret = malloc( sizeof(tAST_Node) );
ret->NextSibling = NULL;
+ //ret->Line = Parser->CurLine;
ret->Type = NODETYPE_BLOCK;
ret->Block.FirstChild = NULL;
ret->Block.LastChild = NULL;
}
}
-tAST_Node *AST_NewIf(tAST_Node *Condition, tAST_Node *True, tAST_Node *False)
+tAST_Node *AST_NewIf(tParser *Parser, tAST_Node *Condition, tAST_Node *True, tAST_Node *False)
{
tAST_Node *ret = malloc( sizeof(tAST_Node) );
ret->NextSibling = NULL;
+ ret->Line = Parser->CurLine;
ret->Type = NODETYPE_IF;
ret->If.Condition = Condition;
ret->If.True = True;
return ret;
}
-tAST_Node *AST_NewLoop(tAST_Node *Init, int bPostCheck, tAST_Node *Condition, tAST_Node *Increment, tAST_Node *Code)
+tAST_Node *AST_NewLoop(tParser *Parser, tAST_Node *Init, int bPostCheck, tAST_Node *Condition, tAST_Node *Increment, tAST_Node *Code)
{
tAST_Node *ret = malloc( sizeof(tAST_Node) );
ret->NextSibling = NULL;
+ ret->Line = Parser->CurLine;
ret->Type = NODETYPE_LOOP;
ret->For.Init = Init;
ret->For.bCheckAfter = !!bPostCheck;
return ret;
}
-tAST_Node *AST_NewAssign(int Operation, tAST_Node *Dest, tAST_Node *Value)
+tAST_Node *AST_NewAssign(tParser *Parser, int Operation, tAST_Node *Dest, tAST_Node *Value)
{
tAST_Node *ret = malloc( sizeof(tAST_Node) );
ret->NextSibling = NULL;
+ ret->Line = Parser->CurLine;
ret->Type = NODETYPE_ASSIGN;
ret->Assign.Operation = Operation;
ret->Assign.Dest = Dest;
return ret;
}
-tAST_Node *AST_NewBinOp(int Operation, tAST_Node *Left, tAST_Node *Right)
+tAST_Node *AST_NewCast(tParser *Parser, int Target, tAST_Node *Value)
+{
+ tAST_Node *ret = malloc( sizeof(tAST_Node) );
+
+ ret->NextSibling = NULL;
+ ret->Line = Parser->CurLine;
+ ret->Type = NODETYPE_CAST;
+ ret->Cast.DataType = Target;
+ ret->Cast.Value = Value;
+
+ return ret;
+}
+
+tAST_Node *AST_NewBinOp(tParser *Parser, int Operation, tAST_Node *Left, tAST_Node *Right)
{
tAST_Node *ret = malloc( sizeof(tAST_Node) );
ret->NextSibling = NULL;
+ ret->Line = Parser->CurLine;
ret->Type = Operation;
ret->BinOp.Left = Left;
ret->BinOp.Right = Right;
/**
*/
-tAST_Node *AST_NewUniOp(int Operation, tAST_Node *Value)
+tAST_Node *AST_NewUniOp(tParser *Parser, int Operation, tAST_Node *Value)
{
tAST_Node *ret = malloc( sizeof(tAST_Node) );
ret->NextSibling = NULL;
+ ret->Line = Parser->CurLine;
ret->Type = Operation;
ret->UniOp.Value = Value;
/**
* \brief Create a new string node
*/
-tAST_Node *AST_NewString(const char *String, int Length)
+tAST_Node *AST_NewString(tParser *Parser, const char *String, int Length)
{
tAST_Node *ret = malloc( sizeof(tAST_Node) + Length + 1 );
ret->NextSibling = NULL;
+ ret->Line = Parser->CurLine;
ret->Type = NODETYPE_STRING;
ret->String.Length = Length;
memcpy(ret->String.Data, String, Length);
/**
* \brief Create a new integer node
*/
-tAST_Node *AST_NewInteger(uint64_t Value)
+tAST_Node *AST_NewInteger(tParser *Parser, uint64_t Value)
{
tAST_Node *ret = malloc( sizeof(tAST_Node) );
ret->NextSibling = NULL;
+ ret->Line = Parser->CurLine;
ret->Type = NODETYPE_INTEGER;
ret->Integer = Value;
return ret;
/**
* \brief Create a new variable reference node
*/
-tAST_Node *AST_NewVariable(const char *Name)
+tAST_Node *AST_NewVariable(tParser *Parser, const char *Name)
{
tAST_Node *ret = malloc( sizeof(tAST_Node) + strlen(Name) + 1 );
ret->NextSibling = NULL;
+ ret->Line = Parser->CurLine;
ret->Type = NODETYPE_VARIABLE;
strcpy(ret->Variable.Name, Name);
return ret;
/**
* \brief Create a new variable definition node
*/
-tAST_Node *AST_NewDefineVar(int Type, const char *Name)
+tAST_Node *AST_NewDefineVar(tParser *Parser, int Type, const char *Name)
{
tAST_Node *ret = malloc( sizeof(tAST_Node) + strlen(Name) + 1 );
ret->NextSibling = NULL;
+ ret->Line = Parser->CurLine;
ret->Type = NODETYPE_DEFVAR;
ret->DefVar.DataType = Type;
ret->DefVar.LevelSizes = NULL;
/**
* \brief Create a new runtime constant reference node
*/
-tAST_Node *AST_NewConstant(const char *Name)
+tAST_Node *AST_NewConstant(tParser *Parser, const char *Name)
{
tAST_Node *ret = malloc( sizeof(tAST_Node) + strlen(Name) + 1 );
ret->NextSibling = NULL;
+ ret->Line = Parser->CurLine;
ret->Type = NODETYPE_CONSTANT;
strcpy(ret->Variable.Name, Name);
return ret;
* \brief Create a function call node
* \note Argument list is manipulated using AST_AppendFunctionCallArg
*/
-tAST_Node *AST_NewFunctionCall(const char *Name)
+tAST_Node *AST_NewFunctionCall(tParser *Parser, const char *Name)
{
tAST_Node *ret = malloc( sizeof(tAST_Node) + strlen(Name) + 1 );
ret->NextSibling = NULL;
+ ret->Line = Parser->CurLine;
ret->Type = NODETYPE_FUNCTIONCALL;
ret->FunctionCall.FirstArg = NULL;
ret->FunctionCall.LastArg = NULL;