00001 #include <fstream>
00002 #include <istream>
00003 #include <limits>
00004 #include <map>
00005 #include <ostream>
00006
00007 #include "calc_error.hpp"
00008 #include "node.hpp"
00009 #include "variables.hpp"
00010
00011 namespace {
00012 symbol_table variables;
00013 std::vector<symbol_table const*> symbol_tables;
00014
00015 class initializer {
00016 public:
00017 initializer() {
00018 variables["pi"] = node(3.141592653589792);
00019 variables["e"] = node(2.718281828459);
00020 symbol_tables.push_back(&variables);
00021 }
00022 };
00023 initializer init;
00024 }
00025
00026 set_symbol_table::set_symbol_table(symbol_table const& locals)
00027 {
00028 symbol_tables.push_back(&locals);
00029 }
00030
00031 set_symbol_table::~set_symbol_table()
00032 {
00033 symbol_tables.pop_back();
00034 }
00035
00036 bool find_symbol(std::string const& name, node& value)
00037 {
00038 for (std::vector<symbol_table const*>::reverse_iterator iter(symbol_tables.rbegin()); iter != symbol_tables.rend(); ++iter) {
00039 symbol_table const& table( **iter );
00040 symbol_table::const_iterator entry = table.find(name);
00041 if (entry != table.end()) {
00042 value = entry->second;
00043 return true;
00044 }
00045 }
00046 return false;
00047 }
00048
00049 node get_variable(std::string const& name)
00050 {
00051 node result;
00052 if (not find_symbol(name, result))
00053 return node();
00054 else if (result.get_parameters().empty())
00055 return result;
00056 else
00057 throw function_error(name, result.get_parameters().size(), 0);
00058 }
00059
00060 void set_variable(std::string const& name, node value)
00061 {
00062 variables[name] = value;
00063 }
00064
00065 node get_function(std::string const& name)
00066 {
00067 node result;
00068 if (not find_symbol(name, result))
00069 throw no_such_function(name);
00070 else
00071 return result;
00072 }
00073
00074 void set_function(std::string const& name, node value)
00075 {
00076 set_variable(name, value);
00077 }
00078
00079 void save_library(std::string const& filename)
00080 {
00081 std::ofstream stream(filename.c_str());
00082 if (not stream)
00083 throw file_error(filename);
00084
00085 stream.precision(std::numeric_limits<double>::digits10);
00086 stream << ":library:\n";
00087 for (symbol_table::iterator symbol(variables.begin()); symbol != variables.end(); ++symbol) {
00088 stream << symbol->first << ' ';
00089 symbol->second.save(stream);
00090 if (stream.fail())
00091 throw file_error(filename);
00092 }
00093 stream << "*\n";
00094 stream.close();
00095 if (stream.fail())
00096 throw file_error(filename);
00097 }
00098
00099 void load_library(std::string const& filename)
00100 {
00101 std::ifstream stream(filename.c_str());
00102 if (not stream)
00103 throw file_error(filename);
00104 std::string token;
00105 if (not std::getline(stream, token))
00106 throw calc_error(filename + ": is empty");
00107 if (token != ":library:")
00108 throw calc_error(filename + ": is not a calculator library file");
00109 while (stream >> token) {
00110 if (token == "*")
00111 return;
00112 else
00113 set_variable(token, node(stream));
00114 }
00115 }