forked from Telodendria/Telodendria
Add support for parsing global variables, not just function declarations.
This commit is contained in:
parent
9292f1d9da
commit
a00ded6d06
5 changed files with 217 additions and 44 deletions
|
@ -505,8 +505,8 @@ HeaderParse(Stream * stream, HeaderExpr * expr)
|
|||
{
|
||||
int i = wordLen;
|
||||
|
||||
expr->type = HP_DECLARATION;
|
||||
strncpy(expr->data.declaration.returnType, word, wordLimit);
|
||||
expr->type = HP_GLOBAL;
|
||||
strncpy(expr->data.global.type, word, wordLimit);
|
||||
|
||||
if (strcmp(word, "struct") == 0 ||
|
||||
strcmp(word, "enum") == 0 ||
|
||||
|
@ -515,8 +515,9 @@ HeaderParse(Stream * stream, HeaderExpr * expr)
|
|||
Free(word);
|
||||
word = HeaderConsumeWord(expr);
|
||||
wordLen = strlen(word);
|
||||
expr->data.declaration.returnType[i] = ' ';
|
||||
strncpy(expr->data.declaration.returnType + i + 1, word, wordLen + 1);
|
||||
expr->data.global.type[i] = ' ';
|
||||
|
||||
strncpy(expr->data.global.type + i + 1, word, wordLen + 1);
|
||||
i += wordLen + 1;
|
||||
}
|
||||
|
||||
|
@ -525,13 +526,16 @@ HeaderParse(Stream * stream, HeaderExpr * expr)
|
|||
c = HeaderConsumeWhitespace(expr);
|
||||
if (c == '*')
|
||||
{
|
||||
expr->data.declaration.returnType[i] = ' ';
|
||||
expr->data.global.type[i] = ' ';
|
||||
|
||||
i++;
|
||||
expr->data.declaration.returnType[i] = '*';
|
||||
expr->data.global.type[i] = '*';
|
||||
|
||||
i++;
|
||||
while ((c = HeaderConsumeWhitespace(expr)) == '*')
|
||||
{
|
||||
expr->data.declaration.returnType[i] = c;
|
||||
expr->data.global.type[i] = c;
|
||||
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
@ -550,45 +554,94 @@ HeaderParse(Stream * stream, HeaderExpr * expr)
|
|||
}
|
||||
else
|
||||
{
|
||||
strncpy(expr->data.declaration.name, word, wordLimit);
|
||||
strncpy(expr->data.global.name, word, wordLimit);
|
||||
Free(word);
|
||||
word = NULL;
|
||||
|
||||
c = HeaderConsumeWhitespace(expr);
|
||||
if (c != '(')
|
||||
|
||||
if (c == ';')
|
||||
{
|
||||
/* That's the end of the global. */
|
||||
}
|
||||
else if (c == '[')
|
||||
{
|
||||
/* Looks like we have an array. Slurp all the dimensions */
|
||||
int block = 1;
|
||||
int i = wordLen;
|
||||
|
||||
expr->data.global.name[i] = '[';
|
||||
i++;
|
||||
|
||||
while (1)
|
||||
{
|
||||
if (i >= HEADER_EXPR_MAX - wordLen)
|
||||
{
|
||||
expr->type = HP_PARSE_ERROR;
|
||||
expr->data.error.msg = "Memory limit exceeded while parsing global array.";
|
||||
expr->data.error.lineNo = expr->state.lineNo;
|
||||
return;
|
||||
}
|
||||
|
||||
c = StreamGetc(expr->state.stream);
|
||||
|
||||
if (StreamEof(expr->state.stream) || StreamError(expr->state.stream))
|
||||
{
|
||||
expr->type = HP_SYNTAX_ERROR;
|
||||
expr->data.error.msg = "Unterminated global array.";
|
||||
expr->data.error.lineNo = expr->state.lineNo;
|
||||
return;
|
||||
}
|
||||
|
||||
if (c == ';')
|
||||
{
|
||||
expr->data.global.name[i] = '\0';
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
expr->data.global.name[i] = c;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (c == '(')
|
||||
{
|
||||
expr->type = HP_DECLARATION;
|
||||
expr->data.declaration.args = ArrayCreate();
|
||||
do
|
||||
{
|
||||
word = HeaderConsumeArg(expr);
|
||||
ArrayAdd(expr->data.declaration.args, word);
|
||||
word = NULL;
|
||||
}
|
||||
while ((!StreamEof(expr->state.stream)) && ((c = HeaderConsumeWhitespace(expr)) != ')'));
|
||||
|
||||
if (StreamEof(expr->state.stream))
|
||||
{
|
||||
expr->type = HP_SYNTAX_ERROR;
|
||||
expr->data.error.msg = "End of file reached before ')'.";
|
||||
expr->data.error.lineNo = expr->state.lineNo;
|
||||
return;
|
||||
}
|
||||
|
||||
c = HeaderConsumeWhitespace(expr);
|
||||
if (c != ';')
|
||||
{
|
||||
expr->type = HP_SYNTAX_ERROR;
|
||||
expr->data.error.msg = "Expected ';'.";
|
||||
expr->data.error.lineNo = expr->state.lineNo;
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
expr->type = HP_SYNTAX_ERROR;
|
||||
expr->data.error.msg = "Expected '('";
|
||||
expr->data.error.msg = "Expected ';', '[', or '('";
|
||||
expr->data.error.lineNo = expr->state.lineNo;
|
||||
return;
|
||||
}
|
||||
|
||||
expr->data.declaration.args = ArrayCreate();
|
||||
|
||||
do
|
||||
{
|
||||
word = HeaderConsumeArg(expr);
|
||||
ArrayAdd(expr->data.declaration.args, word);
|
||||
word = NULL;
|
||||
}
|
||||
while ((!StreamEof(expr->state.stream)) && ((c = HeaderConsumeWhitespace(expr)) != ')'));
|
||||
|
||||
if (StreamEof(expr->state.stream))
|
||||
{
|
||||
expr->type = HP_SYNTAX_ERROR;
|
||||
expr->data.error.msg = "End of file reached before ')'.";
|
||||
expr->data.error.lineNo = expr->state.lineNo;
|
||||
return;
|
||||
}
|
||||
|
||||
c = HeaderConsumeWhitespace(expr);
|
||||
if (c != ';')
|
||||
{
|
||||
expr->type = HP_SYNTAX_ERROR;
|
||||
expr->data.error.msg = "Expected ';'.";
|
||||
expr->data.error.lineNo = expr->state.lineNo;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,6 +36,7 @@ typedef enum HeaderExprType
|
|||
HP_PREPROCESSOR_DIRECTIVE,
|
||||
HP_TYPEDEF,
|
||||
HP_DECLARATION,
|
||||
HP_GLOBAL,
|
||||
HP_SYNTAX_ERROR,
|
||||
HP_PARSE_ERROR,
|
||||
HP_EOF
|
||||
|
@ -48,6 +49,12 @@ typedef struct HeaderDeclaration
|
|||
Array *args;
|
||||
} HeaderDeclaration;
|
||||
|
||||
typedef struct HeaderGlobal
|
||||
{
|
||||
char type[64];
|
||||
char name[HEADER_EXPR_MAX - 64];
|
||||
} HeaderGlobal;
|
||||
|
||||
typedef struct HeaderExpr
|
||||
{
|
||||
HeaderExprType type;
|
||||
|
@ -55,6 +62,7 @@ typedef struct HeaderExpr
|
|||
{
|
||||
char text[HEADER_EXPR_MAX];
|
||||
HeaderDeclaration declaration;
|
||||
HeaderGlobal global;
|
||||
struct
|
||||
{
|
||||
int lineNo;
|
||||
|
|
|
@ -24,6 +24,20 @@
|
|||
#ifndef TELODENDRIA_H
|
||||
#define TELODENDRIA_H
|
||||
|
||||
/***
|
||||
* @Nm Telodendria
|
||||
* @Nd Branding and callback functions specific to Telodendria.
|
||||
* @Dd March 12 2023
|
||||
* @Xr Memory Log
|
||||
*
|
||||
* This API provides the callbacks used to hook Telodendria into the
|
||||
* various other APIs. It exists primarily to be called by
|
||||
* .Fn main ,
|
||||
* but these functions are not static so
|
||||
* .Fn main
|
||||
* can be in a separate compilation unit.
|
||||
*/
|
||||
|
||||
#include <Memory.h>
|
||||
#include <Log.h>
|
||||
#include <HttpRouter.h>
|
||||
|
@ -31,22 +45,64 @@
|
|||
#define TELODENDRIA_LOGO_WIDTH 56
|
||||
#define TELODENDRIA_LOGO_HEIGHT 22
|
||||
|
||||
/**
|
||||
* This holds the Telodendria ASCII art logo.
|
||||
* .Va TELODENDRIA_LOGO_HEIGHT
|
||||
* and
|
||||
* .Va TELODENDRIA_LOGO_WIDTH
|
||||
* are the sizes of each dimension of the two-dimensional array.
|
||||
* .Va TELODENDRIA_LOGO_HEIGHT
|
||||
* is the number of lines the logo contains, and
|
||||
* .Va TELODENDRIA_LOGO_WIDTH
|
||||
* is the number of characters in each line.
|
||||
* .Pp
|
||||
* .Sy NOTE:
|
||||
* the Telodendria logo belongs solely to the Telodendria project. If
|
||||
* this code is modified and distributed as something other than a
|
||||
* packaging of the official Telodendria source package, the logo
|
||||
* must be replaced with a different one, or removed entirely. Consult
|
||||
* the licensing section of
|
||||
* .Xr telodendria 7
|
||||
* for details.
|
||||
*/
|
||||
extern const char
|
||||
TelodendriaLogo[TELODENDRIA_LOGO_HEIGHT][TELODENDRIA_LOGO_WIDTH];
|
||||
TelodendriaLogo[TELODENDRIA_LOGO_HEIGHT][TELODENDRIA_LOGO_WIDTH];
|
||||
|
||||
#define TELODENDRIA_HEADER_WIDTH 56
|
||||
#define TELODENDRIA_HEADER_HEIGHT 6
|
||||
|
||||
/**
|
||||
* This holds the Telodendria ASCII art header. It follows the same
|
||||
* conventions as the logo, but is not under any particular
|
||||
* restrictions other than those spelled out in the license.
|
||||
*/
|
||||
extern const char
|
||||
TelodendriaHeader[TELODENDRIA_HEADER_HEIGHT][TELODENDRIA_HEADER_WIDTH];
|
||||
TelodendriaHeader[TELODENDRIA_HEADER_HEIGHT][TELODENDRIA_HEADER_WIDTH];
|
||||
|
||||
extern void
|
||||
TelodendriaMemoryHook(MemoryAction, MemoryInfo *, void *);
|
||||
/**
|
||||
* This function follows the function prototype required by
|
||||
* .Fn MemoryHook .
|
||||
* It is executed every time an allocation, re-allocation, or free
|
||||
* occurs, and is responsible for logging memory operations to the
|
||||
* log.
|
||||
*/
|
||||
extern void TelodendriaMemoryHook(MemoryAction, MemoryInfo *, void *);
|
||||
|
||||
extern void
|
||||
TelodendriaGenerateMemReport(void);
|
||||
/**
|
||||
* Generate a memory report in the current working directory. This
|
||||
* function is intended to be called after all memory has supposedly
|
||||
* been freed. It allocates no new memory of its own (except what is
|
||||
* required by FILE pointers) and simply dumps all of the allocated
|
||||
* memory out to a file if there is any memory allocated.
|
||||
* .Pp
|
||||
* This function is used to detect and fix memory leaks.
|
||||
*/
|
||||
extern void TelodendriaGenerateMemReport(void);
|
||||
|
||||
extern void
|
||||
TelodendriaPrintHeader(void);
|
||||
/**
|
||||
* Print the logo and header, along with the copyright year and holder,
|
||||
* and the version number, out to the global log.
|
||||
*/
|
||||
extern void TelodendriaPrintHeader(void);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -118,6 +118,7 @@ recipe_docs() {
|
|||
if [ $(mod_time "$header") -ge $(mod_time "$man") ]; then
|
||||
echo "DOC $basename"
|
||||
if ! hdoc -D Os=Telodendria -i "$header" -o "$man"; then
|
||||
rm "$man"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
|
|
@ -46,6 +46,12 @@ typedef struct DocTypedef
|
|||
char text[HEADER_EXPR_MAX];
|
||||
} DocTypedef;
|
||||
|
||||
typedef struct DocGlobal
|
||||
{
|
||||
char docs[HEADER_EXPR_MAX];
|
||||
HeaderGlobal global;
|
||||
} DocGlobal;
|
||||
|
||||
static void
|
||||
ParseMainBlock(HashMap * registers, Array * descr, char *comment)
|
||||
{
|
||||
|
@ -105,6 +111,9 @@ main(int argc, char **argv)
|
|||
Array *typedefs = ArrayCreate();
|
||||
DocTypedef *type = NULL;
|
||||
|
||||
Array *globals = ArrayCreate();
|
||||
DocGlobal *global = NULL;
|
||||
|
||||
char comment[HEADER_EXPR_MAX];
|
||||
int isDocumented = 0;
|
||||
|
||||
|
@ -287,6 +296,24 @@ main(int argc, char **argv)
|
|||
isDocumented = 0;
|
||||
}
|
||||
break;
|
||||
case HP_GLOBAL:
|
||||
if (!isDocumented)
|
||||
{
|
||||
StreamPrintf(StreamStderr(),
|
||||
"Error: Global %s is undocumented.\n",
|
||||
expr.data.global.name);
|
||||
exit = EXIT_FAILURE;
|
||||
goto finish;
|
||||
}
|
||||
else
|
||||
{
|
||||
global = Malloc(sizeof(DocGlobal));
|
||||
global->global = expr.data.global;
|
||||
strncpy(global->docs, comment, sizeof(global->docs));
|
||||
ArrayAdd(globals, global);
|
||||
isDocumented = 0;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
StreamPrintf(StreamStderr(), "Unknown header type: %d\n", expr.type);
|
||||
StreamPrintf(StreamStderr(), "This is a programming error.\n");
|
||||
|
@ -352,6 +379,34 @@ last:
|
|||
StreamPutc(out, '\n');
|
||||
}
|
||||
|
||||
if (ArraySize(globals))
|
||||
{
|
||||
StreamPrintf(out, ".Sh GLOBALS\n");
|
||||
for (i = 0; i < ArraySize(globals); i++)
|
||||
{
|
||||
char *line;
|
||||
global = ArrayGet(globals, i);
|
||||
|
||||
StreamPrintf(out, ".Ss %s %s\n", global->global.type, global->global.name);
|
||||
|
||||
line = strtok(global->docs, "\n");
|
||||
while (line)
|
||||
{
|
||||
while (*line && (isspace(*line) || *line == '*'))
|
||||
{
|
||||
line++;
|
||||
}
|
||||
|
||||
if (*line)
|
||||
{
|
||||
StreamPrintf(out, "%s\n", line);
|
||||
}
|
||||
|
||||
line = strtok(NULL, "\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ArraySize(typedefs))
|
||||
{
|
||||
StreamPrintf(out, ".Sh TYPE DECLARATIONS\n");
|
||||
|
|
Loading…
Reference in a new issue