Initial commit
This commit is contained in:
144
src/lexer.c
Normal file
144
src/lexer.c
Normal 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(¤tLine, 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(¤tLine, 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(¤tLine, 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(¤tLine, tok);
|
||||
}
|
||||
if (currentLine.count > 0) {
|
||||
addLineToLexed(&result, currentLine);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
23
src/lexer.h
Normal file
23
src/lexer.h
Normal 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
48
src/main.c
Normal 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
32
src/parser.c
Normal 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
27
src/parser.h
Normal 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
90
src/types.c
Normal 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
116
src/types.h
Normal 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
|
||||
Reference in New Issue
Block a user