view interps/sadol/BDSM2.cpp @ 6842:76c0c1881313

<olsner> learn The internet is for everything. However many thing can done even without internet too, often better without use of internet, but internet is good too.
author HackBot
date Mon, 15 Feb 2016 01:09:11 +0000
parents 859f9b4339e6
children
line wrap: on
line source

/*
 * BDSM2
 * Author: Adam Sawicki
 * http://www.regedit.risp.pl
 * mailto:regedit@risp.pl
 */
#include "pch.hpp"
#include <iostream>
#include <cstdio>
#include "Console.hpp"
#include "Source.hpp"

// array of elements of type T indexed by 'A'..'Z' or 'a'..'z'
// 'A' and 'a' means the same elements etc.
template <typename T>
class CharIndexedArray
{
private:
	T m_Arr[26];

public:
	T & operator [] (char ch)
	{
		if (ch >= 'a' && ch <= 'z')
			return m_Arr[ch-'a'];
		else if (ch >= 'A' && ch <= 'Z')
			return m_Arr[ch-'A'];
		else
			Error("Invalid char array index: "+CharToStr(ch));
		return m_Arr[0];
	}
	const T & operator [] (char ch) const
	{
		if (ch >= 'a' && ch <= 'z')
			return m_Arr[ch-'a'];
		else if (ch >= 'A' && ch <= 'Z')
			return m_Arr[ch-'A'];
		else
			Error("Invalid char array index: "+CharToStr(ch));
		return m_Arr[0];
	}
};

//==============================================================================

class Value
{
public:
	enum TYPE {
		TYPE_NONE,
		TYPE_INTEGER,
		TYPE_DOUBLE,
		TYPE_STRING,
		TYPE_LIST,
	};

	typedef std::vector<Value> ValueVector;

	// return:
	// value < 0 if v1 < v2
	// value == 0 if v1 == v2
	// value > 0 if v1 > v2
	static int ValueCmp(const Value &v1, const Value &v2);

private:
	struct StringRealValue
	{
	private:
		int m_ReferenceCounter;

	public:
		string m_String;

		// create new value with counter 1, empty
		StringRealValue() : m_ReferenceCounter(1) { }
		// create new value with counter 1, initialized
		StringRealValue(const string &String) : m_ReferenceCounter(1), m_String(String) { }
		// create new value with counter 1 based on existing value
		StringRealValue(const StringRealValue &v) : m_ReferenceCounter(1), m_String(v.m_String) { }
		void AddReference() { m_ReferenceCounter++; }
		int GetReferenceCount() { return m_ReferenceCounter; }
		// dec reference counter, free object if 0
		static void Destroy(StringRealValue *v);
	};

	struct ListRealValue
	{
	private:
		int m_ReferenceCounter;

	public:
		ValueVector m_List;

		// create new value with counter 1, empty
		ListRealValue() : m_ReferenceCounter(1) { }
		// create new value with counter 1, initialized
		ListRealValue(const ValueVector &List) : m_ReferenceCounter(1), m_List(List) { }
		// create new value with counter 1 based on existing value
		ListRealValue(const ListRealValue &v) : m_ReferenceCounter(1), m_List(v.m_List) { }
		void AddReference() { m_ReferenceCounter++; }
		int GetReferenceCount() { return m_ReferenceCounter; }
		// dec reference counter, free object if 0
		static void Destroy(ListRealValue *v);
	};

	TYPE m_Type;
	union {
		int m_Integer;
		double m_Double;
		StringRealValue *m_String;
		ListRealValue *m_List;
	};

	void CreateCopy(const Value &v);
	void Destroy();

	void ConvertToInteger(Value *v) const;
	void ConvertToDouble(Value *v) const;
	void ConvertToString(Value *v) const;
	void ConvertToList(Value *v) const;

public:
	// create uninitialized value
	Value() : m_Type(TYPE_NONE) { }
	// create initialized, empty value with given type
	// Integer or Double has undefined value, String or List is empty.
	Value(TYPE Type);
	// copy constructor
	Value(const Value &v);
	// create initialized value
	Value(int Integer) : m_Type(TYPE_INTEGER), m_Integer(Integer) { }
	Value(double Double) : m_Type(TYPE_DOUBLE), m_Double(Double) { }
	Value(const string &String) : m_Type(TYPE_STRING), m_String(new StringRealValue(String)) { }
	Value(const ValueVector &List) : m_Type(TYPE_STRING), m_List(new ListRealValue(List)) { }
	~Value();

	Value & operator = (const Value &v);
	Value & operator = (TYPE Type);
	Value & operator = (int Integer);
	Value & operator = (double Double);
	Value & operator = (const ValueVector &List);
	Value & operator = (const string &String);

	TYPE GetType() const { return m_Type; }
	string GetTypeName() const;
	// only if type is Integer
	const int & ReadInteger() const { return m_Integer; }
	int & AcceessInteger() { return m_Integer; }
	// only if type is Double
	const double & ReadDouble() const { return m_Double; }
	double & AccessDouble() { return m_Double; }
	// only if type is List
	// use if don't want to modify - performance!
	const ValueVector & ReadList() const { return m_List->m_List; }
	// only if type is String
	// use if don't want to modify - performance!
	const string & ReadString() const { return m_String->m_String; }
	// only if type is List
	ValueVector & AccessList();
	// only if type is String
	string & AccessString();

	void ConsoleOut() const;

	void ConvertTo(Value *v, TYPE Type) const;
	bool ConvertToBool() const;
	int ConvertToInteger() const;
	double ConvertToDouble() const;
	void ConvertToString(string *s) const;
};

int Value::ValueCmp(const Value &v1, const Value &v2)
{
	// list comparison
	if (v1.GetType() == Value::TYPE_LIST || v2.GetType() == Value::TYPE_LIST)
	{
		Value w1, w2;
		v1.ConvertTo(&w1, Value::TYPE_LIST);
		v2.ConvertTo(&w2, Value::TYPE_LIST);

		int R;
		for (size_t i = 0; true; i++)
		{
			if (i == w1.ReadList().size() && i == w2.ReadList().size())
				return 0;
			else if (i == w1.ReadList().size())
				return -1;
			else if (i == w2.ReadList().size())
				return +1;
			else
			{
				R = ValueCmp(w1.ReadList()[i], w2.ReadList()[i]);
				if (R != 0)
					return R;
			}
		}
	}
	// string comparison
	else if (v1.GetType() == Value::TYPE_STRING || v2.GetType() == Value::TYPE_STRING)
	{
		Value w1, w2;
		v1.ConvertTo(&w1, Value::TYPE_STRING);
		v2.ConvertTo(&w2, Value::TYPE_STRING);

		if (w1.ReadString() == w2.ReadString())
			return 0;
		else if (w1.ReadString() < w2.ReadString())
			return -1;
		else
			return +1;
	}
	// double comparison
	else if (v1.GetType() == Value::TYPE_DOUBLE || v2.GetType() == Value::TYPE_DOUBLE)
	{
		Value w1, w2;
		v1.ConvertTo(&w1, Value::TYPE_DOUBLE);
		v2.ConvertTo(&w2, Value::TYPE_DOUBLE);

		if (w1.ReadDouble() == w2.ReadDouble())
			return 0;
		else if (w1.ReadDouble() < w2.ReadDouble())
			return -1;
		else
			return +1;
	}
	// integer comparison
	else
	{
		// both must be integer
		return v1.ReadInteger() - v2.ReadInteger();
	}
}

