#include "parser.h"
#include "lexeme.h"
+#include "lexeme_data.h"
#include "lexer.h"
#include "lexeme_id.h"
-#include "tree.h"
-#include "literal.h"
#include "datum_id.h"
+#include "reader.h"
+#include "object.h"
+#include "gc.h"
+#include "primitive.h"
+#include "primitive_class.h"
+#include "primitive_util.h"
+#include "data_castor.h"
using namespace utakata;
-using namespace utakata::interpreter;
using namespace utakata::parser;
using namespace utakata::lexeme;
+using namespace utakata::interpreter;
-parser::DatumException::DatumException (std::string str) : str_()
+parser::DatumException::DatumException(std::string str) : str_()
{
// エラーメッセージを定義する。
std::stringstream ss;
ss << "datum error ! -- message : [" << str << "]" << std::endl;
- str_ = ss.str ();
+ str_ = ss.str();
}
-const char* parser::DatumException::what () const throw ()
+const char* parser::DatumException::what() const throw()
{
- return str_.c_str ();
+ return str_.c_str();
}
////////////////////////////
// Parser Implementations //
-////////////////////////////
+///////////////////////////
-parser::Parser::Parser (smart_ptr<lexer::Lexer> l) : lexer_(l),
- handler_()
+parser::Parser::Parser(smart_ptr<lexer::Lexer> l) : lexer_(l),
+ handler_()
{
// 初期状態用ハンドラの設定
std::pair<PARSERSTATUS, smart_ptr<IParserHandler> > p;
handler_.insert(p);
// リスト内部用ハンドラの設定
- p.first = PS_LIST_CAR;
+ p.first = PS_LIST;
p.second.add(new ListHandler);
handler_.insert(p);
// .内用ハンドラの設定
- p.first = PS_AFTER_DOT;
- p.second.add(new DotHandler);
+ p.first = PS_END_DOT;
+ p.second.add(new DotEndHandler);
handler_.insert(p);
- // abbreviation用ハンドラの設定
+ // abbreviation 用ハンドラの設定
p.first = PS_ABBREVIATION;
p.second.add(new AbbrevHandler);
handler_.insert(p);
+
+ // error 用のハンドラの設定
+ p.first = PS_ERROR;
+ p.second.add(new ErrorHandler);
+ handler_.insert(p);
}
-smart_ptr<syntax::Tree> parser::Parser::parse (smart_ptr<utf8::UTF8InputStream>& strm)
+smart_ptr<data::Object> parser::Parser::parse(smart_ptr<reader::StreamReader>& strm,
+ gc::GarbageCollector& gc)
{
- std::stack<PARSERSTATUS> statusstack; statusstack.push(PS_INIT);
- smart_ptr<lexeme::ILexeme> lexm;
- smart_ptr<syntax::Tree> root(new syntax::Tree());
- syntax::Tree::iterator it = root->begin();
- std::stack<syntax::Tree::iterator> stack;
- stack.push(it);
-
- while (! (lexm = lexer_->lex (strm)).isNull ()) {
- if (lexm->getID() == lexeme::LexemeID::eos)
- {
- break;
- }
+ HandlerData data(gc);
+ data.status.push(PS_INIT);
- // 基本的にすべてハンドラに任せる。
- handler_[statusstack.top()]->exec(root, lexm, stack, statusstack);
- }
+ while(!data.status.empty()) {
- // 終端に逹した時点で、stackにデータが殘っていたら例外。
-
- if (!stack.empty())
- {
- throw DatumException ("()の整合性が取れていません");
+ if(data.status.top() != PS_ERROR)
+ {
+ if (data.chain)
+ {
+ data.chain = false;
+ }
+ else
+ {
+ data.lexm = lexer_->lex(strm);
+ }
+
+ if(data.lexm.isNull() ||
+ data.lexm->getID() == lexeme::LexemeID::eos)
+ {
+ break;
+ }
+ // 基本的にすべてハンドラに任せる。
+ handler_[data.status.top()]->exec(data);
+ }
+ else
+ {
+ // ERROR だったら、強制的にハンドラを回してループから抜ける。
+ handler_[data.status.top()]->exec(data);
+ }
}
- return root;
+ // stackのtopにはmainが殘ったままなので、data.stackのtopを追加してやる。
+ smart_ptr<data::Object> ret(new data::Object(data.stack.top()));
+ return ret;
}
-bool parser::isAbbrev (smart_ptr<lexeme::ILexeme> l)
+bool parser::isAbbrev(smart_ptr<lexeme::ILexeme> l)
{
// abbreviation かどうかを判別する。
- switch (l->getID ().toEnum ())
+ switch(l->getID().toEnum())
{
case lexeme::LexemeID::BACKQUOTE: return true;
case lexeme::LexemeID::QUOTE: return true;
}
}
+interpreter::IObject* parser::makePrimitiveFromLexeme(smart_ptr<lexeme::ILexeme> l)
+{
+ // 各lexemeに対応した固定lexemeを返す。
+ interpreter::IObject* o = NULL;
+ switch (l->getID().toEnum())
+ {
+ case lexeme::LexemeID::STRING:
+ return util::makeString(l->getData()->string->str);
+ case lexeme::LexemeID::CHARACTOR:
+ return util::makeCharactor(l->getData()->charactor->spec);
+ case lexeme::LexemeID::IDENTIFIER:
+ return util::makeSymbol(l->getData()->symbol->id);
+ case lexeme::LexemeID::BOOLEAN:
+ return util::makeBoolean(l->getData()->boolean->boolean);
+ case lexeme::LexemeID::NUMBER:
+ {
+ lexeme::NumberData& t = *(l->getData()->number);
+ return util::makeNumber(t.real, t.imagin, t.exact,
+ t.radix);
+ }
+ case lexeme::LexemeID::BACKQUOTE:
+ return util::Abbrev<primitive::Quasiquote>::make();
+ case lexeme::LexemeID::QUOTE:
+ return util::Abbrev<primitive::Quote>::make();
+ case lexeme::LexemeID::UNQUOTE:
+ return util::Abbrev<primitive::Unquote>::make();
+ case lexeme::LexemeID::UNQUOTESPLICING:
+ return util::Abbrev<primitive::UnquoteSplicing>::make();
+ case lexeme::LexemeID::SYNTAX:
+ return util::Abbrev<primitive::Syntax>::make();
+ case lexeme::LexemeID::QUASISYNTAX:
+ return util::Abbrev<primitive::Quasisyntax>::make();
+ case lexeme::LexemeID::UNSYNTAX:
+ return util::Abbrev<primitive::Unsyntax>::make();
+ case lexeme::LexemeID::UNSYNTAXSPLICING:
+ return util::Abbrev<primitive::UnsyntaxSplicing>::make();
+ default:
+ break;
+ }
+
+ return o;
+}
+
+/////////////////////
+// parser handlers //
+/////////////////////
-bool InitHandler::exec_(smart_ptr<syntax::Tree>& main,
- const smart_ptr<lexeme::ILexeme>& lexm,
- treestack& stack,
- std::stack<PARSERSTATUS>& status)
+bool InitHandler::exec_(HandlerData& data)
{
+ data.status.pop();
// 初期状態の解釈処理を行う。
- if (lexm->getID () == lexeme::LexemeID::openParenthesis)
+ if(data.lexm->getID() == lexeme::LexemeID::openParenthesis)
{
- // 開き括弧である場合、もはやmainをツリーに登録する必要も無く、
- // iteratorをstackするだけでよい。stackしたiteratorは、原則として
- // )が来ないと取り外せない。
- stack.push(syntax::Tree::iterator());
+ // 開き括弧である場合、compoundsに新しくpushして返る。
+ data.compounds.push(std::vector<data::Object>());
+ data.status.push(PS_LIST);
}
- else if (lexm->getID () == lexeme::LexemeID::string ||
- lexm->getID () == lexeme::LexemeID::number ||
- lexm->getID () == lexeme::LexemeID::identifier ||
- lexm->getID () == lexeme::LexemeID::charactor ||
- lexm->getID () == lexeme::LexemeID::boolean)
+ else if(data.lexm->getID() == lexeme::LexemeID::string ||
+ data.lexm->getID() == lexeme::LexemeID::number ||
+ data.lexm->getID() == lexeme::LexemeID::identifier ||
+ data.lexm->getID() == lexeme::LexemeID::charactor ||
+ data.lexm->getID() == lexeme::LexemeID::boolean)
{
- // それぞれの場合、 lexeme_datum として扱われる。
- // stack.topのiteratorにconsする。
- main->cons(stack.top(), syntax::makeLexemeDatum(
- literal::generateLiteral(lexm)));
- // statusをpopする。
- status.pop();
+ // それぞれの場合、単純にstackに各オブジェクトをpushする。
+
+ data::Object o = data::Object(false,
+ data.gc.add(makePrimitiveFromLexeme(data.lexm)));
+ if (data.compounds.empty())
+ {
+ data.stack.push(o);
+ }
+ else
+ {
+ data.compounds.top().push_back(o);
+ }
}
- else if (isAbbrev(lexm))
+ else if(isAbbrev(data.lexm))
{
- // abbreviaitionである場合でも、これはまったくの同様
- // である。ただし、abbreviationは正確にはconpound datumを構成
- // するため、新規イテレータを導入する必要がある。
- syntax::Tree::iterator it2;
- main->cons(it2, syntax::makeAbbreviation(
- literal::generateLiteral(lexm)));
- stack.push(it2);
-
- // status stackに、PS_ABBREVIATIONとPS_INITを積む。
- status.push(PS_ABBREVIATION);
- status.push(PS_INIT);
+ // abbreviation である場合には、 全体をリストに展開するため、carまでは
+ // 設定された状態にする。
+ std::vector<data::Object> v;
+ v.push_back(data::Object(false,
+ data.gc.add(makePrimitiveFromLexeme(data.lexm))));
+
+ data.compounds.push(v);
+
+ // status stack に、 PS_ABBREVIATIONとPS_INITを積む。
+ data.status.push(PS_ABBREVIATION);
+ data.status.push(PS_INIT);
}
else
{
- throw DatumException ("datum の開始記号ではありません");
+ throw DatumException("datum の開始記号ではありません");
}
return true;
}
-// List内部処理のハンドリング
+// List 内部処理のハンドリング
-bool ListHandler::exec_(smart_ptr<syntax::Tree>& main,
- const smart_ptr<lexeme::ILexeme>& lexm,
- treestack& stack,
- std::stack<PARSERSTATUS>& status)
+bool ListHandler::exec_(HandlerData& data)
{
- // listの内部である場合。
- if (lexm->getID () == lexeme::LexemeID::openParenthesis)
+ // list の開始部分である場合。
+ if(data.lexm->getID() == lexeme::LexemeID::openParenthesis)
{
- // スタックに積む。
- stack.push(main);
- main.add(new syntax::Tree);
- // 再度積む。
- status.push(PS_LIST_CAR);
+ // 更にcompoundsに追加して積む。
+ data.compounds.push(std::vector<data::Object>());
+ data.status.push(PS_LIST);
}
- else if (lexm->getID () == lexeme::LexemeID::closeParenthesis)
+ else if(data.lexm->getID() == lexeme::LexemeID::closeParenthesis)
{
- // スタックから取り出す。
- smart_ptr<syntax::Tree> tree2 = stack.top(); stack.pop();
- // carが空かどうかでチェックする。
- if (!syntax::hasCar(*tree2))
+ // 原則として、閉括弧が来た時点で終了とするだけでよい。
+ // 現在のtopにあるcompoundsが、データであるとされているため、
+ // とりあえずtopにあるvectorをConsの繋がりに変換する。
+
+ std::vector<data::Object> v = data.compounds.top(); data.compounds.pop();
+ // vectorをConsへと変換するには、次のようにして後ろからやっていく
+ // 方式が一番面倒がない。
+ // 1. cdrをnil、carをvectorの末尾であるデータとしたconsを作成する。
+ // 2. vectorの次のデータをcar、前のconsをcdrとしたconsを作成する。
+ // 3. 先頭まで続ける。
+
+ if (v.size() == 0)
{
- tree2->appendTreeToCar(main);
+ // サイズが0の場合には、nilを設定する。
+ data::Object o = data::Object(false,
+ data.gc.add(util::makeNil()));
+ pushList(data, o);
}
else
{
- tree2->concat(main);
+ // 後ろから前に向かっていく。
+ std::vector<data::Object>::reverse_iterator begin = v.rbegin(),
+ end = v.rend();
+ // ちょっと面倒すぎるなこれ。
+ data::Object o = data::Object(
+ false, data.gc.add(
+ util::makeCons(*begin,
+ data::Object(false, data.gc.add(util::makeNil()))))
+ );
+ ++begin;
+ for (; begin != end; ++begin)
+ {
+ // 順次oに再設定していく。
+ o = data::Object(
+ false, data.gc.add(
+ util::makeCons(*begin, o)));
+ }
+ pushList(data, o);
}
- main = tree2;
- // 現在のPS_LIST_CARをpopする。
- status.pop();
+
+ data.status.pop();
}
- else if (lexm->getID () == lexeme::LexemeID::string ||
- lexm->getID () == lexeme::LexemeID::number ||
- lexm->getID () == lexeme::LexemeID::identifier ||
- lexm->getID () == lexeme::LexemeID::charactor ||
- lexm->getID () == lexeme::LexemeID::boolean)
+ else if (data.lexm->getID() == lexeme::LexemeID::string ||
+ data.lexm->getID() == lexeme::LexemeID::number ||
+ data.lexm->getID() == lexeme::LexemeID::identifier ||
+ data.lexm->getID() == lexeme::LexemeID::charactor ||
+ data.lexm->getID() == lexeme::LexemeID::boolean)
{
- // carが空かどうかをチェックして、設定を行う必要がある。
- if (!syntax::hasCar(*main))
+ // データスタックの頂上にあるvectorに追加する。
+ data.compounds.top().push_back(
+ data::Object(
+ false, data.gc.add(makePrimitiveFromLexeme(data.lexm))));
+ }
+ else if(isAbbrev(data.lexm))
+ {
+ // abbreviation は、結論としてはリストに展開される。carは常にabbreviationである
+ // とすることで問題は無いので、作成したconsを、topに置くことで実現する。
+
+ std::vector<data::Object> v;
+ v.push_back(data::Object(false,
+ data.gc.add(makePrimitiveFromLexeme(data.lexm))));
+
+ data.compounds.push(v);
+
+ // status stack に、 PS_ABBREVIATION と PS_INIT を積む。
+ data.status.push(PS_ABBREVIATION);
+ data.status.push(PS_INIT);
+ }
+ else if(data.lexm->getID() == lexeme::LexemeID::dot)
+ {
+ // .が来た場合で、topのvectorがemptyだったらどうしようもなくなるので終了。
+
+ if (data.compounds.top().empty())
{
- syntax::setLiteralToCar(*main, literal::generateLiteral(lexm));
+ data.status.push(PS_ERROR);
+ data.error = "necessary one datum previous dot";
}
else
{
- main->concat(literal::generateLiteral(lexm));
+ // この時点で、終わり方が確定したため、別のハンドラに任せる。
+ // ただし、compoundの方は特に変化は必要が無いので、そちらはそのまま。
+ data.status.pop();
+ data.status.push(PS_END_DOT);
+ data.status.push(PS_INIT);
}
}
- else if (isAbbrev(lexm))
+ else
+ {
+ // 上記以外は許容しない。
+ data.status.push(PS_ERROR);
+ }
+
+ return true;
+}
+
+void ListHandler::pushList(HandlerData& data, data::Object& o)
+{
+ if (!data.compounds.empty())
+ {
+ data.compounds.top().push_back(o);
+ }
+ else
{
- // abbreviation を判別して status を返す。
- // この場合、新規にツリーを作成して、再度設定を行う。
- stack.push(main);
- main.add(new syntax::Tree);
- syntax::setLiteralToCar(*main, literal::generateLiteral(lexm),
- getAbbrevID(lexm));
- // status stackに、PS_PABBREVIATIONとPS_INITを積む。
- status.push(PS_ABBREVIATION);
- status.push(PS_INIT);
+ data.stack.push(o);
}
- else if (lexm->getID() == lexeme::LexemeID::dot)
+}
+
+bool DotEndHandler::exec_(HandlerData& data)
+{
+ // .後の) を待つ部分のハンドラ。
+ // このハンドラでは、) 以外が来た場合にはすべて構文エラーとなる。
+ data.status.pop();
+ if(data.lexm->getID() == lexeme::LexemeID::closeParenthesis)
{
- // .が来た場合、かつcarが設定されていない場合には、エラーとなる。
- if (!syntax::hasCar(*main))
+ // stackの頂点とcompoundsのトップを取得する。
+<<<<<<< HEAD
+=======
+ data::Object t = data.stack.top(); data.stack.pop();
+>>>>>>> 6403bdd4479dc5a3e6ca42aa2dc9b0dc4d6bf71d
+ std::vector<data::Object> v = data.compounds.top(); data.compounds.pop();
+ // vectorをConsへと変換するには、次のようにして後ろからやっていく
+ // 方式が一番面倒がない。
+ // 1. cdrをstackのtop、carをvectorの末尾であるデータとしたconsを作成する。
+ // 2. vectorの次のデータをcar、前のconsをcdrとしたconsを作成する。
+ // 3. 先頭まで続ける。
+
+<<<<<<< HEAD
+=======
+ //
+>>>>>>> 6403bdd4479dc5a3e6ca42aa2dc9b0dc4d6bf71d
{
- throw DatumException ("リストの先頭に . が設定されることは出来ません");
+ // 後ろから前に向かっていく。
+ std::vector<data::Object>::reverse_iterator begin = v.rbegin(),
+ end = v.rend();
+ // ちょっと面倒すぎるなこれ。
+<<<<<<< HEAD
+ // cdrにcompoundsの末尾を、carにその前を設定する。
+ data::Object o = data::Object(
+ false, data.gc.add(
+ util::makeCons(begin[1], begin[0]))
+ );
+ begin += 2;
+=======
+ data::Object o = data::Object(
+ false, data.gc.add(
+ util::makeCons(*begin, o))
+ );
+ ++begin;
+>>>>>>> 6403bdd4479dc5a3e6ca42aa2dc9b0dc4d6bf71d
+ for (; begin != end; ++begin)
+ {
+ // 順次oに再設定していく。
+ o = data::Object(
+ false, data.gc.add(
+ util::makeCons(*begin, o)));
+ }
+
+ if (!data.compounds.empty())
+ {
+ data.compounds.top().push_back(o);
+ }
+ else
+ {
+ data.stack.push(o);
+ }
}
- status.push(PS_AFTER_DOT);
+
+ // ここまでは、すべてDataSpace内部のDataEntityを対象に処理しているため、
+ // Objectで正しく受け渡しができていれば問題は発生しない。
+ }
+ else
+ {
+ // 上記以外は許容しない。
+ data.status.push(PS_ERROR);
}
return true;
}
-// dot処理内部のハンドリング
+// Abbreviation 処理のハンドリング。
-bool DotHandler::exec_(smart_ptr<syntax::Tree>& main,
- const smart_ptr<lexeme::ILexeme>& lexm,
- treestack& stack,
- std::stack<PARSERSTATUS>& status)
+bool AbbrevHandler::exec_(HandlerData& data)
{
- // .の後である場合。
- if (lexm->getID () == lexeme::LexemeID::openParenthesis)
- {
- // 開き括弧である場合
- stack.push(main);
- main.add(new syntax::Tree);
- status.push(PS_LIST_CAR);
- }
- else if (lexm->getID () == lexeme::LexemeID::string ||
- lexm->getID () == lexeme::LexemeID::number ||
- lexm->getID () == lexeme::LexemeID::identifier ||
- lexm->getID () == lexeme::LexemeID::charactor ||
- lexm->getID () == lexeme::LexemeID::boolean)
+ // abbreviationの場合、すでにPS_INITを事前に積んであるため、
+ // 一つ分のdatumが来ていることが確定している。
+ // すでにabbreviation分のObjectはcompoundのtopに積んであるため、
+ // consを作成して、compoundかstackのtopに積むだけ。
+
+ std::vector<data::Object> v = data.compounds.top(); data.compounds.pop();
+
+ if (v.size() != 2)
{
- // リテラルの場合、単純に戻るのみとなる。
- main->appendCdr(syntax::DatumID::literal);
- main->cdr()->setLiteral(literal::generateLiteral(lexm));
- status.pop();
+ data.status.push(PS_ERROR);
}
- else if (lexm->getID() == lexeme::LexemeID::closeParenthesis)
+ else
{
- smart_ptr<syntax::Tree> tree2 = stack.top(); stack.pop();
- // carが空かどうかでチェックする。
- if (!syntax::hasCar(*tree2))
+ // まだcompoundsが存在している場合には、これを返すようにする。
+ data::Object c = data::Object(
+ false, data.gc.add(util::makeCons(
+ v[1],
+ data::Object(false, data.gc.add(util::makeNil()))
+ )));
+ data::Object o =
+ data::Object(false,
+ data.gc.add(util::makeCons(v[0], c)));
+ if (!data.compounds.empty())
{
- tree2->appendTreeToCar(main);
+ data.compounds.top().push_back(o);
}
else
{
- tree2->concat(main);
+ data.stack.push(o);
}
- main = main->cdr();
- // 基本的にステータスはpopするのみ。
- status.pop();
}
+
+ data.status.pop();
+ data.chain = true;
+
return true;
}
-// ABBREVIATION処理のハンドリング。
+// syntax error のハンドリング
-bool AbbrevHandler::exec_(smart_ptr<syntax::Tree>& main,
- const smart_ptr<lexeme::ILexeme>& lexm,
- treestack& stack,
- std::stack<PARSERSTATUS>& status)
+bool ErrorHandler::exec_(HandlerData& data)
{
- // この場合には、stackのtopに現在のツリーをconcatし、その後
- // 更にpopして追加を行う。
- // carが空かどうかをチェックして、設定を行う必要がある。
- smart_ptr<syntax::Tree> t2 = stack.top(); stack.pop();
- t2->concat(main);
-
- // この時点で、abbrev開始前のnodeに戻ることができる。
- main = t2;
- status.pop();
+ // 基本的にはエラーのハンドリングを行うだけ。
+ // 一応発生した前後の位置と発生した lexeme くらいは表示したいかな。
+ std::stringstream ss;
+ ss << "syntax error:" << data.error;
+ throw DatumException(ss.str());
return true;
}