1325 lines
52 KiB
C++
1325 lines
52 KiB
C++
![]() |
/**
|
|||
|
* @file
|
|||
|
*
|
|||
|
* @copyright
|
|||
|
* @verbatim
|
|||
|
Copyright @ 2017 Audi Electronics Venture GmbH. All rights reserved.
|
|||
|
|
|||
|
This Source Code Form is subject to the terms of the Mozilla
|
|||
|
Public License, v. 2.0. If a copy of the MPL was not distributed
|
|||
|
with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|||
|
|
|||
|
If it is not possible or desirable to put the notice in a particular file, then
|
|||
|
You may include the notice in a location (such as a LICENSE file in a
|
|||
|
relevant directory) where a recipient would be likely to look for such a notice.
|
|||
|
|
|||
|
You may add additional accurate notices of copyright ownership.
|
|||
|
@endverbatim
|
|||
|
*/
|
|||
|
|
|||
|
#include <ddl.h>
|
|||
|
#include "header_importer.h"
|
|||
|
#include "header_basic_type.h"
|
|||
|
#include "header_typedef.h"
|
|||
|
#include "header_header.h"
|
|||
|
#include "parserhelper.h"
|
|||
|
|
|||
|
namespace ddl_generator
|
|||
|
{
|
|||
|
namespace oo
|
|||
|
{
|
|||
|
//define all needed error types and values locally
|
|||
|
_MAKE_RESULT(0, ERR_NOERROR)
|
|||
|
_MAKE_RESULT(-4, ERR_POINTER)
|
|||
|
_MAKE_RESULT(-5, ERR_INVALID_ARG)
|
|||
|
_MAKE_RESULT(-11, ERR_INVALID_FILE)
|
|||
|
_MAKE_RESULT(-20, ERR_NOT_FOUND)
|
|||
|
_MAKE_RESULT(-24, ERR_PATH_NOT_FOUND)
|
|||
|
_MAKE_RESULT(-36, ERR_UNKNOWN_FORMAT)
|
|||
|
_MAKE_RESULT(-37, ERR_NOT_INITIALISED)
|
|||
|
_MAKE_RESULT(-38, ERR_FAILED)
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
using namespace ddl_generator::oo;
|
|||
|
|
|||
|
using namespace ddl;
|
|||
|
|
|||
|
|
|||
|
namespace ddl
|
|||
|
{
|
|||
|
#define AMOUNT_OF_TOKENS 3
|
|||
|
//#define AMOUNT_OF_SINGLE_SEPARATORS 27
|
|||
|
const std::string g_tokens[AMOUNT_OF_TOKENS] = { "struct", "enum", "union" };
|
|||
|
const std::string g_single_separators = "{}[]#()<>%:;.?*+-/<2F>&|<7C>!=,\\\"<EFBFBD>;";
|
|||
|
const std::string g_name_chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_";
|
|||
|
|
|||
|
|
|||
|
class HeaderParserHelper
|
|||
|
{
|
|||
|
public:
|
|||
|
/**
|
|||
|
* CTOR
|
|||
|
*/
|
|||
|
HeaderParserHelper() {};
|
|||
|
|
|||
|
/**
|
|||
|
* DTOR
|
|||
|
*/
|
|||
|
virtual ~HeaderParserHelper() {};
|
|||
|
|
|||
|
/**
|
|||
|
* The method skipToNextContent skips comments and whitespace
|
|||
|
* until the next code fragment or the end of the file is reached.
|
|||
|
*
|
|||
|
* @param [in] src Pass a pointer to a string,
|
|||
|
* returns a pointer to the next character in the string,
|
|||
|
* that is part of the code.
|
|||
|
*/
|
|||
|
static void skipToNextContent(const char* &src)
|
|||
|
{
|
|||
|
const char* current = NULL;
|
|||
|
const char* forward_search = NULL;
|
|||
|
while (current != src)
|
|||
|
{
|
|||
|
current = src;
|
|||
|
forward_search = src;
|
|||
|
skipComment(src, getNextElement(forward_search));
|
|||
|
ddl_generator::skipWhitespace(src);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* The method isValidName checks whether a string is a valid name for either a variable or a type.
|
|||
|
* Used definition:
|
|||
|
* Must start with a letter oder an underscore.
|
|||
|
* Second to last character can be a number, letter or underscore.
|
|||
|
*
|
|||
|
* @param [in] name The name to be analyzed.
|
|||
|
* @returns True if the name is valid, false otherwise.
|
|||
|
*/
|
|||
|
static bool isValidName(const std::string &name)
|
|||
|
{
|
|||
|
a_util::regex::RegularExpression reg_ex("^[_a-zA-Z][_a-zA-Z0-9]*$");
|
|||
|
int consumed;
|
|||
|
return reg_ex.match(name, a_util::regex::RegularExpression::AT_Both, consumed);
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* The method skipBlock skips the next block.
|
|||
|
* Example:
|
|||
|
* bla = 5;
|
|||
|
* typedef struct {
|
|||
|
* int a;
|
|||
|
* };
|
|||
|
* The function skips to the semicolon after the last parenthesis.
|
|||
|
*
|
|||
|
* @param [in, out] src The source to be skipped, points to the next character after the parenthesis.
|
|||
|
*/
|
|||
|
static void skipBlock(const char* &src)
|
|||
|
{
|
|||
|
uint64_t depth = 0;
|
|||
|
while (*src != '\0' && *src != '{')
|
|||
|
{
|
|||
|
src++;
|
|||
|
}
|
|||
|
depth++;
|
|||
|
while (*src != '\0')
|
|||
|
{
|
|||
|
if (*src == '{')
|
|||
|
{
|
|||
|
depth++;
|
|||
|
}
|
|||
|
else if (*src == '}')
|
|||
|
{
|
|||
|
depth--;
|
|||
|
if (depth == 0)
|
|||
|
{
|
|||
|
src++;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
src++;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* The method exitBlock exists from the current block;
|
|||
|
* Example
|
|||
|
* blubb = 5;
|
|||
|
* bla blubber;
|
|||
|
* }
|
|||
|
* The method jumps to the character after the parenthesis.
|
|||
|
*
|
|||
|
* @param [in] src The string to be analyzed, returns a pointer to the character after the parenthesis
|
|||
|
* of the current block or to the end of the string.
|
|||
|
*/
|
|||
|
static void exitBlock(const char* &src)
|
|||
|
{
|
|||
|
while (*src != '\0')
|
|||
|
{
|
|||
|
if (*src == '}')
|
|||
|
{
|
|||
|
src++;
|
|||
|
break;
|
|||
|
}
|
|||
|
if (*src == '{')
|
|||
|
{
|
|||
|
skipBlock(src);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
src++;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* The function getNextElement extracts the next c++ element.
|
|||
|
* This can be a whole word like a type name or a single character like
|
|||
|
* a plus sign or the beginning/end of a comment line //, / * or * /
|
|||
|
* (cannot write the "comment close" without space or it would break the code of this file)
|
|||
|
* This function will not check any validity. So Names like "123onetwothree" are allowed.
|
|||
|
*
|
|||
|
* @param [in, out] src The string to be analyzed, returns a pointer to the character after found element.
|
|||
|
* @returns A string containing the element.
|
|||
|
*/
|
|||
|
static std::string getNextElement(const char* &src)
|
|||
|
{
|
|||
|
std::string result = "";
|
|||
|
while (*src != '\0')
|
|||
|
{
|
|||
|
//Check for a number or a name
|
|||
|
if (g_name_chars.find(*src) != std::string::npos)
|
|||
|
{
|
|||
|
result.push_back(*src);
|
|||
|
src++;
|
|||
|
while (g_name_chars.find(*src) != std::string::npos)
|
|||
|
{
|
|||
|
result.push_back(*src);
|
|||
|
src++;
|
|||
|
}
|
|||
|
break;
|
|||
|
}
|
|||
|
// Check for a single character like +, - and so on
|
|||
|
else if (g_single_separators.find(*src) != std::string::npos)
|
|||
|
{
|
|||
|
result = *src;
|
|||
|
src++;
|
|||
|
// Check for comment
|
|||
|
if (result == "/")
|
|||
|
{
|
|||
|
if (*src == '/' || *src == '*')
|
|||
|
{
|
|||
|
result.push_back(*src);
|
|||
|
src++;
|
|||
|
}
|
|||
|
}
|
|||
|
else if (result == "*")
|
|||
|
{
|
|||
|
if (*src == '/')
|
|||
|
{
|
|||
|
result.push_back(*src);
|
|||
|
src++;
|
|||
|
}
|
|||
|
}
|
|||
|
//Check for escape character
|
|||
|
else if (result == "\\")
|
|||
|
{
|
|||
|
result.push_back(*src);
|
|||
|
src++;
|
|||
|
}
|
|||
|
break;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
// Probably just space or newlines. If anything else has not been captured by this algorithm,
|
|||
|
// please add it here or where it fits.
|
|||
|
src++;
|
|||
|
}
|
|||
|
}
|
|||
|
return result;
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* The function getNextCodeElement extracts the next c++ element outside a comment.
|
|||
|
* This can be a whole word like a type name or a single character like
|
|||
|
* a plus sign.
|
|||
|
* This function will not check any validity. So Names like "123onetwothree" are allowed.
|
|||
|
* This function assumes that it is outside a comment.
|
|||
|
*
|
|||
|
* @param [in, out] src The string to be analyzed, returns a pointer to the character after found element.
|
|||
|
* @returns A string containing the element.
|
|||
|
*/
|
|||
|
static std::string getNextCodeElement(const char* &src)
|
|||
|
{
|
|||
|
std::string result;
|
|||
|
while (*src != '\0')
|
|||
|
{
|
|||
|
result = getNextElement(src);
|
|||
|
if (result == "/*" || result == "//")
|
|||
|
{
|
|||
|
skipComment(src, result);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
return result;
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* The method skipComment skips a comment. Use in conjunction with getNextElement().
|
|||
|
*
|
|||
|
* @param [in, out] p A pointer to the string containing the comment.
|
|||
|
The pointer will point to the first character after the comment.
|
|||
|
* @param [in] comment_begin The string containing the begin of the comment.
|
|||
|
* if the string does not contain a comment beginning (line // or / *)
|
|||
|
* nothing will be skipped.
|
|||
|
*/
|
|||
|
static void skipComment(const char* &src, const std::string &comment_begin)
|
|||
|
{
|
|||
|
if (comment_begin == "//")
|
|||
|
{
|
|||
|
skipEOL(src);
|
|||
|
}
|
|||
|
else if (comment_begin == "/*")
|
|||
|
{
|
|||
|
while ((getNextElement(src) != "*/") && (*src != '\0'))
|
|||
|
{
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* The method SkipToEOL [...]
|
|||
|
*
|
|||
|
* @param [in, out] src A pointer to the string containing the comment.
|
|||
|
The pointer will point to the first character after the EOL character (0x0A).
|
|||
|
*/
|
|||
|
static void skipEOL(const char* &src)
|
|||
|
{
|
|||
|
while (*src != '\n' && *src != '\0')
|
|||
|
{
|
|||
|
src++;
|
|||
|
}
|
|||
|
src++;
|
|||
|
}
|
|||
|
};
|
|||
|
|
|||
|
|
|||
|
HeaderImporter::HeaderImporter()
|
|||
|
{
|
|||
|
_types = NULL;
|
|||
|
_header = NULL;
|
|||
|
_default_type = NULL;
|
|||
|
}
|
|||
|
|
|||
|
HeaderImporter::~HeaderImporter()
|
|||
|
{
|
|||
|
_types = NULL;
|
|||
|
_header = NULL;
|
|||
|
_default_type = NULL;
|
|||
|
}
|
|||
|
|
|||
|
a_util::result::Result HeaderImporter::setHeaderString(const std::string &source)
|
|||
|
{
|
|||
|
_input_file = a_util::filesystem::Path();
|
|||
|
_header_source = source;
|
|||
|
return ERR_NOERROR;
|
|||
|
}
|
|||
|
|
|||
|
a_util::result::Result HeaderImporter::setFileName(const a_util::filesystem::Path &filename)
|
|||
|
{
|
|||
|
_header_source = "";
|
|||
|
_input_file = filename;
|
|||
|
return ERR_NOERROR;
|
|||
|
}
|
|||
|
|
|||
|
a_util::result::Result HeaderImporter::setKnownTypes(const HeaderTypesVec* types)
|
|||
|
{
|
|||
|
_types = types;
|
|||
|
return ERR_NOERROR;
|
|||
|
}
|
|||
|
|
|||
|
a_util::result::Result HeaderImporter::setDefaultIntegerType(const HeaderType* type)
|
|||
|
{
|
|||
|
_default_type = type;
|
|||
|
return ERR_NOERROR;
|
|||
|
}
|
|||
|
|
|||
|
HeaderTypesVec* HeaderImporter::getDefaultTypes()
|
|||
|
{
|
|||
|
HeaderBasicType* basic_type = NULL;
|
|||
|
HeaderTypesVec* types = new HeaderTypesVec();
|
|||
|
|
|||
|
// Remark: t-Types(for example tBool, tUInt32) are keeped for compliance with old versions
|
|||
|
|
|||
|
basic_type = new HeaderBasicType("bool", 1, 8);
|
|||
|
types->push_back(basic_type);
|
|||
|
types->push_back(new HeaderTypedef("tBool", basic_type));
|
|||
|
|
|||
|
basic_type = new HeaderBasicType("char", 1, 8);
|
|||
|
types->push_back(basic_type);
|
|||
|
types->push_back(new HeaderTypedef("tChar", basic_type));
|
|||
|
|
|||
|
basic_type = new HeaderBasicType("uint8_t", 1, 8);
|
|||
|
types->push_back(basic_type);
|
|||
|
types->push_back(new HeaderTypedef("unsigned char", basic_type));
|
|||
|
types->push_back(new HeaderTypedef("tUInt8", basic_type));
|
|||
|
types->push_back(new HeaderTypedef("uint_least8_t", basic_type));
|
|||
|
types->push_back(new HeaderTypedef("uint_least8_t", basic_type));
|
|||
|
types->push_back(new HeaderTypedef("uint_fast8_t", basic_type));
|
|||
|
|
|||
|
basic_type = new HeaderBasicType("int8_t", 1, 8);
|
|||
|
types->push_back(basic_type);
|
|||
|
types->push_back(new HeaderTypedef("signed char", basic_type));
|
|||
|
types->push_back(new HeaderTypedef("char", basic_type));
|
|||
|
types->push_back(new HeaderTypedef("tInt8", basic_type));
|
|||
|
types->push_back(new HeaderTypedef("int_least8_t", basic_type));
|
|||
|
types->push_back(new HeaderTypedef("int_least8_t", basic_type));
|
|||
|
types->push_back(new HeaderTypedef("int_fast8_t", basic_type));
|
|||
|
|
|||
|
basic_type = new HeaderBasicType("uint16_t", 2, 16);
|
|||
|
types->push_back(basic_type);
|
|||
|
types->push_back(new HeaderTypedef("unsigned short", basic_type));
|
|||
|
types->push_back(new HeaderTypedef("tUInt16", basic_type));
|
|||
|
types->push_back(new HeaderTypedef("uint_least16_t", basic_type));
|
|||
|
|
|||
|
basic_type = new HeaderBasicType("int16_t", 2, 16);
|
|||
|
types->push_back(basic_type);
|
|||
|
types->push_back(new HeaderTypedef("signed short", basic_type));
|
|||
|
types->push_back(new HeaderTypedef("short", basic_type));
|
|||
|
types->push_back(new HeaderTypedef("tInt16", basic_type));
|
|||
|
types->push_back(new HeaderTypedef("int_least16_t", basic_type));
|
|||
|
|
|||
|
basic_type = new HeaderBasicType("uint32_t", 4, 32);
|
|||
|
types->push_back(basic_type);
|
|||
|
#ifdef __ADTF32
|
|||
|
types->push_back(new HeaderTypedef("unsigned long", basic_type));
|
|||
|
#endif
|
|||
|
types->push_back(new HeaderTypedef("unsigned int", basic_type));
|
|||
|
types->push_back(new HeaderTypedef("tUInt32", basic_type));
|
|||
|
types->push_back(new HeaderTypedef("uint_least32_t", basic_type));
|
|||
|
types->push_back(new HeaderTypedef("uint_fast16_t", basic_type));
|
|||
|
types->push_back(new HeaderTypedef("uint_fast32_t", basic_type));
|
|||
|
|
|||
|
basic_type = new HeaderBasicType("int32_t", 4, 32);
|
|||
|
types->push_back(basic_type);
|
|||
|
#ifdef __ADTF32
|
|||
|
types->push_back(new HeaderTypedef("signed long", basic_type));
|
|||
|
types->push_back(new HeaderTypedef("long", basic_type));
|
|||
|
#endif
|
|||
|
types->push_back(new HeaderTypedef("signed int", basic_type));
|
|||
|
types->push_back(new HeaderTypedef("int", basic_type));
|
|||
|
types->push_back(new HeaderTypedef("tInt32", basic_type));
|
|||
|
types->push_back(new HeaderTypedef("int_least32_t", basic_type));
|
|||
|
types->push_back(new HeaderTypedef("int_fast16_t", basic_type));
|
|||
|
types->push_back(new HeaderTypedef("int_fast32_t", basic_type));
|
|||
|
|
|||
|
basic_type = new HeaderBasicType("uint64_t", 8, 64);
|
|||
|
types->push_back(basic_type);
|
|||
|
types->push_back(new HeaderTypedef("unsigned long", basic_type));
|
|||
|
types->push_back(new HeaderTypedef("unsigned long long", basic_type));
|
|||
|
types->push_back(new HeaderTypedef("unsigned __int64", basic_type));
|
|||
|
types->push_back(new HeaderTypedef("tUInt64", basic_type));
|
|||
|
types->push_back(new HeaderTypedef("uint_least64_t", basic_type));
|
|||
|
types->push_back(new HeaderTypedef("uint_least64_t", basic_type));
|
|||
|
|
|||
|
basic_type = new HeaderBasicType("int64_t", 8, 64);
|
|||
|
types->push_back(basic_type);
|
|||
|
types->push_back(new HeaderTypedef("signed long", basic_type));
|
|||
|
types->push_back(new HeaderTypedef("long", basic_type));
|
|||
|
types->push_back(new HeaderTypedef("signed long long", basic_type));
|
|||
|
types->push_back(new HeaderTypedef("long long", basic_type));
|
|||
|
types->push_back(new HeaderTypedef("signed __int64", basic_type));
|
|||
|
types->push_back(new HeaderTypedef("__int64", basic_type));
|
|||
|
types->push_back(new HeaderTypedef("tInt64", basic_type));
|
|||
|
types->push_back(new HeaderTypedef("int_least64_t", basic_type));
|
|||
|
types->push_back(new HeaderTypedef("int_least64_t", basic_type));
|
|||
|
|
|||
|
basic_type = new HeaderBasicType("float", 4, 32);
|
|||
|
types->push_back(basic_type);
|
|||
|
types->push_back(new HeaderTypedef("tFloat32", basic_type));
|
|||
|
|
|||
|
basic_type = new HeaderBasicType("double", 8, 64);
|
|||
|
|
|||
|
types->push_back(basic_type);
|
|||
|
types->push_back(new HeaderTypedef("tFloat64", basic_type));
|
|||
|
|
|||
|
// tFloat128 is not supported, because type is deprecated
|
|||
|
/*basic_type = new HeaderBasicType("tFloat128", 4, 128);
|
|||
|
types->push_back(basic_type);
|
|||
|
types->push_back(new HeaderTypedef("long double", basic_type));*/
|
|||
|
|
|||
|
return types;
|
|||
|
}
|
|||
|
|
|||
|
Header * HeaderImporter::getHeader()
|
|||
|
{
|
|||
|
return _header;
|
|||
|
}
|
|||
|
|
|||
|
a_util::result::Result HeaderImporter::createNew()
|
|||
|
{
|
|||
|
if (_header_source == "" && _input_file.getLastElement().isEmpty())
|
|||
|
{
|
|||
|
return ERR_NOT_INITIALISED;
|
|||
|
}
|
|||
|
if (!_input_file.getLastElement().isEmpty())
|
|||
|
{
|
|||
|
if (a_util::filesystem::readTextFile(_input_file, _header_source) != a_util::filesystem::OK)
|
|||
|
{
|
|||
|
return (ERR_FAILED);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
_last_error = "";
|
|||
|
// Old header will not be destroyed since caller is responsible for the pointer.
|
|||
|
_header = new Header();
|
|||
|
_header->setName(_input_file.getLastElement());
|
|||
|
if (isFailed((BuildTypedefs())))
|
|||
|
{
|
|||
|
return ERR_FAILED;
|
|||
|
}
|
|||
|
if (isFailed((BuildConstants())))
|
|||
|
{
|
|||
|
return ERR_FAILED;
|
|||
|
}
|
|||
|
if (isFailed(buildEnums()))
|
|||
|
{
|
|||
|
return ERR_FAILED;
|
|||
|
}
|
|||
|
if (isFailed((buildStructs())))
|
|||
|
{
|
|||
|
return ERR_FAILED;
|
|||
|
}
|
|||
|
if (_last_error.length() > 0)
|
|||
|
{
|
|||
|
return ERR_FAILED;
|
|||
|
}
|
|||
|
return ERR_NOERROR;
|
|||
|
}
|
|||
|
|
|||
|
a_util::result::Result HeaderImporter::DestroyHeader()
|
|||
|
{
|
|||
|
delete _header;
|
|||
|
return ERR_NOERROR;
|
|||
|
}
|
|||
|
|
|||
|
a_util::result::Result HeaderImporter::BuildTypedefs()
|
|||
|
{
|
|||
|
if (_header == NULL)
|
|||
|
{
|
|||
|
return ERR_POINTER;
|
|||
|
}
|
|||
|
const char* pos = _header_source.c_str();
|
|||
|
while (*pos != '\0')
|
|||
|
{
|
|||
|
std::string next_word = HeaderParserHelper::getNextCodeElement(pos);
|
|||
|
if (next_word == "typedef")
|
|||
|
{
|
|||
|
std::string original_name;
|
|||
|
std::string new_name;
|
|||
|
std::string token;
|
|||
|
if (a_util::result::isOk(parseTypedef(pos, token, original_name, new_name)))
|
|||
|
{
|
|||
|
const HeaderType* original_type = findKnownType(original_name);
|
|||
|
if (original_type != NULL)
|
|||
|
{
|
|||
|
HeaderTypedef* new_type = new HeaderTypedef(new_name, original_type);
|
|||
|
_header->addTypedef(new_type);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
addErrorDescription(std::string("Unknown type name: ").append(original_name), pos);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
return ERR_NOERROR;
|
|||
|
}
|
|||
|
|
|||
|
a_util::result::Result HeaderImporter::BuildConstants()
|
|||
|
{
|
|||
|
if (_header == NULL)
|
|||
|
{
|
|||
|
return ERR_POINTER;
|
|||
|
}
|
|||
|
|
|||
|
// Only constants with integers as values will be accepted, since they are needed for the size of arrays.
|
|||
|
// Buildup of a constant:
|
|||
|
// const Type Name = number;
|
|||
|
// #define NAME number
|
|||
|
const char* pos = _header_source.c_str();
|
|||
|
while (*pos != '\0')
|
|||
|
{
|
|||
|
std::string next_word = HeaderParserHelper::getNextCodeElement(pos);
|
|||
|
if (next_word == "const")
|
|||
|
{
|
|||
|
next_word = HeaderParserHelper::getNextCodeElement(pos);
|
|||
|
if (HeaderParserHelper::isValidName(next_word))
|
|||
|
{
|
|||
|
std::string type_name = next_word;
|
|||
|
if (type_name == "signed" || type_name == "unsigned")
|
|||
|
{
|
|||
|
next_word = HeaderParserHelper::getNextCodeElement(pos);
|
|||
|
type_name.append(" ");
|
|||
|
type_name.append(next_word);
|
|||
|
}
|
|||
|
// Look for the type in the list of known types.
|
|||
|
const HeaderType* type = findKnownType(next_word);
|
|||
|
next_word = HeaderParserHelper::getNextCodeElement(pos);
|
|||
|
// Pointers will be ignored, so next element has to be the variable name
|
|||
|
if (HeaderParserHelper::isValidName(next_word))
|
|||
|
{
|
|||
|
std::string name = next_word;
|
|||
|
next_word = HeaderParserHelper::getNextCodeElement(pos);
|
|||
|
if (next_word == "=")
|
|||
|
{
|
|||
|
next_word = HeaderParserHelper::getNextCodeElement(pos);
|
|||
|
// Anything but integers will be ignored since constants are only only useful for the parser,
|
|||
|
// if an array size refers to them.
|
|||
|
if (a_util::strings::isInt64(next_word))
|
|||
|
{
|
|||
|
int64_t value = a_util::strings::toInt64(next_word);
|
|||
|
next_word = HeaderParserHelper::getNextCodeElement(pos);
|
|||
|
// No fancy values like 34+32 or 866+other_const will be accepted at the moment, so we expect a semicolon now.
|
|||
|
if (next_word == ";")
|
|||
|
{
|
|||
|
//Yeah! We found a constant with an int.
|
|||
|
HeaderConstant* constant = new HeaderConstant();
|
|||
|
constant->setName(name);
|
|||
|
constant->setType(type);
|
|||
|
constant->reset(value);
|
|||
|
_header->addConstant(constant);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
else if (next_word == "#")
|
|||
|
{
|
|||
|
next_word = HeaderParserHelper::getNextCodeElement(pos);
|
|||
|
if (next_word == "define")
|
|||
|
{
|
|||
|
// Look for end of line (ignoring multiline defines)
|
|||
|
const char* eol_pos = pos;
|
|||
|
HeaderParserHelper::skipEOL(eol_pos);
|
|||
|
next_word = HeaderParserHelper::getNextCodeElement(pos);
|
|||
|
std::string const_name = next_word;
|
|||
|
// Still same line?
|
|||
|
if (pos <= eol_pos)
|
|||
|
{
|
|||
|
const char* tmp_pos = pos;
|
|||
|
|
|||
|
// a #define doesn't necessarily have a value. so maybe
|
|||
|
// we're already in the next line and mistakenly analyze
|
|||
|
// the next statement already. this most likely breaks the
|
|||
|
// parsing process, because this "next_word" would be lost.
|
|||
|
// so don't consume the next word until we're sure to have a
|
|||
|
// value
|
|||
|
next_word = HeaderParserHelper::getNextCodeElement(tmp_pos);
|
|||
|
if (tmp_pos <= eol_pos)
|
|||
|
{
|
|||
|
// everything ok, go on exploring this header
|
|||
|
next_word = HeaderParserHelper::getNextCodeElement(pos);
|
|||
|
}
|
|||
|
|
|||
|
// Still same line? Did we find an int?
|
|||
|
if (pos <= eol_pos && a_util::strings::isInt64(next_word))
|
|||
|
{
|
|||
|
int64_t value = a_util::strings::toInt64(next_word);
|
|||
|
// Check if the next word is not in the same line anymore or eof is reached.
|
|||
|
// Allowed is only /*...*/ comments.
|
|||
|
// We must not increase pos, since otherwise a "#define" or "const"
|
|||
|
// from the next line could be skipped.
|
|||
|
next_word = HeaderParserHelper::getNextElement(tmp_pos);
|
|||
|
while (tmp_pos < eol_pos && next_word == "/*")
|
|||
|
{
|
|||
|
HeaderParserHelper::skipComment(tmp_pos, next_word);
|
|||
|
next_word = HeaderParserHelper::getNextElement(tmp_pos);
|
|||
|
}
|
|||
|
if (tmp_pos > eol_pos || *tmp_pos == '\0')
|
|||
|
{
|
|||
|
const HeaderType* type = findKnownType("tUInt64");
|
|||
|
if (_default_type != NULL)
|
|||
|
{
|
|||
|
type = _default_type;
|
|||
|
}
|
|||
|
if (type != NULL)
|
|||
|
{
|
|||
|
HeaderConstant* constant = new HeaderConstant();
|
|||
|
constant->setName(const_name);
|
|||
|
constant->setType(type);
|
|||
|
constant->reset(value);
|
|||
|
_header->addConstant(constant);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
return ERR_NOERROR;
|
|||
|
}
|
|||
|
|
|||
|
a_util::result::Result HeaderImporter::buildStructs()
|
|||
|
{
|
|||
|
// The following types of definitions will raise our parsing attention:
|
|||
|
// 1. struct original_name {..};
|
|||
|
// 2. typedef struct {..} typedef_name;
|
|||
|
// 3. typedef struct original_name {..} typedef_name;
|
|||
|
// #3 will result in a type entry and a typedef entry in the header, since both names refer to the same type
|
|||
|
// Not supported are unnamed structs, like the following:
|
|||
|
// 4. struct {..} name;
|
|||
|
// 5. struct {..};
|
|||
|
// 6. typedef struct {..};
|
|||
|
const char* pos = _header_source.c_str();
|
|||
|
// This pack information could be extracted as a configurable setting later
|
|||
|
std::vector<size_t> pack_stack;
|
|||
|
// Set default packing depending n compiler used
|
|||
|
#if defined(_MSC_VER) || (defined(__GNUC__) && defined(__ADTF64))
|
|||
|
pack_stack.push_back(8);
|
|||
|
#else
|
|||
|
#if defined(__GNUC__) & defined(__ADTF32)
|
|||
|
pack_stack.push_back(4);
|
|||
|
#else
|
|||
|
//unknown compiler / platform
|
|||
|
pack_stack.push_back(4);
|
|||
|
#endif
|
|||
|
#endif
|
|||
|
while (*pos != '\0')
|
|||
|
{
|
|||
|
char tmp = *pos;
|
|||
|
bool is_typedef = false;
|
|||
|
std::string next_word = HeaderParserHelper::getNextCodeElement(pos);
|
|||
|
// Packing identification
|
|||
|
if (next_word == "#")
|
|||
|
{
|
|||
|
next_word = HeaderParserHelper::getNextCodeElement(pos);
|
|||
|
if (next_word == "pragma")
|
|||
|
{
|
|||
|
next_word = HeaderParserHelper::getNextCodeElement(pos);
|
|||
|
if (next_word == "pack")
|
|||
|
{
|
|||
|
next_word = HeaderParserHelper::getNextCodeElement(pos);
|
|||
|
if (next_word == "(")
|
|||
|
{
|
|||
|
std::string command;
|
|||
|
next_word = HeaderParserHelper::getNextCodeElement(pos);
|
|||
|
if (!a_util::strings::isInt64(next_word))
|
|||
|
{
|
|||
|
if (next_word == "push" || next_word == "pop")
|
|||
|
{
|
|||
|
command = next_word;
|
|||
|
next_word = HeaderParserHelper::getNextCodeElement(pos);
|
|||
|
if (next_word == ",")
|
|||
|
{
|
|||
|
next_word = HeaderParserHelper::getNextCodeElement(pos);
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
addErrorDescription("Cannot parse pragma, only push and pop are supported.", pos);
|
|||
|
}
|
|||
|
}
|
|||
|
if (command == "pop")
|
|||
|
{
|
|||
|
if (next_word == ")")
|
|||
|
{
|
|||
|
if (pack_stack.size() > 1)
|
|||
|
{
|
|||
|
pack_stack.pop_back();
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
addErrorDescription("Too many pragma pop.", pos);
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
addErrorDescription("Pragma pop is missing a closing parenthesis.", pos);
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
if (a_util::strings::isInt64(next_word))
|
|||
|
{
|
|||
|
if (command == "")
|
|||
|
{
|
|||
|
pack_stack[pack_stack.size() - 1] = a_util::strings::toInt64(next_word);
|
|||
|
}
|
|||
|
else if (command == "push")
|
|||
|
{
|
|||
|
pack_stack.push_back(a_util::strings::toInt64(next_word));
|
|||
|
}
|
|||
|
else {
|
|||
|
addErrorDescription(a_util::strings::format("Unknown pragma command %s.", command.c_str()), pos);
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
addErrorDescription("Unknown value found within pragma, expected a number.", pos);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
// Check for typedef of #2 or #3
|
|||
|
if (next_word == "typedef")
|
|||
|
{
|
|||
|
is_typedef = true;
|
|||
|
next_word = HeaderParserHelper::getNextCodeElement(pos);
|
|||
|
}
|
|||
|
// Check for #1 - #3
|
|||
|
if (next_word == "struct")
|
|||
|
{
|
|||
|
next_word = HeaderParserHelper::getNextCodeElement(pos);
|
|||
|
// Check for #1 or #3
|
|||
|
std::string original_name;
|
|||
|
std::string typedef_name;
|
|||
|
if (next_word != "{")
|
|||
|
{
|
|||
|
original_name = next_word;
|
|||
|
next_word = HeaderParserHelper::getNextCodeElement(pos);
|
|||
|
}
|
|||
|
if (next_word == "{")
|
|||
|
{
|
|||
|
HeaderStructElementVec elements = extractStructElements(pos);
|
|||
|
next_word = HeaderParserHelper::getNextCodeElement(pos);
|
|||
|
if (next_word != ";")
|
|||
|
{
|
|||
|
if (!is_typedef)
|
|||
|
{
|
|||
|
addErrorDescription("Cannot parse struct.", pos);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
//check for #2 or #3
|
|||
|
if (HeaderParserHelper::isValidName(next_word))
|
|||
|
{
|
|||
|
typedef_name = next_word;
|
|||
|
next_word = HeaderParserHelper::getNextCodeElement(pos);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
addErrorDescription("The typedef struct is unreadable.", pos);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
HeaderStruct* header_struct = new HeaderStruct();
|
|||
|
if (original_name.size() != 0)
|
|||
|
{
|
|||
|
header_struct->setName(original_name);
|
|||
|
if (is_typedef && typedef_name.size() != 0)
|
|||
|
{
|
|||
|
_header->addTypedef(new HeaderTypedef(typedef_name, header_struct));
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
header_struct->setName(typedef_name);
|
|||
|
}
|
|||
|
// Check for not #4 - #6
|
|||
|
if (header_struct->getName().size() != 0 && !(is_typedef && typedef_name.size() == 0))
|
|||
|
{
|
|||
|
for (HeaderStructElementVec::const_iterator iter = elements.begin(); iter != elements.end(); iter++)
|
|||
|
{
|
|||
|
header_struct->addElement(*iter);
|
|||
|
}
|
|||
|
// Set current packing within struct if current packing is smaller than the native packing of the struct
|
|||
|
if (header_struct->getPacking() > pack_stack.back())
|
|||
|
{
|
|||
|
header_struct->setPacking(pack_stack.back());
|
|||
|
}
|
|||
|
_header->addStruct(header_struct);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
addErrorDescription("Cannot interpret this struct, no name given.", pos);
|
|||
|
// Clean up allocated memory
|
|||
|
delete header_struct;
|
|||
|
for (HeaderStructElementVec::const_iterator iter = elements.begin(); iter != elements.end(); iter++)
|
|||
|
{
|
|||
|
delete *iter;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
addErrorDescription("Cannot interpret this struct.", pos);
|
|||
|
return ERR_UNKNOWN_FORMAT;
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
// No typedef for a struct it seems.
|
|||
|
}
|
|||
|
}
|
|||
|
return ERR_NOERROR;
|
|||
|
}
|
|||
|
|
|||
|
a_util::result::Result HeaderImporter::buildEnums()
|
|||
|
{
|
|||
|
// The following types of definitions will raise our parsing attention:
|
|||
|
// 1. enum original_name {..};
|
|||
|
// 2. typedef enum {..} typedef_name;
|
|||
|
// 3. typedef enum original_name {..} typedef_name;
|
|||
|
// #3 will result in a type entry and a typedef entry in the header, since both names refer to the same type
|
|||
|
// Not supported are unnamed enums, like the following:
|
|||
|
// 4. enum {..} name;
|
|||
|
// 5. enum {..};
|
|||
|
// 6. typedef enum {..};
|
|||
|
const char* pos = _header_source.c_str();
|
|||
|
|
|||
|
while (*pos != '\0')
|
|||
|
{
|
|||
|
char tmp = *pos;
|
|||
|
bool is_typedef = false;
|
|||
|
std::string next_word = HeaderParserHelper::getNextCodeElement(pos);
|
|||
|
|
|||
|
// Check for typedef of #2 or #3
|
|||
|
if (next_word == "typedef")
|
|||
|
{
|
|||
|
is_typedef = true;
|
|||
|
next_word = HeaderParserHelper::getNextCodeElement(pos);
|
|||
|
}
|
|||
|
// Check for #1 - #3
|
|||
|
if (next_word == "enum")
|
|||
|
{
|
|||
|
next_word = HeaderParserHelper::getNextCodeElement(pos);
|
|||
|
// Check for #1 or #3
|
|||
|
std::string original_name;
|
|||
|
std::string typedef_name;
|
|||
|
if (next_word != "{")
|
|||
|
{
|
|||
|
original_name = next_word;
|
|||
|
next_word = HeaderParserHelper::getNextCodeElement(pos);
|
|||
|
}
|
|||
|
if (next_word == "{")
|
|||
|
{
|
|||
|
HeaderEnumValueMap enum_values = extractEnumValues(pos);
|
|||
|
next_word = HeaderParserHelper::getNextCodeElement(pos);
|
|||
|
if (next_word != ";")
|
|||
|
{
|
|||
|
if (!is_typedef)
|
|||
|
{
|
|||
|
addErrorDescription("Cannot parse enum.", pos);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
//check for #2 or #3
|
|||
|
if (HeaderParserHelper::isValidName(next_word))
|
|||
|
{
|
|||
|
typedef_name = next_word;
|
|||
|
next_word = HeaderParserHelper::getNextCodeElement(pos);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
addErrorDescription("The typedef enum is unreadable.", pos);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
HeaderEnum* header_enum = new HeaderEnum();
|
|||
|
if (original_name.size() != 0)
|
|||
|
{
|
|||
|
header_enum->setName(original_name);
|
|||
|
if (is_typedef && typedef_name.size() != 0)
|
|||
|
{
|
|||
|
_header->addTypedef(new HeaderTypedef(typedef_name, header_enum));
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
header_enum->setName(typedef_name);
|
|||
|
}
|
|||
|
// Check for not #4 - #6
|
|||
|
if (header_enum->getName().size() != 0)
|
|||
|
{
|
|||
|
for (auto iter = enum_values.begin(); iter != enum_values.end(); iter++)
|
|||
|
{
|
|||
|
header_enum->addValue(iter->first, iter->second);
|
|||
|
}
|
|||
|
_header->addEnum(header_enum);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
addErrorDescription("Cannot interpret this enum, no name given.", pos);
|
|||
|
// Clean up allocated memory
|
|||
|
delete header_enum;
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
addErrorDescription("Cannot interpret this enum.", pos);
|
|||
|
return ERR_UNKNOWN_FORMAT;
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
// No typedef for a enum it seems.
|
|||
|
}
|
|||
|
}
|
|||
|
return ERR_NOERROR;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
const std::string& HeaderImporter::getLastError() const
|
|||
|
{
|
|||
|
return _last_error;
|
|||
|
}
|
|||
|
|
|||
|
const HeaderType* HeaderImporter::findKnownType(const std::string &name) const
|
|||
|
{
|
|||
|
const HeaderType* type = NULL;
|
|||
|
// Search for name in know types
|
|||
|
for (HeaderTypesVec::const_iterator iter = _types->begin(); iter != _types->end(); iter++)
|
|||
|
{
|
|||
|
if ((*iter)->getName() == name)
|
|||
|
{
|
|||
|
type = *iter;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
if (type == NULL)
|
|||
|
{
|
|||
|
// If not found in the known types, look in the already parsed typedefs for the type.
|
|||
|
const HeaderTypedefs typedefs = _header->getTypedefs();
|
|||
|
for (HeaderTypedefs::const_iterator iter = typedefs.begin(); iter != typedefs.end(); iter++)
|
|||
|
{
|
|||
|
if ((*iter)->getName() == name)
|
|||
|
{
|
|||
|
type = *iter;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
if (type == NULL)
|
|||
|
{
|
|||
|
// If not found in the already parsed typedefs, look in the already parsed structs for the type.
|
|||
|
const HeaderStructs structs = _header->getStructs();
|
|||
|
for (HeaderStructs::const_iterator iter = structs.begin(); iter != structs.end(); iter++)
|
|||
|
{
|
|||
|
if ((*iter)->getName() == name)
|
|||
|
{
|
|||
|
type = *iter;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
if (type == NULL)
|
|||
|
{
|
|||
|
// If not found in the already parsed typedefs or structs look in the already parsed enums for the type.
|
|||
|
const HeaderEnums enums = _header->getEnums();
|
|||
|
for (auto iter = enums.begin(); iter != enums.end(); iter++)
|
|||
|
{
|
|||
|
if ((*iter)->getName() == name)
|
|||
|
{
|
|||
|
type = *iter;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
return type;
|
|||
|
}
|
|||
|
|
|||
|
HeaderStructElementVec HeaderImporter::extractStructElements(const char* &pos)
|
|||
|
{
|
|||
|
// Copied over from the adtfcodec/cc_header.cpp implementation
|
|||
|
// modified to fit current requirements.
|
|||
|
std::string next_element;
|
|||
|
std::set<std::string> structs;
|
|||
|
HeaderStructElementVec elements;
|
|||
|
|
|||
|
while (*pos != '\0')
|
|||
|
{
|
|||
|
next_element = HeaderParserHelper::getNextCodeElement(pos);
|
|||
|
if (next_element.compare("}") == 0)
|
|||
|
{
|
|||
|
break;
|
|||
|
}
|
|||
|
// Extract type
|
|||
|
std::string type_name = next_element;
|
|||
|
if (!HeaderParserHelper::isValidName(type_name))
|
|||
|
{
|
|||
|
addErrorDescription(std::string("Unexpected string ").append(type_name), pos);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
if (type_name == "signed" || type_name == "unsigned")
|
|||
|
{
|
|||
|
next_element = HeaderParserHelper::getNextCodeElement(pos);
|
|||
|
if (HeaderParserHelper::isValidName(next_element))
|
|||
|
{
|
|||
|
type_name.append(" ");
|
|||
|
type_name.append(next_element);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
addErrorDescription(std::string("Unexpected string ").append(type_name), pos);
|
|||
|
HeaderParserHelper::exitBlock(pos);
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
const HeaderType* type = findKnownType(type_name);
|
|||
|
if (type != NULL)
|
|||
|
{
|
|||
|
// Type successfully identified, try to extract member name
|
|||
|
next_element = HeaderParserHelper::getNextCodeElement(pos);
|
|||
|
// No pointer support yet
|
|||
|
if (next_element == "*")
|
|||
|
{
|
|||
|
addErrorDescription("No pointers supported yet", pos);
|
|||
|
HeaderParserHelper::exitBlock(pos);
|
|||
|
break;
|
|||
|
}
|
|||
|
if (!HeaderParserHelper::isValidName(next_element))
|
|||
|
{
|
|||
|
addErrorDescription(std::string("Invalid member name ").append(next_element), pos);
|
|||
|
HeaderParserHelper::exitBlock(pos);
|
|||
|
break;
|
|||
|
}
|
|||
|
std::string element_name = next_element;
|
|||
|
// try to extract array info
|
|||
|
size_t len = 1;
|
|||
|
next_element = HeaderParserHelper::getNextCodeElement(pos);
|
|||
|
if (next_element == "[")
|
|||
|
{
|
|||
|
next_element = HeaderParserHelper::getNextCodeElement(pos);
|
|||
|
if (!a_util::strings::isInt64(next_element))
|
|||
|
{
|
|||
|
// Is it a constant`?
|
|||
|
if (HeaderParserHelper::isValidName(next_element))
|
|||
|
{
|
|||
|
bool found = false;
|
|||
|
HeaderConstants constants = _header->getConstants();
|
|||
|
for (HeaderConstants::const_iterator iter = constants.begin(); iter != constants.end(); iter++)
|
|||
|
{
|
|||
|
if ((*iter)->getName() == next_element)
|
|||
|
{
|
|||
|
found = true;
|
|||
|
if ((*iter)->asInt64() > 0)
|
|||
|
{
|
|||
|
len = (*iter)->asInt64();
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
addErrorDescription("Array size type is not int", pos);
|
|||
|
HeaderParserHelper::exitBlock(pos);
|
|||
|
break;
|
|||
|
}
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
if (!found)
|
|||
|
{
|
|||
|
addErrorDescription("Array size value could not be found", pos);
|
|||
|
HeaderParserHelper::exitBlock(pos);
|
|||
|
break;
|
|||
|
}
|
|||
|
next_element = HeaderParserHelper::getNextCodeElement(pos);
|
|||
|
if (next_element != "]")
|
|||
|
{
|
|||
|
addErrorDescription(std::string("Unexpected string ").append(next_element), pos);
|
|||
|
}
|
|||
|
next_element = HeaderParserHelper::getNextCodeElement(pos);
|
|||
|
if (next_element != ";")
|
|||
|
{
|
|||
|
addErrorDescription(std::string("Unexpected string ").append(next_element), pos);
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
addErrorDescription(std::string("Invalid array size ").append(next_element), pos);
|
|||
|
HeaderParserHelper::exitBlock(pos);
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
len = a_util::strings::toInt32(next_element);
|
|||
|
next_element = HeaderParserHelper::getNextCodeElement(pos);
|
|||
|
if (next_element != "]")
|
|||
|
{
|
|||
|
addErrorDescription(std::string("Unexpected string ").append(next_element), pos);
|
|||
|
}
|
|||
|
next_element = HeaderParserHelper::getNextCodeElement(pos);
|
|||
|
if (next_element != ";")
|
|||
|
{
|
|||
|
addErrorDescription(std::string("Unexpected string ").append(next_element), pos);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
else if (next_element != ";")
|
|||
|
{
|
|||
|
addErrorDescription(std::string("Missing ; at end of struct member"), pos);
|
|||
|
HeaderParserHelper::exitBlock(pos);
|
|||
|
break;
|
|||
|
}
|
|||
|
HeaderStructElement* element = new HeaderStructElement();
|
|||
|
element->setType(type);
|
|||
|
element->setName(element_name);
|
|||
|
element->setArraySize(len);
|
|||
|
// No pointer element recognition implemented yet
|
|||
|
element->setIsPointer(false);
|
|||
|
// No static element recognition implemented yet
|
|||
|
element->setIsStatic(false);
|
|||
|
// No const element recognition implemented yet
|
|||
|
element->setIsConst(false);
|
|||
|
elements.push_back(element);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
addErrorDescription(std::string("Unknown type name: ").append(type_name), pos);
|
|||
|
do
|
|||
|
{
|
|||
|
next_element = HeaderParserHelper::getNextCodeElement(pos);
|
|||
|
} while (next_element != ";" && next_element != "}");
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
return elements;
|
|||
|
}
|
|||
|
|
|||
|
a_util::result::Result HeaderImporter::addErrorDescription(const std::string &description, const char* pos)
|
|||
|
{
|
|||
|
const char* search_pos = _header_source.c_str();
|
|||
|
uint64_t line_number = 1;
|
|||
|
while (*search_pos != '\0')
|
|||
|
{
|
|||
|
if (search_pos >= pos)
|
|||
|
{
|
|||
|
break;
|
|||
|
}
|
|||
|
else if (*search_pos == '\n')
|
|||
|
{
|
|||
|
line_number++;
|
|||
|
}
|
|||
|
search_pos++;
|
|||
|
}
|
|||
|
if (_last_error.size() != 0)
|
|||
|
{
|
|||
|
_last_error.append("\n");
|
|||
|
}
|
|||
|
_last_error.append(a_util::strings::format("Error: \"%s\" at Line %d", description.c_str(), line_number));
|
|||
|
return ERR_NOERROR;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
a_util::result::Result HeaderImporter::parseTypedef(const char* &pos, std::string &token, std::string &original_type_name, std::string& new_type_name)
|
|||
|
{
|
|||
|
// We found a possible candidate for a new typedef
|
|||
|
// We can have the following cases:
|
|||
|
// 1 typedef token{...
|
|||
|
// 2 typedef token {...
|
|||
|
// 3 typedef token Bla{...
|
|||
|
// 4 typedef token Bla {...
|
|||
|
// 5 typedef token Bla Blubb;
|
|||
|
// 6 typedef Bla Blubb;
|
|||
|
// We are looking only for the last two.
|
|||
|
const char* working_pos = pos;
|
|||
|
std::string local_token;
|
|||
|
// Check if first word if its a token
|
|||
|
std::string next_word = HeaderParserHelper::getNextCodeElement(working_pos);
|
|||
|
for (uint64_t idx = 0; idx < AMOUNT_OF_TOKENS; idx++)
|
|||
|
{
|
|||
|
if (g_tokens[idx] == next_word)
|
|||
|
{
|
|||
|
local_token = next_word;
|
|||
|
next_word = HeaderParserHelper::getNextCodeElement(working_pos);
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
// Now there have to be two valid names and one semicolon. Lets check it out!
|
|||
|
if (HeaderParserHelper::isValidName(next_word))
|
|||
|
{
|
|||
|
std::string local_original_type_name = next_word;
|
|||
|
next_word = HeaderParserHelper::getNextCodeElement(working_pos);
|
|||
|
if (HeaderParserHelper::isValidName(next_word))
|
|||
|
{
|
|||
|
std::string local_new_type_name = next_word;
|
|||
|
next_word = HeaderParserHelper::getNextCodeElement(working_pos);
|
|||
|
if (next_word.compare(";") == 0)
|
|||
|
{
|
|||
|
// Yes!!! we found a valid typedef, case #5 or #6
|
|||
|
new_type_name = local_new_type_name;
|
|||
|
original_type_name = local_original_type_name;
|
|||
|
token = local_token;
|
|||
|
pos = working_pos;
|
|||
|
return ERR_NOERROR;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
return ERR_UNKNOWN_FORMAT;
|
|||
|
}
|
|||
|
|
|||
|
HeaderEnumValueMap HeaderImporter::extractEnumValues(const char* &pos)
|
|||
|
{
|
|||
|
std::string next_element;
|
|||
|
HeaderEnumValueMap values;
|
|||
|
int32_t next_idx = 0;
|
|||
|
|
|||
|
while (*pos != '\0')
|
|||
|
{
|
|||
|
next_element = HeaderParserHelper::getNextCodeElement(pos);
|
|||
|
if (next_element.compare("}") == 0)
|
|||
|
{
|
|||
|
break;
|
|||
|
}
|
|||
|
// Extract type
|
|||
|
std::string value_name = next_element;
|
|||
|
if (!HeaderParserHelper::isValidName(value_name))
|
|||
|
{
|
|||
|
addErrorDescription(std::string("Unexpected string ").append(value_name), pos);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
next_element = HeaderParserHelper::getNextCodeElement(pos);
|
|||
|
if (next_element == "," || next_element == "}")
|
|||
|
{
|
|||
|
values[next_idx++] = value_name;
|
|||
|
}
|
|||
|
else if (next_element == "=")
|
|||
|
{
|
|||
|
std::string index = HeaderParserHelper::getNextCodeElement(pos);
|
|||
|
if (index == "-")
|
|||
|
{
|
|||
|
index += HeaderParserHelper::getNextCodeElement(pos);
|
|||
|
}
|
|||
|
int32_t idx = a_util::strings::toInt32(index);
|
|||
|
if (values.count(idx) > 0)
|
|||
|
{
|
|||
|
addErrorDescription(std::string("Duplicate value in enum ").append(index), pos);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
values[idx] = value_name;
|
|||
|
next_idx = (std::max)(++next_idx, ++idx); //extra parantheses since msvc defines a max macro somewhere...
|
|||
|
}
|
|||
|
|
|||
|
next_element = HeaderParserHelper::getNextCodeElement(pos);
|
|||
|
if (next_element != "," && next_element != "}")
|
|||
|
{
|
|||
|
addErrorDescription(std::string("Unexpected token ").append(next_element), pos);
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
addErrorDescription(std::string("Unexpected token ").append(next_element), pos);
|
|||
|
}
|
|||
|
|
|||
|
if (next_element == "}")
|
|||
|
{
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
return values;
|
|||
|
}
|
|||
|
|
|||
|
} //namespace ddl
|