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;
+}