812 lines
25 KiB
C
812 lines
25 KiB
C
/*!
|
|
* @file cfile_parser.c
|
|
* @brief
|
|
* @details
|
|
* Project: \n
|
|
* Subsystem: \n
|
|
* Module: \n
|
|
* Code: GNU-C\n
|
|
*
|
|
* @date 28.02.2017
|
|
* @author SESA354004
|
|
*/
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <ctype.h>
|
|
#include "xregex.h"
|
|
#include "xtypes.h"
|
|
#include "xstring.h"
|
|
#include "xmalloc.h"
|
|
#include "cfile_if.h"
|
|
#include "cfile_parser_if.h"
|
|
#include "cfile_parser_loc.h"
|
|
#include "cfile_parser_worker_loc.h"
|
|
#include "debug.h"
|
|
|
|
/*! @brief Block detection return values */
|
|
typedef enum _CFILE_BLOCK_RETURN_T
|
|
{
|
|
CFILE_BLOCK_DETECT_ERROR = -1, /*!< @brief description */
|
|
CFILE_BLOCK_DETECT_NONE = 0, /*!< @brief description */
|
|
CFILE_BLOCK_DETECT_START = 1, /*!< @brief description */
|
|
CFILE_BLOCK_DETECT_END = 2, /*!< @brief description */
|
|
} cfile_block_return_t;
|
|
|
|
STATIC bool cfile_parser_initialized = false;
|
|
STATIC regex_t regXfunction;
|
|
STATIC regex_t regXprefix;
|
|
STATIC regex_t regXparameter;
|
|
STATIC regex_t regXfuPtrSeparator;
|
|
STATIC regex_t regXfunctionPointer;
|
|
STATIC regex_t regXvariable;
|
|
|
|
STATIC regex_t regXExpressionStart;
|
|
STATIC regex_t regXExpressionEnd;
|
|
|
|
// line evaluation related variables
|
|
STATIC uint32_t cfile_parser_removeCommentHelper = 0;
|
|
STATIC uint32_t cfile_parser_removeBraceHelper = 0;
|
|
|
|
int8_t cfile_parser_init()
|
|
{
|
|
if (0 > regcomp(®XExpressionStart, CPARS_EXPRESSION_START, (REG_EXTENDED | REG_NEWLINE)))
|
|
{
|
|
perror("Error regex\n");
|
|
return -1;
|
|
}
|
|
if (0 > regcomp(®XExpressionEnd, CPARS_EXPRESSION_END, (REG_EXTENDED | REG_NEWLINE)))
|
|
{
|
|
perror("Error regex\n");
|
|
return -1;
|
|
}
|
|
if (0 > regcomp(®Xfunction, CPARS_REGEX_FUNCTION, (REG_EXTENDED | REG_NEWLINE)))
|
|
{
|
|
perror("Error regex\n");
|
|
return -1;
|
|
}
|
|
if (0 > regcomp(®Xprefix, CPARS_REGEX_PREFIX, (REG_EXTENDED)))
|
|
{
|
|
perror("Error regex\n");
|
|
return -1;
|
|
}
|
|
if (0 > regcomp(®Xparameter, CPARS_REGEX_PARAMETER, (REG_EXTENDED)))
|
|
{
|
|
perror("Error regex\n");
|
|
return -1;
|
|
}
|
|
if (0 > regcomp(®XfuPtrSeparator, CPARS_REGEX_PARAMETER_FUPTR_SEPA, (REG_EXTENDED)))
|
|
{
|
|
perror("Error regex\n");
|
|
return -1;
|
|
}
|
|
if (0 > regcomp(®XfunctionPointer, CPARS_REGEX_FUNCTIONPOINTER, (REG_EXTENDED)))
|
|
{
|
|
perror("Error regex\n");
|
|
return -1;
|
|
}
|
|
if (0 > regcomp(®Xvariable, CPARS_REGEX_VARIABLE, (REG_EXTENDED | REG_NEWLINE)))
|
|
{
|
|
perror("Error regex\n");
|
|
return -1;
|
|
}
|
|
|
|
cfile_parser_initialized = true;
|
|
return 0;
|
|
}
|
|
|
|
#if isDebugLevel(1)
|
|
STATIC void printMatchGroup(char *aString, regmatch_t *aMatchGroup)
|
|
{
|
|
char match[1024] =
|
|
{ 0};
|
|
uint8_t i = 0;
|
|
|
|
for (i = 0; i < CFILE_PARSER_MAX_REGEX_MATCHING_GROUPS && 0 <= aMatchGroup[i].rm_so; ++i)
|
|
{
|
|
if (aMatchGroup[i].rm_so < aMatchGroup[i].rm_eo)
|
|
{
|
|
DEBUG_LOG_APPEND(1, "[%02d](%.3ld - %.3ld)[%03d]:", i, aMatchGroup[i].rm_so, aMatchGroup[i].rm_eo,
|
|
(int ) (aMatchGroup[i].rm_eo - aMatchGroup[i].rm_so));
|
|
strlcpy(match, &aString[aMatchGroup[i].rm_so], (size_t) (aMatchGroup[i].rm_eo - aMatchGroup[i].rm_so + 1));
|
|
DEBUG_LOG_APPEND(1, "%s", match);
|
|
DEBUG_LOG_APPEND(1, "\n");
|
|
}
|
|
}
|
|
}
|
|
#else
|
|
#define printMatchGroup(aString, aMatchgroup) do { /*nothing*/ } while(0)
|
|
#endif
|
|
|
|
STATIC void checkFunctionType(cfunction_t *aFunction, char *aExpression)
|
|
{
|
|
char *tempChar = NULL;
|
|
|
|
if (NULL == aFunction || NULL == aExpression)
|
|
{
|
|
return;
|
|
}
|
|
|
|
aFunction->type = CFUNCTION_TYPE_REGULAR;
|
|
|
|
tempChar = strrchr(aExpression, CPARS_PROTOTYPE_END_C);
|
|
if (tempChar)
|
|
{
|
|
aFunction->type = CFUNCTION_TYPE_PROTO;
|
|
}
|
|
|
|
if (NULL == aFunction->prefix)
|
|
{
|
|
return;
|
|
}
|
|
if (NULL != strstr(aFunction->prefix, CPARS_PREFIX_EXTERN_S))
|
|
{
|
|
aFunction->type = CFUNCTION_TYPE_EXTERN;
|
|
}
|
|
else if ((NULL != strstr(aFunction->prefix, CPARS_PREFIX_STATIC_S) || NULL != strstr(aFunction->prefix, CPARS_PREFIX_STATIC2_S))
|
|
&& CFUNCTION_TYPE_PROTO != aFunction->type)
|
|
{
|
|
aFunction->type = CFUNCTION_TYPE_STATIC;
|
|
}
|
|
}
|
|
|
|
/*!
|
|
* @brief Extract C expression prefix and data type and removing trailing blanks
|
|
* @param [out] *aElement Pointer to C element structure
|
|
* @param [in] aElementType C element type (CELEMENT_TYPE_VARIABLE, CELEMENT_TYPE_FUNCTION supported)
|
|
* @param [in] *aString Pointer to a substring containing data type and/or prefix
|
|
* @param [in] aSize Length of string
|
|
* @retval 0 processing successful
|
|
* @retval -1 processing failed
|
|
*/
|
|
STATIC int8_t matchPrefix(void *aElement, celement_type_t aElementType, char *aString, size_t aSize)
|
|
{
|
|
regmatch_t matchGroup[CFILE_PARSER_MAX_REGEX_MATCHING_GROUPS];
|
|
char *temp = NULL;
|
|
char *end = NULL;
|
|
char **prefix = NULL;
|
|
char **type = NULL;
|
|
|
|
if (NULL == aElement || NULL == aString || 0 == aSize)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
switch (aElementType)
|
|
{
|
|
case CELEMENT_TYPE_VARIABLE:
|
|
{
|
|
prefix = &((cfile_variable_t*) aElement)->prefix;
|
|
type = &((cfile_variable_t*) aElement)->dataType;
|
|
break;
|
|
}
|
|
case CELEMENT_TYPE_FUNCTION:
|
|
{
|
|
prefix = &((cfunction_t*) aElement)->prefix;
|
|
type = &((cfunction_t*) aElement)->dataType;
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
temp = (char*) xmalloc(aSize + 1);
|
|
if (NULL == temp)
|
|
{
|
|
return -1;
|
|
}
|
|
strlcpy(temp, aString, aSize + 1);
|
|
|
|
// remove trailing spaces
|
|
end = temp + strlen(temp) - 1;
|
|
while (end > temp && isspace((uint8_t ) *end))
|
|
{
|
|
end--;
|
|
}
|
|
*(end + 1) = '\0';
|
|
|
|
if (CELEMENT_TYPE_VARIABLE == aElementType)
|
|
{
|
|
((cfile_variable_t*) aElement)->type = CVARIABLE_TYPE_REGULAR;
|
|
}
|
|
|
|
if (0 == regexec(®Xprefix, temp, CFILE_PARSER_MAX_REGEX_MATCHING_GROUPS, matchGroup, 0))
|
|
{
|
|
if (XREGEX_IS_MATCHGROUP(matchGroup, 1))
|
|
{
|
|
xmallocStrlcpy(prefix, &temp[matchGroup[1].rm_so], XREGEX_SIZEOF_MATCHGROUP(matchGroup, 1));
|
|
if (CELEMENT_TYPE_VARIABLE == aElementType)
|
|
{
|
|
if (*prefix && NULL != strstr(*prefix, CPARS_PREFIX_EXTERN_S))
|
|
{
|
|
((cfile_variable_t*) aElement)->type = CVARIABLE_TYPE_EXTERN;
|
|
}
|
|
else if (*prefix && (NULL != strstr(*prefix, CPARS_PREFIX_STATIC_S) || NULL != strstr(*prefix, CPARS_PREFIX_STATIC2_S)))
|
|
{
|
|
((cfile_variable_t*) aElement)->type = CVARIABLE_TYPE_STATIC;
|
|
}
|
|
}
|
|
}
|
|
if (XREGEX_IS_MATCHGROUP(matchGroup, 2))
|
|
{
|
|
xmallocStrlcpy(type, &temp[matchGroup[2].rm_so], XREGEX_SIZEOF_MATCHGROUP(matchGroup, 2));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
xmallocStrlcpy(type, temp, strlen(temp));
|
|
}
|
|
|
|
if (CELEMENT_TYPE_VARIABLE == aElementType)
|
|
{
|
|
if (*type && NULL != strstr(*type, CPARS_ELEMENT_CONST))
|
|
{
|
|
CVARIABLE_SET_TYPE(((cfile_variable_t* ) aElement)->type, CVARIABLE_TYPE_CONST);
|
|
}
|
|
}
|
|
|
|
free(temp);
|
|
return 0;
|
|
}
|
|
|
|
/*!
|
|
* @brief Find first given "start" or "end" string and return position
|
|
* @param [in] *aBlockStart Terminated string defining the start of a block
|
|
* @param [in] *aBlockEnd Terminated string defining the end of a block
|
|
* @param [in] *aLine Terminated line (e.g. read from a file getline())
|
|
* @param [out] **aPosition Pointing to found block string (realted to \ref aRemove) / NULL for CFILE_BLOCK_DETECT_NONE or CFILE_BLOCK_DETECT_ERROR
|
|
* @param [in] aRemove false - remove only content of block; true - also remove block strings
|
|
* @return cfile_block_return_t
|
|
* @retval CFILE_BLOCK_DETECT_START Start found
|
|
* @retval CFILE_BLOCK_DETECT_END End found
|
|
* @retval CFILE_BLOCK_DETECT_NONE No start or end found
|
|
* @retval CFILE_BLOCK_DETECT_ERROR Null pointer detected
|
|
*/
|
|
STATIC cfile_block_return_t cBlockDetection(const char *aBlockStart, const char *aBlockEnd, char *aLine, char **aPosition, bool aRemove)
|
|
{
|
|
char *blockStart = NULL;
|
|
char *blockEnd = NULL;
|
|
cfile_block_return_t ret = CFILE_BLOCK_DETECT_NONE;
|
|
|
|
if ( NULL == aBlockStart || NULL == aBlockEnd || NULL == aLine || NULL == aPosition)
|
|
{
|
|
perror("Null pointer");
|
|
return CFILE_BLOCK_DETECT_ERROR;
|
|
}
|
|
|
|
blockStart = strstr(aLine, aBlockStart);
|
|
blockEnd = strstr(aLine, aBlockEnd);
|
|
|
|
if (NULL == blockStart && NULL == blockEnd)
|
|
{
|
|
// no block element
|
|
ret = CFILE_BLOCK_DETECT_NONE;
|
|
}
|
|
else if (NULL == blockStart)
|
|
{
|
|
// last line of block
|
|
ret = CFILE_BLOCK_DETECT_END;
|
|
}
|
|
else if (NULL == blockEnd)
|
|
{
|
|
// first line of block
|
|
|
|
ret = CFILE_BLOCK_DETECT_START;
|
|
}
|
|
else if (blockStart < blockEnd)
|
|
{
|
|
// inline block
|
|
ret = CFILE_BLOCK_DETECT_START;
|
|
}
|
|
else
|
|
{
|
|
// last line of multi line block with further blocks in line
|
|
ret = CFILE_BLOCK_DETECT_END;
|
|
}
|
|
|
|
switch (ret)
|
|
{
|
|
case CFILE_BLOCK_DETECT_START:
|
|
{
|
|
*aPosition = (aRemove ? blockStart : blockStart + strlen(aBlockStart));
|
|
break;
|
|
}
|
|
case CFILE_BLOCK_DETECT_END:
|
|
{
|
|
*aPosition = (aRemove ? blockEnd + strlen(aBlockEnd) : blockEnd);
|
|
break;
|
|
}
|
|
case CFILE_BLOCK_DETECT_NONE:
|
|
{
|
|
*aPosition = NULL;
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
ret = CFILE_BLOCK_DETECT_ERROR;
|
|
*aPosition = NULL;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/*!
|
|
* @brief Remove blocks defined by "start" and "end"
|
|
* @attention May be called multiple time (for a whole file). *aHelper must not be changed within the process.
|
|
* @param [in] *aLine Terminated line (e.g. read from a file getline())
|
|
* @param [in] *aBlockStart Terminated string defining the start of a block
|
|
* @param [in] *aBlockEnd Terminated string defining the end of a block
|
|
* @param [in,out] *aHelper Storage for block traversal
|
|
* @param [in] aRemove false - remove only content of block; true - also remove block strings
|
|
* @retval 0 Blocks removed or none found
|
|
* @retval 1 Line only within block
|
|
* @retval -1 Invalid block ending ("end" without corresponding "start")
|
|
* @retval -2 Null pointer detected
|
|
*/
|
|
STATIC int8_t cBlockRemoval(char *aLine, const char *aBlockStart, const char *aBlockEnd, uint32_t *aHelper, bool aRemove, bool aIgnore)
|
|
{
|
|
const uint8_t depth = 1; // preparation to support which depth should be removed for nested block
|
|
bool blockLine = false;
|
|
int8_t ret = -1;
|
|
bool whileRun = true;
|
|
char *blockWorker = NULL;
|
|
char *blockMatch = NULL;
|
|
char *blockStart = NULL;
|
|
cfile_block_return_t blockDetected = CFILE_BLOCK_DETECT_NONE;
|
|
|
|
if (NULL == aLine || NULL == aBlockStart || NULL == aBlockEnd || NULL == aHelper)
|
|
{
|
|
perror("Null pointer");
|
|
return -2;
|
|
}
|
|
|
|
blockWorker = aLine;
|
|
if (depth <= *aHelper)
|
|
{
|
|
blockStart = aLine;
|
|
blockLine = true;
|
|
}
|
|
|
|
while (whileRun && CFILE_BLOCK_DETECT_NONE <= (blockDetected = cBlockDetection(aBlockStart, aBlockEnd, blockWorker, &blockMatch, aRemove)))
|
|
{
|
|
switch (blockDetected)
|
|
{
|
|
case CFILE_BLOCK_DETECT_START:
|
|
{
|
|
// additional starts within depth are ignored if aIgnore is true
|
|
// e.g. C comments are not allowed to be nested
|
|
if (!(aIgnore && depth <= *aHelper))
|
|
{
|
|
++*aHelper;
|
|
if (NULL == blockStart && depth <= *aHelper)
|
|
{
|
|
blockStart = blockMatch;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
printf(CPARS_WARNING_START"Nested block start \"%s\": %s", aBlockStart, aLine);
|
|
}
|
|
blockWorker = (aRemove ? blockMatch + strlen(aBlockStart) : blockMatch);
|
|
break;
|
|
}
|
|
case CFILE_BLOCK_DETECT_END:
|
|
{
|
|
if (NULL != blockStart)
|
|
{
|
|
// inline comment
|
|
if (depth < *aHelper)
|
|
{
|
|
// remove block elements within depth + n
|
|
blockMatch += (aRemove ? 0 : strlen(aBlockEnd));
|
|
}
|
|
strlcpy(blockStart, blockMatch, strlen(blockMatch) + 1);
|
|
blockMatch = NULL;
|
|
if (depth >= *aHelper)
|
|
{
|
|
// block removed when last end is hit
|
|
blockWorker = (aRemove ? blockStart : blockStart + strlen(aBlockEnd));
|
|
blockStart = NULL;
|
|
}
|
|
else
|
|
{
|
|
blockWorker = blockStart;
|
|
}
|
|
}
|
|
|
|
if (depth == *aHelper)
|
|
{
|
|
blockLine = false;
|
|
}
|
|
if (0 < *aHelper)
|
|
{
|
|
--*aHelper;
|
|
}
|
|
else
|
|
{
|
|
// error closing brace without beginning
|
|
whileRun = false;
|
|
ret = -1;
|
|
}
|
|
break;
|
|
}
|
|
case CFILE_BLOCK_DETECT_NONE:
|
|
{
|
|
if (NULL != blockStart && depth <= *aHelper)
|
|
{
|
|
// lines within a block
|
|
strlcpy(blockStart, CPARS_LINE_ENDING, strlen(CPARS_LINE_ENDING) + 1);
|
|
}
|
|
whileRun = false;
|
|
if (blockLine)
|
|
{
|
|
ret = 1;
|
|
}
|
|
else
|
|
{
|
|
ret = 0;
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
perror("Fatal unknown case");
|
|
whileRun = false;
|
|
ret = -1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/*!
|
|
* @brief Remove comments from given line
|
|
* @param [in] *aLine terminated string
|
|
* @return see \ref cBlockRemoval()
|
|
* @retval -2 NULL pointer detected
|
|
*/
|
|
STATIC int8_t removeCcomments(char *aLine)
|
|
{
|
|
char *comment = NULL;
|
|
|
|
if (NULL == aLine)
|
|
{
|
|
perror("Null pointer");
|
|
return -2;
|
|
}
|
|
|
|
// remove basic inline comments
|
|
comment = strstr(aLine, CPARS_COMMENT_INLINE);
|
|
if (NULL != comment)
|
|
{
|
|
strlcpy(comment, CPARS_LINE_ENDING, strlen(CPARS_LINE_ENDING) + 1);
|
|
comment = NULL;
|
|
}
|
|
|
|
return cBlockRemoval(aLine, CPARS_COMMENT_BLOCK_START, CPARS_COMMENT_BLOCK_END, &cfile_parser_removeCommentHelper, true, true);
|
|
}
|
|
|
|
/*!
|
|
* @brief Replace ',' within function pointer parameter with '#'
|
|
* @attention must be reverted (\ref revertFunctionPointer) before usage
|
|
* @param [in,out] *aParameter String of parameter
|
|
* @retval uint32_t Amount of ',' replaced
|
|
*/
|
|
uint32_t prepareFunctionPointer(char *aParameter)
|
|
{
|
|
uint32_t matches = 0;
|
|
char *worker = aParameter;
|
|
regmatch_t matchGroup[CFILE_PARSER_MAX_REGEX_MATCHING_GROUPS];
|
|
while (0 == regexec(®XfuPtrSeparator, worker, CFILE_PARSER_MAX_REGEX_MATCHING_GROUPS, matchGroup, 0) && XREGEX_IS_MATCHGROUP(matchGroup, 1))
|
|
{
|
|
++matches;
|
|
worker[matchGroup[1].rm_so] = '#';
|
|
}
|
|
return matches;
|
|
}
|
|
|
|
/*!
|
|
* @brief Revert '#' within function pointer parameter to ','
|
|
* @param [in,out] *aParameter String of parameter
|
|
* @retval uint32_t Amount of '#' replaced
|
|
*/
|
|
uint32_t revertFunctionPointer(char *aParameter)
|
|
{
|
|
uint32_t matches = 0;
|
|
char *worker = aParameter;
|
|
while ((worker = strstr(worker, "#")))
|
|
{
|
|
++matches;
|
|
*worker = ',';
|
|
}
|
|
return matches;
|
|
}
|
|
|
|
STATIC int8_t evaluateParameter(char *aParameter, cfunction_t *aFunction)
|
|
{
|
|
char *token = NULL;
|
|
regmatch_t matchGroup[CFILE_PARSER_MAX_REGEX_MATCHING_GROUPS];
|
|
cfunction_parameter_t *tempParameter = NULL;
|
|
|
|
if (NULL == aParameter || NULL == aFunction)
|
|
{
|
|
return -1;
|
|
}
|
|
prepareFunctionPointer(aParameter);
|
|
token = strtok(aParameter, ",");
|
|
while (token)
|
|
{
|
|
if (0 == regexec(®XfunctionPointer, token, CFILE_PARSER_MAX_REGEX_MATCHING_GROUPS, matchGroup, 0))
|
|
{
|
|
// TODO only "1 dimensional" function pointer supported (e.g. void (**func)(void) NOT SUPPORTED)
|
|
(void) revertFunctionPointer(token);
|
|
|
|
tempParameter = cfunction_newParameter(&aFunction->parameter);
|
|
tempParameter->type = CPARAMETER_TYPE_FUNCPTR;
|
|
|
|
if (XREGEX_IS_MATCHGROUP(matchGroup, 1))
|
|
{
|
|
xmallocStrlcpy(&tempParameter->dataType, &token[matchGroup[1].rm_so], XREGEX_SIZEOF_MATCHGROUP(matchGroup, 1));
|
|
if (NULL != tempParameter->dataType)
|
|
{
|
|
xStringTrim(tempParameter->dataType, XREGEX_SIZEOF_MATCHGROUP(matchGroup, 1));
|
|
}
|
|
}
|
|
if (XREGEX_IS_MATCHGROUP(matchGroup, 2))
|
|
{
|
|
xmallocStrlcpy(&tempParameter->name, &token[matchGroup[2].rm_so], XREGEX_SIZEOF_MATCHGROUP(matchGroup, 2));
|
|
if (NULL != tempParameter->name)
|
|
{
|
|
xStringTrim(tempParameter->name, XREGEX_SIZEOF_MATCHGROUP(matchGroup, 2));
|
|
}
|
|
}
|
|
if (XREGEX_IS_MATCHGROUP(matchGroup, 3))
|
|
{
|
|
xmallocStrlcpy(&tempParameter->array, &token[matchGroup[3].rm_so], XREGEX_SIZEOF_MATCHGROUP(matchGroup, 3));
|
|
if (NULL != tempParameter->array)
|
|
{
|
|
xStringTrim(tempParameter->array, XREGEX_SIZEOF_MATCHGROUP(matchGroup, 3));
|
|
}
|
|
}
|
|
|
|
}
|
|
else if (0 == regexec(®Xparameter, token, CFILE_PARSER_MAX_REGEX_MATCHING_GROUPS, matchGroup, 0))
|
|
{
|
|
tempParameter = cfunction_newParameter(&aFunction->parameter);
|
|
tempParameter->type = CPARAMETER_TYPE_REGULAR;
|
|
if (XREGEX_IS_MATCHGROUP(matchGroup, 1))
|
|
{
|
|
xmallocStrlcpy(&tempParameter->dataType, &token[matchGroup[1].rm_so], XREGEX_SIZEOF_MATCHGROUP(matchGroup, 1));
|
|
if (NULL != tempParameter->dataType)
|
|
{
|
|
xStringTrim(tempParameter->dataType, XREGEX_SIZEOF_MATCHGROUP(matchGroup, 1));
|
|
}
|
|
}
|
|
if (XREGEX_IS_MATCHGROUP(matchGroup, 2))
|
|
{
|
|
xmallocStrlcpy(&tempParameter->name, &token[matchGroup[2].rm_so], XREGEX_SIZEOF_MATCHGROUP(matchGroup, 2));
|
|
if (NULL != tempParameter->name)
|
|
{
|
|
xStringTrim(tempParameter->name, XREGEX_SIZEOF_MATCHGROUP(matchGroup, 2));
|
|
}
|
|
}
|
|
if (XREGEX_IS_MATCHGROUP(matchGroup, 3))
|
|
{
|
|
xmallocStrlcpy(&tempParameter->array, &token[matchGroup[3].rm_so], XREGEX_SIZEOF_MATCHGROUP(matchGroup, 3));
|
|
if (NULL != tempParameter->array)
|
|
{
|
|
xStringTrim(tempParameter->array, XREGEX_SIZEOF_MATCHGROUP(matchGroup, 2));
|
|
}
|
|
}
|
|
}
|
|
token = strtok(NULL, ",");
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
STATIC int8_t cfile_parser_evaluateExpression(char *aExpression, cfile_t *aCfile)
|
|
{
|
|
char *tempChar = NULL;
|
|
cfile_variable_t *variable = NULL;
|
|
cfunction_t *function = NULL;
|
|
regmatch_t matchGroup[CFILE_PARSER_MAX_REGEX_MATCHING_GROUPS];
|
|
|
|
if (NULL == aExpression || NULL == aCfile)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
if (0 == regexec(®Xfunction, aExpression, CFILE_PARSER_MAX_REGEX_MATCHING_GROUPS, matchGroup,
|
|
REG_NOTEOL) && CFILE_PARSER_IS_MATCHGROUP_FUNCTION(matchGroup))
|
|
{
|
|
printMatchGroup(aExpression, matchGroup);
|
|
function = cfunction_addNewFunction(&aCfile->functions);
|
|
(void) matchPrefix(function, CELEMENT_TYPE_FUNCTION, &aExpression[matchGroup[1].rm_so], XREGEX_SIZEOF_MATCHGROUP(matchGroup, 1));
|
|
checkFunctionType(function, aExpression);
|
|
xmallocStrlcpy(&function->name, &aExpression[matchGroup[2].rm_so], XREGEX_SIZEOF_MATCHGROUP(matchGroup, 2));
|
|
if (XREGEX_IS_MATCHGROUP(matchGroup, 3))
|
|
{
|
|
xmallocStrlcat(&tempChar, &aExpression[matchGroup[3].rm_so], XREGEX_SIZEOF_MATCHGROUP(matchGroup, 3));
|
|
if (NULL != tempChar)
|
|
{
|
|
evaluateParameter(tempChar, function);
|
|
}
|
|
xfree((void**) &tempChar);
|
|
}
|
|
}
|
|
else if (0 == regexec(®Xvariable, aExpression, CFILE_PARSER_MAX_REGEX_MATCHING_GROUPS, matchGroup,
|
|
REG_NOTEOL) && XREGEX_IS_MATCHGROUP(matchGroup, 1))
|
|
{
|
|
printMatchGroup(aExpression, matchGroup);
|
|
variable = cfile_newVariable(&aCfile->variables);
|
|
if (variable)
|
|
{
|
|
(void) matchPrefix(variable, CELEMENT_TYPE_VARIABLE, &aExpression[matchGroup[1].rm_so], XREGEX_SIZEOF_MATCHGROUP(matchGroup, 1));
|
|
xmallocStrlcpy(&variable->name, &aExpression[matchGroup[2].rm_so], XREGEX_SIZEOF_MATCHGROUP(matchGroup, 2));
|
|
// contains array information if available "[10]"
|
|
if (XREGEX_IS_MATCHGROUP(matchGroup, 3))
|
|
{
|
|
xmallocStrlcpy(&tempChar, &aExpression[matchGroup[3].rm_so], XREGEX_SIZEOF_MATCHGROUP(matchGroup, 3));
|
|
if (NULL != tempChar)
|
|
{
|
|
xStringTrim(tempChar, strlen(tempChar));
|
|
}
|
|
|
|
if (2 == strlen(tempChar) - xStrCount(tempChar, ' '))
|
|
{
|
|
// array without size definition
|
|
xmallocStrlcat(&variable->dataType, "*", 1);
|
|
}
|
|
else
|
|
{
|
|
xmallocStrlcpy(&variable->array, tempChar, strlen(tempChar));
|
|
}
|
|
|
|
xfree((void**) &tempChar);
|
|
}
|
|
}
|
|
}
|
|
else if (0 == regexec(®XfunctionPointer, aExpression, CFILE_PARSER_MAX_REGEX_MATCHING_GROUPS, matchGroup, 0) //
|
|
&& XREGEX_IS_MATCHGROUP(matchGroup, 1) //
|
|
&& XREGEX_IS_MATCHGROUP(matchGroup, 2) //
|
|
&& XREGEX_IS_MATCHGROUP(matchGroup, 3))
|
|
{
|
|
// TODO only "1 dimensional" function pointer supported (e.g. void (**func)(void) NOT SUPPORTED)
|
|
printMatchGroup(aExpression, matchGroup);
|
|
variable = cfile_newVariable(&aCfile->variables);
|
|
if (variable)
|
|
{
|
|
(void) matchPrefix(variable, CELEMENT_TYPE_VARIABLE, &aExpression[matchGroup[1].rm_so], XREGEX_SIZEOF_MATCHGROUP(matchGroup, 1));
|
|
CVARIABLE_SET_TYPE(variable->type, CVARIABLE_TYPE_FUPTR);
|
|
xmallocStrlcpy(&variable->name, &aExpression[matchGroup[2].rm_so], XREGEX_SIZEOF_MATCHGROUP(matchGroup, 2));
|
|
// contains array information if available "[10]"
|
|
if (XREGEX_IS_MATCHGROUP(matchGroup, 3))
|
|
{
|
|
xmallocStrlcpy(&variable->array, &aExpression[matchGroup[3].rm_so], XREGEX_SIZEOF_MATCHGROUP(matchGroup, 3));
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
STATIC uint32_t cfile_parser_evaluateLine(uint32_t aNumber, char *aLine, cfile_t *aCfile)
|
|
{
|
|
char *position = aLine;
|
|
uint32_t warnings = 0;
|
|
static char *match = NULL;
|
|
static uint8_t depth = 0;
|
|
char *tempMatch = NULL;
|
|
char *tempChar = NULL;
|
|
int8_t ret = 0;
|
|
|
|
regex_t *matchStart = ®XExpressionStart;
|
|
regex_t *matchEnd = ®XExpressionEnd;
|
|
|
|
ret = removeCcomments(aLine);
|
|
if (-1 == ret)
|
|
{
|
|
++warnings;
|
|
}
|
|
else if (0 != ret)
|
|
{
|
|
return 0;
|
|
}
|
|
ret = cBlockRemoval(aLine, "{", "}", &cfile_parser_removeBraceHelper, false, false);
|
|
if (-1 == ret)
|
|
{
|
|
++warnings;
|
|
}
|
|
else if (0 != ret)
|
|
{
|
|
return 0;
|
|
}
|
|
DEBUG_LOG_APPEND(2, "[ Li %04u] %s", aNumber, aLine);
|
|
tempChar = strrchr(aLine, '\n');
|
|
if (tempChar)
|
|
{
|
|
*tempChar = '\0';
|
|
}
|
|
tempChar = strrchr(aLine, '\r');
|
|
if (tempChar)
|
|
{
|
|
*tempChar = '\0';
|
|
}
|
|
|
|
while (position)
|
|
{
|
|
if (NULL != (tempMatch = strstr(position, "#include")))
|
|
{
|
|
// TODO save include information
|
|
DEBUG_LOG_APPEND(1, "[ Re %04u][%zu] %s\n", aNumber, strlen(tempMatch), tempMatch);
|
|
position = NULL;
|
|
continue;
|
|
}
|
|
warnings += regExWorker(&match, &position, matchStart, matchEnd, &depth, false);
|
|
if (match && 0 == depth)
|
|
{
|
|
DEBUG_LOG_APPEND(1, "[ Re %04u][%zu] %s\n", aNumber, strlen(match), match);
|
|
// Evaluate C expression
|
|
(void) cfile_parser_evaluateExpression(match, aCfile);
|
|
xfree((void**) &match);
|
|
}
|
|
}
|
|
return warnings;
|
|
}
|
|
|
|
uint32_t cfile_parser(char *aPath, cfile_t *aCfile)
|
|
{
|
|
FILE *fdesc;
|
|
ssize_t charRead = 0;
|
|
size_t lineSize = 0;
|
|
uint32_t lineNumber = 0;
|
|
char *fileLine = NULL; // will be allocated by getline(); must be freed
|
|
uint32_t warningCounter = 0;
|
|
|
|
if (false == cfile_parser_initialized)
|
|
{
|
|
cfile_parser_init();
|
|
}
|
|
|
|
fdesc = fopen(aPath, "r");
|
|
if (NULL == fdesc)
|
|
{
|
|
perror("Error open file");
|
|
return -1;
|
|
}
|
|
|
|
do
|
|
{
|
|
charRead = getline(&fileLine, &lineSize, fdesc);
|
|
if (0 <= charRead)
|
|
{
|
|
lineNumber++;
|
|
warningCounter += cfile_parser_evaluateLine(lineNumber, fileLine, aCfile);
|
|
}
|
|
} while (0 <= charRead);
|
|
|
|
free(fileLine);
|
|
(void) fclose(fdesc);
|
|
|
|
// error detection for block removal
|
|
if (0 != cfile_parser_removeCommentHelper || 0 != cfile_parser_removeBraceHelper)
|
|
{
|
|
DEBUG_LOG_APPEND(1, "Helper (%d/%d) %s\n", cfile_parser_removeCommentHelper, cfile_parser_removeBraceHelper, gnu_basename(aPath));
|
|
cfile_parser_removeCommentHelper = 0;
|
|
cfile_parser_removeBraceHelper = 0;
|
|
++warningCounter;
|
|
}
|
|
|
|
// if (warningCounter)
|
|
// {
|
|
// ret = -4;
|
|
// }
|
|
|
|
return warningCounter;
|
|
}
|