OSDN Git Service

<inline hex esacpe>の非終端記号を解釈するInlineHexEscapeLexer、及びテストを追加。
authorderui <derutakayu@user.sourceforge.jp>
Wed, 6 Jan 2010 14:47:47 +0000 (23:47 +0900)
committerderui <derutakayu@user.sourceforge.jp>
Wed, 6 Jan 2010 14:47:47 +0000 (23:47 +0900)
StringLexerの内容をほぼ完了。

src/lexer/inline_hex_escape_lexer.cpp [new file with mode: 0755]
src/lexer/inline_hex_escape_lexer.h [new file with mode: 0755]
src/lexer/inner_hex_lexer.cpp
src/lexer/string_lexer.cpp
src/lexer/string_lexer.h
src/lexer/term_checker.cpp
src/lexer/term_checker.h
test/inline_hex_escape_lexer_test.cpp [new file with mode: 0755]

diff --git a/src/lexer/inline_hex_escape_lexer.cpp b/src/lexer/inline_hex_escape_lexer.cpp
new file mode 100755 (executable)
index 0000000..3bb5860
--- /dev/null
@@ -0,0 +1,47 @@
+#include <algorithm>
+
+#include "src/exception_macro.h"
+#include "src/lexer/inner_hex_lexer.h"
+#include "src/lexer/lexer_interface.h"
+#include "src/lexer/term_lexer.h"
+#include "src/lexer/term_checker.h"
+#include "src/lexer/inline_hex_escape_lexer.h"
+#include "src/unicode.h"
+#include "src/encoding_reader.h"
+#include "lib/range.h"
+
+namespace lexer = utakata::lexer;
+namespace term = utakata::lexer::term;
+namespace unicode = utakata::unicode;
+
+// 宣言のコメントを参照してください。
+bool lexer::InlineHexEscapeLexer::Lex(reader::EncodingReader* reader,
+                                    unsigned int* result) {
+  unicode::UniString prefix(reader->Peek(2));
+
+  if (prefix != unicode::Convert("\\x")) {
+    return false;
+  }
+
+  unicode::UniString hex_value;
+  lexer::TermLexer<term::HexValue> hex_checker;
+
+  while (hex_checker.CheckToken(reader) && reader->IsEof()) {
+    hex_value.Append(unicode::UniChar(reader->Read()));
+  }
+
+  if (hex_value.IsEmpty() ) {
+    unicode::UniString encoded_string("invalid escape sequence : ");
+    THROW_EXCEPTION_(lexer::LexException, encoded_string);
+  } else if (reader->Peek() != ';') {
+    THROW_EXCEPTION_(lexer::LexException, unicode::Convert(
+        "inline hex escape is end of ';'"));
+  }
+
+  reader->Read();
+  lexer::InnerHexValueLexer inner_hex;
+
+  inner_hex.Lex(hex_checker, result);
+
+  return true;
+}
diff --git a/src/lexer/inline_hex_escape_lexer.h b/src/lexer/inline_hex_escape_lexer.h
new file mode 100755 (executable)
index 0000000..bb60435
--- /dev/null
@@ -0,0 +1,27 @@
+// <inline hex escape>に該当する字句を読み出す機能を提供します。
+// ここで提供されるデータは、次のデータを有効
+// 
+#ifndef _UTAKATA_SRC_LEXER_INLINE_HEX_ESCAPE_LEXER_H_
+#define _UTAKATA_SRC_LEXER_INLINE_HEX_ESCAPE_LEXER_H_
+
+namespace utakata {
+namespace reader {
+class EncodingReader;
+}
+
+namespace lexer {
+
+// \x<hex scalar value>;に一致するエスケープを、scalar valueに一致する
+// 文字列を、一致するunicode表現とします。
+class InlineHexEscapeLexer {
+ public:
+
+  // readerの先頭が\xでは無い場合、falseを返却します。その場合、result
+  // は更新されません。
+  // 構文に一致しない場合、LexException例外が送出されます。
+  virtual bool Lex(reader::EncodingReader* reader, unsigned int* result);
+};
+}
+}
+
+#endif /* _UTAKATA_SRC_LEXER_INLINE_HEX_ESCAPE_LEXER_H_ */
index 4b3aa6b..716072b 100755 (executable)
@@ -11,7 +11,6 @@
 #include "lib/range.h"
 
 namespace lexer = utakata::lexer;
