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); tok = newToken(l, TT_ILLEGAL);
} }
//printf("Invalid token: %X\n", l->ch);
//return NULL;
} }
readChar(l); readChar(l);
@ -146,8 +144,11 @@ newWhitespaceToken(Lexer* l)
tok->type = TT_WHITESPACE; tok->type = TT_WHITESPACE;
int position = l->position; 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; char ch = l->ch;
while (peekChar(l) == ch){ while (peekChar(l) == ch){
readChar(l); readChar(l);
@ -277,7 +278,7 @@ newToken(Lexer* l,
{ {
Token* tok = malloc(sizeof(Token)); Token* tok = malloc(sizeof(Token));
char* nc = malloc(sizeof(char)+1); char* nc = malloc(sizeof(char)+1);
*nc = l->ch; nc[0] = l->ch;
nc[1] = '\0'; nc[1] = '\0';
tok->type = tt; tok->type = tt;
tok->literal = nc; tok->literal = nc;

26
lexer.h
View File

@ -4,21 +4,6 @@
#ifndef LEXER_H #ifndef LEXER_H
#define 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 { typedef struct Lexer {
char* rawFile; char* rawFile;
int rawLen; int rawLen;
@ -32,19 +17,10 @@ typedef struct Lexer {
} Lexer; } Lexer;
//typedef struct Node {
// NodeType type;
// char RawText;
// int LineNumber;
//
// //struct Node **ChildNodes;
// void** ChildNodes;
// int ChildCount;
//} Node;
Lexer* NewLexer(const char* filename); Lexer* NewLexer(const char* filename);
Token* NextToken(Lexer* l); Token* NextToken(Lexer* l);
void ReadChar(Lexer* l); void ReadChar(Lexer* l);
void Parse(Lexer* l); void Parse(Lexer* l);
void FreeLexer(Lexer* l);
#endif #endif

32
main.c
View File

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

127
node.c
View File

@ -1,5 +1,6 @@
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <assert.h>
#include "node.h" #include "node.h"
@ -19,10 +20,12 @@ ParseNodes(Token* firstToken)
Token* currentToken = firstToken; Token* currentToken = firstToken;
Node* prevNode = NULL; Node* prevNode = NULL;
while (1) { while (currentToken != NULL)
{
Node* currentNode = NULL; Node* currentNode = NULL;
switch (currentToken->type) { switch (currentToken->type)
{
case TT_NEWLINE: case TT_NEWLINE:
case TT_WHITESPACE: case TT_WHITESPACE:
break; break;
@ -44,21 +47,17 @@ ParseNodes(Token* firstToken)
break; break;
} }
if (currentToken->next == NULL) { if (currentToken->type == TT_NEWLINE || currentToken->type == TT_WHITESPACE)
break; currentToken = FreeToken(currentToken);
}
currentToken = currentToken->next;
if (currentNode == NULL) if (currentNode == NULL)
continue; continue;
if (prevNode != NULL) { if (prevNode != NULL)
prevNode->next = currentNode; prevNode->next = currentNode;
}
if (firstNode == NULL) { if (firstNode == NULL)
firstNode = currentNode; firstNode = currentNode;
}
prevNode = currentNode; prevNode = currentNode;
} }
@ -70,12 +69,13 @@ Node*
parseHeader(Token** startToken) parseHeader(Token** startToken)
{ {
Token* t = *startToken; Token* t = *startToken;
// Count the number of TT_HASH tokens // Count the number of TT_HASH tokens
int count = 1; int count = 1;
while (t->next != NULL && t->next->type == TT_HASH) while (t->next != NULL && t->next->type == TT_HASH)
{ {
count++; count++;
t = t->next; t = FreeToken(t);
} }
if (t->next == NULL) if (t->next == NULL)
@ -83,12 +83,11 @@ parseHeader(Token** startToken)
printf("Header missing text"); printf("Header missing text");
return NULL; return NULL;
} }
t = t->next;
// Trim leading whitespace // Trim leading whitespace
while (t->next != NULL && t->type == TT_WHITESPACE) while (t->next != NULL && t->type == TT_WHITESPACE)
{ {
t = t->next; t = FreeToken(t);
} }
if (t->next == NULL) if (t->next == NULL)
@ -99,6 +98,7 @@ parseHeader(Token** startToken)
Token* end = t; Token* end = t;
int len = 0; int len = 0;
// find header text size // find header text size
while (end->type != TT_NEWLINE && end->type != TT_EOF) { while (end->type != TT_NEWLINE && end->type != TT_EOF) {
len += end->length; len += end->length;
@ -110,10 +110,9 @@ parseHeader(Token** startToken)
while(t != end) { while(t != end) {
strncat(strbuff, t->literal, t->length); strncat(strbuff, t->literal, t->length);
t = t->next; t = FreeToken(t);
} }
*startToken = t; *startToken = t;
HeaderNode* retval = malloc(sizeof(HeaderNode)); HeaderNode* retval = malloc(sizeof(HeaderNode));
@ -144,14 +143,19 @@ parseCodeBlock(Token** startToken)
// find closing ticks // find closing ticks
int tlen = 0; // number of tokens int tlen = 0; // number of tokens
int clen = 0; // number of characters 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 // skip the first newline
if (t->type == TT_NEWLINE) { while ((*startToken)->type == TT_NEWLINE) {
t = t->next; *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) { while (t->next != NULL && t->type != TT_TRIPLEBACKTICK) {
if (t->next->type == TT_EOF) { if (t->next->type == TT_EOF) {
printf("premature EOF"); printf("premature EOF");
@ -174,20 +178,22 @@ parseCodeBlock(Token** startToken)
char* strbuff = malloc(sizeof(char)*clen+1); char* strbuff = malloc(sizeof(char)*clen+1);
strbuff[0] = '\0'; strbuff[0] = '\0';
int i; 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++) { for(i = 0; i < tlen; i++) {
strncat(strbuff, t->literal, t->length); 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)); CodeBlockNode* ret = malloc(sizeof(CodeBlockNode));
ret->type = NT_BlockCode; ret->type = NT_BlockCode;
@ -208,14 +214,11 @@ parseParagraph(Token** startToken)
if (t->type == TT_GT) { if (t->type == TT_GT) {
pnode->ptype = PT_Quote; pnode->ptype = PT_Quote;
// consume TT_GT // consume TT_GT
Token* consumed = t; t = FreeToken(t);
t = t->next;
FreeToken(consumed);
} }
pnode->content = t; pnode->content = t;
Token* prevToken = NULL; Token* prevToken = NULL;
Token* consumed = NULL;
while(t != NULL) while(t != NULL)
{ {
@ -226,10 +229,8 @@ parseParagraph(Token** startToken)
if (t->next->type == TT_WHITESPACE) if (t->next->type == TT_WHITESPACE)
{ {
// Consume the newline if the next one is a space. // Consume the newline if the next one is a space.
consumed = t; t = FreeToken(t);
t = t->next;
prevToken->next = t; prevToken->next = t;
FreeToken(consumed);
} }
else else
{ {
@ -245,18 +246,14 @@ parseParagraph(Token** startToken)
if (pnode->ptype == PT_Quote) { if (pnode->ptype == PT_Quote) {
if (t->type == TT_GT) { if (t->type == TT_GT) {
// removes TT_GT // removes TT_GT
consumed = t; t = FreeToken(t);
t = t->next;
prevToken->next = t; prevToken->next = t;
FreeToken(consumed);
if (t->next != NULL && t->next->type == TT_WHITESPACE) if (t->next != NULL && t->next->type == TT_WHITESPACE)
{ {
// removes TT_WHITESPACE // removes TT_WHITESPACE
consumed = t; t = FreeToken(t);
t = t->next;
prevToken->next = t; prevToken->next = t;
FreeToken(consumed);
} }
continue; continue;
} }
@ -276,7 +273,6 @@ parseParagraph(Token** startToken)
} }
} // TT_NEWLINE check } // TT_NEWLINE check
//printf("t->literal: %s\n", t->literal);
if (prevToken != NULL) if (prevToken != NULL)
prevToken->next = t; prevToken->next = t;
prevToken = t; prevToken = t;
@ -296,22 +292,22 @@ paragraphEnd:
{ {
if(t->next == NULL) if(t->next == NULL)
{ {
FreeToken(t);
prevToken->next = NULL; prevToken->next = NULL;
break; break;
} }
else if (t->next->type == TT_WHITESPACE) else if (t->next->type == TT_WHITESPACE)
{ {
// concatinate the two. /* concatinate the two. */
int len = t->length + t->next->length; int len = t->length + t->next->length;
char* newws = malloc(sizeof(char)*len+1); char* newws = malloc(sizeof(char)*len+1);
newws[0] = '\0'; newws[0] = '\0';
strncat(newws, t->literal, t->length); strncat(newws, t->literal, t->length);
strncat(newws, t->next->literal, t->next->length); strncat(newws, t->next->literal, t->next->length);
consumed = t; t = FreeToken(t);
t = t->next;
prevToken->next = t; prevToken->next = t;
FreeToken(consumed);
t->length = len; t->length = len;
free(t->literal); free(t->literal);
t->literal = newws; t->literal = newws;
@ -346,8 +342,6 @@ NodeTypeString(NodeType t)
return "NT_InlineCode"; return "NT_InlineCode";
case NT_BlockCode: case NT_BlockCode:
return "NT_BlockCode"; return "NT_BlockCode";
case NT_BlockQuote:
return "NT_BlockQuote";
case NT_Bold: case NT_Bold:
return "NT_Bold"; return "NT_Bold";
case NT_Underline: case NT_Underline:
@ -375,3 +369,40 @@ ParagraphTypeString(ParagraphType t)
} }
return "UNKNOWN"; 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_Paragraph,
NT_UnorderedList, NT_UnorderedList,
NT_OrderedList, NT_OrderedList,
NT_BlockQuote,
// Contained elements (cannot be bare) // Contained elements (cannot be bare)
// text modifiers // text modifiers
@ -71,5 +70,6 @@ typedef struct {
Node* ParseNodes(Token* firstToken); Node* ParseNodes(Token* firstToken);
char* NodeTypeString(NodeType t); char* NodeTypeString(NodeType t);
char* ParagraphTypeString(ParagraphType t); char* ParagraphTypeString(ParagraphType t);
Node* FreeNode(Node* node);
#endif #endif

View File

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

11
token.c
View File

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

View File

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