void Value::StringRealValue::Destroy(StringRealValue *v)
{
	v->m_ReferenceCounter--;
	if (v->m_ReferenceCounter == 0)
		delete v;
}

void Value::ListRealValue::Destroy(ListRealValue *v)
{
	v->m_ReferenceCounter--;
	if (v->m_ReferenceCounter == 0)
		delete v;
}

void Value::CreateCopy(const Value &v)
{
	m_Type = v.m_Type;

	switch (v.m_Type)
	{
	case TYPE_INTEGER:
		m_Integer = v.m_Integer;
		break;
	case TYPE_DOUBLE:
		m_Double = v.m_Double;
		break;
	// add reference to the same real value object
	case TYPE_STRING:
		m_String = v.m_String;
		m_String->AddReference();
		break;
	case TYPE_LIST:
		m_List = v.m_List;
		m_List->AddReference();
		break;
	}
}

void Value::Destroy()
{
	// dec reference, destroy if needed
	switch (m_Type)
	{
	case TYPE_STRING:
		StringRealValue::Destroy(m_String);
		break;
	case TYPE_LIST:
		ListRealValue::Destroy(m_List);
		break;
	}
}

void Value::ConvertToInteger(Value *v) const
{
	*v = ConvertToInteger();
}

void Value::ConvertToDouble(Value *v) const
{
	*v = ConvertToDouble();
}

void Value::ConvertToString(Value *v) const
{
	switch (m_Type)
	{
	case TYPE_INTEGER:
		{
			string s;
			IntToStr(ReadInteger(), &s);
			*v = s;
		}
		break;
	case TYPE_DOUBLE:
		*v = DoubleToStr(ReadDouble(), 'g');
		break;
	case TYPE_STRING:
		*v = *this;
		break;
	case TYPE_LIST:
		Error("Cannot convert list to string");
		break;
	case TYPE_NONE:
		Error("Cannot convert uninitialized value to string");
	}
}

void Value::ConvertToList(Value *v) const
{
	switch (m_Type)
	{
	case TYPE_INTEGER:
	case TYPE_DOUBLE:
	case TYPE_STRING:
		*v = Value::TYPE_LIST;
		v->AccessList().push_back(*this);
		break;
	case TYPE_LIST:
		*v = *this;
		break;
	case TYPE_NONE:
		Error("Cannot convert uninitialized value to list");
	}
}

Value::Value(TYPE Type) : m_Type(Type)
{
	switch (Type)
	{
	case TYPE_STRING:
		m_String = new StringRealValue();
		break;
	case TYPE_LIST:
		m_List = new ListRealValue();
		break;
	}
}

Value::Value(const Value &v)
{
	CreateCopy(v);
}

Value::~Value()
{
	Destroy();
}

Value & Value::operator = (const Value &v)
{
	if (&v != this)
	{
		// as destructor
		Destroy();
		// as constructor
		CreateCopy(v);
	}
	return *this;
}

Value & Value::operator = (TYPE Type)
{
	// as destructor
	Destroy();
	// as constructor
	m_Type = Type;
	switch (Type)
	{
	case TYPE_STRING:
		m_String = new StringRealValue();
		break;
	case TYPE_LIST:
		m_List = new ListRealValue();
		break;
	}

	return *this;
}

Value & Value::operator = (int Integer)
{
	// as destructor
	Destroy();
	// as constructor
	m_Type = TYPE_INTEGER;
	m_Integer = Integer;

	return *this;
}

Value & Value::operator = (double Double)
{
	// as destructor
	Destroy();
	// as constructor
	m_Type = TYPE_DOUBLE;
	m_Double = Double;

	return *this;
}

Value & Value::operator = (const ValueVector &List)
{
	// as destructor
	Destroy();
	// as constructor
	m_Type = TYPE_LIST;
	m_List = new ListRealValue(List);

	return *this;
}

Value & Value::operator = (const string &String)
{
	// as destructor
	Destroy();
	// as constructor
	m_Type = TYPE_STRING;
	m_String = new StringRealValue(String);

	return *this;
}

string Value::GetTypeName() const
{
	switch (m_Type)
	{
	case TYPE_NONE:
		return "none";
	case TYPE_INTEGER:
		return "integer";
	case TYPE_DOUBLE:
		return "double";
	case TYPE_STRING:
		return "string";
	case TYPE_LIST:
		return "list";
	default:
		return "unknown";
	}
}

Value::ValueVector & Value::AccessList()
{
	if (m_List->GetReferenceCount() > 1)
	{
		// copy on write!
		ListRealValue *l = new ListRealValue(*m_List);
		ListRealValue::Destroy(m_List);
		m_List = l;
	}
	return m_List->m_List;
}

string & Value::AccessString()
{
	if (m_String->GetReferenceCount() > 1)
	{
		// copy on write!
		StringRealValue *s = new StringRealValue(*m_String);
		StringRealValue::Destroy(m_String);
		m_String = s;
	}
	return m_String->m_String;
}

void Value::ConsoleOut() const
{
	switch (m_Type)
	{
	case TYPE_INTEGER:
		g_Console.OutInteger(ReadInteger());
		break;
	case TYPE_DOUBLE:
		g_Console.OutDouble(ReadDouble());
		break;
	case TYPE_STRING:
		g_Console.OutString(ReadString());
		break;
	case TYPE_LIST:
		{
			g_Console.OutString("(");
			for (size_t i = 0; i < ReadList().size(); i++)
			{
				if (i > 0)
					g_Console.OutString(",");
				ReadList()[i].ConsoleOut();
			}
			g_Console.OutString(")");
		}
		break;
	case TYPE_NONE:
		Error("Cannot print uninitialized value", ERR_IO);
	}
}

void Value::ConvertTo(Value *v, TYPE Type) const
{
	switch (Type)
	{
	case TYPE_INTEGER:
		ConvertToInteger(v);
		break;
	case TYPE_DOUBLE:
		ConvertToDouble(v);
		break;
	case TYPE_STRING:
		ConvertToString(v);
		break;
	case TYPE_LIST:
		ConvertToList(v);
		break;
	case TYPE_NONE:
		Error("Cannot convert to uninitialized value");
	}
}

bool Value::ConvertToBool() const
{
	switch (m_Type)
	{
	case TYPE_INTEGER:
		return (m_Integer >= 1);
	case TYPE_DOUBLE:
		return (m_Double >= 1.0);
	case TYPE_STRING:
		return !ReadString().empty();
	case TYPE_LIST:
		return !ReadList().empty();
	case TYPE_NONE:
		Error("Cannot convert uninitialized value to bool");
	}
	return false;
}

int Value::ConvertToInteger() const
{
	switch (m_Type)
	{
	case TYPE_INTEGER:
		return ReadInteger();
	case TYPE_DOUBLE:
		return Round(ReadDouble());
	case TYPE_STRING:
		return (int)ReadString().size();
	case TYPE_LIST:
		return (int)ReadList().size();
	case TYPE_NONE:
		Error("Cannot convert uninitialized value to integer");
	}
	return 0;
}

double Value::ConvertToDouble() const
{
	switch (m_Type)
	{
	case TYPE_INTEGER:
		return (double)ReadInteger();
	case TYPE_DOUBLE:
		return ReadDouble();
	case TYPE_STRING:
		return (double)ReadString().size();
	case TYPE_LIST:
		return (double)ReadList().size();
	case TYPE_NONE:
		Error("Cannot convert uninitialized value to double");
	}
	return 0.0;
}

