/* * Copyright (c) 2015-2017 Carsten Sonne Larsen * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #include "mem.h" #include "clib.h" #include "lib/real.h" #include "lib/charbuf.h" #include "localize/help.h" #include "localize/text.h" #include "localize/start.h" #include "main/parser.h" #include "main/graphlist.h" #include "main/statements.h" #include "system/console.h" #include "system/program.h" // ----------------------------------------------------- // ------------------ ClearStatement ------------------- // ----------------------------------------------------- char* ClearStatement::Execute() { Program->Console->Clear(); return (char*)EMPTYSTRING; } // ----------------------------------------------------- // ------------------- ExitStatement ------------------- // ----------------------------------------------------- char* ExitStatement::Execute() { Program->Exit(); return (char*)EMPTYSTRING; } // ----------------------------------------------------- // ------------------ EmptyStatement ------------------- // ----------------------------------------------------- char* EmptyStatement::Execute() { return (char*)EMPTYSTRING; } // ----------------------------------------------------- // ----------------- VersionStatement ------------------ // ----------------------------------------------------- char* VersionStatement::Execute() { output->Empty(); output->EnsureSize( StrLen(BOLD) + StrLen(TXTVERSMSG) + StrLen(NEWLINE) * 2 + StrLen(NORMALTEXT) + StrLen(TXTCOMPMSG)); output->Append(BOLD); output->Append(TXTVERSMSG); output->Append(NORMALTEXT); output->Append(NEWLINE); output->Append(TXTCOMPMSG); output->Append(NEWLINE); return output->GetString(); } // ----------------------------------------------------- // ------------------ PromptStatement ------------------ // ----------------------------------------------------- PromptStatement::PromptStatement(char* prompt) { AllocAndCopy(&this->prompt,prompt); } PromptStatement::~PromptStatement() { delete prompt; } char* PromptStatement::Execute() { CharBuffer *buf = new CharBuffer(); buf->ClearAndCopy(prompt); while(buf->RemoveTrailing(' ')); buf->Append(' '); Program->SetPrompt(buf->GetString()); delete buf; return (char*)EMPTYSTRING; } // ----------------------------------------------------- // ----------------- PrefsStatement -------------------- // ----------------------------------------------------- PrefsStatement::PrefsStatement() { argument = Symbol(0); } PrefsStatement::PrefsStatement(Symbol argument) { this->argument = argument; } char* PrefsStatement::Execute() { bool success; if (argument == symsave) { success = Program->Preferences->Keep(); success &= Program->Preferences->Save(); return (success ? HELPPREFSAVE : HELPPREFNOSA); } else if (argument == symload) { success = Program->Preferences->Load(); if (success) { Program->Console->SetPrompt( Program->Preferences->GetPrompt()); Program->Input->SetDigits( Program->Preferences->GetDigits()); Program->Output->SetDigits( Program->Preferences->GetDigits()); return(HELPPREFLOAD); } else { return(HELPPREFNOLO); } } return Program->Preferences->GetDescription(); } // ----------------------------------------------------- // ----------------- MemoryStatement ------------------ // ----------------------------------------------------- char* MemoryStatement::Execute() { long blocks, size, peak; MemUsage(&blocks, &size, &peak); Number *a = new RealNumber((int)blocks); Number *b = new RealNumber((int)size); Number *c = new RealNumber((int)peak); NumeralSystem *ns = new DecimalSystem(8); output->Empty(); output->EnsureSize( StrLen(TXTMEMBLOCKS) + 8 + StrLen(TXTMEMSIZE) + 12 + StrLen(TXTMEMMAXSIZE) + 12); output->Append(TXTMEMBLOCKS); output->Append(ns->GetText(a)); output->Append(NEWLINE); output->Append(TXTMEMSIZE); output->Append(ns->GetText(b)); output->Append(NEWLINE); output->Append(TXTMEMMAXSIZE); output->Append(ns->GetText(c)); output->Append(NEWLINE); delete a; delete b; delete c; delete ns; return output->GetString(); } // ----------------------------------------------------- // ------------------ SilentStatement ------------------ // ----------------------------------------------------- SilentStatement::SilentStatement(StatementNode* statement) : statement(statement) { } SilentStatement::~SilentStatement() { if (statement != NOMEM) { delete statement; } } char* SilentStatement::Execute() { statement->Execute(); return (char*)EMPTYSTRING; } SyntaxNode* SilentStatement::GetNext() { if (iterator == NOMEM) { iterator = statement; return iterator; } return NOMEM; } void SilentStatement::Attach(SyntaxNode* node) { if (statement == NOMEM) { statement = (StatementNode*)node; node->SetParent(this); } } void SilentStatement::Detach(SyntaxNode* node) { if (statement == node) { statement = NOMEM; } } void SilentStatement::Replace(SyntaxNode* n, SyntaxNode* x) { if (statement == n) { delete statement; statement = (StatementNode*)x; } } // ----------------------------------------------------- // ------------------- EvalStatement ------------------- // ----------------------------------------------------- EvalStatement::EvalStatement(ExpressionNode* expression) : StatementNode(), expression(expression) { } EvalStatement::~EvalStatement() { if (expression != NOMEM) { delete expression; } } char* EvalStatement::Execute() { Number* result = expression->Evaluate(); Program->SetLastResult(result); const char *text = expression->GetText(); const char *val = Program->Output->GetText(result); output->Empty(); output->EnsureSize( StrLen(text) + 3 + StrLen(val) + StrLen(NEWLINE) + 1); output->Append(text); output->Append(" = "); output->Append(val); output->Append(NEWLINE); return output->GetString(); } SyntaxNode* EvalStatement::GetNext() { if (iterator == NOMEM) { iterator = expression; return iterator; } return NOMEM; } void EvalStatement::Attach(SyntaxNode* node) { if (expression == NOMEM) { expression = (ExpressionNode*)node; node->SetParent(this); } } void EvalStatement::Detach(SyntaxNode* node) { if (expression == node) { expression = NOMEM; } } void EvalStatement::Replace(SyntaxNode* n, SyntaxNode* x) { if (expression == n) { delete expression; expression = (ExpressionNode*)x; } } // ----------------------------------------------------- // ------------------- HelpStatement ------------------- // ----------------------------------------------------- HelpStatement::HelpStatement() : StatementNode() { argument = (Symbol)0; ident = NOMEM; } HelpStatement::HelpStatement(Symbol argument) : StatementNode(), argument(argument) { ident = NOMEM; } HelpStatement::HelpStatement(const char *ident) { argument = symident; AllocAndCopy(&this->ident, ident); } HelpStatement::~HelpStatement() { if (ident != NOMEM) { delete [] ident; } } char* HelpStatement::Execute() { char *text = argument != symident ? Program->Language->GetHelpText(argument) : Program->Language->GetHelpText(ident); output->ClearAndCopy(text); return output->GetString(); } // ----------------------------------------------------- // ----------------- DeleteStatement ------------------- // ----------------------------------------------------- /** * @brief Constructor used to delete either all variable or functions. * */ DeleteStatement::DeleteStatement(Symbol symbol) { type = symbol; name = NOMEM; argument = NOMEM; } /** * @brief Constructor used to delete a Variable. * */ DeleteStatement::DeleteStatement(const char *name) : StatementNode() { type = symvariable; AllocAndCopy(&this->name, name); argument = NOMEM; } /** * @brief Constructor used to delete a function. * */ DeleteStatement::DeleteStatement(const char *name, const char *argument) : StatementNode() { type = symfunction; AllocAndCopy(&this->name, name); AllocAndCopy(&this->argument, argument); } DeleteStatement::~DeleteStatement() { if (name != NOMEM) { delete [] name; } if (argument != NOMEM) { delete [] argument; } } char* DeleteStatement::Execute() { bool success = true; output->Empty(); if (type == symvariable && name == NOMEM) { Program->Variables->Clear(); } else if (type == symvariable && name != NOMEM) { success = Program->Variables->Delete(name); const char *msg = HELPVARNDEF; output->EnsureSize( StrLen(msg) + StrLen(name) + StrLen(NEWLINE) + 1); output->Append(msg); output->Append(name); output->Append(NEWLINE); } else if (type == symfunction && name == NOMEM) { Program->Functions->Clear(); } else if (type == symfunction && name != NOMEM) { success = Program->Functions->Delete(name, argument); const char *msg = HELPFUNNDEF; output->EnsureSize( StrLen(msg) + StrLen(name) + 2 + StrLen(argument) + StrLen(NEWLINE) + 1); output->Append(msg); output->Append(name); output->Append("("); output->Append(argument); output->Append(")"); output->Append(NEWLINE); } return (char*)(success ? EMPTYSTRING : output->GetString()); } // ----------------------------------------------------- // ----------------- InputStatement -------------------- // ----------------------------------------------------- /** * @brief Constructor used to show number of active digits. * */ InputStatement::InputStatement() : base(0) { } /** * @brief Constructor used to set number of active digits. * */ InputStatement::InputStatement(unsigned int base) : StatementNode(), base(base) { } char* InputStatement::Execute() { const char *text; if (base != 0) { int digits = Program->Input->GetDigits(); Program->NewPositionalInput(base, digits); text = HELPINPUSETT; } else { text = HELPINPUSHOW; } const char *desc = Program->Input->GetName(); output->Empty(); output->EnsureSize(StrLen(text) + StrLen(desc) + StrLen(NEWLINE) + 1); output->Append(text); output->Append(desc); output->Append(NEWLINE); return output->GetString(); } // ----------------------------------------------------- // ----------------- OutputStatement ------------------- // ----------------------------------------------------- /** * @brief Constructor used to show number of active digits. * */ OutputStatement::OutputStatement() : base(0) { } /** * @brief Constructor used to set number of active digits. * */ OutputStatement::OutputStatement(unsigned int base) : StatementNode(), base(base) { } char* OutputStatement::Execute() { const char *text; if (base != 0) { int digits = Program->Output->GetDigits(); Program->NewPositionalOutput(base, digits); text = HELPOUTPSETT; } else { text = HELPOUTPSHOW; } const char *desc = Program->Output->GetName(); output->Empty(); output->EnsureSize(StrLen(text) + StrLen(desc) + StrLen(NEWLINE) + 1); output->Append(text); output->Append(desc); output->Append(NEWLINE); return output->GetString(); } // ----------------------------------------------------- // ----------------- DigitsStatement ------------------- // ----------------------------------------------------- /** * @brief Constructor used to show number of active digits. * */DigitsStatement::DigitsStatement() { show = true; } /** * @brief Constructor used to show number of active digits. * */ DigitsStatement::DigitsStatement(unsigned int digits) : digits(digits) { show = false; } char* DigitsStatement::Execute() { const char *text; if (!show) { Program->Input->SetDigits(digits); Program->Output->SetDigits(digits); Program->Preferences->SetDigits(digits); text = HELPDIGISETT; } else { text = HELPDIGISHOW; digits = Program->Output->GetDigits(); } Number *d = new RealNumber(digits); NumeralSystem *ns = new DecimalSystem(2); const char *dtext = ns->GetText(d); delete d; output->Empty(); output->EnsureSize(StrLen(text) + StrLen(dtext) + StrLen(NEWLINE) + 1); output->Append(text); output->Append(dtext); output->Append(NEWLINE); delete ns; return output->GetString(); } // ----------------------------------------------------- // ------------------ ShowStatement -------------------- // ----------------------------------------------------- ShowStatement::ShowStatement(const char* file) { AllocAndCopy(&this->file, file); } ShowStatement::~ShowStatement() { delete [] file; } char* ShowStatement::Execute() { CharBuffer *text = Program->Filesystem->LoadTextFile(file); if (text == NOMEM) { return (char*)(MSGNOFILE); } delete output; output = text; return text->GetString(); } // ----------------------------------------------------- // ------------------ ListStatement -------------------- // ----------------------------------------------------- ListStatement::ListStatement() : StatementNode() { directory = NOMEM; } ListStatement::ListStatement(const char *directory) : StatementNode() { AllocAndCopy(&this->directory, directory); } ListStatement::~ListStatement() { if (directory != NOMEM) { delete [] directory; } } char* ListStatement::Execute() { CharBuffer *text = Program->Filesystem->ListDirectory(directory); if (text == NOMEM) { return (char*)(MSGNODIR); } delete output; output = text; return text->GetString(); } // ----------------------------------------------------- // ------------------ LoadStatement -------------------- // ----------------------------------------------------- LoadStatement::LoadStatement(const char *file) { AllocAndCopy(&this->file, file); } LoadStatement::~LoadStatement() { delete [] file; } char* LoadStatement::Execute() { CharBuffer *input = Program->Filesystem->LoadTextFile(file); if (input == NOMEM) { return (char*)(MSGNOFILE); } Parser *parser = new Parser(input->GetString()); delete input; SyntaxNode *node = parser->Parse(); delete parser; node->Execute(); delete node; return (char*)HELPLOADSUCC; } // ----------------------------------------------------- // ------------------ SaveStatement -------------------- // ----------------------------------------------------- SaveStatement::SaveStatement(const char *file) { AllocAndCopy(&this->file, file); } SaveStatement::~SaveStatement() { delete [] file; } char* SaveStatement::Execute() { const char *vars = Program->Variables->ListDefinitions(); const char *funcs = Program->Functions->ListDefinitions(); if (vars == NOMEM && funcs == NOMEM) { return (char*)HELPSAVENOTH; } int len = 1; len += vars != NOMEM ? StrLen(vars) : 0; len += funcs != NOMEM ? StrLen(funcs) : 0; CharBuffer *text = new CharBuffer(len); text->Empty(); if (vars != NOMEM) { text->Append(vars); } if (funcs != NOMEM) { text->Append(funcs); } bool success = Program->Filesystem->SaveTextFile(file, text->GetString()); delete text; return (char*)(success ? HELPSAVESUCC : HELPSAVEFAIL); } // ----------------------------------------------------- // ---------------- ExecuteStatement ------------------- // ----------------------------------------------------- ExecuteStatement::ExecuteStatement(const char *file) { AllocAndCopy(&this->file, file); } ExecuteStatement::~ExecuteStatement() { delete [] file; } char* ExecuteStatement::Execute() { CharBuffer *input = Program->Filesystem->LoadTextFile(file); if (input == NOMEM) { return (char*)(MSGNOFILE); } Parser *parser = new Parser(input->GetString()); delete input; SyntaxNode *node = parser->Parse(); delete parser; const char *res = node->Execute(); output->ClearAndCopy(res); delete node; return output->GetString(); } // ----------------------------------------------------- // ------------------ PlotStatement -------------------- // ----------------------------------------------------- PlotStatement::PlotStatement(const char* name, const char* parameter, const char* file) : StatementNode() { AllocAndCopy(&this->name, name); AllocAndCopy(&this->parameter, parameter); AllocAndCopy(&this->file, file); } PlotStatement::PlotStatement(const char* name, const char* parameter) : StatementNode() { AllocAndCopy(&this->name, name); AllocAndCopy(&this->parameter, parameter); file = NOMEM; } PlotStatement::~PlotStatement() { delete [] name; delete [] parameter; if (file != NOMEM) { delete [] file; } } char* PlotStatement::Execute() { UserFunction *function = Program->Functions->GetFunctionDef(name, parameter); if (function == NOMEM) { return (char*)("Function does not exists." NEWLINE); } output->Empty(); Grid *grid = new Grid(function); static const int width = 400; static const int height = 300; grid->SetScreenBounderues(0, width, 20, height); bool first = true; static const double min = -5.0; static const double max = +5.0; grid->SetFunctionBounderies(min, max); double x = min; double step = grid->GetHorizontalResolution(); int screenX; int screenY; RealNumber *n = new RealNumber(); NumeralSystem *ns = new DecimalSystem(5); while (x < max) { grid->GetScreenCoordinates(x, &screenX, &screenY); output->EnsureGrowth(32); if (screenX != -1 && screenY != -1) { if (first) { output->Append('('); n->SetRealValue(screenX); output->Append(ns->GetText(n)); output->Append(','); n->SetRealValue(height - screenY); output->Append(ns->GetText(n)); output->Append(')'); output->Append(NEWLINE); first = false; } else { output->Append('('); n->SetRealValue(screenX); output->Append(ns->GetText(n)); output->Append(','); n->SetRealValue(height - screenY); output->Append(ns->GetText(n)); output->Append(')'); output->Append(NEWLINE); } } x = x + step; } delete n; delete ns; return output->GetString(); } // ----------------------------------------------------- // ------------------ DrawStatement -------------------- // ----------------------------------------------------- DrawStatement::DrawStatement(const char* name, const char* parameter) { AllocAndCopy(&this->name, name); AllocAndCopy(&this->parameter, parameter); } DrawStatement::~DrawStatement() { delete [] name; delete [] parameter; } char* DrawStatement::Execute() { UserFunction *function = Program->Functions->GetFunctionDef(name, parameter); if (function == NOMEM) { return (char*)("Function does not exists." NEWLINE); } GraphWindow *graph = Program->Graphs->CreateNewWindow(); if (graph == NOMEM) { return (char*)"Graphs are not supported in this version."; } graph->OpenGraphWindow(function); graph->DrawGraph(function); return (char*)EMPTYSTRING; }