~groovestomp/c-parser

1aaf0aa3fff65d69fd7514ab282cddc4948d9527 — Aaron Oman 2 years ago f3fb07e
Clean up dependencies
5 files changed, 183 insertions(+), 211 deletions(-)

M src/gs.h
M src/lexer.c
M src/main.c
M src/parse_tree.c
M src/parser.c
M src/gs.h => src/gs.h +83 -150
@@ 15,12 15,6 @@
#define GS_H
#define GS_VERSION 0.2.0-dev

#include <stdio.h>
#include <stdlib.h>
#include <string.h> /* memset */
#include <stdarg.h> /* va_list */
#include <libgen.h> /* basename */

#define GSArraySize(Array) (sizeof((Array)) / sizeof((Array)[0]))

/******************************************************************************


@@ 50,22 44,24 @@
#define GSMax(A, B) ((A) < (B) ? (B) : (A))
#define GSMin(A, B) ((A) < (B) ? (A) : (B))

#define GSAbortWithMessage(...) \
        { \
                char String##__LINE__[256];                             \
                sprintf(String##__LINE__, "In %s() at line #%i: ", __func__, __LINE__); \
                fprintf(stderr, String##__LINE__);                       \
                fprintf(stderr, __VA_ARGS__); \
                exit(EXIT_FAILURE); \
        }

#define GSLog(...) \
        { \
                char String##__LINE__[256];                             \
                sprintf(String##__LINE__, "In %s() at line #%i: ", __func__, __LINE__); \
                fprintf(stdout, String##__LINE__);                       \
                fprintf(stdout, __VA_ARGS__); \
        }
// TODO: Move to platform-specific header
/* #define GSAbortWithMessage(...) \ */
/*         { \ */
/*                 char String##__LINE__[256];                             \ */
/*                 sprintf(String##__LINE__, "In %s() at line #%i: ", __func__, __LINE__); \ */
/*                 fprintf(stderr, String##__LINE__);                       \ */
/*                 fprintf(stderr, __VA_ARGS__); \ */
/*                 exit(EXIT_FAILURE); \ */
/*         } */

// TODO: Move to platform-specific header
/* #define GSLog(...) \ */
/*         { \ */
/*                 char String##__LINE__[256];                             \ */
/*                 sprintf(String##__LINE__, "In %s() at line #%i: ", __func__, __LINE__); \ */
/*                 fprintf(stdout, String##__LINE__);                       \ */
/*                 fprintf(stdout, __VA_ARGS__); \ */
/*         } */

#define GS1024Inverse 1.0/1024
#define GSBytesToKilobytes(X) (X) * GS1024Inverse


@@ 77,6 73,11 @@
 * TODO: Conditionally do typedefs?
 ******************************************************************************/
#define GSNullChar '\0'

#ifndef NULL
#define NULL 0
#endif

#define GSNullPtr NULL

typedef int bool;


@@ 101,6 102,16 @@ typedef double f64;
typedef long double f128;

/******************************************************************************
 * Allocator
 ******************************************************************************/
typedef struct gs_allocator {
        void *(*Alloc)(u64);
        void (*Free)(void *);
        void *(*Realloc)(void *, u64);
        void *(*ArrayAlloc)(u64, u64);
} gs_allocator;