void Value::ConvertToString(string *s) const
{
	switch (m_Type)
	{
	case TYPE_INTEGER:
		IntToStr(ReadInteger(), s);
		break;
	case TYPE_DOUBLE:
		*s = DoubleToStr(ReadDouble(), 'g');
		break;
	case TYPE_STRING:
		*s = ReadString();
		break;
	case TYPE_LIST:
		{
			string s2;
			*s = "(";
			for (size_t i = 0; i < ReadList().size(); i++)
			{
				if (i > 0)
					*s += ",";
				ReadList()[i].ConvertToString(&s2);
				*s += s2;
			}
			*s += ")";
		}
		break;
	case TYPE_NONE:
		Error("Cannot convert uninitialized value to string");
	}
}

//==============================================================================

struct LValue
{
	enum TYPE
	{
		TYPE_VALUE,
		TYPE_STRCHAR,
	};

	TYPE m_Type;
	union
	{
		// only if value
		Value *m_Value;
		// only if str char
		string *m_String;
	};
	// only if str char
	size_t m_StringIndex;

	LValue() { }
	LValue(Value *a_Value) : m_Type(TYPE_VALUE), m_Value(a_Value) { }
	LValue(string *a_String, size_t a_StringIndex) : m_Type(TYPE_STRCHAR), m_String(a_String), m_StringIndex(a_StringIndex) { }
};

//==============================================================================

// Contains char indexed array of value pointers.
// Auto-init and auto-destroy.
struct VarContext
{
	CharIndexedArray<Value*> m_Values;

	VarContext()
	{
		for (char ch = 'A'; ch < 'Z'; ch++)
			m_Values[ch] = 0;
	}
	~VarContext()
	{
		for (char ch = 'A'; ch < 'Z'; ch++)
			delete m_Values[ch];
	}
};

// Stack of var contexts
class VarContextStack
{
private:
	std::vector<VarContext*> m_Stack;
	Value m_DefaultValue;

public:
	VarContextStack();

	void PushNew();
	void Pop();

	const Value & ReadVar(char ch) const;
	Value & AccessVar(char ch);
};

VarContextStack::VarContextStack() : m_DefaultValue((int)0)
{
}

void VarContextStack::PushNew()
{
	m_Stack.push_back(new VarContext);
}

void VarContextStack::Pop()
{
	delete m_Stack.back();
	m_Stack.pop_back();
}

const Value & VarContextStack::ReadVar(char ch) const
{
	for (std::vector<VarContext*>::const_reverse_iterator rit = m_Stack.rbegin(); rit != m_Stack.rend(); ++rit)
		if ((*rit)->m_Values[ch])
			return *((*rit)->m_Values[ch]);
	return m_DefaultValue;
}

Value & VarContextStack::AccessVar(char ch)
{
	if (m_Stack.back()->m_Values[ch] == 0)
		m_Stack.back()->m_Values[ch] = new Value(m_DefaultValue);
	return *m_Stack.back()->m_Values[ch];
}

// Only in Execute call sequence.
VarContextStack g_VarContextStack;
VarContext g_GlobalVars;

//==============================================================================

struct Function;
struct Node;

struct Scope
{
private:
	// zero pointer list
	void InitLocalFunctions();

public:
	Scope *m_Parent;
	Node *m_Node;
	CharIndexedArray<Function*> m_LocalFunctions;

	Scope(Scope *a_Parent, Node *a_Node) : m_Parent(a_Parent), m_Node(a_Node) { InitLocalFunctions(); }
	virtual ~Scope();

	void ParseToEnd(Source &src);
	// Parse given source as single expression, fill in this structure's fields
	void Parse(Source &src);
	// Value is list of arguments
	void Execute(Value *result, Value *args);
	void Optimize();
};

struct Function : public Scope
{
	// -1 means variable arg count
	int m_ArgCount;

	Function(Scope *a_Parent, Node *a_Node, int a_ArgCount) : Scope(a_Parent, a_Node), m_ArgCount(a_ArgCount) { }
};



void Scope::InitLocalFunctions()
{
	for (char ch = 'a'; ch <= 'z'; ch++)
		m_LocalFunctions[ch] = 0;
}



// Used only in Parse call sequence.
std::vector<Scope*> g_ScopeStack;
CharIndexedArray<Function*> g_GlobalFunctions;

//==============================================================================

struct Node
{
private:
	void NodeError(const string &msg, ERR_PLACE place = ERR_GENERAL);
	// free subnodes and clear subnode list
	void ClearSubnodes();

	int Parse_Integer(Source &src);
	// does +
	void OpAdd(Value *result, const Value &v1, const Value &v2);
	// does - * %
	void OpSubMulMod(char Op, Value *result, const Value &v1, const Value &v2);
	// does / ^
	void OpDivPow(char Op, Value *result, const Value &v1, const Value &v2);
	// does \ { blablabla - placeholder not to end line with \ }
	void OpFloor(Value *result, const Value &v);
	// does '
	void OpAposConverter(int Kind, Value *result, const Value &v);
	// does = < >
	void OpComparison(char Op, Value *result, const Value &v1, const Value &v2);

public:
	enum TYPE {
		TYPE_SYMBOL,
		TYPE_CONSTANT,
	};

	TYPE m_Type;
	Source::Iterator m_SrcIterator;

	// only if symbol:
	// If 'A'..'Z' or 'a'..'z', m_Function == 0 means variable, != 0 means function call.
	char m_Ch;
	std::vector<Node*> m_Sub;
	union {
		// only if m_Ch == 'a'..'z' or 'A'..'Z' and this is a function call:
		// Function that should be called (weak pointer).
		Function *m_Function;
		// only if m_Ch == ';' => 0, 1, 2, 3
		// or m_Ch == '\'' => 1, 2
		int m_ExtraInt;
	};

	// only if constant:
	Value m_Value;

	Node();
	~Node();
	// Parse given source to the end as sequence of commands, fill in this structure's fields
	void ParseToEnd(Source &src);
	// Parse given source as single expression, fill in this structure's fields
	void Parse(Source &src);
	// Value is list of arguments.
	void Execute(Value *result, Value *args);
	LValue GetLValue(Value *args);
	void Optimize();
};

Scope::~Scope()
{
	for (char ch = 'a'; ch <= 'z'; ch++)
		delete m_LocalFunctions[ch];
	delete m_Node;
}

void Scope::ParseToEnd(Source &src)
{
	g_ScopeStack.push_back(this);

	m_Node = new Node;
	m_Node->ParseToEnd(src);

	g_ScopeStack.pop_back();
}

void Scope::Parse(Source &src)
{
	g_ScopeStack.push_back(this);

	m_Node = new Node;
	m_Node->Parse(src);

	g_ScopeStack.pop_back();
}

void Scope::Execute(Value *result, Value *args)
{
	g_ScopeStack.push_back(this);
	g_VarContextStack.PushNew();

	m_Node->Execute(result, args);

	g_VarContextStack.Pop();
	g_ScopeStack.pop_back();
}

void Scope::Optimize()
{
	// TODO - scope stack
	m_Node->Optimize();
}

void Node::NodeError(const string &msg, ERR_PLACE place)
{
	Error(msg + " (" + m_SrcIterator.ToString() + ')', place);
}

void Node::ClearSubnodes()
{
	for (size_t i = 0; i < m_Sub.size(); i++)
		delete m_Sub[i];
	m_Sub.clear();
}

