Mercurial > hg > Members > nobuyasu > SampleSource
diff 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 diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Bison-Flex/CALC/discrete-parser/EUC/parser.cpp Mon May 09 03:11:59 2011 +0900 @@ -0,0 +1,239 @@ +// +// 四則演算パーサー +// +// 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; +}