/******************************************************************************
 * Character Definitions
 *-----------------------------------------------------------------------------
 * Functions to interact with C's basic ASCII char type.


@@ 250,7 261,7 @@ GSStringIsEqual(char *LeftString, char *RightString, int MaxNumToMatch)
	return true;
}

size_t
u32
GSStringLength(char *String)
{
	char *P = String;


@@ 488,7 499,7 @@ GSStringReject(char *Source, char *Dest, unsigned int MaxLength, GSStringFilterF
 *     char *Value = "value";
 *     int StringLength = 256;
 *     int NumElements = 13;
 *     size_t BytesRequired = GSHashMapBytesRequired(StringLength, NumElements);
 *     u32 BytesRequired = GSHashMapBytesRequired(StringLength, NumElements);
 *     gs_hash_map *Map = GSHashMapInit(alloca(BytesRequired), StringLength, NumElements);
 *     GSHashMapSet(Map, "key", Value);
 *     if(GSHashMapHasKey(Map, "key"))


@@ 500,7 511,7 @@ GSStringReject(char *Source, char *Dest, unsigned int MaxLength, GSStringFilterF
typedef struct gs_hash_map
{
        unsigned int Count;
        size_t AllocatedBytes;
        u32 AllocatedBytes;
        unsigned int Capacity;
        unsigned int MaxKeyLength;



@@ 526,7 537,7 @@ __GSHashMapComputeHash(gs_hash_map *Self, char *String)
        return Result;
}

size_t
u32
GSHashMapBytesRequired(unsigned int MaxKeyLength, unsigned int NumEntries)
{
        int AllocSize =


@@ 552,10 563,14 @@ GSHashMapInit(void *Memory, unsigned int MaxKeyLength, unsigned int NumEntries)
        int KeysMemLength = MaxKeyLength * NumEntries;

        Self->Keys = KeyValueMemory;
        memset(Self->Keys, 0, KeysMemLength);
        for (int i = 0; i < KeysMemLength; i++) {
                Self->Keys[i] = 0;
        }

        Self->Values = (void **)(Self->Keys + KeysMemLength);
        memset(Self->Values, 0, (sizeof(void **) * NumEntries));
        for (int i = 0; i < NumEntries; i++) {
                Self->Values[i] = 0;
        }

        return Self;
}


@@ 682,8 697,7 @@ GSHashMapGrow(gs_hash_map **Self, unsigned int NumEntries, void *New)
                if(Key != NULL)
                {
                        bool Success = GSHashMapSet(*Self, Key, Value);
                        if(!Success)
                                GSAbortWithMessage("This should have worked!\n");
                        if(!Success) return false;
                }
        }



@@ 757,89 771,6 @@ GSHashMapDelete(gs_hash_map *Self, char *Wanted)
}

/******************************************************************************
 * Arg Parsing
 ******************************************************************************/

typedef struct gs_args
{
        int Count;
        char **Args;
} gs_args;

void
GSArgsInit(gs_args *Self, int ArgCount, char **Args)
{
        Self->Count = ArgCount;
        Self->Args = Args;
}

char *
GSArgsProgramName(gs_args *Self)
{
        char *ProgramName = Self->Args[0];
        char *Result = basename(ProgramName);
        return Result;
}

bool
GSArgsIsPresent(gs_args *Args, char *Wanted)
{
        int StringLength = GSStringLength(Wanted);
        for(int I=0; I<Args->Count; I++)
        {
                if(GSStringIsEqual(Wanted, Args->Args[I], StringLength))
                {
                        return true;
                }
        }
        return false;
}

int /* Returns -1 if Arg not found. */
GSArgsFind(gs_args *Args, char *Wanted)
{
        int StringLength = GSStringLength(Wanted);
        for(int I=0; I<Args->Count; I++)
        {
                if(GSStringIsEqual(Wanted, Args->Args[I], StringLength))
                {
                        return I;
                }
        }
        return -1;
}

char * /* Returns NULL if Index is invalid. */
GSArgsAtIndex(gs_args *Args, int Index)
{
        if((Index < 0) ||
           (Index > (Args->Count - 1)))
                return NULL;
        else
                return Args->Args[Index];
}

char * /* Returns NULL if Marker is not found or no trailing arg. */
GSArgsAfter(gs_args *Args, char *Marker)
{
        int Index = GSArgsFind(Args, Marker);
        if(Index < 0) return NULL;

        char *Arg = GSArgsAtIndex(Args, Index + 1);
        return Arg;
}

bool
GSArgsHelpWanted(gs_args *Args)
{
        if(GSArgsIsPresent(Args, "-h") ||
           GSArgsIsPresent(Args, "--help"))
                return true;
        else
                return false;
}

/******************************************************************************
 * Byte streams / Buffers / File IO
 ******************************************************************************/



@@ 847,13 778,13 @@ typedef struct gs_buffer
{
        char *Start;
        char *Cursor;
        size_t Capacity;
        size_t Length;
        u64 Capacity;
        u64 Length;
        char *SavedCursor;
} gs_buffer;

gs_buffer *
GSBufferInit(gs_buffer *Buffer, char *Start, size_t Size)
GSBufferInit(gs_buffer *Buffer, char *Start, u64 Size)
{
        Buffer->Start = Start;
        Buffer->Cursor = Start;


@@ 866,7 797,7 @@ GSBufferInit(gs_buffer *Buffer, char *Start, size_t Size)
bool
GSBufferIsEOF(gs_buffer *Buffer)
{
        int Size = Buffer->Cursor - Buffer->Start;
        u64 Size = Buffer->Cursor - Buffer->Start;
        bool Result = Size >= Buffer->Length;
        return Result;
}


@@ 903,38 834,40 @@ GSBufferRestoreCursor(gs_buffer *Buffer)
        return true;
}

size_t
GSFileSize(char *FileName)
{
        size_t FileSize = 0;
        FILE *File = fopen(FileName, "r");
        if(File != NULL)
        {
                fseek(File, 0, SEEK_END);
                FileSize = ftell(File);
                fclose(File);
        }
        return FileSize;
}

