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 token_(),
00009 kind_()
00010 {}
00011
00012 std::string parser::charify(char c)
00013 {
00014 if (c == '\a') return "\'\\a\'";
00015 if (c == '\b') return "\'\\b\'";
00016 if (c == '\f') return "\'\\f\'";
00017 if (c == '\n') return "\'\\n\'";
00018 if (c == '\r') return "\'\\r\'";
00019 if (c == '\t') return "\'\\t\'";
00020 if (c == '\v') return "\'\\v\'";
00021 if (c == '\'') return "\'\\'\'";
00022 if (c == '\\') return "\'\\\\\'";
00023
00024 if (isprint(c))
00025 return std::string("\'") + c + '\'';
00026 else {
00027 std::ostringstream stream;
00028 stream << "'\\x" << std::hex;
00029 stream.fill('0');
00030 stream.width(2);
00031 stream << (std::char_traits<char>::to_int_type(c) & 0xFF) << '\'';
00032 return stream.str();
00033 }
00034 }
00035
00036 void parser::get_identifier(std::string& identifier)
00037 {
00038 identifier.clear();
00039 char c;
00040 if (not input_.get(c))
00041 return;
00042 if (not isalpha(c))
00043 throw parse_error("syntax error: expected alphabetic, got " + charify(c));
00044 identifier += c;
00045 while (input_.get(c)) {
00046 if (not isalnum(c)) {
00047 input_.unget();
00048 return;
00049 }
00050 identifier += c;
00051 }
00052 return;
00053 }
00054
00055
00056
00057
00058
00059
00060
00061
00062 parser::kind parser::get_token(std::string& token)
00063 {
00064 if (not token_.empty())
00065 {
00066 token = token_;
00067 kind result(kind_);
00068 token_.clear();
00069 kind_ = eof;
00070 return result;
00071 }
00072
00073 char c;
00074 if (not (input_ >> c))
00075 return eof;
00076 if (isalpha(c)) {
00077 input_.unget();
00078 get_identifier(token);
00079 return identifier;
00080 }
00081
00082
00083 token.clear();
00084 if (c == '+' or c == '-' or c == '*' or c == '/' or c == '%' or c == '(' or c == ')' or c == '=') {
00085 token += c;
00086 return kind(c);
00087 }
00088
00089 if (c < '0' or c > '9') {
00090 input_.unget();
00091 throw parse_error("syntax error: expected digit, got " + charify(c));
00092 }
00093 while (c >= '0' and c <= '9') {
00094 token += c;
00095 if (not input_.get(c))
00096 return number;
00097 }
00098 if (c == '.') {
00099 token += c;
00100 if (not input_.get(c))
00101 throw parse_error("unterminated number: expected digit after the decimal point");
00102 if (c < '0' or c > '9') {
00103 input_.unget();
00104 throw parse_error("syntax error: expected digit after decimal point, got " + charify(c));
00105 }
00106 while (c >= '0' and c <= '9') {
00107 token += c;
00108 if (not input_.get(c))
00109 return number;
00110 }
00111 }
00112 if (c == 'e' or c == 'E') {
00113 token += c;
00114 if (not input_.get(c))
00115 throw parse_error("unterminated number: expected digit in the exponent");
00116 if (c == '-' or c == '+') {
00117 token += c;
00118 if (not input_.get(c))
00119 throw parse_error("unterminated number: expected digit after sign in the exponent");
00120 }
00121 if (c < '0' or c > '9') {
00122 input_.unget();
00123 throw parse_error("syntax error: expected digit in the exponent, got " + charify(c));
00124 }
00125 while (c >= '0' and c <= '9') {
00126 token += c;
00127 if (not input_.get(c))
00128 return number;
00129 }
00130 }
00131 input_.unget();
00132 return number;
00133 }
00134
00135 bool parser::get_number(std::string const& token, double& result)
00136 {
00137 std::istringstream stream(token);
00138
00139 return (stream >> result);
00140 }
00141
00142 bool parser::get_expr(double& result)
00143 {
00144 std::string token;
00145 kind k(get_token(token));
00146 if (k == eof)
00147 return false;
00148
00149 if (k == identifier and token == "var") {
00150 std::string name;
00151
00152 k = get_token(name);
00153 if (k != identifier)
00154 throw parse_error("syntax error: expected IDENTIFIER, but got " + name);
00155 k = get_token(token);
00156 if (k != '=')
00157 throw parse_error("syntax error: expected =, but got " + token);
00158 if (not get_add_expr(result))
00159 throw parse_error("syntax error: expected additive-exprssion in assignment");
00160 set_variable(name, result);
00161 return true;
00162 }
00163
00164 if (k == identifier and token == "quit")
00165 std::exit(0);
00166
00167 push_back(token, k);
00168 if (not get_add_expr(result))
00169 throw parse_error("syntax error: expected an additive-expression");
00170
00171 return true;
00172 }
00173
00174 bool parser::get_add_expr(double& result)
00175 {
00176 if (not get_mul_expr(result))
00177 return false;
00178 std::string token;
00179 while (kind k = get_token(token)) {
00180 if (k != '+' and k != '-') {
00181 push_back(token, k);
00182 return true;
00183 } else {
00184 double right;
00185 if (not get_mul_expr(right))
00186 throw parse_error("syntax error: unterminated expression. Expected a multiplicative-expression after " + token);
00187 if (k == '+')
00188 result += right;
00189 else
00190 result -= right;
00191 }
00192 }
00193 return true;
00194 }
00195
00196 bool parser::get_mul_expr(double& result)
00197 {
00198 if (not get_unary(result))
00199 return false;
00200 std::string token;
00201 while (kind k = get_token(token)) {
00202 if (k != '*' and k != '/') {
00203 push_back(token, k);
00204 return true;
00205 } else {
00206 double right;
00207 if (not get_unary(right))
00208 throw parse_error("syntax error: unterminated expression. Expected a unary-expression after " + token);
00209 if (k == '*')
00210 result *= right;
00211 else if (right == 0.0)
00212 throw parse_error("division by zero");
00213 else
00214 result /= right;
00215 }
00216 }
00217 return true;
00218 }
00219
00220 bool parser::get_unary(double& result)
00221 {
00222 std::string token;
00223 if (kind k = get_token(token)) {
00224 if (k == '-') {
00225 if (not get_primary(result))
00226 return false;
00227 result = -result;
00228 return true;
00229 } else if (k == '+') {
00230 return get_primary(result);
00231 } else {
00232 push_back(token, k);
00233 return get_primary(result);
00234 }
00235 }
00236 return false;
00237 }
00238
00239 bool parser::get_primary(double& result)
00240 {
00241 std::string token;
00242 if (kind k = get_token(token)) {
00243 if (k == '(') {
00244 if (not get_expr(result))
00245 return false;
00246 k = get_token(token);
00247 if (k == eof)
00248 throw parse_error("syntax error: EOF when expecting ')'");
00249 else if (k != ')')
00250 throw parse_error("syntax error: expected ')', but got " + token);
00251 else
00252 return true;
00253 } else if (k == number) {
00254 if (not get_number(token, result))
00255 throw parse_error("Invalid numeric literal: " + token);
00256 return true;
00257 } else if (k == identifier) {
00258 result = get_variable(token);
00259 return true;
00260 } else {
00261 throw parse_error("syntax error: expected a primary, but got " + token);
00262 }
00263 }
00264 return false;
00265 }
00266
00267 void parse_loop(std::istream& input, std::ostream& output)
00268 {
00269 std::string line;
00270
00271
00272
00273 for (output << "> "; std::getline(input, line); output << "> ") {
00274 std::istringstream input(line);
00275 parser p(input);
00276 try {
00277 double x;
00278 while (p.get_expr(x))
00279 output << x << '\n';
00280 } catch(parse_error const& ex) {
00281 output << ex.what() << '\n';
00282 } catch(std::exception const& ex) {
00283 output << "exception: " << ex.what() << '\n';
00284 }
00285 }
00286 }