6 #include "lexeme_data.h"
13 #include "primitive.h"
14 #include "primitive_class.h"
15 #include "primitive_util.h"
16 #include "data_castor.h"
18 using namespace utakata;
19 using namespace utakata::parser;
20 using namespace utakata::lexeme;
21 using namespace utakata::interpreter;
23 parser::DatumException::DatumException(std::string str) : str_()
27 ss << "datum error ! -- message : [" << str << "]" << std::endl;
31 const char* parser::DatumException::what() const throw()
36 ////////////////////////////
37 // Parser Implementations //
38 ///////////////////////////
40 parser::Parser::Parser(smart_ptr<lexer::Lexer> l) : lexer_(l),
44 std::pair<PARSERSTATUS, smart_ptr<IParserHandler> > p;
46 p.second.add(new InitHandler);
51 p.second.add(new ListHandler);
56 p.second.add(new DotEndHandler);
59 // abbreviation 用ハンドラの設定
60 p.first = PS_ABBREVIATION;
61 p.second.add(new AbbrevHandler);
66 p.second.add(new ErrorHandler);
70 smart_ptr<data::Object> parser::Parser::parse(smart_ptr<reader::StreamReader>& strm,
71 gc::GarbageCollector& gc)
74 data.status.push(PS_INIT);
76 while(!data.status.empty()) {
78 if(data.status.top() != PS_ERROR)
86 data.lexm = lexer_->lex(strm);
89 if(data.lexm.isNull() ||
90 data.lexm->getID() == lexeme::LexemeID::eos)
95 handler_[data.status.top()]->exec(data);
99 // ERROR だったら、強制的にハンドラを回してループから抜ける。
100 handler_[data.status.top()]->exec(data);
104 // stackのtopにはmainが殘ったままなので、data.stackのtopを追加してやる。
105 smart_ptr<data::Object> ret(new data::Object(data.stack.top()));
109 bool parser::isAbbrev(smart_ptr<lexeme::ILexeme> l)
111 // abbreviation かどうかを判別する。
112 switch(l->getID().toEnum())
114 case lexeme::LexemeID::BACKQUOTE: return true;
115 case lexeme::LexemeID::QUOTE: return true;
116 case lexeme::LexemeID::UNQUOTE: return true;
117 case lexeme::LexemeID::UNQUOTESPLICING: return true;
118 case lexeme::LexemeID::SYNTAX: return true;
119 case lexeme::LexemeID::QUASISYNTAX: return true;
120 case lexeme::LexemeID::UNSYNTAX: return true;
121 case lexeme::LexemeID::UNSYNTAXSPLICING: return true;
127 interpreter::IObject* parser::makePrimitiveFromLexeme(smart_ptr<lexeme::ILexeme> l)
129 // 各lexemeに対応した固定lexemeを返す。
130 interpreter::IObject* o = NULL;
131 switch (l->getID().toEnum())
133 case lexeme::LexemeID::STRING:
134 return util::makeString(l->getData()->string->str);
135 case lexeme::LexemeID::CHARACTOR:
136 return util::makeCharactor(l->getData()->charactor->spec);
137 case lexeme::LexemeID::IDENTIFIER:
138 return util::makeSymbol(l->getData()->symbol->id);
139 case lexeme::LexemeID::BOOLEAN:
140 return util::makeBoolean(l->getData()->boolean->boolean);
141 case lexeme::LexemeID::NUMBER:
143 lexeme::NumberData& t = *(l->getData()->number);
144 return util::makeNumber(t.real, t.imagin, t.exact,
147 case lexeme::LexemeID::BACKQUOTE:
148 return util::Abbrev<primitive::Quasiquote>::make();
149 case lexeme::LexemeID::QUOTE:
150 return util::Abbrev<primitive::Quote>::make();
151 case lexeme::LexemeID::UNQUOTE:
152 return util::Abbrev<primitive::Unquote>::make();
153 case lexeme::LexemeID::UNQUOTESPLICING:
154 return util::Abbrev<primitive::UnquoteSplicing>::make();
155 case lexeme::LexemeID::SYNTAX:
156 return util::Abbrev<primitive::Syntax>::make();
157 case lexeme::LexemeID::QUASISYNTAX:
158 return util::Abbrev<primitive::Quasisyntax>::make();
159 case lexeme::LexemeID::UNSYNTAX:
160 return util::Abbrev<primitive::Unsyntax>::make();
161 case lexeme::LexemeID::UNSYNTAXSPLICING:
162 return util::Abbrev<primitive::UnsyntaxSplicing>::make();
170 /////////////////////
171 // parser handlers //
172 /////////////////////
174 bool InitHandler::exec_(HandlerData& data)
178 if(data.lexm->getID() == lexeme::LexemeID::openParenthesis)
180 // 開き括弧である場合、compoundsに新しくpushして返る。
181 data.compounds.push(std::vector<data::Object>());
182 data.status.push(PS_LIST);
184 else if(data.lexm->getID() == lexeme::LexemeID::string ||
185 data.lexm->getID() == lexeme::LexemeID::number ||
186 data.lexm->getID() == lexeme::LexemeID::identifier ||
187 data.lexm->getID() == lexeme::LexemeID::charactor ||
188 data.lexm->getID() == lexeme::LexemeID::boolean)
190 // それぞれの場合、単純にstackに各オブジェクトをpushする。
192 data::Object o = data::Object(false,
193 data.gc.add(makePrimitiveFromLexeme(data.lexm)));
194 if (data.compounds.empty())
200 data.compounds.top().push_back(o);
203 else if(isAbbrev(data.lexm))
205 // abbreviation である場合には、 全体をリストに展開するため、carまでは
207 std::vector<data::Object> v;
208 v.push_back(data::Object(false,
209 data.gc.add(makePrimitiveFromLexeme(data.lexm))));
211 data.compounds.push(v);
213 // status stack に、 PS_ABBREVIATIONとPS_INITを積む。
214 data.status.push(PS_ABBREVIATION);
215 data.status.push(PS_INIT);
219 throw DatumException("datum の開始記号ではありません");
227 bool ListHandler::exec_(HandlerData& data)
230 if(data.lexm->getID() == lexeme::LexemeID::openParenthesis)
232 // 更にcompoundsに追加して積む。
233 data.compounds.push(std::vector<data::Object>());
234 data.status.push(PS_LIST);
236 else if(data.lexm->getID() == lexeme::LexemeID::closeParenthesis)
238 // 原則として、閉括弧が来た時点で終了とするだけでよい。
239 // 現在のtopにあるcompoundsが、データであるとされているため、
240 // とりあえずtopにあるvectorをConsの繋がりに変換する。
242 std::vector<data::Object> v = data.compounds.top(); data.compounds.pop();
243 // vectorをConsへと変換するには、次のようにして後ろからやっていく
245 // 1. cdrをnil、carをvectorの末尾であるデータとしたconsを作成する。
246 // 2. vectorの次のデータをcar、前のconsをcdrとしたconsを作成する。
251 // サイズが0の場合には、nilを設定する。
252 data::Object o = data::Object(false,
253 data.gc.add(util::makeNil()));
259 std::vector<data::Object>::reverse_iterator begin = v.rbegin(),
262 data::Object o = data::Object(
264 util::makeCons(*begin,
265 data::Object(false, data.gc.add(util::makeNil()))))
268 for (; begin != end; ++begin)
273 util::makeCons(*begin, o)));
280 else if (data.lexm->getID() == lexeme::LexemeID::string ||
281 data.lexm->getID() == lexeme::LexemeID::number ||
282 data.lexm->getID() == lexeme::LexemeID::identifier ||
283 data.lexm->getID() == lexeme::LexemeID::charactor ||
284 data.lexm->getID() == lexeme::LexemeID::boolean)
286 // データスタックの頂上にあるvectorに追加する。
287 data.compounds.top().push_back(
289 false, data.gc.add(makePrimitiveFromLexeme(data.lexm))));
291 else if(isAbbrev(data.lexm))
293 // abbreviation は、結論としてはリストに展開される。carは常にabbreviationである
294 // とすることで問題は無いので、作成したconsを、topに置くことで実現する。
296 std::vector<data::Object> v;
297 v.push_back(data::Object(false,
298 data.gc.add(makePrimitiveFromLexeme(data.lexm))));
300 data.compounds.push(v);
302 // status stack に、 PS_ABBREVIATION と PS_INIT を積む。
303 data.status.push(PS_ABBREVIATION);
304 data.status.push(PS_INIT);
306 else if(data.lexm->getID() == lexeme::LexemeID::dot)
308 // .が来た場合で、topのvectorがemptyだったらどうしようもなくなるので終了。
310 if (data.compounds.top().empty())
312 data.status.push(PS_ERROR);
313 data.error = "necessary one datum previous dot";
317 // この時点で、終わり方が確定したため、別のハンドラに任せる。
318 // ただし、compoundの方は特に変化は必要が無いので、そちらはそのまま。
320 data.status.push(PS_END_DOT);
321 data.status.push(PS_INIT);
327 data.status.push(PS_ERROR);
333 void ListHandler::pushList(HandlerData& data, data::Object& o)
335 if (!data.compounds.empty())
337 data.compounds.top().push_back(o);
345 bool DotEndHandler::exec_(HandlerData& data)
348 // このハンドラでは、) 以外が来た場合にはすべて構文エラーとなる。
350 if(data.lexm->getID() == lexeme::LexemeID::closeParenthesis)
352 // stackの頂点とcompoundsのトップを取得する。
353 std::vector<data::Object> v = data.compounds.top(); data.compounds.pop();
354 // vectorをConsへと変換するには、次のようにして後ろからやっていく
356 // 1. cdrをstackのtop、carをvectorの末尾であるデータとしたconsを作成する。
357 // 2. vectorの次のデータをcar、前のconsをcdrとしたconsを作成する。
362 std::vector<data::Object>::reverse_iterator begin = v.rbegin(),
365 // cdrにcompoundsの末尾を、carにその前を設定する。
366 data::Object o = data::Object(
368 util::makeCons(begin[1], begin[0]))
371 for (; begin != end; ++begin)
376 util::makeCons(*begin, o)));
379 if (!data.compounds.empty())
381 data.compounds.top().push_back(o);
389 // ここまでは、すべてDataSpace内部のDataEntityを対象に処理しているため、
390 // Objectで正しく受け渡しができていれば問題は発生しない。
395 data.status.push(PS_ERROR);
401 // Abbreviation 処理のハンドリング。
403 bool AbbrevHandler::exec_(HandlerData& data)
405 // abbreviationの場合、すでにPS_INITを事前に積んであるため、
406 // 一つ分のdatumが来ていることが確定している。
407 // すでにabbreviation分のObjectはcompoundのtopに積んであるため、
408 // consを作成して、compoundかstackのtopに積むだけ。
410 std::vector<data::Object> v = data.compounds.top(); data.compounds.pop();
414 data.status.push(PS_ERROR);
418 // まだcompoundsが存在している場合には、これを返すようにする。
419 data::Object c = data::Object(
420 false, data.gc.add(util::makeCons(
422 data::Object(false, data.gc.add(util::makeNil()))
426 data.gc.add(util::makeCons(v[0], c)));
427 if (!data.compounds.empty())
429 data.compounds.top().push_back(o);
443 // syntax error のハンドリング
445 bool ErrorHandler::exec_(HandlerData& data)
447 // 基本的にはエラーのハンドリングを行うだけ。
448 // 一応発生した前後の位置と発生した lexeme くらいは表示したいかな。
449 std::stringstream ss;
450 ss << "syntax error:" << data.error;
451 throw DatumException(ss.str());