From f971fd3e5c5dbc2ff98592a0836a3e4c67eab0cc Mon Sep 17 00:00:00 2001 From: derui Date: Thu, 10 Sep 2009 23:41:48 +0900 Subject: [PATCH] =?utf8?q?utf8=5Fstring,=20utf8=E3=81=A8=E3=81=AA=E3=81=A3?= =?utf8?q?=E3=81=A6=E3=81=84=E3=81=9F=E3=82=82=E3=81=AE=E3=82=92=E3=80=81s?= =?utf8?q?cheme=E4=B8=AD=E3=81=AEUnicode=E3=81=AE=E5=9F=BA=E7=82=B9?= =?utf8?q?=E3=81=A8=E3=81=AA=E3=82=8BUniChar=E3=81=A8UniString=E3=81=AB?= =?utf8?q?=E6=AD=A3=E8=A6=8F=E5=8C=96=E3=80=82=20utf8=E3=81=AE=E8=AA=AD?= =?utf8?q?=E3=81=BF=E5=87=BA=E3=81=97=E3=81=AF=E3=80=81scheme=E3=81=AEport?= =?utf8?q?=E3=81=AB=E4=BC=BC=E3=81=9B=E3=81=9FBinaryPort=E3=81=A8Transcode?= =?utf8?q?r=E3=81=AE=E7=B5=84=E5=90=88=E3=81=9B=E3=81=A7=E8=AA=AD=E5=87=BA?= =?utf8?q?=E3=81=99=E3=82=88=E3=81=86=E3=81=AB=E5=A4=89=E6=9B=B4=E4=B8=AD?= =?utf8?q?=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + binary_port.cpp | 88 ++++++ binary_port.h | 51 +++ delimiter.cpp | 18 +- delimiter.h | 16 +- lexeme.h | 6 +- lexeme_impl.cpp | 90 +++--- lexeme_impl.h | 54 ++-- lexer.h | 2 +- literal.cpp | 24 +- literal.h | 8 +- literal_data.cpp | 28 +- literal_data.h | 28 +- literal_impl.cpp | 26 +- literal_impl.h | 20 +- number_lexer.h | 62 ++-- port.h | 59 ++++ primitive.cpp | 14 +- primitive.h | 26 +- sublexer_impl.cpp | 82 ++--- sublexer_impl.h | 28 +- test/Makefile.am | 16 +- test/cons_test.cpp | 6 +- test/environment_test.cpp | 8 +- test/sublexer_test.cpp | 4 +- test/{utf8_string_test.cpp => unicode_test.cpp} | 44 +-- test/{utf8_test.cpp => utf8_transcoder_test.cpp} | 0 transcoder.h | 30 ++ tree.cpp | 4 +- tree.h | 6 +- unicode.cpp | 242 +++++++++++++++ unicode.h | 168 ++++++++++ utf8.cpp | 379 ----------------------- utf8.h | 135 -------- utf8_string.cpp | 275 ---------------- utf8_string.h | 210 ------------- utf8_transcoder.cpp | 251 +++++++++++++++ utf8_transcoder.h | 94 ++++++ 38 files changed, 1294 insertions(+), 1309 deletions(-) create mode 100644 binary_port.cpp create mode 100755 binary_port.h mode change 100644 => 100755 delimiter.cpp mode change 100644 => 100755 delimiter.h mode change 100644 => 100755 number_lexer.h create mode 100755 port.h mode change 100644 => 100755 primitive.cpp mode change 100644 => 100755 test/sublexer_test.cpp rename test/{utf8_string_test.cpp => unicode_test.cpp} (68%) mode change 100644 => 100755 rename test/{utf8_test.cpp => utf8_transcoder_test.cpp} (100%) create mode 100755 transcoder.h create mode 100755 unicode.cpp create mode 100755 unicode.h delete mode 100755 utf8.cpp delete mode 100755 utf8.h delete mode 100644 utf8_string.cpp delete mode 100755 utf8_string.h create mode 100755 utf8_transcoder.cpp create mode 100755 utf8_transcoder.h diff --git a/.gitignore b/.gitignore index 7fefbaf..e9b1e15 100644 --- a/.gitignore +++ b/.gitignore @@ -23,3 +23,4 @@ utakata /test/utf8_test /test/syntax_tree_test /test/environment_test +/test/utf8_transcoder_test diff --git a/binary_port.cpp b/binary_port.cpp new file mode 100644 index 0000000..435615b --- /dev/null +++ b/binary_port.cpp @@ -0,0 +1,88 @@ +#include "binary_port.h" + +using namespace utakata; +using namespace utakata::port; + +BinaryInputPort::BinaryInputPort(smart_ptr& s) : stream_(s) +{ +} + +int BinaryInputPort::read() +{ + // 現在利用保持しているstreamから1バイト分だけ読出す。 + // eofの場合、std::istream::traits_type::eofを返す。 + + validate(); + + if (stream_->eof() || !stream_->ready()) + { + return std::istream::traits_type::eof; + } + + return stream_->read(); +} + +std::vector BinaryInputPort::read(size_t num) +{ + // 指定したサイズ分のbyteを読出す。 + // 指定サイズが読み出しきれず、eofになった場合には、eofは返さない。 + validate(); + + if (num <= 0) + { + throw PortException("must be greater than zero of read size"); + } + + if (stream_->eof() || !stream_->ready()) + { + return std::vector(); + } + + std::vector ret(); + for (int i = 0; i < num; ++i) + { + int tmp = stream_->read(); + if (tmp == std::istream::traits_type::eof) + { + break; + } + ret.push_back(tmp); + } + + return ret; +} + +int BinaryInputPort::peek() +{ + // 基本的にはpeekがそのまま利用される。 + validate(); + + if (stream_->eof() || !stream_->ready()) + { + return std::istream::traits_type::eof; + } + + return stream_->peek(); +} + +void BinaryInputPort::unget(int ch) +{ + // 渡したchを元に戻す。成功しない場合には例外が発生する。 + validate(); + stream_->unget(ch); +} + +bool BinaryInputPort::isEOF() +{ + // 現在streamが終端かどうかを返す。 + validate(); + return stream_->eof(); +} + +void BinaryInputPort::validate() +{ + if (stream_.isNull()) + { + throw PortException("stream must valid instantce but NULL!"); + } +} diff --git a/binary_port.h b/binary_port.h new file mode 100755 index 0000000..487aaf4 --- /dev/null +++ b/binary_port.h @@ -0,0 +1,51 @@ +#ifndef _BINARY_PORT_H_ +#define _BINARY_PORT_H_ + +#include +#include + +#include "port.h" +#include "smart_ptr.h" + +namespace utakata { + + namespace port { + + class BinaryInputPort : public IInputPort + { + // 渡されたistreamから1バイトだけ読み取る。 + // 読み出した際、std::istream::traits_type::eofである + // 場合、portが末尾に到達している。 + public: + + // 利用するistreamを指定する。 + BinaryInputPort(smart_ptr& s); + virtual ~BinaryInputPort() {} + + virtual int read(); + virtual std::vector read(size_t num); + + virtual int peek(); + + // 現在streamのどこまでを読んでいるのかを返す。 + virtual size_t pos(); + + // 渡されたvectorをstreamに戻す。 + virtual void unget(int ch); + + // 現在のportが終了時点かどうかを返す。 + virtual bool isEOF(); + + private: + + // 内部のvalidチェックを行う。 + // validチェックは成功しない場合にはPortExceptionが発生する。 + void validate(); + + smart_ptr stream_; + }; + }; + +}; + +#endif /* _BINARY_PORT_H_ */ diff --git a/delimiter.cpp b/delimiter.cpp old mode 100644 new mode 100755 index 2211d48..387927f --- a/delimiter.cpp +++ b/delimiter.cpp @@ -2,7 +2,7 @@ using namespace utakata::lexer_delimiter; -bool Normal::operator()(const utakata::utf8_string::UTF8Char& ch) +bool Normal::operator()(const utakata::unicode::UniChar& ch) { // 渡された文字がデリミタかどうかを返す。 // 渡された文字がデリミタかどうかを判別する。 @@ -35,7 +35,7 @@ bool Normal::operator()(const utakata::utf8_string::UTF8Char& ch) } } -bool Whitespace::operator()(const utakata::utf8_string::UTF8Char& ch) +bool Whitespace::operator()(const utakata::unicode::UniChar& ch) { switch (ch.toUTF16Code()) { @@ -51,7 +51,7 @@ bool Whitespace::operator()(const utakata::utf8_string::UTF8Char& ch) } } -bool LineEnding::operator()(const utakata::utf8_string::UTF8Char& ch, +bool LineEnding::operator()(const utakata::unicode::UniChar& ch, smart_ptr& strm) { // 今の文字と、次の文字とを利用してチェックする。 @@ -61,7 +61,7 @@ bool LineEnding::operator()(const utakata::utf8_string::UTF8Char& ch, case '\r': //次の文字が必要になる。 { - utakata::utf8_string::UTF8Char ch2(strm->peek()); + utakata::unicode::UniChar ch2(strm->peek()); if (ch2.toUTF16Code() == '\n') { strm->read(); @@ -73,7 +73,7 @@ bool LineEnding::operator()(const utakata::utf8_string::UTF8Char& ch, } } -bool HexValue::operator()(const utakata::utf8_string::UTF8Char& ch) +bool HexValue::operator()(const utakata::unicode::UniChar& ch) { if (ch.toUTF16Code() >= 'a' && ch.toUTF16Code() <= 'f') { @@ -85,10 +85,10 @@ bool HexValue::operator()(const utakata::utf8_string::UTF8Char& ch) } // 最後に数値だけの判定を返す。 - return utakata::utf8_string::is_numeric(ch); + return utakata::unicode::is_numeric(ch); } -bool String::operator()(const utakata::utf8_string::UTF8Char& ch) +bool String::operator()(const utakata::unicode::UniChar& ch) { if (ch.toUTF16Code() == '"') { @@ -97,7 +97,7 @@ bool String::operator()(const utakata::utf8_string::UTF8Char& ch) return false; } -bool Prefix::operator()(const utakata::utf8_string::UTF8String& str) +bool Prefix::operator()(const utakata::unicode::UniString& str) { std::string s = str.toStr(); @@ -111,7 +111,7 @@ bool Prefix::operator()(const utakata::utf8_string::UTF8String& str) return false; } -bool Exactness::operator()(const utakata::utf8_string::UTF8String& str) +bool Exactness::operator()(const utakata::unicode::UniString& str) { std::string s = str.toStr(); diff --git a/delimiter.h b/delimiter.h old mode 100644 new mode 100755 index d64a999..c0ef4df --- a/delimiter.h +++ b/delimiter.h @@ -1,7 +1,7 @@ #ifndef _DELIMITER_H_ #define _DELIMITER_H_ -#include "utf8_string.h" +#include "unicode.h" #include "smart_ptr.h" #include "utf8.h" @@ -17,7 +17,7 @@ namespace utakata { { // 通常のデリミタとして処理するべきデリミタ一覧を返す。 public: - bool operator()(const utakata::utf8_string::UTF8Char& ch); + bool operator()(const utakata::unicode::UniChar& ch); }; @@ -25,7 +25,7 @@ namespace utakata { { // 空白として認識される文字であるかどうかを返す。 public: - bool operator()(const utakata::utf8_string::UTF8Char& ch); + bool operator()(const utakata::unicode::UniChar& ch); }; class LineEnding @@ -34,7 +34,7 @@ namespace utakata { // 但し、次の文字も含め改行である場合があるため、 // まとめて調べるため、streamを必要とする。 public: - bool operator()(const utakata::utf8_string::UTF8Char& ch, + bool operator()(const utakata::unicode::UniChar& ch, smart_ptr& strm); }; @@ -42,28 +42,28 @@ namespace utakata { { // 文字列を分割するためのデリミタを定義する。 public: - bool operator()(const utakata::utf8_string::UTF8Char& ch); + bool operator()(const utakata::unicode::UniChar& ch); }; class Prefix { // のプレフィックスを調査する。 public: - bool operator()(const utakata::utf8_string::UTF8String& str); + bool operator()(const utakata::unicode::UniString& str); }; class Exactness { // の正確性を調査する。 public: - bool operator()(const utakata::utf8_string::UTF8String& str); + bool operator()(const utakata::unicode::UniString& str); }; class HexValue { // 16進数で利用可能な文字の範囲であるかどうかを返す。 public: - bool operator()(const utakata::utf8_string::UTF8Char& ch); + bool operator()(const utakata::unicode::UniChar& ch); }; }; diff --git a/lexeme.h b/lexeme.h index eb76911..bec515a 100755 --- a/lexeme.h +++ b/lexeme.h @@ -5,8 +5,8 @@ namespace utakata { - namespace utf8_string { - class UTF8String; + namespace unicode { + class UniString; }; namespace literal { @@ -29,7 +29,7 @@ namespace utakata { virtual const LexemeID getID() const = 0; // stringのデータ型において、文字列を取得する。 - virtual smart_ptr toString() const = 0; + virtual smart_ptr toString() const = 0; // リテラルとして扱うためのデータを取得する。各リテラルのうち、 // lexeme Datumとして扱うことができるデータについてはこれらとなる。 diff --git a/lexeme_impl.cpp b/lexeme_impl.cpp index e93b2df..1d79757 100755 --- a/lexeme_impl.cpp +++ b/lexeme_impl.cpp @@ -7,151 +7,151 @@ #include "literal_data.h" using namespace utakata::lexeme; -using namespace utakata::utf8_string; +using namespace utakata::unicode; using namespace utakata::literal; //////////////////////// -// 各lexeme生成関数 // +// 蜷�exeme逕滓�髢「謨ー // //////////////////////// smart_ptr utakata::lexeme::makeOpenParen() { - smart_ptr tmp(new UTF8String(convert("("))); + smart_ptr tmp(new UniString(convert("("))); return smart_ptr(new PureLexeme(tmp, LexemeID::openParenthesis)); } smart_ptr utakata::lexeme::makeEOS() { - return smart_ptr(new PureLexeme(smart_ptr(), LexemeID::eos)); + return smart_ptr(new PureLexeme(smart_ptr(), LexemeID::eos)); } smart_ptr utakata::lexeme::makeCloseParen() { - smart_ptr tmp(new UTF8String(utf8_string::convert(")"))); + smart_ptr tmp(new UniString(unicode::convert(")"))); return smart_ptr(new PureLexeme(tmp, LexemeID::closeParenthesis)); } smart_ptr utakata::lexeme::makeBackQuote() { - smart_ptr tmp(new UTF8String(utf8_string::convert("`"))); + smart_ptr tmp(new UniString(unicode::convert("`"))); return smart_ptr(new PureLexeme(tmp, LexemeID::backquote)); } smart_ptr utakata::lexeme::makeQuote() { - smart_ptr tmp(new UTF8String(utf8_string::convert("'"))); + smart_ptr tmp(new UniString(unicode::convert("'"))); return smart_ptr(new PureLexeme(tmp, LexemeID::quote)); } smart_ptr utakata::lexeme::makeDot() { - smart_ptr tmp(new UTF8String(utf8_string::convert("."))); + smart_ptr tmp(new UniString(unicode::convert("."))); return smart_ptr(new PureLexeme(tmp, LexemeID::dot)); } -smart_ptr utakata::lexeme::makeIdentifier(const utakata::utf8_string::UTF8String& str) +smart_ptr utakata::lexeme::makeIdentifier(const utakata::unicode::UniString& str) { return smart_ptr(new Identifier(str)); } -smart_ptr utakata::lexeme::makeString(const utakata::utf8_string::UTF8String& str) +smart_ptr utakata::lexeme::makeString(const utakata::unicode::UniString& str) { return smart_ptr(new String(str)); } smart_ptr utakata::lexeme::makeUnquoteSplicing() { - smart_ptr tmp(new UTF8String(utf8_string::convert(",@"))); + smart_ptr tmp(new UniString(unicode::convert(",@"))); return smart_ptr(new PureLexeme(tmp, LexemeID::unquoteSplicing)); } smart_ptr utakata::lexeme::makeUnquote() { - smart_ptr tmp(new UTF8String(utf8_string::convert(","))); + smart_ptr tmp(new UniString(unicode::convert(","))); return smart_ptr(new PureLexeme(tmp, LexemeID::unquote)); } smart_ptr utakata::lexeme::makeByteVector() { - smart_ptr tmp(new UTF8String(utf8_string::convert("#vu("))); + smart_ptr tmp(new UniString(unicode::convert("#vu("))); return smart_ptr(new PureLexeme(tmp, LexemeID::byteVector)); } smart_ptr utakata::lexeme::makeVector() { - smart_ptr tmp(new UTF8String(utf8_string::convert("#("))); + smart_ptr tmp(new UniString(unicode::convert("#("))); return smart_ptr(new PureLexeme(tmp, LexemeID::vector)); } smart_ptr utakata::lexeme::makeSyntax() { - smart_ptr tmp(new UTF8String(utf8_string::convert("#'"))); + smart_ptr tmp(new UniString(unicode::convert("#'"))); return smart_ptr(new PureLexeme(tmp, LexemeID::syntax)); } smart_ptr utakata::lexeme::makeQuasiSyntax() { - smart_ptr tmp(new UTF8String(utf8_string::convert("#`"))); + smart_ptr tmp(new UniString(unicode::convert("#`"))); return smart_ptr(new PureLexeme(tmp, LexemeID::quasiSyntax)); } smart_ptr utakata::lexeme::makeUnsyntaxSplicing() { - smart_ptr tmp(new UTF8String(utf8_string::convert("#,@"))); + smart_ptr tmp(new UniString(unicode::convert("#,@"))); return smart_ptr(new PureLexeme(tmp, LexemeID::unsyntaxSplicing)); } smart_ptr utakata::lexeme::makeUnsyntax() { - smart_ptr tmp(new UTF8String(utf8_string::convert("#,"))); + smart_ptr tmp(new UniString(unicode::convert("#,"))); return smart_ptr(new PureLexeme(tmp, LexemeID::unsyntax)); } -smart_ptr utakata::lexeme::makeCharactor(const utakata::utf8_string::UTF8Char& str) +smart_ptr utakata::lexeme::makeCharactor(const utakata::unicode::UniChar& str) { return smart_ptr(new Charactor(str)); } -smart_ptr utakata::lexeme::makeBoolean(smart_ptr ch) +smart_ptr utakata::lexeme::makeBoolean(smart_ptr ch) { return smart_ptr(new Boolean(ch)); } -smart_ptr utakata::lexeme::makeNanImaginary(const utakata::utf8_string::UTF8String& str, +smart_ptr utakata::lexeme::makeNanImaginary(const utakata::unicode::UniString& str, bool exact) { - return smart_ptr(new Number(utakata::utf8_string::UTF8String(), + return smart_ptr(new Number(utakata::unicode::UniString(), str, exact, 10)); } -smart_ptr utakata::lexeme::makeInfImaginary(const utakata::utf8_string::UTF8String& str, +smart_ptr utakata::lexeme::makeInfImaginary(const utakata::unicode::UniString& str, bool exact) { - return smart_ptr(new Number(utakata::utf8_string::UTF8String(), + return smart_ptr(new Number(utakata::unicode::UniString(), str, exact, 10)); } -smart_ptr utakata::lexeme::makeImaginaryOnly(const utakata::utf8_string::UTF8String& str, +smart_ptr utakata::lexeme::makeImaginaryOnly(const utakata::unicode::UniString& str, bool exact) { - return smart_ptr(new Number(utakata::utf8_string::UTF8String(), + return smart_ptr(new Number(utakata::unicode::UniString(), str, exact, 10)); } -smart_ptr utakata::lexeme::makeNumber(const utakata::utf8_string::UTF8String& real, - const utakata::utf8_string::UTF8String& imagin, +smart_ptr utakata::lexeme::makeNumber(const utakata::unicode::UniString& real, + const utakata::unicode::UniString& imagin, bool exact, int radix) { return smart_ptr(new Number(real, imagin, exact, radix)); @@ -161,7 +161,7 @@ smart_ptr utakata::lexeme::makeNumber(const utakata::utf8_string::UTF8S // PureLexeme // //////////////// -PureLexeme::PureLexeme(smart_ptr str, +PureLexeme::PureLexeme(smart_ptr str, lexeme::LexemeID id) : str_(str), id_(id) {} @@ -170,7 +170,7 @@ const LexemeID PureLexeme::getID() const return id_; } -smart_ptr PureLexeme::toString() const +smart_ptr PureLexeme::toString() const { return str_; } @@ -184,8 +184,8 @@ smart_ptr PureLexeme::getData() const // Identifier // //////////////// -Identifier::Identifier(const utakata::utf8_string::UTF8String& str) : - str_(new utakata::utf8_string::UTF8String(str)) +Identifier::Identifier(const utakata::unicode::UniString& str) : + str_(new utakata::unicode::UniString(str)) { } @@ -194,7 +194,7 @@ const utakata::lexeme::LexemeID Identifier::getID() const return utakata::lexeme::LexemeID::identifier; } -smart_ptr Identifier::toString() const +smart_ptr Identifier::toString() const { return str_; } @@ -208,8 +208,8 @@ smart_ptr Identifier::getData() const // String // ///////////// -String::String(const utakata::utf8_string::UTF8String& str) : - str_(new utakata::utf8_string::UTF8String(str)) +String::String(const utakata::unicode::UniString& str) : + str_(new utakata::unicode::UniString(str)) { } @@ -218,7 +218,7 @@ const utakata::lexeme::LexemeID String::getID() const return utakata::lexeme::LexemeID::string; } -smart_ptr String::toString() const +smart_ptr String::toString() const { return str_; } @@ -232,8 +232,8 @@ smart_ptr String::getData() const // Number // //////////// -Number::Number(const UTF8String& real, - const UTF8String& imagin, +Number::Number(const UniString& real, + const UniString& imagin, bool exact, int radix) : data_(new LiteralData) { @@ -245,9 +245,9 @@ const utakata::lexeme::LexemeID Number::getID() const return utakata::lexeme::LexemeID::number; } -smart_ptr Number::toString() const +smart_ptr Number::toString() const { - return smart_ptr(new UTF8String(*data_->number->real + *data_->number->imagin)); + return smart_ptr(new UniString(*data_->number->real + *data_->number->imagin)); } smart_ptr Number::getData() const @@ -259,7 +259,7 @@ smart_ptr Number::getData() const // Charactor // /////////////// -Charactor::Charactor(const UTF8Char& ch) : ch_(new UTF8Char(ch)) +Charactor::Charactor(const UniChar& ch) : ch_(new UniChar(ch)) { } @@ -268,9 +268,9 @@ const utakata::lexeme::LexemeID Charactor::getID() const return utakata::lexeme::LexemeID::charactor; } -smart_ptr Charactor::toString() const +smart_ptr Charactor::toString() const { - smart_ptr c(new utakata::utf8_string::UTF8String(ch_)); + smart_ptr c(new utakata::unicode::UniString(ch_)); return c; } @@ -283,7 +283,7 @@ smart_ptr Charactor::getData() const // Boolean // ///////////// -Boolean::Boolean(smart_ptr ch) : bool_(new UTF8String()) +Boolean::Boolean(smart_ptr ch) : bool_(new UniString()) { *bool_ += "#"; *bool_ += *ch; @@ -294,7 +294,7 @@ const utakata::lexeme::LexemeID Boolean::getID() const return utakata::lexeme::LexemeID::boolean; } -smart_ptr Boolean::toString() const +smart_ptr Boolean::toString() const { return bool_; } diff --git a/lexeme_impl.h b/lexeme_impl.h index 6e1b5c3..100f663 100755 --- a/lexeme_impl.h +++ b/lexeme_impl.h @@ -7,7 +7,7 @@ #include "smart_ptr.h" #include "function_callback.h" -#include "utf8_string.h" +#include "unicode.h" #include "lexeme_id.h" // lexeme の様々な実装を定義する. @@ -31,19 +31,19 @@ namespace utakata { smart_ptr makeUnsyntax (); smart_ptr makeByteVector (); smart_ptr makeVector (); - smart_ptr makeIdentifier (const utakata::utf8_string::UTF8String& str); - smart_ptr makeString (const utakata::utf8_string::UTF8String& str); - smart_ptr makeNumber (const utakata::utf8_string::UTF8String& real, - const utakata::utf8_string::UTF8String& imaginary, + smart_ptr makeIdentifier (const utakata::unicode::UniString& str); + smart_ptr makeString (const utakata::unicode::UniString& str); + smart_ptr makeNumber (const utakata::unicode::UniString& real, + const utakata::unicode::UniString& imaginary, bool exact, int radix); - smart_ptr makeCharactor (const utakata::utf8_string::UTF8String& str); - smart_ptr makeNanImaginary (const utakata::utf8_string::UTF8String& str, + smart_ptr makeCharactor (const utakata::unicode::UniString& str); + smart_ptr makeNanImaginary (const utakata::unicode::UniString& str, bool exact); - smart_ptr makeInfImaginary (const utakata::utf8_string::UTF8String& str, + smart_ptr makeInfImaginary (const utakata::unicode::UniString& str, bool exact); - smart_ptr makeImaginaryOnly (const utakata::utf8_string::UTF8String& str, + smart_ptr makeImaginaryOnly (const utakata::unicode::UniString& str, bool exact); - smart_ptr makeBoolean (smart_ptr ch); + smart_ptr makeBoolean (smart_ptr ch); //////////////////////////////////////////// @@ -55,18 +55,18 @@ namespace utakata { // LiteralDataを必要としないデータに対して処理を行うためのクラス。 // 文字列と該当するLexemeIDを渡すことで実現する。 public: - PureLexeme(smart_ptr str, + PureLexeme(smart_ptr str, lexeme::LexemeID id); virtual ~PureLexeme() {} const lexeme::LexemeID getID() const ; - smart_ptr toString() const; + smart_ptr toString() const; smart_ptr getData() const; private: - smart_ptr str_; + smart_ptr str_; lexeme::LexemeID id_; }; @@ -78,15 +78,15 @@ namespace utakata { { public: - String (const utakata::utf8_string::UTF8String& ident); + String (const utakata::unicode::UniString& ident); virtual ~String (){} const lexeme::LexemeID getID () const; - smart_ptr toString () const; + smart_ptr toString () const; smart_ptr getData() const; private: - smart_ptr str_; + smart_ptr str_; }; @@ -98,15 +98,15 @@ namespace utakata { { public: - Identifier (const utakata::utf8_string::UTF8String& ident); + Identifier (const utakata::unicode::UniString& ident); virtual ~Identifier (){} const lexeme::LexemeID getID () const; - smart_ptr toString () const; + smart_ptr toString () const; smart_ptr getData() const; private: - smart_ptr str_; + smart_ptr str_; }; @@ -117,11 +117,11 @@ namespace utakata { class Number : public ILexeme { public: - Number (const utf8_string::UTF8String& real, const utf8_string::UTF8String& imagin, + Number (const unicode::UniString& real, const unicode::UniString& imagin, bool exact, int radix); virtual ~Number (){} const lexeme::LexemeID getID () const; - smart_ptr toString () const; + smart_ptr toString () const; smart_ptr getData() const; private: @@ -135,16 +135,16 @@ namespace utakata { class Charactor : public ILexeme { public: - Charactor (const utf8_string::UTF8String& ch); + Charactor (const unicode::UniString& ch); virtual ~Charactor (){} const lexeme::LexemeID getID () const; - smart_ptr toString() const; + smart_ptr toString() const; smart_ptr getData() const; private: - smart_ptr ch_; + smart_ptr ch_; }; ///////////// @@ -154,15 +154,15 @@ namespace utakata { class Boolean : public ILexeme { public: - Boolean (smart_ptr ch); + Boolean (smart_ptr ch); virtual ~Boolean (){} const lexeme::LexemeID getID () const; - smart_ptr toString () const; + smart_ptr toString () const; smart_ptr getData() const; private: - smart_ptr bool_; + smart_ptr bool_; }; }; diff --git a/lexer.h b/lexer.h index 0760090..9deac60 100755 --- a/lexer.h +++ b/lexer.h @@ -3,7 +3,7 @@ #include "smart_ptr.h" #include "utf8.h" -#include "utf8_string.h" +#include "unicode.h" #include "lexeme.h" #include diff --git a/literal.cpp b/literal.cpp index f2222e3..c376fe9 100755 --- a/literal.cpp +++ b/literal.cpp @@ -1,18 +1,18 @@ #include "literal.h" #include "literal_impl.h" -#include "utf8_string.h" +#include "unicode.h" #include "datum_id.h" #include "literal_data.h" #include "lexeme_impl.h" #include "lexeme_id.h" using namespace utakata::lexeme; -using namespace utakata::utf8_string; +using namespace utakata::unicode; using namespace utakata::syntax; using namespace utakata::literal; -smart_ptr Literal::toValue() +smart_ptr Literal::toValue() { // 内部実装を基にデータを出力する。 return toValue_(); @@ -30,7 +30,7 @@ DatumID Literal::getID() const smart_ptr utakata::literal::generateLiteral(smart_ptr l) { - smart_ptr s; + smart_ptr s; switch (l->getID().toEnum()) { @@ -45,43 +45,43 @@ smart_ptr utakata::literal::generateLiteral(smart_ptr l) case LexemeID::IDENTIFIER: return smart_ptr(new utakata::literal::Symbol(l->getData())); case LexemeID::BACKQUOTE: - s.add(new UTF8String(convert("backquote"))); + s.add(new UniString(convert("backquote"))); return smart_ptr(new utakata::literal::Abbreviation( l->toString(), s)); case LexemeID::QUOTE: - s.add(new UTF8String(convert("quote"))); + s.add(new UniString(convert("quote"))); return smart_ptr(new utakata::literal::Abbreviation( l->toString(), s)); case LexemeID::UNQUOTE: - s.add(new UTF8String(convert("unquote"))); + s.add(new UniString(convert("unquote"))); return smart_ptr(new utakata::literal::Abbreviation( l->toString(), s)); case LexemeID::UNQUOTESPLICING: - s.add(new UTF8String(convert("unquote-splicing"))); + s.add(new UniString(convert("unquote-splicing"))); return smart_ptr(new utakata::literal::Abbreviation( l->toString(), s)); case LexemeID::SYNTAX: - s.add(new UTF8String(convert("syntax"))); + s.add(new UniString(convert("syntax"))); return smart_ptr(new utakata::literal::Abbreviation( l->toString(), s)); case LexemeID::QUASISYNTAX: - s.add(new UTF8String(convert("quasisyntax"))); + s.add(new UniString(convert("quasisyntax"))); return smart_ptr(new utakata::literal::Abbreviation( l->toString(), s)); case LexemeID::UNSYNTAX: - s.add(new UTF8String(convert("unsyntax"))); + s.add(new UniString(convert("unsyntax"))); return smart_ptr(new utakata::literal::Abbreviation( l->toString(), s)); case LexemeID::UNSYNTAXSPLICING: - s.add(new UTF8String(convert("unsyntax-splicing"))); + s.add(new UniString(convert("unsyntax-splicing"))); return smart_ptr(new utakata::literal::Abbreviation( l->toString(), s)); diff --git a/literal.h b/literal.h index 1c631b5..2c7b89f 100755 --- a/literal.h +++ b/literal.h @@ -16,8 +16,8 @@ namespace utakata { }; - namespace utf8_string { - class UTF8String; + namespace unicode { + class UniString; }; namespace literal { @@ -37,14 +37,14 @@ namespace utakata { Literal() {} virtual ~Literal() {} - smart_ptr toValue(); + smart_ptr toValue(); const smart_ptr& getData() const; syntax::DatumID getID() const; private: - virtual smart_ptr toValue_() = 0; + virtual smart_ptr toValue_() = 0; virtual const smart_ptr& getData_() const = 0; virtual syntax::DatumID getID_() const = 0; diff --git a/literal_data.cpp b/literal_data.cpp index 4aa4c01..488f9fd 100755 --- a/literal_data.cpp +++ b/literal_data.cpp @@ -1,59 +1,59 @@ #include "literal_data.h" -#include "utf8_string.h" +#include "unicode.h" using namespace utakata::literal; -using namespace utakata::utf8_string; +using namespace utakata::unicode; -smart_ptr utakata::literal::makeString(const utf8_string::UTF8String& str) +smart_ptr utakata::literal::makeString(const unicode::UniString& str) { // stringを内部に生成して返すのみ。 smart_ptr ret(new LiteralData); ret->string.add(new StringData); - ret->string->str.add(new UTF8String(str)); + ret->string->str.add(new UniString(str)); return ret; } -smart_ptr utakata::literal::makeNumber(const utf8_string::UTF8String& real, - const utf8_string::UTF8String& imagin, +smart_ptr utakata::literal::makeNumber(const unicode::UniString& real, + const unicode::UniString& imagin, bool exact, bool radix) { // numberを内部に生成して返すのみ。 smart_ptr ret(new LiteralData); ret->number.add(new NumberData); - ret->number->real.add(new UTF8String(real)); - ret->number->imagin.add(new UTF8String(imagin)); + ret->number->real.add(new UniString(real)); + ret->number->imagin.add(new UniString(imagin)); ret->number->exact = exact; ret->number->radix = radix; return ret; } -smart_ptr utakata::literal::makeBoolean(const utf8_string::UTF8String& str, +smart_ptr utakata::literal::makeBoolean(const unicode::UniString& str, bool boolean) { // booleanを内部に生成して返すのみ。 smart_ptr ret(new LiteralData); ret->boolean.add(new BooleanData); - ret->boolean->str.add(new UTF8String(str)); + ret->boolean->str.add(new UniString(str)); ret->boolean->boolean = boolean; return ret; } -smart_ptr utakata::literal::makeCharactor(const utf8_string::UTF8Char& ch) +smart_ptr utakata::literal::makeCharactor(const unicode::UniChar& ch) { // charactorを内部に生成する。charactorは、元となる文字列から、 // 対応するUTF-8の文字コードを生成する。 smart_ptr ret(new LiteralData); ret->charactor.add(new CharactorData); - ret->charactor->spec.add(new UTF8Char(ch)); + ret->charactor->spec.add(new UniChar(ch)); return ret; } -smart_ptr utakata::literal::makeSymbol(const utf8_string::UTF8String& str) +smart_ptr utakata::literal::makeSymbol(const unicode::UniString& str) { // symnbolを内部に生成して返すのみ。 smart_ptr ret(new LiteralData); ret->symbol.add(new SymbolData); - ret->symbol->id.add(new UTF8String(str)); + ret->symbol->id.add(new UniString(str)); return ret; } diff --git a/literal_data.h b/literal_data.h index 394a61a..13aeeda 100755 --- a/literal_data.h +++ b/literal_data.h @@ -6,9 +6,9 @@ namespace utakata { - namespace utf8_string { + namespace unicode { - class UTF8String; + class UniString; }; @@ -17,7 +17,7 @@ namespace utakata { struct StringData { // 文字列を保持するためのデータ型. たんにそのまま. - smart_ptr str; + smart_ptr str; }; struct NumberData @@ -26,8 +26,8 @@ namespace utakata { // 数値データは, それぞれ実数部分と虚数部分, そして // 正確性と radix を定義する必要がある. // radix = 10 ではない場合, 常に exact = true として振る舞う. - smart_ptr real; - smart_ptr imagin; + smart_ptr real; + smart_ptr imagin; bool exact; int radix; }; @@ -37,20 +37,20 @@ namespace utakata { // Boolean を表すデータ. これでは bool 型の変数によって#t と#f を表現 // することにする. bool boolean; - smart_ptr str; + smart_ptr str; }; struct CharactorData { // Charactor を構成するためのデータ. // この時点で、渡された文字列から数値に変換が完了しているものとする。 - smart_ptr spec; + smart_ptr spec; }; struct SymbolData { // シンボルを構成するためのデータ. - smart_ptr id; + smart_ptr id; }; @@ -71,14 +71,14 @@ namespace utakata { }; // 各データ入りのLiteralDataを返すヘルパー関数。 - smart_ptr makeString(const utf8_string::UTF8String& str); - smart_ptr makeNumber(const utf8_string::UTF8String& real, - const utf8_string::UTF8String& imagin, + smart_ptr makeString(const unicode::UniString& str); + smart_ptr makeNumber(const unicode::UniString& real, + const unicode::UniString& imagin, bool exact, bool radix); - smart_ptr makeBoolean(const utf8_string::UTF8String& str, + smart_ptr makeBoolean(const unicode::UniString& str, bool boolean); - smart_ptr makeCharactor(const utf8_string::UTF8Char& ch); - smart_ptr makeSymbol(const utf8_string::UTF8String& str); + smart_ptr makeCharactor(const unicode::UniChar& ch); + smart_ptr makeSymbol(const unicode::UniString& str); }; diff --git a/literal_impl.cpp b/literal_impl.cpp index 907025f..61c2546 100755 --- a/literal_impl.cpp +++ b/literal_impl.cpp @@ -1,18 +1,18 @@ #include "literal_impl.h" #include "literal_data.h" -#include "utf8_string.h" +#include "unicode.h" #include "datum_id.h" using namespace utakata; -using namespace utakata::utf8_string; +using namespace utakata::unicode; using namespace utakata::literal; literal::Boolean::Boolean(smart_ptr data) : data_(data) { } -smart_ptr literal::Boolean::toValue_() +smart_ptr literal::Boolean::toValue_() { return data_->boolean->str; } @@ -35,10 +35,10 @@ String::String(smart_ptr data) : data_(data) { } -smart_ptr literal::String::toValue_() +smart_ptr literal::String::toValue_() { // 文字列として返す。 - smart_ptr s(new utf8_string::UTF8String); + smart_ptr s(new unicode::UniString); *s += "\""; *s += *data_->string->str; *s += "\""; @@ -63,9 +63,9 @@ Number::Number(smart_ptr data) : data_(data) { } -smart_ptr literal::Number::toValue_() +smart_ptr literal::Number::toValue_() { - smart_ptr tmp(new UTF8String); + smart_ptr tmp(new UniString); *tmp = *data_->number->real + *data_->number->imagin; return tmp; } @@ -88,7 +88,7 @@ Symbol::Symbol(smart_ptr data) : data_(data) { } -smart_ptr literal::Symbol::toValue_() +smart_ptr literal::Symbol::toValue_() { return data_->symbol->id; } @@ -111,7 +111,7 @@ Charactor::Charactor(smart_ptr data) : data_(data) { } -smart_ptr literal::Charactor::toValue_() +smart_ptr literal::Charactor::toValue_() { return data_->charactor->spec; } @@ -133,18 +133,18 @@ const smart_ptr& Charactor::getData_() const struct Abbreviation::pImpl { smart_ptr data; - smart_ptr str; + smart_ptr str; }; -Abbreviation::Abbreviation(const smart_ptr& str, - const smart_ptr& symbol) : +Abbreviation::Abbreviation(const smart_ptr& str, + const smart_ptr& symbol) : pimpl_(new pImpl) { pimpl_->str = str; pimpl_->data = makeSymbol(*symbol); } -smart_ptr Abbreviation::toValue_() +smart_ptr Abbreviation::toValue_() { return pimpl_->str; } diff --git a/literal_impl.h b/literal_impl.h index 60e0426..2001ace 100755 --- a/literal_impl.h +++ b/literal_impl.h @@ -6,8 +6,8 @@ namespace utakata { - namespace utf8_string { - class UTF8String; + namespace unicode { + class UniString; }; namespace syntax { @@ -25,7 +25,7 @@ namespace utakata { private: - smart_ptr toValue_(); + smart_ptr toValue_(); const smart_ptr& getData_() const; syntax::DatumID getID_() const; @@ -41,7 +41,7 @@ namespace utakata { private: - smart_ptr toValue_(); + smart_ptr toValue_(); const smart_ptr& getData_() const; syntax::DatumID getID_() const; smart_ptr data_; @@ -55,7 +55,7 @@ namespace utakata { private: - smart_ptr toValue_(); + smart_ptr toValue_(); const smart_ptr& getData_() const; syntax::DatumID getID_() const; smart_ptr data_; @@ -69,7 +69,7 @@ namespace utakata { private: - smart_ptr toValue_(); + smart_ptr toValue_(); const smart_ptr& getData_() const; syntax::DatumID getID_() const; smart_ptr data_; @@ -83,7 +83,7 @@ namespace utakata { private: - smart_ptr toValue_(); + smart_ptr toValue_(); const smart_ptr& getData_() const; syntax::DatumID getID_() const; @@ -98,13 +98,13 @@ namespace utakata { // 各Abbreviationは、展開時の文字列=シンボルと、 // リテラルとして保持するデータの二種類を分けて持つ必要がある。 public: - Abbreviation(const smart_ptr& str, - const smart_ptr& symbol); + Abbreviation(const smart_ptr& str, + const smart_ptr& symbol); virtual ~Abbreviation() {} private: - smart_ptr toValue_(); + smart_ptr toValue_(); const smart_ptr& getData_() const; syntax::DatumID getID_() const; diff --git a/number_lexer.h b/number_lexer.h old mode 100644 new mode 100755 index d78cf93..d6488e0 --- a/number_lexer.h +++ b/number_lexer.h @@ -4,7 +4,7 @@ #include #include -#include "utf8_string.h" +#include "unicode.h" #include "smart_ptr.h" #include "utf8.h" #include "lexeme.h" @@ -40,8 +40,8 @@ namespace utakata { Number() : INIT(1), REAL(2), UREAL(3), NAN_IMAGINARY(4), INF_IMAGINARY(5), IMAGINARY_ONLY(8), FLAG(9), END(10), IMAGINARY(11), - exact_(false), realnum_(new utf8_string::UTF8String()), - imaginary_(new utf8_string::UTF8String()) + exact_(false), realnum_(new unicode::UniString()), + imaginary_(new unicode::UniString()) { } @@ -49,14 +49,14 @@ namespace utakata { smart_ptr lex(smart_ptr stream, smart_ptr& next, - const utf8_string::UTF8String& str, + const unicode::UniString& str, bool exactness) { // 全体的な流れは同一であり、基数の違いによる // 数値の違い程度しか問題は発生しない。 exact_ = exactness; lexer_delimiter::Normal nor; - utf8_string::UTF8String number = str; + unicode::UniString number = str; while (true) { // デリミタまで読んでしまう。 if (stream->isEOF()) @@ -64,7 +64,7 @@ namespace utakata { throw utakata::sublexer::LexException(pos_, "illegal number format"); } - utf8_string::UTF8Char ch(stream->read()); + unicode::UniChar ch(stream->read()); if (nor(ch)) { stream->unget(ch.getBytes()); @@ -89,11 +89,11 @@ namespace utakata { now = next; } - smart_ptr lexNumber_(const utf8_string::UTF8String& number) + smart_ptr lexNumber_(const unicode::UniString& number) { // デリミタまでを取得したデータを、実際の数値オブジェクトとして解釈させる。 // 解釈できなかった場合、字句構文エラーとして扱う。 - utf8_string::UTF8String::const_utf8iterator begin = number.begin(), + unicode::UniString::const_utf8iterator begin = number.begin(), end = number.end(); int status = INIT, prevstatus = INIT; @@ -146,7 +146,7 @@ namespace utakata { else if (status == FLAG) { // 虚数部分の先頭符号を示す。 - utf8_string::UTF8String s; + unicode::UniString s; s.insert(s.begin(), begin, end); if (s.size() == 1) @@ -167,7 +167,7 @@ namespace utakata { else { // +i,-i以外の場合は、限定領域がrealである必要がある。 - utf8_string::UTF8String s2; + unicode::UniString s2; s2.insert(s2.begin(), s.begin() + 1, s.end() - 1); if (s2.toStr() == "nan.0" || s2.toStr() == "inf.0") { @@ -177,7 +177,7 @@ namespace utakata { else { // urealである必要がある。 - utakata::utf8_string::UTF8String::const_utf8iterator begin = s2.begin(), + utakata::unicode::UniString::const_utf8iterator begin = s2.begin(), end = s2.end(); UReal(pos_).lex(begin, end); // 例外が発生しなければureal_である。 @@ -204,11 +204,11 @@ namespace utakata { } // 初期状態で確定可能なリテラルをチェックする。 - int complex_(utf8_string::UTF8String::const_utf8iterator& begin, - const utf8_string::UTF8String::const_utf8iterator& end) + int complex_(unicode::UniString::const_utf8iterator& begin, + const unicode::UniString::const_utf8iterator& end) { // 一文字単位で調べていく。checker_に該当するデータの場合には、 - utf8_string::UTF8String s; + unicode::UniString s; s.insert(s.begin(), begin, end); if (s.toStr() == "-nan.0i" || s.toStr() == "+nan.0i") { @@ -235,8 +235,8 @@ namespace utakata { } - int real_(utf8_string::UTF8String::const_utf8iterator& begin, - const utf8_string::UTF8String::const_utf8iterator& end) + int real_(unicode::UniString::const_utf8iterator& begin, + const unicode::UniString::const_utf8iterator& end) { // 実数の表現でなければならない。 // 先頭一文字が符号表現か、符号無し表現で @@ -253,8 +253,8 @@ namespace utakata { } } - int innerReal_(utf8_string::UTF8String::const_utf8iterator& begin, - const utf8_string::UTF8String::const_utf8iterator& end, + int innerReal_(unicode::UniString::const_utf8iterator& begin, + const unicode::UniString::const_utf8iterator& end, bool flag) { // realの符号有無に関係の無い、共通部分の分離。 @@ -262,8 +262,8 @@ namespace utakata { { ++begin; } - utf8_string::UTF8String s; - utf8_string::UTF8String::const_utf8iterator save = begin; + unicode::UniString s; + unicode::UniString::const_utf8iterator save = begin; while (begin != end && (begin->toUTF16Code() != '+' || begin->toUTF16Code() != '-')) { ++begin; @@ -288,8 +288,8 @@ namespace utakata { } - int flag_(utf8_string::UTF8String::const_utf8iterator& begin, - const utf8_string::UTF8String::const_utf8iterator& end) + int flag_(unicode::UniString::const_utf8iterator& begin, + const unicode::UniString::const_utf8iterator& end) { // 虚数の先頭に必ず必要な符号が存在するかどうかを返す。 if (begin->toUTF16Code() == '+' || begin->toUTF16Code() == '-') @@ -307,8 +307,8 @@ namespace utakata { // チェックを行うための関数オブジェクト。 bool exact_; - smart_ptr realnum_; - smart_ptr imaginary_; + smart_ptr realnum_; + smart_ptr imaginary_; size_t pos_; }; @@ -320,7 +320,7 @@ namespace utakata { class UInteger { // 指定された基数の値であるかどうかを調べる。 - typedef utakata::utf8_string::UTF8String::const_utf8iterator iter; + typedef utakata::unicode::UniString::const_utf8iterator iter; public: UInteger() {} virtual ~UInteger(){} @@ -333,7 +333,7 @@ namespace utakata { template<> class UInteger<2> { - typedef utakata::utf8_string::UTF8String::const_utf8iterator iter; + typedef utakata::unicode::UniString::const_utf8iterator iter; public: bool operator()(iter it) { if (it->toUTF16Code() == '0' || it->toUTF16Code() == '1') @@ -347,7 +347,7 @@ namespace utakata { template<> class UInteger<8> { - typedef utakata::utf8_string::UTF8String::const_utf8iterator iter; + typedef utakata::unicode::UniString::const_utf8iterator iter; public: bool operator()(iter it) { if (it->toUTF16Code() == '0' || it->toUTF16Code() == '1' || @@ -364,7 +364,7 @@ namespace utakata { template<> class UInteger<10> { - typedef utakata::utf8_string::UTF8String::const_utf8iterator iter; + typedef utakata::unicode::UniString::const_utf8iterator iter; public: bool operator()(iter it) { if (it->toUTF16Code() == '0' || it->toUTF16Code() == '1' || @@ -382,7 +382,7 @@ namespace utakata { template<> class UInteger<16> { - typedef utakata::utf8_string::UTF8String::const_utf8iterator iter; + typedef utakata::unicode::UniString::const_utf8iterator iter; public: bool operator()(iter it) { if (it->toUTF16Code() == '0' || it->toUTF16Code() == '1' || @@ -410,7 +410,7 @@ namespace utakata { template class UReal { - typedef utakata::utf8_string::UTF8String::const_utf8iterator iter; + typedef utakata::unicode::UniString::const_utf8iterator iter; public: UReal(size_t pos) : pos_(pos) { @@ -461,7 +461,7 @@ namespace utakata { template<> class UReal<10> { - typedef utakata::utf8_string::UTF8String::const_utf8iterator iter; + typedef utakata::unicode::UniString::const_utf8iterator iter; public: UReal(size_t pos) : pos_(pos) { diff --git a/port.h b/port.h new file mode 100755 index 0000000..5f7f520 --- /dev/null +++ b/port.h @@ -0,0 +1,59 @@ +#ifndef _STREAM_H_ +#define _STREAM_H_ + +#include +#include +#include + +namespace utakata { + + namespace stream { + + class IInputPort + { + // 入力を抽象化したport + // このportでは、原則として単純に1バイトを読み出すしかできない。 + // intとしているのは、ベースとしているistreamがintを返すように + // 設計されているためであり、256を返す可能性があるためである。 + public: + + IInputPort(){} + virtual ~IInputPort(){} + + // ストリームから1単位読みだして返す。 + // ストリーム毎に、1単位が異なるため、vectorにてバイト単位で + // 抽出する。 + virtual int read() = 0; + virtual std::vector read(size_t num) = 0; + + virtual int peek() = 0; + + // 現在streamのどこまでを読んでいるのかを返す。 + virtual size_t pos() = 0; + + // 渡されたvectorをstreamに戻す。 + virtual void unget(int ch) = 0; + + // 現在のportが終了時点かどうかを返す。 + virtual bool isEOF() = 0; + }; + + // streamになんらか異常が発生した場合に送出される例外 + class PortException : public std::exception + { + public: + PortException(const std::string& str) : str_(str) {} + virtual ~PortException() throw() {} + + const char* what() throw() { + return str_.c_str(); + } + private: + + std::string str_; + }; + + }; +} + +#endif /* _STREAM_H_ */ diff --git a/primitive.cpp b/primitive.cpp old mode 100644 new mode 100755 index 6412cfc..5b2f345 --- a/primitive.cpp +++ b/primitive.cpp @@ -1,29 +1,29 @@ #include "primitive.h" #include "object.h" -#include "utf8_string.h" +#include "unicode.h" using namespace utatata; using namespace utakata::interpreter; -using namespace utakata::utf8_string; +using namespace utakata::unicode; -utatata::primitive::String(const smart_ptr& data) : data_(data) +utatata::primitive::String(const smart_ptr& data) : data_(data) { } -UTF8String& primitive::String::getData() +UniString& primitive::String::getData() { return *data_; } -primitive::Charactor::Charactor(const smart_ptr& data) : data_() +primitive::Charactor::Charactor(const smart_ptr& data) : data_() { - // UTF8Stringを解析して、文字コードに変換する。 + // UniStringを解析して、文字コードに変換する。 // ここで渡されるdataは、すでに先頭の#\が取り除かれている状態となっている。 // 実際にはここで解釈するのではなく、 } -UTF8Char& primitive::Charactor::getData() +UniChar& primitive::Charactor::getData() { return data_; } diff --git a/primitive.h b/primitive.h index 51350e9..b43c7f4 100755 --- a/primitive.h +++ b/primitive.h @@ -8,9 +8,9 @@ namespace utakata { - namespace utf8_string { - class UTF8Char; - class UTF8String; + namespace unicode { + class UniChar; + class UniString; }; namespace interpreter { @@ -36,29 +36,29 @@ namespace utakata { { // scheme中での文字列を指す。 public: - String(const smart_ptr& data); + String(const smart_ptr& data); virtual ~String() {} - utf8_string::UTF8String& getData(); + unicode::UniString& getData(); priavte: - smart_ptr data_; + smart_ptr data_; }; class Charactor { // scheme中でのunicode文字を表す。 - // 一文字のみを表現するため、UTF8Charが利用される。 + // 一文字のみを表現するため、UniCharが利用される。 public: - Charactor(const smart_ptr& data); + Charactor(const smart_ptr& data); virtual ~Charactor() {} - utf8_string::UTF8Char& getData(); + unicode::UniChar& getData(); private: - smart_ptr data_; + smart_ptr data_; }; class Boolean @@ -80,14 +80,14 @@ namespace utakata { // シンボルを表現する。シンボルは実際には単純な文字列として // 保持されるが、処理の際に特別に処理される点が異なっている。 public: - Symbol(const smart_ptr& sym); + Symbol(const smart_ptr& sym); virtual ~Symbol() {} - utf8_string::UTF8String& getData(); + unicode::UniString& getData(); private: - smart_ptr symbol_; + smart_ptr symbol_; }; class List diff --git a/sublexer_impl.cpp b/sublexer_impl.cpp index 6abb1ef..41fa552 100755 --- a/sublexer_impl.cpp +++ b/sublexer_impl.cpp @@ -2,7 +2,7 @@ #include #include -#include "utf8_string.h" +#include "unicode.h" #include "sublexer_impl.h" #include "lexeme_impl.h" #include "delimiter.h" @@ -10,18 +10,18 @@ #include "lexeme_id.h" using namespace utakata; -using namespace utakata::utf8_string; +using namespace utakata::unicode; smart_ptr sublexer::FirstLexer::lex(smart_ptr stream, smart_ptr& next) { // chにはlexerから渡された、今回読みだした文字が渡されている。 - UTF8String str; + UniString str; // 最初に実行されるので、最初の空白を読み飛ばす。 - UTF8Char ch(stream->read()); + UniChar ch(stream->read()); { lexer_delimiter::Whitespace sps; while (sps(ch)) { @@ -56,18 +56,18 @@ smart_ptr sublexer::FirstLexer::lex(smart_ptrpeek()))) + if (lexer_delimiter::Normal()(UniChar(stream->peek()))) { ret = lexeme::makeDot(); } } - else if (utf8_string::is_numeric(ch)) + else if (unicode::is_numeric(ch)) { // 先頭が数値だった場合、これは10進数だと判断して次に進む。 - next.add(new sublexer::NumberLexer(UTF8String(ch.getBytes()))); + next.add(new sublexer::NumberLexer(UniString(ch.getBytes()))); ret = smart_ptr(); } - else if (utf8_string::is_alpha(ch) || + else if (unicode::is_alpha(ch) || ch.toUTF16Code() == '!' || ch.toUTF16Code() == '$' || ch.toUTF16Code() == '%' || ch.toUTF16Code() == '&' || ch.toUTF16Code() == '*' || ch.toUTF16Code() == '/' || @@ -79,7 +79,7 @@ smart_ptr sublexer::FirstLexer::lex(smart_ptr(); } else if (ch.toUTF16Code() == ';') @@ -117,13 +117,13 @@ smart_ptr sublexer::FirstLexer::lex(smart_ptr(); } -smart_ptr sublexer::FirstLexer::lex_(const utakata::utf8_string::UTF8String& str, +smart_ptr sublexer::FirstLexer::lex_(const utakata::unicode::UniString& str, smart_ptr stream, smart_ptr& next) { if (str[0].toUTF16Code() == ',') { - UTF8Char ch = stream->peek(); + UniChar ch = stream->peek(); // 次の一文字で決定できる。 if (ch.toUTF16Code() == '@') { @@ -139,7 +139,7 @@ smart_ptr sublexer::FirstLexer::lex_(const utakata::utf8_string else if (str[0].toUTF16Code() == '#') { // コメントなどに繋がる時もあるため、面倒。 - UTF8Char ch = stream->peek(); + UniChar ch = stream->peek(); if (ch.toUTF16Code() == '\'') { stream->read(); @@ -212,7 +212,7 @@ smart_ptr sublexer::FirstLexer::lex_(const utakata::utf8_string { // 先頭が-の場合、次の文字を見てから決める。 // 基本的には数値だが、次の文字によってはidentifierになりうる。 - UTF8Char ch(stream->peek()); + UniChar ch(stream->peek()); lexer_delimiter::Normal nor; if (ch.toUTF16Code() == '>' || nor(ch)) { @@ -238,10 +238,10 @@ smart_ptr sublexer::StringLexer::lex(smart_ptrisEOF()) { - UTF8Char tmp(stream->peek()); + UniChar tmp(stream->peek()); if (st(tmp)) { // readしておく。 stream->read(); @@ -272,12 +272,12 @@ smart_ptr sublexer::NestedCommentLexer::lex(smart_ptrisEOF() && count > 0) { - utf8_string::UTF8Char tmp(stream->read()); + unicode::UniChar tmp(stream->read()); if (tmp.toUTF16Code() == '#') { // 次の文字を調べる。 - utf8_string::UTF8Char t2(stream->read()); + unicode::UniChar t2(stream->read()); if (t2.toUTF16Code() == '|') { ++count; @@ -286,7 +286,7 @@ smart_ptr sublexer::NestedCommentLexer::lex(smart_ptrread()); + unicode::UniChar t2(stream->read()); if (t2.toUTF16Code() == '#') { --count; @@ -299,15 +299,15 @@ smart_ptr sublexer::NestedCommentLexer::lex(smart_ptr sublexer::NumberLexer::innerLex_(smart_ptr stream, smart_ptr& next, - const utf8_string::UTF8String& str) + const unicode::UniString& str) { // prefixをチェックして、返すべきものを決定する。 if (prefix_ == BINARY) @@ -332,7 +332,7 @@ smart_ptr sublexer::NumberLexer::innerLex_(smart_ptr sublexer::NumberLexer::lex(smart_ptr sublexer::NumberLexer::lex(smart_ptr sublexer::NumberLexer::lex(smart_ptr sublexer::IdentifierLexer::lex(smart_ptr stream, @@ -433,7 +433,7 @@ smart_ptr sublexer::IdentifierLexer::lex(smart_ptr sublexer::IdentifierLexer::lex(smart_ptrpeek()); + UniChar next(stream->peek()); if (nor(next)) { return lexeme::makeIdentifier(str); @@ -453,7 +453,7 @@ smart_ptr sublexer::IdentifierLexer::lex(smart_ptrisEOF()) { - UTF8Char tmp(stream->peek()); + UniChar tmp(stream->peek()); if (nor(tmp)) { break; } @@ -470,15 +470,15 @@ smart_ptr sublexer::CharactorLexer::lex(smart_ptrread()); + UniChar ch(stream->read()); bool flag = ch.toUTF16Code() == 'x' ? true : false; // Hexを解釈する。解釈部分を書くと面倒になるため、単純な別関数にしておく。 - UTF8String str(ch.getBytes()); + UniString str(ch.getBytes()); lexer_delimiter::Normal nor; lexer_delimiter::HexValue hex; while (!stream->isEOF()) { - UTF8Char tmp(stream->peek()); + UniChar tmp(stream->peek()); if (nor(tmp)) { break; @@ -496,18 +496,18 @@ smart_ptr sublexer::CharactorLexer::lex(smart_ptr sublexer::CharactorLexer::parseCharSpec(const utf8_string::UTF8String& s) +std::vector sublexer::CharactorLexer::parseCharSpec(const unicode::UniString& s) { // 対象となる文字列を //================================================================================ -sublexer::BooleanLexer::BooleanLexer(const utf8_string::UTF8Char& ch) : ch_(new utf8_string::UTF8Char(ch)) +sublexer::BooleanLexer::BooleanLexer(const unicode::UniChar& ch) : ch_(new unicode::UniChar(ch)) { } @@ -519,7 +519,7 @@ smart_ptr sublexer::BooleanLexer::lex(smart_ptrisEOF()) { - UTF8Char ch(stream->peek()); + UniChar ch(stream->peek()); lexer_delimiter::Normal nor; if (!nor(ch)) @@ -537,7 +537,7 @@ smart_ptr sublexer::BooleanLexer::lex(smart_ptr sublexer::ByteVectorLexer::lex(smart_ptrread(3)); + UniString str(stream->read(3)); if (str.toStr() != "u8(") { std::stringstream ss; @@ -574,7 +574,7 @@ smart_ptr sublexer::OneLineCommentLexer::lex( lexer_delimiter::LineEnding end; while (!stream->isEOF()) { // 改行が出力されるまで全て読み飛ばす。 - UTF8Char ch = stream->read(); + UniChar ch = stream->read(); if (end(ch, stream)) { // この時点で、読み飛ばしまで行われている。 diff --git a/sublexer_impl.h b/sublexer_impl.h index bf949c0..2608b45 100755 --- a/sublexer_impl.h +++ b/sublexer_impl.h @@ -7,7 +7,7 @@ #include "smart_ptr.h" #include "utf8.h" #include "lexeme.h" -#include "utf8_string.h" +#include "unicode.h" namespace utakata { @@ -41,7 +41,7 @@ namespace utakata { private: // lex関数中で利用される、雑多になった字句解析関数の分割 - smart_ptr lex_(const utakata::utf8_string::UTF8String& str, + smart_ptr lex_(const utakata::unicode::UniString& str, smart_ptr stream, smart_ptr& next); @@ -102,7 +102,7 @@ namespace utakata { private: // 渡された文字列のspecを判定する。 - std::vector parseCharSpec(const utf8_string::UTF8String& s); + std::vector parseCharSpec(const unicode::UniString& s); }; @@ -116,7 +116,7 @@ namespace utakata { const unsigned char HEX; public: - NumberLexer(const utakata::utf8_string::UTF8String& str); + NumberLexer(const utakata::unicode::UniString& str); virtual ~NumberLexer(){} smart_ptr lex(smart_ptr stream, @@ -125,17 +125,17 @@ namespace utakata { smart_ptr innerLex_(smart_ptr stream, smart_ptr& next, - const utakata::utf8_string::UTF8String& str); + const utakata::unicode::UniString& str); // 渡した文字列からprefixを抽出して返す。 - unsigned char getPrefix_(const utakata::utf8_string::UTF8String& str); + unsigned char getPrefix_(const utakata::unicode::UniString& str); // 正確性を抽出して返す。 - void checkExactness_(const utakata::utf8_string::UTF8String& str); + void checkExactness_(const utakata::unicode::UniString& str); private: - smart_ptr str_; + smart_ptr str_; bool exact_; // 正確性を設定する。 unsigned char prefix_; // prefixを設定する。 @@ -149,7 +149,7 @@ namespace utakata { // を保存する必要すらない。 public: - IdentifierLexer(const utakata::utf8_string::UTF8String& str); + IdentifierLexer(const utakata::unicode::UniString& str); virtual ~IdentifierLexer(){} smart_ptr lex(smart_ptr stream, @@ -157,7 +157,7 @@ namespace utakata { private: - smart_ptr str_; + smart_ptr str_; }; class BooleanLexer : public ISubLexer @@ -166,7 +166,7 @@ namespace utakata { // いずれかの次には、必ず区切り文字がなければならない。 public: - BooleanLexer(const utakata::utf8_string::UTF8Char& ch); + BooleanLexer(const utakata::unicode::UniChar& ch); virtual ~BooleanLexer(){} smart_ptr lex(smart_ptr stream, @@ -174,7 +174,7 @@ namespace utakata { private: - smart_ptr ch_; + smart_ptr ch_; }; class ByteVectorLexer : public ISubLexer @@ -183,7 +183,7 @@ namespace utakata { // vu8ではない場合には、エラーとなる。 public: - ByteVectorLexer(const utakata::utf8_string::UTF8Char& ch); + ByteVectorLexer(const utakata::unicode::UniChar& ch); virtual ~ByteVectorLexer(){} smart_ptr lex(smart_ptr stream, @@ -191,7 +191,7 @@ namespace utakata { private: - smart_ptr ch_; + smart_ptr ch_; }; }; diff --git a/test/Makefile.am b/test/Makefile.am index 79389a9..4eed2a6 100755 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -3,24 +3,24 @@ AM_CPPFLAGS = -Wall -fno-default-inline INCLUDES = -I$(top_srcdir) SRC_DIR=/home/derui/develop/utakata -bin_PROGRAMS = utf8_test textarrayformat_test utf8_string_test lexer_test sublexer_test \ +bin_PROGRAMS = utf8_transcoder_test textarrayformat_test unicode_test lexer_test sublexer_test \ syntax_tree_test parser_test environment_test type_test -utf8_string_test_SOURCES = utf8_string_test.cpp ${SRC_DIR}/utf8_string.cpp ${SRC_DIR}/simpletest.cpp ${SRC_DIR}/utf8.cpp -utf8_test_SOURCES = utf8_test.cpp ${SRC_DIR}/utf8.cpp ${SRC_DIR}/simpletest.cpp +unicode_test_SOURCES = unicode_test.cpp ${SRC_DIR}/unicode.cpp ${SRC_DIR}/simpletest.cpp ${SRC_DIR}/utf8_transcoder.cpp +utf8_transcoder_test_SOURCES = utf8_transcoder_test.cpp ${SRC_DIR}/utf8_transcoder.cpp ${SRC_DIR}/simpletest.cpp textarrayformat_test_SOURCES = textarrayformat_test.cpp ${SRC_DIR}/textarrayformat.cpp ${SRC_DIR}/simpletest.cpp -lexer_test_SOURCES = ${SRC_DIR}/lexeme_id.h lexer_test.cpp ${SRC_DIR}/utf8_string.cpp ${SRC_DIR}/simpletest.cpp ${SRC_DIR}/utf8.cpp ${SRC_DIR}/textarrayformat.cpp ${SRC_DIR}/lexeme_impl.cpp \ +lexer_test_SOURCES = ${SRC_DIR}/lexeme_id.h lexer_test.cpp ${SRC_DIR}/unicode.cpp ${SRC_DIR}/simpletest.cpp ${SRC_DIR}/utf8_transcoder.cpp ${SRC_DIR}/textarrayformat.cpp ${SRC_DIR}/lexeme_impl.cpp \ ${SRC_DIR}/delimiter.cpp ${SRC_DIR}/sublexer_impl.cpp ${SRC_DIR}/lexer.cpp ${SRC_DIR}/literal_data.cpp -sublexer_test_SOURCES = sublexer_test.cpp ${SRC_DIR}/sublexer_impl.cpp ${SRC_DIR}/simpletest.cpp ${SRC_DIR}/utf8_string.cpp ${SRC_DIR}/utf8.cpp \ +sublexer_test_SOURCES = sublexer_test.cpp ${SRC_DIR}/sublexer_impl.cpp ${SRC_DIR}/simpletest.cpp ${SRC_DIR}/unicode.cpp ${SRC_DIR}/utf8_transcoder.cpp \ ${SRC_DIR}/lexeme_impl.cpp ${SRC_DIR}/delimiter.cpp ${SRC_DIR}/literal_data.cpp -parser_test_SOURCES = parser_test.cpp ${SRC_DIR}/sublexer_impl.cpp ${SRC_DIR}/simpletest.cpp ${SRC_DIR}/utf8.cpp ${SRC_DIR}/utf8_string.cpp \ +parser_test_SOURCES = parser_test.cpp ${SRC_DIR}/sublexer_impl.cpp ${SRC_DIR}/simpletest.cpp ${SRC_DIR}/utf8_transcoder.cpp ${SRC_DIR}/unicode.cpp \ ${SRC_DIR}/lexeme_impl.cpp ${SRC_DIR}/parser.cpp ${SRC_DIR}/delimiter.cpp ${SRC_DIR}/textarrayformat.cpp ${SRC_DIR}/lexer.cpp ${SRC_DIR}/literal_data.cpp \ ${SRC_DIR}/literal.cpp ${SRC_DIR}/literal_impl.cpp ${SRC_DIR}/tree.cpp ${SRC_DIR}/parser_handler.cpp -syntax_tree_test_SOURCES = ${SRC_DIR}/lexeme_id.h ${SRC_DIR}/utf8_string.cpp ${SRC_DIR}/simpletest.cpp ${SRC_DIR}/utf8.cpp ${SRC_DIR}/textarrayformat.cpp ${SRC_DIR}/lexeme_impl.cpp \ +syntax_tree_test_SOURCES = ${SRC_DIR}/lexeme_id.h ${SRC_DIR}/unicode.cpp ${SRC_DIR}/simpletest.cpp ${SRC_DIR}/utf8_transcoder.cpp ${SRC_DIR}/textarrayformat.cpp ${SRC_DIR}/lexeme_impl.cpp \ ${SRC_DIR}/delimiter.cpp ${SRC_DIR}/sublexer_impl.cpp ${SRC_DIR}/lexer.cpp ${SRC_DIR}/literal_data.cpp ${SRC_DIR}/tree.cpp \ ${SRC_DIR}/literal.cpp ${SRC_DIR}/literal_impl.cpp syntax_tree_test.cpp environment_test_SOURCES = ${SRC_DIR}/environment.cpp environment_test.cpp ${SRC_DIR}/simpletest.cpp \ - ${SRC_DIR}/utf8_string.cpp ${SRC_DIR}/utf8.cpp ${SRC_DIR}/object.cpp ${SRC_DIR}/type.cpp ${SRC_DIR}/data_structure.cpp + ${SRC_DIR}/unicode.cpp ${SRC_DIR}/utf8_transcoder.cpp ${SRC_DIR}/object.cpp ${SRC_DIR}/type.cpp ${SRC_DIR}/data_structure.cpp type_test_SOURCES = ${SRC_DIR}/type.cpp type_test.cpp ${SRC_DIR}/simpletest.cpp check_PROGRANS = $(bin_PROGRAMS) diff --git a/test/cons_test.cpp b/test/cons_test.cpp index 092231f..81d14bd 100755 --- a/test/cons_test.cpp +++ b/test/cons_test.cpp @@ -7,7 +7,7 @@ #include "../textarrayformat.h" #include "../lexeme_id.h" -#include "../utf8_string.h" +#include "../unicode.h" #include "../cons.h" #include "../object.h" @@ -20,8 +20,8 @@ public: Stub() {} virtual ~Stub() {} bool enableChange() const {return false;} - smart_ptr toValue() { - smart_ptr s(new utf8_string::UTF8String); + smart_ptr toValue() { + smart_ptr s(new unicode::UniString); *s += "hoge"; return s; } diff --git a/test/environment_test.cpp b/test/environment_test.cpp index 8a37088..f6a8838 100755 --- a/test/environment_test.cpp +++ b/test/environment_test.cpp @@ -12,7 +12,7 @@ #include "../type.h" #include "../utf8.h" -#include "../utf8_string.h" +#include "../unicode.h" using namespace std; @@ -21,13 +21,13 @@ using namespace utakata; class String : public interpreter::DataEntity { public: - String(std::string str) : str_(new utf8_string::UTF8String(utf8_string::convert(str))) + String(std::string str) : str_(new unicode::UniString(unicode::convert(str))) {} virtual ~String() {} virtual unsigned char* getAddress() {return reinterpret_cast(&(*str_));} - smart_ptr str_; + smart_ptr str_; }; bool environment_test(smart_ptr asserter) @@ -55,7 +55,7 @@ bool environment_test(smart_ptr asserter) env.append("name", o); // 実際にはの部分はDataCastingHelperで処理が隠蔽される。 - utf8_string::UTF8String* tmp = reinterpret_cast( + unicode::UniString* tmp = reinterpret_cast( env["name"]->getSpace()->getTypeDescripter().getEntity()->getAddress()); asserter->check(tmp->toStr(), "hoge"); diff --git a/test/sublexer_test.cpp b/test/sublexer_test.cpp old mode 100644 new mode 100755 index ddeb3dd..6e842ee --- a/test/sublexer_test.cpp +++ b/test/sublexer_test.cpp @@ -13,8 +13,8 @@ int main(int argc, char *argv[]) { simpletest::SimpleTestSuite suite("sublexer's test"); // suite.addTester(sfcr::screate(utf8_multichar_test, suite.getAsserter())); -// suite.addTester(sfcr::screate(utf8_string_test, suite.getAsserter())); -// suite.addTester(sfcr::screate(utf8_string_util_test, suite.getAsserter())); +// suite.addTester(sfcr::screate(unicode_test, suite.getAsserter())); +// suite.addTester(sfcr::screate(unicode_util_test, suite.getAsserter())); suite.run(); return 0; } diff --git a/test/utf8_string_test.cpp b/test/unicode_test.cpp old mode 100644 new mode 100755 similarity index 68% rename from test/utf8_string_test.cpp rename to test/unicode_test.cpp index 8bc4843..bf9d02f --- a/test/utf8_string_test.cpp +++ b/test/unicode_test.cpp @@ -9,7 +9,7 @@ #include "../utf8.h" -#include "../utf8_string.h" +#include "../unicode.h" #include "../textarrayformat.h" bool utf8_multichar_test(smart_ptr asserter) @@ -23,21 +23,21 @@ bool utf8_multichar_test(smart_ptr asserter) utakata::utf8::UTF8InputStream stream(ss); // 単独のreadを試す。 - utakata::utf8_string::UTF8Char ch(stream.read()); + utakata::unicode::UniChar ch(stream.read()); asserter->check(ch.toUTF16Code(), utakata::utf8::generateUTF8Code("あ")); // peekが問題なく働いていることのテスト - utakata::utf8_string::UTF8Char ch2(stream.peek()); + utakata::unicode::UniChar ch2(stream.peek()); asserter->check(ch2.toUTF16Code(), utakata::utf8::generateUTF8Code("い")); - utakata::utf8_string::UTF8Char ch3(stream.read()); + utakata::unicode::UniChar ch3(stream.read()); asserter->check(ch3.toUTF16Code(), utakata::utf8::generateUTF8Code("い")); // asciiだとしても問題無く読みだせるはず。 - utakata::utf8_string::UTF8Char ch4(stream.peek()); + utakata::unicode::UniChar ch4(stream.peek()); asserter->check(ch4.toUTF16Code(), 'u'); // ascii文字の範囲であるかどうかを判定する関数のテスト。 - asserter->check(utakata::utf8_string::is_ascii_char(ch4), true); - asserter->check(utakata::utf8_string::is_ascii_char(ch), false); + asserter->check(utakata::unicode::is_ascii_char(ch4), true); + asserter->check(utakata::unicode::is_ascii_char(ch), false); // 同一コードなので比較して同じになるはず。 asserter->check(ch == ch2, false, "chとch2が異なる"); @@ -49,17 +49,17 @@ bool utf8_multichar_test(smart_ptr asserter) return asserter->isOk(); } -bool utf8_string_test(smart_ptr asserter) +bool unicode_test(smart_ptr asserter) { // マルチバイトとascii文字の混在文字も正しく扱うことのできる - // CUTF8Stringのテスト + // CUniStringのテスト std::string tmp("あいうえsssお("); smart_ptr ss(new std::stringstream(tmp)); utakata::utf8::UTF8InputStream stream(ss); - utakata::utf8_string::UTF8String str(stream.read(5)); + utakata::unicode::UniString str(stream.read(5)); asserter->check(str.begin()->toStr(), "あ"); asserter->check(str.size(), 5); @@ -68,15 +68,15 @@ bool utf8_string_test(smart_ptr asserter) asserter->check(str[5].toStr(), "あ"); // 本当に基本的なもの以外は、同一の名前空間内に関数が用意されている。 - // utf8_stringから返されるのは、UTF8のバイト列を設定した文字列であると + // unicodeから返されるのは、UTF8のバイト列を設定した文字列であると // する。 - asserter->check(utakata::utf8_string::substring(str,0,2).toStr(), "あい"); - asserter->check(utakata::utf8_string::substring(str,1,2).toStr(), "いう"); - asserter->check(utakata::utf8_string::substring(str, 2).toStr(), "うえsあいうえs"); + asserter->check(utakata::unicode::substring(str,0,2).toStr(), "あい"); + asserter->check(utakata::unicode::substring(str,1,2).toStr(), "いう"); + asserter->check(utakata::unicode::substring(str, 2).toStr(), "うえsあいうえs"); { ss->seekg(0, std::ios::beg); - utakata::utf8_string::UTF8String str(stream.read(9)); + utakata::unicode::UniString str(stream.read(9)); str += std::string("("); asserter->check(str.toStr(), "あいうえsssお(("); } @@ -86,9 +86,9 @@ bool utf8_string_test(smart_ptr asserter) return asserter->isOk(); } -bool utf8_string_util_test(smart_ptr asserter) +bool unicode_util_test(smart_ptr asserter) { - // CUTF8Stringと共に利用するためのユーティリティ関数の操作を + // CUniStringと共に利用するためのユーティリティ関数の操作を // 行う。 std::string tmp("あいうえsssお"); @@ -96,9 +96,9 @@ bool utf8_string_util_test(smart_ptr asserter) smart_ptr ss(new std::stringstream(tmp)); utakata::utf8::UTF8InputStream stream(ss); - utakata::utf8_string::UTF8String str(stream.read(5)); - utakata::utf8_string::UTF8String str2(stream.read(3)); - utakata::utf8_string::UTF8String str3 = str; + utakata::unicode::UniString str(stream.read(5)); + utakata::unicode::UniString str2(stream.read(3)); + utakata::unicode::UniString str3 = str; // 挿入してみる。 str.insert(str.begin(), str2.begin(), str2.end()); @@ -118,8 +118,8 @@ int main(int argc, char *argv[]) { simpletest::SimpleTestSuite suite("UTF-8 文字列テスト"); suite.addTester(sfcr::screate(utf8_multichar_test, suite.getAsserter())); - suite.addTester(sfcr::screate(utf8_string_test, suite.getAsserter())); - suite.addTester(sfcr::screate(utf8_string_util_test, suite.getAsserter())); + suite.addTester(sfcr::screate(unicode_test, suite.getAsserter())); + suite.addTester(sfcr::screate(unicode_util_test, suite.getAsserter())); suite.run(); return 0; } diff --git a/test/utf8_test.cpp b/test/utf8_transcoder_test.cpp similarity index 100% rename from test/utf8_test.cpp rename to test/utf8_transcoder_test.cpp diff --git a/transcoder.h b/transcoder.h new file mode 100755 index 0000000..5f78bba --- /dev/null +++ b/transcoder.h @@ -0,0 +1,30 @@ +#ifndef _TRANSCODER_H_ +#define _TRANSCODER_H_ + +namespace utakata { + + namespace port { + class IInputPort; + }; + + namespace transcoder { + + class ITranscoder + { + // 入力されたバイト列を、それぞれの判定によってUniCharに + // 変換する。 + // このインターフェースは入力値を変換するためだけのものであり、 + // schemeのtranscoderとは多少機能が異なる。 + // これはlexerのインターフェースで利用される。 + public: + ITranscoder() {} + virtual ~ITranscoder() {} + + // 渡されたInputPortから一文字分だけ読み出して、unicode値を返す。 + virtual unsigned long transcode(port::IInputPort& bytes) = 0; + }; + }; + +}; + +#endif /* _TRANSCODER_H_ */ diff --git a/tree.cpp b/tree.cpp index 1ba0e6b..fd877fa 100755 --- a/tree.cpp +++ b/tree.cpp @@ -6,14 +6,14 @@ #include "tree.h" #include -#include "utf8_string.h" +#include "unicode.h" #include "literal_data.h" #include "literal.h" #include "datum_id.h" using namespace utakata; using namespace utakata::literal; -using namespace utakata::utf8_string; +using namespace utakata::unicode; using namespace utakata::syntax; // 原則としてそれぞれ単純に呼びだされるのみ。 diff --git a/tree.h b/tree.h index ce2263a..4b1e0dd 100755 --- a/tree.h +++ b/tree.h @@ -7,9 +7,9 @@ namespace utakata { - namespace utf8_string { + namespace unicode { - class UTF8String; + class UniString; }; @@ -125,7 +125,7 @@ namespace utakata { std::pair > makeAbbreviation (smart_ptr l); // 渡したtreeの内容を文字列に変換する。 -// smart_ptr treeToValue(Tree& t); +// smart_ptr treeToValue(Tree& t); }; }; diff --git a/unicode.cpp b/unicode.cpp new file mode 100755 index 0000000..0088d0b --- /dev/null +++ b/unicode.cpp @@ -0,0 +1,242 @@ +#include +#include +#include +#include + +#include "unicode.h" + +using namespace utakata::unicode; + +//================================================================================ + +unicode::UniChar::UniChar() : code_(0) +{ +} + +unicode::UniChar::UniChar(const unicode::UniChar& ch) +{ + // 単純にそれぞれの値をコピーする。 + code_ = ch.code_; +} + +unicode::UniChar& unicode::UniChar::operator=(unicode::unicode_t ch) : + code_(ch) +{ + // 安全なスワップを利用する。 + +} + +unicode::UniChar& unicode::UniChar::operator=(const unicode::UniChar& ch) +{ + // 安全なスワップを利用する。 + UniChar c(ch); + swap(c); + return *this; +} + +unicode::UniChar& unicode::UniChar::operator=(unicode::unicode_t ch) +{ + code_ = ch; + return *this; +} + +bool unicode::UniChar::operator==(const unicode::UniChar& ch) const +{ + return ch.code_ == code_; +} + +bool unicode::UniChar::operator!=(const unicode::UniChar& ch) const +{ + return !(*this == ch); +} + +bool UniChar::operator<(const UniChar& ch) const +{ + return code_ < ch.code_; +} + +bool UniChar::operator>(const UniChar& ch) const +{ + return code_ > ch.code_; +} + +bool unicode::UniChar::operator==(unicode::unicode_t ch) const +{ + return ch == code_; +} + +bool unicode::UniChar::operator!=(unicode::unicode_t ch) const +{ + return !(*this == ch); +} + +bool UniChar::operator<(unicode_t ch) const +{ + return code_ < ch; +} + +bool UniChar::operator>(unicode_t ch) const +{ + return code_ > ch; +} + +void unicode::UniChar::swap(unicode::UniChar& ch) +{ + // 値と標準コンテナなので、特に問題なく動作する。 + std::swap(code_, ch.code_); +} + +bool unicode::is_ascii(const UniChar& ch) +{ + // 0x7f >= ascii >= 0x00 がasciiなので、その範囲で判定を行う。 + return ch >= 0 && ch <= 0x7f ? true : false; +} + +bool unicode::is_numeric(const UniChar& ch) +{ + return '0' <= ch && ch <= '9' ? true : false; +} + +bool unicode::is_alpha(const UniChar& ch) +{ + // 通常のアルファベットであるかどうかを判別する。 + // 大文字、小文字は問わない。 + if (('a' <= ch.getRawCode() && ch.getRawCode() <= 'z') || + ('A' <= ch.getRawCode() && ch.getRawCode() <= 'Z')) + { + return true; + } + return false; +} + +//================================================================================ + +unicode::UniString::UniString() : chars_() +{ +} + +unicode::UniString::UniString(const UniChar& ch, int num) : chars_() +{ + chars_.assign(ch, num); +} + +unicode::UniString::UniString( + const UniString& str) : chars_(str.chars_) +{ +} + +void UniString::assign(const unicode::UniChar& ch, int num) +{ + UniString tmp(ch, num); + swap(tmp); +} + +void UniString::assign(const UniString& str) +{ + //基本的に=で渡した場合と全く同じなので、そのようにする。 + UniString tmp(str); + swap(tmp); +} + +UniString& UniString::operator=(const UniString& str) +{ + assign(str); + return *this; +} + +void UniString::swap(UniString& str) +{ + // シンプルにswapを行う。 + std::swap(chars_, str.chars_); +} + +UniString& UniString::operator+=(const UniString& str) +{ + // 一度コピーと加算してから実際にswapさせる。 + UniString tmp(str); + chars_.insert(chars_.end(), tmp.chars_.begin(), tmp.chars_.end()); + return *this; +} + +UniString& UniString::operator+=(const std::vector& ch) +{ + // 実際には文字を設定するのに利用される。 + // また、これを定義しておくことで、streamからの結果を直接設定することができる。 + UniString tmp(ch); + chars_.insert(chars_.end(), tmp.chars_.begin(), tmp.chars_.end()); + return *this; +} + +UniString& UniString::operator+=(const UniChar& ch) +{ + // 実際には文字を設定するのに利用される。 + // また、これを定義しておくことで、streamからの結果を直接設定することができる。 + UniString tmp(*this); + tmp.push_back(ch); + swap(tmp); + return *this; +} + +void UniString::insert(UniString::iterator it, UniString::iterator begin, + UniString::iterator last) +{ + // 渡されたのは実際にはvectorのイテレータなので、 + // そのままvectorの実装に任せることができる。 + chars_.insert(it, begin, last); +} + +void UniString::insert(UniString::iterator it, + UniString::const_iterator begin, + UniString::const_iterator last) +{ + // 渡されたのがconstであるかどうかというだけの違いであるため、 + // そのまま渡すことができる。 + chars_.insert(it, begin, last); +} + +//================================================================================ + +unicode::UniString unicode::substring( + const unicode::UniString& str, size_t begin, size_t end) +{ + if (end == 0) + { + // 先頭から末尾までを取得する。 + UniString s; + s.insert(s.begin(), str.begin() + begin, str.end()); + return s; + } + else if (begin <= end) + { + UniString s; + s.insert(s.begin(), str.begin() + begin, str.begin() + (begin + end)); + return s; + } + else + { + throw range_error("out of range in unicode::substring"); + } +} + +UniString unicode::operator+(const UniString& lh, const UniString& rh) +{ + // 双方をコピーして加算して返す。凄い負荷が高い。 + UniString str(lh); + str += rh; + return str; +} + +UniString unicode::operator+(const UniString& lh, const UniChar& rh) +{ + // 文字と加算する。 + UniString tmp(lh); + tmp += rh.getBytes(); + return tmp; +} + +UniString unicode::operator+(const UniChar& lh, const UniString& rh) +{ + UniString tmp(lh.getBytes()); + tmp += rh; + return tmp; +} diff --git a/unicode.h b/unicode.h new file mode 100755 index 0000000..f28f719 --- /dev/null +++ b/unicode.h @@ -0,0 +1,168 @@ +#ifndef _UNICODE_H_ +#define _UNICODE_H_ + +#include +#include +#include +#include + +namespace utakata { + +// CUniCharの作成と、CUniCharのコンテナであるCUniStringを定義する。 + + // 内部で利用されるunicodeスカラー値の型。 + typedef unsigned long unicode_t; + + class range_error : public std::exception + { + public: + range_error(const std::string& str) : str_(str) {} + virtual ~range_error() throw() {} + + const char* what() throw() { + return str_.c_str(); + } + private: + + std::string str_; + }; + + class UniChar + { + // schemeにおけるunicodeスカラー値一つ分を表す。 + // スカラー値はunsigned longで保持され、基本的には構造体のように + // 振る舞う。 + public: + + // デフォルトではnul(0x0000)が指定される。 + UniChar(); + virtual ~UniChar(){} + + // コピーコンストラクタを宣言したため、同時にoperator=を宣言する。 + UniChar(const UniChar& ch); + UniChar(unicode_t code); + UniChar& operator=(const UniChar& ch); + UniChar& operator=(unicode_t ch); + + // 各演算子のオーバーロード。 + // <=と>=は、それぞれ>の結果のnot、<の結果のnotを + // 用いることで実装できるため、この二つだけ供えていれば問題ない。 + bool operator==(const UniChar& code) const; + bool operator<(const UniChar& code) const; + bool operator>(const UniChar& code) const; + bool operator!=(const UniChar& code) const; + + bool operator!=(unicode_t code) const; + bool operator==(unicode_t code) const; + bool operator<(unicode_t code) const; + bool operator>(unicode_t code) const; + + // 内部で保持しているコードを返す。 + unicode_t getRawCode() const {return this->code_;} + + private: + + // 渡されたUniCharの内部と交換する。 + void swap(UniChar& ch); + + unicode_t code_; + }; + + // 各unicode用変換用の関数群。 + + // 渡されたUniCharがasciiコードの範囲内に収まっているかどうかを返す。 + bool is_ascii(const UniChar& ch); + + // 渡されたUniCharが、それぞれ数値、アルファベットであるかどうか + // を返す。これらはutf8モジュールのユーティリティ関数によって実装される。 + bool is_numeric(const UniChar& ch); + bool is_alpha(const UniChar& ch); + + //================================================================================ + + class UniString + { + // UniCharを複数連結して保持するためのコンテナ + // 相互での比較などもサポートし、utakataの内部全般で + // 標準として使用することが可能なものとし、かつ標準コンテナと + // ほぼ同様の処理を行うことができるように定義されている。 + // というか内部では単純なvectorで定義されているため、 + // typedefされた型を指定するだけで、イテレータとして利用可能。 + + public: + + // イテレータとして簡単に利用するためのtypedefマクロ + typedef std::vector::iterator iterator; + typedef std::vector::const_iterator const_iterator; + + public: + + UniString(); + // 第一引数のchをnum個数分設定する。 + UniString(const UniChar& ch, int num); + UniString(const UniString& str); + virtual ~UniString(){} + + // 実体に代入する。代入が行われなかった場合、元のデータ + // は保存される。 + void assign(const UniChar& ch, int num); + void assign(const UniString& str); + + // iteratorを取得する。 + const_iterator begin() const {return chars_.begin();} + iterator begin() {return chars_.begin();} + + // 末尾のイテレータを取得する。 + const_iterator end() const {return chars_.end();} + iterator end() {return chars_.end();} + + // []をオーバーロードする。これは常に境界のチェックを行う。 + const UniChar& operator[](size_t t) const {return chars_.at(t);} + UniChar& operator[](size_t t) { + return const_cast( + static_cast(this)->chars_[t]);} + + // サイズを取得する。 + size_t size() const {return chars_.size();} + // 空かどうかを調べる。 + bool empty() const {return chars_.empty();} + + // 安全なswapと共に提供する。 + UniString& operator=(const UniString& str); + + // 加算のみをサポートする。 + UniString& operator+=(const UniString& str); + UniString& operator+=(const std::vector& ch); + UniString& operator+=(const UniChar& ch); + UniString& operator+=(const std::string& str); + + // 渡したイテレータの範囲を追加する + // beginとlastは同一のUniStringから取得されたものであること。 + void insert(iterator it, iterator begin, iterator last); + void insert(iterator it, const_iterator begin, + const_iterator last); + + // UniCharを単体で末尾に追加する。 + void push_back(const UniChar& ch); + + private: + + void swap(UniString& str); + + std::vector chars_; + }; + + UniString operator+(const UniString& lh, const UniString& rh); + UniString operator+(const UniString& lh, const UniChar& rh); + UniString operator+(const UniChar& lh, const UniString& rh); + + // substringの実装を行う。 + // [begin, end)までの文字を文字列として返す。 + // endが渡されないか、0が渡された場合、beginから末尾までが返される。 + UniString substring(const UniString& str, size_t begin, size_t end = 0); + + }; + +}; + +#endif /* _UNICODE_H_ */ diff --git a/utf8.cpp b/utf8.cpp deleted file mode 100755 index eeb42f6..0000000 --- a/utf8.cpp +++ /dev/null @@ -1,379 +0,0 @@ -#include -#include -#include -#include -#include -#include - -#include "InputStream.h" -#include "utf8.h" -#include "smart_ptr.h" - -using namespace std;; -using namespace utakata::utf8; - -UTF8InputStream::UTF8InputStream() : EOF_(0xff), strm_(), pos_(0) -{ -} - -UTF8InputStream::UTF8InputStream(smart_ptr strm) : EOF_(0xff), strm_(strm), - pos_(0) -{ -} - -bool UTF8InputStream::open(smart_ptr strm) -{ - //現在保持しているストリームと切り替える。 - // 基本的にただスワップするだけで問題ない。 - - // NULLポインタではなく、問題無く開かれている場合には、次のようにして開始する。 - if (strm.isNull() != false && !strm->good()) { - strm_ = strm; - } else { - return false; - } - return true; -} - -std::vector UTF8InputStream::read() -{ - // UTF-8の一文字を読みだして返す。 - // UTF-8に該当しない場合、空のvectorを返す。 - if (!strm_->eof() && !strm_->good()) { - throw StreamException("not ready input stream"); - } - - // 最初に一文字だけ読みだして、チェックをかける。 - int c = 0; - c = strm_->peek(); - if (c != std::istream::traits_type::eof()) - { - // 末尾でない場合のみ、以降のチェックに入る。 - size_t size = 0; - // 先頭1バイトが正常でなかった場合はそのまま抜ける - if (is_utf8_first_byte(static_cast(c), size)) - { - if (size > 0) - { - // sizeが0より大きい場合には、この時複数バイトで文字が構成 - // されていると考えられるため、明示的に複数文字を取得する。 - std::vector tmp(size, 0); - strm_->read(&tmp[0], size); - - if (strm_->bad()) - { - // 読み取りきれなかった場合には、ストリームに一応読出せた - // 分を元に戻す。 - std::for_each(tmp.rbegin(), tmp.rend(), PutBack(strm_)); - return std::vector(1, 0); - } - std::vector rtn; - rtn.insert(rtn.begin(), tmp.begin(), tmp.end()); - - // 読みこめたので、++する。 - ++pos_; - return rtn; - } - } - } - - return std::vector(1, EOF_); -} - -std::vector UTF8InputStream::read(int num) -{ - // 指定された文字分だけ読みだしてくる。 - // 途中で終了した場合、その文字の分だけunsigned charが減少すること - // になっている。 - // numが0の場合、必ず空のvectorが返される。 - - if (num == 0) - { - return std::vector(); - } - - // eofの場合なら、この時点でeofが返るので、それで問題はない。 - std::vector rtn = this->read(); - for (int i = 1; i < num && !strm_->eof(); ++i) - { - // 個数に到達するか、もしくはeofとなるまでは追加しつづける。 - std::vector tmp = this->read(); - rtn.insert(rtn.end(), tmp.begin(), tmp.end()); - } - - pos_ += num; - - return rtn; -} - -std::vector UTF8InputStream::peek() -{ - // 一文字分だけ先読みする。先読みした場合、文字は戻す。 - std::vector tmp = this->read(); - // 一応戻すサイズが存在する場合だけ、これを実行させることにする。 - if (tmp.size() > 0) - { - // 複雑な繰り返しを表現する場合には、積極的にalgorithmを利用するようにする。 - - std::for_each(tmp.rbegin(), tmp.rend(), - utakata::utf8::PutBack(strm_)); - --pos_; - } - return tmp; -} - -void UTF8InputStream::unget(const std::vector& ch) -{ - // 渡されたバイト列をストリームに差し戻す。 - size_t t = 0; - if (is_utf8_one(ch, t)) - { - std::for_each(ch.rbegin(), ch.rend(), PutBack(strm_)); - } - - if (pos_ > 0) - { - --pos_; - } -} - -bool utakata::utf8::UTF8InputStream::isEOF() const -{ - bool ret = false; - if (strm_->good()) - { - ret = strm_->eof() ? true : false; - } - else - { - ret = true; - } - - return ret; -} - -//================================================================================ - -long utakata::utf8::generateUTF8Code(const std::vector& bytes) -{ - // 1文字分のUTF8のバイト列を受け取って、コードに変換して返す。 - // 先頭の値によって、次のように値を決定することができる。 - // x = utf8の先頭バイト - // y1〜yN = utf8の先頭バイト以降のバイト - // N = utf8の先頭バイトを含むバイト数 - // code = (y1 & ((1 << 7) - 1)) << (6 * n-1) + (y2 & ((1 << 7) -1)) << (6 * (n - 1))...+ x & ((1 << N) -1) << (6 * N-1) - // 先頭バイト以外は、全て先頭に10とうビットが設定されている。このビットを除いた6ビットをする。 - // つまり、末尾のバイトから順次やっていけばよい。 - - std::vector tmp(bytes); - const unsigned char max_c = (1 << (sizeof(unsigned char) * 8 - 1)) - 1; - long code = 0; - - if (tmp.empty()) - { - return 0; - } - - if (tmp.size() == 1) - { - // asciiコードは7bitなのでそこだけ切り取って返す。 - code = tmp[0] & max_c; - } - else - { - // 一時的に利用されるクラス。 - struct Lambda - { - unsigned char operator()(unsigned char c, int s) { - return c << (6 * s); - } - }; - - // サイズが1以外の場合、ここからがちと違う。 - std::vector::reverse_iterator beg = tmp.rbegin(), - end = tmp.rend() - 1; - const unsigned char char_bit = (1 << 6) - 1; - for (int i = 0; beg != end; ++i,++beg) - { - code += Lambda()((*beg & char_bit), i); - } - - // 最後だけ、別の計算が必要になる。 - const unsigned char first_byte = (1 << ((sizeof(unsigned char) + 1) - tmp.size())) - 1; - code += Lambda()(first_byte,tmp.size() - 1); - - } - - return code; -} - - -long utakata::utf8::generateUTF8Code(const std::string& bytes) -{ - // UTF8である一文字のstringを受け取って、先頭1文字の値を返す。 - - std::string str = bytes; - std::vector tmp; - tmp.insert(tmp.end(), str.begin(), str.end()); - - // vectorにしなおしたら後は元々の関数に任せる。 - return generateUTF8Code(tmp); -} - -bool utakata::utf8::is_utf8_one(const std::vector& bytes, size_t& size) -{ - //渡したバイト列がUTF8の一文字に該当するかどうかを返す。 - size_t back = size; - - if (bytes.size() == 0) - { - size = back; - return false; - } - - size_t num = 0; - - if (!is_utf8_first_byte(bytes[0], num)) - { - size = back; - return false; - } - - // そもそもbytesのサイズが足りない場合にも失敗とする。 - if (num > bytes.size()) - { - size = back; - return false; - } - - // 先頭要素以外が正しければそれで問題ないとする。 - if (num > 1) - { - - const CheckUTF8Byte& checker = for_each(bytes.begin() + 1, bytes.begin() + num, - CheckUTF8Byte()); - - if (checker.good) - { - size = num; - } else { - size = back; - return false; - } - } else { - // sizeが0の場合には、この時点で1を設定するようにする。 - size = num; - } - - // 最後まで到達した時点で成功とする。 - return true; -} - -bool utakata::utf8::is_utf8_all(const std::vector& bytes) -{ - // 与えられたバイト列全てがUTF-8であるかどうかを返す。 - size_t size = 0; - std::vector::const_iterator it = bytes.begin(); - while (is_utf8_one(std::vector(it, bytes.end()), size)) { - it += size; - size = 0; - } - - if (it == bytes.end()) { - return true; - } - - return false; -} - -bool utakata::utf8::is_utf8_first_byte(unsigned char c, size_t& size) -{ - // UTf-8の先頭バイトであるかどうかを返す。 - // 先頭バイトである場合には、その先頭バイトを含む、一文字のサイズを返す。 - // 先頭バイトではない場合には、 - const unsigned char max_c = 1 << (sizeof(unsigned char) * 8 - 1); - - size_t back = size; - - // 最上位ビットが0である場合、これはasciiコードを指す。 - if (!(c & max_c)) - { - size = 1; - return true; - } - - unsigned char first = c << 1; - size_t num = 1; - while (first & max_c) { - first <<= 1; - num += 1; - } - - // ここまできたとき、最上位ビットは0であるはず。 - // numが5未満である場合、とりあえず正常としておくこととする。 - const unsigned char max_utf8_sequence = 5; - if (num < max_utf8_sequence) { - size = num; - return true; - } - else if (num == 1) - { - // numが1の場合、何らかの理由で先頭が欠落したと見られる。 - // この場合、スキップするべきバイト数を返す。 - size = 1; - return false; - - } else { - size = back; - return false; - } -} - - -bool utakata::utf8::is_utf8_ascii(const std::vector& bytes) -{ - // 一文字かつ、0x00〜0x7fの範囲であるデータであることが条件となる。 - size_t s = 0; - bool b = is_utf8_one(bytes, s); - - if (b && s == 1) - { - return true; - } - return false; -} - -bool utakata::utf8::is_utf8_numeric(const std::vector& bytes) -{ - // 一文字分だけが渡されていると判断する。 - if (!is_utf8_ascii(bytes)) - { - return false; - } - - if (bytes[0] >= '0' && bytes[0] <= '9') - { - return true; - } - - return false; -} - -bool utakata::utf8::is_utf8_alpha(const std::vector& bytes) -{ - // 同じく一文字であると判別する。 - // asciiのサブセットなので、先にasciiであると判別しておく。 - if (!is_utf8_ascii(bytes)) - { - return false; - } - - if ((bytes[0] >= 'a' && bytes[0] <= 'z') || - (bytes[0] >= 'A' && bytes[0] <= 'Z')) - - { - return true; - } - - return false; -} diff --git a/utf8.h b/utf8.h deleted file mode 100755 index 6c8b44c..0000000 --- a/utf8.h +++ /dev/null @@ -1,135 +0,0 @@ -#ifndef _UTF8_H_ -#define _UTF8_H_ - -#include -#include -#include -#include - -#include "smart_ptr.h" -#include "InputStream.h" - -namespace utakata { - - namespace utf8 { - - // inputstreamの準備が出来ていない場合に送出される例外 - class StreamException : public std::exception - { - public: - StreamException(const std::string& str) : str_(str) {} - virtual ~StreamException() throw() {} - - const char* what() throw() { - return str_.c_str(); - } - private: - - std::string str_; - }; - - class UTF8InputStream : public IInputStream - { - /** - 入力ストリームから、UTF-8のデータを指定した文字だけ読みだして - 返す。 - */ - - const unsigned char EOF_; - - public: - - // 入力に利用するストリームは最初に渡される。 - // 最初に渡さない場合には、後から開けるようにしておかなけりゃならない。 - UTF8InputStream(); - UTF8InputStream(smart_ptr strm); - virtual ~UTF8InputStream(){} - - bool open(smart_ptr strm); - - std::vector read(); - std::vector read(int num); - - std::vector peek(); - std::vector peek(int num); - - // 読み出した文字数を返す。 - size_t pos() const {return pos_;} - - // 渡したvectorをストリームに戻す。vectorは、readで取得した - // データの並びでなければならない。つまり、read()した - // データを戻す際に利用する。 - void unget(const std::vector& ch); - - // ファイルの終端に到達しているかどうかを返す。 - // trueを返す場合、readの結果は常にEOF文字を返す。 - bool isEOF() const; - - private: - - smart_ptr strm_; - size_t pos_; - }; - - - // UTF-8のコードを表すバイト列をUTF-8のコードに変換する。 - long generateUTF8Code(const std::vector& code); - long generateUTF8Code(const std::string& ch); - - struct CheckUTF8Byte - { - // UTF8の先頭バイト以外であるかどうかをチェックする。 - const unsigned char checker; - bool good; - CheckUTF8Byte() : checker(0x2), good(true) {} - - template - void operator()(const T& t) { - // 先頭ビットが10ではない場合、チェックに失敗する。 - T tmp = t >> 6; - if ( ((tmp & 0x3)) != checker) { - good = false; - } - } - }; - - struct PutBack - { - // 渡されたデータをistreamにputbackする。 - smart_ptr strm_; - PutBack(smart_ptr strm) : strm_(strm) {} - - template - void operator()(T t) - { - strm_->putback(t); - } - }; - - // 与えられたバイト列の先頭から、UTF8一文字に該当しているかどうかを返す。 - // バイト列がUTF8に該当する場合、そのバイト列のサイズを返す。 - bool is_utf8_one(const std::vector& bytes, size_t& size); - - // 与えられたバイト列全てが、UTF8に該当しているかどうかを返す。 - bool is_utf8_all(const std::vector& bytes); - - // UTF-8の先頭バイトとして正しいフォーマットであるかどうか。 - // 正しいフォーマットである場合、渡したバイトを含めた、一文字である - // バイト数を返す。 - bool is_utf8_first_byte(unsigned char c, size_t& size); - - // 渡したバイト列が、0-9で判別される数値文字と一致するかどうかを返す。 - // is_asciiのサブセットを判別するものである。 - bool is_utf8_numeric(const std::vector& bytes); - - // 渡したバイト列が、a-zA-Zの領域であるかどうかを調べる。 - // is_asciiのサブセットを判別するものである。 - bool is_utf8_alpha(const std::vector& bytes); - - // 渡したバイト列が、0x00〜0x7fの領域であるかどうかを返す。 - // is_utf8_alpha, is_utf8_numericのスーパーセットとなる。 - bool is_utf8_ascii(const std::vector& bytes); - }; -} - -#endif /* _UTF8_H_ */ diff --git a/utf8_string.cpp b/utf8_string.cpp deleted file mode 100644 index 512b3c1..0000000 --- a/utf8_string.cpp +++ /dev/null @@ -1,275 +0,0 @@ -#include -#include -#include -#include - -#include "utf8.h" -#include "utf8_string.h" - -using namespace utakata::utf8; -using namespace utakata::utf8_string; - -//================================================================================ - -utakata::utf8_string::UTF8Char::UTF8Char(const std::vector& utf8) : utf8_bytes_(utf8), utf16_code_(0) -{ - this->utf16_code_ = utakata::utf8::generateUTF8Code(utf8_bytes_); -} - -utakata::utf8_string::UTF8Char::UTF8Char(const utakata::utf8_string::UTF8Char& ch) -{ - // 単純にそれぞれの値をコピーする。 - this->utf8_bytes_ = ch.utf8_bytes_; - utf16_code_ = ch.utf16_code_; -} - -utakata::utf8_string::UTF8Char& utakata::utf8_string::UTF8Char::operator=(const utakata::utf8_string::UTF8Char& ch) -{ - // 安全なスワップを利用する。 - UTF8Char c(ch); - swap(c); - return *this; -} - -bool utakata::utf8_string::UTF8Char::operator==(const utakata::utf8_string::UTF8Char& ch) const -{ - // 全てのUTF8Charが保持しているUTF16変換が施された - // コードで比較を行う。実際にはlongでの比較なのでかなり速い。 - - return ch.utf16_code_ == utf16_code_; -} - -bool utakata::utf8_string::UTF8Char::operator!=(const utakata::utf8_string::UTF8Char& ch) const -{ - return !(*this == ch); -} - -bool UTF8Char::operator<(const UTF8Char& ch) const -{ - return utf16_code_ < ch.utf16_code_; -} - -bool UTF8Char::operator>(const UTF8Char& ch) const -{ - return utf16_code_ > ch.utf16_code_; -} - - -void utakata::utf8_string::UTF8Char::swap(utakata::utf8_string::UTF8Char& ch) -{ - // 値と標準コンテナなので、特に問題なく動作する。 - std::swap(utf16_code_, ch.utf16_code_); - std::swap(utf8_bytes_, ch.utf8_bytes_); -} - -std::string utakata::utf8_string::UTF8Char::toStr() const -{ - // 単純に置換が行える。 - std::string tmp; - tmp.insert(tmp.end(), utf8_bytes_.begin(), utf8_bytes_.end()); - return tmp; -} - -bool utakata::utf8_string::is_ascii_char(const UTF8Char& ch) -{ - // 0x7f >= ascii >= 0x00 がasciiなので、その範囲で判定を行う。 - return is_utf8_ascii(ch.getBytes()) ? true : false; -} - -bool utakata::utf8_string::is_numeric(const UTF8Char& ch) -{ - return is_utf8_numeric(ch.getBytes()) ? true : false; -} - -bool utakata::utf8_string::is_alpha(const UTF8Char& ch) -{ - return is_utf8_alpha(ch.getBytes()) ? true : false; -} - -bool utakata::utf8_string::is_eof(const UTF8Char& ch) -{ - return ch.getBytes()[0] == 0xff ? true : false; -} - -//================================================================================ - -utakata::utf8_string::UTF8String::UTF8String() : chars_() -{ -} - -utakata::utf8_string::UTF8String::UTF8String( - const std::vector& bytes) : chars_() -{ - assign(bytes); -} - -utakata::utf8_string::UTF8String::UTF8String( - const UTF8String& str) : chars_(str.chars_) -{ -} - -void UTF8String::assign(const std::vector& bytes) -{ - // 与えられたbytesを順次utf8charに変換していく。 - // 与えられたbytesのうち、有効なデータのみを変換していく。 - std::vector chars; - std::vector::const_iterator it = bytes.begin(), - end = bytes.end(); - - while (it != end) { - size_t i = 0; - if (utakata::utf8::is_utf8_one(std::vector(it, end), i)) - { - // 直接生成して渡す。 - chars.push_back(std::vector(it, it + i)); - } - // 判別に失敗した場合でも、スキップするべきバイト数は - // 渡されてくるため、とりあえず追加するだけでよい。 - it += i; - } - // 最後にswapするとよい。 - std::swap(chars_, chars); -} - -void UTF8String::assign(const UTF8String& str) -{ - //基本的に=で渡した場合と全く同じなので、そのようにする。 - UTF8String tmp(str); - swap(tmp); -} - -UTF8String& UTF8String::operator=(const UTF8String& str) -{ - assign(str); - return *this; -} - -void UTF8String::swap(UTF8String& str) -{ - // シンプルにswapを行う。 - std::swap(chars_, str.chars_); -} - -UTF8String& UTF8String::operator+=(const UTF8String& str) -{ - // 一度コピーと加算してから実際にswapさせる。 - UTF8String tmp(str); - chars_.insert(chars_.end(), tmp.chars_.begin(), tmp.chars_.end()); - return *this; -} - -UTF8String& UTF8String::operator+=(const std::vector& ch) -{ - // 実際には文字を設定するのに利用される。 - // また、これを定義しておくことで、streamからの結果を直接設定することができる。 - UTF8String tmp(ch); - chars_.insert(chars_.end(), tmp.chars_.begin(), tmp.chars_.end()); - return *this; -} - -UTF8String& UTF8String::operator+=(const std::string& str) -{ - // 実際には文字を設定するのに利用される。 - // また、これを定義しておくことで、streamからの結果を直接設定することができる。 - std::vector t; - std::string::const_iterator begin = str.begin(), end = str.end(); - for (; begin != end; ++begin) - { - t.push_back(*begin); - } - - UTF8String tmp(t); - chars_.insert(chars_.end(), tmp.chars_.begin(), tmp.chars_.end()); - return *this; -} - -UTF8String& UTF8String::operator+=(const UTF8Char& ch) -{ - // 実際には文字を設定するのに利用される。 - // また、これを定義しておくことで、streamからの結果を直接設定することができる。 - UTF8String tmp(ch.getBytes()); - chars_.insert(chars_.end(), tmp.chars_.begin(), tmp.chars_.end()); - return *this; -} - - -std::string UTF8String::toStr() const -{ - // 文字列に変換する。 - std::string ret; - std::for_each(chars_.begin(), chars_.end(), - UTF8StringToString(ret)); - return ret; -} - -void UTF8String::insert(UTF8String::utf8iterator it, UTF8String::utf8iterator begin, - UTF8String::utf8iterator last) -{ - // 渡されたのは実際にはvectorのイテレータなので、 - // そのままvectorの実装に任せることができる。 - chars_.insert(it, begin, last); -} - -void UTF8String::insert(UTF8String::utf8iterator it, - UTF8String::const_utf8iterator begin, - UTF8String::const_utf8iterator last) -{ - // 渡されたのがconstであるかどうかというだけの違いであるため、 - // そのまま渡すことができる。 - chars_.insert(it, begin, last); -} - -//================================================================================ - -utakata::utf8_string::UTF8String utakata::utf8_string::substring( - const utakata::utf8_string::UTF8String& str, size_t begin, size_t end) -{ - if (end == 0) - { - // 先頭から末尾までを取得する。 - UTF8String s; - s.insert(s.begin(), str.begin() + begin, str.end()); - return s; - } - else if (begin <= end) - { - UTF8String s; - s.insert(s.begin(), str.begin() + begin, str.begin() + (begin + end)); - return s; - } - else - { - throw range_error("out of range in utakata::utf8_string::substring"); - } -} - -utakata::utf8_string::UTF8String utakata::utf8_string::convert( - const std::string& str) -{ - UTF8String tmp; - tmp += str; - return tmp; -} - -UTF8String utakata::utf8_string::operator+(const UTF8String& lh, const UTF8String& rh) -{ - // 双方をコピーして加算して返す。凄い負荷が高い。 - UTF8String str(lh); - str += rh; - return str; -} - -UTF8String utakata::utf8_string::operator+(const UTF8String& lh, const UTF8Char& rh) -{ - // 文字と加算する。 - UTF8String tmp(lh); - tmp += rh.getBytes(); - return tmp; -} - -UTF8String utakata::utf8_string::operator+(const UTF8Char& lh, const UTF8String& rh) -{ - UTF8String tmp(lh.getBytes()); - tmp += rh; - return tmp; -} diff --git a/utf8_string.h b/utf8_string.h deleted file mode 100755 index 3eeb95d..0000000 --- a/utf8_string.h +++ /dev/null @@ -1,210 +0,0 @@ -#ifndef _UTF8_STRING_H_ -#define _UTF8_STRING_H_ - -#include -#include -#include -#include - - -// UTF8のバイト列、あるいは文字列から、UTF8の一文字単位で保持を行う -// CUTF8Charの作成と、CUTF8CharのコンテナであるCUTF8Stringを定義する。 - - -namespace utakata { - - namespace utf8_string { - - class range_error : public std::exception - { - public: - range_error(const std::string& str) : str_(str) {} - virtual ~range_error() throw() {} - - const char* what() throw() { - return str_.c_str(); - } - private: - - std::string str_; - }; - - class UTF8Char - { - /** - UTF8と判断されたバイト列を受け取り、実際の値を返す。 - ここで言う実際の値とは、UTF-8で定まっているバイト列の表現から、 - 固定とされる表現部分を削除し、有効とされる値を結合した値を指す。 - この値は実際のUTF16のコードと同一であり、完全なマッピングが可能 - となる。 - - 110xxxxx 10yyyyyy --> xxxxxyyyyyy = 11bit - 1110xxxx 10yyyyyy 10zzzzzz --> xxxxyyyyyyzzzzzz = 16bit - 11110xxx 10yyyyyy 10zzzzzz 10vvvvvv --> xxxyyyyyyzzzzzzvvvvvv = 21bit - ※策定仕様では、5byte以上となるUTF-8は異常であるとされるため、21bitが表現 - できればよい。 - - 21bitを十分に表現することができる整数型は、longのみであるため、必ずlongとして - 返す。 - intに暗黙のキャストをすることができるが、intは16bitまでしか保持義務が無いため、 - 原則としてCUTF8Charはlongで扱う。 - */ - - public: - // バイト列を必ず渡す必要がある。 - UTF8Char(const std::vector& utf8); - virtual ~UTF8Char(){} - - // コピーコンストラクタを宣言したため、同時にoperator=を宣言する。 - UTF8Char(const UTF8Char& ch); - UTF8Char& operator=(const UTF8Char& ch); - - // 各演算子のオーバーロード。 - // <=と>=は、それぞれ>の結果のnot、<の結果のnotを - // 用いることで実装できるため、この二つだけ供えていれば問題ない。 - // また、比較には内部で保持しているutf16_code_を用いるため、 - // 速度面で気にする必要は無い。 - bool operator==(const UTF8Char& code) const; - bool operator<(const UTF8Char& code) const; - bool operator>(const UTF8Char& code) const; - bool operator!=(const UTF8Char& code) const; - - // UTF8->UTF16に変換したコードを返す。 - long toUTF16Code() const {return this->utf16_code_;} - - // 実際のバイト列を返す。 - const std::vector& getBytes() const {return utf8_bytes_;} - - // 文字列として変換して返す。 - std::string toStr() const; - - // 渡されたUTF8Charの内部と交換する。 - void swap(UTF8Char& ch); - - private: - - // utf8を表すバイト列 - std::vector utf8_bytes_; - // 渡されたバイト列を実際のコードにしたもの - long utf16_code_; - }; - - // 渡されたUTF8Charがasciiコードの範囲内に収まっているかどうかを返す。 - bool is_ascii_char(const UTF8Char& ch); - - // 渡されたUTF8Charが、それぞれ数値、アルファベットであるかどうか - // を返す。これらはutf8モジュールのユーティリティ関数によって実装される。 - bool is_numeric(const UTF8Char& ch); - bool is_alpha(const UTF8Char& ch); - - // UTF8では先頭1バイトが0xffになることはありえないので、 - // 先頭1バイトが0xffの場合には、これは終端記号であるとした。 - bool is_eof(const UTF8Char& ch); - - //================================================================================ - - class UTF8String - { - // UTF8の文字列を保持するためのコンテナ。 - // 相互での比較などもサポートし、utakataの内部全般で - // 標準として使用することが可能なものとし、かつ標準コンテナと - // ほぼ同様の処理を行うことができるように定義されている。 - // というか内部では単純なvectorで定義されているため、 - // typedefされた型を指定するだけで、イテレータとして利用可能。 - - public: - - // イテレータとして簡単に利用するためのtypedefマクロ - typedef std::vector::iterator utf8iterator; - typedef std::vector::const_iterator const_utf8iterator; - - public: - - UTF8String(); - - UTF8String(const std::vector& bytes); - UTF8String(const UTF8String& str); - virtual ~UTF8String(){} - - // 実体に代入する。代入が行われなかった場合、元のデータ - // は保存される。 - void assign(const std::vector& bytes); - void assign(const UTF8String& str); - - // iteratorを取得する。 - const_utf8iterator begin() const {return chars_.begin();} - utf8iterator begin() {return chars_.begin();} - - // 末尾のイテレータを取得する。 - const_utf8iterator end() const {return chars_.end();} - utf8iterator end() {return chars_.end();} - - // []をオーバーロードする。これは常に境界のチェックを行う。 - const UTF8Char& operator[](size_t t) const {return chars_.at(t);} - UTF8Char& operator[](size_t t) { - return const_cast( - static_cast(this)->chars_[t]);} - - // サイズを取得する。 - size_t size() const {return chars_.size();} - // 空かどうかを調べる。 - bool empty() const {return size() == 0 ? true : false;} - - // 安全なswapと共に提供する。 - UTF8String& operator=(const UTF8String& str); - void swap(UTF8String& str); - - // 加算のみをサポートする。 - UTF8String& operator+=(const UTF8String& str); - UTF8String& operator+=(const std::vector& ch); - UTF8String& operator+=(const UTF8Char& ch); - UTF8String& operator+=(const std::string& str); - - // std::stringへ変換する。ただし、std::string上でのinsertなどは - // 保証できない。 - std::string toStr() const; - - // 渡したイテレータの範囲を追加する - // beginとlastは同一のUTF8Stringから取得されたものであること。 - void insert(utf8iterator it, utf8iterator begin, utf8iterator last); - void insert(utf8iterator it, const_utf8iterator begin, - const_utf8iterator last); - - private: - - std::vector chars_; - }; - - UTF8String operator+(const UTF8String& lh, const UTF8String& rh); - UTF8String operator+(const UTF8String& lh, const UTF8Char& rh); - UTF8String operator+(const UTF8Char& lh, const UTF8String& rh); - - // std::stringから直接utf8stringをを作成する。 - UTF8String convert(const std::string& str); - - // substringの実装を行う。 - // [begin, end)までの文字を文字列として返す。 - // endが渡されないか、0が渡された場合、beginから末尾までが返される。 - UTF8String substring(const UTF8String& str, size_t begin, size_t end = 0); - - template - class UTF8StringToString : public std::unary_function - { - // イテレータを受け取り、std::stringを初期化引数で渡されたものに - // コピーしていく。 - public: - - UTF8StringToString(std::string& str) : ret_(str) {} - void operator()(const T& it) { - ret_ += it.toStr(); - } - - private: - - std::string& ret_; - }; - }; - -}; - -#endif /* _UTF8_STRING_H_ */ diff --git a/utf8_transcoder.cpp b/utf8_transcoder.cpp new file mode 100755 index 0000000..763ed70 --- /dev/null +++ b/utf8_transcoder.cpp @@ -0,0 +1,251 @@ +#include +#include +#include + +#include "utf8_transcoder.h" +#include "smart_ptr.h" +#include "binary_port.h" + +using namespace std;; +using namespace utakata::transcoder; +using namespace utakata; + +unsigned long transcoder::UTF8Transcoder::transcode(port::BinaryInputPort& p) +{ + // 渡されたバイナリポートから、一文字を読みとる。 + // 最初に一文字だけ読みだして、チェックをかける。 + + // まずは読み取りをおこなう。 + int c = 0; + c = strm_->peek(); + + std::vector bytes; + if (c != std::istream::traits_type::eof()) + { + // 末尾でない場合のみ、以降のチェックに入る。 + size_t size = 0; + // 先頭1バイトが正常でなかった場合はそのまま抜ける + if (is_utf8_first_byte(static_cast(c), size)) + { + if (size > 0) + { + // sizeが0より大きい場合には、この時複数バイトで文字が構成 + // されていると考えられるため、明示的に複数文字を取得する。 + // peekされているので、読み取り位置は変化しない。 + std::vector tmp = strm_->read(size + 1); + } + } + } + + return generate(bytes); +} + +unsigned long transcoder::UTF8Transcoder::generate(const std::vector& bytes) +{ + // 1文字分のUTF8のバイト列を受け取って、コードに変換して返す。 + // 先頭の値によって、次のように値を決定することができる。 + // x = utf8の先頭バイト + // y1〜yN = utf8の先頭バイト以降のバイト + // N = utf8の先頭バイトを含むバイト数 + // code = (y1 & ((1 << 7) - 1)) << (6 * n-1) + (y2 & ((1 << 7) -1)) << (6 * (n - 1))...+ x & ((1 << N) -1) << (6 * N-1) + // 先頭バイト以外は、全て先頭に10とうビットが設定されている。このビットを除いた6ビットをする。 + // つまり、末尾のバイトから順次やっていけばよい。 + + const unsigned char max_c = (1 << (sizeof(unsigned char) * 8 - 1)) - 1; + unsigned long code = 0; + + // 一文字も読みだせていないなら0を返す。 + if (!bytes.empty()) + { + if (tmp.size() == 1) + { + // asciiコードは7bitなのでそこだけ切り取って返す。 + code = tmp[0] & max_c; + } + else + { + // 一時的に利用されるクラス。 + struct Lambda + { + unsigned char operator()(unsigned char c, int s) { + return c << (6 * s); + } + }; + + // サイズが1以外の場合、ここからがちと違う。 + std::vector::reverse_iterator beg = tmp.rbegin(), + end = tmp.rend() - 1; + const unsigned char char_bit = (1 << 6) - 1; + for (int i = 0; beg != end; ++i,++beg) + { + code += Lambda()((*beg & char_bit), i); + } + + // 最後だけ、別の計算が必要になる。 + const unsigned char first_byte = (1 << ((sizeof(unsigned char) + 1) - tmp.size())) - 1; + code += Lambda()(first_byte,tmp.size() - 1); + } + } + + return code; +} + +// utf8関連の便利関数 + +bool utakata::transcoder::utf8::is_utf8_one(const std::vector& bytes, size_t& size) +{ + //渡したバイト列がUTF8の一文字に該当するかどうかを返す。 + size_t back = size; + + if (bytes.size() == 0) + { + size = back; + return false; + } + + size_t num = 0; + + if (!is_utf8_first_byte(bytes[0], num)) + { + size = back; + return false; + } + + // そもそもbytesのサイズが足りない場合にも失敗とする。 + if (num > bytes.size()) + { + size = back; + return false; + } + + // 先頭要素以外が正しければそれで問題ないとする。 + if (num > 1) + { + + const CheckUTF8Byte& checker = for_each(bytes.begin() + 1, bytes.begin() + num, + CheckUTF8Byte()); + + if (checker.good) + { + size = num; + } else { + size = back; + return false; + } + } else { + // sizeが0の場合には、この時点で1を設定するようにする。 + size = num; + } + + // 最後まで到達した時点で成功とする。 + return true; +} + +bool utakata::transcoder::utf8::is_utf8_all(const std::vector& bytes) +{ + // 与えられたバイト列全てがUTF-8であるかどうかを返す。 + size_t size = 0; + std::vector::const_iterator it = bytes.begin(); + while (is_utf8_one(std::vector(it, bytes.end()), size)) { + it += size; + size = 0; + } + + if (it == bytes.end()) { + return true; + } + + return false; +} + +bool utakata::transcoder::utf8::is_utf8_first_byte(unsigned char c, size_t& size) +{ + // UTf-8の先頭バイトであるかどうかを返す。 + // 先頭バイトである場合には、その先頭バイトを含む、一文字のサイズを返す。 + // 先頭バイトではない場合には、 + const unsigned char max_c = 1 << (sizeof(unsigned char) * 8 - 1); + + size_t back = size; + + // 最上位ビットが0である場合、これはasciiコードを指す。 + if (!(c & max_c)) + { + size = 1; + return true; + } + + unsigned char first = c << 1; + size_t num = 1; + while (first & max_c) { + first <<= 1; + num += 1; + } + + // ここまできたとき、最上位ビットは0であるはず。 + // numが5未満である場合、とりあえず正常としておくこととする。 + const unsigned char max_utf8_sequence = 5; + if (num < max_utf8_sequence) { + size = num; + return true; + } + else if (num == 1) + { + // numが1の場合、何らかの理由で先頭が欠落したと見られる。 + // この場合、スキップするべきバイト数を返す。 + size = 1; + return false; + + } else { + size = back; + return false; + } +} + + +bool utakata::transcoder::utf8::is_utf8_ascii(const std::vector& bytes) +{ + // 一文字かつ、0x00〜0x7fの範囲であるデータであることが条件となる。 + size_t s = 0; + bool b = is_utf8_one(bytes, s); + + if (b && s == 1) + { + return true; + } + return false; +} + +bool utakata::transcoder::utf8::is_utf8_numeric(const std::vector& bytes) +{ + // 一文字分だけが渡されていると判断する。 + if (!is_utf8_ascii(bytes)) + { + return false; + } + + if (bytes[0] >= '0' && bytes[0] <= '9') + { + return true; + } + + return false; +} + +bool utakata::transcoder::utf8::is_utf8_alpha(const std::vector& bytes) +{ + // 同じく一文字であると判別する。 + // asciiのサブセットなので、先にasciiであると判別しておく。 + if (!is_utf8_ascii(bytes)) + { + return false; + } + + if ((bytes[0] >= 'a' && bytes[0] <= 'z') || + (bytes[0] >= 'A' && bytes[0] <= 'Z')) + + { + return true; + } + + return false; +} diff --git a/utf8_transcoder.h b/utf8_transcoder.h new file mode 100755 index 0000000..2dbc5f5 --- /dev/null +++ b/utf8_transcoder.h @@ -0,0 +1,94 @@ +#ifndef _UTF8_TRANSCODER_H_ +#define _UTF8_TRANSCODER_H_ + +#include +#include +#include + +#include "smart_ptr.h" +#include "transcoder.h" + +namespace utakata { + + namespace port { + class BinaryInputPort; + }; + + namespace transcoder { + + class UTF8Transcoder : public ITranscoder + { + // UTF-8のバイト列が与えられた場合に利用されるTranscoder + public: + UTF8Transcoder() {} + virtual ~UTF8Transcoder() {} + + virtual unsigned long transcode(port::BinaryInputPort& p); + + private: + + unsigned long generate(const std::vector& bytes); + }; + + namespace utf8 { + + // これらの便利関数は、とりあえずこの中に定義しておく。 + + struct CheckUTF8Byte + { + // UTF8の先頭バイト以外であるかどうかをチェックする。 + const unicode::UniChar checker; + bool good; + CheckUTF8Byte() : checker(0x2), good(true) {} + + template + void operator()(const T& t) { + // 先頭ビットが10ではない場合、チェックに失敗する。 + T tmp = t >> 6; + if ( ((tmp & 0x3)) != checker) { + good = false; + } + } + }; + + struct PutBack + { + // 渡されたデータをistreamにputbackする。 + smart_ptr strm_; + PutBack(smart_ptr strm) : strm_(strm) {} + + template + void operator()(T t) + { + strm_->putback(t); + } + }; + + // 与えられたバイト列の先頭から、UTF8一文字に該当しているかどうかを返す。 + // バイト列がUTF8に該当する場合、そのバイト列のサイズを返す。 + bool is_utf8_one(const std::vector& bytes, size_t& size); + + // 与えられたバイト列全てが、UTF8に該当しているかどうかを返す。 + bool is_utf8_all(const std::vector& bytes); + + // UTF-8の先頭バイトとして正しいフォーマットであるかどうか。 + // 正しいフォーマットである場合、渡したバイトを含めた、一文字である + // バイト数を返す。 + bool is_utf8_first_byte(unicode::UniChar c, size_t& size); + + // 渡したバイト列が、0-9で判別される数値文字と一致するかどうかを返す。 + // is_asciiのサブセットを判別するものである。 + bool is_utf8_numeric(const std::vector& bytes); + + // 渡したバイト列が、a-zA-Zの領域であるかどうかを調べる。 + // is_asciiのサブセットを判別するものである。 + bool is_utf8_alpha(const std::vector& bytes); + + // 渡したバイト列が、0x00〜0x7fの領域であるかどうかを返す。 + // is_utf8_alpha, is_utf8_numericのスーパーセットとなる。 + bool is_utf8_ascii(const std::vector& bytes); + }; + }; +} + +#endif /* _UTF8_TRANSCODER_H_ */ -- 2.11.0