int Node::Parse_Integer(Source &src)
{
	src.Skip();
	src.SaveErrPos();
	Node *node = new Node();
	node->Parse(src);
	node->Optimize();
	if (node->m_Type != Node::TYPE_CONSTANT)
		src.SrcError("Cannot evaluate number in compilation time", ERR_PARSE);
	src.DropErrPos();
	int R = node->m_Value.ConvertToInteger();
	delete node;

	return R;
}

void Node::OpAdd(Value *result, const Value &v1, const Value &v2)
{
	// 0 = list cat
	// 1 = add as lists
	// 2 = add as strings
	// 3 = add as double
	// 4 = add as integer
	int Type = -1;

	if (v1.GetType() == Value::TYPE_LIST && v2.GetType() == Value::TYPE_LIST)
		Type = 0;
	else if (v1.GetType() == Value::TYPE_LIST || v2.GetType() == Value::TYPE_LIST)
		Type = 1;
	else if (v1.GetType() == Value::TYPE_STRING || v2.GetType() == Value::TYPE_STRING)
		Type = 2;
	else if (v1.GetType() == Value::TYPE_DOUBLE || v2.GetType() == Value::TYPE_DOUBLE)
		Type = 3;
	else
		Type = 4;

	switch (Type)
	{
	case 0:
		*result = v1;
		for (size_t i = 0; i < v2.ReadList().size(); i++)
			result->AccessList().push_back(v2.ReadList()[i]);
		break;
	case 1:
		{
			Value w2;
			v1.ConvertTo(result, Value::TYPE_LIST);
			v2.ConvertTo(&w2, Value::TYPE_LIST);
			for (size_t i = 0; i < w2.ReadList().size(); i++)
				result->AccessList().push_back(w2.ReadList()[i]);
		}
		break;
	case 2:
		{
			Value w2;
			v1.ConvertTo(result, Value::TYPE_STRING);
			v2.ConvertTo(&w2, Value::TYPE_STRING);
			result->AccessString() += w2.ReadString();
		}
		break;
	case 3:
		{
			Value w2;
			v1.ConvertTo(result, Value::TYPE_DOUBLE);
			v2.ConvertTo(&w2, Value::TYPE_DOUBLE);
			result->AccessDouble() += w2.ReadDouble();
		}
		break;
	case 4:
		*result = v1.ReadInteger() + v2.ReadInteger();
		break;
	}
}

void Node::OpSubMulMod(char Op, Value *result, const Value &v1, const Value &v2)
{
	// integer
	if (v1.GetType() == Value::TYPE_INTEGER && v2.GetType() == Value::TYPE_INTEGER)
	{
		int i1 = v1.ReadInteger();
		int i2 = v2.ReadInteger();
		switch (Op)
		{
		case '-':
			*result = i1 - i2;
			break;
		case '*':
			*result = i1 * i2;
			break;
		case '%':
			if (i2 == 0)
				NodeError("Integer division '%' by 0");
			*result = i1 % i2;
			break;
		}
	}
	// double
	else if ( (v1.GetType() == Value::TYPE_INTEGER || v1.GetType() == Value::TYPE_DOUBLE) &&
		(v2.GetType() == Value::TYPE_INTEGER || v2.GetType() == Value::TYPE_DOUBLE) )
	{
		double d1 = v1.ConvertToDouble();
		double d2 = v2.ConvertToDouble();
		switch (Op)
		{
		case '-':
			*result = d1 - d2;
			break;
		case '*':
			*result = d1 * d2;
			break;
		case '%':
			if (d2 == 0.0)
				NodeError("Double division '%' by 0");
			*result = fmod(d1, d2);
			break;
		}
	}
	else
		NodeError("Invalid argument types for '"+CharToStr(Op)+"': "+v1.GetTypeName()+", "+v2.GetTypeName());
}

void Node::OpDivPow(char Op, Value *result, const Value &v1, const Value &v2)
{
	double d1 = v1.ConvertToDouble();
	double d2 = v2.ConvertToDouble();

	switch (Op)
	{
	case '/':
		if (d2 == 0.0)
			NodeError("Double division '/' by 0");
		*result = d1 / d2;
		break;
	case '^':
		*result = pow(d1, d2);
		break;
	}
}

void Node::OpFloor(Value *result, const Value &v)
{
	*result = floor(v.ConvertToDouble());
}

void Node::OpAposConverter(int Kind, Value *result, const Value &v)
{
	if (Kind == 1)
	{
		string s;
		v.ConvertToString(&s);
		if (s.empty())
			NodeError("Cannot convert empty string to ASCII code in '''");
		*result = (int)(unsigned int)(unsigned char)s[0];
	}
	else if (Kind == 2)
	{
		int i = v.ConvertToInteger();
		if (i < 0 || i >= 256)
			NodeError("Cannot convert integer value "+IntToStr(i)+" into ASCII character");
		*result = Value::TYPE_STRING;
		result->AccessString() += (char)(unsigned char)(unsigned int)i;
	}
}

void Node::OpComparison(char Op, Value *result, const Value &v1, const Value &v2)
{
	int R = Value::ValueCmp(v1, v2);
	
	switch (Op)
	{
	case '=':
		*result = (int)( (R == 0) ? 1 : 0 );
		break;
	case '>':
		*result = (int)( (R > 0) ? 1 : 0 );
		break;
	case '<':
		*result = (int)( (R < 0) ? 1 : 0 );
		break;
	}
}

Node::Node() : m_Function(0)
{
}

Node::~Node()
{
	ClearSubnodes();
}

void Node::ParseToEnd(Source &src)
{
	// This node is ( symbol
	m_Type = TYPE_SYMBOL;
	m_SrcIterator = src.GetIterator();
	m_Ch = '(';

	Node *node;
	for (;;)
	{
		src.Skip();

		if (src.End())
			break;

		m_Sub.push_back(node = new Node);
		node->Parse(src);
	}
}

