Compare commits

8 Commits
Author SHA1 Message Date
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
glm94 d4dd459389 Fixed a bug with string parsing in the Scanner. 2022-03-15 18:37:25 +00:00
15 changed files with 240 additions and 54 deletions
+1
View File
@@ -1,3 +1,4 @@
clox
*.lox
obj/
bin/
+30 -6
View File
@@ -1,13 +1,37 @@
CC = gcc
SOURCEFILES := $(wildcard *.c)
CFLAGS=-g -Wall -DDEBUG
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 -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:
$(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);
}
+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
+101 -14
View File
@@ -1,4 +1,5 @@
#include "interpreter.h"
#include "expr.h"
#include "token.h"
#include <errno.h>
#include <stdio.h>
@@ -6,18 +7,60 @@
#include <string.h>
Object* Evaluate(Expr*);
Object* CreateObject(void*, TokenType);
void FreeObject(Object*);
Object* CreateObject(const void*, TokenType);
Object* VisitLiteralExpression(Expr*);
Object* VisitGroupingExpression(Expr*);
Object* VisitBinaryExpression(Expr*);
int IsTruthy(Object*);
int IsEqual(Object*, Object*);
int ConcatStringObject(Object*, const Object*);
void CheckNumberOperands(TokenType, int, ...);
void PrintObject(Object*);
const void* VisitLiteralExpression(Expr* expression) {
return expression->expression.Literal->literal;
void PrintObject(Object* o) {
switch(o->instance) {
case INS_BOOLEAN:
printf("BOOL: %d\n", o->value.boolean);
break;
case INS_DOUBLE:
printf("DOUBLE: %f\n", o->value.number);
break;
case INS_STRING:
printf("STRING: %s\n", o->value.string);
break;
default:
printf("NULL\n");
}
}
void* VisitGroupingExpression(Expr* expression) {
return Evaluate(expression);
void Interpret(Expr* exp) {
Object* c = Evaluate(exp);
switch(c->instance) {
case INS_BOOLEAN:
printf("Bool %d\n", c->value.boolean);
break;
case INS_DOUBLE:
printf("Number %f\n", c->value.number);
break;
case INS_STRING:
printf("String '%s'\n", c->value.string);
break;
default:
printf("Default\n");
}
printf("Freeing Object...\n");
FreeObject(c);
}
Object* VisitLiteralExpression(Expr* expr) {
return CreateObject(expr->expression.Literal->literal, expr->expression.Literal->type);
}
//NOTE: We rely on this helper method which simply sends the expression back into
//the interpreters visitor implementation
Object* VisitGroupingExpression(Expr* expression) {
return Evaluate(expression->expression.Grouping.expression);
}
Object* VisitBinaryExpression(Expr* expression) {
@@ -27,52 +70,61 @@ Object* VisitBinaryExpression(Expr* expression) {
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:
CheckNumberOperands(expression->expression.Binary.op->type, 2, left, right);
left->value.number *= right->value.number;
FreeObject(right);
return left;
@@ -107,18 +159,16 @@ Object* VisitBinaryExpression(Expr* expression) {
}
Object* VisitUnaryExpression(Expr* expression) {
Object* right = Evaluate(expression);
Object* right = Evaluate(expression->expression.Unary.right);
Object* c;
double computed_value;
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);
//right needs to be negated, but that kind of introduces a
//memory leak since we can't really change it, what with the
//whole "const void*" thing and all.
return c;
case Bang:
computed_value = !IsTruthy(right);
@@ -135,11 +185,27 @@ Object* VisitUnaryExpression(Expr* expression) {
}
Object* Evaluate(Expr* expression) {
//accept -> calls Visitor functions by type
switch (expression->type) {
case EXPRESSION:
fprintf(stderr, "EXPRESSION case seen for expression.\n");
break;
case UNARY:
return VisitUnaryExpression(expression);
case GROUPING:
return VisitGroupingExpression(expression->expression.Grouping.expression);
case BINARY:
return VisitBinaryExpression(expression);
case LITERAL:
return VisitLiteralExpression(expression);
default:
fprintf(stderr, "Default case seen for expression.\n");
break;
}
//return expr.accept(this);
return NULL;
}
Object* CreateObject(void* value, TokenType type) {
Object* CreateObject(const void* value, TokenType type) {
Object* object = calloc(1, sizeof(Object));
if (!object) {
@@ -152,6 +218,7 @@ Object* CreateObject(void* value, TokenType type) {
object->instance = INS_NULL;
break;
case Number:
//printf("NUM: %p, %f\n", value, *(double*) value);
object->instance = INS_DOUBLE;
object->value.number = *(double*) value;
break;
@@ -162,11 +229,16 @@ Object* CreateObject(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));
if (!object->value.string) {
fprintf(stderr, "Faild to calloc %u bytes for a new string Object. %s.\n", length + 1, strerror(errno));
return NULL;
}
strncpy(object->value.string, value, length);
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.
}
@@ -222,4 +294,19 @@ 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);
}
+2 -3
View File
@@ -20,8 +20,7 @@ typedef struct Object {
} value;
} Object;
const void* VisitLiteralExpression(Expr*);
void* VisitGroupingExpression(Expr*);
Object* VisitBinaryExpression(Expr*);
void Interpret(Expr*);
void FreeObject(Object*);
#endif
+4 -1
View File
@@ -1,6 +1,7 @@
#include "scanner.h"
#include "parser.h"
#include "expr.h"
#include "interpreter.h"
#include <stdio.h>
#include <stdlib.h>
#include <sysexits.h>
@@ -38,11 +39,13 @@ void RunFile(const char* path) {
char* contents = GetFileContents(path);
TokenList* tokens = ScanTokens(contents);
free(contents);
printf("TOKENS:\n");
Print(tokens);
printf("TREE:\n");
printf("EXPRESSION TREE:\n");
Expr* tree = GenerateExpressionTree(tokens);
PrintExpressionTree(tree);
printf("\n");
Interpret(tree);
FreeExpressionTree(tree);
DestroyTokenList(tokens);
}
+36 -1
View File
@@ -1,5 +1,6 @@
#include "parser.h"
#include "expr.h"
#include "statement.h"
#include "token.h"
#include <stdio.h>
@@ -10,6 +11,9 @@ Expr* Term(void);
Expr* Factor(void);
Expr* Unary(void);
Expr* Primary(void);
Stmt* Statement(void);
Stmt* PrintStatement(void);
Stmt* ExpressionStatement(void);
int Match(int, ...);
int Check(TokenType);
int ParserAtEnd(void);
@@ -32,6 +36,34 @@ 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");
AdvanceParser();
return CreateStatement(value, STMT_Print);
}
Stmt* ExpressionStatement(void) {
Expr* expr = Expression();
if (!Match(1, Semicolon)) fprintf(stderr, "Expected ';' after expression\n");
AdvanceParser();
return CreateStatement(expr, STMT_Expression);
}
Stmt* ExpressionStatement(void);
Expr* Equality() {
Expr* expr = Comparison();
@@ -146,7 +178,7 @@ Expr* Primary() {
return temp;
}
printf("Bad expression\n");
fprintf(stderr, "Bad expression, this should be unreachable.\n");
return NULL;
}
@@ -157,11 +189,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;
}
+1
View File
@@ -4,6 +4,7 @@
#include "expr.h"
#include "scanner.h"
#include "token.h"
#include "statement.h"
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
+17 -6
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.
@@ -212,6 +213,8 @@ void ParseString(TokenList *list) {
return;
}
AdvanceScanner();
char* lexeme = calloc(current - start + 1, sizeof(char));
if (!lexeme) {
@@ -222,8 +225,6 @@ void ParseString(TokenList *list) {
snprintf(lexeme, current - start, "%s", &source_code[start]);
AddToTokenList(CreateToken(lexeme, lexeme, line, String), list);
AdvanceScanner(); // The closing ".
}
void ParseNumber(TokenList* list) {
@@ -235,17 +236,27 @@ void ParseNumber(TokenList* list) {
while(isdigit(ScannerPeek())) AdvanceScanner();
}
char* lexeme = calloc(current - start + 2, sizeof(char));
AdvanceScanner();
char* lexeme = calloc(current - start + 1, sizeof(char));
if (!lexeme) {
fprintf(stderr, "Failed to calloc for number lexeme. %s\n", strerror(errno));
return;
}
snprintf(lexeme, current - start + 1, "%s", &source_code[start]);
double value = atof(lexeme); //Will this reference become stale on return?
snprintf(lexeme, current - start, "%s", &source_code[start]);
double* value = calloc(1, sizeof(double));
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);
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