Mercurial > repo
view interps/sadol/BDSM2.cpp @ 12518:2d8fe55c6e65 draft default tip
<int-e> learn The password of the month is release incident pilot.
author | HackEso <hackeso@esolangs.org> |
---|---|
date | Sun, 03 Nov 2024 00:31:02 +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. */