void Node::Parse(Source &src)
{
	src.Skip();

	m_Type = TYPE_SYMBOL;
	m_SrcIterator = src.GetIterator();
	m_Ch = src.GetS();

	// zero args
	if (m_Ch >= '0' && m_Ch <= '9' || m_Ch == '_')
	{
	}
	// one arg
	else if (m_Ch == '[' || m_Ch == '!' || m_Ch == '`' || m_Ch == '\\')
	{
		Node *node = new Node;
		m_Sub.push_back(node);
		node->Parse(src);
	}
	// direct string
	else if (m_Ch == '"')
	{
		int CharCount = Parse_Integer(src);
		m_Type = TYPE_CONSTANT;
		m_Value = Value::TYPE_STRING;
		for (int i = 0; i < CharCount; i++)
			m_Value.AccessString() += src.GetS();
	}
	// function definition
	else if (m_Ch == '~')
	{
		// name
		char func_name;
		src.Skip();
		func_name = src.GetS();
		if (!( func_name >= 'a' && func_name <= 'z' || func_name >= 'A' && func_name <= 'Z' ))
			src.SrcError("Invalid function name: '" + CharToStr(func_name) + "'", ERR_PARSE);

		// argument count
		int func_arg_count = Parse_Integer(src);
		if (func_arg_count < -1)
			NodeError("Invalid argument count for function '"+CharToStr(func_name)+"': "+IntToStr(func_arg_count), ERR_PARSE);

		// - global
		if (func_name >= 'A' && func_name <= 'Z')
		{
			Function *func = new Function(g_ScopeStack.front(), new Node, func_arg_count);
			// save function
			if (g_GlobalFunctions[func_name])
				NodeError("Global function redefinition: '"+CharToStr(func_name)+"'", ERR_PARSE);
			g_GlobalFunctions[func_name] = func;
			// parse body
			func->Parse(src);
			func->Optimize();
		}
		// - local
		else
		{
			Function *func = new Function(g_ScopeStack.back(), new Node, func_arg_count);
			// save function
			if (g_ScopeStack.back()->m_LocalFunctions[func_name])
				NodeError("Local function redefinition: '"+CharToStr(func_name)+"'", ERR_PARSE);
			g_ScopeStack.back()->m_LocalFunctions[func_name] = func;
			// parse body
			func->Parse(src);
			func->Optimize();
		}

		// this expression result
		m_Type = TYPE_CONSTANT;
		m_Value = (int)1;
	}
	// two args
	else if (m_Ch == '+' || m_Ch == '-' || m_Ch == '*' || m_Ch == '/' ||
		m_Ch == '^' || m_Ch == '%' || m_Ch == ':' ||
		m_Ch == '#' || m_Ch == ']' || m_Ch == '@' || m_Ch == '=' ||
		m_Ch == '>' || m_Ch == '<' || m_Ch == '&' || m_Ch == '|')
	{
		Node *node1 = new Node;
		Node *node2 = new Node;
		m_Sub.push_back(node1);
		m_Sub.push_back(node2);
		node1->Parse(src);
		node2->Parse(src);
	}
	// three args
	else if (m_Ch == '?')
	{
		Node *node1 = new Node;
		Node *node2 = new Node;
		Node *node3 = new Node;
		m_Sub.push_back(node1);
		m_Sub.push_back(node2);
		m_Sub.push_back(node3);
		node1->Parse(src);
		node2->Parse(src);
		node3->Parse(src);
	}
	// function call or variable
	else if (m_Ch >= 'a' && m_Ch <= 'z' || m_Ch >= 'A' && m_Ch <= 'Z')
	{
		// if function, fill in the m_Function
		m_Function = 0;
		// - global
		if (m_Ch >= 'A' && m_Ch <= 'Z')
			// assign proper pointer or 0
			m_Function = g_GlobalFunctions[m_Ch];
		// - local
		else
		{
			Scope *scope = g_ScopeStack.back();
			while (scope != 0)
			{
				if (scope->m_LocalFunctions[m_Ch])
				{
					m_Function = scope->m_LocalFunctions[m_Ch];
					break;
				}
				scope = scope->m_Parent;
			}
		}
		
		// this is function call
		if (m_Function)
		{
			// pointer to function is already saved in m_Function
			// argument count
			int arg_count = m_Function->m_ArgCount;
			if (arg_count == -1)
				arg_count = Parse_Integer(src);
			// arguments
			Node *node;
			for (int i = 0; i < arg_count; i++)
			{
				node = new Node;
				node->Parse(src);
				m_Sub.push_back(node);
			}
		}
		// this is variable - do nothing
		// m_Function stays 0
	}
	// variable arg count
	else if (m_Ch == ',' || m_Ch == '.' || m_Ch == '(' || m_Ch == '$') {
		int SubnodeCount = Parse_Integer(src);
		Node *node;
		for (int i = 0; i < SubnodeCount; i++)
		{
			node = new Node;
			node->Parse(src);
			m_Sub.push_back(node);
		}
	}
	else if (m_Ch == ';')
	{
		m_ExtraInt = Parse_Integer(src);
	}
	else if (m_Ch == '\'')
	{
		m_ExtraInt = Parse_Integer(src);
		if (m_ExtraInt == 0)
		{
			m_Type = TYPE_CONSTANT;
			m_Value = (int)(unsigned int)(unsigned char)src.GetS();
		}
		else if (m_ExtraInt == 1 || m_ExtraInt == 2)
		{
			// one subnode
			Node *node = new Node;
			node->Parse(src);
			m_Sub.push_back(node);
		}
		else
			NodeError("Invalid numeric constant in ''': "+IntToStr(m_ExtraInt), ERR_PARSE);
	}
	else
		// Erroneous character
		src.SrcError("Unsupported character: '" + CharToStr(m_Ch) + "'", ERR_PARSE);
}

