forked from lda/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;
|
int i = wordLen;
|
||||||
|
|
||||||
expr->type = HP_DECLARATION;
|
expr->type = HP_GLOBAL;
|
||||||
strncpy(expr->data.declaration.returnType, word, wordLimit);
|
strncpy(expr->data.global.type, word, wordLimit);
|
||||||
|
|
||||||
if (strcmp(word, "struct") == 0 ||
|
if (strcmp(word, "struct") == 0 ||
|
||||||
strcmp(word, "enum") == 0 ||
|
strcmp(word, "enum") == 0 ||
|
||||||
|
@ -515,8 +515,9 @@ HeaderParse(Stream * stream, HeaderExpr * expr)
|
||||||
Free(word);
|
Free(word);
|
||||||
word = HeaderConsumeWord(expr);
|
word = HeaderConsumeWord(expr);
|
||||||
wordLen = strlen(word);
|
wordLen = strlen(word);
|
||||||
expr->data.declaration.returnType[i] = ' ';
|
expr->data.global.type[i] = ' ';
|
||||||
strncpy(expr->data.declaration.returnType + i + 1, word, wordLen + 1);
|
|
||||||
|
strncpy(expr->data.global.type + i + 1, word, wordLen + 1);
|
||||||
i += wordLen + 1;
|
i += wordLen + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -525,13 +526,16 @@ HeaderParse(Stream * stream, HeaderExpr * expr)
|
||||||
c = HeaderConsumeWhitespace(expr);
|
c = HeaderConsumeWhitespace(expr);
|
||||||
if (c == '*')
|
if (c == '*')
|
||||||
{
|
{
|
||||||
expr->data.declaration.returnType[i] = ' ';
|
expr->data.global.type[i] = ' ';
|
||||||
|
|
||||||
i++;
|
i++;
|
||||||
expr->data.declaration.returnType[i] = '*';
|
expr->data.global.type[i] = '*';
|
||||||
|
|
||||||
i++;
|
i++;
|
||||||
while ((c = HeaderConsumeWhitespace(expr)) == '*')
|
while ((c = HeaderConsumeWhitespace(expr)) == '*')
|
||||||
{
|
{
|
||||||
expr->data.declaration.returnType[i] = c;
|
expr->data.global.type[i] = c;
|
||||||
|
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -550,21 +554,61 @@ HeaderParse(Stream * stream, HeaderExpr * expr)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
strncpy(expr->data.declaration.name, word, wordLimit);
|
strncpy(expr->data.global.name, word, wordLimit);
|
||||||
Free(word);
|
Free(word);
|
||||||
word = NULL;
|
word = NULL;
|
||||||
|
|
||||||
c = HeaderConsumeWhitespace(expr);
|
c = HeaderConsumeWhitespace(expr);
|
||||||
if (c != '(')
|
|
||||||
|
if (c == ';')
|
||||||
{
|
{
|
||||||
expr->type = HP_SYNTAX_ERROR;
|
/* That's the end of the global. */
|
||||||
expr->data.error.msg = "Expected '('";
|
}
|
||||||
|
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;
|
expr->data.error.lineNo = expr->state.lineNo;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
expr->data.declaration.args = ArrayCreate();
|
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
|
do
|
||||||
{
|
{
|
||||||
word = HeaderConsumeArg(expr);
|
word = HeaderConsumeArg(expr);
|
||||||
|
@ -590,6 +634,15 @@ HeaderParse(Stream * stream, HeaderExpr * expr)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
expr->type = HP_SYNTAX_ERROR;
|
||||||
|
expr->data.error.msg = "Expected ';', '[', or '('";
|
||||||
|
expr->data.error.lineNo = expr->state.lineNo;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
@ -36,6 +36,7 @@ typedef enum HeaderExprType
|
||||||
HP_PREPROCESSOR_DIRECTIVE,
|
HP_PREPROCESSOR_DIRECTIVE,
|
||||||
HP_TYPEDEF,
|
HP_TYPEDEF,
|
||||||
HP_DECLARATION,
|
HP_DECLARATION,
|
||||||
|
HP_GLOBAL,
|
||||||
HP_SYNTAX_ERROR,
|
HP_SYNTAX_ERROR,
|
||||||
HP_PARSE_ERROR,
|
HP_PARSE_ERROR,
|
||||||
HP_EOF
|
HP_EOF
|
||||||
|
@ -48,6 +49,12 @@ typedef struct HeaderDeclaration
|
||||||
Array *args;
|
Array *args;
|
||||||
} HeaderDeclaration;
|
} HeaderDeclaration;
|
||||||
|
|
||||||
|
typedef struct HeaderGlobal
|
||||||
|
{
|
||||||
|
char type[64];
|
||||||
|
char name[HEADER_EXPR_MAX - 64];
|
||||||
|
} HeaderGlobal;
|
||||||
|
|
||||||
typedef struct HeaderExpr
|
typedef struct HeaderExpr
|
||||||
{
|
{
|
||||||
HeaderExprType type;
|
HeaderExprType type;
|
||||||
|
@ -55,6 +62,7 @@ typedef struct HeaderExpr
|
||||||
{
|
{
|
||||||
char text[HEADER_EXPR_MAX];
|
char text[HEADER_EXPR_MAX];
|
||||||
HeaderDeclaration declaration;
|
HeaderDeclaration declaration;
|
||||||
|
HeaderGlobal global;
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
int lineNo;
|
int lineNo;
|
||||||
|
|
|
@ -24,6 +24,20 @@
|
||||||
#ifndef TELODENDRIA_H
|
#ifndef TELODENDRIA_H
|
||||||
#define 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 <Memory.h>
|
||||||
#include <Log.h>
|
#include <Log.h>
|
||||||
#include <HttpRouter.h>
|
#include <HttpRouter.h>
|
||||||
|
@ -31,22 +45,64 @@
|
||||||
#define TELODENDRIA_LOGO_WIDTH 56
|
#define TELODENDRIA_LOGO_WIDTH 56
|
||||||
#define TELODENDRIA_LOGO_HEIGHT 22
|
#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
|
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_WIDTH 56
|
||||||
#define TELODENDRIA_HEADER_HEIGHT 6
|
#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
|
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
|
#endif
|
||||||
|
|
|
@ -118,6 +118,7 @@ recipe_docs() {
|
||||||
if [ $(mod_time "$header") -ge $(mod_time "$man") ]; then
|
if [ $(mod_time "$header") -ge $(mod_time "$man") ]; then
|
||||||
echo "DOC $basename"
|
echo "DOC $basename"
|
||||||
if ! hdoc -D Os=Telodendria -i "$header" -o "$man"; then
|
if ! hdoc -D Os=Telodendria -i "$header" -o "$man"; then
|
||||||
|
rm "$man"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
|
@ -46,6 +46,12 @@ typedef struct DocTypedef
|
||||||
char text[HEADER_EXPR_MAX];
|
char text[HEADER_EXPR_MAX];
|
||||||
} DocTypedef;
|
} DocTypedef;
|
||||||
|
|
||||||
|
typedef struct DocGlobal
|
||||||
|
{
|
||||||
|
char docs[HEADER_EXPR_MAX];
|
||||||
|
HeaderGlobal global;
|
||||||
|
} DocGlobal;
|
||||||
|
|
||||||
static void
|
static void
|
||||||
ParseMainBlock(HashMap * registers, Array * descr, char *comment)
|
ParseMainBlock(HashMap * registers, Array * descr, char *comment)
|
||||||
{
|
{
|
||||||
|
@ -105,6 +111,9 @@ main(int argc, char **argv)
|
||||||
Array *typedefs = ArrayCreate();
|
Array *typedefs = ArrayCreate();
|
||||||
DocTypedef *type = NULL;
|
DocTypedef *type = NULL;
|
||||||
|
|
||||||
|
Array *globals = ArrayCreate();
|
||||||
|
DocGlobal *global = NULL;
|
||||||
|
|
||||||
char comment[HEADER_EXPR_MAX];
|
char comment[HEADER_EXPR_MAX];
|
||||||
int isDocumented = 0;
|
int isDocumented = 0;
|
||||||
|
|
||||||
|
@ -287,6 +296,24 @@ main(int argc, char **argv)
|
||||||
isDocumented = 0;
|
isDocumented = 0;
|
||||||
}
|
}
|
||||||
break;
|
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:
|
default:
|
||||||
StreamPrintf(StreamStderr(), "Unknown header type: %d\n", expr.type);
|
StreamPrintf(StreamStderr(), "Unknown header type: %d\n", expr.type);
|
||||||
StreamPrintf(StreamStderr(), "This is a programming error.\n");
|
StreamPrintf(StreamStderr(), "This is a programming error.\n");
|
||||||
|
@ -352,6 +379,34 @@ last:
|
||||||
StreamPutc(out, '\n');
|
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))
|
if (ArraySize(typedefs))
|
||||||
{
|
{
|
||||||
StreamPrintf(out, ".Sh TYPE DECLARATIONS\n");
|
StreamPrintf(out, ".Sh TYPE DECLARATIONS\n");
|
||||||
|
|
Loading…
Reference in a new issue