Initial commit

This commit is contained in:
2025-11-23 13:37:08 +11:00
commit d1711accde
10 changed files with 499 additions and 0 deletions

144
src/lexer.c Normal file
View File

@@ -0,0 +1,144 @@
#include "lexer.h"
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
void addTokenToLine(TokenLine* line, Token tok) {
line->count++;
Token* newTokens = realloc(line->tokens, line->count * sizeof(Token));
if (!newTokens) {
perror("Failed to allocate token");
exit(EXIT_FAILURE);
}
line->tokens = newTokens;
line->tokens[line->count - 1] = tok;
}
void addLineToLexed(LexedFile* lf, TokenLine line) {
lf->lineCount++;
TokenLine* newLines = realloc(lf->lines, lf->lineCount * sizeof(TokenLine));
if (!newLines) {
perror("Failed to allocate line");
exit(EXIT_FAILURE);
}
lf->lines = newLines;
lf->lines[lf->lineCount - 1] = line;
}
LexedFile lexFile(const char* fileContents) {
LexedFile result = {0};
result.lines = NULL;
result.lineCount = 0;
TokenLine currentLine = {0};
currentLine.tokens = NULL;
currentLine.count = 0;
char buf[1024] = {0};
size_t bufLen = 0;
bool inString = false;
bool inChar = false;
bool isComment = false;
for (size_t i = 0; fileContents[i] != '\0'; i++) {
char c = fileContents[i];
switch (c) {
case '"':
if (!isComment) {
if (inChar) {
buf[bufLen++] = c;
} else {
inString = !inString;
buf[bufLen++] = c;
}
}
break;
case '\'':
if (!isComment) {
if (inString) {
buf[bufLen++] = c;
} else {
inChar = !inChar;
buf[bufLen++] = c;
}
}
break;
case '\n':
if (!inString && !inChar) {
// Add current token to line if exists
if (bufLen > 0) {
buf[bufLen] = '\0';
Token tok;
tok.text = strdup(buf);
// Add tok to currentLine (need helper function)
addTokenToLine(&currentLine, tok);
bufLen = 0;
}
// Add line to result (need helper function)
addLineToLexed(&result, currentLine);
// Reset for next line
currentLine.tokens = NULL;
currentLine.count = 0;
isComment = false;
} else if (!isComment) {
buf[bufLen++] = c;
}
break;
case '#':
if (!inString && !inChar) {
isComment = true;
if (bufLen > 0) {
buf[bufLen] = '\0';
Token tok;
tok.text = strdup(buf);
addTokenToLine(&currentLine, tok);
bufLen = 0;
}
addLineToLexed(&result, currentLine);
currentLine.tokens = NULL;
currentLine.count = 0;
} else {
buf[bufLen++] = c;
}
break;
case ' ':
if (!inString && !inChar) {
if (bufLen > 0 && !isComment) {
buf[bufLen] = '\0';
Token tok;
tok.text = strdup(buf);
addTokenToLine(&currentLine, tok);
bufLen = 0;
}
} else {
buf[bufLen++] = c;
}
break;
default:
if (!isComment) {
buf[bufLen++] = c;
}
break;
}
}
// Handle any remaining content
if (bufLen > 0) {
buf[bufLen] = '\0';
Token tok;
tok.text = strdup(buf);
addTokenToLine(&currentLine, tok);
}
if (currentLine.count > 0) {
addLineToLexed(&result, currentLine);
}
return result;
}

23
src/lexer.h Normal file
View File

@@ -0,0 +1,23 @@
#ifndef LEXER_H
#define LEXER_H
#include <stdlib.h>
typedef struct Token {
char* text;
} Token;
typedef struct TokenLine {
Token* tokens;
size_t count;
} TokenLine;
typedef struct LexedFile {
TokenLine* lines;
size_t lineCount;
} LexedFile;
LexedFile lexFile(const char* fileContents);
void freeLexedFile(LexedFile* lf);
#endif

48
src/main.c Normal file
View File