void Node::Execute(Value *result, Value *args)
{
	// Value
	if (m_Type == TYPE_CONSTANT)
	{
		*result = m_Value;
		return;
	}

	// Code symbol
	if (m_Ch >= '0' && m_Ch <= '9')
	{
		*result = (int)(unsigned char)(m_Ch - '0');
	}
	// function call or variable
	else if (m_Ch >= 'a' && m_Ch <= 'z' || m_Ch >= 'A' && m_Ch <= 'Z')
	{
		// function call
		if (m_Function)
		{
			// construct argument list
			Value CallArgs = Value(Value::TYPE_LIST);
			Value CallArg;
			for (size_t i = 0; i < m_Sub.size(); i++)
			{
				m_Sub[i]->Execute(&CallArg, args);
				CallArgs.AccessList().push_back(CallArg);
			}
			// call function
			m_Function->Execute(result, &CallArgs);
		}
		// variable
		else
		{
			// global variable
			if (m_Ch >= 'A' && m_Ch <= 'Z')
			{
				if (g_GlobalVars.m_Values[m_Ch])
					*result = *g_GlobalVars.m_Values[m_Ch];
				else
					*result = (int)0;
			}
			// local variable
			else
				*result = g_VarContextStack.ReadVar(m_Ch);
		}
	}
	else if (m_Ch == '$')
	{
		Value element;
		*result = Value::TYPE_LIST;
		for (size_t i = 0; i < m_Sub.size(); i++)
		{
			m_Sub[i]->Execute(&element, args);
			result->AccessList().push_back(element);
		}
	}
	else if (m_Ch == ':')
	{
		m_Sub[1]->Execute(result, args);
		LValue lval = m_Sub[0]->GetLValue(args);
		// assign to a value
		if (lval.m_Type == LValue::TYPE_VALUE)
			*lval.m_Value = *result;
		// assign to a string character
		else
		{
			// string with length 1 is expected
			Value str_val;
			result->ConvertTo(&str_val, Value::TYPE_STRING);
			if (str_val.ReadString().length() != 1)
				NodeError("Cannot assing to string character string with length: "+Size_tToStr(str_val.ReadString().length()), ERR_EXECUTE);
			(*lval.m_String)[lval.m_StringIndex] = str_val.ReadString()[0];
		}
	}
	else if (m_Ch == '#')
	{
		Value val_l, val_n;
		m_Sub[1]->Execute(&val_n, args);
		m_Sub[0]->Execute(&val_l, args);
		int index = val_n.ConvertToInteger();
		if (val_l.GetType() == Value::TYPE_LIST)
		{
			if (index == -1)
				*result = (int)val_l.ReadList().size();
			else if (index >= 0 && index < (int)val_l.ReadList().size())
				*result = val_l.ReadList()[index];
			else
				NodeError("Cannot extract element from list with '#' on index: "+IntToStr(index)+" - index out of bounds (list size: "+Size_tToStr(val_l.ReadList().size())+")", ERR_EXECUTE);
		}
		else if (val_l.GetType() == Value::TYPE_STRING)
		{
			if (index == -1)
				*result = (int)val_l.ReadString().size();
			else if (index >= 0 && index < (int)val_l.ReadString().size())
				*result = CharToStr(val_l.ReadString()[index]);
			else
				NodeError("Cannot extract element from string with '#' on index: "+IntToStr(index)+" - index out of bounds (string size: "+Size_tToStr(val_l.ReadString().size())+")", ERR_EXECUTE);
		}
		else
			NodeError("Cannot extract element from "+val_l.GetTypeName()+" with '#' on index: "+IntToStr(index)+" - invalid type", ERR_EXECUTE);
	}
	else if (m_Ch == '(')
	{
		*result = (int)0;
		for (size_t i = 0; i < m_Sub.size(); i++)
			m_Sub[i]->Execute(result, args);
	}
	else if (m_Ch == '@')
	{
		*result = (int)0;
		Value condition_value;
		for (;;)
		{
			m_Sub[0]->Execute(&condition_value, args);
			if (!condition_value.ConvertToBool())
				break;
			m_Sub[1]->Execute(result, args);
		}
	}
	else if (m_Ch == '?')
	{
		Value ConditionValue;
		m_Sub[0]->Execute(&ConditionValue, args);
		if (ConditionValue.ConvertToBool())
			m_Sub[1]->Execute(result, args);
		else
			m_Sub[2]->Execute(result, args);
	}
	else if (m_Ch == '!') {
		m_Sub[0]->Execute(result, args);
		result->ConsoleOut();
	}
	else if (m_Ch == ';')
	{
		switch (m_ExtraInt)
		{
		case 0:
			*result = Value::TYPE_STRING;
			result->AccessString() += g_Console.InChar();
			break;
		case 1:
			*result = g_Console.InInteger();
			break;
		case 2:
			*result = g_Console.InDouble();
			break;
		case 3:
			*result = Value::TYPE_STRING;
			g_Console.InString(&result->AccessString());
			break;
		}
	}
	else if (m_Ch == '=' || m_Ch == '<' || m_Ch == '>')
	{
		Value v1, v2;
		m_Sub[0]->Execute(&v1, args);
		m_Sub[1]->Execute(&v2, args);
		OpComparison(m_Ch, result, v1, v2);
	}
	else if (m_Ch == '+')
	{
		Value v1, v2;
		m_Sub[0]->Execute(&v1, args);
		m_Sub[1]->Execute(&v2, args);
		OpAdd(result, v1, v2);
	}
	else if (m_Ch == '-' || m_Ch == '*' || m_Ch == '%')
	{
		Value v1, v2;
		m_Sub[0]->Execute(&v1, args);
		m_Sub[1]->Execute(&v2, args);
		OpSubMulMod(m_Ch, result, v1, v2);
	}
	else if (m_Ch == '/' || m_Ch == '^')
	{
		Value v1, v2;
		m_Sub[0]->Execute(&v1, args);
		m_Sub[1]->Execute(&v2, args);
		OpDivPow(m_Ch, result, v1, v2);
	}
	else if (m_Ch == '\\')
	{
		Value v;
		m_Sub[0]->Execute(&v, args);
		OpFloor(result, v);
	}
	else if (m_Ch == '&')
	{
		Value V;
		bool B;
		m_Sub[0]->Execute(&V, args);
		B = V.ConvertToBool();
		if (B)
		{
			m_Sub[1]->Execute(&V, args);
			B = V.ConvertToBool();
		}
		*result = (int)(B ? 1 : 0);
	}
	else if (m_Ch == '|')
	{
		Value V;
		bool B;
		m_Sub[0]->Execute(&V, args);
		B = ! V.ConvertToBool();
		if (B)
		{
			m_Sub[1]->Execute(&V, args);
			B = ! V.ConvertToBool();
		}
		*result = (int)(B ? 0 : 1);
	}
	else if (m_Ch == '[')
	{
		LValue lval = m_Sub[0]->GetLValue(args);
		if (lval.m_Type != LValue::TYPE_VALUE)
			NodeError("Tyme mismatch in '[' - list or string expected", ERR_EXECUTE);
		if (lval.m_Value->GetType() == Value::TYPE_LIST)
		{
			if (lval.m_Value->ReadList().empty())
				NodeError("Empty list for '['", ERR_EXECUTE);
			*result = lval.m_Value->ReadList().back();
			lval.m_Value->AccessList().pop_back();
		}
		else if (lval.m_Value->GetType() == Value::TYPE_STRING)
		{
			if (lval.m_Value->ReadString().empty())
				NodeError("Empty string for '['", ERR_EXECUTE);
			*result = CharToStr(lval.m_Value->ReadString()[lval.m_Value->ReadString().size()-1]);
			lval.m_Value->AccessString().erase(lval.m_Value->ReadString().size()-1);
		}
		else
			NodeError("Invalid l-value for '[' ("+lval.m_Value->GetTypeName()+") - list or string expected", ERR_EXECUTE);
	}
	else if (m_Ch == ']')
	{
		Value NewValue;
		m_Sub[1]->Execute(&NewValue, args);
		LValue lval = m_Sub[0]->GetLValue(args);

		if (lval.m_Type != LValue::TYPE_VALUE)
			NodeError("Type mismatch in ']' - list or string expected", ERR_EXECUTE);

		if (lval.m_Value->GetType() == Value::TYPE_LIST)
			lval.m_Value->AccessList().push_back(NewValue);
		else if (lval.m_Value->GetType() == Value::TYPE_STRING)
		{
			if (NewValue.GetType() != Value::TYPE_STRING || NewValue.ReadString().size() != 1)
				NodeError("Invalid argument for ']' - single character expected", ERR_EXECUTE);
			lval.m_Value->AccessString() += NewValue.ReadString()[0];
		}
		else
			NodeError("Invalid l-value for ']' ("+lval.m_Value->GetTypeName()+") - list or string expected", ERR_EXECUTE);

		*result = *lval.m_Value;
	}
	else if (m_Ch == '_')
		*result = *args;
	else if (m_Ch == '\'')
	{
		Value v;
		m_Sub[0]->Execute(&v, args);
		OpAposConverter(m_ExtraInt, result, v);
	}
	else if (m_Ch == '`')
	{
		// read string
		Value str;
		m_Sub[0]->Execute(&str, args);
		if (str.GetType() != Value::TYPE_STRING)
			NodeError("String expected for '`' - found: "+str.GetTypeName(), ERR_EXECUTE);
		// parse code
		Source src(&str.ReadString());
		Node *node = new Node;
		node->ParseToEnd(src);
		node->Optimize();
		node->Execute(result, args);
		delete node;
	}
	else
		NodeError("Unknown command: '"+CharToStr(m_Ch)+"'", ERR_EXECUTE);
}

