Compare commits

..
15 Commits
Author SHA1 Message Date
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
glm94 d4dd459389 Fixed a bug with string parsing in the Scanner. 2022-03-15 18:37:25 +00:00
glm94 1ded68ddee Fixed a bug in the IsTruthy function. The VisitBinaryExpression now processes more operations. 2022-03-14 19:20:03 +00:00
glm94 3044f23bcc Creating an object of type Boolean should work correctly, as long as the Boolean value being passed is done so as a double*. 2022-03-14 16:52:47 +00:00
glm94 f666585f5f More refactoring trying to get this cleaned up while trying to keep it easy(ish) to extend for later chapters. I'll never take namespaces for granted again... 2022-03-09 21:13:52 +00:00
glm94 e802c57a93 Trying a more object oriented approach and created an 'Object' struct to have metadata for the values the interpreter works with. 2022-03-08 22:08:06 +00:00
glm94 2d587e75b1 Extemely broken, but all the code up to 7.3 should be here, now the refactoring begins to make it C code and not Java code. 2022-03-07 19:22:39 +00:00
glm94 d39d20aa6e Added a reminder in the Parser in the event of bad syntax. 2022-03-07 18:13:35 +00:00
16 changed files with 625 additions and 50 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 -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:
$(BIN) test.lox
-6
View File
@@ -1,6 +0,0 @@
#include "expr.h"
void VisitBinary(struct binary);
void VisitGrouping(struct grouping);
void VisitLiteral(Token);
void VisitUnary(struct unary);
-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
+5 -4
View File
@@ -2,6 +2,7 @@
#define EXPRESSION_H
#include "scanner.h"
#include <stdarg.h>
typedef enum {
EXPRESSION,
@@ -39,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
+312
View File
@@ -0,0 +1,312 @@
#include "interpreter.h"
#include "expr.h"
#include "token.h"
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
Object* Evaluate(Expr*);
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*);
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 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) {
Object* left = Evaluate(expression->expression.Binary.left);
Object* right = Evaluate(expression->expression.Binary.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:
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 Plus:
if (left->instance == INS_DOUBLE && right->instance == INS_DOUBLE) {
left->value.number += right->value.number;
FreeObject(right);
return left;
}
if (left->instance == INS_STRING && right->instance == INS_STRING) {
if (ConcatStringObject(left, right)) {
FreeObject(right);
return left;
}
}
break;
default:
FreeObject(left);
FreeObject(right);
return NULL; //Should be unreachable.
}
FreeObject(left);
FreeObject(right);
// Unreachable
return NULL;
}
Object* VisitUnaryExpression(Expr* 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);
return c;
case Bang:
computed_value = !IsTruthy(right);
FreeObject(right);
c = CreateObject(&computed_value, TRUE); //TRUE or FALSE, doesn't matter here since it becomes INS_BOOLEAN in the end.
return c;
default:
FreeObject(right);
return NULL; //Should be unreachable.
}
FreeObject(right);
return NULL; //Should be unreachable.
}
Object* Evaluate(Expr* expression) {
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(const void* value, TokenType type) {
Object* object = calloc(1, sizeof(Object));
if (!object) {
fprintf(stderr, "Failed to calloc object. %s.\n", strerror(errno));
return NULL;
}
switch(type) {
case NIL:
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;
case TRUE:
case FALSE:
object->instance = INS_BOOLEAN;
object->value.boolean = *(double*) value;
break;
default:
if (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;
}
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.
}
return object;
}
void FreeObject(Object* object) {
if (object->instance == INS_STRING) free(object->value.string);
free(object);
}
int ConcatStringObject(Object* a, const Object* b) {
if (!a || !b) return 0;
if (a->instance != INS_STRING || b->instance != INS_STRING) return 0;
int a_length = strlen(a->value.string);
int b_length = strlen(b->value.string);
char* c;
c = realloc(a->value.string, a_length + b_length + 1);
if (!c) {
fprintf(stderr, "Failed to realloc for object concat. %s.\n", strerror(errno));
return 0;
}
a->value.string = c;
a->value.string[a_length + b_length] = '\0';
strncat(a->value.string, b->value.string, b_length);
return 1;
}
int IsTruthy(Object* object) {
if (!object || object->instance == INS_NULL) return 0;
if (object->instance == INS_BOOLEAN) return object->value.boolean;
return 1;
}
int IsEqual(Object* a, Object* b) {
if (a->instance == INS_NULL && b->instance == INS_NULL) return 1;
if (a->instance == INS_NULL) return 0;
if (b->instance == INS_DOUBLE && b->instance == INS_DOUBLE) {
return a->value.number == b->value.number;
}
if (a->instance == INS_STRING && b->instance == INS_STRING) {
return strcmp(a->value.string, b->value.string) == 0;
}
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);
}
+26
View File
@@ -0,0 +1,26 @@
#ifndef INTERPRETER_H
#define INTERPRETER_H
#include "expr.h"
#include "token.h"
typedef enum {
INS_STRING,
INS_DOUBLE,
INS_BOOLEAN,
INS_NULL
} ObjectInstanceType;
typedef struct Object {
ObjectInstanceType instance;
union {
char* string;
double number;
int boolean;
} value;
} Object;
void Interpret(Expr*);
void FreeObject(Object*);
#endif
+14 -5
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>
@@ -12,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);
@@ -38,12 +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");
FreeExpressionTree(tree);
Interpret(tree);
FreeStatementList(statements);
//FreeExpressionTree(tree);
DestroyTokenList(tokens);
}
+119 -6
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,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();
@@ -133,16 +184,20 @@ Expr* Primary() {
if (Match(1, LParen)) {
expr = Expression();
Expr* temp = calloc(1, sizeof(Expr));
if (!Check(RParen)) printf("Unbalanced\n"); //Todo: something or another...
if (!Check(RParen)) {
free(expr);
printf("Unbalanced\n"); //Todo: something or another...
return NULL;
}
//Consume(RParen, "Expect ')' after expression.");
Expr* temp = calloc(1, sizeof(Expr));
temp->type = GROUPING;
temp->expression.Grouping.expression = expr;
return temp;
}
printf("Bad expression\n");
fprintf(stderr, "Bad expression, this should be unreachable.\n");
return NULL;
}
@@ -153,11 +208,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;
}
@@ -183,7 +241,11 @@ Token* AdvanceParser() {
return Previous();
}
//In the Java implementation this get's called in catch blocks.
//Obviously that's not going to fly in C, so I need some way to
//"unwind" the stack. Maybe synchronizing (setting the Current variable)
//will be enough, and simply return NULLs up the call stack.
//Naive but might work in the future for this.
void SynchronizeParser(void) {
AdvanceParser();
//Discard tokens until we find a statement boundary, or at least something that looks like one.
@@ -243,3 +305,54 @@ 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;
}
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
+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));
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
+32 -2
View File
@@ -1,4 +1,6 @@
#include "token.h"
#include <stdlib.h>
#include <string.h>
KeyValuePair TokenTypeMappings[TOKENTYPE_MAPPINGS_COUNT] = {
{ "(", LParen}, { ")", RParen}, { ",", Comma }, { ".", Dot },
@@ -31,12 +33,12 @@ 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;
}
token->literal = mapping_result;
if (type != NIL) token->literal = mapping_result;
token->lexeme = mapping_result;
}
@@ -61,3 +63,31 @@ void FreeToken(Token* token) {
free(token);
}
char* GetTokenStringValue(Token* token, int* length) {
length = 0;
if (!token) return NULL;
if (token->type != String) return NULL;
*length = strlen(token->lexeme);
if (length == 0) return NULL;
char* value = calloc(strlen(token->lexeme) + 1, sizeof(char));
strncpy(value, token->lexeme, *length);
return value;
}
int GetTokenNumberValue(Token* token, double* value) {
value = 0;
if (!token) return 0;
if (token->type != Number) return 0;
*value = *((double*)token->literal);
return 1;
}
+2
View File
@@ -50,6 +50,8 @@ extern KeyValuePair TokenTypeMappings[TOKENTYPE_MAPPINGS_COUNT];
//If the first parameter is NULL, the token creation will attempt to infer the lexeme from the TokenType.
Token* CreateToken(const char*, void*, int, TokenType);
char* GetTokenStringValue(Token*, int*);
int GetTokenNumberValue(Token*, double*);
void FreeToken(Token*);
#endif