Compare commits

10 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
glm94 d4dd459389 Fixed a bug with string parsing in the Scanner. 2022-03-15 18:37:25 +00:00
16 changed files with 353 additions and 75 deletions
+1
View File
@@ -1,3 +1,4 @@
clox clox
*.lox *.lox
obj/ obj/
bin/
+30 -6
View File
@@ -1,13 +1,37 @@
CC = gcc 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) all: $(BIN)
@mkdir -p obj
$(CC) $^ -o obj/clox 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: clean
.PHONY: test
clean: 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);
}
-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; } expression;
}; };
void VisitBinary(struct binary); // void VisitBinary(struct binary);
void VisitGrouping(struct grouping); // void VisitGrouping(struct grouping);
void VisitLiteral(Token); // void VisitLiteral(Token);
void VisitUnary(struct unary); // void VisitUnary(struct unary);
#endif #endif
+101 -14
View File
@@ -1,4 +1,5 @@
#include "interpreter.h" #include "interpreter.h"
#include "expr.h"
#include "token.h" #include "token.h"
#include <errno.h> #include <errno.h>
#include <stdio.h> #include <stdio.h>
@@ -6,18 +7,60 @@
#include <string.h> #include <string.h>
Object* Evaluate(Expr*); Object* Evaluate(Expr*);
Object* CreateObject(void*, TokenType); Object* CreateObject(const void*, TokenType);
void FreeObject(Object*); Object* VisitLiteralExpression(Expr*);
Object* VisitGroupingExpression(Expr*);
Object* VisitBinaryExpression(Expr*);
int IsTruthy(Object*); int IsTruthy(Object*);
int IsEqual(Object*, Object*); int IsEqual(Object*, Object*);
int ConcatStringObject(Object*, const Object*); int ConcatStringObject(Object*, const Object*);
void CheckNumberOperands(TokenType, int, ...);
void PrintObject(Object*);
const void* VisitLiteralExpression(Expr* expression) { void PrintObject(Object* o) {
return expression->expression.Literal->literal; 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) { void Interpret(Expr* exp) {
return Evaluate(expression); 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* VisitBinaryExpression(Expr* expression) {
@@ -27,52 +70,61 @@ Object* VisitBinaryExpression(Expr* expression) {
switch(expression->expression.Binary.op->type) { switch(expression->expression.Binary.op->type) {
case Greater: case Greater:
CheckNumberOperands(expression->expression.Binary.op->type, 2, left, right);
computed_value = left->value.number > right->value.number; computed_value = left->value.number > right->value.number;
FreeObject(left); FreeObject(left);
FreeObject(right); FreeObject(right);
return CreateObject(&computed_value, TRUE); return CreateObject(&computed_value, TRUE);
//return left > right; //return left > right;
case Greater_Equal: case Greater_Equal:
CheckNumberOperands(expression->expression.Binary.op->type, 2, left, right);
computed_value = left->value.number >= right->value.number; computed_value = left->value.number >= right->value.number;
FreeObject(left); FreeObject(left);
FreeObject(right); FreeObject(right);
return CreateObject(&computed_value, TRUE); return CreateObject(&computed_value, TRUE);
//return left >= right; //return left >= right;
case Less: case Less:
CheckNumberOperands(expression->expression.Binary.op->type, 2, left, right);
computed_value = left->value.number < right->value.number; computed_value = left->value.number < right->value.number;
FreeObject(left); FreeObject(left);
FreeObject(right); FreeObject(right);
return CreateObject(&computed_value, TRUE); return CreateObject(&computed_value, TRUE);
//return left < right; //return left < right;
case Less_Equal: case Less_Equal:
CheckNumberOperands(expression->expression.Binary.op->type, 2, left, right);
computed_value = left->value.number <= right->value.number; computed_value = left->value.number <= right->value.number;
FreeObject(left); FreeObject(left);
FreeObject(right); FreeObject(right);
return CreateObject(&computed_value, TRUE); return CreateObject(&computed_value, TRUE);
//return left <= right; //return left <= right;
case Bang_Equal: case Bang_Equal:
CheckNumberOperands(expression->expression.Binary.op->type, 2, left, right);
computed_value = !IsEqual(left, right); computed_value = !IsEqual(left, right);
FreeObject(left); FreeObject(left);
FreeObject(right); FreeObject(right);
return CreateObject(&computed_value, TRUE); return CreateObject(&computed_value, TRUE);
//return !IsEqual(left, right); //return !IsEqual(left, right);
case Equal_Equal: case Equal_Equal:
CheckNumberOperands(expression->expression.Binary.op->type, 2, left, right);
computed_value = IsEqual(left, right); computed_value = IsEqual(left, right);
FreeObject(left); FreeObject(left);
FreeObject(right); FreeObject(right);
return CreateObject(&computed_value, TRUE); return CreateObject(&computed_value, TRUE);
//return IsEqual(left, right); //return IsEqual(left, right);
case Minus: case Minus:
CheckNumberOperands(expression->expression.Binary.op->type, 2, left, right);
left->value.number -= right->value.number; left->value.number -= right->value.number;
FreeObject(right); FreeObject(right);
return left; return left;
//return left - right; //return left - right;
case Slash: case Slash:
CheckNumberOperands(expression->expression.Binary.op->type, 2, left, right);
left->value.number /= right->value.number; left->value.number /= right->value.number;
FreeObject(right); FreeObject(right);
return left; return left;
//return *((double*)left) / *((double*)right); //return *((double*)left) / *((double*)right);
case Star: case Star:
CheckNumberOperands(expression->expression.Binary.op->type, 2, left, right);
left->value.number *= right->value.number; left->value.number *= right->value.number;
FreeObject(right); FreeObject(right);
return left; return left;
@@ -107,18 +159,16 @@ Object* VisitBinaryExpression(Expr* expression) {
} }
Object* VisitUnaryExpression(Expr* expression) { Object* VisitUnaryExpression(Expr* expression) {
Object* right = Evaluate(expression); Object* right = Evaluate(expression->expression.Unary.right);
Object* c; Object* c;
double computed_value; double computed_value;
switch (expression->expression.Unary.op->type) { switch (expression->expression.Unary.op->type) {
case Minus: case Minus:
CheckNumberOperands(expression->expression.Unary.op->type, 1, right);//This needs to "throw" if the function fails.
computed_value = -right->value.number; computed_value = -right->value.number;
FreeObject(right); FreeObject(right);
c = CreateObject(&computed_value, Number); 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; return c;
case Bang: case Bang:
computed_value = !IsTruthy(right); computed_value = !IsTruthy(right);
@@ -135,11 +185,27 @@ Object* VisitUnaryExpression(Expr* expression) {
} }
Object* Evaluate(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; return NULL;
} }
Object* CreateObject(void* value, TokenType type) { Object* CreateObject(const void* value, TokenType type) {
Object* object = calloc(1, sizeof(Object)); Object* object = calloc(1, sizeof(Object));
if (!object) { if (!object) {
@@ -152,6 +218,7 @@ Object* CreateObject(void* value, TokenType type) {
object->instance = INS_NULL; object->instance = INS_NULL;
break; break;
case Number: case Number:
//printf("NUM: %p, %f\n", value, *(double*) value);
object->instance = INS_DOUBLE; object->instance = INS_DOUBLE;
object->value.number = *(double*) value; object->value.number = *(double*) value;
break; break;
@@ -162,11 +229,16 @@ Object* CreateObject(void* value, TokenType type) {
break; break;
default: default:
if (value) { if (value) {
int length = strlen(value); unsigned int length = strlen(value);
object->instance = INS_STRING; object->instance = INS_STRING;
object->value.string = calloc(length + 1, sizeof(char)); 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. } else object->instance = INS_NULL; //TODO: this is most likely an error, but we'll ignore that for now.
} }
@@ -223,3 +295,18 @@ int IsEqual(Object* a, Object* b) {
return 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);
}
+2 -3
View File
@@ -20,8 +20,7 @@ typedef struct Object {
} value; } value;
} Object; } Object;
const void* VisitLiteralExpression(Expr*); void Interpret(Expr*);
void* VisitGroupingExpression(Expr*); void FreeObject(Object*);
Object* VisitBinaryExpression(Expr*);
#endif #endif
+14 -5
View File
@@ -1,6 +1,7 @@
#include "scanner.h" #include "scanner.h"
#include "parser.h" #include "parser.h"
#include "expr.h" #include "expr.h"
#include "interpreter.h"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <sysexits.h> #include <sysexits.h>
@@ -12,6 +13,10 @@ void RunPrompt(void);
char* GetFileContents(const char*); char* GetFileContents(const char*);
int main(int argc, char** argv) { int main(int argc, char** argv) {
#ifdef DEBUG
printf("Debug clox build.\n");
#endif
if (argc > 2) { if (argc > 2) {
printf("Useage: clox [script]\n"); printf("Useage: clox [script]\n");
exit(EX_USAGE); exit(EX_USAGE);
@@ -38,12 +43,16 @@ void RunFile(const char* path) {
char* contents = GetFileContents(path); char* contents = GetFileContents(path);
TokenList* tokens = ScanTokens(contents); TokenList* tokens = ScanTokens(contents);
free(contents); free(contents);
Print(tokens); printf("TOKENS:\n");
printf("TREE:\n"); //Print(tokens);
Expr* tree = GenerateExpressionTree(tokens); printf("EXPRESSION TREE:\n");
PrintExpressionTree(tree); //Expr* tree = GenerateExpressionTree(tokens);
StatementList* statements = Parse(tokens);
//PrintExpressionTree(tree);
printf("\n"); printf("\n");
FreeExpressionTree(tree); //Interpret(tree);
FreeStatementList(statements);
//FreeExpressionTree(tree);
DestroyTokenList(tokens); DestroyTokenList(tokens);
} }
+116 -3
View File
@@ -1,7 +1,10 @@
#include "parser.h" #include "parser.h"
#include "expr.h" #include "expr.h"
#include "statement.h"
#include "token.h" #include "token.h"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
#include <string.h>
Expr* Expression(void); Expr* Expression(void);
Expr* Equality(void); Expr* Equality(void);
@@ -10,6 +13,11 @@ Expr* Term(void);
Expr* Factor(void); Expr* Factor(void);
Expr* Unary(void); Expr* Unary(void);
Expr* Primary(void); Expr* Primary(void);
Stmt* Statement(void);
Stmt* PrintStatement(void);
Stmt* ExpressionStatement(void);
StatementList* CreateStatementList(void);
int AddStatementToList(Stmt*, StatementList*);
int Match(int, ...); int Match(int, ...);
int Check(TokenType); int Check(TokenType);
int ParserAtEnd(void); int ParserAtEnd(void);
@@ -17,14 +25,29 @@ Token* ParserPeek(void);
Token* Previous(void); Token* Previous(void);
Token* AdvanceParser(void); Token* AdvanceParser(void);
void SynchronizeParser(void); void SynchronizeParser(void);
void FreeExpressionTree(Expr*);
const TokenList* ListOfTokens; const TokenList* ListOfTokens;
int Current = 0; int Current = 0;
Expr* GenerateExpressionTree(const TokenList* list) { StatementList* Parse(const TokenList* list) {
ListOfTokens = 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 //Simply expands the equality rule
@@ -32,6 +55,40 @@ Expr* Expression() {
return Equality(); 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* Equality() {
Expr* expr = Comparison(); Expr* expr = Comparison();
@@ -146,7 +203,7 @@ Expr* Primary() {
return temp; return temp;
} }
printf("Bad expression\n"); fprintf(stderr, "Bad expression, this should be unreachable.\n");
return NULL; return NULL;
} }
@@ -157,11 +214,14 @@ int Match(int count, ...) {
for(int i = 0; i < count; i++) { for(int i = 0; i < count; i++) {
if(Check(va_arg(list, TokenType))) { if(Check(va_arg(list, TokenType))) {
va_end(list);
AdvanceParser(); AdvanceParser();
return 1; return 1;
} }
} }
va_end(list);
return 0; return 0;
} }
@@ -251,3 +311,56 @@ void FreeExpressionTree(Expr* tree) {
free(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
+17 -6
View File
@@ -1,5 +1,6 @@
#include "scanner.h" #include "scanner.h"
#include "token.h" #include "token.h"
#include <string.h>
const char* source_code; const char* source_code;
//Start and Current hold the offsets that index into the string source_code. //Start and Current hold the offsets that index into the string source_code.
@@ -212,6 +213,8 @@ void ParseString(TokenList *list) {
return; return;
} }
AdvanceScanner();
char* lexeme = calloc(current - start + 1, sizeof(char)); char* lexeme = calloc(current - start + 1, sizeof(char));
if (!lexeme) { if (!lexeme) {
@@ -222,8 +225,6 @@ void ParseString(TokenList *list) {
snprintf(lexeme, current - start, "%s", &source_code[start]); snprintf(lexeme, current - start, "%s", &source_code[start]);
AddToTokenList(CreateToken(lexeme, lexeme, line, String), list); AddToTokenList(CreateToken(lexeme, lexeme, line, String), list);
AdvanceScanner(); // The closing ".
} }
void ParseNumber(TokenList* list) { void ParseNumber(TokenList* list) {
@@ -235,17 +236,27 @@ void ParseNumber(TokenList* list) {
while(isdigit(ScannerPeek())) AdvanceScanner(); while(isdigit(ScannerPeek())) AdvanceScanner();
} }
char* lexeme = calloc(current - start + 2, sizeof(char)); AdvanceScanner();
char* lexeme = calloc(current - start + 1, sizeof(char));
if (!lexeme) { if (!lexeme) {
fprintf(stderr, "Failed to calloc for number lexeme. %s\n", strerror(errno)); fprintf(stderr, "Failed to calloc for number lexeme. %s\n", strerror(errno));
return; return;
} }
snprintf(lexeme, current - start + 1, "%s", &source_code[start]); 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() { 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); const char* mapping_result = GetLexemeMapping(type);
if (!mapping_result) { 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); free(token);
return NULL; return NULL;
} }
View File