Initial commit
This commit is contained in:
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
cmake-build-debug
|
||||||
|
build
|
||||||
|
ground
|
||||||
|
groundc
|
||||||
|
.idea
|
||||||
13
CMakeLists.txt
Normal file
13
CMakeLists.txt
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
cmake_minimum_required(VERSION 4.0)
|
||||||
|
project(groundc C)
|
||||||
|
|
||||||
|
set(CMAKE_C_STANDARD 11)
|
||||||
|
|
||||||
|
include_directories(src)
|
||||||
|
|
||||||
|
add_executable(groundc
|
||||||
|
src/main.c
|
||||||
|
src/parser.c
|
||||||
|
src/parser.h
|
||||||
|
src/types.c
|
||||||
|
src/types.h)
|
||||||
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
|
||||||
1
tests/test.grnd
Normal file
1
tests/test.grnd
Normal file
@@ -0,0 +1 @@
|
|||||||
|
println "dingus"
|
||||||
Reference in New Issue
Block a user