LValue Node::GetLValue(Value *args)
{
	// variable
	if (m_Ch >= 'a' && m_Ch <= 'z' || m_Ch >= 'A' && m_Ch <= 'Z')
	{
		// function - error
		if (m_Function)
			NodeError("Cannot return '"+CharToStr(m_Ch)+"' as l-value - it is a function call", ERR_EXECUTE);
		// global variable
		if (m_Ch >= 'A' && m_Ch <= 'Z')
		{
			if (!g_GlobalVars.m_Values[m_Ch])
				g_GlobalVars.m_Values[m_Ch] = new Value((int)0);
			return LValue(g_GlobalVars.m_Values[m_Ch]);
		}
		// local variable
		else
			return LValue(&g_VarContextStack.AccessVar(m_Ch));
	}
	else if (m_Ch == '_')
		return LValue(args);
	else if (m_Ch == '(')
	{
		if (m_Sub.size() == 0)
			NodeError("Cannot return empty '(' as l-value", ERR_EXECUTE);
		return m_Sub.back()->GetLValue(args);
	}
	else if (m_Ch == '@')
	{
		LValue lval;
		bool OK = false;
		Value condition_value;
		for (;;)
		{
			m_Sub[0]->Execute(&condition_value, args);
			if (!condition_value.ConvertToBool())
				break;
			lval = m_Sub[1]->GetLValue(args);
			OK = true;
		}
		if (!OK)
			NodeError("Cannot return loop with 0 iterations as l-value", ERR_EXECUTE);
		return lval;
	}
	else if (m_Ch == '#')
	{
		LValue result;
		Value val_n;
		m_Sub[1]->Execute(&val_n, args);
		LValue val_l = m_Sub[0]->GetLValue(args);
		int index = val_n.ConvertToInteger();

		if (val_l.m_Type == LValue::TYPE_STRCHAR)
		{
			if (index == 0)
				result = val_l;
			else
				NodeError("Cannot return element of string's element as l-value if index "+IntToStr(index)+" is not 0", ERR_EXECUTE);
		}
		else
		{
			if (val_l.m_Value->GetType() == Value::TYPE_LIST)
			{
				if (index >= 0 && index < (int)val_l.m_Value->ReadList().size())
				{
					result.m_Type = LValue::TYPE_VALUE;
					result.m_Value = &val_l.m_Value->AccessList()[index];
				}
				else
					NodeError("Cannot return element of list as l-value - index "+IntToStr(index)+" out of bounds", ERR_EXECUTE);
			}
			else if (val_l.m_Value->GetType() == Value::TYPE_STRING)
			{
				if (index >= 0 && index < (int)val_l.m_Value->ReadString().size())
				{
					result.m_Type = LValue::TYPE_STRCHAR;
					result.m_String = &val_l.m_Value->AccessString();
					result.m_StringIndex = index;
				}
				else
					NodeError("Cannot return element of string as l-value - index "+IntToStr(index)+" out of bounds", ERR_EXECUTE);
			}
			else
				NodeError("Cannot return element of "+val_l.m_Value->GetTypeName()+" as l-value", ERR_EXECUTE);
		}
		return result;
	}
	else if (m_Ch == ']')
	{
		Value NewValue;
		m_Sub[1]->Execute(&NewValue, args);
		LValue lval = m_Sub[0]->GetLValue(args);

		if (lval.m_Type != LValue::TYPE_VALUE)
			NodeError("Type mismatch in ']' - list or string expected", ERR_EXECUTE);

		if (lval.m_Value->GetType() == Value::TYPE_LIST)
			lval.m_Value->AccessList().push_back(NewValue);
		else if (lval.m_Value->GetType() == Value::TYPE_STRING)
		{
			if (NewValue.GetType() != Value::TYPE_STRING || NewValue.ReadString().size() != 1)
				NodeError("Invalid argument for ']' - single character expected", ERR_EXECUTE);
			lval.m_Value->AccessString() += NewValue.ReadString()[0];
		}
		else
			NodeError("Invalid l-value for ']' ("+lval.m_Value->GetTypeName()+") - list or string expected", ERR_EXECUTE);

		return lval;
	}
	else if (m_Ch == '?')
	{
		Value ConditionValue;
		m_Sub[0]->Execute(&ConditionValue, args);
		if (ConditionValue.ConvertToBool())
			return m_Sub[1]->GetLValue(args);
		else
			return m_Sub[2]->GetLValue(args);
	}
	else
	{
		NodeError("Cannot obtain l-value from symbol: '"+CharToStr(m_Ch)+"'", ERR_EXECUTE);
		return LValue();
	}
}

