mirror of
https://github.com/pocoproject/poco.git
synced 2025-10-24 17:30:44 +02:00
added support for C++14/17 number literals
This commit is contained in:
@@ -33,7 +33,7 @@ class CppParser_API CppToken: public Poco::Token
|
|||||||
public:
|
public:
|
||||||
CppToken();
|
CppToken();
|
||||||
~CppToken();
|
~CppToken();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void syntaxError(const std::string& expected, const std::string& actual);
|
void syntaxError(const std::string& expected, const std::string& actual);
|
||||||
};
|
};
|
||||||
@@ -66,7 +66,7 @@ public:
|
|||||||
OP_BITAND_ASSIGN, // &=
|
OP_BITAND_ASSIGN, // &=
|
||||||
OP_AND, // &&
|
OP_AND, // &&
|
||||||
OP_BITOR, // |
|
OP_BITOR, // |
|
||||||
OP_BITOR_ASSIGN, // |=
|
OP_BITOR_ASSIGN, // |=
|
||||||
OP_OR, // ||
|
OP_OR, // ||
|
||||||
OP_XOR, // ^
|
OP_XOR, // ^
|
||||||
OP_XOR_ASSIGN, // ^=
|
OP_XOR_ASSIGN, // ^=
|
||||||
@@ -92,17 +92,17 @@ public:
|
|||||||
OP_SEMICOLON, // ;
|
OP_SEMICOLON, // ;
|
||||||
OP_QUESTION // ?
|
OP_QUESTION // ?
|
||||||
};
|
};
|
||||||
|
|
||||||
OperatorToken();
|
OperatorToken();
|
||||||
~OperatorToken();
|
~OperatorToken();
|
||||||
Poco::Token::Class tokenClass() const;
|
Poco::Token::Class tokenClass() const;
|
||||||
bool start(char c, std::istream& istr);
|
bool start(char c, std::istream& istr);
|
||||||
void finish(std::istream& istr);
|
void finish(std::istream& istr);
|
||||||
int asInteger() const;
|
int asInteger() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
typedef std::map<std::string, int> OpMap;
|
typedef std::map<std::string, int> OpMap;
|
||||||
|
|
||||||
OpMap _opMap;
|
OpMap _opMap;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -197,17 +197,17 @@ public:
|
|||||||
KW_XOR,
|
KW_XOR,
|
||||||
KW_XOR_EQ
|
KW_XOR_EQ
|
||||||
};
|
};
|
||||||
|
|
||||||
IdentifierToken();
|
IdentifierToken();
|
||||||
~IdentifierToken();
|
~IdentifierToken();
|
||||||
Poco::Token::Class tokenClass() const;
|
Poco::Token::Class tokenClass() const;
|
||||||
bool start(char c, std::istream& istr);
|
bool start(char c, std::istream& istr);
|
||||||
void finish(std::istream& istr);
|
void finish(std::istream& istr);
|
||||||
int asInteger() const;
|
int asInteger() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
typedef std::map<std::string, int> KWMap;
|
typedef std::map<std::string, int> KWMap;
|
||||||
|
|
||||||
KWMap _kwMap;
|
KWMap _kwMap;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -244,9 +244,16 @@ public:
|
|||||||
Poco::Token::Class tokenClass() const;
|
Poco::Token::Class tokenClass() const;
|
||||||
bool start(char c, std::istream& istr);
|
bool start(char c, std::istream& istr);
|
||||||
void finish(std::istream& istr);
|
void finish(std::istream& istr);
|
||||||
|
|
||||||
int asInteger() const;
|
int asInteger() const;
|
||||||
double asFloat() const;
|
double asFloat() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void finishHex(std::istream& istr, int next);
|
||||||
|
void finishBin(std::istream& istr, int next);
|
||||||
|
void finishExp(std::istream& istr, int next);
|
||||||
|
void finishSuffix(std::istream& istr, int next);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool _isFloat;
|
bool _isFloat;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ OperatorToken::OperatorToken()
|
|||||||
_opMap[":"] = i++;
|
_opMap[":"] = i++;
|
||||||
_opMap["::"] = i++;
|
_opMap["::"] = i++;
|
||||||
_opMap[";"] = i++;
|
_opMap[";"] = i++;
|
||||||
_opMap["?"] = i++;
|
_opMap["?"] = i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -345,7 +345,7 @@ void IdentifierToken::finish(std::istream& istr)
|
|||||||
while ((next >= 'A' && next <= 'Z') ||
|
while ((next >= 'A' && next <= 'Z') ||
|
||||||
(next >= 'a' && next <= 'z') ||
|
(next >= 'a' && next <= 'z') ||
|
||||||
(next >= '0' && next <= '9') ||
|
(next >= '0' && next <= '9') ||
|
||||||
(next == '_' || next == '$'))
|
(next == '_' || next == '$'))
|
||||||
{
|
{
|
||||||
_value += (char) istr.get();
|
_value += (char) istr.get();
|
||||||
next = istr.peek();
|
next = istr.peek();
|
||||||
@@ -388,7 +388,7 @@ bool StringLiteralToken::start(char c, std::istream& istr)
|
|||||||
|
|
||||||
void StringLiteralToken::finish(std::istream& istr)
|
void StringLiteralToken::finish(std::istream& istr)
|
||||||
{
|
{
|
||||||
int next = istr.peek();
|
int next = istr.peek();
|
||||||
while (next != -1 && next != '"' && next != '\n' && next != '\r')
|
while (next != -1 && next != '"' && next != '\n' && next != '\r')
|
||||||
{
|
{
|
||||||
if (next == '\\') _value += (char) istr.get();
|
if (next == '\\') _value += (char) istr.get();
|
||||||
@@ -447,7 +447,7 @@ bool CharLiteralToken::start(char c, std::istream& istr)
|
|||||||
|
|
||||||
void CharLiteralToken::finish(std::istream& istr)
|
void CharLiteralToken::finish(std::istream& istr)
|
||||||
{
|
{
|
||||||
int next = istr.peek();
|
int next = istr.peek();
|
||||||
while (next != -1 && next != '\'' && next != '\n' && next != '\r')
|
while (next != -1 && next != '\'' && next != '\n' && next != '\r')
|
||||||
{
|
{
|
||||||
if (next == '\\') _value += (char) istr.get();
|
if (next == '\\') _value += (char) istr.get();
|
||||||
@@ -513,23 +513,18 @@ void NumberLiteralToken::finish(std::istream& istr)
|
|||||||
_isFloat = false;
|
_isFloat = false;
|
||||||
if (_value[0] != '.') // starts with digit
|
if (_value[0] != '.') // starts with digit
|
||||||
{
|
{
|
||||||
if (next == 'x')
|
if (_value[0] == '0')
|
||||||
{
|
{
|
||||||
_value += (char) istr.get();
|
if (next == 'x' || next == 'X')
|
||||||
next = istr.peek();
|
|
||||||
while (std::isxdigit(next))
|
|
||||||
{
|
|
||||||
_value += (char) istr.get();
|
|
||||||
next = istr.peek();
|
|
||||||
}
|
|
||||||
while (next == 'L' || next == 'l' || next == 'U' || next == 'u')
|
|
||||||
{
|
{
|
||||||
_value += (char) istr.get();
|
return finishHex(istr, next);
|
||||||
next = istr.peek();
|
}
|
||||||
|
else if (next == 'b' || next == 'B')
|
||||||
|
{
|
||||||
|
return finishBin(istr, next);
|
||||||
}
|
}
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
while (next >= '0' && next <= '9')
|
while ((next >= '0' && next <= '9') || next == '\'')
|
||||||
{
|
{
|
||||||
_value += (char) istr.get();
|
_value += (char) istr.get();
|
||||||
next = istr.peek();
|
next = istr.peek();
|
||||||
@@ -563,37 +558,91 @@ void NumberLiteralToken::finish(std::istream& istr)
|
|||||||
if (next == 'e' || next == 'E')
|
if (next == 'e' || next == 'E')
|
||||||
{
|
{
|
||||||
_isFloat = true;
|
_isFloat = true;
|
||||||
|
finishExp(istr, next);
|
||||||
|
}
|
||||||
|
finishSuffix(istr, next);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void NumberLiteralToken::finishHex(std::istream& istr, int next)
|
||||||
|
{
|
||||||
|
_value += (char) istr.get();
|
||||||
|
next = istr.peek();
|
||||||
|
while (std::isxdigit(next) || next == '\'')
|
||||||
|
{
|
||||||
_value += (char) istr.get();
|
_value += (char) istr.get();
|
||||||
next = istr.peek();
|
next = istr.peek();
|
||||||
if (next == '+' || next == '-')
|
}
|
||||||
|
if (next == '.')
|
||||||
|
{
|
||||||
|
_isFloat = true;
|
||||||
|
_value += (char) istr.get();
|
||||||
|
next = istr.peek();
|
||||||
|
while (std::isxdigit(next) || next == '\'')
|
||||||
{
|
{
|
||||||
_value += (char) istr.get();
|
_value += (char) istr.get();
|
||||||
next = istr.peek();
|
next = istr.peek();
|
||||||
}
|
}
|
||||||
if (next >= '0' && next <= '9')
|
}
|
||||||
|
if (next == 'p' || next == 'P')
|
||||||
|
{
|
||||||
|
finishExp(istr, next);
|
||||||
|
}
|
||||||
|
finishSuffix(istr, next);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void NumberLiteralToken::finishBin(std::istream& istr, int next)
|
||||||
|
{
|
||||||
|
_value += (char) istr.get();
|
||||||
|
next = istr.peek();
|
||||||
|
while (next == '0' || next == '1' || next == '\'')
|
||||||
|
{
|
||||||
|
_value += (char) istr.get();
|
||||||
|
next = istr.peek();
|
||||||
|
}
|
||||||
|
finishSuffix(istr, next);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void NumberLiteralToken::finishExp(std::istream& istr, int next)
|
||||||
|
{
|
||||||
|
_isFloat = true;
|
||||||
|
_value += (char) istr.get();
|
||||||
|
next = istr.peek();
|
||||||
|
if (next == '+' || next == '-')
|
||||||
|
{
|
||||||
|
_value += (char) istr.get();
|
||||||
|
next = istr.peek();
|
||||||
|
}
|
||||||
|
if (next >= '0' && next <= '9')
|
||||||
|
{
|
||||||
|
while (next >= '0' && next <= '9')
|
||||||
{
|
{
|
||||||
while (next >= '0' && next <= '9')
|
_value += (char) istr.get();
|
||||||
{
|
next = istr.peek();
|
||||||
_value += (char) istr.get();
|
|
||||||
next = istr.peek();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
std::string s(1, (char) next);
|
|
||||||
syntaxError("digit", s);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::string s(1, (char) next);
|
||||||
|
syntaxError("digit", s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void NumberLiteralToken::finishSuffix(std::istream& istr, int next)
|
||||||
|
{
|
||||||
if (_isFloat)
|
if (_isFloat)
|
||||||
{
|
{
|
||||||
if (next == 'L' || next == 'l' || next == 'F' || next == 'f')
|
if (next == 'L' || next == 'l' || next == 'F' || next == 'f')
|
||||||
_value += (char) istr.get();
|
_value += (char) istr.get();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
while (next == 'L' || next == 'l' || next == 'U' || next == 'u')
|
while (next == 'L' || next == 'l' || next == 'U' || next == 'u')
|
||||||
{
|
{
|
||||||
_value += (char) istr.get();
|
_value += (char) istr.get();
|
||||||
next = istr.peek();
|
next = istr.peek();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -603,7 +652,6 @@ void NumberLiteralToken::finish(std::istream& istr)
|
|||||||
int NumberLiteralToken::asInteger() const
|
int NumberLiteralToken::asInteger() const
|
||||||
{
|
{
|
||||||
return static_cast<int>(std::strtol(_value.c_str(), 0, 0));
|
return static_cast<int>(std::strtol(_value.c_str(), 0, 0));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -656,7 +704,7 @@ void CommentToken::finish(std::istream& istr)
|
|||||||
{
|
{
|
||||||
next = istr.get();
|
next = istr.get();
|
||||||
_value += (char) next;
|
_value += (char) next;
|
||||||
if (next == '*' && istr.peek() == '/')
|
if (next == '*' && istr.peek() == '/')
|
||||||
{
|
{
|
||||||
_value += (char) istr.get();
|
_value += (char) istr.get();
|
||||||
break;
|
break;
|
||||||
@@ -704,7 +752,7 @@ void PreprocessorToken::finish(std::istream& istr)
|
|||||||
int next = istr.peek();
|
int next = istr.peek();
|
||||||
while (next != -1 && next != '\r' && next != '\n')
|
while (next != -1 && next != '\r' && next != '\n')
|
||||||
{
|
{
|
||||||
if (next == '\\')
|
if (next == '\\')
|
||||||
{
|
{
|
||||||
istr.get();
|
istr.get();
|
||||||
int p = istr.peek();
|
int p = istr.peek();
|
||||||
|
|||||||
@@ -13,6 +13,8 @@
|
|||||||
#include "CppUnit/TestSuite.h"
|
#include "CppUnit/TestSuite.h"
|
||||||
#include "Poco/CppParser/Utility.h"
|
#include "Poco/CppParser/Utility.h"
|
||||||
#include "Poco/CppParser/Symbol.h"
|
#include "Poco/CppParser/Symbol.h"
|
||||||
|
#include "Poco/CppParser/CppToken.h"
|
||||||
|
#include <sstream>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
|
|
||||||
@@ -33,6 +35,7 @@ std::string options("/I \"C:\\Program Files\\Microsoft Visual Studio 8\\VC\\INCL
|
|||||||
"/C, /P, /TP");
|
"/C, /P, /TP");
|
||||||
std::string path("C:\\Program Files\\Microsoft Visual Studio 8\\Common7\\IDE;C:\\Program Files\\Microsoft Visual Studio 8\\VC\\BIN;C:\\Program Files\\Microsoft Visual Studio 8\\Common7\\Tools;;C:\\Program Files\\Microsoft Visual Studio 8\\Common7\\Tools\\bin");
|
std::string path("C:\\Program Files\\Microsoft Visual Studio 8\\Common7\\IDE;C:\\Program Files\\Microsoft Visual Studio 8\\VC\\BIN;C:\\Program Files\\Microsoft Visual Studio 8\\Common7\\Tools;;C:\\Program Files\\Microsoft Visual Studio 8\\Common7\\Tools\\bin");
|
||||||
|
|
||||||
|
|
||||||
CppParserTest::CppParserTest(const std::string& name): CppUnit::TestCase(name)
|
CppParserTest::CppParserTest(const std::string& name): CppUnit::TestCase(name)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -52,15 +55,15 @@ void CppParserTest::testParseDir()
|
|||||||
inc.push_back("./*.h");
|
inc.push_back("./*.h");
|
||||||
std::vector<std::string> exc;
|
std::vector<std::string> exc;
|
||||||
Utility::parseDir(inc, exc, st, linker, options, path);
|
Utility::parseDir(inc, exc, st, linker, options, path);
|
||||||
|
|
||||||
NameSpace::SymbolTable::const_iterator it = st.begin();
|
NameSpace::SymbolTable::const_iterator it = st.begin();
|
||||||
NameSpace::SymbolTable::const_iterator itEnd = st.end();
|
NameSpace::SymbolTable::const_iterator itEnd = st.end();
|
||||||
for (it; it != itEnd; ++it)
|
for (; it != itEnd; ++it)
|
||||||
{
|
{
|
||||||
std::cout << it->first << ": ";
|
std::cout << it->first << ": ";
|
||||||
Symbol* pSym = it->second;
|
Symbol* pSym = it->second;
|
||||||
std::cout << pSym->name() << ", " << pSym->getDocumentation() << "\n";
|
std::cout << pSym->name() << ", " << pSym->getDocumentation() << "\n";
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -70,15 +73,15 @@ void CppParserTest::testExtractName()
|
|||||||
std::string decl("int _var");
|
std::string decl("int _var");
|
||||||
std::string name = Symbol::extractName(decl);
|
std::string name = Symbol::extractName(decl);
|
||||||
assertTrue (name == "_var");
|
assertTrue (name == "_var");
|
||||||
|
|
||||||
decl = "void func(int arg1, int arg2)";
|
decl = "void func(int arg1, int arg2)";
|
||||||
name = Symbol::extractName(decl);
|
name = Symbol::extractName(decl);
|
||||||
assertTrue (name == "func");
|
assertTrue (name == "func");
|
||||||
|
|
||||||
decl = "const std::vector<NS::MyType>* var";
|
decl = "const std::vector<NS::MyType>* var";
|
||||||
name = Symbol::extractName(decl);
|
name = Symbol::extractName(decl);
|
||||||
assertTrue (name == "var");
|
assertTrue (name == "var");
|
||||||
|
|
||||||
decl = "const std::vector<NS::MyType>* func(int arg) = 0";
|
decl = "const std::vector<NS::MyType>* func(int arg) = 0";
|
||||||
name = Symbol::extractName(decl);
|
name = Symbol::extractName(decl);
|
||||||
assertTrue (name == "func");
|
assertTrue (name == "func");
|
||||||
@@ -94,7 +97,7 @@ void CppParserTest::testExtractName()
|
|||||||
decl = "template <typename A, typename B> B func(A a, B b)";
|
decl = "template <typename A, typename B> B func(A a, B b)";
|
||||||
name = Symbol::extractName(decl);
|
name = Symbol::extractName(decl);
|
||||||
assertTrue (name == "func");
|
assertTrue (name == "func");
|
||||||
|
|
||||||
decl = "template <typename A, typename B> class Class";
|
decl = "template <typename A, typename B> class Class";
|
||||||
name = Symbol::extractName(decl);
|
name = Symbol::extractName(decl);
|
||||||
assertTrue (name == "Class");
|
assertTrue (name == "Class");
|
||||||
@@ -113,6 +116,70 @@ void CppParserTest::testExtractName()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void CppParserTest::testNumberLiterals()
|
||||||
|
{
|
||||||
|
testNumberLiteral("123");
|
||||||
|
testNumberLiteral("0123");
|
||||||
|
testNumberLiteral("0x123");
|
||||||
|
testNumberLiteral("0XABC");
|
||||||
|
testNumberLiteral("0b010101");
|
||||||
|
testNumberLiteral("0B101010");
|
||||||
|
|
||||||
|
testNumberLiteral("123L");
|
||||||
|
testNumberLiteral("0123L");
|
||||||
|
testNumberLiteral("0x123L");
|
||||||
|
testNumberLiteral("0XABCL");
|
||||||
|
testNumberLiteral("0b010101L");
|
||||||
|
testNumberLiteral("0B101010L");
|
||||||
|
|
||||||
|
testNumberLiteral("123LL");
|
||||||
|
testNumberLiteral("0123LL");
|
||||||
|
testNumberLiteral("0x123LL");
|
||||||
|
testNumberLiteral("0XABCLL");
|
||||||
|
testNumberLiteral("0b010101LL");
|
||||||
|
testNumberLiteral("0B101010LL");
|
||||||
|
|
||||||
|
testNumberLiteral("123U");
|
||||||
|
testNumberLiteral("0123U");
|
||||||
|
testNumberLiteral("0x123U");
|
||||||
|
testNumberLiteral("0XABCU");
|
||||||
|
testNumberLiteral("0b010101U");
|
||||||
|
testNumberLiteral("0B101010U");
|
||||||
|
|
||||||
|
testNumberLiteral("123UL");
|
||||||
|
testNumberLiteral("0123UL");
|
||||||
|
testNumberLiteral("0x123UL");
|
||||||
|
testNumberLiteral("0XABCUL");
|
||||||
|
testNumberLiteral("0b010101UL");
|
||||||
|
testNumberLiteral("0B101010UL");
|
||||||
|
|
||||||
|
testNumberLiteral("1.23");
|
||||||
|
testNumberLiteral(".123");
|
||||||
|
testNumberLiteral("1.23e+3");
|
||||||
|
testNumberLiteral("1.23E-3");
|
||||||
|
|
||||||
|
testNumberLiteral("0x1fp1");
|
||||||
|
testNumberLiteral("0x1f.e3p+12");
|
||||||
|
testNumberLiteral("0x1f.e3p-12");
|
||||||
|
|
||||||
|
testNumberLiteral("123'456");
|
||||||
|
testNumberLiteral("1'234'567");
|
||||||
|
testNumberLiteral("0x1234'5678");
|
||||||
|
testNumberLiteral("0xFFFF'FFFFULL");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void CppParserTest::testNumberLiteral(const std::string& literal)
|
||||||
|
{
|
||||||
|
NumberLiteralToken tok;
|
||||||
|
|
||||||
|
std::istringstream istr(literal);
|
||||||
|
assertTrue (tok.start(istr.get(), istr));
|
||||||
|
tok.finish(istr);
|
||||||
|
assertEquals (tok.tokenString(), literal);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void CppParserTest::setUp()
|
void CppParserTest::setUp()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -129,6 +196,7 @@ CppUnit::Test* CppParserTest::suite()
|
|||||||
|
|
||||||
CppUnit_addTest(pSuite, CppParserTest, testParseDir);
|
CppUnit_addTest(pSuite, CppParserTest, testParseDir);
|
||||||
CppUnit_addTest(pSuite, CppParserTest, testExtractName);
|
CppUnit_addTest(pSuite, CppParserTest, testExtractName);
|
||||||
|
CppUnit_addTest(pSuite, CppParserTest, testNumberLiterals);
|
||||||
|
|
||||||
return pSuite;
|
return pSuite;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,12 +26,16 @@ public:
|
|||||||
|
|
||||||
void testParseDir();
|
void testParseDir();
|
||||||
void testExtractName();
|
void testExtractName();
|
||||||
|
void testNumberLiterals();
|
||||||
|
|
||||||
void setUp();
|
void setUp();
|
||||||
void tearDown();
|
void tearDown();
|
||||||
|
|
||||||
static CppUnit::Test* suite();
|
static CppUnit::Test* suite();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void testNumberLiteral(const std::string& literal);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user