WIP recursive line worker detects C variable and function definitions

- todo: detect expressione type (function, variable, ...)
This commit is contained in:
2017-03-09 08:04:29 +00:00
parent 4fd1780b42
commit 11d281fe75
11 changed files with 365 additions and 27 deletions

View File

@@ -71,3 +71,9 @@ char* xmallocStrlcat(char **aDest, char *aSource, size_t aSize)
return *aDest; return *aDest;
} }
void xfree(void **aDest)
{
free(*aDest);
*aDest = NULL;
}

View File

@@ -17,6 +17,7 @@
#include <malloc.h> #include <malloc.h>
void *xmalloc(size_t size); void *xmalloc(size_t size);
void xfree(void**);
char* xmallocStrlcpy(char **aDest, char *aSource, size_t aSize); char* xmallocStrlcpy(char **aDest, char *aSource, size_t aSize);
char* xmallocStrlcat(char **aDest, char *aSource, size_t aSize); char* xmallocStrlcat(char **aDest, char *aSource, size_t aSize);

79
src/stubser/cfile.c Normal file
View File

@@ -0,0 +1,79 @@
/*!
* @file cfile.c
* @brief
* @details
* Project: \n
* Subsystem: \n
* Module: \n
* Code: GNU-C\n
*
* @date 08.03.2017
* @author SESA354004
*/
#include <stdio.h>
#include <string.h>
#include "xtypes.h"
#include "xmalloc.h"
#include "cfile_if.h"
cfile_variable_t* cfile_newVariable(cfile_variableList_t *aList)
{
cfile_variable_t *new = NULL;
if (NULL == aList)
{
perror("Null pointer");
return NULL;
}
new = (cfile_variable_t*) xmalloc(sizeof(cfile_variable_t));
memset(new, 0, sizeof(cfile_variable_t));
if (NULL == aList->head)
{
aList->head = new;
aList->current = new;
}
else
{
aList->current->next = new;
aList->current = new;
}
++aList->amount;
return new;
}
int8_t cfile_freeVariables(cfile_variableList_t *aVariable)
{
cfile_variable_t *work = NULL;
cfile_variable_t *next = NULL;
if (NULL == aVariable)
{
perror("Null pointer");
return -1;
}
work = aVariable->head;
while (work)
{
next = work->next;
free(work->type);
free(work->name);
free(work);
work = next;
}
aVariable->amount = 0;
aVariable->head = NULL;
aVariable->current = NULL;
return 0;
}
void cfile_free(cfile_t *aCfile)
{
cfile_freeVariables(&aCfile->variables);
cfunction_freeList(&aCfile->functions);
}

53
src/stubser/cfile_if.h Normal file
View File

@@ -0,0 +1,53 @@
/*!
* @file cfile_if.h
* @brief
* @details
* Project: \n
* Subsystem: \n
* Module: \n
* Code: GNU-C\n
*
* @date 08.03.2017
* @author SESA354004
*/
#ifndef STUBSER_CFILE_IF_H_
#define STUBSER_CFILE_IF_H_
#include "cfunction_if.h"
/*! @brief Parameter list node */
typedef struct _CFILE_VARIABLE_T
{
char* prefix; /*!< @brief variable prefix (e.g. static) */
char* type; /*!< @brief data type */
char* name; /*!< @brief name */
struct _CFILE_VARIABLE_T *next;
} cfile_variable_t;
/*! @brief parameter array */
typedef struct _CFILE_VARIABLE_LIST_T
{
uint8_t amount;
cfile_variable_t *head;
cfile_variable_t *current;
} cfile_variableList_t;
/*! @brief brief_description */
typedef struct _CFILE_T
{
cfile_variableList_t variables; /*! @brief C variables */
cfunction_list_t functions; /*!< @brief C functions */
} cfile_t;
#define CFILE_T_DEFAULT {\
.variables.amount = 0, \
.variables.head = NULL, \
.variables.current = NULL, \
.functions = CFUNCTION_LIST_DEFAULT }
cfile_variable_t* cfile_newVariable(cfile_variableList_t *aList);
int8_t cfile_freeVariables(cfile_variableList_t *aVariable);
void cfile_free(cfile_t *aCfile);
#endif /* STUBSER_CFILE_IF_H_ */

