00001 #include <sstream>
00002
00003 #include "parse.hpp"
00004
00005 parser::parser(std::istream& input)
00006 : input_(input),
00007 ctype_(std::use_facet<std::ctype<char> >(input.getloc()))
00008 {}
00009
00010 std::string parser::charify(char c)
00011 {
00012 if (c == '\a') return "\'\\a\'";
00013 if (c == '\b') return "\'\\b\'";
00014 if (c == '\f') return "\'\\f\'";
00015 if (c == '\n') return "\'\\n\'";
00016 if (c == '\r') return "\'\\r\'";
00017 if (c == '\t') return "\'\\t\'";
00018 if (c == '\v') return "\'\\v\'";
00019 if (c == '\'') return "\'\\'\'";
00020 if (c == '\\') return "\'\\\\\'";
00021
00022 if (ctype_.is(ctype_.print, c))
00023 return std::string("\'") + c + '\'';
00024 else {
00025 std::ostringstream stream;
00026 stream << "'\\x" << std::hex;
00027 stream.fill('0');
00028 stream.width(2);
00029 stream << (std::char_traits<char>::to_int_type(c) & 0xFF) << '\'';
00030 return stream.str();
00031 }
00032 }
00033
00034
00035
00036
00037 bool parser::get_number(double& result)
00038 {
00039 std::string token;
00040 char c;
00041 if (not input_.get(c))
00042 return false;
00043 if (c == '+' or c == '-') {
00044 token += c;
00045 if (not input_.get(c))
00046 throw parse_error("unterminated number: expected a digit after the sign");
00047 }
00048 if (c < '0' or c > '9') {
00049 input_.unget();
00050 throw parse_error("syntax error: expected digit, got " + charify(c));
00051 }
00052 while (c >= '0' and c <= '9') {
00053 token += c;
00054 if (not input_.get(c)) {
00055 std::istringstream tmp(token);
00056
00057 return (tmp >> result);
00058 }
00059 }
00060 if (c == '.') {
00061 token += c;
00062 if (not input_.get(c))
00063 throw parse_error("unterminated number: expected digit after the decimal point");
00064 if (c < '0' or c > '9') {
00065 input_.unget();
00066 throw parse_error("syntax error: expected digit after decimal point, got " + charify(c));
00067 }
00068 while (c >= '0' and c <= '9') {
00069 token += c;
00070 if (not input_.get(c)) {
00071 std::istringstream tmp(token);
00072
00073 return (tmp >> result);
00074 }
00075 }
00076 }
00077 if (c == 'e' or c == 'E') {
00078 token += c;
00079 if (not input_.get(c))
00080 throw parse_error("unterminated number: expected digit in the exponent");
00081 if (c == '-' or c == '+') {
00082 token += c;
00083 if (not input_.get(c))
00084 throw parse_error("unterminated number: expected digit after sign in the exponent");
00085 }
00086 if (c < '0' or c > '9') {
00087 input_.unget();
00088 throw parse_error("syntax error: expected digit in the exponent, got " + charify(c));
00089 }
00090 while (c >= '0' and c <= '9') {
00091 token += c;
00092 if (not input_.get(c)) {
00093 std::istringstream tmp(token);
00094
00095 return (tmp >> result);
00096 }
00097 }
00098 }
00099 input_.unget();
00100
00101 std::istringstream tmp(token);
00102
00103 return (tmp >> result);
00104 }
00105
00106
00107
00108
00109 bool parser::get_expr(double& result)
00110 {
00111 if (not get_mult_expr(result))
00112 return false;
00113 char c;
00114 while (input_ >> c) {
00115 if (c != '+' and c != '-') {
00116 input_.unget();
00117 return true;
00118 } else {
00119 double right;
00120 if (not get_mult_expr(right))
00121 throw parse_error("syntax error: unterminated expression. Expected a multiplicative-exprssion after " + c);
00122 if (c == '+')
00123 result += right;
00124 else
00125 result -= right;
00126 }
00127 }
00128 return true;
00129 }
00130
00131
00132
00133
00134 bool parser::get_mult_expr(double& result)
00135 {
00136 if (not get_primary(result))
00137 return false;
00138 char c;
00139 while (input_ >> c) {
00140 if (c != '*' and c != '/') {
00141 input_.unget();
00142 return true;
00143 } else {
00144 double right;
00145 if (not get_primary(right))
00146 throw parse_error("syntax error: unterminated expression. Expected a primary after " + c);
00147 if (c == '*')
00148 result *= right;
00149 else if (right == 0.0)
00150 throw parse_error("division by zero");
00151 else
00152 result /= right;
00153 }
00154 }
00155 return true;
00156 }
00157
00158
00159
00160
00161 bool parser::get_primary(double& result)
00162 {
00163 char c;
00164 if (not (input_ >> c))
00165
00166 return false;
00167 else if (c == '(') {
00168 if (not get_expr(result))
00169 return false;
00170 if (not (input_ >> c))
00171 throw parse_error("syntax error: EOF when expecting ')'");
00172 else if (c != ')')
00173 throw parse_error("syntax error: expected ')', but got " + charify(c));
00174 else
00175 return true;
00176 } else {
00177 input_.unget();
00178 return get_number(result);
00179 }
00180 }
00181
00182 void parse_loop(std::istream& input, std::ostream& output)
00183 {
00184 std::string line;
00185
00186
00187
00188 for (output << "> "; std::getline(input, line); output << "> ") {
00189 std::istringstream input(line);
00190 parser p(input);
00191 try {
00192 double x;
00193 while (p.get_expr(x))
00194 output << x << '\n';
00195 } catch(parse_error const& ex) {
00196 output << ex.what() << '\n';
00197 } catch(std::exception const& ex) {
00198 output << "exception: " << ex.what() << '\n';
00199 }
00200 }
00201 }