Mercurial > hg > Members > nobuyasu > SampleSource
view Bison-Flex/CALC/discrete-parser/EUC/parser.cpp @ 0:db40c85cad7a default tip
upload sample source
author | nobuyasu <dimolto@cr.ie.u-ryukyu.ac.jp> |
---|---|
date | Mon, 09 May 2011 03:11:59 +0900 |
parents | |
children |
line wrap: on
line source
// // 四則演算パーサー // // Chihiro.SAKAMOTO // #include <climits> #include <cstdio> #include "parser.h" cparser::cparser() : token_type(OP_EOF) { } cparser::~cparser() { } // 構文解析 // // statement ::= <value> "=" <expr> // | "print" <expr> // | "list" // bool cparser::parse(calc_driver *driver, const std::string &f) { if ((fp = std::fopen(f.c_str(), "r")) == NULL) return false; int token; std::string str; while ((token = get_token(str)) != OP_EOF) { if (token == OP_LIST) { // listコマンド driver->list(); } else if (token == OP_PRINT) { // printコマンド cnode *node = add_sub_expr(); driver->print(node); delete node; } else if (token == OP_VALUE) { // 代入 std::string equ; if (get_token(equ) != OP_EQU) return false; cnode *node = add_sub_expr(); driver->assign(str, node); delete node; } else if (token != OP_NEWLINE) { // 空行以外はエラー return false; } token = get_token(str); if (token != OP_NEWLINE) // 行末の\nを読み捨てる unget_token(token, str); } std::fclose(fp); return true; } // +−の処理 // expr ::= <muldiv> (("+" | "-") <muldiv>)* cnode *cparser::add_sub_expr() { cnode *left = mul_div_expr(); if (left == NULL) return NULL; for (;;) { std::string str; int token = get_token(str); if (token != OP_PLUS && token != OP_MINUS) { unget_token(token, str); break; } cnode *right = mul_div_expr(); if (right == NULL) { delete left; return NULL; } left = new cnode(token, left, right); } return left; } // */の処理 // muldiv ::= <term> (("*" | "/") <term>)* cnode *cparser::mul_div_expr() { cnode *left = term(); if (left == NULL) return NULL; for (;;) { std::string str; int token = get_token(str); if (token != OP_TIMES && token != OP_DIVIDE) { unget_token(token, str); break; } cnode *right = term(); if (right == NULL) { delete left; return NULL; } left = new cnode(token, left, right); } return left; } // 終端 // term ::= "-" <term> | "(" <expr> ")" | <number> | <value> cnode *cparser::term() { std::string str; int token = get_token(str); if (token == OP_MINUS) { return new cnode(OP_NEG, term()); } if (token == OP_OPAR) { cnode *node = add_sub_expr(); if (node == NULL) return NULL; token = get_token(str); if (token != OP_CPAR) { delete node; unget_token(token, str); return NULL; } return node; } if (token == OP_CONST) { return new cnode(OP_CONST, atoi(str.c_str())); } if (token == OP_VALUE) { return new cnode(OP_VALUE, new std::string(str)); } return NULL; } // ロケール無視の文字判定 inline bool _isspace(int c) { return c == ' ' || c == '\t'; } inline bool _isnum(int c) { return c >= '0' && c <= '9'; } inline bool _isalpha(int c) { return c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c == '_'; } // 字句解析 // // トークン トークン種別 // // '+' OP_PLUS // '-' OP_MINUS // '*' OP_TIMES // '/' OP_DIVIDE // '(' OP_OPAR // ')' OP_CPAR // '=' OP_EQU // '\n' OP_NEWLINE // EOF OP_EOF // // "print" OP_PRINT // "list" OP_LIST // [0-9]+ OP_CONST // [a-zA-Z_][a-zA-Z0-9_]* OP_VALUE // int cparser::_get_token(std::string &str) { int c; // 先行する空白類を読み飛ばす。 do { c = std::fgetc(fp); } while (_isspace(c)) ; // strは再利用されているかもしれないので、クリアしておく str.clear(); // 記号の場合は、1文字で1トークンなので、種別を返す。 switch (c) { case '+': return OP_PLUS; case '-': return OP_MINUS; case '*': return OP_TIMES; case '/': return OP_DIVIDE; case '(': return OP_OPAR; case ')': return OP_CPAR; case '=': return OP_EQU; case '\n': return OP_NEWLINE; case EOF: return OP_EOF; } // 1文字目が数字の場合は、数字文字列としてトークンを切り出す。 if (_isnum(c)) { while (_isnum(c)) { str += c; c = std::fgetc(fp); } std::ungetc(c, fp); return OP_CONST; } // 1文字目が英字の場合は、「識別子」としてトークンを切り出す。 if (_isalpha(c)) { while (_isalpha(c) || _isnum(c)) { str += c; c = fgetc(fp); } std::ungetc(c, fp); // 切り出したトークンが「予約語」の場合は、対応したトークン種別を返す。 if (str == "print") return OP_PRINT; if (str == "list") return OP_LIST; return OP_VALUE; } // その他の文字はエラーとする。 return OP_ERROR; }