Fix a lot of memory leaks

Added a bunch of code to free created objects.  One notable change was
to return the next token from FreeToken() to cut down on boiler plate
code that kept track of a "consumed" token.  Now all that just happens
in FreeToken() and I don't have to worry about that anywhere else.

Also added FreeNode() to free all nodes.  This wasn't done before at
all.  Like FreeToken(), it will return the next node in the list to
avoid having to track that stuff in the calling context.
This commit is contained in:
Zorchenhimer 2023-11-15 21:43:03 -05:00
parent c17eaf1ec4
commit b952ac99ac
8 changed files with 115 additions and 97 deletions

11
lexer.c
View File

@ -128,8 +128,6 @@ NextToken(Lexer* l)
{
tok = newToken(l, TT_ILLEGAL);
}
//printf("Invalid token: %X\n", l->ch);
//return NULL;
}
readChar(l);
@ -146,8 +144,11 @@ newWhitespaceToken(Lexer* l)
tok->type = TT_WHITESPACE;
int position = l->position;
// grab the char so we can use this funciton for both
// spaces and tabs.
/*
* Grab the char so we can use this funciton for both
* spaces and tabs.
*/
char ch = l->ch;
while (peekChar(l) == ch){
readChar(l);
@ -277,7 +278,7 @@ newToken(Lexer* l,
{
Token* tok = malloc(sizeof(Token));
char* nc = malloc(sizeof(char)+1);
*nc = l->ch;
nc[0] = l->ch;
nc[1] = '\0';
tok->type = tt;
tok->literal = nc;

26
lexer.h
View File

@ -4,21 +4,6 @@
#ifndef LEXER_H
#define LEXER_H
//typedef enum NodeType {
// NT_Root,
// NT_Header1,
// NT_Header2,
// NT_Header3,
// NT_ListItem,
// NT_OrderedListItem,
// NT_Paragraph,
// NT_PlainText,
// NT_BoldText,
// NT_UnderlineText,
// NT_InlineCode,
// NT_BlockCode,
//} NodeType;
typedef struct Lexer {
char* rawFile;
int rawLen;
@ -32,19 +17,10 @@ typedef struct Lexer {
} Lexer;
//typedef struct Node {
// NodeType type;
// char RawText;
// int LineNumber;
//
// //struct Node **ChildNodes;
// void** ChildNodes;
// int ChildCount;
//} Node;
Lexer* NewLexer(const char* filename);
Token* NextToken(Lexer* l);
void ReadChar(Lexer* l);
void Parse(Lexer* l);
void FreeLexer(Lexer* l);
#endif

32
main.c
View File

@ -52,15 +52,17 @@ main(int argc, const char** argv)
}
while(tt != TT_EOF);
FreeLexer(l);
writeTokenFile(firstToken);
Node* node = ParseNodes(firstToken);
Node* firstNode = ParseNodes(firstToken);
Node* node = firstNode;
printf("nodes:\n");
while(node != NULL)
{
/*PrintNodeType(node->type);*/
switch (node->type) {
switch (node->type)
{
case NT_Header1:
case NT_Header2:
case NT_Header3:
@ -115,14 +117,20 @@ main(int argc, const char** argv)
node = node->next;
}
//printf("rawLen: %d position: %d readPosition: %d ch: %c line: %d column: %d\n",
// l->rawLen,
// l->position,
// l->readPosition,
// l->ch,
// l->line,
// l->column
//);
node = firstNode;
firstNode = NULL;
while ((node = FreeNode(node)) != NULL);
if (node != NULL)
printf("last node != NULL\n");
if (firstNode != NULL)
{
printf("firstNode != NULL\n");
printf("%s\n", NodeTypeString(firstNode->type));
}
return 0;
}

127
node.c
View File

@ -1,5 +1,6 @@
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include "node.h"
@ -19,10 +20,12 @@ ParseNodes(Token* firstToken)
Token* currentToken = firstToken;
Node* prevNode = NULL;
while (1) {
while (currentToken != NULL)
{
Node* currentNode = NULL;
switch (currentToken->type) {
switch (currentToken->type)
{
case TT_NEWLINE:
case TT_WHITESPACE:
break;
@ -44,21 +47,17 @@ ParseNodes(Token* firstToken)
break;
}
if (currentToken->next == NULL) {
break;
}
if (currentToken->type == TT_NEWLINE || currentToken->type == TT_WHITESPACE)
currentToken = FreeToken(currentToken);
currentToken = currentToken->next;
if (currentNode == NULL)
continue;
if (prevNode != NULL) {
if (prevNode != NULL)
prevNode->next = currentNode;
}
if (firstNode == NULL) {
if (firstNode == NULL)
firstNode = currentNode;
}
prevNode = currentNode;
}
@ -70,12 +69,13 @@ Node*
parseHeader(Token** startToken)
{
Token* t = *startToken;
// Count the number of TT_HASH tokens
int count = 1;
while (t->next != NULL && t->next->type == TT_HASH)
{
count++;
t = t->next;
t = FreeToken(t);
}
if (t->next == NULL)
@ -83,12 +83,11 @@ parseHeader(Token** startToken)
printf("Header missing text");
return NULL;
}
t = t->next;
// Trim leading whitespace
while (t->next != NULL && t->type == TT_WHITESPACE)
{
t = t->next;
t = FreeToken(t);
}
if (t->next == NULL)
@ -99,6 +98,7 @@ parseHeader(Token** startToken)
Token* end = t;
int len = 0;
// find header text size
while (end->type != TT_NEWLINE && end->type != TT_EOF) {
len += end->length;
@ -110,10 +110,9 @@ parseHeader(Token** startToken)
while(t != end) {
strncat(strbuff, t->literal, t->length);
t = t->next;
t = FreeToken(t);
}
*startToken = t;
HeaderNode* retval = malloc(sizeof(HeaderNode));
@ -144,14 +143,19 @@ parseCodeBlock(Token** startToken)
// find closing ticks
int tlen = 0; // number of tokens
int clen = 0; // number of characters
Token* t = *startToken;
t = t->next; // skip past the opening triple backtick
// skip past the opening triple backtick
*startToken = FreeToken(*startToken);
// skip the first newline
if (t->type == TT_NEWLINE) {
t = t->next;
while ((*startToken)->type == TT_NEWLINE) {
*startToken = FreeToken(*startToken);
}
// assign this after we skip tokens so we don't have to
// re-skip them later.
Token* t = *startToken;
while (t->next != NULL && t->type != TT_TRIPLEBACKTICK) {
if (t->next->type == TT_EOF) {
printf("premature EOF");
@ -174,20 +178,22 @@ parseCodeBlock(Token** startToken)
char* strbuff = malloc(sizeof(char)*clen+1);
strbuff[0] = '\0';
int i;
t = t->next; // skip past the opening triple backtick
// skip the first newline
if (t->type == TT_NEWLINE) {
t = t->next;
}
for(i = 0; i < tlen; i++) {
strncat(strbuff, t->literal, t->length);
t = t->next;
t = FreeToken(t);
}
// skip past closing triple backtick
*startToken = t->next;
/*
* Skip past closing triple backtick
* This is modifying the *parameter* that was passed in,
* so we can return the node and advance the token tree.
*/
*startToken = FreeToken(t);
while ((*startToken)->type == TT_NEWLINE || (*startToken)->type == TT_WHITESPACE) {
*startToken = FreeToken(*startToken);
}
CodeBlockNode* ret = malloc(sizeof(CodeBlockNode));
ret->type = NT_BlockCode;
@ -208,14 +214,11 @@ parseParagraph(Token** startToken)
if (t->type == TT_GT) {
pnode->ptype = PT_Quote;
// consume TT_GT
Token* consumed = t;
t = t->next;
FreeToken(consumed);
t = FreeToken(t);
}
pnode->content = t;
Token* prevToken = NULL;
Token* consumed = NULL;
while(t != NULL)
{
@ -226,10 +229,8 @@ parseParagraph(Token** startToken)
if (t->next->type == TT_WHITESPACE)
{
// Consume the newline if the next one is a space.
consumed = t;
t = t->next;
t = FreeToken(t);
prevToken->next = t;
FreeToken(consumed);
}
else
{
@ -245,18 +246,14 @@ parseParagraph(Token** startToken)
if (pnode->ptype == PT_Quote) {
if (t->type == TT_GT) {
// removes TT_GT
consumed = t;
t = t->next;
t = FreeToken(t);
prevToken->next = t;
FreeToken(consumed);
if (t->next != NULL && t->next->type == TT_WHITESPACE)
{
// removes TT_WHITESPACE
consumed = t;
t = t->next;
t = FreeToken(t);
prevToken->next = t;
FreeToken(consumed);
}
continue;
}
@ -276,7 +273,6 @@ parseParagraph(Token** startToken)
}
} // TT_NEWLINE check
//printf("t->literal: %s\n", t->literal);
if (prevToken != NULL)
prevToken->next = t;
prevToken = t;
@ -296,22 +292,22 @@ paragraphEnd:
{
if(t->next == NULL)
{
FreeToken(t);
prevToken->next = NULL;
break;
}
else if (t->next->type == TT_WHITESPACE)
{
// concatinate the two.
/* concatinate the two. */
int len = t->length + t->next->length;
char* newws = malloc(sizeof(char)*len+1);
newws[0] = '\0';
strncat(newws, t->literal, t->length);
strncat(newws, t->next->literal, t->next->length);
consumed = t;
t = t->next;
t = FreeToken(t);
prevToken->next = t;
FreeToken(consumed);
t->length = len;
free(t->literal);
t->literal = newws;
@ -346,8 +342,6 @@ NodeTypeString(NodeType t)
return "NT_InlineCode";
case NT_BlockCode:
return "NT_BlockCode";
case NT_BlockQuote:
return "NT_BlockQuote";
case NT_Bold:
return "NT_Bold";
case NT_Underline:
@ -375,3 +369,40 @@ ParagraphTypeString(ParagraphType t)
}
return "UNKNOWN";
}
Node*
FreeNode(Node* node)
{
Node* next = node->next;
switch (node->type)
{
case NT_Header1:
case NT_Header2:
case NT_Header3:
case NT_Header4:
free(((HeaderNode*)node)->rawText);
break;
case NT_BlockCode:
free(((CodeBlockNode*)node)->rawText);
break;
case NT_Error:
free(((ErrorNode*)node)->error);
break;
case NT_Paragraph:
{
ParagraphNode* pnode = (ParagraphNode*)node;
Token* t = pnode->content;
while ((t = FreeToken(t)) != NULL);
}
break;
case NT_UnorderedList:
case NT_OrderedList:
case NT_InlineCode:
case NT_Bold:
case NT_Underline:
assert(0 && "//TODO");
break;
}
free(node);
return next;
}

2
node.h
View File

@ -19,7 +19,6 @@ typedef enum {
NT_Paragraph,
NT_UnorderedList,
NT_OrderedList,
NT_BlockQuote,
// Contained elements (cannot be bare)
// text modifiers
@ -71,5 +70,6 @@ typedef struct {
Node* ParseNodes(Token* firstToken);
char* NodeTypeString(NodeType t);
char* ParagraphTypeString(ParagraphType t);
Node* FreeNode(Node* node);
#endif

View File

@ -12,7 +12,6 @@ pellentesque. *Sit fusce.* At ligula dolor parturient sodales auctor. Egestas.
this has some `inline
code` in it.
> Block Quote thing.
> Dictum pharetra nulla _aliquet tincidunt_ parturient netus gravida rutrum
>

11
token.c
View File

@ -13,23 +13,26 @@ char* printableOnly(char* input);
char*
TokenString(Token* t)
{
//char* str = malloc(sizeof(char) * 1000);
snprintf(stringBuff, 1000, "[%d:%d] Type: %s Literal: '%s'",
char* printable = printableOnly(t->literal);
snprintf(stringBuff, STRING_BUFF_SIZE, "[%d:%d] Type: %s Literal: '%s'",
t->line,
t->column,
TokenTypeString(t->type),
printableOnly(t->literal)
printable
);
free(printable);
return stringBuff;
}
void
Token*
FreeToken(Token* t)
{
Token* next = t->next;
if (t->type != TT_TRIPLEBACKTICK)
free(t->literal);
free(t);
return next;
}
char*

View File

@ -30,6 +30,6 @@ typedef struct Token {
char* TokenString(Token* t);
char* TokenTypeString(TokenType tt);
void FreeToken(Token* t);
Token* FreeToken(Token* t);
#endif