bool
GSFileCopyToBuffer(char *FileName, gs_buffer *Buffer)
{
        FILE *File = fopen(FileName, "r");
        if(File == NULL) return false;

        fseek(File, 0, SEEK_END);
        size_t FileSize = ftell(File);
        int Remaining = (Buffer->Start + Buffer->Capacity) - Buffer->Cursor;
        if(FileSize > Remaining) return false;

        fseek(File, 0, SEEK_SET);
        size_t BytesRead = fread(Buffer->Cursor, 1, FileSize, File);
        Buffer->Length += FileSize;
        Buffer->Cursor += FileSize;
        *(Buffer->Cursor) = '\0';

        return true;
}
// TODO: Move to platform-specific header include.
/* size_t */
/* GSFileSize(char *FileName) */
/* { */
/*         size_t FileSize = 0; */
/*         FILE *File = fopen(FileName, "r"); */
/*         if(File != NULL) */
/*         { */
/*                 fseek(File, 0, SEEK_END); */
/*                 FileSize = ftell(File); */
/*                 fclose(File); */
/*         } */
/*         return FileSize; */
/* } */

// TODO: Move to platform-specific header include
/* bool */
/* GSFileCopyToBuffer(char *FileName, gs_buffer *Buffer) */
/* { */
/*         FILE *File = fopen(FileName, "r"); */
/*         if(File == NULL) return false; */

/*         fseek(File, 0, SEEK_END); */
/*         size_t FileSize = ftell(File); */
/*         int Remaining = (Buffer->Start + Buffer->Capacity) - Buffer->Cursor; */
/*         if(FileSize > Remaining) return false; */

/*         fseek(File, 0, SEEK_SET); */
/*         size_t BytesRead = fread(Buffer->Cursor, 1, FileSize, File); */
/*         Buffer->Length += FileSize; */
/*         Buffer->Cursor += FileSize; */
/*         *(Buffer->Cursor) = '\0'; */

/*         return true; */
/* } */

#endif /* GS_H */

M src/lexer.c => src/lexer.c +2 -0
@@ 12,6 12,8 @@

#include "gs.h"

#include <stdio.h> /* TODO: Remove printfs */