-namespace term = utakata::lexer::term;
 namespace unicode = utakata::unicode;
 
 // 宣言のコメントを参照してください。
@@ -21,7 +20,7 @@ bool lexer::InnerHexValueLexer::Lex(const unicode::UniString& string,
       end = string.End();
 
   if (akebono::range::find_if_not(
-          string, term::HexValueChecker()) != end) {
+          string, HexValueChecker()) != end) {
     return false;
   }
 
index d391c50..d1b4a3d 100755 (executable)
@@ -3,6 +3,7 @@
 #include "src/lexer/string_lexer.h"
 #include "src/lexer/term_lexer.h"
 #include "src/lexer/term_checker.h"
+#include "src/lexer/inline_hex_escape_lexer.h"
 #include "src/lexeme.h"
 #include "src/encoding_reader.h"
 #include "src/unicode.h"
@@ -12,6 +13,21 @@ namespace term = utakata::lexer::term;
 namespace reader = utakata::reader;
 namespace unicode = utakata::unicode;
 
+// 宣言のコメントを参照してください。
+unsigned int lexer::EscapeConverter::Convert(unsigned int code) {
+  switch (code) {
+    case 'a'  : return kAlarm;
+    case 'b'  : return kBackspace;
+    case 't'  : return kTab;
+    case 'n'  : return kLinefeed;
+    case 'v'  : return kVTab;
+    case 'f'  : return kForward;
+    case 'r'  : return kCaridgeReturn;
+    case '"'  : return kDoubleQuote;
+    case '\\' : return kBackslash;
+    default: return 0;
+  }
+}
 
 // 宣言のコメントを参照して下さい。
 bool lexer::EscapeLexer::Lex(reader::EncodingReader* reader,
@@ -28,16 +44,16 @@ bool lexer::EscapeLexer::Lex(reader::EncodingReader* reader,
 
   lexer::InlineHexEscapeLexer inline_escape;
 
-  if (inline_escape(reader, code)) {
+  if (inline_escape(reader, &code)) {
     return true;
   }
 
   reader->Read();
   lexer::TermLexer<term::IntralineWhiteSpaceChecker> intraline;
   lexer::TermLexer<term::LineEndingChecker> lineend;
-  if (!CheckEscapeSequence(escape.At(1)) &&
-      !intraline.CheckToken(reader) &&
-      !lineend.CheckToken(reader)) {
+  
+  if (!EscapeConverter.CanConvert(escape.At(1).rawcode()) &&
+      !intraline.CheckToken(reader) && !lineend.CheckToken(reader)) {
     unicode::UniString encoded_string("invalid escape sequence : ");
     encoded_string.Append(escape);
     THROW_EXCEPTION_(lexer::LexException, encoded_string);
@@ -66,60 +82,32 @@ unsigned int lexer::EscapeLexer::ConvertEscapeToCode(
       THROW_EXCEPTION_(lexer::LexException, encoded_string);
     }
   } else {
-    // 1文字だけReadしているのは、すでに\に該当する部分がReadされており、
-    // escapeとして渡されている文字列以降をチェックするために、
-    // escape分を読捨てるためです。
-    reader->Read();
-    while (intraline.CheckToken(reader) && !reader->IsEof()) {
-      intraline.ReadToken(reader);
-    }
-
-    if (!lineend.CheckToken(reader)) {
-      unicode::UniString encoded_string;
-      THROW_EXCEPTION_(lexer::LexException,
-                       unicode::Convert("must line ending after whitespaces"));
-    }
-    lineend.ReadToken(reader);
-
-    while (intraline.CheckToken(reader) && !reader->IsEof()) {
-      intraline.ReadToken(reader);
-    }
+    ReadIntralines(reader);
   }
 
   return code;
 }
 
-// 宣言のコメントを参照して下さい。
-bool lexer::EscapeConverter::CanConvert(unsigned int code) {
-  switch (code) {
-    case 'a'  :
-    case 'b'  :
-    case 't'  :
-    case 'n'  :
-    case 'v'  :
-    case 'f'  :
-    case 'r'  :
-    case '"'  :
-    case '\\' :
-      return true;
-    default:
-      return false;
+// 処理の先頭で1文字だけReadしているのは、すでに\と次の文字が
+// 読出されているためです。
+void lexer::EscapeLexer::ReadIntralines(reader::EncodingReader* reader) {
+  lexer::TermLexer<term::IntralineWhiteSpaceChecker> intraline;
+  lexer::TermLexer<term::LineEndingChecker> lineend;
+
+  reader->Read();
+  while (intraline.CheckToken(reader) && !reader->IsEof()) {
+    intraline.ReadToken(reader);
   }
-}
 
-// 宣言のコメントを参照してください。
-unsigned int lexer::EscapeConverter::Convert(unsigned int code) {
-  switch (code) {
-    case 'a'  : return kAlarm;
-    case 'b'  : return kBackspace;
-    case 't'  : return kTab;
-    case 'n'  : return kLinefeed;
-    case 'v'  : return kVTab;
-    case 'f'  : return kForward;
-    case 'r'  : return kCaridgeReturn;
-    case '"'  : return kDoubleQuote;
-    case '\\' : return kBackslash;
-    default: return 0;
+  if (!lineend.CheckToken(reader)) {
+    unicode::UniString encoded_string;
+    THROW_EXCEPTION_(lexer::LexException,
+                     unicode::Convert("must line ending after whitespaces"));
+  }
+  lineend.ReadToken(reader);
+
+  while (intraline.CheckToken(reader) && !reader->IsEof()) {
+    intraline.ReadToken(reader);
   }
 }
 
index 041487b..aea82be 100755 (executable)
@@ -39,7 +39,9 @@ class EscapeConverter {
 public:
 
   // エスケープシーケンスの文字コードである場合、trueを返します。
-  bool CanConvert(unsigned int code);
+  bool CanConvert(unsigned int code) {
+    return Convert(code) == 0;
+  }
 
   // エスケープシーケンスの文字コードから、各エスケープシーケンスに
   // 該当する値を返却します。
@@ -84,16 +86,17 @@ public:
 
  private:
 
-  // 渡された文字が、エスケープシーケンスとして認識される文字
-  // である場合、trueを返します。
-  bool CheckEscapeSeacense(const unicode::UniChar& escape);
-
   // 渡されたエスケープシーケンスから、該当する文字コードを取得します。
   // 内部では、\<intraline whitespace>...のチェックも行います。
   // エスケープシーケンスとして認識されない文字列が渡された場合、
   // LexExceptionを送出します。
   unsigned int ConvertEscapeToCode(const unicode::UniString& escape,
                                    reader::EncodingReader* reader);
+
+  // readerから、Intraline whiltespace及び改行を読み捨てます。
+  // <intraline whitespace>*<line ending><intraline whitespace>*に
+  // 一致しない場合、lexer::LexExceptionが送出されます。
+  void ReadIntralines(reader::EncodingReader* reader);
 };
 
 class StringLexer : public IPartOfLexer {
index 35b79b6..ba44747 100755 (executable)
@@ -81,6 +81,13 @@ bool term::HexValue::operator()(reader::EncodingReader* reader,
 }
 
 // 宣言のコメントを参照してください。
+bool term::HexValueChecker::operator()(const unicode::UniChar& ch) {
+  return (('a' <= ch.rawcode() && ch.rawcode() <= 'f') ||
+          ('A' <= ch.rawcode() && ch.rawcode() <= 'F') ||
+          ('0' <= ch.rawcode() && ch.rawcode() <= '9'));
+}
+
+// 宣言のコメントを参照してください。
 bool term::StringDoubleQuote::operator()(reader::EncodingReader* reader,
                                          unsigned int* size) {
   unicode::UniChar ch(reader->Peek());
index a042063..64aeea4 100644 (file)
@@ -66,7 +66,13 @@ class HexValue {
   // 渡されたreaderの読み出し位置は更新されません。
   bool operator()(reader::EncodingReader* reader, unsigned int* size);
 };
-}
+
+class HexValueChecker {
+ public:
+  // 渡された文字が、HexValueの領域内であるかどうかを返します。
+  bool operator()(const unicode::UniChar& ch);
+};
+
 }
 }
 
diff --git a/test/inline_hex_escape_lexer_test.cpp b/test/inline_hex_escape_lexer_test.cpp
new file mode 100755 (executable)
index 0000000..5521547
--- /dev/null
@@ -0,0 +1,62 @@
+#include <iostream>
+
+#include <test/gtest/gtest.h>
+#include "lib/textarrayformat.h"
+#include "src/lexer/lexer_interface.h"
+#include "src/lexer/inline_hex_escape_lexer.h"
+#include "src/unicode.h"
+#include "lib/scoped_ptr.h"
+#include "src/encoding_reader.h"
+#include "src/string_reader.h"
+#include "src/utf8_transcoder.h"
+
+namespace textarrayformat = utility::textarrayformat;
+namespace lexer = utakata::lexer;
+namespace unicode = utakata::unicode;
+
+class InlineHexEscapeLexerTest : public ::testing::Test {
+ protected:
+  virtual void SetUp() {
+    gen.reset(new textarrayformat::TextArrayGenerator("========="));
+    gen->Punctuate("\\x000F; \\x1aF;");
+    gen->Punctuate("\\9dG; \\x;");
+    gen->Punctuate("\\x; \\x1 ");
+  }
+
+  akebono::scoped_ptr<textarrayformat::TextArrayGenerator> gen;
+};
+
+TEST_F(InlineHexEscapeLexerTest, SuccessPattern) {
+  textarrayformat::TextArrayReader textarray(*gen);
+  reader::StringReader sr(textarray.GetBlockAt(0));
+  reader::EncodingReader reader(&sr, new transcoder::UTF8Transcoder);
+
+  lexer::InlineHexEscapeLexer l;
+
+  unsigned int ret = 0;
+  EXPECT_TRUE(l.Lex(&reader, &ret));
+  EXPECT_EQ(ret, static_cast<unsigned int>(0xF));
+
+  reader.Read();
+  EXPECT_TRUE(l.Lex(&reader, &ret));
+  EXPECT_EQ(ret, static_cast<unsigned int>(0x1aF));
+}
+
+TEST_F(InlineHexEscapeLexerTest, FailurePattern) {
+  textarrayformat::TextArrayReader textarray(*gen);
+  reader::StringReader sr(textarray.GetBlockAt(1));
+  reader::EncodingReader reader(&sr, new transcoder::UTF8Transcoder);
+
+  lexer::InlineHexEscapeLexer l;
+
+  unsigned int ret = 0;
+  EXPECT_THROW(l.Lex(&reader, &ret), lexer::LexException);
+
+  reader.Read(4);
+  EXPECT_THROW(l.Lex(&reader, &ret), lexer::LexException);
+}
+
+int main(int argc, char** argv) {
+  testing::InitGoogleTest(&argc, argv);
+  return RUN_ALL_TESTS();
+}