Compare commits

9 Commits
Author SHA1 Message Date
glm94 70a3118a99 'Minor' bug fix for the StatementList, forgot to set the capacity. 2022-04-04 19:44:13 +00:00
glm94 842473742e Begun refactoring the Parser to generate a list of Stmt which the Interpreter will then execute (to be done). 2022-04-04 19:22:59 +00:00
glm94 73067fcc1f Added statements to the Parser, currently just the Print and Expression statements. 8.1 isn't quite done yet, maybe half way there. 2022-03-23 19:43:46 +00:00
glm94 bf59a98628 Updated the Makefile, set debug option for the compiler, and fixed all the warnings generated by gcc with O2 optimization option for release builds. 2022-03-18 17:01:15 +00:00
glm94 1e6bbb87d4 Cleaned up the Makefile, added the framework for checking for runtime errrors in the Interpreter and fixed a bug where I didn't close out the 'va_list' in the Match function in the Parser. 2022-03-17 18:58:23 +00:00
glm94 34557c92c3 Setup the Makefile to allow me to produce a release build and to create some directories if they're not there already. 2022-03-16 18:23:11 +00:00
glm94 b3693f17df Updated the project structure, and modified the Makefile to hopefully be future proof so I can freely make sub-folders in the src/ folder and not have to worry about breaking the Makefile. 2022-03-16 18:07:37 +00:00
glm94 6daaaae7c2 Fixed a bug when the scanner parses a number and creates the token. 2022-03-16 00:00:17 -05:00
glm94 b072921304 Touched up the Scanner. Refactored the Interpreter some more, this time it's able to be run on simple expressions. String concatenation can be performed by the Interpreter however, numbers and Booleans are not being stored correctly in the Object structures. 2022-03-15 20:50:08 +00:00
16 changed files with 273 additions and 62 deletions
+1
View File
@@ -1,3 +1,4 @@
clox
*.lox
obj/
bin/
+27 -7
View File
@@ -1,17 +1,37 @@
CC = gcc
SOURCEFILES := $(wildcard *.c)
CFLAGS=-g -Wall -DDEBUG -Wpedantic
SRCDIR=src
OBJDIR=obj
SRCS=$(wildcard $(SRCDIR)/*.c)
# Substitute all .c with .o from SRCS
OBJS=$(patsubst $(SRCDIR)/%.c, $(OBJDIR)/%.o, $(SRCS))
SOURCE := $(wildcard *.c)
BINDIR=bin
BIN=$(BINDIR)/clox
$(SOURCE:.c=.o): $(SOURCE)
@mkdir -p obj
$(CC) $^ -o obj/clox
all: $(BIN)
release: CFLAGS=-Wall -Wpedantic -O2
release: clean
release: $(BIN)
$(BIN): $(OBJS) $(BINDIR)
$(CC) $(CFLAGS) $(OBJS) -o $@
$(OBJDIR)/%.o: $(SRCDIR)/%.c $(OBJDIR)
$(CC) $(CFLAGS) -c $< -o $@
$(BINDIR):
mkdir $@
$(OBJDIR):
mkdir $@
.PHONY: clean
.PHONY: test
clean:
rm -r obj
rm -rf $(BINDIR)/* $(OBJDIR)/*
test:
./obj/clox test.lox
$(BIN) test.lox
-18
View File
@@ -1,18 +0,0 @@
#include "expr.h"
char* Parenthesize(char*, int, ...);
void VisitBinary(struct binary expr) {
}
void VisitGrouping(struct grouping);
void VisitLiteral(Token);
void VisitUnary(struct unary);
char* Parenthesize(char* operator, int count, ...) {
va_list list;
va_start(list, count);
va_arg(list, Expr);
}
-15
View File
@@ -1,15 +0,0 @@
#ifndef PARSER_H
#define PARSER_H
#include "expr.h"
#include "scanner.h"
#include "token.h"
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
Expr* GenerateExpressionTree(const TokenList* list);
void PrintExpressionTree(const Expr*);
void FreeExpressionTree(Expr*);
#endif
+4 -4
View File
@@ -40,9 +40,9 @@ struct Expr {
} expression;
};
void VisitBinary(struct binary);
void VisitGrouping(struct grouping);
void VisitLiteral(Token);
void VisitUnary(struct unary);
// void VisitBinary(struct binary);
// void VisitGrouping(struct grouping);
// void VisitLiteral(Token);
// void VisitUnary(struct unary);
#endif
+33 -6
View File
@@ -14,6 +14,7 @@ Object* VisitBinaryExpression(Expr*);
int IsTruthy(Object*);
int IsEqual(Object*, Object*);
int ConcatStringObject(Object*, const Object*);
void CheckNumberOperands(TokenType, int, ...);
void PrintObject(Object*);
void PrintObject(Object* o) {
@@ -53,7 +54,6 @@ void Interpret(Expr* exp) {
}
Object* VisitLiteralExpression(Expr* expr) {
printf("Literal: %p\n", (double *) expr->expression.Literal->literal);
return CreateObject(expr->expression.Literal->literal, expr->expression.Literal->type);
}
@@ -66,59 +66,65 @@ Object* VisitGroupingExpression(Expr* expression) {
Object* VisitBinaryExpression(Expr* expression) {
Object* left = Evaluate(expression->expression.Binary.left);
Object* right = Evaluate(expression->expression.Binary.right);
PrintObject(left);
PrintObject(right);
double computed_value;
switch(expression->expression.Binary.op->type) {
case Greater:
CheckNumberOperands(expression->expression.Binary.op->type, 2, left, right);
computed_value = left->value.number > right->value.number;
FreeObject(left);
FreeObject(right);
return CreateObject(&computed_value, TRUE);
//return left > right;
case Greater_Equal:
CheckNumberOperands(expression->expression.Binary.op->type, 2, left, right);
computed_value = left->value.number >= right->value.number;
FreeObject(left);
FreeObject(right);
return CreateObject(&computed_value, TRUE);
//return left >= right;
case Less:
CheckNumberOperands(expression->expression.Binary.op->type, 2, left, right);
computed_value = left->value.number < right->value.number;
FreeObject(left);
FreeObject(right);
return CreateObject(&computed_value, TRUE);
//return left < right;
case Less_Equal:
CheckNumberOperands(expression->expression.Binary.op->type, 2, left, right);
computed_value = left->value.number <= right->value.number;
FreeObject(left);
FreeObject(right);
return CreateObject(&computed_value, TRUE);
//return left <= right;
case Bang_Equal:
CheckNumberOperands(expression->expression.Binary.op->type, 2, left, right);
computed_value = !IsEqual(left, right);
FreeObject(left);
FreeObject(right);
return CreateObject(&computed_value, TRUE);
//return !IsEqual(left, right);
case Equal_Equal:
CheckNumberOperands(expression->expression.Binary.op->type, 2, left, right);
computed_value = IsEqual(left, right);
FreeObject(left);
FreeObject(right);
return CreateObject(&computed_value, TRUE);
//return IsEqual(left, right);
case Minus:
CheckNumberOperands(expression->expression.Binary.op->type, 2, left, right);
left->value.number -= right->value.number;
FreeObject(right);
return left;
//return left - right;
case Slash:
CheckNumberOperands(expression->expression.Binary.op->type, 2, left, right);
left->value.number /= right->value.number;
FreeObject(right);
return left;
//return *((double*)left) / *((double*)right);
case Star:
printf("%f * %f = %f\n", left->value.number, right->value.number, left->value.number * right->value.number);
CheckNumberOperands(expression->expression.Binary.op->type, 2, left, right);
left->value.number *= right->value.number;
FreeObject(right);
return left;
@@ -159,6 +165,7 @@ Object* VisitUnaryExpression(Expr* expression) {
switch (expression->expression.Unary.op->type) {
case Minus:
CheckNumberOperands(expression->expression.Unary.op->type, 1, right);//This needs to "throw" if the function fails.
computed_value = -right->value.number;
FreeObject(right);
c = CreateObject(&computed_value, Number);
@@ -222,11 +229,16 @@ Object* CreateObject(const void* value, TokenType type) {
break;
default:
if (value) {
int length = strlen(value);
unsigned int length = strlen(value);
object->instance = INS_STRING;
object->value.string = calloc(length + 1, sizeof(char));
strncpy(object->value.string, value, length);
if (!object->value.string) {
fprintf(stderr, "Faild to calloc %u bytes for a new string Object. %s.\n", length + 1, strerror(errno));
return NULL;
}
memcpy(object->value.string, value, length);
} else object->instance = INS_NULL; //TODO: this is most likely an error, but we'll ignore that for now.
}
@@ -283,3 +295,18 @@ int IsEqual(Object* a, Object* b) {
return 0;
}
void CheckNumberOperands(TokenType operator, int operandCount, ...) {
va_list list;
va_start(list, operandCount);
for(int i = 0; i < operandCount; i++) {
Object* operand = va_arg(list, Object*);
if (operand->instance != INS_DOUBLE) {
va_end(list);
return; //TODO: "throw" runtime error "Operand must be a number."
}
}
va_end(list);
}
View File
+13 -6
View File
@@ -13,6 +13,10 @@ void RunPrompt(void);
char* GetFileContents(const char*);
int main(int argc, char** argv) {
#ifdef DEBUG
printf("Debug clox build.\n");
#endif
if (argc > 2) {
printf("Useage: clox [script]\n");
exit(EX_USAGE);
@@ -39,13 +43,16 @@ void RunFile(const char* path) {
char* contents = GetFileContents(path);
TokenList* tokens = ScanTokens(contents);
free(contents);
Print(tokens);
printf("TREE:\n");
Expr* tree = GenerateExpressionTree(tokens);
PrintExpressionTree(tree);
printf("TOKENS:\n");
//Print(tokens);
printf("EXPRESSION TREE:\n");
//Expr* tree = GenerateExpressionTree(tokens);
StatementList* statements = Parse(tokens);
//PrintExpressionTree(tree);
printf("\n");
Interpret(tree);
FreeExpressionTree(tree);
//Interpret(tree);
FreeStatementList(statements);
//FreeExpressionTree(tree);
DestroyTokenList(tokens);
}
+116 -3
View File
@@ -1,7 +1,10 @@
#include "parser.h"
#include "expr.h"
#include "statement.h"
#include "token.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
Expr* Expression(void);
Expr* Equality(void);
@@ -10,6 +13,11 @@ Expr* Term(void);
Expr* Factor(void);
Expr* Unary(void);
Expr* Primary(void);
Stmt* Statement(void);
Stmt* PrintStatement(void);
Stmt* ExpressionStatement(void);
StatementList* CreateStatementList(void);
int AddStatementToList(Stmt*, StatementList*);
int Match(int, ...);
int Check(TokenType);
int ParserAtEnd(void);
@@ -17,14 +25,29 @@ Token* ParserPeek(void);
Token* Previous(void);
Token* AdvanceParser(void);
void SynchronizeParser(void);
void FreeExpressionTree(Expr*);
const TokenList* ListOfTokens;
int Current = 0;
Expr* GenerateExpressionTree(const TokenList* list) {
StatementList* Parse(const TokenList* list) {
ListOfTokens = list;
StatementList* statements = CreateStatementList();
Stmt* statement = NULL;
return Expression();
if (!statements) return NULL;
while(!ParserAtEnd()) {
statement = Statement();
if (!statement) {
fprintf(stderr, "[Warn] No statement generated\n");
continue;
}
AddStatementToList(statement, statements);
}
return statements;
}
//Simply expands the equality rule
@@ -32,6 +55,40 @@ Expr* Expression() {
return Equality();
}
Stmt* Statement(void) {
if (Match(1, PRINT)) return PrintStatement();
return ExpressionStatement();
}
Stmt* PrintStatement(void) {
Expr* value = Expression();
if (!Match(1, Semicolon)) {
fprintf(stderr, "Expected ';' after value\n");
return NULL;
}
AdvanceParser();
return CreateStatement(value, STMT_Print);
}
Stmt* ExpressionStatement(void) {
Expr* expr = Expression();
if (!Match(1, Semicolon)) {
fprintf(stderr, "Expected ';' after expression\n");
return NULL;
}
AdvanceParser();
return CreateStatement(expr, STMT_Expression);
}
Stmt* ExpressionStatement(void);
Expr* Equality() {
Expr* expr = Comparison();
@@ -146,7 +203,7 @@ Expr* Primary() {
return temp;
}
printf("Bad expression\n");
fprintf(stderr, "Bad expression, this should be unreachable.\n");
return NULL;
}
@@ -157,11 +214,14 @@ int Match(int count, ...) {
for(int i = 0; i < count; i++) {
if(Check(va_arg(list, TokenType))) {
va_end(list);
AdvanceParser();
return 1;
}
}
va_end(list);
return 0;
}
@@ -251,3 +311,56 @@ void FreeExpressionTree(Expr* tree) {
free(tree);
}
void FreeStatementList(StatementList* list) {
if (!list) return;
for(int i = 0; i < list->size; i++) {
FreeExpressionTree(list->content[i]->expression);
free(list->content[i]);
}
free(list);
}
StatementList* CreateStatementList(void) {
StatementList* list = calloc(1, sizeof(StatementList));
if (!list) {
fprintf(stderr, "Failed to calloc StatementList. %s\n", strerror(errno));
return NULL;
}
list->content = calloc(STATEMENTLIST_DEFAULT_SIZE, sizeof(Stmt));
if (!list->content) {
fprintf(stderr, "Failed to calloc StatementList contents. %s\n", strerror(errno));
free(list);
return NULL;
}
list->capacity = STATEMENTLIST_DEFAULT_SIZE;
return list;
}
int AddStatementToList(Stmt* statement, StatementList* list) {
if (!statement || !list) return 0;
if (list->size == list->capacity) {
void* new_ptr = realloc(list->content, sizeof(Stmt) * list->capacity * 2);
if (!new_ptr) {
fprintf(stderr, "Failed to realloc StatmentList to size %d. %s\n", list->capacity * 2, strerror(errno));
return 0;
}
list->content = new_ptr;
list->capacity *= 2;
}
list->content[list->size] = statement;
list->size++;
return 1;
}
+24
View File
@@ -0,0 +1,24 @@
#ifndef PARSER_H
#define PARSER_H
#include "expr.h"
#include "scanner.h"
#include "token.h"
#include "statement.h"
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#define STATEMENTLIST_DEFAULT_SIZE 32
typedef struct {
Stmt** content;
int size;
int capacity;
} StatementList;
StatementList* Parse(const TokenList*);
void PrintExpressionTree(const Expr*);
void FreeStatementList(StatementList*);
#endif
+11 -2
View File
@@ -1,5 +1,6 @@
#include "scanner.h"
#include "token.h"
#include <string.h>
const char* source_code;
//Start and Current hold the offsets that index into the string source_code.
@@ -245,9 +246,17 @@ void ParseNumber(TokenList* list) {
}
snprintf(lexeme, current - start, "%s", &source_code[start]);
double value = atof(lexeme); //Will this reference become stale on return?
double* value = calloc(1, sizeof(double));
AddToTokenList(CreateToken(lexeme, &value, line, Number), list);
if (!value) {
fprintf(stderr, "Failed to calloc for number value. %s\n", strerror(errno));
free(lexeme);
return;
}
*value = atof(lexeme);
AddToTokenList(CreateToken(lexeme, value, line, Number), list);
}
char PeekNext() {
View File
+21
View File
@@ -0,0 +1,21 @@
#include "statement.h"
Stmt* CreateStatement(Expr* expression, StatementType type) {
Stmt* stmt = calloc(1, sizeof(Stmt));
if (!stmt) {
fprintf(stderr, "Failed to calloc space for Statement. %s.\n", strerror(errno));
return NULL;
}
stmt->expression = expression;
stmt->type = type;
return stmt;
}
void FreeStatement(Stmt* stmt) {
if (!stmt) return;
free(stmt);
}
+22
View File
@@ -0,0 +1,22 @@
#ifndef STATEMENT_H
#define STATEMENT_H
#include "expr.h"
#include <stdlib.h>
#include <string.h>
#include <errno.h>
typedef enum {
STMT_Expression,
STMT_Print
} StatementType;
typedef struct stmt {
StatementType type;
Expr* expression;
} Stmt;
Stmt* CreateStatement(Expr*, StatementType);
void FreeStatement(Stmt*);
#endif
+1 -1
View File
@@ -33,7 +33,7 @@ Token* CreateToken(const char* lexeme, void* literal, int line, TokenType type)
const char* mapping_result = GetLexemeMapping(type);
if (!mapping_result) {
fprintf(stderr, "Failed to get the mapping for %s\n", lexeme);
fprintf(stderr, "Failed to get the mapping for TokenType value %d.\n", type);
free(token);
return NULL;
}
View File