void Node::Optimize()
{
	if (m_Type == TYPE_CONSTANT)
		return;

	// optimize subnodes
	for (size_t i = 0; i < m_Sub.size(); i++)
		m_Sub[i]->Optimize();

	// optimize this node
	if (m_Ch >= '0' && m_Ch <= '9') {
		m_Type = TYPE_CONSTANT;
		m_Value = (int)(unsigned char)(m_Ch - '0');
	}
	else if (m_Ch == ',')
	{
		m_Type = TYPE_CONSTANT;
		m_Value = (int)0;
		for (size_t i = 0; i < m_Sub.size(); i++)
		{
			if (m_Sub[i]->m_Type != TYPE_CONSTANT)
				m_Sub[i]->NodeError("Cannot evaluate digit value for ',' in compilation time for digit index: " + Size_tToStr(i), ERR_OPTIMIZE);
			m_Value.AcceessInteger() = m_Value.AcceessInteger() * 10 + m_Sub[i]->m_Value.ConvertToInteger();
		}
		ClearSubnodes();
	}
	else if (m_Ch == '.')
	{
		m_Type = TYPE_CONSTANT;
		m_Value = (double)0.0;
		double factor = 0.1;
		for (size_t i = 0; i < m_Sub.size(); i++)
		{
			if (m_Sub[i]->m_Type != Node::TYPE_CONSTANT)
				m_Sub[i]->NodeError("Cannot evaluate digit value for '.' in compilation time for digit index: " + Size_tToStr(i), ERR_OPTIMIZE);
			m_Value.AccessDouble() += m_Sub[i]->m_Value.ConvertToInteger() * factor;
			factor *= 0.1;
		}
		ClearSubnodes();
	}
	else if (m_Ch == '(')
	{
		for (int i = (int)m_Sub.size()-2; i >= 0; i--)
		{
			if (m_Sub[i]->m_Type == TYPE_CONSTANT)
			{
				delete m_Sub[i];
				m_Sub.erase(m_Sub.begin()+i);
			}
		}
	}
	else if (m_Ch == '+')
	{
		if (m_Sub[0]->m_Type == TYPE_CONSTANT && m_Sub[1]->m_Type == TYPE_CONSTANT)
		{
			m_Type = TYPE_CONSTANT;
			OpAdd(&m_Value, m_Sub[0]->m_Value, m_Sub[1]->m_Value);
			ClearSubnodes();
		}
	}
	else if (m_Ch == '-' || m_Ch == '*' || m_Ch == '%')
	{
		if (m_Sub[0]->m_Type == TYPE_CONSTANT && m_Sub[1]->m_Type == TYPE_CONSTANT)
		{
			m_Type = TYPE_CONSTANT;
			OpSubMulMod(m_Ch, &m_Value, m_Sub[0]->m_Value, m_Sub[1]->m_Value);
			ClearSubnodes();
		}
	}
	else if (m_Ch == '/' || m_Ch == '^')
	{
		if (m_Sub[0]->m_Type == TYPE_CONSTANT && m_Sub[1]->m_Type == TYPE_CONSTANT)
		{
			m_Type = TYPE_CONSTANT;
			OpDivPow(m_Ch, &m_Value, m_Sub[0]->m_Value, m_Sub[1]->m_Value);
			ClearSubnodes();
		}
	}
	else if (m_Ch == '\\')
	{
		if (m_Sub[0]->m_Type == TYPE_CONSTANT)
		{
			m_Type = TYPE_CONSTANT;
			OpFloor(&m_Value, m_Sub[0]->m_Value);
			ClearSubnodes();
		}
	}
	else if (m_Ch == '\'')
	{
		if (m_Sub[0]->m_Type == TYPE_CONSTANT)
		{
			m_Type = TYPE_CONSTANT;
			OpAposConverter(m_ExtraInt, &m_Value, m_Sub[0]->m_Value);
			ClearSubnodes();
		}
	}
	else if (m_Ch == '@')
	{
		if (m_Sub[0]->m_Type == TYPE_CONSTANT && m_Sub[0]->m_Value.ConvertToBool() == false)
		{
			m_Type = TYPE_CONSTANT;
			m_Value = (int)0;
			ClearSubnodes();
		}
	}
	else if (m_Ch == '#')
	{
		if (m_Sub[0]->m_Type == TYPE_CONSTANT && m_Sub[1]->m_Type == TYPE_CONSTANT)
		{
			m_Type = TYPE_CONSTANT;
			Value &val_l = m_Sub[0]->m_Value;
			Value &val_n = m_Sub[1]->m_Value;
			int index = val_n.ConvertToInteger();
			if (val_l.GetType() == Value::TYPE_LIST)
			{
				if (index == -1)
					m_Value = (int)val_l.ReadList().size();
				else if (index >= 0 && index < (int)val_l.ReadList().size())
					m_Value = val_l.ReadList()[index];
				else
					NodeError("Cannot extract element from list with '#' on index: "+IntToStr(index)+" - index out of bounds", ERR_OPTIMIZE);
			}
			else if (val_l.GetType() == Value::TYPE_STRING)
			{
				if (index == -1)
					m_Value = (int)val_l.ReadString().size();
				else if (index >= 0 && index < (int)val_l.ReadString().size())
					m_Value = CharToStr(val_l.ReadString()[index]);
				else
					NodeError("Cannot extract element from string with '#' on index: "+IntToStr(index)+" - index out of bounds", ERR_OPTIMIZE);
			}
			else
				NodeError("Cannot extract element from "+val_l.GetTypeName()+" with '#' on index: "+IntToStr(index)+" - invalid type", ERR_OPTIMIZE);
			ClearSubnodes();
		}
	}
	else if (m_Ch == '$')
	{
		size_t i;
		for (i = 0; i < m_Sub.size(); i++)
			if (m_Sub[i]->m_Type != TYPE_CONSTANT)
				return;

		m_Type = TYPE_CONSTANT;
		m_Value = Value::TYPE_LIST;
		Value element;
		for (i = 0; i < m_Sub.size(); i++)
			m_Value.AccessList().push_back(m_Sub[i]->m_Value);

		ClearSubnodes();
	}
	else if (m_Ch == '&')
	{
		bool Const1 = (m_Sub[0]->m_Type == TYPE_CONSTANT);
		bool Const2 = (m_Sub[1]->m_Type == TYPE_CONSTANT);

		if (Const1 && Const2)
		{
			m_Type = TYPE_CONSTANT;
			m_Value = (int)(m_Sub[0]->m_Value.ConvertToBool() && m_Sub[1]->m_Value.ConvertToBool() ? 1 : 0);
			ClearSubnodes();
		}
		else if (Const1 && m_Sub[0]->m_Value.ConvertToBool() == false)
		{
			m_Type = TYPE_CONSTANT;
			m_Value = (int)0;
			ClearSubnodes();
		}
	}
	else if (m_Ch == '|')
	{
		bool Const1 = (m_Sub[0]->m_Type == TYPE_CONSTANT);
		bool Const2 = (m_Sub[1]->m_Type == TYPE_CONSTANT);

		if (Const1 && Const2)
		{
			m_Type = TYPE_CONSTANT;
			m_Value = (int)(m_Sub[0]->m_Value.ConvertToBool() || m_Sub[1]->m_Value.ConvertToBool() ? 1 : 0);
			ClearSubnodes();
		}
		else if (Const1 && m_Sub[0]->m_Value.ConvertToBool() == true)
		{
			m_Type = TYPE_CONSTANT;
			m_Value = (int)1;
			ClearSubnodes();
		}
	}
	else if (m_Ch == '=' || m_Ch == '>' || m_Ch == '<')
	{
		if (m_Sub[0]->m_Type == TYPE_CONSTANT && m_Sub[1]->m_Type == TYPE_CONSTANT)
		{
			m_Type = TYPE_CONSTANT;
			OpComparison(m_Ch, &m_Value, m_Sub[0]->m_Value, m_Sub[1]->m_Value);
			ClearSubnodes();
		}
	}
	else if (m_Ch == '[')
	{
		if (m_Sub[0]->m_Type == TYPE_CONSTANT)
		{
			m_Type = TYPE_CONSTANT;

			if (m_Sub[0]->m_Value.GetType() == Value::TYPE_LIST)
			{
				if (m_Sub[0]->m_Value.ReadList().empty())
					NodeError("Empty list for '['", ERR_OPTIMIZE);
				m_Value = m_Sub[0]->m_Value.ReadList().back();
			}
			else if (m_Sub[0]->m_Value.GetType() == Value::TYPE_STRING)
			{
				if (m_Sub[0]->m_Value.ReadString().empty())
					NodeError("Empty string for '['", ERR_OPTIMIZE);
				m_Value = CharToStr(m_Sub[0]->m_Value.ReadString()[m_Sub[0]->m_Value.ReadString().size()-1]);
			}
			else
				NodeError("Invalid l-value for '[' ("+m_Sub[0]->m_Value.GetTypeName()+") - list or string expected", ERR_OPTIMIZE);

			ClearSubnodes();
		}
	}
	else if (m_Ch == '?')
	{
		if (m_Sub[0]->m_Type == TYPE_CONSTANT && m_Sub[1]->m_Type == TYPE_CONSTANT && m_Sub[2]->m_Type == TYPE_CONSTANT)
		{
			m_Type = TYPE_CONSTANT;

			if (m_Sub[0]->m_Value.ConvertToBool())
				m_Value = m_Sub[1]->m_Value;
			else
				m_Value = m_Sub[2]->m_Value;

			ClearSubnodes();
		}
	}
}

//==============================================================================

Scope *g_GlobalScope;

void Intro()
{
	std::cerr << "Badly Developed SADOL Machine\n"
		"Version: 2.0, 21 Dec 2005\n"
		"\n"
		"Copyright (C) 2005 Adam Sawicki\n"
		"All rights reserved\n"
		"\n"
		"Implementation of the SADOL esoteric programming language interpreter.\n"
		"\n"
		"Usage:\n"
		"  BDSM <source-file>\n";
}

void Interpret(const string &Src)
{
//	std::cout << Src << std::endl;

	for (char ch = 'a'; ch < 'z'; ch++)
		g_GlobalFunctions[ch] = 0;

	Source src_obj(&Src);

	g_GlobalScope = new Scope(0, new Node);
	g_GlobalScope->ParseToEnd(src_obj);
	g_GlobalScope->Optimize();
	Value VOut;
	Value VArgs = Value(Value::TYPE_LIST);
	g_GlobalScope->Execute(&VOut, &VArgs);
	delete g_GlobalScope;
}

void Go(const char *FileName)
{
	// Open source file
	FILE *file = fopen(FileName, "rb");
	if (file == 0)
		Error("Cannot open file: "+string(FileName));

	// Read source into string
	char buf[BUF_SIZE];
	size_t count;
	string src;
	for (;;) {
		count = fread(buf, 1, BUF_SIZE, file);
		if (count > 0) {
			src.append(buf, count);
		}
		else break;
	}

	// Close source file
	fclose(file);

	// Interpret!
	Interpret(src);
}

int main(int argc, char **argv)
{
	if (argc == 2)
	{
		Go(argv[1]);
		return 0;
	}
	else {
		Intro();
		return -1;
	}
}

/* When error, every function can call Error.
*/