1017 lines
33 KiB
C++
1017 lines
33 KiB
C++
// **************************************************************************
|
|
//
|
|
// (C) Copyright 2009 Swiss SIMTEC AG
|
|
//
|
|
// **************************************************************************
|
|
//
|
|
// $HeadURL$
|
|
// $LastChangedBy$
|
|
// $LastChangedDate$
|
|
// $LastChangedRevision$
|
|
//
|
|
// **************************************************************************
|
|
|
|
// manual class headers
|
|
#include "LogViewXdrParser.hpp"
|
|
|
|
// from cpp_includes
|
|
#include "LogViewXdrElement.hpp"
|
|
#include <QMessageBox>
|
|
#include "LogViewXdrStruct.hpp"
|
|
#include "LogViewField.hpp"
|
|
#include "LogViewXdrValue.hpp"
|
|
#include "LogViewXdrType.hpp"
|
|
|
|
#include <QFile>
|
|
#include <QTextStream>
|
|
#include <QApplication>
|
|
|
|
namespace N_LogView
|
|
{
|
|
|
|
LogViewXdrParser::LogViewXdrParser()
|
|
: m_WithinComment(false)
|
|
, m_LineNbr(0)
|
|
, m_DoReadUntilSemicolon(false)
|
|
, m_WordListIndex(0)
|
|
, m_ActElement(nullptr)
|
|
, m_State(e_ParseMain)
|
|
, m_logger(getLogger("LogViewXdrParser"))
|
|
{}
|
|
|
|
LogViewXdrParser::~LogViewXdrParser()
|
|
{
|
|
for (const auto &elem : m_ElementMap)
|
|
delete elem.second;
|
|
}
|
|
|
|
// ---------------------------------------------------------------
|
|
void LogViewXdrParser::addStandardType(const QString& a_name, const uint16_t a_dataSize, const uint16_t a_realSize, const LogViewXdrStandardType::E_ValueKind a_kind, const LogViewXdrStandardType::E_DynArraySizeMethod a_dynArraySizeMethod, const LogViewXdrStandardType::E_ByteOrder a_byteOrder)
|
|
{
|
|
QString name = a_name.trimmed();
|
|
auto ptr = new LogViewXdrStandardType(name, a_dataSize, a_realSize, a_kind, a_dynArraySizeMethod, a_byteOrder);
|
|
if (!addToElementMap(name, ptr))
|
|
delete ptr;
|
|
if ((a_dynArraySizeMethod == LogViewXdrStandardType::e_DynArrayIndex || a_dynArraySizeMethod == LogViewXdrStandardType::e_DynArrayIndexDiv8)
|
|
&& a_kind != LogViewXdrStandardType::e_Unsigned)
|
|
showErrorMessage(QObject::tr("Standard-typ \'%1\': e_DynArrayIndex oder e_DynArrayIndexDiv darf nur mit e_Unsigned verwendet werden!"));
|
|
}
|
|
|
|
|
|
// ---------------------------------------------------------------
|
|
void LogViewXdrParser::parseX_File(const QString& a_fileName)
|
|
{
|
|
for (const auto &elem : m_ElementMap)
|
|
delete elem.second;
|
|
m_ElementMap.clear();
|
|
m_DefinesMap.clear();
|
|
m_TelegramMap.clear();
|
|
m_LineNbr = 0;
|
|
m_WordListIndex = 0;
|
|
m_WithinComment = false;
|
|
m_ActElement = nullptr;
|
|
m_State = e_ParseMain;
|
|
|
|
// define some (XDR-)standard-types
|
|
addStandardType(QLatin1String("unsigned short"), 4, 2, LogViewXdrStandardType::e_Unsigned);
|
|
addStandardType(QLatin1String("unsigned int"), 4, 4, LogViewXdrStandardType::e_Unsigned);
|
|
addStandardType(QLatin1String("short"), 4, 2, LogViewXdrStandardType::e_Signed);
|
|
addStandardType(QLatin1String("int"), 4, 4, LogViewXdrStandardType::e_Signed);
|
|
addStandardType(QLatin1String("u_int"), 4, 4, LogViewXdrStandardType::e_Unsigned);
|
|
addStandardType(QLatin1String("char"), 4, 2, LogViewXdrStandardType::e_Character);
|
|
addStandardType(QLatin1String("unsigned char"), 4, 1, LogViewXdrStandardType::e_Unsigned);
|
|
addStandardType(QLatin1String("unsigned long"), 4, 4, LogViewXdrStandardType::e_Unsigned);
|
|
addStandardType(QLatin1String("u_long"), 4, 4, LogViewXdrStandardType::e_Unsigned);
|
|
addStandardType(QLatin1String("u_short"), 4, 2, LogViewXdrStandardType::e_Unsigned);
|
|
addStandardType(QLatin1String("float"), 4, 4, LogViewXdrStandardType::e_Float, LogViewXdrStandardType::e_DynArrayMsgLength, LogViewXdrStandardType::e_ByteOrderBigEndian);
|
|
addStandardType(QLatin1String("double"), 8, 8, LogViewXdrStandardType::e_Float, LogViewXdrStandardType::e_DynArrayMsgLength, LogViewXdrStandardType::e_ByteOrderBigEndian);
|
|
addStandardType(QLatin1String("opaque"), 1, 1, LogViewXdrStandardType::e_Data);
|
|
addStandardType(QLatin1String("string"), 1, 1, LogViewXdrStandardType::e_Character);
|
|
|
|
// for tetra-telegrams
|
|
addStandardType(QLatin1String("alpha"), 1, 1, LogViewXdrStandardType::e_Character);
|
|
addStandardType(QLatin1String("UInt8"), 1, 1, LogViewXdrStandardType::e_Unsigned);
|
|
addStandardType(QLatin1String("UInt16"), 2, 2, LogViewXdrStandardType::e_Unsigned);
|
|
addStandardType(QLatin1String("UInt24"), 3, 3, LogViewXdrStandardType::e_Unsigned);
|
|
addStandardType(QLatin1String("SInt8"), 1, 1, LogViewXdrStandardType::e_Signed);
|
|
addStandardType(QLatin1String("SInt16"), 2, 2, LogViewXdrStandardType::e_Signed);
|
|
addStandardType(QLatin1String("SInt24"), 3, 3, LogViewXdrStandardType::e_Signed);
|
|
// little-endian values (for TETRA-header)
|
|
addStandardType(QLatin1String("UInt16LE"), 2, 2, LogViewXdrStandardType::e_Unsigned, LogViewXdrStandardType::e_DynArrayMsgLength, LogViewXdrStandardType::e_ByteOrderLittleEndian);
|
|
addStandardType(QLatin1String("UInt32LE"), 4, 4, LogViewXdrStandardType::e_Unsigned, LogViewXdrStandardType::e_DynArrayMsgLength, LogViewXdrStandardType::e_ByteOrderLittleEndian);
|
|
// index for next dyn. array (only for TETRA)
|
|
addStandardType(QLatin1String("UInt8Idx"), 1, 1, LogViewXdrStandardType::e_Unsigned, LogViewXdrStandardType::e_DynArrayIndex);
|
|
addStandardType(QLatin1String("UInt16Idx"), 2, 2, LogViewXdrStandardType::e_Unsigned, LogViewXdrStandardType::e_DynArrayIndex);
|
|
addStandardType(QLatin1String("UInt16LEIdx"), 2, 2, LogViewXdrStandardType::e_Unsigned, LogViewXdrStandardType::e_DynArrayIndex, LogViewXdrStandardType::e_ByteOrderLittleEndian);
|
|
// index (div 8) for next dyn. array (only for TETRA)
|
|
addStandardType(QLatin1String("UInt8IdxDiv8"), 1, 1, LogViewXdrStandardType::e_Unsigned, LogViewXdrStandardType::e_DynArrayIndexDiv8);
|
|
addStandardType(QLatin1String("UInt16IdxDiv8"), 2, 2, LogViewXdrStandardType::e_Unsigned, LogViewXdrStandardType::e_DynArrayIndexDiv8);
|
|
|
|
const auto DEFINE_NAME = QLatin1String("%#define");
|
|
|
|
// parse the file
|
|
m_Filename = a_fileName;
|
|
m_State = e_ParseMain;
|
|
QFile xFile(a_fileName);
|
|
if (xFile.open(QIODevice::ReadOnly | QIODevice::Text))
|
|
{
|
|
QString lastLines;
|
|
uint32_t lastLinesCount = 0;
|
|
QTextStream in(&xFile);
|
|
while (!in.atEnd())
|
|
{
|
|
m_Line = lastLines + QLatin1Char(' ') + in.readLine();
|
|
m_Line = m_Line.simplified();
|
|
m_LineNbr++;
|
|
// INFO_LOG(m_logger) << m_LineNbr << ": " << m_Line.toStdString();
|
|
|
|
// ignore lines with %
|
|
if (m_Line.startsWith(QLatin1Char('%')) && !m_Line.startsWith(DEFINE_NAME))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// remove comments (sourounded with /* */)
|
|
const QString cleanLine = removeComments(m_Line).simplified();
|
|
|
|
// ignore empty lines
|
|
if (cleanLine.isEmpty())
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// INFO_LOG(m_logger) << "w/o comment: \'" << cleanLine.toStdString() << "\'";
|
|
// read in whole construct
|
|
if (m_DoReadUntilSemicolon && !cleanLine.endsWith(QLatin1Char(';')))
|
|
{
|
|
lastLines = cleanLine;
|
|
m_LineNbr--;
|
|
lastLinesCount++;
|
|
continue;
|
|
}
|
|
|
|
lastLines.clear();
|
|
|
|
// check whether it is the begin of a construct
|
|
if (e_ParseMain == m_State)
|
|
{
|
|
if (cleanLine.startsWith(QLatin1String("union ")))
|
|
{
|
|
m_State = e_ParseUnion;
|
|
}
|
|
else if (cleanLine.startsWith(QLatin1String("struct ")))
|
|
{
|
|
m_State = e_ParseStruct;
|
|
}
|
|
}
|
|
|
|
// parse the line when we are within
|
|
switch (m_State)
|
|
{
|
|
case e_ParseUnion:
|
|
parseUnion(cleanLine);
|
|
break;
|
|
case e_ParseStruct:
|
|
parseStruct(cleanLine);
|
|
break;
|
|
case e_ParseEnum:
|
|
parseEnum(cleanLine);
|
|
break;
|
|
default:
|
|
if (m_Line.startsWith(DEFINE_NAME))
|
|
{
|
|
parseDefine(m_Line.mid(DEFINE_NAME.size()));
|
|
}
|
|
else if (cleanLine.startsWith(QLatin1String("typedef ")))
|
|
{
|
|
parseTypedef(cleanLine);
|
|
}
|
|
else if (cleanLine.startsWith(QLatin1String("enum ")))
|
|
{
|
|
parseEnum(cleanLine.mid(5));
|
|
}
|
|
else if (cleanLine.startsWith(QLatin1String("enum8 ")))
|
|
{
|
|
parseEnum(cleanLine.mid(6), 1);
|
|
}
|
|
else if (cleanLine.startsWith(QLatin1String("enum16 ")))
|
|
{
|
|
parseEnum(cleanLine.mid(7), 2);
|
|
}
|
|
}
|
|
|
|
if (lastLinesCount > 0)
|
|
{
|
|
m_LineNbr += lastLinesCount;
|
|
lastLinesCount = 0;
|
|
}
|
|
}
|
|
xFile.close();
|
|
// erase all parsing-values (otherwise errormessages will have wrong informations)
|
|
m_LineNbr = 0;
|
|
m_Line.clear();
|
|
}
|
|
else
|
|
{
|
|
QMessageBox::warning(nullptr, QLatin1String("Dateifehler"), QStringLiteral("Konnte die Datei <b>%1</b> nicht öffnen").arg(a_fileName));
|
|
}
|
|
}
|
|
|
|
|
|
// ---------------------------------------------------------------
|
|
QString LogViewXdrParser::removeComments(const QString& a_line)
|
|
{
|
|
static const QChar slash(QLatin1Char('/'));
|
|
static const QChar asterik(QLatin1Char('*'));
|
|
// remove comments (sourounded with /* */)
|
|
QString cleanLine; cleanLine.reserve(a_line.size());
|
|
QString::const_iterator iter = a_line.begin();
|
|
QString::const_iterator end = a_line.end();
|
|
while (iter != end)
|
|
{
|
|
if (!m_WithinComment)
|
|
{
|
|
// does comment begin?
|
|
if (slash == *iter)
|
|
{
|
|
if (++iter != end)
|
|
{
|
|
if (asterik == *iter)
|
|
{
|
|
// yes, comment begins
|
|
m_WithinComment = true;
|
|
}
|
|
else
|
|
{
|
|
// no comment begin
|
|
cleanLine.append(slash);
|
|
cleanLine.append(*iter);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// end of line
|
|
cleanLine.append(slash);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// no
|
|
cleanLine.append(*iter);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// does comment end?
|
|
if (asterik == *iter)
|
|
{
|
|
if (++iter != end)
|
|
{
|
|
if (slash == *iter)
|
|
{
|
|
m_WithinComment = false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (iter != end)
|
|
++iter;
|
|
}
|
|
return cleanLine;
|
|
}
|
|
|
|
|
|
// ---------------------------------------------------------------
|
|
void LogViewXdrParser::parseTypedef(const QString &a_line)
|
|
{
|
|
fillWordList(a_line);
|
|
|
|
// typedef: "typedef telegramm_id_int_et telegramm_id_et;"
|
|
// -------
|
|
// keyword 'typedef'
|
|
if (isNextWord("typedef"))
|
|
{
|
|
// get type
|
|
bool ok;
|
|
QString type = getNextType(ok);
|
|
// fixme: make boolean for structure wrong and gray out telegrams with wrong struct
|
|
getElement(type); // do not abort when type does not exist, otherwise we will never get an error, when we try to show a telegram with a wrong structure
|
|
// get name
|
|
QString name = getNextWord("Name");
|
|
if (name.isEmpty()) return;
|
|
if (!isNextWord(";")) return;
|
|
// all ok
|
|
uint16_t dynArrayOffset;
|
|
uint16_t arraySize = parseArray(name, dynArrayOffset);
|
|
LogViewXdrType* typedefElement = new LogViewXdrType(name, type, arraySize, dynArrayOffset, LogViewXdrElement::e_KindTypedef);
|
|
if (!addToElementMap(name, typedefElement))
|
|
delete typedefElement;
|
|
}
|
|
}
|
|
|
|
|
|
// ---------------------------------------------------------------
|
|
void LogViewXdrParser::parseDefine(const QString &a_line)
|
|
{
|
|
const QString line = a_line.trimmed();
|
|
int sepPos = line.indexOf(QLatin1Char(' '));
|
|
if (sepPos >= 0)
|
|
{
|
|
const QString name = line.leftRef(sepPos).trimmed().toString();
|
|
QStringRef substitution = line.midRef(sepPos).trimmed();
|
|
sepPos = substitution.indexOf(QLatin1Char(' '));
|
|
if (sepPos >= 0)
|
|
substitution = substitution.left(sepPos).trimmed();
|
|
|
|
// convert to number
|
|
bool ok = false;
|
|
const int64_t value = calcValue(substitution.toString(), ok);
|
|
if (ok)
|
|
{
|
|
//INFO_LOG(m_logger) << "Define: name=" << name.toStdString() << " subst=" << substitution.toStdString() << " value=" << value;
|
|
m_DefinesMap.insert(std::make_pair(name, LogViewXdrValue(name, value, LogViewXdrElement::e_KindDefine)));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
showErrorMessage(QObject::tr("<b>Space</b> zwischen define-name und substitution nicht gefunden"));
|
|
}
|
|
}
|
|
|
|
|
|
// ---------------------------------------------------------------
|
|
void LogViewXdrParser::parseEnum(const QString &a_line, const uint16_t a_enumSize)
|
|
{
|
|
if (QLatin1String("};") != a_line)
|
|
{
|
|
switch(m_State)
|
|
{
|
|
default:
|
|
// first line of enum containing the name
|
|
// i.e.: "enum telegramm_id_int_et {"
|
|
if (a_line.endsWith(QLatin1String(" {")))
|
|
{
|
|
m_State = e_ParseEnum;
|
|
const QString name = a_line.leftRef(a_line.length()-2).trimmed().toString();
|
|
m_ActElement = new LogViewXdrStruct(name, LogViewXdrElement::e_KindEnum, a_enumSize);
|
|
if (!addToElementMap(name, m_ActElement))
|
|
{
|
|
delete m_ActElement;
|
|
m_ActElement = nullptr;
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
showErrorMessage(QObject::tr("Endet nicht mit <b> {</b>"));
|
|
}
|
|
break;
|
|
|
|
case e_ParseEnum:
|
|
{
|
|
// middle lines of struct containing the elements
|
|
// i.e.: "MANIPULATIONSMELDUNG = 2,"
|
|
QString name;
|
|
QString valueText;
|
|
if (parseEnumLine(a_line, name, valueText))
|
|
{
|
|
// is the valueText a previous enum-element?
|
|
bool error = true;
|
|
uint32_t enumValue = m_ActElement->getChildValue(valueText, &error);
|
|
if (!error)
|
|
{
|
|
valueText = QString::number(enumValue);
|
|
}
|
|
// calculate
|
|
bool ok;
|
|
int64_t value = calcValue(valueText, ok);
|
|
if (ok)
|
|
m_ActElement->addElement(name, value, LogViewXdrElement::e_KindEnumElement);
|
|
else
|
|
ERROR_LOG(m_logger) << "Problem with converting text to number: name=" << name.toStdString() << " valueText=" << valueText.toStdString();
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// end of struct
|
|
m_State = e_ParseMain;
|
|
//INFO_LOG(m_logger) << "CheckEnum " << m_ActElement->getName().toStdString();
|
|
// check(*m_ActElement);
|
|
}
|
|
}
|
|
|
|
|
|
// ---------------------------------------------------------------
|
|
void LogViewXdrParser::parseStruct(const QString &a_line)
|
|
{
|
|
fillWordList(a_line);
|
|
if (!m_DoReadUntilSemicolon)
|
|
{
|
|
// first line of struct: "struct gef_wirkfeld_flaechendeckendes_feuer_meldung_rt {"
|
|
// --------------------
|
|
// keyword 'union'
|
|
if (isNextWord("struct"))
|
|
{
|
|
// union name
|
|
QString structName = getNextWord("Struktur-Name");
|
|
if (structName.isEmpty()) return;
|
|
if (!isNextWord("{")) return;
|
|
// all ok => proceed parsing union
|
|
m_ActElement = new LogViewXdrStruct(structName, LogViewXdrElement::e_KindStruct);
|
|
if (!addToElementMap(structName, m_ActElement))
|
|
{
|
|
delete m_ActElement;
|
|
m_ActElement = nullptr;
|
|
return;
|
|
}
|
|
m_State = e_ParseStruct;
|
|
m_DoReadUntilSemicolon = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!isNextWord("}", false))
|
|
{
|
|
// next lines of struct: "gef_header_rt:3..6 header;"
|
|
// --------------------
|
|
// get type
|
|
bool ok;
|
|
QString type = getNextType(ok);
|
|
if (!ok) return;
|
|
// fixme: make boolean for structure wrong and gray out telegrams with wrong struct
|
|
if (m_UnionType != type) getElement(type); // do not abort when type does not exist, otherwise we will never get an error, when we try to show a telegram with a wrong structure
|
|
// get bitfield (if any) ":2..5"
|
|
int16_t firstBit = -1;
|
|
int16_t lastBit = -1;
|
|
bool isLast = true;
|
|
if (isNextWord(":", false))
|
|
{
|
|
isNextWord(":");
|
|
QString bitfield = getNextWord("Bitfield");
|
|
isLast = parseBitfield(bitfield, firstBit, lastBit);
|
|
}
|
|
// get name
|
|
QString name = getNextWord("Name");
|
|
if (name.isEmpty()) return;
|
|
if (!isNextWord(";")) return;
|
|
// all ok
|
|
uint16_t dynArrayOffset;
|
|
uint16_t arraySize = parseArray(name, dynArrayOffset);
|
|
if(firstBit >= 0)
|
|
DEBUG_LOG(m_logger) << "Add Element " << name
|
|
<< " with type " << type
|
|
<< " array size: " << arraySize
|
|
<< " first:last " << firstBit << ":" << lastBit
|
|
<< " isLast: " << isLast;
|
|
m_ActElement->addElement(name, type, arraySize, dynArrayOffset, LogViewXdrElement::e_KindStructElement, firstBit, lastBit, isLast);
|
|
}
|
|
else
|
|
{
|
|
// end of struct "};"
|
|
if (!isNextWord("}")) return;
|
|
if (!isNextWord(";")) return;
|
|
m_State = e_ParseMain;
|
|
m_DoReadUntilSemicolon = false;
|
|
// INFO_LOG(m_logger) << "CheckStruct \'" << m_ActElement->getName().toStdString() << "\'";
|
|
// if (m_ActElement->getName() != "intern_tele") // fixme: remove this structure from element-map
|
|
// {
|
|
// check(*m_ActElement);
|
|
// }
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// ---------------------------------------------------------------
|
|
void LogViewXdrParser::parseUnion(const QString& a_line)
|
|
{
|
|
// we can not really parse the union, we expect that only 1 union exists, and this
|
|
// union holds all the telegrams, which we insert into a telegram-list
|
|
static const LogViewXdrStruct* telegramIdType = nullptr;
|
|
|
|
fillWordList(a_line);
|
|
if (!m_DoReadUntilSemicolon)
|
|
{
|
|
// first line of union "union gef_tg_nd_ switch (gef_telegramm_id_et telegramm_id) {"
|
|
// -------------------
|
|
// keyword 'union'
|
|
if (isNextWord("union"))
|
|
{
|
|
// union name
|
|
m_UnionType = getNextWord("Union-Typ");
|
|
if (m_UnionType.isEmpty()) return;
|
|
// keyword 'switch'
|
|
if (!isNextWord("switch")) return;
|
|
if (!isNextWord("(")) return;
|
|
// telegram-id-type
|
|
getNextEnum(telegramIdType);
|
|
if (telegramIdType == nullptr) return;
|
|
// telegram-id-name
|
|
QString name = getNextWord("Parameter-Name");
|
|
if (name.isEmpty()) return;
|
|
if (!isNextWord(")")) return;
|
|
if (!isNextWord("{")) return;
|
|
// all ok => proceed parsing union
|
|
m_State = e_ParseUnion;
|
|
m_DoReadUntilSemicolon = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!isNextWord("}", false))
|
|
{
|
|
QString keyword = getNextWord();
|
|
if (keyword == QLatin1String("case"))
|
|
{
|
|
// next lines of union "case GEF_INIT: gef_init_meldung_rt init_meldung;"
|
|
// -------------------
|
|
QStringList constExprList;
|
|
QString type;
|
|
do
|
|
{
|
|
// get constant-expression
|
|
QString constExpression = getNextWord("Konstanten-Ausdruck");
|
|
if (constExpression.isEmpty()) return;
|
|
constExprList << constExpression;
|
|
// check double-point
|
|
if (!isNextWord(":")) return;
|
|
// get type or another case
|
|
type = getNextWord("Typ");
|
|
if (type.isEmpty()) return;
|
|
}
|
|
while (type == QLatin1String("case"));
|
|
// fixme: make boolean for structure wrong and gray out telegrams with wrong struct
|
|
getElement(type); // do not abort when type does not exist, otherwise we will never get an error, when we try to show a telegram with a wrong structure
|
|
// get name
|
|
QString name = getNextWord("Name");
|
|
if (name.isEmpty()) return;
|
|
// check semicolon
|
|
if (!isNextWord(";")) return;
|
|
// all ok => add to telegram-map
|
|
for (const QString &constExpr : qAsConst(constExprList))
|
|
{
|
|
bool error;
|
|
int32_t telegramId = static_cast<int>(telegramIdType->getChildValue(constExpr, &error));
|
|
if (!error)
|
|
{
|
|
m_TelegramMap.insert(std::make_pair(telegramId, LogViewXdrType(constExpr, type, 1, 0, LogViewXdrElement::e_KindEnumElement))); // fixme: e_KindCaseElement und 1 entfernen
|
|
}
|
|
else
|
|
{
|
|
showErrorMessage(QObject::tr("\'%1\' ist nicht definiert in \'%2\'").arg(constExpr, telegramIdType->getName()));
|
|
}
|
|
}
|
|
}
|
|
else if (keyword == QLatin1String("default"))
|
|
{
|
|
// check double-point
|
|
if (isNextWord(":"))
|
|
{
|
|
QString defaultDefinition = getNextWord();
|
|
if (defaultDefinition == QLatin1String("void"))
|
|
{
|
|
isNextWord(";");
|
|
// all ok
|
|
}
|
|
else
|
|
{
|
|
showErrorMessage(QObject::tr("default: muss void; enthalten. Falls nicht, muss das richtige Verhalten implementiert werden..."));
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
showErrorMessage(QObject::tr("Erwarte Keyword <b>case</b> oder <b>default</b> statt \'%1\'").arg(keyword));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// end of union "};"
|
|
if (!isNextWord("}")) return;
|
|
if (!isNextWord(";")) return;
|
|
m_State = e_ParseMain;
|
|
m_DoReadUntilSemicolon = false;
|
|
//check(*m_ActElement);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// ---------------------------------------------------------------
|
|
bool LogViewXdrParser::parseEnumLine(const QString& a_line, QString& a_name, QString& a_value) const
|
|
{
|
|
QString line;
|
|
if (a_line.endsWith(QLatin1Char(',')))
|
|
{
|
|
line = a_line.left(a_line.length()-1);
|
|
}
|
|
else
|
|
{
|
|
line = a_line;
|
|
}
|
|
line = line.trimmed();
|
|
|
|
int sepPos = line.lastIndexOf(QLatin1Char('='));
|
|
if (-1 != sepPos)
|
|
{
|
|
a_name = line.leftRef(sepPos).trimmed().toString();
|
|
a_value = line.midRef(sepPos+1).trimmed().toString();
|
|
return true; // successful
|
|
}
|
|
else
|
|
{
|
|
showErrorMessage(QObject::tr("konnte Trennzeichen <b>\'=\'</b> zwischen Name und Wert nicht finden!"));
|
|
}
|
|
return false; // failure happenend
|
|
}
|
|
|
|
|
|
// ---------------------------------------------------------------
|
|
// Shows an error-message containing the line-nbr, the line
|
|
// itself and an additional error-text
|
|
// ---------------------------------------------------------------
|
|
void LogViewXdrParser::showErrorMessage(const QString& a_errorText) const
|
|
{
|
|
const auto tlws = QApplication::topLevelWidgets();
|
|
QMessageBox::warning(tlws.size() ? tlws.first() : nullptr,
|
|
QObject::tr("Telegram Structure Parser"),
|
|
QStringLiteral("<i>%4:%1:<br><b>%2</b></i><br><br>%3").arg(m_LineNbr).arg(m_Line, a_errorText, m_Filename));
|
|
}
|
|
|
|
|
|
// ---------------------------------------------------------------
|
|
int64_t LogViewXdrParser::calcValue(const QString& a_calcText, bool& a_isOk)
|
|
{
|
|
// ignore strings
|
|
a_isOk = false;
|
|
int64_t value = 0;
|
|
if (!a_calcText.startsWith(QLatin1Char('\"')))
|
|
{
|
|
N_SST::IntegerCalculator::E_Error error;
|
|
std::string errorText;
|
|
value = calc(a_calcText.toStdString(), error, &errorText);
|
|
|
|
// show error if one happend
|
|
if (error != N_SST::IntegerCalculator::e_Ok)
|
|
{
|
|
switch (error)
|
|
{
|
|
case N_SST::IntegerCalculator::e_DivisionByZero:
|
|
showErrorMessage(QObject::tr("Division durch 0 nicht erlaubt!"));
|
|
break;
|
|
case N_SST::IntegerCalculator::e_InvalidOperand:
|
|
showErrorMessage(QObject::tr("Operand %1 ist fehlerhaft!").arg(QString::fromStdString(errorText)));
|
|
break;
|
|
case N_SST::IntegerCalculator::e_MissingLeftParanthesis:
|
|
showErrorMessage(QObject::tr("Es fehlen Klammer Öffnungen (!"));
|
|
break;
|
|
case N_SST::IntegerCalculator::e_MissingRightParanthesis:
|
|
showErrorMessage(QObject::tr("Es fehlen Klammer Schliessungen )!"));
|
|
break;
|
|
case N_SST::IntegerCalculator::e_NoOperandBetweenOperators:
|
|
showErrorMessage(QObject::tr("Zwei Operationen (%1) nacheinander sind nicht erlaubt!").arg(QString::fromStdString(errorText)));
|
|
break;
|
|
case N_SST::IntegerCalculator::e_UnknownOperationOrVariable:
|
|
showErrorMessage(QObject::tr("Operation oder Variable %1 unbekannt!").arg(QString::fromStdString(errorText)));
|
|
break;
|
|
case N_SST::IntegerCalculator::e_UnknownError:
|
|
showErrorMessage(QObject::tr("Unbekannter Fehler!"));
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
ERROR_LOG(m_logger) << "Problem with converting '" << a_calcText << "' to integer";
|
|
}
|
|
else
|
|
{
|
|
a_isOk = true;
|
|
}
|
|
}
|
|
return value;
|
|
}
|
|
|
|
|
|
// ---------------------------------------------------------------
|
|
bool LogViewXdrParser::getVariableValue(const std::string& a_variableName, int64_t& a_value) const
|
|
{
|
|
return getDefine(QString::fromStdString(a_variableName), a_value);
|
|
}
|
|
|
|
// ---------------------------------------------------------------
|
|
// This function delivers the name of the telegram and the
|
|
// name of its structure. The telegram will be defined with
|
|
// a_telegramId.
|
|
// The name will be delivered as return-parameter; the
|
|
// structure-name as out parameter a_structName.
|
|
// If the telegram was not found, error-texts instead names
|
|
// will be returned.
|
|
// ---------------------------------------------------------------
|
|
QString LogViewXdrParser::getTelegramName(int a_telegramId) const
|
|
{
|
|
const auto iter = m_TelegramMap.find(a_telegramId);
|
|
if (m_TelegramMap.end() != iter)
|
|
return iter->second.getName();
|
|
|
|
return QObject::tr("<telegramId \'%1\' not found!>").arg(a_telegramId);
|
|
}
|
|
|
|
// ---------------------------------------------------------------
|
|
QString LogViewXdrParser::getStructName(int a_telegramId) const
|
|
{
|
|
const auto iter = m_TelegramMap.find(a_telegramId);
|
|
if (m_TelegramMap.end() != iter)
|
|
return iter->second.getType();
|
|
|
|
return QObject::tr("<telegramId \'%1\' not found!>").arg(a_telegramId);
|
|
}
|
|
|
|
// ---------------------------------------------------------------
|
|
bool LogViewXdrParser::getDefine(const QString& a_name, int64_t& a_value) const
|
|
{
|
|
const auto iter = m_DefinesMap.find(a_name);
|
|
if (iter != m_DefinesMap.end())
|
|
{
|
|
a_value = iter->second.getValue();
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
// ---------------------------------------------------------------
|
|
const LogViewXdrElement* LogViewXdrParser::getElement(const QString& a_name) const
|
|
{
|
|
const auto iter = m_ElementMap.find(a_name);
|
|
if (iter != m_ElementMap.end())
|
|
return iter->second;
|
|
|
|
showErrorMessage(QObject::tr("Typ \'<b><i>%1</i></b>\' nicht definiert!").arg(a_name));
|
|
return nullptr;
|
|
}
|
|
|
|
|
|
// ---------------------------------------------------------------
|
|
uint16_t LogViewXdrParser::parseArray(QString& a_name, uint16_t& a_dynArrayMsgOffset) const
|
|
{
|
|
a_dynArrayMsgOffset = 0;
|
|
QString oldName = a_name;
|
|
|
|
// is it a static array []?
|
|
// ------------------------
|
|
int pos = a_name.indexOf(QLatin1Char('['));
|
|
if (pos >= 0)
|
|
{
|
|
int endPos = a_name.indexOf(QLatin1Char(']'));
|
|
if (endPos > pos)
|
|
{
|
|
// get the array-size
|
|
QString arraySizeText = a_name.mid(pos+1, endPos-pos-1);
|
|
// set new name
|
|
a_name = a_name.left(pos);
|
|
// INFO_LOG(m_logger) << "new a_name=" << a_name.toStdString() << " arraySizeText=" << arraySizeText.toStdString();
|
|
int64_t arraySizeValue = 1;
|
|
// check whether it is a define
|
|
if (!getDefine(arraySizeText, arraySizeValue))
|
|
{
|
|
bool ok = false;
|
|
arraySizeValue = arraySizeText.toInt(&ok);
|
|
if (!ok)
|
|
{
|
|
showErrorMessage(QObject::tr("%1: <b>[%2]</b> is not a number").arg(oldName, arraySizeText));
|
|
}
|
|
}
|
|
// INFO_LOG(m_logger) << "ArraySize=" << arraySizeValue;
|
|
return arraySizeValue;
|
|
}
|
|
else
|
|
{
|
|
showErrorMessage(QObject::tr("%1: Did not found expected <b>']'</b>").arg(oldName));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
|
|
// is it an dynamic array <>?
|
|
// --------------------------
|
|
//INFO_LOG(m_logger) << "check for <";
|
|
pos = a_name.indexOf(QLatin1Char('<'));
|
|
if (pos >= 0)
|
|
{
|
|
int endPos = a_name.indexOf(QLatin1Char('>'));
|
|
if (endPos > pos)
|
|
{
|
|
// get the array-size
|
|
QString arraySizeText = a_name.mid(pos+1, endPos-pos-1);
|
|
//INFO_LOG(m_logger) << "pos=" << pos << " endPos=" << endPos << " => " << arraySizeText.toStdString();
|
|
// set new name
|
|
a_name = a_name.left(pos);
|
|
// INFO_LOG(m_logger) << "new a_name=" << a_name.toStdString() << " arraySizeText=" << arraySizeText.toStdString();
|
|
// check whether it is a define
|
|
int64_t arraySizeValue = 1;
|
|
if (!getDefine(arraySizeText, arraySizeValue))
|
|
{
|
|
bool ok = false;
|
|
arraySizeValue = arraySizeText.toInt(&ok);
|
|
if (!ok)
|
|
{
|
|
showErrorMessage(QObject::tr("%1: <b>\'%2\'</b> is not a number").arg(a_name, arraySizeText));
|
|
}
|
|
else
|
|
{
|
|
// INFO_LOG(m_logger) << "a_name=" << a_name.toStdString() << " a_dynArrayMsgOffset=" << a_dynArrayMsgOffset;
|
|
}
|
|
}
|
|
a_dynArrayMsgOffset = arraySizeValue;
|
|
// INFO_LOG(m_logger) << a_name.toStdString() << " is a dynamic array with size=" << arraySizeValue;
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
showErrorMessage(QObject::tr("%1: Did not found expected <b>'>'</b>").arg(a_name));
|
|
}
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
|
|
// ---------------------------------------------------------------
|
|
bool LogViewXdrParser::isNextWord(const char *a_word, const bool a_doIncrement)
|
|
{
|
|
const QString word = QString::fromUtf8(a_word);
|
|
bool ok = (m_WordListIndex < m_WordList.size() &&
|
|
m_WordList.at(m_WordListIndex) == word);
|
|
|
|
// show error-message
|
|
if (!ok && a_doIncrement)
|
|
{
|
|
if (m_WordListIndex > 0)
|
|
showErrorMessage(QObject::tr("Erwarte <b>%1</b> nach \'%2\'!").arg(word, m_WordList.at(m_WordListIndex-1)));
|
|
else
|
|
showErrorMessage(QObject::tr("Erwarte <b>%1</b>!").arg(word));
|
|
}
|
|
|
|
if (a_doIncrement)
|
|
m_WordListIndex++;
|
|
return ok;
|
|
}
|
|
|
|
|
|
// ---------------------------------------------------------------
|
|
void LogViewXdrParser::fillWordList(const QString& a_line)
|
|
{
|
|
QString line = a_line;
|
|
line.replace(QLatin1Char('('), QLatin1String(" ( "));
|
|
line.replace(QLatin1Char(')'), QLatin1String(" ) "));
|
|
line.replace(QLatin1Char('{'), QLatin1String(" { "));
|
|
line.replace(QLatin1Char('}'), QLatin1String(" } "));
|
|
line.replace(QLatin1Char(':'), QLatin1String(" : "));
|
|
line.replace(QLatin1Char(';'), QLatin1String(" ; "));
|
|
m_WordList = line.split(QLatin1Char(' '), QString::SkipEmptyParts);
|
|
m_WordListIndex = 0;
|
|
// ----------------------
|
|
// for debugging only
|
|
// foreach (const QString &str, qAsConst(m_WordList))
|
|
// INFO_LOG(m_logger) << "word=" << str.toStdString();
|
|
// ----------------------
|
|
}
|
|
|
|
|
|
// ---------------------------------------------------------------
|
|
QString LogViewXdrParser::getNextWord(const char *a_errorText)
|
|
{
|
|
QString word;
|
|
if (m_WordListIndex < m_WordList.size())
|
|
word = m_WordList.at(m_WordListIndex);
|
|
|
|
if (word.isEmpty() && a_errorText)
|
|
{
|
|
const QString errTxt(QString::fromUtf8(a_errorText));
|
|
if (m_WordListIndex > 0)
|
|
showErrorMessage(QObject::tr("Erwarte <b>%1</b> nach \'%2\'!").arg(errTxt, m_WordList.at(m_WordListIndex-1)));
|
|
else
|
|
showErrorMessage(QObject::tr("Erwarte <b>%1</b>!").arg(errTxt));
|
|
}
|
|
m_WordListIndex++;
|
|
return word;
|
|
}
|
|
|
|
|
|
// ---------------------------------------------------------------
|
|
QString LogViewXdrParser::getNextType(bool& a_ok)
|
|
{
|
|
a_ok = true;
|
|
QString type = getNextWord("Typ");
|
|
if (type.isEmpty()) a_ok = false;
|
|
if (type == QLatin1String("unsigned") ||
|
|
type == QLatin1String("signed"))
|
|
{
|
|
QString type2 = getNextWord("Typ");
|
|
if (type2.isEmpty()) a_ok = false;
|
|
type = QStringLiteral("%1 %2").arg(type, type2);
|
|
}
|
|
return type;
|
|
}
|
|
|
|
|
|
// ---------------------------------------------------------------
|
|
QString LogViewXdrParser::getNextEnum(const LogViewXdrStruct*& a_enumStruct)
|
|
{
|
|
QString type;
|
|
a_enumStruct = nullptr;
|
|
if (m_WordListIndex < m_WordList.size())
|
|
{
|
|
type = m_WordList.at(m_WordListIndex);
|
|
a_enumStruct = static_cast<const LogViewXdrStruct*>(getElement(type));
|
|
if (a_enumStruct)
|
|
{
|
|
if (LogViewXdrElement::e_KindEnum != a_enumStruct->getKind())
|
|
{
|
|
showErrorMessage(QObject::tr("Typ \'%1\' muss ein Enum sein!").arg(type));
|
|
a_enumStruct = nullptr;
|
|
}
|
|
}
|
|
else
|
|
showErrorMessage(QObject::tr("Enum \'%1\' nicht definiert!").arg(type));
|
|
m_WordListIndex++;
|
|
}
|
|
return type;
|
|
}
|
|
|
|
|
|
// ---------------------------------------------------------------
|
|
bool LogViewXdrParser::parseBitfield(const QString& a_fieldText, int16_t& a_firstBit, int16_t& a_lastBit) const
|
|
{
|
|
// INFO_LOG(m_logger) << "a_fieldText=" << a_fieldText.toStdString();
|
|
// bitfield-definition: "0..2"
|
|
a_firstBit = -1;
|
|
a_lastBit = -1;
|
|
bool isLast = true;
|
|
// first bit
|
|
int doublePointPos = a_fieldText.indexOf(QLatin1String(".."));
|
|
if (doublePointPos != -1)
|
|
{
|
|
QString bitText = a_fieldText.left(doublePointPos);
|
|
bool ok;
|
|
a_firstBit = bitText.toInt(&ok);
|
|
if (ok)
|
|
{
|
|
// last bit
|
|
bitText = a_fieldText.mid(doublePointPos+2);
|
|
// is it the last bitfield of this data-value (indicated by !)
|
|
if (bitText.endsWith(QLatin1Char('!')))
|
|
{
|
|
isLast = true;
|
|
bitText.chop(1);
|
|
}
|
|
else
|
|
{
|
|
isLast = false;
|
|
}
|
|
a_lastBit = bitText.toInt(&ok);
|
|
if (ok)
|
|
{
|
|
// remove bitfield-stuff
|
|
// a_line = a_line.remove(bitfieldPos, endPos-bitfieldPos);
|
|
}
|
|
else
|
|
{
|
|
showErrorMessage(QObject::tr("Bitfeld-Defintion muss folgendes Format haben: :0..2. Zweites Bit (%1) ist keine Zahl!").arg(bitText));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
showErrorMessage(QObject::tr("Bitfeld-Defintion muss folgendes Format haben: :0..2. Erstes Bit (%1) ist keine Zahl!").arg(bitText));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
showErrorMessage(QObject::tr("Bitfeld-Defintion muss folgendes Format haben: :0..2. Habe .. nicht gefunden!"));
|
|
}
|
|
return isLast;
|
|
}
|
|
|
|
|
|
// ---------------------------------------------------------------
|
|
// adds an element to the element-map if it does not already
|
|
// exist within this map.
|
|
// If it exists, an error-message will be raised instead and
|
|
// false will be returned.
|
|
// ---------------------------------------------------------------
|
|
bool LogViewXdrParser::addToElementMap(const QString& a_name, LogViewXdrElement* a_element)
|
|
{
|
|
if (m_ElementMap.find(a_name) == m_ElementMap.end())
|
|
{
|
|
m_ElementMap.insert(std::make_pair(a_name, a_element));
|
|
return true;
|
|
}
|
|
showErrorMessage(QObject::tr("Der Typ '%1' wurde bereits frueher definiert => Bitte ein einem Ort entfernen!").arg(a_name));
|
|
return false;
|
|
}
|
|
|
|
} // namespace N_LogView
|
|
|