enum token_type {
        Token_Unknown,


M src/main.c => src/main.c +57 -21
@@ 7,15 7,17 @@
 * Copyright - 2020, Aaron Oman and the C-Parser contributors
 * SPDX-License-Identifier: LGPL-3.0-only
 ******************************************************************************/
#include <stdlib.h> /* EXIT_SUCCESS, EXIT_FAILURE */
#include <stdio.h>
#include <alloca.h>

#include "gs.h"
#include "lexer.c"
#include "parser.c"

void Usage(char *Name) {
 #include <stdlib.h> /* EXIT_SUCCESS, EXIT_FAILURE */
#include <stdio.h>
#include <string.h> // strerror
#include <sys/stat.h>
#include <errno.h>

void Usage(const char *Name) {
        printf("Usage: %s operation file [options]\n", Name);
        puts("  operation: One of: [parse, lex].");
        puts("  file: Must be a file in this directory.");


@@ 26,27 28,61 @@ void Usage(char *Name) {
        exit(EXIT_SUCCESS);
}

int main(int ArgCount, char **Arguments) {
        gs_args Args;
        GSArgsInit(&Args, ArgCount, Arguments);
        if (GSArgsHelpWanted(&Args)           ||
           ArgCount < 3                      ||
           (!GSArgsIsPresent(&Args, "parse") &&
            !GSArgsIsPresent(&Args, "lex")))
                Usage(GSArgsProgramName(&Args));
int main(int argc, char **argv) {
        const char *ProgName = argv[0];

        for (int i = 0; i < argc; i++) {
                if (GSStringIsEqual(argv[i], "--help", 6) ||
                    GSStringIsEqual(argv[i], "-help", 5) ||
                    GSStringIsEqual(argv[i], "-h", 2))
                        Usage(ProgName);
        }

        if (argc < 3) Usage(ProgName);

        char *Command = argv[1];

        if (!GSStringIsEqual(Command, "parse", 5) &&
            !GSStringIsEqual(Command, "lex", 3))
                Usage(ProgName);

        char *Filename = argv[2];
        struct stat StatBuf;
        if (stat(Filename, &StatBuf) != 0) {
                fprintf(stderr, strerror(errno));
                exit(EXIT_FAILURE);
        }

        char *BufStart = (char *)malloc(StatBuf.st_size);
        gs_buffer Buffer;
        char *Filename = GSArgsAtIndex(&Args, 2);
        size_t AllocSize = GSFileSize(Filename);
        GSBufferInit(&Buffer, alloca(AllocSize), AllocSize);
        GSBufferInit(&Buffer, BufStart, StatBuf.st_size);

        FILE *File = fopen(Filename, "r");
        if (File == NULL) {
                fprintf(stderr, strerror(errno));
                exit(EXIT_FAILURE);
        }

        size_t BytesRead = fread(Buffer.Cursor, 1, StatBuf.st_size, File);
        Buffer.Length += StatBuf.st_size;
        Buffer.Cursor += StatBuf.st_size;
        *(Buffer.Cursor) = '\0';

        fclose(File);

        if (!GSFileCopyToBuffer(Filename, &Buffer))
                GSAbortWithMessage("Couldn't copy entire file to buffer\n");
        gs_allocator Allocator = {
                .Alloc = malloc,
                .Free = free,
                .Realloc = realloc,
                .ArrayAlloc = calloc,
        };

        if (GSArgsIsPresent(&Args, "parse"))
                Parse(&Buffer, GSArgsIsPresent(&Args, "--show-parse-tree"));
        else
        if (GSStringIsEqual(Command, "parse", 5)) {
                bool ShowParseTree = (argc == 4 && GSStringIsEqual(argv[3], "--show-parse-tree", 17));
                Parse(Allocator, &Buffer, ShowParseTree);
        } else {
                Lex(&Buffer);
        }

        return EXIT_SUCCESS;
}

M src/parse_tree.c => src/parse_tree.c +33 -32
@@ 10,24 10,12 @@
#ifndef PARSE_TREE
#define PARSE_TREE

#include <stdint.h>
#include <errno.h>
#include "gs.h"

#define DEFAULT_ALLOC_COUNT 2

typedef void *(*parse_tree_alloc)(size_t);
typedef void (*parse_tree_free)(void *);
typedef void *(*parse_tree_realloc)(void *, size_t);

typedef struct parse_tree_allocator {
        parse_tree_alloc Alloc;
        parse_tree_free Free;
        parse_tree_realloc Realloc;
} parse_tree_allocator;

typedef struct parse_tree_node {
        parse_tree_allocator Allocator;
        gs_allocator Allocator;
        u32 NameLength;
        u32 Capacity;
        u32 NumChildren;


@@ 36,7 24,26 @@ typedef struct parse_tree_node {
        struct parse_tree_node *Children;
} parse_tree_node;

parse_tree_node *ParseTreeInit(parse_tree_allocator Allocator);
typedef enum ParseTreeErrorEnum {
        ParseTreeErrorChildAlloc,
        ParseTreeErrorNone,
} ParseTreeErrorEnum;

const char *__ParseTree_ErrorStrings[] = {
        "Couldn't allocate memory for new child node",
        "No Error"
};

ParseTreeErrorEnum __ParseTree_LastError = ParseTreeErrorNone;

const char *ParseTreeErrorString() {
        const char *Result = __ParseTree_ErrorStrings[__ParseTree_LastError];
        __ParseTree_LastError = ParseTreeErrorNone;

        return Result;
}

parse_tree_node *ParseTreeInit(gs_allocator Allocator);
void ParseTreeDeinit(parse_tree_node *Node);

void ParseTreeSetName(parse_tree_node *Node, char *Name);


@@ 45,12 52,12 @@ void ParseTreeSet(parse_tree_node *Self, char *Name, token Token);
void ParseTreeNewChildren(parse_tree_node *Self, u32 Count);
void ParseTreePrint(parse_tree_node *Self, u32 IndentLevel, u32 IndentIncrement);

parse_tree_node *__ParseTree_Alloc(parse_tree_allocator Allocator) {
parse_tree_node *__ParseTree_Alloc(gs_allocator Allocator) {
        parse_tree_node *Node = (parse_tree_node *)Allocator.Alloc(sizeof(*Node));
        return Node;
}

void __ParseTree_Init(parse_tree_node *Node, parse_tree_allocator Allocator) {
void __ParseTree_Init(parse_tree_node *Node, gs_allocator Allocator) {
        Node->Allocator = Allocator;

        Node->Token.Text = NULL;


@@ 68,7 75,7 @@ void __ParseTree_Init(parse_tree_node *Node, parse_tree_allocator Allocator) {
        return;
}

parse_tree_node *ParseTreeInit(parse_tree_allocator Allocator) {
parse_tree_node *ParseTreeInit(gs_allocator Allocator) {
        parse_tree_node *Node = __ParseTree_Alloc(Allocator);
        __ParseTree_Init(Node, Allocator);
        return Node;


@@ 100,19 107,15 @@ void ParseTreeSet(parse_tree_node *Self, char *Name, token Token) {
        ParseTreeSetToken(Self, Token);
}

void __ParseTree_AddChild(parse_tree_node *Self, char *Name) {
bool __ParseTree_AddChild(parse_tree_node *Self, char *Name) {
        u32 NameLength = GSStringLength(Name);
        u32 AllocCount = DEFAULT_ALLOC_COUNT;

        if (Self->Children == NULL) {
                Self->Children = (parse_tree_node *)malloc(sizeof(parse_tree_node) * AllocCount);
                Self->Children = (parse_tree_node *)Self->Allocator.Alloc(sizeof(parse_tree_node) * AllocCount);
                if (Self->Children == NULL) {
                        int errval = errno;
                        if (errval == ENOMEM) {
                                GSAbortWithMessage("Couldn't allocate node in debug tree! Out of memory!\n");
                        } else {
                                GSAbortWithMessage("Couldn't allocate node in debug tree! I don't know why!\n");
                        }
                        __ParseTree_LastError = ParseTreeErrorChildAlloc;
                        return false;
                }
                Self->Capacity = AllocCount;
                for (int i=0; i<AllocCount; i++) {


@@ 121,14 124,10 @@ void __ParseTree_AddChild(parse_tree_node *Self, char *Name) {
        } else if (Self->Capacity <= Self->NumChildren) {
                if (Self->Capacity > 0) {
                        AllocCount = Self->Capacity * 2;
                        Self->Children = (parse_tree_node *)realloc(Self->Children, sizeof(parse_tree_node) * AllocCount);
                        Self->Children = (parse_tree_node *)Self->Allocator.Realloc(Self->Children, sizeof(parse_tree_node) * AllocCount);
                        if (Self->Children == NULL) {
                                int errval = errno;
                                if (errval == ENOMEM) {
                                        GSAbortWithMessage("Couldn't allocate node in debug tree! Out of memory!\n");
                                } else {
                                        GSAbortWithMessage("Couldn't allocate node in debug tree! I don't know why!\n");
                                }
                                __ParseTree_LastError = ParseTreeErrorChildAlloc;
                                return false;
                        }
                        Self->Capacity = AllocCount;
                        for (int i=Self->NumChildren; i<AllocCount; i++) {


@@ 139,6 138,8 @@ void __ParseTree_AddChild(parse_tree_node *Self, char *Name) {

        ParseTreeSetName(&Self->Children[Self->NumChildren], Name);
        Self->NumChildren++;

        return true;
}

void ParseTreeNewChildren(parse_tree_node *Self, u32 Count) {

M src/parser.c => src/parser.c +8 -8
@@ 15,6 15,8 @@
#include "lexer.c"
#include "parse_tree.c"

gs_allocator __Parser_Allocator;

void __Parser_ParseTreeUpdate(parse_tree_node *ParseTree, char *Name, u32 NumChildren) {
        ParseTreeSetName(ParseTree, Name);
        if (NumChildren > 0) {


@@ 55,17 57,17 @@ struct typedef_names {
struct typedef_names TypedefNames;

void TypedefClear() {
        free((void *)TypedefNames.Name);
        free((void *)TypedefNames.NameIndex);
        __Parser_Allocator.Free((void *)TypedefNames.Name);
        __Parser_Allocator.Free((void *)TypedefNames.NameIndex);
        TypedefNames.Capacity = 0;
        TypedefNames.NumNames = 0;
}

void TypedefInit() {
        char *Memory = (char *)malloc(1024);
        char *Memory = (char *)__Parser_Allocator.Alloc(1024);
        TypedefNames.Name = Memory;
        TypedefNames.Capacity = 1024;
        TypedefNames.NameIndex = malloc(1024 / 2 * sizeof(int));
        TypedefNames.NameIndex = __Parser_Allocator.Alloc(1024 / 2 * sizeof(int));
        TypedefNames.NumNames = 0;
}



@@ 2742,10 2744,8 @@ bool ParseTranslationUnit(struct tokenizer *Tokenizer, parse_tree_node *ParseTre
        return false;
}

void Parse(gs_buffer *FileContents, bool ShowParseTree) {
        parse_tree_allocator Allocator;
        Allocator.Alloc = malloc;
        Allocator.Free = free;
void Parse(gs_allocator Allocator, gs_buffer *FileContents, bool ShowParseTree) {
        __Parser_Allocator = Allocator;
        parse_tree_node *ParseTree = ParseTreeInit(Allocator);

        struct tokenizer Tokenizer;