Files
assm-test/src/parser.c
T

300 lines
7.3 KiB
C

#include "../includes/parser.h"
#include <string.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#ifndef HIGHMEMORY
#define HIGHMEMORY 65535 //64KiB - 1 AKA 0xFFFF
#endif
//#define HEAPTOP HIGHMEMORY
typedef struct {
Token* token;
int address;
} Symbol;
struct intr {
TokenType struction;
unsigned int parameter1;
unsigned int parameter2;
};
Symbol* CreateSymbol(Token* token, int address);
const List* TokensList;
int CurrentToken = 0;
//int HeapTop = HIGHMEMORY;
void AddSymbol(Token*, int);
void PrintSymbols(void);
void HandleOperation(void);
void HandleAssemblerDirective(void);
void AdvanceParser(void);
Token* PeekToken(void);
int ParserAtEnd(void);
int Expect(int, ...);
int ExpectTokenClass(int, ...);
const Symbol* GetSymbol(char*);
List* SymbolsTable;
unsigned int ProgramCounter = 0;
void ParseTokens(List* tokens) {
if (!tokens) return;
TokensList = tokens;
SymbolsTable = CreateList();
while(!ParserAtEnd()) {
Token* t = PeekToken();
switch(t->token_class) {
case Directive:
HandleAssemblerDirective();
break;
case Opcode:
ProgramCounter++;
HandleOperation();
break;
case Immediate16:
ProgramCounter++;
AddSymbol(t, ProgramCounter);
break;
default:
break;
}
AdvanceParser();
}
PrintSymbols();
DestroyList(SymbolsTable);
printf("Program Counter: %d\n", ProgramCounter);
//printf("Heap Top: %#06X\n", HeapTop);
}
void HandleAssemblerDirective(void) {
if (PeekToken()->type == DB) {
AdvanceParser();
Token* identifier = PeekToken();
if (!Expect(1, IDENTIFIER)) {
fprintf(stderr, "Expected identifier on line %d\n", PeekToken()->line);
exit(1);
}
AddSymbol(identifier, ProgramCounter);
switch(PeekToken()->type) {
case STRING:
ProgramCounter += strlen(PeekToken()->lexeme);
printf("[INFO] %s = '%s'\n", identifier->lexeme, PeekToken()->lexeme);
AdvanceParser();
if (PeekToken()->type == COMMA) {
AdvanceParser();
if (PeekToken()-> type != NUMBER) {
fprintf(stderr, "Expected string termination byte on line %d\n", PeekToken()->line);
exit(1);
}
else {
//Add the NULL byte.
ProgramCounter++;
return;
}
}
case NUMBER:
break;
default:
fprintf(stderr, "[Line: %d] Expected either a number or string after identifier '%s'.\n", PeekToken()->line, identifier->lexeme);
exit(1);
}
}
}
void HandleOperation(void) {
const Instruction* inst = GetOpcodeDetails(PeekToken()->type);
if (!inst) return;
AdvanceParser();
printf("[%#05X] %s ", ProgramCounter, inst->lexeme);
if (inst->parameter_one == None) {
printf("\n");
return;
}
if (inst->parameter_one && PeekToken()->token_class > 0) {
//printf("Matched '%s'\n", PeekToken()->lexeme);
if (inst->parameter_one & Reg) {
//Encode the register number here.
printf("%s ", PeekToken()->lexeme);
}
else if (inst->parameter_one & Immediate16) {
if (PeekToken()->type == IDENTIFIER || PeekToken()->type == LABEL) {
const Symbol* symbol = GetSymbol(PeekToken()->lexeme);
if (!symbol) {
fprintf(stderr, "[Error] %s is undefined.\n", PeekToken()->lexeme);
exit(1);
}
printf("[%s@%#04X] ", PeekToken()->lexeme, symbol->address);
}
else if (PeekToken()->type == NUMBER) printf("%s ", PeekToken()->lexeme);
ProgramCounter += 2;
}
AdvanceParser();
}
if (inst->parameter_two == None) {
printf("\n");
return;
}
if (PeekToken()->type == COMMA) {
AdvanceParser();
} else {
fprintf(stderr, "Expected comma at line %d\n", PeekToken()->line);
exit(666);
return;
}
if (inst->parameter_two && PeekToken()->token_class > 0) {
//printf("Matched 2 '%s'\n", PeekToken()->lexeme);
if (inst->parameter_two & Immediate16) {
if (PeekToken()->type == IDENTIFIER || PeekToken()->type == LABEL) {
const Symbol* symbol = GetSymbol(PeekToken()->lexeme);
if (!symbol) {
fprintf(stderr, "[Error] %s is undefined.\n", PeekToken()->lexeme);
exit(1);
}
printf("[%s@%#04X] ", PeekToken()->lexeme, symbol->address);
}
else if (PeekToken()->type == NUMBER) printf("%s ", PeekToken()->lexeme);
ProgramCounter += 2;
}
AdvanceParser();
} else {
printf("Failed to match %s (class: %d)\n", PeekToken()->lexeme, PeekToken()->token_class);
printf("Inst %s (class: %x)\n", inst->lexeme, inst->parameter_two);
}
printf("\n");
}
int ExpectTokenClass(int count, ...) {
va_list list;
Token* token = PeekToken();
va_start(list, count);
for(int i = 0; i < count; i++) {
if (va_arg(list, TokenClass) == token->token_class) {
va_end(list);
AdvanceParser();
return 1;
}
}
va_end(list);
return 0;
}
int Expect(int count, ...) {
va_list list;
Token* token = PeekToken();
va_start(list, count);
for(int i = 0; i < count; i++) {
if (va_arg(list, TokenType) == token->type) {
va_end(list);
AdvanceParser();
return 1;
}
}
va_end(list);
return 0;
}
void PrintSymbols(void) {
printf("-----SYMBOLS-----\n");
for(int i = 0; i < SymbolsTable->size; i++) {
Symbol* symbol = SymbolsTable->content[i];
printf("[%#06X] %s\n", symbol->address, symbol->token->lexeme);
}
printf("-----SYMBOLS-----\n");
}
void AddSymbol(Token* token, int address) {
if (!token) return;
if (token->type != IDENTIFIER && token->type != LABEL) return;
for(int i = 0; i < SymbolsTable->size; i++) {
Symbol* s = SymbolsTable->content[i];
if (strcmp(s->token->lexeme, token->lexeme) == 0) return;
}
Symbol* symbol = CreateSymbol(token, address);
AddListItem(symbol, sizeof(Symbol), SymbolsTable);
}
const Symbol* GetSymbol(char* name) {
if (!name) return NULL;
for(int i = 0; i < SymbolsTable->size; i++) {
const Symbol* s = SymbolsTable->content[i];
if (strcmp(s->token->lexeme, name) == 0) return s;
}
return NULL;
}
Symbol* CreateSymbol(Token* token, int address) {
Symbol* symbol = calloc(1, sizeof(Symbol));
if (!symbol) return NULL;
symbol->token = token;
symbol->address = address;
return symbol;
}
void AdvanceParser(void) {
if (ParserAtEnd()) return;
CurrentToken++;
}
int ParserAtEnd(void) {
if (CurrentToken >= TokensList->size) return 1;
return 0;
}
Token* PeekToken(void) {
return TokensList->content[CurrentToken];
}