View File

@@ -17,12 +17,11 @@
#include "xtypes.h" #include "xtypes.h"
#include "xstring.h" #include "xstring.h"
#include "xmalloc.h" #include "xmalloc.h"
#include "cfunction_if.h" #include "cfile_if.h"
#include "cfile_parser_loc.h" #include "cfile_parser_loc.h"
#include "cfile_parser_worker_loc.h"
#include "debug.h" #include "debug.h"
#define CFILE_PARSER_MAX_REGEX_MATCHING_GROUPS 10
/*! @brief Block detection return values */ /*! @brief Block detection return values */
typedef enum _CFILE_BLOCK_RETURN_T typedef enum _CFILE_BLOCK_RETURN_T
{ {
@@ -44,6 +43,11 @@ STATIC regex_t regXmlProto;
STATIC regex_t regXproto; STATIC regex_t regXproto;
STATIC regex_t regXprefix; STATIC regex_t regXprefix;
STATIC regex_t regXparameter; STATIC regex_t regXparameter;
STATIC regex_t regXvariable;
STATIC regex_t regXExpressionStart;
STATIC regex_t regXExpressionAssign;
STATIC regex_t regXExpressionEnd;
// line evaluation related variables // line evaluation related variables
STATIC uint32_t cfile_parser_removeCommentHelper = 0; STATIC uint32_t cfile_parser_removeCommentHelper = 0;
@@ -52,6 +56,21 @@ STATIC char *cfile_parser_parameterStorage = NULL;
int8_t cfile_parser_init() int8_t cfile_parser_init()
{ {
if (0 > regcomp(&regXExpressionStart, CPARS_EXPRESSION_START, (REG_EXTENDED | REG_NEWLINE)))
{
perror("Error regex\n");
return -1;
}
if (0 > regcomp(&regXExpressionAssign, CPARS_EXPRESSION_EXPEND, (REG_EXTENDED | REG_NEWLINE)))
{
perror("Error regex\n");
return -1;
}
if (0 > regcomp(&regXExpressionEnd, CPARS_EXPRESSION_END, (REG_EXTENDED | REG_NEWLINE)))
{
perror("Error regex\n");
return -1;
}
if (0 > regcomp(&regX, FUNCTION_BASE, (REG_EXTENDED | REG_NEWLINE))) if (0 > regcomp(&regX, FUNCTION_BASE, (REG_EXTENDED | REG_NEWLINE)))
{ {
perror("Error regex\n"); perror("Error regex\n");
@@ -97,6 +116,11 @@ int8_t cfile_parser_init()
perror("Error regex\n"); perror("Error regex\n");
return -1; return -1;
} }
if (0 > regcomp(&regXvariable, CPARS_REGEX_VARIABLE, (REG_EXTENDED | REG_NEWLINE)))
{
perror("Error regex\n");
return -1;
}
cfile_parser_initialized = true; cfile_parser_initialized = true;
return 0; return 0;
@@ -471,6 +495,7 @@ STATIC int8_t evaluateParameter(char *aParameter, cfunction_t *aFunction)
return 0; return 0;
} }
#if(0)
/*! /*!
* @brief Process a string (e.g. from getline()) if it is a single or multiple line function definition * @brief Process a string (e.g. from getline()) if it is a single or multiple line function definition
* @todo closing parenthesis within parameter list will break the detection * @todo closing parenthesis within parameter list will break the detection
@@ -478,7 +503,7 @@ STATIC int8_t evaluateParameter(char *aParameter, cfunction_t *aFunction)
* @retval -2 Given String not a function * @retval -2 Given String not a function
* @retval 0 function evaluated * @retval 0 function evaluated
*/ */
STATIC cfunction_t* cfile_parser_evaluateLine(char *aLine) STATIC cfunction_t* cfile_parser_evaluateLine1(char *aLine)
{ {
const size_t maxGroup = CFILE_PARSER_MAX_REGEX_MATCHING_GROUPS; const size_t maxGroup = CFILE_PARSER_MAX_REGEX_MATCHING_GROUPS;
regmatch_t matchGroup[maxGroup]; regmatch_t matchGroup[maxGroup];
@@ -573,7 +598,7 @@ STATIC cfunction_t* cfile_parser_evaluateLine(char *aLine)
switch (cfile_parser_functionLine) switch (cfile_parser_functionLine)
{ {
case 0: // single line function definition case 0: // single line function definition
case 1: // first line of multi line function definition case 1:// first line of multi line function definition
{ {
// TODO multiple functions in one line // TODO multiple functions in one line
cfile_parser_function = cfunction_newFunction(); cfile_parser_function = cfunction_newFunction();
@@ -623,12 +648,63 @@ STATIC cfunction_t* cfile_parser_evaluateLine(char *aLine)
return NULL; return NULL;
} }
#endif
int8_t cfile_parser(char *aPath, cfunction_list_t *aList) STATIC bool workerActive = false;
const stringWorker cWorker[2] =
{ cfile_expWorker, // Parse for variables
NULL };
STATIC char *match = NULL;
STATIC int8_t cfile_parser_evaluateLine(uint32_t aNumber, char *aLine, cfile_t *aCfile)
{
stringWorker *worker = (stringWorker*) cWorker;
char *position = aLine;
char *result = NULL;
size_t cSize = 0;
regex_t *matchStart = &regXExpressionStart;
regex_t *matchEnd = &regXExpressionEnd;
DEBUG_LOG_APPEND(1, "[ Li %04u] %s\n", aNumber, aLine);
// start with variable worker
while (position && NULL != *worker)
{
result = (*worker)(&position, matchStart, matchEnd, &workerActive, &cSize);
if (NULL == result)
{
if (false == workerActive)
{
xfree((void**) &match);
++worker;
}
continue;
}
xmallocStrlcat(&match, result, cSize);
if (false == workerActive)
{
DEBUG_LOG_APPEND(1, "Works %zu %s\n", cSize, match);
// TODO evaluate expression according to worker
xfree((void**) &match);
worker = (stringWorker*) cWorker;
}
else
{
// force space between findings
xmallocStrlcat(&match, " ", 2);
}
}
return 0;
}
int8_t cfile_parser(char *aPath, cfile_t *aCfile)
{ {
FILE *fdesc; FILE *fdesc;
ssize_t charRead = 0; ssize_t charRead = 0;
size_t lineSize = 0; size_t lineSize = 0;
uint32_t lineNumber = 1;
char *cTemp = NULL;
char *fileLine = NULL; // will be allocated by getline(); must be freed char *fileLine = NULL; // will be allocated by getline(); must be freed
if (false == cfile_parser_initialized) if (false == cfile_parser_initialized)
@@ -648,12 +724,25 @@ int8_t cfile_parser(char *aPath, cfunction_list_t *aList)
charRead = getline(&fileLine, &lineSize, fdesc); charRead = getline(&fileLine, &lineSize, fdesc);
if (0 <= charRead) if (0 <= charRead)
{ {
cfunction_t *function = NULL; if (0 != removeCcomments(fileLine))
function = cfile_parser_evaluateLine(fileLine);
if (NULL != function)
{ {
(void) cfunction_addFunction(aList, function); continue;
} }
if (0 != cBlockRemoval(fileLine, "{", "}", &cfile_parser_removeBraceHelper, false, false))
{
continue;
}
cTemp = strrchr(fileLine, '\n');
if (cTemp)
{
*cTemp = '\0';
}
cTemp = strrchr(fileLine, '\r');
if (cTemp)
{
*cTemp = '\0';
}
(void) cfile_parser_evaluateLine(lineNumber++, fileLine, aCfile);
} }
} while (0 <= charRead); } while (0 <= charRead);

View File

@@ -14,6 +14,6 @@
#ifndef STUBSER_CFILE_PARSER_IF_H_ #ifndef STUBSER_CFILE_PARSER_IF_H_
#define STUBSER_CFILE_PARSER_IF_H_ #define STUBSER_CFILE_PARSER_IF_H_
int8_t cfile_parser(char *aPath, cfunction_list_t *aList); int8_t cfile_parser(char *aPath, cfile_t *aList);
#endif /* STUBSER_CFILE_PARSER_IF_H_ */ #endif /* STUBSER_CFILE_PARSER_IF_H_ */

View File

@@ -14,6 +14,8 @@
#ifndef STUBSER_CFILE_PARSER_LOC_H_ #ifndef STUBSER_CFILE_PARSER_LOC_H_
#define STUBSER_CFILE_PARSER_LOC_H_ #define STUBSER_CFILE_PARSER_LOC_H_
#define CFILE_PARSER_MAX_REGEX_MATCHING_GROUPS 10
#define CPARS_LINE_ENDING "\r\n" #define CPARS_LINE_ENDING "\r\n"
#define CPARS_COMMENT_INLINE "//" #define CPARS_COMMENT_INLINE "//"
#define CPARS_COMMENT_BLOCK_START "/*" #define CPARS_COMMENT_BLOCK_START "/*"
@@ -27,10 +29,25 @@
#define FUNCTION_ML_PROTO FUNCTION_ML_PAR "\\).*[[:blank:]]*;" #define FUNCTION_ML_PROTO FUNCTION_ML_PAR "\\).*[[:blank:]]*;"
#define FUNCTION_PROTO FUNCTION_BASE "\\).*[[:blank:]]*;" #define FUNCTION_PROTO FUNCTION_BASE "\\).*[[:blank:]]*;"
#define CPARS_REGEX_VARIABLE "^[[:blank:]]*([ _\\*[:alnum:]]*)[[:blank:]]*[;=]"
#define CPARS_REGEX_PARAMETER "[[:blank:]]*([ _\\*[:alnum:]]* +\\**)([_\\*[:alnum:]]*)[[:blank:]]*" #define CPARS_REGEX_PARAMETER "[[:blank:]]*([ _\\*[:alnum:]]* +\\**)([_\\*[:alnum:]]*)[[:blank:]]*"
#define CPARS_REGEX_PREFIX "(extern|EXTERN|static|STATIC|volatile|near|far)[[:blank:]]+([^\\*]*\\**)" #define CPARS_REGEX_PREFIX "(extern|EXTERN|static|STATIC|volatile|near|far)[[:blank:]]+([^\\*]*\\**)"
#define CPARS_EXPRESSION_START "^[[:blank:]]*([A-Za-z][\\_\\*[:alnum:]]*)"
#define CPARS_EXPRESSION_EXPEND "[[:blank:]]*([=\{])[[:blank:]]*"
#define CPARS_EXPRESSION_END "[[:blank:]]*([\\};]+)"
#define CFILE_PARSER_IS_MATCHGROUP_FUNCTION(matchGroup) (XREGEX_IS_MATCHGROUP(matchGroup, 1) && XREGEX_IS_MATCHGROUP(matchGroup, 2)) #define CFILE_PARSER_IS_MATCHGROUP_FUNCTION(matchGroup) (XREGEX_IS_MATCHGROUP(matchGroup, 1) && XREGEX_IS_MATCHGROUP(matchGroup, 2))
/*! @brief Type of function definition */
typedef enum _CELEMENT_TYPE_T
{
CELEMENT_TYPE_UNDEF = 0, /*!< @brief undefined */
CELEMENT_TYPE_INCLUDE = 1, /*!< @brief C #include */
CELEMENT_TYPE_DEFINE = 2, /*!< @brief C #define */
CELEMENT_TYPE_VARIABLE = 3, /*!< @brief Prototype C variable definition */
CELEMENT_TYPE_FUNCTION = 4, /*!< @brief Prototype C function definition */
CELEMENT_TYPE_LAST_ENUM
} celement_type_t;
#endif /* STUBSER_CFILE_PARSER_LOC_H_ */ #endif /* STUBSER_CFILE_PARSER_LOC_H_ */

View File

@@ -0,0 +1,69 @@
/*!
* @file cfile_parser_worker.c
* @brief
* @details
* Project: \n
* Subsystem: \n
* Module: \n
* Code: GNU-C\n
*
* @date 09.03.2017
* @author SESA354004
*/
#include "xtypes.h"
#include "xregex.h"
#include "debug.h"
#include "cfile_parser_loc.h"
#include "cfile_parser_worker_loc.h"
char* cfile_expWorker(char **aInput, const regex_t *aStart, const regex_t *aEnd, bool *aActive, size_t *aSize)
{
regmatch_t matchGroup[CFILE_PARSER_MAX_REGEX_MATCHING_GROUPS];
char *begin;
if (!**aInput)
{
*aInput = NULL;
return NULL;
}
if (!*aActive)
{
*aSize = 0;
begin = NULL;
}
else
{
begin = *aInput;
}
if (*aActive)
{
if (aEnd != NULL && 0 == regexec(aEnd, *aInput, CFILE_PARSER_MAX_REGEX_MATCHING_GROUPS, matchGroup, REG_NOTEOL) && XREGEX_IS_MATCHGROUP(matchGroup, 1))
{
DEBUG_LOG_APPEND(1, "[ CEe]");
*aActive = false;
*aSize += matchGroup[1].rm_so; // don't include end marker in result
*aInput += matchGroup[1].rm_eo;
return begin;
}
else
{
DEBUG_LOG_APPEND(1, "[ CE+]");
*aSize += strlen(*aInput);
*aInput += strlen(*aInput);
return begin;
}
}
else if (0 == regexec(aStart, *aInput, CFILE_PARSER_MAX_REGEX_MATCHING_GROUPS, matchGroup, REG_NOTEOL) && XREGEX_IS_MATCHGROUP(matchGroup, 1))
{
DEBUG_LOG_APPEND(1, "[ CEs]");
*aActive = true;
*aSize += XREGEX_SIZEOF_MATCHGROUP(matchGroup, 1);
begin = *aInput + matchGroup[1].rm_so;
*aInput += matchGroup[1].rm_eo;
cfile_expWorker(aInput, aStart, aEnd, aActive, aSize);
}
return begin;
}

View File

@@ -0,0 +1,21 @@
/*!
* @file cfile_parser_worker_loc.h
* @brief
* @details
* Project: \n
* Subsystem: \n
* Module: \n
* Code: GNU-C\n
*
* @date 09.03.2017
* @author SESA354004
*/
#ifndef STUBSER_CFILE_PARSER_WORKER_LOC_H_
#define STUBSER_CFILE_PARSER_WORKER_LOC_H_
typedef char* (*stringWorker)(char**, const regex_t *, const regex_t *, bool*, size_t*);
char* cfile_expWorker(char **aInput, const regex_t *aStart, const regex_t *aEnd, bool *aActive, size_t *aSize);
#endif /* STUBSER_CFILE_PARSER_WORKER_LOC_H_ */

View File

@@ -32,6 +32,14 @@ typedef struct _CFUNCTION_PARAMETER_T
struct _CFUNCTION_PARAMETER_T *next; struct _CFUNCTION_PARAMETER_T *next;
} cfunction_parameter_t; } cfunction_parameter_t;
/*! @brief parameter array */
typedef struct _CFUNCTION_PARAMETER_LIST_T
{
uint8_t amount;
cfunction_parameter_t *head;
cfunction_parameter_t *current;
} cfunction_parameterList_t;
/*! @brief brief_description */ /*! @brief brief_description */
typedef struct _CFUNCTION_T typedef struct _CFUNCTION_T
{ {
@@ -39,12 +47,7 @@ typedef struct _CFUNCTION_T
char *prefix; /*!< @brief prefix like static or extern */ char *prefix; /*!< @brief prefix like static or extern */
char *dataType; /*!< @brief return type */ char *dataType; /*!< @brief return type */
char *name; /*!< @brief name */ char *name; /*!< @brief name */
struct _CFUNCTION_PARAMETER_LIST_T cfunction_parameterList_t parameter;/*!< @brief parameter array */
{
uint8_t amount;
cfunction_parameter_t *head;
cfunction_parameter_t *current;
} parameter;/*!< @brief parameter array */
struct _CFUNCTION_T *next; struct _CFUNCTION_T *next;
} cfunction_t; } cfunction_t;

View File

@@ -19,7 +19,7 @@
#include "xtypes.h" #include "xtypes.h"
#include "xstring.h" #include "xstring.h"
#include "xmalloc.h" #include "xmalloc.h"
#include "cfunction_if.h" #include "cfile_if.h"
#include "cfile_parser_if.h" #include "cfile_parser_if.h"
#include "stubser_if.h" #include "stubser_if.h"
#include "stubser_loc.h" #include "stubser_loc.h"
@@ -194,7 +194,7 @@ STATIC int8_t createStubFunctionBlock(FILE *aFile, FILE *aHeader, cfunction_t *a
return 0; return 0;
} }
STATIC int8_t createStub(char *aOutput, char *aNoSuffix, cfunction_list_t *aFunctionList) STATIC int8_t createStub(char *aOutput, char *aNoSuffix, cfile_t *aCfile)
{ {
FILE *cfile; FILE *cfile;
FILE *cheader; FILE *cheader;
@@ -202,7 +202,7 @@ STATIC int8_t createStub(char *aOutput, char *aNoSuffix, cfunction_list_t *aFunc
char *cHeaderName = NULL; char *cHeaderName = NULL;
cfunction_t *function = NULL; cfunction_t *function = NULL;
if (NULL == aOutput || NULL == aFunctionList) if (NULL == aOutput || NULL == aCfile)
{ {
return -1; return -1;
} }
@@ -246,7 +246,7 @@ STATIC int8_t createStub(char *aOutput, char *aNoSuffix, cfunction_list_t *aFunc
fprintf(cheader, "#ifndef _STUB_%s_H"NEWLINES, aNoSuffix); fprintf(cheader, "#ifndef _STUB_%s_H"NEWLINES, aNoSuffix);
fprintf(cheader, "#define _STUB_%s_H"NEWLINES NEWLINES, aNoSuffix); fprintf(cheader, "#define _STUB_%s_H"NEWLINES NEWLINES, aNoSuffix);
function = aFunctionList->head; function = aCfile->functions.head;
while (function) while (function)
{ {
(void) createStubFunctionBlock(cfile, cheader, function); (void) createStubFunctionBlock(cfile, cheader, function);
@@ -271,12 +271,12 @@ STATIC int8_t createStub(char *aOutput, char *aNoSuffix, cfunction_list_t *aFunc
int stubser_createStub(char *path, char* aNoSuffix, char *aOutput) int stubser_createStub(char *path, char* aNoSuffix, char *aOutput)
{ {
int8_t ret = -1; int8_t ret = -1;
cfunction_list_t functionList = cfile_t cFile =
CFUNCTION_LIST_DEFAULT; CFILE_T_DEFAULT;
char fileName[PATH_MAX] = char fileName[PATH_MAX] =
{ '\0' }; { '\0' };
ret = cfile_parser(path, &functionList); ret = cfile_parser(path, &cFile);
DEBUG_LOG_APPEND(1, "\n"); DEBUG_LOG_APPEND(1, "\n");
if (0 != ret) if (0 != ret)
{ {
@@ -302,7 +302,7 @@ int stubser_createStub(char *path, char* aNoSuffix, char *aOutput)
printf(STUB_CONSOLE_PARSE_OK_S1, gnu_basename(path)); printf(STUB_CONSOLE_PARSE_OK_S1, gnu_basename(path));
#endif #endif
sprintf(fileName, "%s/stub_%s", aOutput, aNoSuffix); sprintf(fileName, "%s/stub_%s", aOutput, aNoSuffix);
ret = createStub(fileName, aNoSuffix, &functionList); ret = createStub(fileName, aNoSuffix, &cFile);
if (0 != ret) if (0 != ret)
{ {
printf(STUB_CONSOLE_CREATE_ERROR_S2, gnu_basename(path), ret); printf(STUB_CONSOLE_CREATE_ERROR_S2, gnu_basename(path), ret);
@@ -313,7 +313,7 @@ int stubser_createStub(char *path, char* aNoSuffix, char *aOutput)
end_stubser_createStub: // function end target end_stubser_createStub: // function end target
cfunction_freeList(&functionList); cfile_free(&cFile);
return ret; return ret;
} }