00001 #include <cstdlib>
00002 #include <iterator>
00003 #include <sstream>
00004
00005 #include "calc_error.hpp"
00006 #include "node.hpp"
00007 #include "parse.hpp"
00008 #include "variables.hpp"
00009
00010 parser::parser(std::istream& input)
00011 : input_(input),
00012 ctype_(std::use_facet<std::ctype<char> >(input.getloc())),
00013 token_(),
00014 kind_()
00015 {}
00016
00017 std::string parser::charify(char c)
00018 {
00019 if (c == '\a') return "\'\\a\'";
00020 if (c == '\b') return "\'\\b\'";
00021 if (c == '\f') return "\'\\f\'";
00022 if (c == '\n') return "\'\\n\'";
00023 if (c == '\r') return "\'\\r\'";
00024 if (c == '\t') return "\'\\t\'";
00025 if (c == '\v') return "\'\\v\'";
00026 if (c == '\'') return "\'\\'\'";
00027 if (c == '\\') return "\'\\\\\'";
00028
00029 if (isprint(c))
00030 return std::string("\'") + c + '\'';
00031 else {
00032 std::ostringstream stream;
00033 stream << "'\\x" << std::hex;
00034 stream.fill('0');
00035 stream.width(2);
00036 stream << (std::char_traits<char>::to_int_type(c) & 0xFF) << '\'';
00037 return stream.str();
00038 }
00039 }
00040
00041 void parser::get_identifier(std::string& identifier)
00042 {
00043 identifier.clear();
00044 char c;
00045 if (not input_.get(c))
00046 return;
00047 if (not isalpha(c))
00048 throw syntax_error("expected alphabetic, got " + charify(c));
00049 identifier += c;
00050 while (input_.get(c)) {
00051 if (not isalnum(c)) {
00052 input_.unget();
00053 return;
00054 }
00055 identifier += c;
00056 }
00057 return;
00058 }
00059
00060 void parser::push_back(std::string const& token, kind k)
00061 {
00062 kind_ = k;
00063 if (kind_ == eof)
00064 token_ = "end of line";
00065 else
00066 token_ = token;
00067 }
00068
00069 parser::kind parser::get_token(std::string& token)
00070 {
00071 if (not token_.empty())
00072 {
00073 kind result(kind_);
00074 token = token_;
00075
00076 token_.clear();
00077 kind_ = eof;
00078
00079 return result;
00080 }
00081
00082 char c;
00083 if (not (input_ >> c)) {
00084 token = "end of line";
00085 return eof;
00086 }
00087 if (isalpha(c)) {
00088 input_.unget();
00089 get_identifier(token);
00090 return identifier;
00091 }
00092
00093
00094 token.clear();
00095 if (c == '+' or c == '-' or c == '*' or c == '/' or c == '%' or c == '(' or c == ')' or c == '=' or c == ',') {
00096 token += c;
00097 return kind(c);
00098 }
00099
00100 if (c < '0' or c > '9') {
00101 input_.unget();
00102 throw syntax_error("expected digit, got " + charify(c));
00103 }
00104 while (c >= '0' and c <= '9') {
00105 token += c;
00106 if (not input_.get(c))
00107 return number;
00108 }
00109 if (c == '.') {
00110 token += c;
00111 if (not input_.get(c))
00112 throw syntax_error("unterminated number: expected digit after the decimal point");
00113 if (c < '0' or c > '9') {
00114 input_.unget();
00115 throw syntax_error("expected digit after decimal point, got " + charify(c));
00116 }
00117 while (c >= '0' and c <= '9') {
00118 token += c;
00119 if (not input_.get(c))
00120 return number;
00121 }
00122 }
00123 if (c == 'e' or c == 'E') {
00124 token += c;
00125 if (not input_.get(c))
00126 throw syntax_error("unterminated number: expected digit in the exponent");
00127 if (c == '-' or c == '+') {
00128 token += c;
00129 if (not input_.get(c))
00130 throw syntax_error("unterminated number: expected digit after sign in the exponent");
00131 }
00132 if (c < '0' or c > '9') {
00133 input_.unget();
00134 throw syntax_error("expected digit in the exponent, got " + charify(c));
00135 }
00136 while (c >= '0' and c <= '9') {
00137 token += c;
00138 if (not input_.get(c))
00139 return number;
00140 }
00141 }
00142 input_.unget();
00143 return number;
00144 }
00145
00146 bool parser::get_number(std::string const& token, node& result)
00147 {
00148 std::istringstream stream(token);
00149
00150 double value;
00151 if (not (stream >> value))
00152 return false;
00153 result = node(value);
00154 return true;
00155 }
00156
00157 void parser::get_definition(std::string& name, identifier_list& parameters, node& definition)
00158 {
00159
00160 kind k = get_token(name);
00161 if (k != identifier)
00162 throw syntax_error("expected IDENTIFIER, got " + name);
00163
00164 std::string token;
00165 k = get_token(token);
00166 if (k == '(') {
00167 get_namelist(std::back_inserter(parameters));
00168 k = get_token(token);
00169 }
00170
00171 if (k != '=')
00172 throw syntax_error("expected = in definition, got " + token);
00173
00174 if (not get_expr(definition))
00175 throw syntax_error("expected exprssion in assignment");
00176 }
00177
00178 bool parser::get_statement(std::ostream& output)
00179 {
00180 std::string token;
00181 kind k(get_token(token));
00182 if (k == eof)
00183 return false;
00184
00185 if (k == identifier and token == "def") {
00186 node definition;
00187 identifier_list parameters;
00188 get_definition(token, parameters, definition);
00189 set_function(token, node(parameters, definition));
00190 return true;
00191 }
00192
00193 if (k == identifier and token == "quit")
00194 std::exit(0);
00195
00196
00197 push_back(token, k);
00198 node n;
00199 if (not get_expr(n))
00200 return false;
00201 else {
00202
00203 output << n.evaluate() << '\n';
00204 return true;
00205 }
00206 }
00207
00208 bool parser::get_expr(node& result)
00209 {
00210 return get_add_expr(result);
00211 }
00212
00213 bool parser::get_add_expr(node& result)
00214 {
00215 if (not get_mul_expr(result))
00216 return false;
00217 std::string token;
00218 while (kind k = get_token(token)) {
00219 if (k != '+' and k != '-') {
00220 push_back(token, k);
00221 return true;
00222 } else {
00223 node right;
00224 if (not get_mul_expr(right))
00225 throw syntax_error("unterminated expression. Expected a multiplicative-expression after " + token);
00226 result = node(result, k, right);
00227 }
00228 }
00229 return true;
00230 }
00231
00232 bool parser::get_mul_expr(node& result)
00233 {
00234 if (not get_unary(result))
00235 return false;
00236 std::string token;
00237 while (kind k = get_token(token)) {
00238 if (k != '*' and k != '/') {
00239 push_back(token, k);
00240 return true;
00241 } else {
00242 node right;
00243 if (not get_unary(right))
00244 throw syntax_error("unterminated expression. Expected a unary-expression after " + token);
00245 result = node(result, k, right);
00246 }
00247 }
00248 return true;
00249 }
00250
00251 bool parser::get_unary(node& result)
00252 {
00253 std::string token;
00254 kind k = get_token(token);
00255 if (k == eof)
00256 return false;
00257 if (k == '-') {
00258 if (not get_primary(result))
00259 throw syntax_error("expected primary after unary " + token + ", got end of line");
00260 result = node(k, result);
00261 return true;
00262 } else if (k == '+') {
00263 if (not get_primary(result))
00264 throw syntax_error("expected primary after unary +, got end of line");
00265 return true;
00266 } else {
00267 push_back(token, k);
00268 return get_primary(result);
00269 }
00270 }
00271
00272 void parser::get_expr_list(node_list& result)
00273 {
00274 result.clear();
00275 std::string token;
00276 while (kind k = get_token(token)) {
00277 if (k == ')')
00278 return;
00279 push_back(token, k);
00280 node expr;
00281 if (not get_expr(expr))
00282 throw syntax_error("unexpected end of line in function argument");
00283 result.push_back(expr);
00284 k = get_token(token);
00285 if (k == ')')
00286 return;
00287 else if (k != ',')
00288 throw syntax_error("expected comma in argument list, got " + token);
00289 }
00290 throw syntax_error("unexpected end of line in function argument list");
00291 }
00292
00293 bool parser::get_primary(node& result)
00294 {
00295 std::string token;
00296 kind k = get_token(token);
00297 if (k == eof)
00298 return false;
00299
00300 if (k == '(') {
00301
00302 if (not get_expr(result))
00303 throw syntax_error("expected expression, got end of line");
00304 k = get_token(token);
00305 if (k != ')')
00306 throw syntax_error("expected ')', got " + token);
00307 else
00308 return true;
00309 }
00310
00311 if (k == number) {
00312
00313 if (not get_number(token, result))
00314 throw syntax_error("Invalid numeric literal: " + token);
00315 return true;
00316 }
00317
00318 if (k == identifier) {
00319
00320 std::string next;
00321 k = get_token(next);
00322 if (k == '(') {
00323
00324 node_list arguments;
00325 get_expr_list(arguments);
00326 result = node(token, arguments);
00327 } else {
00328 static const node_list no_arguments;
00329
00330 push_back(next, k);
00331 result = node(token);
00332 }
00333 return true;
00334 }
00335 throw syntax_error("expected a primary, got " + token);
00336 }
00337
00338 void parse_loop(std::istream& input, std::ostream& output)
00339 {
00340 std::string line;
00341
00342
00343
00344 for (output << "> "; std::getline(input, line); output << "> ") {
00345 std::istringstream input(line);
00346 parser p(input);
00347 try {
00348 while (p.get_statement(output)) {
00349
00350 }
00351 } catch(calc_error const& ex) {
00352 output << ex.what() << '\n';
00353 } catch(std::exception const& ex) {
00354 output << "exception: " << ex.what() << '\n';
00355 }
00356 }
00357 }