@@ -0,0 +1,48 @@
#include "types.h"
#include "parser.h"
#include <stdio.h>
char* getFileContents(const char* filename) {
// https://stackoverflow.com/questions/3747086/reading-the-whole-text-file-into-a-char-array-in-c
FILE* fp;
long lSize;
char* file;
fp = fopen(filename, "rb");
if (!fp) {
perror(filename);
exit(1);
}
fseek(fp, 0L, SEEK_END);
lSize = ftell(fp);
rewind(fp);
file = calloc(1, lSize + 1);
if (!file) {
fclose(fp);
fputs("memory allocation fail when reading file", stderr);
exit(1);
}
if (1!=fread(file, lSize, 1, fp)) {
fclose(fp);
free(file);
fputs("couldn't read entire file", stderr);
exit(1);
}
// we done
fclose(fp);
return file;
}
int main(int argc, char** argv) {
if (argc < 2) {
printf("Usage: ground [file]\n");
exit(1);
}
char* file = getFileContents(argv[1]);
GroundProgram program = parseFile(file);
}

32
src/parser.c Normal file
View File

@@ -0,0 +1,32 @@
#include "parser.h"
#include "types.h"
#include "lexer.h"
#include <stdio.h>
GroundProgram createGroundProgram() {
GroundProgram gp;
gp.size = 0;
return gp;
}
void addInstructionToProgram(GroundProgram* gp, GroundInstruction instruction) {
gp->size++;
GroundInstruction* ptr = realloc(gp->instructions, gp->size * sizeof(GroundInstruction));
if (ptr == NULL) {
perror("Couldn't allocate memory for instruction");
exit(1);
}
gp->instructions = ptr;
gp->instructions[gp->size - 1] = instruction;
}
void freeGroundProgram(GroundProgram* gp) {
for (int i = 0; i < gp->size; i++) {
freeGroundInstruction(&gp->instructions[i]);
}
}
GroundProgram parseFile(LexedFile file) {
GroundProgram gp;
return gp;
}

27
src/parser.h Normal file
View File

@@ -0,0 +1,27 @@
#ifndef PARSER_H
#define PARSER_H
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include "types.h"
#include "lexer.h"
typedef struct GroundProgram {
GroundInstruction* instructions;
size_t size;
} GroundProgram;
// Creates a new GroundProgram
GroundProgram createGroundProgram();
// Adds instruction (instruction) to GroundProgram (gp)
void addInstructionToProgram(GroundProgram* gp, GroundInstruction instruction);
// Frees all GroundInstructions in GroundProgram (gp)
void freeGroundProgram(GroundProgram* gp);
// Parses the file into a GroundProgram
GroundProgram parseFile(LexedFile file);
#endif

90
src/types.c Normal file
View File

@@ -0,0 +1,90 @@
#include "types.h"
GroundValue createIntGroundValue(int64_t in) {
GroundValue gv;
gv.data.intVal = in;
gv.type = INT;
return gv;
}
GroundValue createDoubleGroundValue(double in) {
GroundValue gv;
gv.data.doubleVal = in;
gv.type = DOUBLE;
return gv;
}
GroundValue createStringGroundValue(const char* in) {
GroundValue gv;
gv.data.stringVal = strdup(in);
gv.type = STRING;
return gv;
}
GroundValue createCharGroundValue(char in) {
GroundValue gv;
gv.data.charVal = in;
gv.type = CHAR;
return gv;
}
GroundValue createBoolGroundValue(bool in) {
GroundValue gv;
gv.data.boolVal = in;
gv.type = BOOL;
return gv;
}
void freeGroundValue(GroundValue* gv) {
if (gv->type == STRING && gv->data.stringVal != NULL) {
free(gv->data.stringVal);
}
}
GroundArg createValueGroundArg(GroundValue value) {
GroundArg ga;
ga.value.value = value;
ga.type = VALUE;
return ga;
}
GroundArg createRefGroundArg(GroundArgType type, const char* refname) {
GroundArg ga;
ga.value.refName = strdup(refname);
ga.type = type;
return ga;
}
void freeGroundArg(GroundArg* ga) {
if (ga->type == VALUE) {
freeGroundValue(&ga->value.value);
} else {
free(ga->value.refName);
}
}
GroundInstruction createGroundInstruction(GroundInstType type) {
GroundInstruction gi;
gi.type = type;
gi.args.args = NULL;
gi.args.length = 0;
return gi;
}
void freeGroundInstruction(GroundInstruction* gi) {
for (size_t i = 0; i < gi-> args.length; i++) {
freeGroundArg(&gi->args.args[i]);
}
}
void addArgToInstruction(GroundInstruction* gi, GroundArg arg) {
gi->args.length ++;
GroundArg* newArgs = realloc(gi->args.args, gi->args.length * sizeof(GroundArg));
if (newArgs == NULL) {
perror("Failed to allocate memory for instruction argument");
exit(EXIT_FAILURE);
}
gi->args.args = newArgs;
gi->args.args[gi->args.length - 1] = arg;
}

