ddl/ddlgenerators/generator_library/headerrepresentation/header_importer.cpp
2019-12-12 14:41:47 +01:00

1325 lines
52 KiB
C++
Raw Blame History

/**
* @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