116
src/types.h Normal file
View File

@@ -0,0 +1,116 @@
#ifndef TYPES_H
#define TYPES_H
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
typedef enum GroundInstType {
IF, JUMP, END, INPUT, PRINT, PRINTLN, SET, GETTYPE, EXISTS, SETLIST, SETLISTAT, GETLISTAT, GETLISTSIZE, LISTAPPEND, GETSTRSIZE, GETSTRCHARAT, ADD, SUBTRACT, MULTIPLY, DIVIDE, EQUAL, INEQUAL, NOT, GREATER, LESSER, STOI, STOD, TOSTRING, FUN, RETURN, ENDFUN, PUSHARG, CALL, STRUCT, ENDSTRUCT, INIT, USE, EXTERN
} GroundInstType;
typedef enum GroundValueType {
INT, DOUBLE, STRING, CHAR, BOOL, LIST, CUSTOM
} GroundValueType;
typedef enum GroundArgType {
VALUE, VALREF, DIRREF, LINEREF, LABEL, FNREF
} GroundArgType;
struct GroundValue;
struct List;
/*
* Stores literal values created in a Ground program.
* Associated functions:
* createIntGroundValue(), createDoubleGroundValue(), createStringGroundvalue(),
* createCharGroundValue(), createBoolGroundValue(), freeGroundValue()
*/
typedef struct GroundValue {
GroundValueType type;
union {
int64_t intVal;
double doubleVal;
char* stringVal;
char charVal;
bool boolVal;
struct List* listVal;
void* customVal;
} data;
} GroundValue;
/*
* Currently unused. Max, implement this sometime soon.
*/
typedef struct List {
size_t size;
size_t capacity;
GroundValue* values;
} List;
/*
* Stores arguments for the GroundInstruction struct.
* Associated functions:
* createValueGroundArg(), createRefGroundArg(), freeGroundArg()
*/
typedef struct GroundArg {
GroundArgType type;
union {
GroundValue value;
char* refName;
} value;
} GroundArg;
/*
* Represents a Ground instruction.
* Associated functions:
* createGroundInstruction(), freeGroundInstruction(), addArgToInstruction()
*/
typedef struct GroundInstruction {
GroundInstType type;
struct {
GroundArg* args;
size_t length;
} args;
} GroundInstruction;
// Creates a GroundValue containing (in), with type INT.
GroundValue createIntGroundValue(int64_t in);
// Creates a GroundValue containing (in), with type DOUBLE.
GroundValue createDoubleGroundValue(double in);
;
// Creates a GroundValue containing (in), with type STRING.
GroundValue createStringGroundValue(const char* in);
// Creates a GroundValue containing (in), with type CHAR.
GroundValue createCharGroundValue(char in);
// Creates a GroundValue containing (in), with type BOOl.
GroundValue createBoolGroundValue(bool in);
// If (gv) contains any data stored on the heap, frees it.
void freeGroundValue(GroundValue* gv);
// Initializes a GroundArg with type VALUE
GroundArg createValueGroundArg(GroundValue value);
// Initializes a GroundArg with type (type), and refname (refname).
GroundArg createRefGroundArg(GroundArgType type, const char* refname);
// Frees all data stored on the heap in a GroundArg.
void freeGroundArg(GroundArg* ga);
// Initializes a GroundInstruction, with inst type (type).
GroundInstruction createGroundInstruction(GroundInstType type);
// Frees all data stored on the heap in a GroundInstruction.
void freeGroundInstruction(GroundInstruction* gi);
// Adds arg (arg) to the GroundInstruction (gi).
void addArgToInstruction(GroundInstruction* gi, GroundArg arg);
#endif